blob: 98ded374289d9de1778168abe4c5d8720d5b0178 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006-2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.am;
18
19import com.android.internal.os.BatteryStatsImpl;
Dianne Hackbornde7faf62009-06-30 13:27:30 -070020import com.android.server.AttributeCache;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import com.android.server.IntentResolver;
22import com.android.server.ProcessMap;
23import com.android.server.ProcessStats;
24import com.android.server.SystemServer;
25import com.android.server.Watchdog;
26import com.android.server.WindowManagerService;
27
Dianne Hackborndd71fc82009-12-16 19:24:32 -080028import dalvik.system.Zygote;
29
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.app.Activity;
31import android.app.ActivityManager;
32import android.app.ActivityManagerNative;
33import android.app.ActivityThread;
34import android.app.AlertDialog;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020035import android.app.ApplicationErrorReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.app.Dialog;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070037import android.app.IActivityController;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.app.IActivityWatcher;
39import android.app.IApplicationThread;
40import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.app.IServiceConnection;
42import android.app.IThumbnailReceiver;
43import android.app.Instrumentation;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070044import android.app.Notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.app.PendingIntent;
46import android.app.ResultInfo;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070047import android.app.Service;
Christopher Tate181fafa2009-05-14 11:12:14 -070048import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020049import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.content.ComponentName;
51import android.content.ContentResolver;
52import android.content.Context;
53import android.content.Intent;
54import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070055import android.content.IIntentReceiver;
56import android.content.IIntentSender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -070057import android.content.IntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.content.pm.ActivityInfo;
59import android.content.pm.ApplicationInfo;
60import android.content.pm.ConfigurationInfo;
61import android.content.pm.IPackageDataObserver;
62import android.content.pm.IPackageManager;
63import android.content.pm.InstrumentationInfo;
Dan Egnor66c40e72010-01-26 16:23:11 -080064import android.content.pm.PackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070066import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067import android.content.pm.ProviderInfo;
68import android.content.pm.ResolveInfo;
69import android.content.pm.ServiceInfo;
70import android.content.res.Configuration;
71import android.graphics.Bitmap;
72import android.net.Uri;
73import android.os.Binder;
Dan Egnor60d87622009-12-16 16:32:58 -080074import android.os.Build;
Dan Egnor42471dd2010-01-07 17:25:22 -080075import android.os.Bundle;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070076import android.os.Debug;
Dan Egnor60d87622009-12-16 16:32:58 -080077import android.os.DropBoxManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080078import android.os.Environment;
Dan Egnor42471dd2010-01-07 17:25:22 -080079import android.os.FileObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080import android.os.FileUtils;
81import android.os.Handler;
82import android.os.IBinder;
83import android.os.IPermissionController;
84import android.os.Looper;
85import android.os.Message;
86import android.os.Parcel;
87import android.os.ParcelFileDescriptor;
88import android.os.PowerManager;
89import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070090import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091import android.os.RemoteException;
92import android.os.ServiceManager;
93import android.os.SystemClock;
94import android.os.SystemProperties;
95import android.provider.Checkin;
96import android.provider.Settings;
97import android.text.TextUtils;
98import android.util.Config;
99import android.util.EventLog;
100import android.util.Log;
101import android.util.PrintWriterPrinter;
102import android.util.SparseArray;
103import android.view.Gravity;
104import android.view.LayoutInflater;
105import android.view.View;
106import android.view.WindowManager;
107import android.view.WindowManagerPolicy;
108
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109import java.io.File;
110import java.io.FileDescriptor;
111import java.io.FileInputStream;
112import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200113import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114import java.io.PrintWriter;
115import java.lang.IllegalStateException;
116import java.lang.ref.WeakReference;
117import java.util.ArrayList;
118import java.util.HashMap;
119import java.util.HashSet;
120import java.util.Iterator;
121import java.util.List;
122import java.util.Locale;
123import java.util.Map;
124
125public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
126 static final String TAG = "ActivityManager";
127 static final boolean DEBUG = false;
128 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
129 static final boolean DEBUG_SWITCH = localLOGV || false;
130 static final boolean DEBUG_TASKS = localLOGV || false;
131 static final boolean DEBUG_PAUSE = localLOGV || false;
132 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
133 static final boolean DEBUG_TRANSITION = localLOGV || false;
134 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700135 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 static final boolean DEBUG_SERVICE = localLOGV || false;
137 static final boolean DEBUG_VISBILITY = localLOGV || false;
138 static final boolean DEBUG_PROCESSES = localLOGV || false;
Dianne Hackborna1e989b2009-09-01 19:54:29 -0700139 static final boolean DEBUG_PROVIDER = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700141 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate436344a2009-09-30 16:17:37 -0700142 static final boolean DEBUG_BACKUP = localLOGV || false;
Dianne Hackborndc6b6352009-09-30 14:20:09 -0700143 static final boolean DEBUG_CONFIGURATION = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 static final boolean VALIDATE_TOKENS = false;
145 static final boolean SHOW_ACTIVITY_START_TIME = true;
146
147 // Control over CPU and battery monitoring.
148 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
149 static final boolean MONITOR_CPU_USAGE = true;
150 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
151 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
152 static final boolean MONITOR_THREAD_CPU_USAGE = false;
153
Dianne Hackborn1655be42009-05-08 14:29:01 -0700154 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700155 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700156
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 private static final String SYSTEM_SECURE = "ro.secure";
158
159 // This is the maximum number of application processes we would like
160 // to have running. Due to the asynchronous nature of things, we can
161 // temporarily go beyond this limit.
162 static final int MAX_PROCESSES = 2;
163
164 // Set to false to leave processes running indefinitely, relying on
165 // the kernel killing them as resources are required.
166 static final boolean ENFORCE_PROCESS_LIMIT = false;
167
168 // This is the maximum number of activities that we would like to have
169 // running at a given time.
170 static final int MAX_ACTIVITIES = 20;
171
172 // Maximum number of recent tasks that we can remember.
173 static final int MAX_RECENT_TASKS = 20;
174
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700175 // Amount of time after a call to stopAppSwitches() during which we will
176 // prevent further untrusted switches from happening.
177 static final long APP_SWITCH_DELAY_TIME = 5*1000;
178
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179 // How long until we reset a task when the user returns to it. Currently
180 // 30 minutes.
181 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
182
183 // Set to true to disable the icon that is shown while a new activity
184 // is being started.
185 static final boolean SHOW_APP_STARTING_ICON = true;
186
187 // How long we wait until giving up on the last activity to pause. This
188 // is short because it directly impacts the responsiveness of starting the
189 // next activity.
190 static final int PAUSE_TIMEOUT = 500;
191
192 /**
193 * How long we can hold the launch wake lock before giving up.
194 */
195 static final int LAUNCH_TIMEOUT = 10*1000;
196
197 // How long we wait for a launched process to attach to the activity manager
198 // before we decide it's never going to come up for real.
199 static final int PROC_START_TIMEOUT = 10*1000;
200
201 // How long we wait until giving up on the last activity telling us it
202 // is idle.
203 static final int IDLE_TIMEOUT = 10*1000;
204
205 // How long to wait after going idle before forcing apps to GC.
206 static final int GC_TIMEOUT = 5*1000;
207
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700208 // The minimum amount of time between successive GC requests for a process.
209 static final int GC_MIN_INTERVAL = 60*1000;
210
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 // How long we wait until giving up on an activity telling us it has
212 // finished destroying itself.
213 static final int DESTROY_TIMEOUT = 10*1000;
214
215 // How long we allow a receiver to run before giving up on it.
216 static final int BROADCAST_TIMEOUT = 10*1000;
217
218 // How long we wait for a service to finish executing.
219 static final int SERVICE_TIMEOUT = 20*1000;
220
221 // How long a service needs to be running until restarting its process
222 // is no longer considered to be a relaunch of the service.
223 static final int SERVICE_RESTART_DURATION = 5*1000;
224
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700225 // How long a service needs to be running until it will start back at
226 // SERVICE_RESTART_DURATION after being killed.
227 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
228
229 // Multiplying factor to increase restart duration time by, for each time
230 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
231 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
232
233 // The minimum amount of time between restarting services that we allow.
234 // That is, when multiple services are restarting, we won't allow each
235 // to restart less than this amount of time from the last one.
236 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
237
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238 // Maximum amount of time for there to be no activity on a service before
239 // we consider it non-essential and allow its process to go on the
240 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700241 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242
243 // How long we wait until we timeout on key dispatching.
244 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
245
246 // The minimum time we allow between crashes, for us to consider this
247 // application to be bad and stop and its services and reject broadcasts.
248 static final int MIN_CRASH_INTERVAL = 60*1000;
249
250 // How long we wait until we timeout on key dispatching during instrumentation.
251 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
252
253 // OOM adjustments for processes in various states:
254
255 // This is a process without anything currently running in it. Definitely
256 // the first to go! Value set in system/rootdir/init.rc on startup.
257 // This value is initalized in the constructor, careful when refering to
258 // this static variable externally.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800259 static final int EMPTY_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260
261 // This is a process only hosting activities that are not visible,
262 // so it can be killed without any disruption. Value set in
263 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800264 static final int HIDDEN_APP_MAX_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265 static int HIDDEN_APP_MIN_ADJ;
266
The Android Open Source Project4df24232009-03-05 14:34:35 -0800267 // This is a process holding the home application -- we want to try
268 // avoiding killing it, even if it would normally be in the background,
269 // because the user interacts with it so much.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800270 static final int HOME_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800271
Christopher Tate6fa95972009-06-05 18:43:55 -0700272 // This is a process currently hosting a backup operation. Killing it
273 // is not entirely fatal but is generally a bad idea.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800274 static final int BACKUP_APP_ADJ;
Christopher Tate6fa95972009-06-05 18:43:55 -0700275
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 // This is a process holding a secondary server -- killing it will not
277 // have much of an impact as far as the user is concerned. Value set in
278 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800279 static final int SECONDARY_SERVER_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280
281 // This is a process only hosting activities that are visible to the
282 // user, so we'd prefer they don't disappear. Value set in
283 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800284 static final int VISIBLE_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800285
286 // This is the process running the current foreground app. We'd really
287 // rather not kill it! Value set in system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800288 static final int FOREGROUND_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289
290 // This is a process running a core server, such as telephony. Definitely
291 // don't want to kill it, but doing so is not completely fatal.
292 static final int CORE_SERVER_ADJ = -12;
293
294 // The system process runs at the default adjustment.
295 static final int SYSTEM_ADJ = -16;
296
297 // Memory pages are 4K.
298 static final int PAGE_SIZE = 4*1024;
299
Jacek Surazski82a73df2009-06-17 14:33:18 +0200300 // System property defining error report receiver for system apps
301 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
302
303 // System property defining default error report receiver
304 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
305
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800306 // Corresponding memory levels for above adjustments.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800307 static final int EMPTY_APP_MEM;
308 static final int HIDDEN_APP_MEM;
309 static final int HOME_APP_MEM;
310 static final int BACKUP_APP_MEM;
311 static final int SECONDARY_SERVER_MEM;
312 static final int VISIBLE_APP_MEM;
313 static final int FOREGROUND_APP_MEM;
314
315 // The minimum number of hidden apps we want to be able to keep around,
316 // without empty apps being able to push them out of memory.
317 static final int MIN_HIDDEN_APPS = 2;
318
319 // We put empty content processes after any hidden processes that have
320 // been idle for less than 30 seconds.
321 static final long CONTENT_APP_IDLE_OFFSET = 30*1000;
322
323 // We put empty content processes after any hidden processes that have
324 // been idle for less than 60 seconds.
325 static final long EMPTY_APP_IDLE_OFFSET = 60*1000;
326
327 static {
328 // These values are set in system/rootdir/init.rc on startup.
329 FOREGROUND_APP_ADJ =
330 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
331 VISIBLE_APP_ADJ =
332 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
333 SECONDARY_SERVER_ADJ =
334 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
335 BACKUP_APP_ADJ =
336 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
337 HOME_APP_ADJ =
338 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
339 HIDDEN_APP_MIN_ADJ =
340 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
341 EMPTY_APP_ADJ =
342 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
343 HIDDEN_APP_MAX_ADJ = EMPTY_APP_ADJ-1;
344 FOREGROUND_APP_MEM =
345 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
346 VISIBLE_APP_MEM =
347 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
348 SECONDARY_SERVER_MEM =
349 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
350 BACKUP_APP_MEM =
351 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
352 HOME_APP_MEM =
353 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
354 HIDDEN_APP_MEM =
355 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
356 EMPTY_APP_MEM =
357 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
358 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800359
Dan Egnor42471dd2010-01-07 17:25:22 -0800360 static final int MY_PID = Process.myPid();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800361
362 static final String[] EMPTY_STRING_ARRAY = new String[0];
363
364 enum ActivityState {
365 INITIALIZING,
366 RESUMED,
367 PAUSING,
368 PAUSED,
369 STOPPING,
370 STOPPED,
371 FINISHING,
372 DESTROYING,
373 DESTROYED
374 }
375
376 /**
377 * The back history of all previous (and possibly still
378 * running) activities. It contains HistoryRecord objects.
379 */
380 final ArrayList mHistory = new ArrayList();
381
382 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700383 * Description of a request to start a new activity, which has been held
384 * due to app switches being disabled.
385 */
386 class PendingActivityLaunch {
387 HistoryRecord r;
388 HistoryRecord sourceRecord;
389 Uri[] grantedUriPermissions;
390 int grantedMode;
391 boolean onlyIfNeeded;
392 }
393
394 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
395 = new ArrayList<PendingActivityLaunch>();
396
397 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800398 * List of all active broadcasts that are to be executed immediately
399 * (without waiting for another broadcast to finish). Currently this only
400 * contains broadcasts to registered receivers, to avoid spinning up
401 * a bunch of processes to execute IntentReceiver components.
402 */
403 final ArrayList<BroadcastRecord> mParallelBroadcasts
404 = new ArrayList<BroadcastRecord>();
405
406 /**
407 * List of all active broadcasts that are to be executed one at a time.
408 * The object at the top of the list is the currently activity broadcasts;
409 * those after it are waiting for the top to finish..
410 */
411 final ArrayList<BroadcastRecord> mOrderedBroadcasts
412 = new ArrayList<BroadcastRecord>();
413
414 /**
Dianne Hackborn12527f92009-11-11 17:39:50 -0800415 * Historical data of past broadcasts, for debugging.
416 */
417 static final int MAX_BROADCAST_HISTORY = 100;
418 final BroadcastRecord[] mBroadcastHistory
419 = new BroadcastRecord[MAX_BROADCAST_HISTORY];
420
421 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800422 * Set when we current have a BROADCAST_INTENT_MSG in flight.
423 */
424 boolean mBroadcastsScheduled = false;
425
426 /**
427 * Set to indicate whether to issue an onUserLeaving callback when a
428 * newly launched activity is being brought in front of us.
429 */
430 boolean mUserLeaving = false;
431
432 /**
433 * When we are in the process of pausing an activity, before starting the
434 * next one, this variable holds the activity that is currently being paused.
435 */
436 HistoryRecord mPausingActivity = null;
437
438 /**
439 * Current activity that is resumed, or null if there is none.
440 */
441 HistoryRecord mResumedActivity = null;
442
443 /**
444 * Activity we have told the window manager to have key focus.
445 */
446 HistoryRecord mFocusedActivity = null;
447
448 /**
449 * This is the last activity that we put into the paused state. This is
450 * used to determine if we need to do an activity transition while sleeping,
451 * when we normally hold the top activity paused.
452 */
453 HistoryRecord mLastPausedActivity = null;
454
455 /**
456 * List of activities that are waiting for a new activity
457 * to become visible before completing whatever operation they are
458 * supposed to do.
459 */
460 final ArrayList mWaitingVisibleActivities = new ArrayList();
461
462 /**
463 * List of activities that are ready to be stopped, but waiting
464 * for the next activity to settle down before doing so. It contains
465 * HistoryRecord objects.
466 */
467 final ArrayList<HistoryRecord> mStoppingActivities
468 = new ArrayList<HistoryRecord>();
469
470 /**
Dianne Hackbornbfe319e2009-09-21 00:34:05 -0700471 * Animations that for the current transition have requested not to
472 * be considered for the transition animation.
473 */
474 final ArrayList<HistoryRecord> mNoAnimActivities
475 = new ArrayList<HistoryRecord>();
476
477 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800478 * List of intents that were used to start the most recent tasks.
479 */
480 final ArrayList<TaskRecord> mRecentTasks
481 = new ArrayList<TaskRecord>();
482
483 /**
484 * List of activities that are ready to be finished, but waiting
485 * for the previous activity to settle down before doing so. It contains
486 * HistoryRecord objects.
487 */
488 final ArrayList mFinishingActivities = new ArrayList();
489
490 /**
491 * All of the applications we currently have running organized by name.
492 * The keys are strings of the application package name (as
493 * returned by the package manager), and the keys are ApplicationRecord
494 * objects.
495 */
496 final ProcessMap<ProcessRecord> mProcessNames
497 = new ProcessMap<ProcessRecord>();
498
499 /**
500 * The last time that various processes have crashed.
501 */
502 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
503
504 /**
505 * Set of applications that we consider to be bad, and will reject
506 * incoming broadcasts from (which the user has no control over).
507 * Processes are added to this set when they have crashed twice within
508 * a minimum amount of time; they are removed from it when they are
509 * later restarted (hopefully due to some user action). The value is the
510 * time it was added to the list.
511 */
512 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
513
514 /**
515 * All of the processes we currently have running organized by pid.
516 * The keys are the pid running the application.
517 *
518 * <p>NOTE: This object is protected by its own lock, NOT the global
519 * activity manager lock!
520 */
521 final SparseArray<ProcessRecord> mPidsSelfLocked
522 = new SparseArray<ProcessRecord>();
523
524 /**
525 * All of the processes that have been forced to be foreground. The key
526 * is the pid of the caller who requested it (we hold a death
527 * link on it).
528 */
529 abstract class ForegroundToken implements IBinder.DeathRecipient {
530 int pid;
531 IBinder token;
532 }
533 final SparseArray<ForegroundToken> mForegroundProcesses
534 = new SparseArray<ForegroundToken>();
535
536 /**
537 * List of records for processes that someone had tried to start before the
538 * system was ready. We don't start them at that point, but ensure they
539 * are started by the time booting is complete.
540 */
541 final ArrayList<ProcessRecord> mProcessesOnHold
542 = new ArrayList<ProcessRecord>();
543
544 /**
545 * List of records for processes that we have started and are waiting
546 * for them to call back. This is really only needed when running in
547 * single processes mode, in which case we do not have a unique pid for
548 * each process.
549 */
550 final ArrayList<ProcessRecord> mStartingProcesses
551 = new ArrayList<ProcessRecord>();
552
553 /**
554 * List of persistent applications that are in the process
555 * of being started.
556 */
557 final ArrayList<ProcessRecord> mPersistentStartingProcesses
558 = new ArrayList<ProcessRecord>();
559
560 /**
561 * Processes that are being forcibly torn down.
562 */
563 final ArrayList<ProcessRecord> mRemovedProcesses
564 = new ArrayList<ProcessRecord>();
565
566 /**
567 * List of running applications, sorted by recent usage.
568 * The first entry in the list is the least recently used.
569 * It contains ApplicationRecord objects. This list does NOT include
570 * any persistent application records (since we never want to exit them).
571 */
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800572 final ArrayList<ProcessRecord> mLruProcesses
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800573 = new ArrayList<ProcessRecord>();
574
575 /**
576 * List of processes that should gc as soon as things are idle.
577 */
578 final ArrayList<ProcessRecord> mProcessesToGc
579 = new ArrayList<ProcessRecord>();
580
581 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800582 * This is the process holding what we currently consider to be
583 * the "home" activity.
584 */
585 private ProcessRecord mHomeProcess;
586
587 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 * List of running activities, sorted by recent usage.
589 * The first entry in the list is the least recently used.
590 * It contains HistoryRecord objects.
591 */
592 private final ArrayList mLRUActivities = new ArrayList();
593
594 /**
595 * Set of PendingResultRecord objects that are currently active.
596 */
597 final HashSet mPendingResultRecords = new HashSet();
598
599 /**
600 * Set of IntentSenderRecord objects that are currently active.
601 */
602 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
603 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
604
605 /**
606 * Intent broadcast that we have tried to start, but are
607 * waiting for its application's process to be created. We only
608 * need one (instead of a list) because we always process broadcasts
609 * one at a time, so no others can be started while waiting for this
610 * one.
611 */
612 BroadcastRecord mPendingBroadcast = null;
613
614 /**
615 * Keeps track of all IIntentReceivers that have been registered for
616 * broadcasts. Hash keys are the receiver IBinder, hash value is
617 * a ReceiverList.
618 */
619 final HashMap mRegisteredReceivers = new HashMap();
620
621 /**
622 * Resolver for broadcast intents to registered receivers.
623 * Holds BroadcastFilter (subclass of IntentFilter).
624 */
625 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
626 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
627 @Override
628 protected boolean allowFilterResult(
629 BroadcastFilter filter, List<BroadcastFilter> dest) {
630 IBinder target = filter.receiverList.receiver.asBinder();
631 for (int i=dest.size()-1; i>=0; i--) {
632 if (dest.get(i).receiverList.receiver.asBinder() == target) {
633 return false;
634 }
635 }
636 return true;
637 }
638 };
639
640 /**
641 * State of all active sticky broadcasts. Keys are the action of the
642 * sticky Intent, values are an ArrayList of all broadcasted intents with
643 * that action (which should usually be one).
644 */
645 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
646 new HashMap<String, ArrayList<Intent>>();
647
648 /**
649 * All currently running services.
650 */
651 final HashMap<ComponentName, ServiceRecord> mServices =
652 new HashMap<ComponentName, ServiceRecord>();
653
654 /**
655 * All currently running services indexed by the Intent used to start them.
656 */
657 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
658 new HashMap<Intent.FilterComparison, ServiceRecord>();
659
660 /**
661 * All currently bound service connections. Keys are the IBinder of
662 * the client's IServiceConnection.
663 */
664 final HashMap<IBinder, ConnectionRecord> mServiceConnections
665 = new HashMap<IBinder, ConnectionRecord>();
666
667 /**
668 * List of services that we have been asked to start,
669 * but haven't yet been able to. It is used to hold start requests
670 * while waiting for their corresponding application thread to get
671 * going.
672 */
673 final ArrayList<ServiceRecord> mPendingServices
674 = new ArrayList<ServiceRecord>();
675
676 /**
677 * List of services that are scheduled to restart following a crash.
678 */
679 final ArrayList<ServiceRecord> mRestartingServices
680 = new ArrayList<ServiceRecord>();
681
682 /**
683 * List of services that are in the process of being stopped.
684 */
685 final ArrayList<ServiceRecord> mStoppingServices
686 = new ArrayList<ServiceRecord>();
687
688 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700689 * Backup/restore process management
690 */
691 String mBackupAppName = null;
692 BackupRecord mBackupTarget = null;
693
694 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800695 * List of PendingThumbnailsRecord objects of clients who are still
696 * waiting to receive all of the thumbnails for a task.
697 */
698 final ArrayList mPendingThumbnails = new ArrayList();
699
700 /**
701 * List of HistoryRecord objects that have been finished and must
702 * still report back to a pending thumbnail receiver.
703 */
704 final ArrayList mCancelledThumbnails = new ArrayList();
705
706 /**
707 * All of the currently running global content providers. Keys are a
708 * string containing the provider name and values are a
709 * ContentProviderRecord object containing the data about it. Note
710 * that a single provider may be published under multiple names, so
711 * there may be multiple entries here for a single one in mProvidersByClass.
712 */
713 final HashMap mProvidersByName = new HashMap();
714
715 /**
716 * All of the currently running global content providers. Keys are a
717 * string containing the provider's implementation class and values are a
718 * ContentProviderRecord object containing the data about it.
719 */
720 final HashMap mProvidersByClass = new HashMap();
721
722 /**
723 * List of content providers who have clients waiting for them. The
724 * application is currently being launched and the provider will be
725 * removed from this list once it is published.
726 */
727 final ArrayList mLaunchingProviders = new ArrayList();
728
729 /**
730 * Global set of specific Uri permissions that have been granted.
731 */
732 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
733 = new SparseArray<HashMap<Uri, UriPermission>>();
734
735 /**
736 * Thread-local storage used to carry caller permissions over through
737 * indirect content-provider access.
738 * @see #ActivityManagerService.openContentUri()
739 */
740 private class Identity {
741 public int pid;
742 public int uid;
743
744 Identity(int _pid, int _uid) {
745 pid = _pid;
746 uid = _uid;
747 }
748 }
749 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
750
751 /**
752 * All information we have collected about the runtime performance of
753 * any user id that can impact battery performance.
754 */
755 final BatteryStatsService mBatteryStatsService;
756
757 /**
758 * information about component usage
759 */
760 final UsageStatsService mUsageStatsService;
761
762 /**
763 * Current configuration information. HistoryRecord objects are given
764 * a reference to this object to indicate which configuration they are
765 * currently running in, so this object must be kept immutable.
766 */
767 Configuration mConfiguration = new Configuration();
768
769 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700770 * Hardware-reported OpenGLES version.
771 */
772 final int GL_ES_VERSION;
773
774 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800775 * List of initialization arguments to pass to all processes when binding applications to them.
776 * For example, references to the commonly used services.
777 */
778 HashMap<String, IBinder> mAppBindArgs;
779
780 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700781 * Temporary to avoid allocations. Protected by main lock.
782 */
783 final StringBuilder mStringBuilder = new StringBuilder(256);
784
785 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800786 * Used to control how we initialize the service.
787 */
788 boolean mStartRunning = false;
789 ComponentName mTopComponent;
790 String mTopAction;
791 String mTopData;
792 boolean mSystemReady = false;
793 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700794 boolean mWaitingUpdate = false;
795 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800796
797 Context mContext;
798
799 int mFactoryTest;
800
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700801 boolean mCheckedForSetup;
802
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800803 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700804 * The time at which we will allow normal application switches again,
805 * after a call to {@link #stopAppSwitches()}.
806 */
807 long mAppSwitchesAllowedTime;
808
809 /**
810 * This is set to true after the first switch after mAppSwitchesAllowedTime
811 * is set; any switches after that will clear the time.
812 */
813 boolean mDidAppSwitch;
814
815 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800816 * Set while we are wanting to sleep, to prevent any
817 * activities from being started/resumed.
818 */
819 boolean mSleeping = false;
820
821 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700822 * Set if we are shutting down the system, similar to sleeping.
823 */
824 boolean mShuttingDown = false;
825
826 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800827 * Set when the system is going to sleep, until we have
828 * successfully paused the current activity and released our wake lock.
829 * At that point the system is allowed to actually sleep.
830 */
831 PowerManager.WakeLock mGoingToSleep;
832
833 /**
834 * We don't want to allow the device to go to sleep while in the process
835 * of launching an activity. This is primarily to allow alarm intent
836 * receivers to launch an activity and get that to run before the device
837 * goes back to sleep.
838 */
839 PowerManager.WakeLock mLaunchingActivity;
840
841 /**
842 * Task identifier that activities are currently being started
843 * in. Incremented each time a new task is created.
844 * todo: Replace this with a TokenSpace class that generates non-repeating
845 * integers that won't wrap.
846 */
847 int mCurTask = 1;
848
849 /**
850 * Current sequence id for oom_adj computation traversal.
851 */
852 int mAdjSeq = 0;
853
854 /**
855 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
856 * is set, indicating the user wants processes started in such a way
857 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
858 * running in each process (thus no pre-initialized process, etc).
859 */
860 boolean mSimpleProcessManagement = false;
861
862 /**
863 * System monitoring: number of processes that died since the last
864 * N procs were started.
865 */
866 int[] mProcDeaths = new int[20];
867
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700868 /**
869 * This is set if we had to do a delayed dexopt of an app before launching
870 * it, to increasing the ANR timeouts in that case.
871 */
872 boolean mDidDexOpt;
873
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800874 String mDebugApp = null;
875 boolean mWaitForDebugger = false;
876 boolean mDebugTransient = false;
877 String mOrigDebugApp = null;
878 boolean mOrigWaitForDebugger = false;
879 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700880 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800881
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700882 final RemoteCallbackList<IActivityWatcher> mWatchers
883 = new RemoteCallbackList<IActivityWatcher>();
884
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800885 /**
886 * Callback of last caller to {@link #requestPss}.
887 */
888 Runnable mRequestPssCallback;
889
890 /**
891 * Remaining processes for which we are waiting results from the last
892 * call to {@link #requestPss}.
893 */
894 final ArrayList<ProcessRecord> mRequestPssList
895 = new ArrayList<ProcessRecord>();
896
897 /**
898 * Runtime statistics collection thread. This object's lock is used to
899 * protect all related state.
900 */
901 final Thread mProcessStatsThread;
902
903 /**
904 * Used to collect process stats when showing not responding dialog.
905 * Protected by mProcessStatsThread.
906 */
907 final ProcessStats mProcessStats = new ProcessStats(
908 MONITOR_THREAD_CPU_USAGE);
909 long mLastCpuTime = 0;
910 long mLastWriteTime = 0;
911
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700912 long mInitialStartTime = 0;
913
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800914 /**
915 * Set to true after the system has finished booting.
916 */
917 boolean mBooted = false;
918
919 int mProcessLimit = 0;
920
921 WindowManagerService mWindowManager;
922
923 static ActivityManagerService mSelf;
924 static ActivityThread mSystemThread;
925
926 private final class AppDeathRecipient implements IBinder.DeathRecipient {
927 final ProcessRecord mApp;
928 final int mPid;
929 final IApplicationThread mAppThread;
930
931 AppDeathRecipient(ProcessRecord app, int pid,
932 IApplicationThread thread) {
933 if (localLOGV) Log.v(
934 TAG, "New death recipient " + this
935 + " for thread " + thread.asBinder());
936 mApp = app;
937 mPid = pid;
938 mAppThread = thread;
939 }
940
941 public void binderDied() {
942 if (localLOGV) Log.v(
943 TAG, "Death received in " + this
944 + " for thread " + mAppThread.asBinder());
945 removeRequestedPss(mApp);
946 synchronized(ActivityManagerService.this) {
947 appDiedLocked(mApp, mPid, mAppThread);
948 }
949 }
950 }
951
952 static final int SHOW_ERROR_MSG = 1;
953 static final int SHOW_NOT_RESPONDING_MSG = 2;
954 static final int SHOW_FACTORY_ERROR_MSG = 3;
955 static final int UPDATE_CONFIGURATION_MSG = 4;
956 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
957 static final int WAIT_FOR_DEBUGGER_MSG = 6;
958 static final int BROADCAST_INTENT_MSG = 7;
959 static final int BROADCAST_TIMEOUT_MSG = 8;
960 static final int PAUSE_TIMEOUT_MSG = 9;
961 static final int IDLE_TIMEOUT_MSG = 10;
962 static final int IDLE_NOW_MSG = 11;
963 static final int SERVICE_TIMEOUT_MSG = 12;
964 static final int UPDATE_TIME_ZONE = 13;
965 static final int SHOW_UID_ERROR_MSG = 14;
966 static final int IM_FEELING_LUCKY_MSG = 15;
967 static final int LAUNCH_TIMEOUT_MSG = 16;
968 static final int DESTROY_TIMEOUT_MSG = 17;
969 static final int SERVICE_ERROR_MSG = 18;
970 static final int RESUME_TOP_ACTIVITY_MSG = 19;
971 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700972 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700973 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800974
975 AlertDialog mUidAlert;
976
977 final Handler mHandler = new Handler() {
978 //public Handler() {
979 // if (localLOGV) Log.v(TAG, "Handler started!");
980 //}
981
982 public void handleMessage(Message msg) {
983 switch (msg.what) {
984 case SHOW_ERROR_MSG: {
985 HashMap data = (HashMap) msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986 synchronized (ActivityManagerService.this) {
987 ProcessRecord proc = (ProcessRecord)data.get("app");
988 if (proc != null && proc.crashDialog != null) {
989 Log.e(TAG, "App already has crash dialog: " + proc);
990 return;
991 }
992 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700993 if (!mSleeping && !mShuttingDown) {
Dan Egnorb7f03672009-12-09 16:22:32 -0800994 Dialog d = new AppErrorDialog(mContext, res, proc);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995 d.show();
996 proc.crashDialog = d;
997 } else {
998 // The device is asleep, so just pretend that the user
999 // saw a crash dialog and hit "force quit".
1000 res.set(0);
1001 }
1002 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001003
1004 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001005 } break;
1006 case SHOW_NOT_RESPONDING_MSG: {
1007 synchronized (ActivityManagerService.this) {
1008 HashMap data = (HashMap) msg.obj;
1009 ProcessRecord proc = (ProcessRecord)data.get("app");
1010 if (proc != null && proc.anrDialog != null) {
1011 Log.e(TAG, "App already has anr dialog: " + proc);
1012 return;
1013 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001014
1015 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
1016 null, null, 0, null, null, null,
1017 false, false, MY_PID, Process.SYSTEM_UID);
1018
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001019 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
1020 mContext, proc, (HistoryRecord)data.get("activity"));
1021 d.show();
1022 proc.anrDialog = d;
1023 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001024
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001025 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001026 } break;
1027 case SHOW_FACTORY_ERROR_MSG: {
1028 Dialog d = new FactoryErrorDialog(
1029 mContext, msg.getData().getCharSequence("msg"));
1030 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001031 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001032 } break;
1033 case UPDATE_CONFIGURATION_MSG: {
1034 final ContentResolver resolver = mContext.getContentResolver();
1035 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1036 } break;
1037 case GC_BACKGROUND_PROCESSES_MSG: {
1038 synchronized (ActivityManagerService.this) {
1039 performAppGcsIfAppropriateLocked();
1040 }
1041 } break;
1042 case WAIT_FOR_DEBUGGER_MSG: {
1043 synchronized (ActivityManagerService.this) {
1044 ProcessRecord app = (ProcessRecord)msg.obj;
1045 if (msg.arg1 != 0) {
1046 if (!app.waitedForDebugger) {
1047 Dialog d = new AppWaitingForDebuggerDialog(
1048 ActivityManagerService.this,
1049 mContext, app);
1050 app.waitDialog = d;
1051 app.waitedForDebugger = true;
1052 d.show();
1053 }
1054 } else {
1055 if (app.waitDialog != null) {
1056 app.waitDialog.dismiss();
1057 app.waitDialog = null;
1058 }
1059 }
1060 }
1061 } break;
1062 case BROADCAST_INTENT_MSG: {
1063 if (DEBUG_BROADCAST) Log.v(
1064 TAG, "Received BROADCAST_INTENT_MSG");
1065 processNextBroadcast(true);
1066 } break;
1067 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001068 if (mDidDexOpt) {
1069 mDidDexOpt = false;
1070 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1071 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1072 return;
1073 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001074 broadcastTimeout();
1075 } break;
1076 case PAUSE_TIMEOUT_MSG: {
1077 IBinder token = (IBinder)msg.obj;
1078 // We don't at this point know if the activity is fullscreen,
1079 // so we need to be conservative and assume it isn't.
1080 Log.w(TAG, "Activity pause timeout for " + token);
1081 activityPaused(token, null, true);
1082 } break;
1083 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001084 if (mDidDexOpt) {
1085 mDidDexOpt = false;
1086 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1087 nmsg.obj = msg.obj;
1088 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1089 return;
1090 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001091 // We don't at this point know if the activity is fullscreen,
1092 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001093 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094 Log.w(TAG, "Activity idle timeout for " + token);
Dianne Hackborne88846e2009-09-30 21:34:25 -07001095 activityIdleInternal(token, true, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001096 } break;
1097 case DESTROY_TIMEOUT_MSG: {
1098 IBinder token = (IBinder)msg.obj;
1099 // We don't at this point know if the activity is fullscreen,
1100 // so we need to be conservative and assume it isn't.
1101 Log.w(TAG, "Activity destroy timeout for " + token);
1102 activityDestroyed(token);
1103 } break;
1104 case IDLE_NOW_MSG: {
1105 IBinder token = (IBinder)msg.obj;
Dianne Hackborne88846e2009-09-30 21:34:25 -07001106 activityIdle(token, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001107 } break;
1108 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001109 if (mDidDexOpt) {
1110 mDidDexOpt = false;
1111 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1112 nmsg.obj = msg.obj;
1113 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1114 return;
1115 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001116 serviceTimeout((ProcessRecord)msg.obj);
1117 } break;
1118 case UPDATE_TIME_ZONE: {
1119 synchronized (ActivityManagerService.this) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001120 for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
1121 ProcessRecord r = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001122 if (r.thread != null) {
1123 try {
1124 r.thread.updateTimeZone();
1125 } catch (RemoteException ex) {
1126 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1127 }
1128 }
1129 }
1130 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001131 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001132 case SHOW_UID_ERROR_MSG: {
1133 // XXX This is a temporary dialog, no need to localize.
1134 AlertDialog d = new BaseErrorDialog(mContext);
1135 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1136 d.setCancelable(false);
1137 d.setTitle("System UIDs Inconsistent");
1138 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1139 d.setButton("I'm Feeling Lucky",
1140 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1141 mUidAlert = d;
1142 d.show();
1143 } break;
1144 case IM_FEELING_LUCKY_MSG: {
1145 if (mUidAlert != null) {
1146 mUidAlert.dismiss();
1147 mUidAlert = null;
1148 }
1149 } break;
1150 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001151 if (mDidDexOpt) {
1152 mDidDexOpt = false;
1153 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1154 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1155 return;
1156 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001157 synchronized (ActivityManagerService.this) {
1158 if (mLaunchingActivity.isHeld()) {
1159 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1160 mLaunchingActivity.release();
1161 }
1162 }
1163 } break;
1164 case SERVICE_ERROR_MSG: {
1165 ServiceRecord srv = (ServiceRecord)msg.obj;
1166 // This needs to be *un*synchronized to avoid deadlock.
1167 Checkin.logEvent(mContext.getContentResolver(),
1168 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1169 srv.name.toShortString());
1170 } break;
1171 case RESUME_TOP_ACTIVITY_MSG: {
1172 synchronized (ActivityManagerService.this) {
1173 resumeTopActivityLocked(null);
1174 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001175 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001177 if (mDidDexOpt) {
1178 mDidDexOpt = false;
1179 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1180 nmsg.obj = msg.obj;
1181 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1182 return;
1183 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184 ProcessRecord app = (ProcessRecord)msg.obj;
1185 synchronized (ActivityManagerService.this) {
1186 processStartTimedOutLocked(app);
1187 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001188 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001189 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1190 synchronized (ActivityManagerService.this) {
1191 doPendingActivityLaunchesLocked(true);
1192 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001193 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001194 case KILL_APPLICATION_MSG: {
1195 synchronized (ActivityManagerService.this) {
1196 int uid = msg.arg1;
1197 boolean restart = (msg.arg2 == 1);
1198 String pkg = (String) msg.obj;
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08001199 forceStopPackageLocked(pkg, uid, restart, false);
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001200 }
1201 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001202 }
1203 }
1204 };
1205
1206 public static void setSystemProcess() {
1207 try {
1208 ActivityManagerService m = mSelf;
1209
1210 ServiceManager.addService("activity", m);
1211 ServiceManager.addService("meminfo", new MemBinder(m));
1212 if (MONITOR_CPU_USAGE) {
1213 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1214 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001215 ServiceManager.addService("permission", new PermissionController(m));
1216
1217 ApplicationInfo info =
1218 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001219 "android", STOCK_PM_FLAGS);
Mike Cleron432b7132009-09-24 15:28:29 -07001220 mSystemThread.installSystemApplicationInfo(info);
1221
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001222 synchronized (mSelf) {
1223 ProcessRecord app = mSelf.newProcessRecordLocked(
1224 mSystemThread.getApplicationThread(), info,
1225 info.processName);
1226 app.persistent = true;
Dan Egnor42471dd2010-01-07 17:25:22 -08001227 app.pid = MY_PID;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001228 app.maxAdj = SYSTEM_ADJ;
1229 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1230 synchronized (mSelf.mPidsSelfLocked) {
1231 mSelf.mPidsSelfLocked.put(app.pid, app);
1232 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001233 mSelf.updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001234 }
1235 } catch (PackageManager.NameNotFoundException e) {
1236 throw new RuntimeException(
1237 "Unable to find android system package", e);
1238 }
1239 }
1240
1241 public void setWindowManager(WindowManagerService wm) {
1242 mWindowManager = wm;
1243 }
1244
1245 public static final Context main(int factoryTest) {
1246 AThread thr = new AThread();
1247 thr.start();
1248
1249 synchronized (thr) {
1250 while (thr.mService == null) {
1251 try {
1252 thr.wait();
1253 } catch (InterruptedException e) {
1254 }
1255 }
1256 }
1257
1258 ActivityManagerService m = thr.mService;
1259 mSelf = m;
1260 ActivityThread at = ActivityThread.systemMain();
1261 mSystemThread = at;
1262 Context context = at.getSystemContext();
1263 m.mContext = context;
1264 m.mFactoryTest = factoryTest;
1265 PowerManager pm =
1266 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1267 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1268 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1269 m.mLaunchingActivity.setReferenceCounted(false);
1270
1271 m.mBatteryStatsService.publish(context);
1272 m.mUsageStatsService.publish(context);
1273
1274 synchronized (thr) {
1275 thr.mReady = true;
1276 thr.notifyAll();
1277 }
1278
1279 m.startRunning(null, null, null, null);
1280
1281 return context;
1282 }
1283
1284 public static ActivityManagerService self() {
1285 return mSelf;
1286 }
1287
1288 static class AThread extends Thread {
1289 ActivityManagerService mService;
1290 boolean mReady = false;
1291
1292 public AThread() {
1293 super("ActivityManager");
1294 }
1295
1296 public void run() {
1297 Looper.prepare();
1298
1299 android.os.Process.setThreadPriority(
1300 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1301
1302 ActivityManagerService m = new ActivityManagerService();
1303
1304 synchronized (this) {
1305 mService = m;
1306 notifyAll();
1307 }
1308
1309 synchronized (this) {
1310 while (!mReady) {
1311 try {
1312 wait();
1313 } catch (InterruptedException e) {
1314 }
1315 }
1316 }
1317
1318 Looper.loop();
1319 }
1320 }
1321
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001322 static class MemBinder extends Binder {
1323 ActivityManagerService mActivityManagerService;
1324 MemBinder(ActivityManagerService activityManagerService) {
1325 mActivityManagerService = activityManagerService;
1326 }
1327
1328 @Override
1329 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1330 ActivityManagerService service = mActivityManagerService;
1331 ArrayList<ProcessRecord> procs;
1332 synchronized (mActivityManagerService) {
1333 if (args != null && args.length > 0
1334 && args[0].charAt(0) != '-') {
1335 procs = new ArrayList<ProcessRecord>();
1336 int pid = -1;
1337 try {
1338 pid = Integer.parseInt(args[0]);
1339 } catch (NumberFormatException e) {
1340
1341 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001342 for (int i=service.mLruProcesses.size()-1; i>=0; i--) {
1343 ProcessRecord proc = service.mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001344 if (proc.pid == pid) {
1345 procs.add(proc);
1346 } else if (proc.processName.equals(args[0])) {
1347 procs.add(proc);
1348 }
1349 }
1350 if (procs.size() <= 0) {
1351 pw.println("No process found for: " + args[0]);
1352 return;
1353 }
1354 } else {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001355 procs = service.mLruProcesses;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001356 }
1357 }
1358 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1359 }
1360 }
1361
1362 static class CpuBinder extends Binder {
1363 ActivityManagerService mActivityManagerService;
1364 CpuBinder(ActivityManagerService activityManagerService) {
1365 mActivityManagerService = activityManagerService;
1366 }
1367
1368 @Override
1369 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1370 synchronized (mActivityManagerService.mProcessStatsThread) {
1371 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1372 }
1373 }
1374 }
1375
1376 private ActivityManagerService() {
1377 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1378 if (v != null && Integer.getInteger(v) != 0) {
1379 mSimpleProcessManagement = true;
1380 }
1381 v = System.getenv("ANDROID_DEBUG_APP");
1382 if (v != null) {
1383 mSimpleProcessManagement = true;
1384 }
1385
Dianne Hackborn2c6c5e62009-10-08 17:55:49 -07001386 Log.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
1387
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001388 File dataDir = Environment.getDataDirectory();
1389 File systemDir = new File(dataDir, "system");
1390 systemDir.mkdirs();
1391 mBatteryStatsService = new BatteryStatsService(new File(
1392 systemDir, "batterystats.bin").toString());
1393 mBatteryStatsService.getActiveStatistics().readLocked();
1394 mBatteryStatsService.getActiveStatistics().writeLocked();
1395
1396 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001397 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398
Jack Palevichb90d28c2009-07-22 15:35:24 -07001399 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1400 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1401
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001402 mConfiguration.makeDefault();
1403 mProcessStats.init();
1404
1405 // Add ourself to the Watchdog monitors.
1406 Watchdog.getInstance().addMonitor(this);
1407
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001408 mProcessStatsThread = new Thread("ProcessStats") {
1409 public void run() {
1410 while (true) {
1411 try {
1412 try {
1413 synchronized(this) {
1414 final long now = SystemClock.uptimeMillis();
1415 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1416 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1417 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1418 // + ", write delay=" + nextWriteDelay);
1419 if (nextWriteDelay < nextCpuDelay) {
1420 nextCpuDelay = nextWriteDelay;
1421 }
1422 if (nextCpuDelay > 0) {
1423 this.wait(nextCpuDelay);
1424 }
1425 }
1426 } catch (InterruptedException e) {
1427 }
1428
1429 updateCpuStatsNow();
1430 } catch (Exception e) {
1431 Log.e(TAG, "Unexpected exception collecting process stats", e);
1432 }
1433 }
1434 }
1435 };
1436 mProcessStatsThread.start();
1437 }
1438
1439 @Override
1440 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1441 throws RemoteException {
1442 try {
1443 return super.onTransact(code, data, reply, flags);
1444 } catch (RuntimeException e) {
1445 // The activity manager only throws security exceptions, so let's
1446 // log all others.
1447 if (!(e instanceof SecurityException)) {
1448 Log.e(TAG, "Activity Manager Crash", e);
1449 }
1450 throw e;
1451 }
1452 }
1453
1454 void updateCpuStats() {
1455 synchronized (mProcessStatsThread) {
1456 final long now = SystemClock.uptimeMillis();
1457 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1458 mProcessStatsThread.notify();
1459 }
1460 }
1461 }
1462
1463 void updateCpuStatsNow() {
1464 synchronized (mProcessStatsThread) {
1465 final long now = SystemClock.uptimeMillis();
1466 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001467
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001468 if (MONITOR_CPU_USAGE &&
1469 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1470 mLastCpuTime = now;
1471 haveNewCpuStats = true;
1472 mProcessStats.update();
1473 //Log.i(TAG, mProcessStats.printCurrentState());
1474 //Log.i(TAG, "Total CPU usage: "
1475 // + mProcessStats.getTotalCpuPercent() + "%");
1476
1477 // Log the cpu usage if the property is set.
1478 if ("true".equals(SystemProperties.get("events.cpu"))) {
1479 int user = mProcessStats.getLastUserTime();
1480 int system = mProcessStats.getLastSystemTime();
1481 int iowait = mProcessStats.getLastIoWaitTime();
1482 int irq = mProcessStats.getLastIrqTime();
1483 int softIrq = mProcessStats.getLastSoftIrqTime();
1484 int idle = mProcessStats.getLastIdleTime();
1485
1486 int total = user + system + iowait + irq + softIrq + idle;
1487 if (total == 0) total = 1;
1488
Doug Zongker2bec3d42009-12-04 12:52:44 -08001489 EventLog.writeEvent(EventLogTags.CPU,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001490 ((user+system+iowait+irq+softIrq) * 100) / total,
1491 (user * 100) / total,
1492 (system * 100) / total,
1493 (iowait * 100) / total,
1494 (irq * 100) / total,
1495 (softIrq * 100) / total);
1496 }
1497 }
1498
Amith Yamasanie43530a2009-08-21 13:11:37 -07001499 long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
Amith Yamasani819f9282009-06-24 23:18:15 -07001500 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001501 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001502 synchronized(mPidsSelfLocked) {
1503 if (haveNewCpuStats) {
1504 if (mBatteryStatsService.isOnBattery()) {
1505 final int N = mProcessStats.countWorkingStats();
1506 for (int i=0; i<N; i++) {
1507 ProcessStats.Stats st
1508 = mProcessStats.getWorkingStats(i);
1509 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1510 if (pr != null) {
1511 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1512 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001513 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001514 } else {
1515 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001516 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001517 if (ps != null) {
1518 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001519 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001520 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001521 }
1522 }
1523 }
1524 }
1525 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001526
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001527 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1528 mLastWriteTime = now;
1529 mBatteryStatsService.getActiveStatistics().writeLocked();
1530 }
1531 }
1532 }
1533 }
1534
1535 /**
1536 * Initialize the application bind args. These are passed to each
1537 * process when the bindApplication() IPC is sent to the process. They're
1538 * lazily setup to make sure the services are running when they're asked for.
1539 */
1540 private HashMap<String, IBinder> getCommonServicesLocked() {
1541 if (mAppBindArgs == null) {
1542 mAppBindArgs = new HashMap<String, IBinder>();
1543
1544 // Setup the application init args
1545 mAppBindArgs.put("package", ServiceManager.getService("package"));
1546 mAppBindArgs.put("window", ServiceManager.getService("window"));
1547 mAppBindArgs.put(Context.ALARM_SERVICE,
1548 ServiceManager.getService(Context.ALARM_SERVICE));
1549 }
1550 return mAppBindArgs;
1551 }
1552
1553 private final void setFocusedActivityLocked(HistoryRecord r) {
1554 if (mFocusedActivity != r) {
1555 mFocusedActivity = r;
1556 mWindowManager.setFocusedApp(r, true);
1557 }
1558 }
1559
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001560 private final void updateLruProcessLocked(ProcessRecord app,
1561 boolean oomAdj, boolean updateActivityTime) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001562 // put it on the LRU to keep track of when it should be exited.
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001563 int lrui = mLruProcesses.indexOf(app);
1564 if (lrui >= 0) mLruProcesses.remove(lrui);
1565
1566 int i = mLruProcesses.size()-1;
1567 int skipTop = 0;
1568
1569 // compute the new weight for this process.
1570 if (updateActivityTime) {
1571 app.lastActivityTime = SystemClock.uptimeMillis();
1572 }
1573 if (app.activities.size() > 0) {
1574 // If this process has activities, we more strongly want to keep
1575 // it around.
1576 app.lruWeight = app.lastActivityTime;
1577 } else if (app.pubProviders.size() > 0) {
1578 // If this process contains content providers, we want to keep
1579 // it a little more strongly.
1580 app.lruWeight = app.lastActivityTime - CONTENT_APP_IDLE_OFFSET;
1581 // Also don't let it kick out the first few "real" hidden processes.
1582 skipTop = MIN_HIDDEN_APPS;
1583 } else {
1584 // If this process doesn't have activities, we less strongly
1585 // want to keep it around, and generally want to avoid getting
1586 // in front of any very recently used activities.
1587 app.lruWeight = app.lastActivityTime - EMPTY_APP_IDLE_OFFSET;
1588 // Also don't let it kick out the first few "real" hidden processes.
1589 skipTop = MIN_HIDDEN_APPS;
1590 }
1591 while (i >= 0) {
1592 ProcessRecord p = mLruProcesses.get(i);
1593 // If this app shouldn't be in front of the first N background
1594 // apps, then skip over that many that are currently hidden.
1595 if (skipTop > 0 && p.setAdj >= HIDDEN_APP_MIN_ADJ) {
1596 skipTop--;
1597 }
1598 if (p.lruWeight <= app.lruWeight){
1599 mLruProcesses.add(i+1, app);
1600 break;
1601 }
1602 i--;
1603 }
1604 if (i < 0) {
1605 mLruProcesses.add(0, app);
1606 }
1607
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001608 //Log.i(TAG, "Putting proc to front: " + app.processName);
1609 if (oomAdj) {
1610 updateOomAdjLocked();
1611 }
1612 }
1613
1614 private final boolean updateLRUListLocked(HistoryRecord r) {
1615 final boolean hadit = mLRUActivities.remove(r);
1616 mLRUActivities.add(r);
1617 return hadit;
1618 }
1619
1620 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1621 int i = mHistory.size()-1;
1622 while (i >= 0) {
1623 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1624 if (!r.finishing && r != notTop) {
1625 return r;
1626 }
1627 i--;
1628 }
1629 return null;
1630 }
1631
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001632 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1633 int i = mHistory.size()-1;
1634 while (i >= 0) {
1635 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1636 if (!r.finishing && !r.delayedResume && r != notTop) {
1637 return r;
1638 }
1639 i--;
1640 }
1641 return null;
1642 }
1643
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001644 /**
1645 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001646 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001647 *
1648 * @param token If non-null, any history records matching this token will be skipped.
1649 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1650 *
1651 * @return Returns the HistoryRecord of the next activity on the stack.
1652 */
1653 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1654 int i = mHistory.size()-1;
1655 while (i >= 0) {
1656 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1657 // Note: the taskId check depends on real taskId fields being non-zero
1658 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1659 return r;
1660 }
1661 i--;
1662 }
1663 return null;
1664 }
1665
1666 private final ProcessRecord getProcessRecordLocked(
1667 String processName, int uid) {
1668 if (uid == Process.SYSTEM_UID) {
1669 // The system gets to run in any process. If there are multiple
1670 // processes with the same uid, just pick the first (this
1671 // should never happen).
1672 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1673 processName);
1674 return procs != null ? procs.valueAt(0) : null;
1675 }
1676 ProcessRecord proc = mProcessNames.get(processName, uid);
1677 return proc;
1678 }
1679
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001680 private void ensurePackageDexOpt(String packageName) {
1681 IPackageManager pm = ActivityThread.getPackageManager();
1682 try {
1683 if (pm.performDexOpt(packageName)) {
1684 mDidDexOpt = true;
1685 }
1686 } catch (RemoteException e) {
1687 }
1688 }
1689
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 private boolean isNextTransitionForward() {
1691 int transit = mWindowManager.getPendingAppTransition();
1692 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1693 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1694 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1695 }
1696
1697 private final boolean realStartActivityLocked(HistoryRecord r,
1698 ProcessRecord app, boolean andResume, boolean checkConfig)
1699 throws RemoteException {
1700
1701 r.startFreezingScreenLocked(app, 0);
1702 mWindowManager.setAppVisibility(r, true);
1703
1704 // Have the window manager re-evaluate the orientation of
1705 // the screen based on the new activity order. Note that
1706 // as a result of this, it can call back into the activity
1707 // manager with a new orientation. We don't care about that,
1708 // because the activity is not currently running so we are
1709 // just restarting it anyway.
1710 if (checkConfig) {
1711 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001712 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 r.mayFreezeScreenLocked(app) ? r : null);
1714 updateConfigurationLocked(config, r);
1715 }
1716
1717 r.app = app;
1718
1719 if (localLOGV) Log.v(TAG, "Launching: " + r);
1720
1721 int idx = app.activities.indexOf(r);
1722 if (idx < 0) {
1723 app.activities.add(r);
1724 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001725 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001726
1727 try {
1728 if (app.thread == null) {
1729 throw new RemoteException();
1730 }
1731 List<ResultInfo> results = null;
1732 List<Intent> newIntents = null;
1733 if (andResume) {
1734 results = r.results;
1735 newIntents = r.newIntents;
1736 }
1737 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1738 + " icicle=" + r.icicle
1739 + " with results=" + results + " newIntents=" + newIntents
1740 + " andResume=" + andResume);
1741 if (andResume) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08001742 EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 System.identityHashCode(r),
1744 r.task.taskId, r.shortComponentName);
1745 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001746 if (r.isHomeActivity) {
1747 mHomeProcess = app;
1748 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001749 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001750 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001751 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001752 r.info, r.icicle, results, newIntents, !andResume,
1753 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001754 } catch (RemoteException e) {
1755 if (r.launchFailed) {
1756 // This is the second time we failed -- finish activity
1757 // and give up.
1758 Log.e(TAG, "Second failure launching "
1759 + r.intent.getComponent().flattenToShortString()
1760 + ", giving up", e);
1761 appDiedLocked(app, app.pid, app.thread);
1762 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1763 "2nd-crash");
1764 return false;
1765 }
1766
1767 // This is the first time we failed -- restart process and
1768 // retry.
1769 app.activities.remove(r);
1770 throw e;
1771 }
1772
1773 r.launchFailed = false;
1774 if (updateLRUListLocked(r)) {
1775 Log.w(TAG, "Activity " + r
1776 + " being launched, but already in LRU list");
1777 }
1778
1779 if (andResume) {
1780 // As part of the process of launching, ActivityThread also performs
1781 // a resume.
1782 r.state = ActivityState.RESUMED;
1783 r.icicle = null;
1784 r.haveState = false;
1785 r.stopped = false;
1786 mResumedActivity = r;
1787 r.task.touchActiveTime();
1788 completeResumeLocked(r);
1789 pauseIfSleepingLocked();
1790 } else {
1791 // This activity is not starting in the resumed state... which
1792 // should look like we asked it to pause+stop (but remain visible),
1793 // and it has done so and reported back the current icicle and
1794 // other state.
1795 r.state = ActivityState.STOPPED;
1796 r.stopped = true;
1797 }
1798
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001799 // Launch the new version setup screen if needed. We do this -after-
1800 // launching the initial activity (that is, home), so that it can have
1801 // a chance to initialize itself while in the background, making the
1802 // switch back to it faster and look better.
1803 startSetupActivityLocked();
1804
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001805 return true;
1806 }
1807
1808 private final void startSpecificActivityLocked(HistoryRecord r,
1809 boolean andResume, boolean checkConfig) {
1810 // Is this activity's application already running?
1811 ProcessRecord app = getProcessRecordLocked(r.processName,
1812 r.info.applicationInfo.uid);
1813
1814 if (r.startTime == 0) {
1815 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001816 if (mInitialStartTime == 0) {
1817 mInitialStartTime = r.startTime;
1818 }
1819 } else if (mInitialStartTime == 0) {
1820 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001821 }
1822
1823 if (app != null && app.thread != null) {
1824 try {
1825 realStartActivityLocked(r, app, andResume, checkConfig);
1826 return;
1827 } catch (RemoteException e) {
1828 Log.w(TAG, "Exception when starting activity "
1829 + r.intent.getComponent().flattenToShortString(), e);
1830 }
1831
1832 // If a dead object exception was thrown -- fall through to
1833 // restart the application.
1834 }
1835
1836 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001837 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001838 }
1839
1840 private final ProcessRecord startProcessLocked(String processName,
1841 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001842 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001843 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1844 // We don't have to do anything more if:
1845 // (1) There is an existing application record; and
1846 // (2) The caller doesn't think it is dead, OR there is no thread
1847 // object attached to it so we know it couldn't have crashed; and
1848 // (3) There is a pid assigned to it, so it is either starting or
1849 // already running.
1850 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1851 + " app=" + app + " knownToBeDead=" + knownToBeDead
1852 + " thread=" + (app != null ? app.thread : null)
1853 + " pid=" + (app != null ? app.pid : -1));
1854 if (app != null &&
1855 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1856 return app;
1857 }
1858
1859 String hostingNameStr = hostingName != null
1860 ? hostingName.flattenToShortString() : null;
1861
1862 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1863 // If we are in the background, then check to see if this process
1864 // is bad. If so, we will just silently fail.
1865 if (mBadProcesses.get(info.processName, info.uid) != null) {
1866 return null;
1867 }
1868 } else {
1869 // When the user is explicitly starting a process, then clear its
1870 // crash count so that we won't make it bad until they see at
1871 // least one crash dialog again, and make the process good again
1872 // if it had been bad.
1873 mProcessCrashTimes.remove(info.processName, info.uid);
1874 if (mBadProcesses.get(info.processName, info.uid) != null) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08001875 EventLog.writeEvent(EventLogTags.AM_PROC_GOOD, info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001876 info.processName);
1877 mBadProcesses.remove(info.processName, info.uid);
1878 if (app != null) {
1879 app.bad = false;
1880 }
1881 }
1882 }
1883
1884 if (app == null) {
1885 app = newProcessRecordLocked(null, info, processName);
1886 mProcessNames.put(processName, info.uid, app);
1887 } else {
1888 // If this is a new package in the process, add the package to the list
1889 app.addPackage(info.packageName);
1890 }
1891
1892 // If the system is not ready yet, then hold off on starting this
1893 // process until it is.
1894 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001895 && !isAllowedWhileBooting(info)
1896 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001897 if (!mProcessesOnHold.contains(app)) {
1898 mProcessesOnHold.add(app);
1899 }
1900 return app;
1901 }
1902
1903 startProcessLocked(app, hostingType, hostingNameStr);
1904 return (app.pid != 0) ? app : null;
1905 }
1906
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001907 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1908 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1909 }
1910
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001911 private final void startProcessLocked(ProcessRecord app,
1912 String hostingType, String hostingNameStr) {
1913 if (app.pid > 0 && app.pid != MY_PID) {
1914 synchronized (mPidsSelfLocked) {
1915 mPidsSelfLocked.remove(app.pid);
1916 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1917 }
1918 app.pid = 0;
1919 }
1920
1921 mProcessesOnHold.remove(app);
1922
1923 updateCpuStats();
1924
1925 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1926 mProcDeaths[0] = 0;
1927
1928 try {
1929 int uid = app.info.uid;
1930 int[] gids = null;
1931 try {
1932 gids = mContext.getPackageManager().getPackageGids(
1933 app.info.packageName);
1934 } catch (PackageManager.NameNotFoundException e) {
1935 Log.w(TAG, "Unable to retrieve gids", e);
1936 }
1937 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1938 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1939 && mTopComponent != null
1940 && app.processName.equals(mTopComponent.getPackageName())) {
1941 uid = 0;
1942 }
1943 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1944 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1945 uid = 0;
1946 }
1947 }
1948 int debugFlags = 0;
1949 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1950 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1951 }
1952 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1953 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1954 }
1955 if ("1".equals(SystemProperties.get("debug.assert"))) {
1956 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1957 }
1958 int pid = Process.start("android.app.ActivityThread",
1959 mSimpleProcessManagement ? app.processName : null, uid, uid,
1960 gids, debugFlags, null);
1961 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1962 synchronized (bs) {
1963 if (bs.isOnBattery()) {
1964 app.batteryStats.incStartsLocked();
1965 }
1966 }
1967
Doug Zongker2bec3d42009-12-04 12:52:44 -08001968 EventLog.writeEvent(EventLogTags.AM_PROC_START, pid, uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001969 app.processName, hostingType,
1970 hostingNameStr != null ? hostingNameStr : "");
1971
1972 if (app.persistent) {
1973 Watchdog.getInstance().processStarted(app, app.processName, pid);
1974 }
1975
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001976 StringBuilder buf = mStringBuilder;
1977 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001978 buf.append("Start proc ");
1979 buf.append(app.processName);
1980 buf.append(" for ");
1981 buf.append(hostingType);
1982 if (hostingNameStr != null) {
1983 buf.append(" ");
1984 buf.append(hostingNameStr);
1985 }
1986 buf.append(": pid=");
1987 buf.append(pid);
1988 buf.append(" uid=");
1989 buf.append(uid);
1990 buf.append(" gids={");
1991 if (gids != null) {
1992 for (int gi=0; gi<gids.length; gi++) {
1993 if (gi != 0) buf.append(", ");
1994 buf.append(gids[gi]);
1995
1996 }
1997 }
1998 buf.append("}");
1999 Log.i(TAG, buf.toString());
2000 if (pid == 0 || pid == MY_PID) {
2001 // Processes are being emulated with threads.
2002 app.pid = MY_PID;
2003 app.removed = false;
2004 mStartingProcesses.add(app);
2005 } else if (pid > 0) {
2006 app.pid = pid;
2007 app.removed = false;
2008 synchronized (mPidsSelfLocked) {
2009 this.mPidsSelfLocked.put(pid, app);
2010 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2011 msg.obj = app;
2012 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2013 }
2014 } else {
2015 app.pid = 0;
2016 RuntimeException e = new RuntimeException(
2017 "Failure starting process " + app.processName
2018 + ": returned pid=" + pid);
2019 Log.e(TAG, e.getMessage(), e);
2020 }
2021 } catch (RuntimeException e) {
2022 // XXX do better error recovery.
2023 app.pid = 0;
2024 Log.e(TAG, "Failure starting process " + app.processName, e);
2025 }
2026 }
2027
2028 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2029 if (mPausingActivity != null) {
2030 RuntimeException e = new RuntimeException();
2031 Log.e(TAG, "Trying to pause when pause is already pending for "
2032 + mPausingActivity, e);
2033 }
2034 HistoryRecord prev = mResumedActivity;
2035 if (prev == null) {
2036 RuntimeException e = new RuntimeException();
2037 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2038 resumeTopActivityLocked(null);
2039 return;
2040 }
2041 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2042 mResumedActivity = null;
2043 mPausingActivity = prev;
2044 mLastPausedActivity = prev;
2045 prev.state = ActivityState.PAUSING;
2046 prev.task.touchActiveTime();
2047
2048 updateCpuStats();
2049
2050 if (prev.app != null && prev.app.thread != null) {
2051 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2052 try {
Doug Zongker2bec3d42009-12-04 12:52:44 -08002053 EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002054 System.identityHashCode(prev),
2055 prev.shortComponentName);
2056 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2057 prev.configChangeFlags);
2058 updateUsageStats(prev, false);
2059 } catch (Exception e) {
2060 // Ignore exception, if process died other code will cleanup.
2061 Log.w(TAG, "Exception thrown during pause", e);
2062 mPausingActivity = null;
2063 mLastPausedActivity = null;
2064 }
2065 } else {
2066 mPausingActivity = null;
2067 mLastPausedActivity = null;
2068 }
2069
2070 // If we are not going to sleep, we want to ensure the device is
2071 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002072 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002073 mLaunchingActivity.acquire();
2074 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2075 // To be safe, don't allow the wake lock to be held for too long.
2076 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2077 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2078 }
2079 }
2080
2081
2082 if (mPausingActivity != null) {
2083 // Have the window manager pause its key dispatching until the new
2084 // activity has started. If we're pausing the activity just because
2085 // the screen is being turned off and the UI is sleeping, don't interrupt
2086 // key dispatch; the same activity will pick it up again on wakeup.
2087 if (!uiSleeping) {
2088 prev.pauseKeyDispatchingLocked();
2089 } else {
2090 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2091 }
2092
2093 // Schedule a pause timeout in case the app doesn't respond.
2094 // We don't give it much time because this directly impacts the
2095 // responsiveness seen by the user.
2096 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2097 msg.obj = prev;
2098 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2099 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2100 } else {
2101 // This activity failed to schedule the
2102 // pause, so just treat it as being paused now.
2103 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2104 resumeTopActivityLocked(null);
2105 }
2106 }
2107
2108 private final void completePauseLocked() {
2109 HistoryRecord prev = mPausingActivity;
2110 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2111
2112 if (prev != null) {
2113 if (prev.finishing) {
2114 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2115 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2116 } else if (prev.app != null) {
2117 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2118 if (prev.waitingVisible) {
2119 prev.waitingVisible = false;
2120 mWaitingVisibleActivities.remove(prev);
2121 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2122 TAG, "Complete pause, no longer waiting: " + prev);
2123 }
2124 if (prev.configDestroy) {
2125 // The previous is being paused because the configuration
2126 // is changing, which means it is actually stopping...
2127 // To juggle the fact that we are also starting a new
2128 // instance right now, we need to first completely stop
2129 // the current instance before starting the new one.
2130 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2131 destroyActivityLocked(prev, true);
2132 } else {
2133 mStoppingActivities.add(prev);
2134 if (mStoppingActivities.size() > 3) {
2135 // If we already have a few activities waiting to stop,
2136 // then give up on things going idle and start clearing
2137 // them out.
2138 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2139 Message msg = Message.obtain();
2140 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2141 mHandler.sendMessage(msg);
2142 }
2143 }
2144 } else {
2145 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2146 prev = null;
2147 }
2148 mPausingActivity = null;
2149 }
2150
Dianne Hackborn55280a92009-05-07 15:53:46 -07002151 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002152 resumeTopActivityLocked(prev);
2153 } else {
2154 if (mGoingToSleep.isHeld()) {
2155 mGoingToSleep.release();
2156 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002157 if (mShuttingDown) {
2158 notifyAll();
2159 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002160 }
2161
2162 if (prev != null) {
2163 prev.resumeKeyDispatchingLocked();
2164 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002165
2166 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2167 long diff = 0;
2168 synchronized (mProcessStatsThread) {
2169 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2170 }
2171 if (diff > 0) {
2172 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2173 synchronized (bsi) {
2174 BatteryStatsImpl.Uid.Proc ps =
2175 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2176 prev.info.packageName);
2177 if (ps != null) {
2178 ps.addForegroundTimeLocked(diff);
2179 }
2180 }
2181 }
2182 }
2183 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002184 }
2185
2186 /**
2187 * Once we know that we have asked an application to put an activity in
2188 * the resumed state (either by launching it or explicitly telling it),
2189 * this function updates the rest of our state to match that fact.
2190 */
2191 private final void completeResumeLocked(HistoryRecord next) {
2192 next.idle = false;
2193 next.results = null;
2194 next.newIntents = null;
2195
2196 // schedule an idle timeout in case the app doesn't do it for us.
2197 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2198 msg.obj = next;
2199 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2200
2201 if (false) {
2202 // The activity was never told to pause, so just keep
2203 // things going as-is. To maintain our own state,
2204 // we need to emulate it coming back and saying it is
2205 // idle.
2206 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2207 msg.obj = next;
2208 mHandler.sendMessage(msg);
2209 }
2210
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002211 reportResumedActivityLocked(next);
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002212
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002213 next.thumbnail = null;
2214 setFocusedActivityLocked(next);
2215 next.resumeKeyDispatchingLocked();
2216 ensureActivitiesVisibleLocked(null, 0);
2217 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002218 mNoAnimActivities.clear();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002219
2220 // Mark the point when the activity is resuming
2221 // TODO: To be more accurate, the mark should be before the onCreate,
2222 // not after the onResume. But for subsequent starts, onResume is fine.
2223 if (next.app != null) {
2224 synchronized (mProcessStatsThread) {
2225 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2226 }
2227 } else {
2228 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2229 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002230 }
2231
2232 /**
2233 * Make sure that all activities that need to be visible (that is, they
2234 * currently can be seen by the user) actually are.
2235 */
2236 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2237 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2238 if (DEBUG_VISBILITY) Log.v(
2239 TAG, "ensureActivitiesVisible behind " + top
2240 + " configChanges=0x" + Integer.toHexString(configChanges));
2241
2242 // If the top activity is not fullscreen, then we need to
2243 // make sure any activities under it are now visible.
2244 final int count = mHistory.size();
2245 int i = count-1;
2246 while (mHistory.get(i) != top) {
2247 i--;
2248 }
2249 HistoryRecord r;
2250 boolean behindFullscreen = false;
2251 for (; i>=0; i--) {
2252 r = (HistoryRecord)mHistory.get(i);
2253 if (DEBUG_VISBILITY) Log.v(
2254 TAG, "Make visible? " + r + " finishing=" + r.finishing
2255 + " state=" + r.state);
2256 if (r.finishing) {
2257 continue;
2258 }
2259
2260 final boolean doThisProcess = onlyThisProcess == null
2261 || onlyThisProcess.equals(r.processName);
2262
2263 // First: if this is not the current activity being started, make
2264 // sure it matches the current configuration.
2265 if (r != starting && doThisProcess) {
2266 ensureActivityConfigurationLocked(r, 0);
2267 }
2268
2269 if (r.app == null || r.app.thread == null) {
2270 if (onlyThisProcess == null
2271 || onlyThisProcess.equals(r.processName)) {
2272 // This activity needs to be visible, but isn't even
2273 // running... get it started, but don't resume it
2274 // at this point.
2275 if (DEBUG_VISBILITY) Log.v(
2276 TAG, "Start and freeze screen for " + r);
2277 if (r != starting) {
2278 r.startFreezingScreenLocked(r.app, configChanges);
2279 }
2280 if (!r.visible) {
2281 if (DEBUG_VISBILITY) Log.v(
2282 TAG, "Starting and making visible: " + r);
2283 mWindowManager.setAppVisibility(r, true);
2284 }
2285 if (r != starting) {
2286 startSpecificActivityLocked(r, false, false);
2287 }
2288 }
2289
2290 } else if (r.visible) {
2291 // If this activity is already visible, then there is nothing
2292 // else to do here.
2293 if (DEBUG_VISBILITY) Log.v(
2294 TAG, "Skipping: already visible at " + r);
2295 r.stopFreezingScreenLocked(false);
2296
2297 } else if (onlyThisProcess == null) {
2298 // This activity is not currently visible, but is running.
2299 // Tell it to become visible.
2300 r.visible = true;
2301 if (r.state != ActivityState.RESUMED && r != starting) {
2302 // If this activity is paused, tell it
2303 // to now show its window.
2304 if (DEBUG_VISBILITY) Log.v(
2305 TAG, "Making visible and scheduling visibility: " + r);
2306 try {
2307 mWindowManager.setAppVisibility(r, true);
2308 r.app.thread.scheduleWindowVisibility(r, true);
2309 r.stopFreezingScreenLocked(false);
2310 } catch (Exception e) {
2311 // Just skip on any failure; we'll make it
2312 // visible when it next restarts.
2313 Log.w(TAG, "Exception thrown making visibile: "
2314 + r.intent.getComponent(), e);
2315 }
2316 }
2317 }
2318
2319 // Aggregate current change flags.
2320 configChanges |= r.configChangeFlags;
2321
2322 if (r.fullscreen) {
2323 // At this point, nothing else needs to be shown
2324 if (DEBUG_VISBILITY) Log.v(
2325 TAG, "Stopping: fullscreen at " + r);
2326 behindFullscreen = true;
2327 i--;
2328 break;
2329 }
2330 }
2331
2332 // Now for any activities that aren't visible to the user, make
2333 // sure they no longer are keeping the screen frozen.
2334 while (i >= 0) {
2335 r = (HistoryRecord)mHistory.get(i);
2336 if (DEBUG_VISBILITY) Log.v(
2337 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2338 + " state=" + r.state
2339 + " behindFullscreen=" + behindFullscreen);
2340 if (!r.finishing) {
2341 if (behindFullscreen) {
2342 if (r.visible) {
2343 if (DEBUG_VISBILITY) Log.v(
2344 TAG, "Making invisible: " + r);
2345 r.visible = false;
2346 try {
2347 mWindowManager.setAppVisibility(r, false);
2348 if ((r.state == ActivityState.STOPPING
2349 || r.state == ActivityState.STOPPED)
2350 && r.app != null && r.app.thread != null) {
2351 if (DEBUG_VISBILITY) Log.v(
2352 TAG, "Scheduling invisibility: " + r);
2353 r.app.thread.scheduleWindowVisibility(r, false);
2354 }
2355 } catch (Exception e) {
2356 // Just skip on any failure; we'll make it
2357 // visible when it next restarts.
2358 Log.w(TAG, "Exception thrown making hidden: "
2359 + r.intent.getComponent(), e);
2360 }
2361 } else {
2362 if (DEBUG_VISBILITY) Log.v(
2363 TAG, "Already invisible: " + r);
2364 }
2365 } else if (r.fullscreen) {
2366 if (DEBUG_VISBILITY) Log.v(
2367 TAG, "Now behindFullscreen: " + r);
2368 behindFullscreen = true;
2369 }
2370 }
2371 i--;
2372 }
2373 }
2374
2375 /**
2376 * Version of ensureActivitiesVisible that can easily be called anywhere.
2377 */
2378 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2379 int configChanges) {
2380 HistoryRecord r = topRunningActivityLocked(null);
2381 if (r != null) {
2382 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2383 }
2384 }
2385
2386 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2387 if (resumed) {
2388 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2389 } else {
2390 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2391 }
2392 }
2393
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002394 private boolean startHomeActivityLocked() {
2395 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2396 && mTopAction == null) {
2397 // We are running in factory test mode, but unable to find
2398 // the factory test app, so just sit around displaying the
2399 // error message and don't try to start anything.
2400 return false;
2401 }
2402 Intent intent = new Intent(
2403 mTopAction,
2404 mTopData != null ? Uri.parse(mTopData) : null);
2405 intent.setComponent(mTopComponent);
2406 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2407 intent.addCategory(Intent.CATEGORY_HOME);
2408 }
2409 ActivityInfo aInfo =
2410 intent.resolveActivityInfo(mContext.getPackageManager(),
2411 STOCK_PM_FLAGS);
2412 if (aInfo != null) {
2413 intent.setComponent(new ComponentName(
2414 aInfo.applicationInfo.packageName, aInfo.name));
2415 // Don't do this if the home app is currently being
2416 // instrumented.
2417 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2418 aInfo.applicationInfo.uid);
2419 if (app == null || app.instrumentationClass == null) {
2420 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2421 startActivityLocked(null, intent, null, null, 0, aInfo,
2422 null, null, 0, 0, 0, false, false);
2423 }
2424 }
2425
2426
2427 return true;
2428 }
2429
2430 /**
2431 * Starts the "new version setup screen" if appropriate.
2432 */
2433 private void startSetupActivityLocked() {
2434 // Only do this once per boot.
2435 if (mCheckedForSetup) {
2436 return;
2437 }
2438
2439 // We will show this screen if the current one is a different
2440 // version than the last one shown, and we are not running in
2441 // low-level factory test mode.
2442 final ContentResolver resolver = mContext.getContentResolver();
2443 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2444 Settings.Secure.getInt(resolver,
2445 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2446 mCheckedForSetup = true;
2447
2448 // See if we should be showing the platform update setup UI.
2449 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2450 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2451 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2452
2453 // We don't allow third party apps to replace this.
2454 ResolveInfo ri = null;
2455 for (int i=0; ris != null && i<ris.size(); i++) {
2456 if ((ris.get(i).activityInfo.applicationInfo.flags
2457 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2458 ri = ris.get(i);
2459 break;
2460 }
2461 }
2462
2463 if (ri != null) {
2464 String vers = ri.activityInfo.metaData != null
2465 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2466 : null;
2467 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2468 vers = ri.activityInfo.applicationInfo.metaData.getString(
2469 Intent.METADATA_SETUP_VERSION);
2470 }
2471 String lastVers = Settings.Secure.getString(
2472 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2473 if (vers != null && !vers.equals(lastVers)) {
2474 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2475 intent.setComponent(new ComponentName(
2476 ri.activityInfo.packageName, ri.activityInfo.name));
2477 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2478 null, null, 0, 0, 0, false, false);
2479 }
2480 }
2481 }
2482 }
2483
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002484 private void reportResumedActivityLocked(HistoryRecord r) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002485 //Log.i(TAG, "**** REPORT RESUME: " + r);
2486
2487 final int identHash = System.identityHashCode(r);
2488 updateUsageStats(r, true);
2489
2490 int i = mWatchers.beginBroadcast();
2491 while (i > 0) {
2492 i--;
2493 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2494 if (w != null) {
2495 try {
2496 w.activityResuming(identHash);
2497 } catch (RemoteException e) {
2498 }
2499 }
2500 }
2501 mWatchers.finishBroadcast();
2502 }
2503
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002504 /**
2505 * Ensure that the top activity in the stack is resumed.
2506 *
2507 * @param prev The previously resumed activity, for when in the process
2508 * of pausing; can be null to call from elsewhere.
2509 *
2510 * @return Returns true if something is being resumed, or false if
2511 * nothing happened.
2512 */
2513 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2514 // Find the first activity that is not finishing.
2515 HistoryRecord next = topRunningActivityLocked(null);
2516
2517 // Remember how we'll process this pause/resume situation, and ensure
2518 // that the state is reset however we wind up proceeding.
2519 final boolean userLeaving = mUserLeaving;
2520 mUserLeaving = false;
2521
2522 if (next == null) {
2523 // There are no more activities! Let's just start up the
2524 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002525 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002526 }
2527
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002528 next.delayedResume = false;
2529
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002530 // If the top activity is the resumed one, nothing to do.
2531 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2532 // Make sure we have executed any pending transitions, since there
2533 // should be nothing left to do at this point.
2534 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002535 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002536 return false;
2537 }
2538
2539 // If we are sleeping, and there is no resumed activity, and the top
2540 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002541 if ((mSleeping || mShuttingDown)
2542 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002543 // Make sure we have executed any pending transitions, since there
2544 // should be nothing left to do at this point.
2545 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002546 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002547 return false;
2548 }
2549
2550 // The activity may be waiting for stop, but that is no longer
2551 // appropriate for it.
2552 mStoppingActivities.remove(next);
2553 mWaitingVisibleActivities.remove(next);
2554
2555 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2556
2557 // If we are currently pausing an activity, then don't do anything
2558 // until that is done.
2559 if (mPausingActivity != null) {
2560 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2561 return false;
2562 }
2563
2564 // We need to start pausing the current activity so the top one
2565 // can be resumed...
2566 if (mResumedActivity != null) {
2567 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2568 startPausingLocked(userLeaving, false);
2569 return true;
2570 }
2571
2572 if (prev != null && prev != next) {
2573 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2574 prev.waitingVisible = true;
2575 mWaitingVisibleActivities.add(prev);
2576 if (DEBUG_SWITCH) Log.v(
2577 TAG, "Resuming top, waiting visible to hide: " + prev);
2578 } else {
2579 // The next activity is already visible, so hide the previous
2580 // activity's windows right now so we can show the new one ASAP.
2581 // We only do this if the previous is finishing, which should mean
2582 // it is on top of the one being resumed so hiding it quickly
2583 // is good. Otherwise, we want to do the normal route of allowing
2584 // the resumed activity to be shown so we can decide if the
2585 // previous should actually be hidden depending on whether the
2586 // new one is found to be full-screen or not.
2587 if (prev.finishing) {
2588 mWindowManager.setAppVisibility(prev, false);
2589 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2590 + prev + ", waitingVisible="
2591 + (prev != null ? prev.waitingVisible : null)
2592 + ", nowVisible=" + next.nowVisible);
2593 } else {
2594 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2595 + prev + ", waitingVisible="
2596 + (prev != null ? prev.waitingVisible : null)
2597 + ", nowVisible=" + next.nowVisible);
2598 }
2599 }
2600 }
2601
2602 // We are starting up the next activity, so tell the window manager
2603 // that the previous one will be hidden soon. This way it can know
2604 // to ignore it when computing the desired screen orientation.
2605 if (prev != null) {
2606 if (prev.finishing) {
2607 if (DEBUG_TRANSITION) Log.v(TAG,
2608 "Prepare close transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002609 if (mNoAnimActivities.contains(prev)) {
2610 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2611 } else {
2612 mWindowManager.prepareAppTransition(prev.task == next.task
2613 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2614 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2615 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002616 mWindowManager.setAppWillBeHidden(prev);
2617 mWindowManager.setAppVisibility(prev, false);
2618 } else {
2619 if (DEBUG_TRANSITION) Log.v(TAG,
2620 "Prepare open transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002621 if (mNoAnimActivities.contains(next)) {
2622 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2623 } else {
2624 mWindowManager.prepareAppTransition(prev.task == next.task
2625 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2626 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2627 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002628 }
2629 if (false) {
2630 mWindowManager.setAppWillBeHidden(prev);
2631 mWindowManager.setAppVisibility(prev, false);
2632 }
2633 } else if (mHistory.size() > 1) {
2634 if (DEBUG_TRANSITION) Log.v(TAG,
2635 "Prepare open transition: no previous");
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002636 if (mNoAnimActivities.contains(next)) {
2637 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2638 } else {
2639 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2640 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002641 }
2642
2643 if (next.app != null && next.app.thread != null) {
2644 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2645
2646 // This activity is now becoming visible.
2647 mWindowManager.setAppVisibility(next, true);
2648
2649 HistoryRecord lastResumedActivity = mResumedActivity;
2650 ActivityState lastState = next.state;
2651
2652 updateCpuStats();
2653
2654 next.state = ActivityState.RESUMED;
2655 mResumedActivity = next;
2656 next.task.touchActiveTime();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08002657 updateLruProcessLocked(next.app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002658 updateLRUListLocked(next);
2659
2660 // Have the window manager re-evaluate the orientation of
2661 // the screen based on the new activity order.
Eric Fischerd4d04de2009-10-27 18:55:57 -07002662 boolean updated;
2663 synchronized (this) {
2664 Configuration config = mWindowManager.updateOrientationFromAppTokens(
2665 mConfiguration,
2666 next.mayFreezeScreenLocked(next.app) ? next : null);
2667 if (config != null) {
2668 /*
2669 * Explicitly restore the locale to the one from the
2670 * old configuration, since the one that comes back from
2671 * the window manager has the default (boot) locale.
2672 *
2673 * It looks like previously the locale picker only worked
2674 * by coincidence: usually it would do its setting of
2675 * the locale after the activity transition, so it didn't
2676 * matter that this lost it. With the synchronized
2677 * block now keeping them from happening at the same time,
2678 * this one always would happen second and undo what the
2679 * locale picker had just done.
2680 */
2681 config.locale = mConfiguration.locale;
2682 next.frozenBeforeDestroy = true;
2683 }
2684 updated = updateConfigurationLocked(config, next);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002685 }
Eric Fischerd4d04de2009-10-27 18:55:57 -07002686 if (!updated) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002687 // The configuration update wasn't able to keep the existing
2688 // instance of the activity, and instead started a new one.
2689 // We should be all done, but let's just make sure our activity
2690 // is still at the top and schedule another run if something
2691 // weird happened.
2692 HistoryRecord nextNext = topRunningActivityLocked(null);
2693 if (DEBUG_SWITCH) Log.i(TAG,
2694 "Activity config changed during resume: " + next
2695 + ", new next: " + nextNext);
2696 if (nextNext != next) {
2697 // Do over!
2698 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2699 }
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07002700 setFocusedActivityLocked(next);
2701 ensureActivitiesVisibleLocked(null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002702 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002703 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002704 return true;
2705 }
2706
2707 try {
2708 // Deliver all pending results.
2709 ArrayList a = next.results;
2710 if (a != null) {
2711 final int N = a.size();
2712 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002713 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002714 TAG, "Delivering results to " + next
2715 + ": " + a);
2716 next.app.thread.scheduleSendResult(next, a);
2717 }
2718 }
2719
2720 if (next.newIntents != null) {
2721 next.app.thread.scheduleNewIntent(next.newIntents, next);
2722 }
2723
Doug Zongker2bec3d42009-12-04 12:52:44 -08002724 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002725 System.identityHashCode(next),
2726 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002727
2728 next.app.thread.scheduleResumeActivity(next,
2729 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002730
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002731 pauseIfSleepingLocked();
2732
2733 } catch (Exception e) {
2734 // Whoops, need to restart this activity!
2735 next.state = lastState;
2736 mResumedActivity = lastResumedActivity;
Dianne Hackborn03abb812010-01-04 18:43:19 -08002737 Log.i(TAG, "Restarting because process died: " + next);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002738 if (!next.hasBeenLaunched) {
2739 next.hasBeenLaunched = true;
2740 } else {
2741 if (SHOW_APP_STARTING_ICON) {
2742 mWindowManager.setAppStartingWindow(
2743 next, next.packageName, next.theme,
2744 next.nonLocalizedLabel,
2745 next.labelRes, next.icon, null, true);
2746 }
2747 }
2748 startSpecificActivityLocked(next, true, false);
2749 return true;
2750 }
2751
2752 // From this point on, if something goes wrong there is no way
2753 // to recover the activity.
2754 try {
2755 next.visible = true;
2756 completeResumeLocked(next);
2757 } catch (Exception e) {
2758 // If any exception gets thrown, toss away this
2759 // activity and try the next one.
2760 Log.w(TAG, "Exception thrown during resume of " + next, e);
2761 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2762 "resume-exception");
2763 return true;
2764 }
2765
2766 // Didn't need to use the icicle, and it is now out of date.
2767 next.icicle = null;
2768 next.haveState = false;
2769 next.stopped = false;
2770
2771 } else {
2772 // Whoops, need to restart this activity!
2773 if (!next.hasBeenLaunched) {
2774 next.hasBeenLaunched = true;
2775 } else {
2776 if (SHOW_APP_STARTING_ICON) {
2777 mWindowManager.setAppStartingWindow(
2778 next, next.packageName, next.theme,
2779 next.nonLocalizedLabel,
2780 next.labelRes, next.icon, null, true);
2781 }
2782 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2783 }
2784 startSpecificActivityLocked(next, true, true);
2785 }
2786
2787 return true;
2788 }
2789
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002790 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2791 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002792 final int NH = mHistory.size();
2793
2794 int addPos = -1;
2795
2796 if (!newTask) {
2797 // If starting in an existing task, find where that is...
2798 HistoryRecord next = null;
2799 boolean startIt = true;
2800 for (int i = NH-1; i >= 0; i--) {
2801 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2802 if (p.finishing) {
2803 continue;
2804 }
2805 if (p.task == r.task) {
2806 // Here it is! Now, if this is not yet visible to the
2807 // user, then just add it without starting; it will
2808 // get started when the user navigates back to it.
2809 addPos = i+1;
2810 if (!startIt) {
2811 mHistory.add(addPos, r);
2812 r.inHistory = true;
2813 r.task.numActivities++;
2814 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2815 r.info.screenOrientation, r.fullscreen);
2816 if (VALIDATE_TOKENS) {
2817 mWindowManager.validateAppTokens(mHistory);
2818 }
2819 return;
2820 }
2821 break;
2822 }
2823 if (p.fullscreen) {
2824 startIt = false;
2825 }
2826 next = p;
2827 }
2828 }
2829
2830 // Place a new activity at top of stack, so it is next to interact
2831 // with the user.
2832 if (addPos < 0) {
2833 addPos = mHistory.size();
2834 }
2835
2836 // If we are not placing the new activity frontmost, we do not want
2837 // to deliver the onUserLeaving callback to the actual frontmost
2838 // activity
2839 if (addPos < NH) {
2840 mUserLeaving = false;
2841 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2842 }
2843
2844 // Slot the activity into the history stack and proceed
2845 mHistory.add(addPos, r);
2846 r.inHistory = true;
2847 r.frontOfTask = newTask;
2848 r.task.numActivities++;
2849 if (NH > 0) {
2850 // We want to show the starting preview window if we are
2851 // switching to a new task, or the next activity's process is
2852 // not currently running.
2853 boolean showStartingIcon = newTask;
2854 ProcessRecord proc = r.app;
2855 if (proc == null) {
2856 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2857 }
2858 if (proc == null || proc.thread == null) {
2859 showStartingIcon = true;
2860 }
2861 if (DEBUG_TRANSITION) Log.v(TAG,
2862 "Prepare open transition: starting " + r);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002863 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
2864 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2865 mNoAnimActivities.add(r);
2866 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
2867 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
2868 mNoAnimActivities.remove(r);
2869 } else {
2870 mWindowManager.prepareAppTransition(newTask
2871 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2872 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2873 mNoAnimActivities.remove(r);
2874 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002875 mWindowManager.addAppToken(
2876 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2877 boolean doShow = true;
2878 if (newTask) {
2879 // Even though this activity is starting fresh, we still need
2880 // to reset it to make sure we apply affinities to move any
2881 // existing activities from other tasks in to it.
2882 // If the caller has requested that the target task be
2883 // reset, then do so.
2884 if ((r.intent.getFlags()
2885 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2886 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002887 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002888 }
2889 }
2890 if (SHOW_APP_STARTING_ICON && doShow) {
2891 // Figure out if we are transitioning from another activity that is
2892 // "has the same starting icon" as the next one. This allows the
2893 // window manager to keep the previous window it had previously
2894 // created, if it still had one.
2895 HistoryRecord prev = mResumedActivity;
2896 if (prev != null) {
2897 // We don't want to reuse the previous starting preview if:
2898 // (1) The current activity is in a different task.
2899 if (prev.task != r.task) prev = null;
2900 // (2) The current activity is already displayed.
2901 else if (prev.nowVisible) prev = null;
2902 }
2903 mWindowManager.setAppStartingWindow(
2904 r, r.packageName, r.theme, r.nonLocalizedLabel,
2905 r.labelRes, r.icon, prev, showStartingIcon);
2906 }
2907 } else {
2908 // If this is the first activity, don't do any fancy animations,
2909 // because there is nothing for it to animate on top of.
2910 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2911 r.info.screenOrientation, r.fullscreen);
2912 }
2913 if (VALIDATE_TOKENS) {
2914 mWindowManager.validateAppTokens(mHistory);
2915 }
2916
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002917 if (doResume) {
2918 resumeTopActivityLocked(null);
2919 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002920 }
2921
2922 /**
2923 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002924 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2925 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002926 * an instance of that activity in the stack and, if found, finish all
2927 * activities on top of it and return the instance.
2928 *
2929 * @param newR Description of the new activity being started.
2930 * @return Returns the old activity that should be continue to be used,
2931 * or null if none was found.
2932 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002933 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002934 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002935 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002936
2937 // First find the requested task.
2938 while (i > 0) {
2939 i--;
2940 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2941 if (r.task.taskId == taskId) {
2942 i++;
2943 break;
2944 }
2945 }
2946
2947 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002948 while (i > 0) {
2949 i--;
2950 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2951 if (r.finishing) {
2952 continue;
2953 }
2954 if (r.task.taskId != taskId) {
2955 return null;
2956 }
2957 if (r.realActivity.equals(newR.realActivity)) {
2958 // Here it is! Now finish everything in front...
2959 HistoryRecord ret = r;
2960 if (doClear) {
2961 while (i < (mHistory.size()-1)) {
2962 i++;
2963 r = (HistoryRecord)mHistory.get(i);
2964 if (r.finishing) {
2965 continue;
2966 }
2967 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2968 null, "clear")) {
2969 i--;
2970 }
2971 }
2972 }
2973
2974 // Finally, if this is a normal launch mode (that is, not
2975 // expecting onNewIntent()), then we will finish the current
2976 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002977 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
2978 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002979 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002980 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002981 if (index >= 0) {
2982 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2983 null, "clear");
2984 }
2985 return null;
2986 }
2987 }
2988
2989 return ret;
2990 }
2991 }
2992
2993 return null;
2994 }
2995
2996 /**
2997 * Find the activity in the history stack within the given task. Returns
2998 * the index within the history at which it's found, or < 0 if not found.
2999 */
3000 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
3001 int i = mHistory.size();
3002 while (i > 0) {
3003 i--;
3004 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
3005 if (candidate.task.taskId != task) {
3006 break;
3007 }
3008 if (candidate.realActivity.equals(r.realActivity)) {
3009 return i;
3010 }
3011 }
3012
3013 return -1;
3014 }
3015
3016 /**
3017 * Reorder the history stack so that the activity at the given index is
3018 * brought to the front.
3019 */
3020 private final HistoryRecord moveActivityToFrontLocked(int where) {
3021 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3022 int top = mHistory.size();
3023 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3024 mHistory.add(top, newTop);
3025 oldTop.frontOfTask = false;
3026 newTop.frontOfTask = true;
3027 return newTop;
3028 }
3029
3030 /**
3031 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3032 * method will be called at the proper time.
3033 */
3034 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3035 boolean sent = false;
3036 if (r.state == ActivityState.RESUMED
3037 && r.app != null && r.app.thread != null) {
3038 try {
3039 ArrayList<Intent> ar = new ArrayList<Intent>();
3040 ar.add(new Intent(intent));
3041 r.app.thread.scheduleNewIntent(ar, r);
3042 sent = true;
3043 } catch (Exception e) {
3044 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3045 }
3046 }
3047 if (!sent) {
3048 r.addNewIntentLocked(new Intent(intent));
3049 }
3050 }
3051
3052 private final void logStartActivity(int tag, HistoryRecord r,
3053 TaskRecord task) {
3054 EventLog.writeEvent(tag,
3055 System.identityHashCode(r), task.taskId,
3056 r.shortComponentName, r.intent.getAction(),
3057 r.intent.getType(), r.intent.getDataString(),
3058 r.intent.getFlags());
3059 }
3060
3061 private final int startActivityLocked(IApplicationThread caller,
3062 Intent intent, String resolvedType,
3063 Uri[] grantedUriPermissions,
3064 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3065 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003066 int callingPid, int callingUid, boolean onlyIfNeeded,
3067 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003068 Log.i(TAG, "Starting activity: " + intent);
3069
3070 HistoryRecord sourceRecord = null;
3071 HistoryRecord resultRecord = null;
3072 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003073 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003074 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003075 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3076 if (index >= 0) {
3077 sourceRecord = (HistoryRecord)mHistory.get(index);
3078 if (requestCode >= 0 && !sourceRecord.finishing) {
3079 resultRecord = sourceRecord;
3080 }
3081 }
3082 }
3083
3084 int launchFlags = intent.getFlags();
3085
3086 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3087 && sourceRecord != null) {
3088 // Transfer the result target from the source activity to the new
3089 // one being started, including any failures.
3090 if (requestCode >= 0) {
3091 return START_FORWARD_AND_REQUEST_CONFLICT;
3092 }
3093 resultRecord = sourceRecord.resultTo;
3094 resultWho = sourceRecord.resultWho;
3095 requestCode = sourceRecord.requestCode;
3096 sourceRecord.resultTo = null;
3097 if (resultRecord != null) {
3098 resultRecord.removeResultsLocked(
3099 sourceRecord, resultWho, requestCode);
3100 }
3101 }
3102
3103 int err = START_SUCCESS;
3104
3105 if (intent.getComponent() == null) {
3106 // We couldn't find a class that can handle the given Intent.
3107 // That's the end of that!
3108 err = START_INTENT_NOT_RESOLVED;
3109 }
3110
3111 if (err == START_SUCCESS && aInfo == null) {
3112 // We couldn't find the specific class specified in the Intent.
3113 // Also the end of the line.
3114 err = START_CLASS_NOT_FOUND;
3115 }
3116
3117 ProcessRecord callerApp = null;
3118 if (err == START_SUCCESS && caller != null) {
3119 callerApp = getRecordForAppLocked(caller);
3120 if (callerApp != null) {
3121 callingPid = callerApp.pid;
3122 callingUid = callerApp.info.uid;
3123 } else {
3124 Log.w(TAG, "Unable to find app for caller " + caller
3125 + " (pid=" + callingPid + ") when starting: "
3126 + intent.toString());
3127 err = START_PERMISSION_DENIED;
3128 }
3129 }
3130
3131 if (err != START_SUCCESS) {
3132 if (resultRecord != null) {
3133 sendActivityResultLocked(-1,
3134 resultRecord, resultWho, requestCode,
3135 Activity.RESULT_CANCELED, null);
3136 }
3137 return err;
3138 }
3139
3140 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3141 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3142 if (perm != PackageManager.PERMISSION_GRANTED) {
3143 if (resultRecord != null) {
3144 sendActivityResultLocked(-1,
3145 resultRecord, resultWho, requestCode,
3146 Activity.RESULT_CANCELED, null);
3147 }
3148 String msg = "Permission Denial: starting " + intent.toString()
3149 + " from " + callerApp + " (pid=" + callingPid
3150 + ", uid=" + callingUid + ")"
3151 + " requires " + aInfo.permission;
3152 Log.w(TAG, msg);
3153 throw new SecurityException(msg);
3154 }
3155
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003156 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003157 boolean abort = false;
3158 try {
3159 // The Intent we give to the watcher has the extra data
3160 // stripped off, since it can contain private information.
3161 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003162 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003163 aInfo.applicationInfo.packageName);
3164 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003165 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003166 }
3167
3168 if (abort) {
3169 if (resultRecord != null) {
3170 sendActivityResultLocked(-1,
3171 resultRecord, resultWho, requestCode,
3172 Activity.RESULT_CANCELED, null);
3173 }
3174 // We pretend to the caller that it was really started, but
3175 // they will just get a cancel result.
3176 return START_SUCCESS;
3177 }
3178 }
3179
3180 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3181 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003182 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003183
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003184 if (mResumedActivity == null
3185 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3186 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3187 PendingActivityLaunch pal = new PendingActivityLaunch();
3188 pal.r = r;
3189 pal.sourceRecord = sourceRecord;
3190 pal.grantedUriPermissions = grantedUriPermissions;
3191 pal.grantedMode = grantedMode;
3192 pal.onlyIfNeeded = onlyIfNeeded;
3193 mPendingActivityLaunches.add(pal);
3194 return START_SWITCHES_CANCELED;
3195 }
3196 }
3197
3198 if (mDidAppSwitch) {
3199 // This is the second allowed switch since we stopped switches,
3200 // so now just generally allow switches. Use case: user presses
3201 // home (switches disabled, switch to home, mDidAppSwitch now true);
3202 // user taps a home icon (coming from home so allowed, we hit here
3203 // and now allow anyone to switch again).
3204 mAppSwitchesAllowedTime = 0;
3205 } else {
3206 mDidAppSwitch = true;
3207 }
3208
3209 doPendingActivityLaunchesLocked(false);
3210
3211 return startActivityUncheckedLocked(r, sourceRecord,
3212 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3213 }
3214
3215 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3216 final int N = mPendingActivityLaunches.size();
3217 if (N <= 0) {
3218 return;
3219 }
3220 for (int i=0; i<N; i++) {
3221 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3222 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3223 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3224 doResume && i == (N-1));
3225 }
3226 mPendingActivityLaunches.clear();
3227 }
3228
3229 private final int startActivityUncheckedLocked(HistoryRecord r,
3230 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3231 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3232 final Intent intent = r.intent;
3233 final int callingUid = r.launchedFromUid;
3234
3235 int launchFlags = intent.getFlags();
3236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003237 // We'll invoke onUserLeaving before onPause only if the launching
3238 // activity did not explicitly state that this is an automated launch.
3239 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3240 if (DEBUG_USER_LEAVING) Log.v(TAG,
3241 "startActivity() => mUserLeaving=" + mUserLeaving);
3242
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003243 // If the caller has asked not to resume at this point, we make note
3244 // of this in the record so that we can skip it when trying to find
3245 // the top running activity.
3246 if (!doResume) {
3247 r.delayedResume = true;
3248 }
3249
3250 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3251 != 0 ? r : null;
3252
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003253 // If the onlyIfNeeded flag is set, then we can do this if the activity
3254 // being launched is the same as the one making the call... or, as
3255 // a special case, if we do not know the caller then we count the
3256 // current top activity as the caller.
3257 if (onlyIfNeeded) {
3258 HistoryRecord checkedCaller = sourceRecord;
3259 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003260 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003261 }
3262 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3263 // Caller is not the same as launcher, so always needed.
3264 onlyIfNeeded = false;
3265 }
3266 }
3267
3268 if (grantedUriPermissions != null && callingUid > 0) {
3269 for (int i=0; i<grantedUriPermissions.length; i++) {
3270 grantUriPermissionLocked(callingUid, r.packageName,
3271 grantedUriPermissions[i], grantedMode, r);
3272 }
3273 }
3274
3275 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3276 intent, r);
3277
3278 if (sourceRecord == null) {
3279 // This activity is not being started from another... in this
3280 // case we -always- start a new task.
3281 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3282 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3283 + intent);
3284 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3285 }
3286 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3287 // The original activity who is starting us is running as a single
3288 // instance... this new activity it is starting must go on its
3289 // own task.
3290 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3291 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3292 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3293 // The activity being started is a single instance... it always
3294 // gets launched into its own task.
3295 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3296 }
3297
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003298 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003299 // For whatever reason this activity is being launched into a new
3300 // task... yet the caller has requested a result back. Well, that
3301 // is pretty messed up, so instead immediately send back a cancel
3302 // and let the new task continue launched as normal without a
3303 // dependency on its originator.
3304 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3305 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003306 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003307 Activity.RESULT_CANCELED, null);
3308 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003309 }
3310
3311 boolean addingToTask = false;
3312 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3313 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3314 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3315 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3316 // If bring to front is requested, and no result is requested, and
3317 // we can find a task that was started with this same
3318 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003319 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003320 // See if there is a task to bring to the front. If this is
3321 // a SINGLE_INSTANCE activity, there can be one and only one
3322 // instance of it in the history, and it is always in its own
3323 // unique task, so we do a special search.
3324 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3325 ? findTaskLocked(intent, r.info)
3326 : findActivityLocked(intent, r.info);
3327 if (taskTop != null) {
3328 if (taskTop.task.intent == null) {
3329 // This task was started because of movement of
3330 // the activity based on affinity... now that we
3331 // are actually launching it, we can assign the
3332 // base intent.
3333 taskTop.task.setIntent(intent, r.info);
3334 }
3335 // If the target task is not in the front, then we need
3336 // to bring it to the front... except... well, with
3337 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3338 // to have the same behavior as if a new instance was
3339 // being started, which means not bringing it to the front
3340 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003341 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003342 if (curTop.task != taskTop.task) {
3343 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3344 boolean callerAtFront = sourceRecord == null
3345 || curTop.task == sourceRecord.task;
3346 if (callerAtFront) {
3347 // We really do want to push this one into the
3348 // user's face, right now.
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07003349 moveTaskToFrontLocked(taskTop.task, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003350 }
3351 }
3352 // If the caller has requested that the target task be
3353 // reset, then do so.
3354 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3355 taskTop = resetTaskIfNeededLocked(taskTop, r);
3356 }
3357 if (onlyIfNeeded) {
3358 // We don't need to start a new activity, and
3359 // the client said not to do anything if that
3360 // is the case, so this is it! And for paranoia, make
3361 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003362 if (doResume) {
3363 resumeTopActivityLocked(null);
3364 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003365 return START_RETURN_INTENT_TO_CALLER;
3366 }
3367 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3368 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3369 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3370 // In this situation we want to remove all activities
3371 // from the task up to the one being started. In most
3372 // cases this means we are resetting the task to its
3373 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003374 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003375 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003376 if (top != null) {
3377 if (top.frontOfTask) {
3378 // Activity aliases may mean we use different
3379 // intents for the top activity, so make sure
3380 // the task now has the identity of the new
3381 // intent.
3382 top.task.setIntent(r.intent, r.info);
3383 }
Doug Zongker2bec3d42009-12-04 12:52:44 -08003384 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003385 deliverNewIntentLocked(top, r.intent);
3386 } else {
3387 // A special case: we need to
3388 // start the activity because it is not currently
3389 // running, and the caller has asked to clear the
3390 // current task to have this activity at the top.
3391 addingToTask = true;
3392 // Now pretend like this activity is being started
3393 // by the top of its task, so it is put in the
3394 // right place.
3395 sourceRecord = taskTop;
3396 }
3397 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3398 // In this case the top activity on the task is the
3399 // same as the one being launched, so we take that
3400 // as a request to bring the task to the foreground.
3401 // If the top activity in the task is the root
3402 // activity, deliver this new intent to it if it
3403 // desires.
3404 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3405 && taskTop.realActivity.equals(r.realActivity)) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003406 logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003407 if (taskTop.frontOfTask) {
3408 taskTop.task.setIntent(r.intent, r.info);
3409 }
3410 deliverNewIntentLocked(taskTop, r.intent);
3411 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3412 // In this case we are launching the root activity
3413 // of the task, but with a different intent. We
3414 // should start a new instance on top.
3415 addingToTask = true;
3416 sourceRecord = taskTop;
3417 }
3418 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3419 // In this case an activity is being launched in to an
3420 // existing task, without resetting that task. This
3421 // is typically the situation of launching an activity
3422 // from a notification or shortcut. We want to place
3423 // the new activity on top of the current task.
3424 addingToTask = true;
3425 sourceRecord = taskTop;
3426 } else if (!taskTop.task.rootWasReset) {
3427 // In this case we are launching in to an existing task
3428 // that has not yet been started from its front door.
3429 // The current task has been brought to the front.
3430 // Ideally, we'd probably like to place this new task
3431 // at the bottom of its stack, but that's a little hard
3432 // to do with the current organization of the code so
3433 // for now we'll just drop it.
3434 taskTop.task.setIntent(r.intent, r.info);
3435 }
3436 if (!addingToTask) {
3437 // We didn't do anything... but it was needed (a.k.a., client
3438 // don't use that intent!) And for paranoia, make
3439 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003440 if (doResume) {
3441 resumeTopActivityLocked(null);
3442 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003443 return START_TASK_TO_FRONT;
3444 }
3445 }
3446 }
3447 }
3448
3449 //String uri = r.intent.toURI();
3450 //Intent intent2 = new Intent(uri);
3451 //Log.i(TAG, "Given intent: " + r.intent);
3452 //Log.i(TAG, "URI is: " + uri);
3453 //Log.i(TAG, "To intent: " + intent2);
3454
3455 if (r.packageName != null) {
3456 // If the activity being launched is the same as the one currently
3457 // at the top, then we need to check if it should only be launched
3458 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003459 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3460 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003461 if (top.realActivity.equals(r.realActivity)) {
3462 if (top.app != null && top.app.thread != null) {
3463 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3464 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3465 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003466 logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003467 // For paranoia, make sure we have correctly
3468 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003469 if (doResume) {
3470 resumeTopActivityLocked(null);
3471 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003472 if (onlyIfNeeded) {
3473 // We don't need to start a new activity, and
3474 // the client said not to do anything if that
3475 // is the case, so this is it!
3476 return START_RETURN_INTENT_TO_CALLER;
3477 }
3478 deliverNewIntentLocked(top, r.intent);
3479 return START_DELIVERED_TO_TOP;
3480 }
3481 }
3482 }
3483 }
3484
3485 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003486 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003487 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003488 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003489 Activity.RESULT_CANCELED, null);
3490 }
3491 return START_CLASS_NOT_FOUND;
3492 }
3493
3494 boolean newTask = false;
3495
3496 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003497 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003498 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3499 // todo: should do better management of integers.
3500 mCurTask++;
3501 if (mCurTask <= 0) {
3502 mCurTask = 1;
3503 }
3504 r.task = new TaskRecord(mCurTask, r.info, intent,
3505 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3506 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3507 + " in new task " + r.task);
3508 newTask = true;
3509 addRecentTask(r.task);
3510
3511 } else if (sourceRecord != null) {
3512 if (!addingToTask &&
3513 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3514 // In this case, we are adding the activity to an existing
3515 // task, but the caller has asked to clear that task if the
3516 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003517 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003518 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003519 if (top != null) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003520 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003521 deliverNewIntentLocked(top, r.intent);
3522 // For paranoia, make sure we have correctly
3523 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003524 if (doResume) {
3525 resumeTopActivityLocked(null);
3526 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003527 return START_DELIVERED_TO_TOP;
3528 }
3529 } else if (!addingToTask &&
3530 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3531 // In this case, we are launching an activity in our own task
3532 // that may already be running somewhere in the history, and
3533 // we want to shuffle it to the front of the stack if so.
3534 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3535 if (where >= 0) {
3536 HistoryRecord top = moveActivityToFrontLocked(where);
Doug Zongker2bec3d42009-12-04 12:52:44 -08003537 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003538 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003539 if (doResume) {
3540 resumeTopActivityLocked(null);
3541 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003542 return START_DELIVERED_TO_TOP;
3543 }
3544 }
3545 // An existing activity is starting this new activity, so we want
3546 // to keep the new one in the same task as the one that is starting
3547 // it.
3548 r.task = sourceRecord.task;
3549 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3550 + " in existing task " + r.task);
3551
3552 } else {
3553 // This not being started from an existing activity, and not part
3554 // of a new task... just put it in the top task, though these days
3555 // this case should never happen.
3556 final int N = mHistory.size();
3557 HistoryRecord prev =
3558 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3559 r.task = prev != null
3560 ? prev.task
3561 : new TaskRecord(mCurTask, r.info, intent,
3562 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3563 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3564 + " in new guessed " + r.task);
3565 }
3566 if (newTask) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003567 EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003568 }
Doug Zongker2bec3d42009-12-04 12:52:44 -08003569 logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003570 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003571 return START_SUCCESS;
3572 }
3573
3574 public final int startActivity(IApplicationThread caller,
3575 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3576 int grantedMode, IBinder resultTo,
3577 String resultWho, int requestCode, boolean onlyIfNeeded,
3578 boolean debug) {
3579 // Refuse possible leaked file descriptors
3580 if (intent != null && intent.hasFileDescriptors()) {
3581 throw new IllegalArgumentException("File descriptors passed in Intent");
3582 }
3583
The Android Open Source Project4df24232009-03-05 14:34:35 -08003584 final boolean componentSpecified = intent.getComponent() != null;
3585
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003586 // Don't modify the client's object!
3587 intent = new Intent(intent);
3588
3589 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003590 ActivityInfo aInfo;
3591 try {
3592 ResolveInfo rInfo =
3593 ActivityThread.getPackageManager().resolveIntent(
3594 intent, resolvedType,
3595 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003596 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003597 aInfo = rInfo != null ? rInfo.activityInfo : null;
3598 } catch (RemoteException e) {
3599 aInfo = null;
3600 }
3601
3602 if (aInfo != null) {
3603 // Store the found target back into the intent, because now that
3604 // we have it we never want to do this again. For example, if the
3605 // user navigates back to this point in the history, we should
3606 // always restart the exact same activity.
3607 intent.setComponent(new ComponentName(
3608 aInfo.applicationInfo.packageName, aInfo.name));
3609
3610 // Don't debug things in the system process
3611 if (debug) {
3612 if (!aInfo.processName.equals("system")) {
3613 setDebugApp(aInfo.processName, true, false);
3614 }
3615 }
3616 }
3617
3618 synchronized(this) {
3619 final long origId = Binder.clearCallingIdentity();
3620 int res = startActivityLocked(caller, intent, resolvedType,
3621 grantedUriPermissions, grantedMode, aInfo,
3622 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003623 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003624 Binder.restoreCallingIdentity(origId);
3625 return res;
3626 }
3627 }
3628
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003629 public int startActivityIntentSender(IApplicationThread caller,
3630 IntentSender intent, Intent fillInIntent, String resolvedType,
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003631 IBinder resultTo, String resultWho, int requestCode,
3632 int flagsMask, int flagsValues) {
3633 // Refuse possible leaked file descriptors
3634 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3635 throw new IllegalArgumentException("File descriptors passed in Intent");
3636 }
3637
3638 IIntentSender sender = intent.getTarget();
3639 if (!(sender instanceof PendingIntentRecord)) {
3640 throw new IllegalArgumentException("Bad PendingIntent object");
3641 }
3642
3643 PendingIntentRecord pir = (PendingIntentRecord)sender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003644
3645 synchronized (this) {
3646 // If this is coming from the currently resumed activity, it is
3647 // effectively saying that app switches are allowed at this point.
3648 if (mResumedActivity != null
3649 && mResumedActivity.info.applicationInfo.uid ==
3650 Binder.getCallingUid()) {
3651 mAppSwitchesAllowedTime = 0;
3652 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003653 }
3654
3655 return pir.sendInner(0, fillInIntent, resolvedType,
3656 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3657 }
3658
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003659 public boolean startNextMatchingActivity(IBinder callingActivity,
3660 Intent intent) {
3661 // Refuse possible leaked file descriptors
3662 if (intent != null && intent.hasFileDescriptors() == true) {
3663 throw new IllegalArgumentException("File descriptors passed in Intent");
3664 }
3665
3666 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003667 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003668 if (index < 0) {
3669 return false;
3670 }
3671 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3672 if (r.app == null || r.app.thread == null) {
3673 // The caller is not running... d'oh!
3674 return false;
3675 }
3676 intent = new Intent(intent);
3677 // The caller is not allowed to change the data.
3678 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3679 // And we are resetting to find the next component...
3680 intent.setComponent(null);
3681
3682 ActivityInfo aInfo = null;
3683 try {
3684 List<ResolveInfo> resolves =
3685 ActivityThread.getPackageManager().queryIntentActivities(
3686 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003687 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003688
3689 // Look for the original activity in the list...
3690 final int N = resolves != null ? resolves.size() : 0;
3691 for (int i=0; i<N; i++) {
3692 ResolveInfo rInfo = resolves.get(i);
3693 if (rInfo.activityInfo.packageName.equals(r.packageName)
3694 && rInfo.activityInfo.name.equals(r.info.name)) {
3695 // We found the current one... the next matching is
3696 // after it.
3697 i++;
3698 if (i<N) {
3699 aInfo = resolves.get(i).activityInfo;
3700 }
3701 break;
3702 }
3703 }
3704 } catch (RemoteException e) {
3705 }
3706
3707 if (aInfo == null) {
3708 // Nobody who is next!
3709 return false;
3710 }
3711
3712 intent.setComponent(new ComponentName(
3713 aInfo.applicationInfo.packageName, aInfo.name));
3714 intent.setFlags(intent.getFlags()&~(
3715 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3716 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3717 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3718 Intent.FLAG_ACTIVITY_NEW_TASK));
3719
3720 // Okay now we need to start the new activity, replacing the
3721 // currently running activity. This is a little tricky because
3722 // we want to start the new one as if the current one is finished,
3723 // but not finish the current one first so that there is no flicker.
3724 // And thus...
3725 final boolean wasFinishing = r.finishing;
3726 r.finishing = true;
3727
3728 // Propagate reply information over to the new activity.
3729 final HistoryRecord resultTo = r.resultTo;
3730 final String resultWho = r.resultWho;
3731 final int requestCode = r.requestCode;
3732 r.resultTo = null;
3733 if (resultTo != null) {
3734 resultTo.removeResultsLocked(r, resultWho, requestCode);
3735 }
3736
3737 final long origId = Binder.clearCallingIdentity();
3738 // XXX we are not dealing with propagating grantedUriPermissions...
3739 // those are not yet exposed to user code, so there is no need.
3740 int res = startActivityLocked(r.app.thread, intent,
3741 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003742 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003743 Binder.restoreCallingIdentity(origId);
3744
3745 r.finishing = wasFinishing;
3746 if (res != START_SUCCESS) {
3747 return false;
3748 }
3749 return true;
3750 }
3751 }
3752
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003753 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003754 Intent intent, String resolvedType, IBinder resultTo,
3755 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003756
3757 // This is so super not safe, that only the system (or okay root)
3758 // can do it.
3759 final int callingUid = Binder.getCallingUid();
3760 if (callingUid != 0 && callingUid != Process.myUid()) {
3761 throw new SecurityException(
3762 "startActivityInPackage only available to the system");
3763 }
3764
The Android Open Source Project4df24232009-03-05 14:34:35 -08003765 final boolean componentSpecified = intent.getComponent() != null;
3766
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003767 // Don't modify the client's object!
3768 intent = new Intent(intent);
3769
3770 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003771 ActivityInfo aInfo;
3772 try {
3773 ResolveInfo rInfo =
3774 ActivityThread.getPackageManager().resolveIntent(
3775 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003776 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003777 aInfo = rInfo != null ? rInfo.activityInfo : null;
3778 } catch (RemoteException e) {
3779 aInfo = null;
3780 }
3781
3782 if (aInfo != null) {
3783 // Store the found target back into the intent, because now that
3784 // we have it we never want to do this again. For example, if the
3785 // user navigates back to this point in the history, we should
3786 // always restart the exact same activity.
3787 intent.setComponent(new ComponentName(
3788 aInfo.applicationInfo.packageName, aInfo.name));
3789 }
3790
3791 synchronized(this) {
3792 return startActivityLocked(null, intent, resolvedType,
3793 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003794 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003795 }
3796 }
3797
3798 private final void addRecentTask(TaskRecord task) {
3799 // Remove any existing entries that are the same kind of task.
3800 int N = mRecentTasks.size();
3801 for (int i=0; i<N; i++) {
3802 TaskRecord tr = mRecentTasks.get(i);
3803 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3804 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3805 mRecentTasks.remove(i);
3806 i--;
3807 N--;
3808 if (task.intent == null) {
3809 // If the new recent task we are adding is not fully
3810 // specified, then replace it with the existing recent task.
3811 task = tr;
3812 }
3813 }
3814 }
3815 if (N >= MAX_RECENT_TASKS) {
3816 mRecentTasks.remove(N-1);
3817 }
3818 mRecentTasks.add(0, task);
3819 }
3820
3821 public void setRequestedOrientation(IBinder token,
3822 int requestedOrientation) {
3823 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003824 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003825 if (index < 0) {
3826 return;
3827 }
3828 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3829 final long origId = Binder.clearCallingIdentity();
3830 mWindowManager.setAppOrientation(r, requestedOrientation);
3831 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003832 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003833 r.mayFreezeScreenLocked(r.app) ? r : null);
3834 if (config != null) {
3835 r.frozenBeforeDestroy = true;
3836 if (!updateConfigurationLocked(config, r)) {
3837 resumeTopActivityLocked(null);
3838 }
3839 }
3840 Binder.restoreCallingIdentity(origId);
3841 }
3842 }
3843
3844 public int getRequestedOrientation(IBinder token) {
3845 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003846 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003847 if (index < 0) {
3848 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3849 }
3850 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3851 return mWindowManager.getAppOrientation(r);
3852 }
3853 }
3854
3855 private final void stopActivityLocked(HistoryRecord r) {
3856 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3857 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3858 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3859 if (!r.finishing) {
3860 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3861 "no-history");
3862 }
3863 } else if (r.app != null && r.app.thread != null) {
3864 if (mFocusedActivity == r) {
3865 setFocusedActivityLocked(topRunningActivityLocked(null));
3866 }
3867 r.resumeKeyDispatchingLocked();
3868 try {
3869 r.stopped = false;
3870 r.state = ActivityState.STOPPING;
3871 if (DEBUG_VISBILITY) Log.v(
3872 TAG, "Stopping visible=" + r.visible + " for " + r);
3873 if (!r.visible) {
3874 mWindowManager.setAppVisibility(r, false);
3875 }
3876 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3877 } catch (Exception e) {
3878 // Maybe just ignore exceptions here... if the process
3879 // has crashed, our death notification will clean things
3880 // up.
3881 Log.w(TAG, "Exception thrown during pause", e);
3882 // Just in case, assume it to be stopped.
3883 r.stopped = true;
3884 r.state = ActivityState.STOPPED;
3885 if (r.configDestroy) {
3886 destroyActivityLocked(r, true);
3887 }
3888 }
3889 }
3890 }
3891
3892 /**
3893 * @return Returns true if the activity is being finished, false if for
3894 * some reason it is being left as-is.
3895 */
3896 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3897 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003898 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003899 TAG, "Finishing activity: token=" + token
3900 + ", result=" + resultCode + ", data=" + resultData);
3901
Dianne Hackborn75b03852009-06-12 15:43:26 -07003902 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003903 if (index < 0) {
3904 return false;
3905 }
3906 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3907
3908 // Is this the last activity left?
3909 boolean lastActivity = true;
3910 for (int i=mHistory.size()-1; i>=0; i--) {
3911 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3912 if (!p.finishing && p != r) {
3913 lastActivity = false;
3914 break;
3915 }
3916 }
3917
3918 // If this is the last activity, but it is the home activity, then
3919 // just don't finish it.
3920 if (lastActivity) {
3921 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3922 return false;
3923 }
3924 }
3925
3926 finishActivityLocked(r, index, resultCode, resultData, reason);
3927 return true;
3928 }
3929
3930 /**
3931 * @return Returns true if this activity has been removed from the history
3932 * list, or false if it is still in the list and will be removed later.
3933 */
3934 private final boolean finishActivityLocked(HistoryRecord r, int index,
3935 int resultCode, Intent resultData, String reason) {
3936 if (r.finishing) {
3937 Log.w(TAG, "Duplicate finish request for " + r);
3938 return false;
3939 }
3940
3941 r.finishing = true;
Doug Zongker2bec3d42009-12-04 12:52:44 -08003942 EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003943 System.identityHashCode(r),
3944 r.task.taskId, r.shortComponentName, reason);
3945 r.task.numActivities--;
3946 if (r.frontOfTask && index < (mHistory.size()-1)) {
3947 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3948 if (next.task == r.task) {
3949 next.frontOfTask = true;
3950 }
3951 }
3952
3953 r.pauseKeyDispatchingLocked();
3954 if (mFocusedActivity == r) {
3955 setFocusedActivityLocked(topRunningActivityLocked(null));
3956 }
3957
3958 // send the result
3959 HistoryRecord resultTo = r.resultTo;
3960 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003961 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3962 + " who=" + r.resultWho + " req=" + r.requestCode
3963 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003964 if (r.info.applicationInfo.uid > 0) {
3965 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3966 r.packageName, resultData, r);
3967 }
3968 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3969 resultData);
3970 r.resultTo = null;
3971 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003972 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003973
3974 // Make sure this HistoryRecord is not holding on to other resources,
3975 // because clients have remote IPC references to this object so we
3976 // can't assume that will go away and want to avoid circular IPC refs.
3977 r.results = null;
3978 r.pendingResults = null;
3979 r.newIntents = null;
3980 r.icicle = null;
3981
3982 if (mPendingThumbnails.size() > 0) {
3983 // There are clients waiting to receive thumbnails so, in case
3984 // this is an activity that someone is waiting for, add it
3985 // to the pending list so we can correctly update the clients.
3986 mCancelledThumbnails.add(r);
3987 }
3988
3989 if (mResumedActivity == r) {
3990 boolean endTask = index <= 0
3991 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3992 if (DEBUG_TRANSITION) Log.v(TAG,
3993 "Prepare close transition: finishing " + r);
3994 mWindowManager.prepareAppTransition(endTask
3995 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3996 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3997
3998 // Tell window manager to prepare for this one to be removed.
3999 mWindowManager.setAppVisibility(r, false);
4000
4001 if (mPausingActivity == null) {
4002 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
4003 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
4004 startPausingLocked(false, false);
4005 }
4006
4007 } else if (r.state != ActivityState.PAUSING) {
4008 // If the activity is PAUSING, we will complete the finish once
4009 // it is done pausing; else we can just directly finish it here.
4010 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
4011 return finishCurrentActivityLocked(r, index,
4012 FINISH_AFTER_PAUSE) == null;
4013 } else {
4014 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
4015 }
4016
4017 return false;
4018 }
4019
4020 private static final int FINISH_IMMEDIATELY = 0;
4021 private static final int FINISH_AFTER_PAUSE = 1;
4022 private static final int FINISH_AFTER_VISIBLE = 2;
4023
4024 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4025 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004026 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004027 if (index < 0) {
4028 return null;
4029 }
4030
4031 return finishCurrentActivityLocked(r, index, mode);
4032 }
4033
4034 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4035 int index, int mode) {
4036 // First things first: if this activity is currently visible,
4037 // and the resumed activity is not yet visible, then hold off on
4038 // finishing until the resumed one becomes visible.
4039 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4040 if (!mStoppingActivities.contains(r)) {
4041 mStoppingActivities.add(r);
4042 if (mStoppingActivities.size() > 3) {
4043 // If we already have a few activities waiting to stop,
4044 // then give up on things going idle and start clearing
4045 // them out.
4046 Message msg = Message.obtain();
4047 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4048 mHandler.sendMessage(msg);
4049 }
4050 }
4051 r.state = ActivityState.STOPPING;
4052 updateOomAdjLocked();
4053 return r;
4054 }
4055
4056 // make sure the record is cleaned out of other places.
4057 mStoppingActivities.remove(r);
4058 mWaitingVisibleActivities.remove(r);
4059 if (mResumedActivity == r) {
4060 mResumedActivity = null;
4061 }
4062 final ActivityState prevState = r.state;
4063 r.state = ActivityState.FINISHING;
4064
4065 if (mode == FINISH_IMMEDIATELY
4066 || prevState == ActivityState.STOPPED
4067 || prevState == ActivityState.INITIALIZING) {
4068 // If this activity is already stopped, we can just finish
4069 // it right now.
4070 return destroyActivityLocked(r, true) ? null : r;
4071 } else {
4072 // Need to go through the full pause cycle to get this
4073 // activity into the stopped state and then finish it.
4074 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4075 mFinishingActivities.add(r);
4076 resumeTopActivityLocked(null);
4077 }
4078 return r;
4079 }
4080
4081 /**
4082 * This is the internal entry point for handling Activity.finish().
4083 *
4084 * @param token The Binder token referencing the Activity we want to finish.
4085 * @param resultCode Result code, if any, from this Activity.
4086 * @param resultData Result data (Intent), if any, from this Activity.
4087 *
Alexey Tarasov83bad3d2009-08-12 15:05:43 +11004088 * @return Returns true if the activity successfully finished, or false if it is still running.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004089 */
4090 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4091 // Refuse possible leaked file descriptors
4092 if (resultData != null && resultData.hasFileDescriptors() == true) {
4093 throw new IllegalArgumentException("File descriptors passed in Intent");
4094 }
4095
4096 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004097 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004098 // Find the first activity that is not finishing.
4099 HistoryRecord next = topRunningActivityLocked(token, 0);
4100 if (next != null) {
4101 // ask watcher if this is allowed
4102 boolean resumeOK = true;
4103 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004104 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004105 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004106 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004107 }
4108
4109 if (!resumeOK) {
4110 return false;
4111 }
4112 }
4113 }
4114 final long origId = Binder.clearCallingIdentity();
4115 boolean res = requestFinishActivityLocked(token, resultCode,
4116 resultData, "app-request");
4117 Binder.restoreCallingIdentity(origId);
4118 return res;
4119 }
4120 }
4121
4122 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4123 String resultWho, int requestCode, int resultCode, Intent data) {
4124
4125 if (callingUid > 0) {
4126 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4127 data, r);
4128 }
4129
The Android Open Source Project10592532009-03-18 17:39:46 -07004130 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4131 + " : who=" + resultWho + " req=" + requestCode
4132 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004133 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4134 try {
4135 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4136 list.add(new ResultInfo(resultWho, requestCode,
4137 resultCode, data));
4138 r.app.thread.scheduleSendResult(r, list);
4139 return;
4140 } catch (Exception e) {
4141 Log.w(TAG, "Exception thrown sending result to " + r, e);
4142 }
4143 }
4144
4145 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4146 }
4147
4148 public final void finishSubActivity(IBinder token, String resultWho,
4149 int requestCode) {
4150 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004151 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004152 if (index < 0) {
4153 return;
4154 }
4155 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4156
4157 final long origId = Binder.clearCallingIdentity();
4158
4159 int i;
4160 for (i=mHistory.size()-1; i>=0; i--) {
4161 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4162 if (r.resultTo == self && r.requestCode == requestCode) {
4163 if ((r.resultWho == null && resultWho == null) ||
4164 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4165 finishActivityLocked(r, i,
4166 Activity.RESULT_CANCELED, null, "request-sub");
4167 }
4168 }
4169 }
4170
4171 Binder.restoreCallingIdentity(origId);
4172 }
4173 }
4174
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07004175 public void overridePendingTransition(IBinder token, String packageName,
4176 int enterAnim, int exitAnim) {
4177 synchronized(this) {
4178 int index = indexOfTokenLocked(token);
4179 if (index < 0) {
4180 return;
4181 }
4182 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4183
4184 final long origId = Binder.clearCallingIdentity();
4185
4186 if (self.state == ActivityState.RESUMED
4187 || self.state == ActivityState.PAUSING) {
4188 mWindowManager.overridePendingAppTransition(packageName,
4189 enterAnim, exitAnim);
4190 }
4191
4192 Binder.restoreCallingIdentity(origId);
4193 }
4194 }
4195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004196 /**
4197 * Perform clean-up of service connections in an activity record.
4198 */
4199 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4200 // Throw away any services that have been bound by this activity.
4201 if (r.connections != null) {
4202 Iterator<ConnectionRecord> it = r.connections.iterator();
4203 while (it.hasNext()) {
4204 ConnectionRecord c = it.next();
4205 removeConnectionLocked(c, null, r);
4206 }
4207 r.connections = null;
4208 }
4209 }
4210
4211 /**
4212 * Perform the common clean-up of an activity record. This is called both
4213 * as part of destroyActivityLocked() (when destroying the client-side
4214 * representation) and cleaning things up as a result of its hosting
4215 * processing going away, in which case there is no remaining client-side
4216 * state to destroy so only the cleanup here is needed.
4217 */
4218 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4219 if (mResumedActivity == r) {
4220 mResumedActivity = null;
4221 }
4222 if (mFocusedActivity == r) {
4223 mFocusedActivity = null;
4224 }
4225
4226 r.configDestroy = false;
4227 r.frozenBeforeDestroy = false;
4228
4229 // Make sure this record is no longer in the pending finishes list.
4230 // This could happen, for example, if we are trimming activities
4231 // down to the max limit while they are still waiting to finish.
4232 mFinishingActivities.remove(r);
4233 mWaitingVisibleActivities.remove(r);
4234
4235 // Remove any pending results.
4236 if (r.finishing && r.pendingResults != null) {
4237 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4238 PendingIntentRecord rec = apr.get();
4239 if (rec != null) {
4240 cancelIntentSenderLocked(rec, false);
4241 }
4242 }
4243 r.pendingResults = null;
4244 }
4245
4246 if (cleanServices) {
4247 cleanUpActivityServicesLocked(r);
4248 }
4249
4250 if (mPendingThumbnails.size() > 0) {
4251 // There are clients waiting to receive thumbnails so, in case
4252 // this is an activity that someone is waiting for, add it
4253 // to the pending list so we can correctly update the clients.
4254 mCancelledThumbnails.add(r);
4255 }
4256
4257 // Get rid of any pending idle timeouts.
4258 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4259 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4260 }
4261
4262 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4263 if (r.state != ActivityState.DESTROYED) {
4264 mHistory.remove(r);
4265 r.inHistory = false;
4266 r.state = ActivityState.DESTROYED;
4267 mWindowManager.removeAppToken(r);
4268 if (VALIDATE_TOKENS) {
4269 mWindowManager.validateAppTokens(mHistory);
4270 }
4271 cleanUpActivityServicesLocked(r);
4272 removeActivityUriPermissionsLocked(r);
4273 }
4274 }
4275
4276 /**
4277 * Destroy the current CLIENT SIDE instance of an activity. This may be
4278 * called both when actually finishing an activity, or when performing
4279 * a configuration switch where we destroy the current client-side object
4280 * but then create a new client-side object for this same HistoryRecord.
4281 */
4282 private final boolean destroyActivityLocked(HistoryRecord r,
4283 boolean removeFromApp) {
4284 if (DEBUG_SWITCH) Log.v(
4285 TAG, "Removing activity: token=" + r
4286 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
Doug Zongker2bec3d42009-12-04 12:52:44 -08004287 EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004288 System.identityHashCode(r),
4289 r.task.taskId, r.shortComponentName);
4290
4291 boolean removedFromHistory = false;
4292
4293 cleanUpActivityLocked(r, false);
4294
Dianne Hackborn03abb812010-01-04 18:43:19 -08004295 final boolean hadApp = r.app != null;
4296
4297 if (hadApp) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004298 if (removeFromApp) {
4299 int idx = r.app.activities.indexOf(r);
4300 if (idx >= 0) {
4301 r.app.activities.remove(idx);
4302 }
4303 if (r.persistent) {
4304 decPersistentCountLocked(r.app);
4305 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004306 if (r.app.activities.size() == 0) {
4307 // No longer have activities, so update location in
4308 // LRU list.
4309 updateLruProcessLocked(r.app, true, false);
4310 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004311 }
4312
4313 boolean skipDestroy = false;
4314
4315 try {
4316 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4317 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4318 r.configChangeFlags);
4319 } catch (Exception e) {
4320 // We can just ignore exceptions here... if the process
4321 // has crashed, our death notification will clean things
4322 // up.
4323 //Log.w(TAG, "Exception thrown during finish", e);
4324 if (r.finishing) {
4325 removeActivityFromHistoryLocked(r);
4326 removedFromHistory = true;
4327 skipDestroy = true;
4328 }
4329 }
4330
4331 r.app = null;
4332 r.nowVisible = false;
4333
4334 if (r.finishing && !skipDestroy) {
4335 r.state = ActivityState.DESTROYING;
4336 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4337 msg.obj = r;
4338 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4339 } else {
4340 r.state = ActivityState.DESTROYED;
4341 }
4342 } else {
4343 // remove this record from the history.
4344 if (r.finishing) {
4345 removeActivityFromHistoryLocked(r);
4346 removedFromHistory = true;
4347 } else {
4348 r.state = ActivityState.DESTROYED;
4349 }
4350 }
4351
4352 r.configChangeFlags = 0;
4353
Dianne Hackborn03abb812010-01-04 18:43:19 -08004354 if (!mLRUActivities.remove(r) && hadApp) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004355 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4356 }
4357
4358 return removedFromHistory;
4359 }
4360
Dianne Hackborn03abb812010-01-04 18:43:19 -08004361 private static void removeHistoryRecordsForAppLocked(ArrayList list, ProcessRecord app) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004362 int i = list.size();
4363 if (localLOGV) Log.v(
4364 TAG, "Removing app " + app + " from list " + list
4365 + " with " + i + " entries");
4366 while (i > 0) {
4367 i--;
4368 HistoryRecord r = (HistoryRecord)list.get(i);
4369 if (localLOGV) Log.v(
4370 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4371 if (r.app == app) {
4372 if (localLOGV) Log.v(TAG, "Removing this entry!");
4373 list.remove(i);
4374 }
4375 }
4376 }
4377
4378 /**
4379 * Main function for removing an existing process from the activity manager
4380 * as a result of that process going away. Clears out all connections
4381 * to the process.
4382 */
4383 private final void handleAppDiedLocked(ProcessRecord app,
4384 boolean restarting) {
4385 cleanUpApplicationRecordLocked(app, restarting, -1);
4386 if (!restarting) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004387 mLruProcesses.remove(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004388 }
4389
4390 // Just in case...
4391 if (mPausingActivity != null && mPausingActivity.app == app) {
4392 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4393 mPausingActivity = null;
4394 }
4395 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4396 mLastPausedActivity = null;
4397 }
4398
4399 // Remove this application's activities from active lists.
4400 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4401 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4402 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4403 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4404
4405 boolean atTop = true;
4406 boolean hasVisibleActivities = false;
4407
4408 // Clean out the history list.
4409 int i = mHistory.size();
4410 if (localLOGV) Log.v(
4411 TAG, "Removing app " + app + " from history with " + i + " entries");
4412 while (i > 0) {
4413 i--;
4414 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4415 if (localLOGV) Log.v(
4416 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4417 if (r.app == app) {
4418 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4419 if (localLOGV) Log.v(
4420 TAG, "Removing this entry! frozen=" + r.haveState
4421 + " finishing=" + r.finishing);
4422 mHistory.remove(i);
4423
4424 r.inHistory = false;
4425 mWindowManager.removeAppToken(r);
4426 if (VALIDATE_TOKENS) {
4427 mWindowManager.validateAppTokens(mHistory);
4428 }
4429 removeActivityUriPermissionsLocked(r);
4430
4431 } else {
4432 // We have the current state for this activity, so
4433 // it can be restarted later when needed.
4434 if (localLOGV) Log.v(
4435 TAG, "Keeping entry, setting app to null");
4436 if (r.visible) {
4437 hasVisibleActivities = true;
4438 }
4439 r.app = null;
4440 r.nowVisible = false;
4441 if (!r.haveState) {
4442 r.icicle = null;
4443 }
4444 }
4445
4446 cleanUpActivityLocked(r, true);
4447 r.state = ActivityState.STOPPED;
4448 }
4449 atTop = false;
4450 }
4451
4452 app.activities.clear();
4453
4454 if (app.instrumentationClass != null) {
4455 Log.w(TAG, "Crash of app " + app.processName
4456 + " running instrumentation " + app.instrumentationClass);
4457 Bundle info = new Bundle();
4458 info.putString("shortMsg", "Process crashed.");
4459 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4460 }
4461
4462 if (!restarting) {
4463 if (!resumeTopActivityLocked(null)) {
4464 // If there was nothing to resume, and we are not already
4465 // restarting this process, but there is a visible activity that
4466 // is hosted by the process... then make sure all visible
4467 // activities are running, taking care of restarting this
4468 // process.
4469 if (hasVisibleActivities) {
4470 ensureActivitiesVisibleLocked(null, 0);
4471 }
4472 }
4473 }
4474 }
4475
4476 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4477 IBinder threadBinder = thread.asBinder();
4478
4479 // Find the application record.
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004480 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4481 ProcessRecord rec = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004482 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4483 return i;
4484 }
4485 }
4486 return -1;
4487 }
4488
4489 private final ProcessRecord getRecordForAppLocked(
4490 IApplicationThread thread) {
4491 if (thread == null) {
4492 return null;
4493 }
4494
4495 int appIndex = getLRURecordIndexForAppLocked(thread);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004496 return appIndex >= 0 ? mLruProcesses.get(appIndex) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004497 }
4498
4499 private final void appDiedLocked(ProcessRecord app, int pid,
4500 IApplicationThread thread) {
4501
4502 mProcDeaths[0]++;
4503
4504 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4505 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4506 + ") has died.");
Doug Zongker2bec3d42009-12-04 12:52:44 -08004507 EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004508 if (localLOGV) Log.v(
4509 TAG, "Dying app: " + app + ", pid: " + pid
4510 + ", thread: " + thread.asBinder());
4511 boolean doLowMem = app.instrumentationClass == null;
4512 handleAppDiedLocked(app, false);
4513
4514 if (doLowMem) {
4515 // If there are no longer any background processes running,
4516 // and the app that died was not running instrumentation,
4517 // then tell everyone we are now low on memory.
4518 boolean haveBg = false;
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004519 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4520 ProcessRecord rec = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004521 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4522 haveBg = true;
4523 break;
4524 }
4525 }
4526
4527 if (!haveBg) {
4528 Log.i(TAG, "Low Memory: No more background processes.");
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004529 EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mLruProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004530 long now = SystemClock.uptimeMillis();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004531 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4532 ProcessRecord rec = mLruProcesses.get(i);
Dianne Hackborn36124872009-10-08 16:22:03 -07004533 if (rec != app && rec.thread != null &&
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004534 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4535 // The low memory report is overriding any current
4536 // state for a GC request. Make sure to do
4537 // visible/foreground processes first.
4538 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4539 rec.lastRequestedGc = 0;
4540 } else {
4541 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004542 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004543 rec.reportLowMemory = true;
4544 rec.lastLowMemory = now;
4545 mProcessesToGc.remove(rec);
4546 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004547 }
4548 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004549 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004550 }
4551 }
Dianne Hackborn03abb812010-01-04 18:43:19 -08004552 } else if (DEBUG_PROCESSES) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004553 Log.d(TAG, "Received spurious death notification for thread "
4554 + thread.asBinder());
4555 }
4556 }
4557
Dan Egnor42471dd2010-01-07 17:25:22 -08004558 /**
4559 * If a stack trace dump file is configured, dump process stack traces.
4560 * @param pids of dalvik VM processes to dump stack traces for
4561 * @return file containing stack traces, or null if no dump file is configured
4562 */
4563 private static File dumpStackTraces(ArrayList<Integer> pids) {
4564 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4565 if (tracesPath == null || tracesPath.length() == 0) {
4566 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004567 }
Dan Egnor42471dd2010-01-07 17:25:22 -08004568
4569 File tracesFile = new File(tracesPath);
4570 try {
4571 File tracesDir = tracesFile.getParentFile();
4572 if (!tracesDir.exists()) tracesFile.mkdirs();
4573 FileUtils.setPermissions(tracesDir.getPath(), 0775, -1, -1); // drwxrwxr-x
4574
4575 if (tracesFile.exists()) tracesFile.delete();
4576 tracesFile.createNewFile();
4577 FileUtils.setPermissions(tracesFile.getPath(), 0666, -1, -1); // -rw-rw-rw-
4578 } catch (IOException e) {
4579 Log.w(TAG, "Unable to prepare ANR traces file: " + tracesPath, e);
4580 return null;
4581 }
4582
4583 // Use a FileObserver to detect when traces finish writing.
4584 // The order of traces is considered important to maintain for legibility.
4585 FileObserver observer = new FileObserver(tracesPath, FileObserver.CLOSE_WRITE) {
4586 public synchronized void onEvent(int event, String path) { notify(); }
4587 };
4588
4589 try {
4590 observer.startWatching();
4591 int num = pids.size();
4592 for (int i = 0; i < num; i++) {
4593 synchronized (observer) {
4594 Process.sendSignal(pids.get(i), Process.SIGNAL_QUIT);
4595 observer.wait(200); // Wait for write-close, give up after 200msec
4596 }
4597 }
4598 } catch (InterruptedException e) {
4599 Log.wtf(TAG, e);
4600 } finally {
4601 observer.stopWatching();
4602 }
4603
4604 return tracesFile;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004605 }
4606
Dan Egnor42471dd2010-01-07 17:25:22 -08004607 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
4608 HistoryRecord parent, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004609 if (app.notResponding || app.crashing) {
4610 return;
4611 }
Dan Egnor42471dd2010-01-07 17:25:22 -08004612
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004613 // Log the ANR to the event log.
Dan Egnor2780e732010-01-22 14:47:35 -08004614 EventLog.writeEvent(EventLogTags.AM_ANR, app.pid, app.processName, app.info.flags,
4615 annotation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004616
Dan Egnor42471dd2010-01-07 17:25:22 -08004617 // Dump thread traces as quickly as we can, starting with "interesting" processes.
4618 ArrayList<Integer> pids = new ArrayList<Integer>(20);
4619 pids.add(app.pid);
4620
4621 int parentPid = app.pid;
4622 if (parent != null && parent.app != null && parent.app.pid > 0) parentPid = parent.app.pid;
4623 if (parentPid != app.pid) pids.add(parentPid);
4624
4625 if (MY_PID != app.pid && MY_PID != parentPid) pids.add(MY_PID);
4626
4627 for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
4628 ProcessRecord r = mLruProcesses.get(i);
4629 if (r != null && r.thread != null) {
4630 int pid = r.pid;
4631 if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) pids.add(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004632 }
4633 }
4634
Dan Egnor42471dd2010-01-07 17:25:22 -08004635 File tracesFile = dumpStackTraces(pids);
4636
4637 // Log the ANR to the main log.
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004638 StringBuilder info = mStringBuilder;
4639 info.setLength(0);
Dan Egnor42471dd2010-01-07 17:25:22 -08004640 info.append("ANR in ").append(app.processName);
4641 if (activity != null && activity.shortComponentName != null) {
4642 info.append(" (").append(activity.shortComponentName).append(")");
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004643 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004644 if (annotation != null) {
Dan Egnor42471dd2010-01-07 17:25:22 -08004645 info.append("\nReason: ").append(annotation).append("\n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004646 }
Dan Egnor42471dd2010-01-07 17:25:22 -08004647 if (parent != null && parent != activity) {
4648 info.append("\nParent: ").append(parent.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004649 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004650
Dan Egnor42471dd2010-01-07 17:25:22 -08004651 String cpuInfo = null;
4652 if (MONITOR_CPU_USAGE) {
4653 updateCpuStatsNow();
4654 synchronized (mProcessStatsThread) { cpuInfo = mProcessStats.printCurrentState(); }
4655 info.append(cpuInfo);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004656 }
4657
Dan Egnor42471dd2010-01-07 17:25:22 -08004658 Log.e(TAG, info.toString());
4659 if (tracesFile == null) {
4660 // There is no trace file, so dump (only) the alleged culprit's threads to the log
4661 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4662 }
4663
4664 addErrorToDropBox("anr", app, activity, parent, annotation, cpuInfo, tracesFile, null);
4665
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004666 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004667 try {
Dan Egnor42471dd2010-01-07 17:25:22 -08004668 // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately
4669 int res = mController.appNotResponding(app.processName, app.pid, info.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004670 if (res != 0) {
Dan Egnor42471dd2010-01-07 17:25:22 -08004671 if (res < 0 && app.pid != MY_PID) Process.killProcess(app.pid);
4672 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004673 }
4674 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004675 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004676 }
4677 }
4678
Dan Egnor42471dd2010-01-07 17:25:22 -08004679 // Unless configured otherwise, swallow ANRs in background processes & kill the process.
4680 boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
4681 Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
4682 if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
4683 Process.killProcess(app.pid);
4684 return;
4685 }
4686
4687 // Set the app's notResponding state, and look up the errorReportReceiver
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004688 makeAppNotRespondingLocked(app,
4689 activity != null ? activity.shortComponentName : null,
4690 annotation != null ? "ANR " + annotation : "ANR",
Dan Egnorb7f03672009-12-09 16:22:32 -08004691 info.toString());
Dan Egnor42471dd2010-01-07 17:25:22 -08004692
4693 // Bring up the infamous App Not Responding dialog
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004694 Message msg = Message.obtain();
4695 HashMap map = new HashMap();
4696 msg.what = SHOW_NOT_RESPONDING_MSG;
4697 msg.obj = map;
4698 map.put("app", app);
4699 if (activity != null) {
4700 map.put("activity", activity);
4701 }
4702
4703 mHandler.sendMessage(msg);
4704 return;
4705 }
4706
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004707 private final void decPersistentCountLocked(ProcessRecord app)
4708 {
4709 app.persistentActivities--;
4710 if (app.persistentActivities > 0) {
4711 // Still more of 'em...
4712 return;
4713 }
4714 if (app.persistent) {
4715 // Ah, but the application itself is persistent. Whatever!
4716 return;
4717 }
4718
4719 // App is no longer persistent... make sure it and the ones
4720 // following it in the LRU list have the correc oom_adj.
4721 updateOomAdjLocked();
4722 }
4723
4724 public void setPersistent(IBinder token, boolean isPersistent) {
4725 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4726 != PackageManager.PERMISSION_GRANTED) {
4727 String msg = "Permission Denial: setPersistent() from pid="
4728 + Binder.getCallingPid()
4729 + ", uid=" + Binder.getCallingUid()
4730 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4731 Log.w(TAG, msg);
4732 throw new SecurityException(msg);
4733 }
4734
4735 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004736 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004737 if (index < 0) {
4738 return;
4739 }
4740 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4741 ProcessRecord app = r.app;
4742
4743 if (localLOGV) Log.v(
4744 TAG, "Setting persistence " + isPersistent + ": " + r);
4745
4746 if (isPersistent) {
4747 if (r.persistent) {
4748 // Okay okay, I heard you already!
4749 if (localLOGV) Log.v(TAG, "Already persistent!");
4750 return;
4751 }
4752 r.persistent = true;
4753 app.persistentActivities++;
4754 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4755 if (app.persistentActivities > 1) {
4756 // We aren't the first...
4757 if (localLOGV) Log.v(TAG, "Not the first!");
4758 return;
4759 }
4760 if (app.persistent) {
4761 // This would be redundant.
4762 if (localLOGV) Log.v(TAG, "App is persistent!");
4763 return;
4764 }
4765
4766 // App is now persistent... make sure it and the ones
4767 // following it now have the correct oom_adj.
4768 final long origId = Binder.clearCallingIdentity();
4769 updateOomAdjLocked();
4770 Binder.restoreCallingIdentity(origId);
4771
4772 } else {
4773 if (!r.persistent) {
4774 // Okay okay, I heard you already!
4775 return;
4776 }
4777 r.persistent = false;
4778 final long origId = Binder.clearCallingIdentity();
4779 decPersistentCountLocked(app);
4780 Binder.restoreCallingIdentity(origId);
4781
4782 }
4783 }
4784 }
4785
4786 public boolean clearApplicationUserData(final String packageName,
4787 final IPackageDataObserver observer) {
4788 int uid = Binder.getCallingUid();
4789 int pid = Binder.getCallingPid();
4790 long callingId = Binder.clearCallingIdentity();
4791 try {
4792 IPackageManager pm = ActivityThread.getPackageManager();
4793 int pkgUid = -1;
4794 synchronized(this) {
4795 try {
4796 pkgUid = pm.getPackageUid(packageName);
4797 } catch (RemoteException e) {
4798 }
4799 if (pkgUid == -1) {
4800 Log.w(TAG, "Invalid packageName:" + packageName);
4801 return false;
4802 }
4803 if (uid == pkgUid || checkComponentPermission(
4804 android.Manifest.permission.CLEAR_APP_USER_DATA,
4805 pid, uid, -1)
4806 == PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08004807 forceStopPackageLocked(packageName, pkgUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004808 } else {
4809 throw new SecurityException(pid+" does not have permission:"+
4810 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4811 "for process:"+packageName);
4812 }
4813 }
4814
4815 try {
4816 //clear application user data
4817 pm.clearApplicationUserData(packageName, observer);
4818 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4819 Uri.fromParts("package", packageName, null));
4820 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4821 broadcastIntentLocked(null, null, intent,
4822 null, null, 0, null, null, null,
4823 false, false, MY_PID, Process.SYSTEM_UID);
4824 } catch (RemoteException e) {
4825 }
4826 } finally {
4827 Binder.restoreCallingIdentity(callingId);
4828 }
4829 return true;
4830 }
4831
Dianne Hackborn03abb812010-01-04 18:43:19 -08004832 public void killBackgroundProcesses(final String packageName) {
4833 if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
4834 != PackageManager.PERMISSION_GRANTED &&
4835 checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4836 != PackageManager.PERMISSION_GRANTED) {
4837 String msg = "Permission Denial: killBackgroundProcesses() from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004838 + Binder.getCallingPid()
4839 + ", uid=" + Binder.getCallingUid()
Dianne Hackborn03abb812010-01-04 18:43:19 -08004840 + " requires " + android.Manifest.permission.KILL_BACKGROUND_PROCESSES;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004841 Log.w(TAG, msg);
4842 throw new SecurityException(msg);
4843 }
4844
4845 long callingId = Binder.clearCallingIdentity();
4846 try {
4847 IPackageManager pm = ActivityThread.getPackageManager();
4848 int pkgUid = -1;
4849 synchronized(this) {
4850 try {
4851 pkgUid = pm.getPackageUid(packageName);
4852 } catch (RemoteException e) {
4853 }
4854 if (pkgUid == -1) {
4855 Log.w(TAG, "Invalid packageName: " + packageName);
4856 return;
4857 }
Dianne Hackborn03abb812010-01-04 18:43:19 -08004858 killPackageProcessesLocked(packageName, pkgUid,
4859 SECONDARY_SERVER_ADJ, false);
4860 }
4861 } finally {
4862 Binder.restoreCallingIdentity(callingId);
4863 }
4864 }
4865
4866 public void forceStopPackage(final String packageName) {
4867 if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
4868 != PackageManager.PERMISSION_GRANTED) {
4869 String msg = "Permission Denial: forceStopPackage() from pid="
4870 + Binder.getCallingPid()
4871 + ", uid=" + Binder.getCallingUid()
4872 + " requires " + android.Manifest.permission.FORCE_STOP_PACKAGES;
4873 Log.w(TAG, msg);
4874 throw new SecurityException(msg);
4875 }
4876
4877 long callingId = Binder.clearCallingIdentity();
4878 try {
4879 IPackageManager pm = ActivityThread.getPackageManager();
4880 int pkgUid = -1;
4881 synchronized(this) {
4882 try {
4883 pkgUid = pm.getPackageUid(packageName);
4884 } catch (RemoteException e) {
4885 }
4886 if (pkgUid == -1) {
4887 Log.w(TAG, "Invalid packageName: " + packageName);
4888 return;
4889 }
4890 forceStopPackageLocked(packageName, pkgUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004891 }
4892 } finally {
4893 Binder.restoreCallingIdentity(callingId);
4894 }
4895 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004896
4897 /*
4898 * The pkg name and uid have to be specified.
4899 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4900 */
4901 public void killApplicationWithUid(String pkg, int uid) {
4902 if (pkg == null) {
4903 return;
4904 }
4905 // Make sure the uid is valid.
4906 if (uid < 0) {
4907 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4908 return;
4909 }
4910 int callerUid = Binder.getCallingUid();
4911 // Only the system server can kill an application
4912 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004913 // Post an aysnc message to kill the application
4914 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4915 msg.arg1 = uid;
4916 msg.arg2 = 0;
4917 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004918 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004919 } else {
4920 throw new SecurityException(callerUid + " cannot kill pkg: " +
4921 pkg);
4922 }
4923 }
4924
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004925 public void closeSystemDialogs(String reason) {
4926 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4927 if (reason != null) {
4928 intent.putExtra("reason", reason);
4929 }
4930
4931 final int uid = Binder.getCallingUid();
4932 final long origId = Binder.clearCallingIdentity();
4933 synchronized (this) {
4934 int i = mWatchers.beginBroadcast();
4935 while (i > 0) {
4936 i--;
4937 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4938 if (w != null) {
4939 try {
4940 w.closingSystemDialogs(reason);
4941 } catch (RemoteException e) {
4942 }
4943 }
4944 }
4945 mWatchers.finishBroadcast();
4946
Dianne Hackbornffa42482009-09-23 22:20:11 -07004947 mWindowManager.closeSystemDialogs(reason);
4948
4949 for (i=mHistory.size()-1; i>=0; i--) {
4950 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4951 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
4952 finishActivityLocked(r, i,
4953 Activity.RESULT_CANCELED, null, "close-sys");
4954 }
4955 }
4956
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004957 broadcastIntentLocked(null, null, intent, null,
4958 null, 0, null, null, null, false, false, -1, uid);
4959 }
4960 Binder.restoreCallingIdentity(origId);
4961 }
4962
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004963 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004964 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004965 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
4966 for (int i=pids.length-1; i>=0; i--) {
4967 infos[i] = new Debug.MemoryInfo();
4968 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004969 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004970 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004971 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07004972
4973 public void killApplicationProcess(String processName, int uid) {
4974 if (processName == null) {
4975 return;
4976 }
4977
4978 int callerUid = Binder.getCallingUid();
4979 // Only the system server can kill an application
4980 if (callerUid == Process.SYSTEM_UID) {
4981 synchronized (this) {
4982 ProcessRecord app = getProcessRecordLocked(processName, uid);
4983 if (app != null) {
4984 try {
4985 app.thread.scheduleSuicide();
4986 } catch (RemoteException e) {
4987 // If the other end already died, then our work here is done.
4988 }
4989 } else {
4990 Log.w(TAG, "Process/uid not found attempting kill of "
4991 + processName + " / " + uid);
4992 }
4993 }
4994 } else {
4995 throw new SecurityException(callerUid + " cannot kill app process: " +
4996 processName);
4997 }
4998 }
4999
Dianne Hackborn03abb812010-01-04 18:43:19 -08005000 private void forceStopPackageLocked(final String packageName, int uid) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08005001 forceStopPackageLocked(packageName, uid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005002 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
5003 Uri.fromParts("package", packageName, null));
5004 intent.putExtra(Intent.EXTRA_UID, uid);
5005 broadcastIntentLocked(null, null, intent,
5006 null, null, 0, null, null, null,
5007 false, false, MY_PID, Process.SYSTEM_UID);
5008 }
5009
Dianne Hackborn03abb812010-01-04 18:43:19 -08005010 private final void killPackageProcessesLocked(String packageName, int uid,
5011 int minOomAdj, boolean callerWillRestart) {
5012 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005013
Dianne Hackborn03abb812010-01-04 18:43:19 -08005014 // Remove all processes this package may have touched: all with the
5015 // same UID (except for the system or root user), and all whose name
5016 // matches the package name.
5017 final String procNamePrefix = packageName + ":";
5018 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5019 final int NA = apps.size();
5020 for (int ia=0; ia<NA; ia++) {
5021 ProcessRecord app = apps.valueAt(ia);
5022 if (app.removed) {
5023 procs.add(app);
5024 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5025 || app.processName.equals(packageName)
5026 || app.processName.startsWith(procNamePrefix)) {
5027 if (app.setAdj >= minOomAdj) {
5028 app.removed = true;
5029 procs.add(app);
5030 }
5031 }
5032 }
5033 }
5034
5035 int N = procs.size();
5036 for (int i=0; i<N; i++) {
5037 removeProcessLocked(procs.get(i), callerWillRestart);
5038 }
5039 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08005040
Dianne Hackborn03abb812010-01-04 18:43:19 -08005041 private final void forceStopPackageLocked(String name, int uid,
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08005042 boolean callerWillRestart, boolean purgeCache) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005043 int i, N;
5044
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005045 if (uid < 0) {
5046 try {
5047 uid = ActivityThread.getPackageManager().getPackageUid(name);
5048 } catch (RemoteException e) {
5049 }
5050 }
5051
Dianne Hackborn03abb812010-01-04 18:43:19 -08005052 Log.i(TAG, "Force stopping package " + name + " uid=" + uid);
5053
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005054 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
5055 while (badApps.hasNext()) {
5056 SparseArray<Long> ba = badApps.next();
5057 if (ba.get(uid) != null) {
5058 badApps.remove();
5059 }
5060 }
5061
Dianne Hackborn03abb812010-01-04 18:43:19 -08005062 killPackageProcessesLocked(name, uid, -100, callerWillRestart);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005063
5064 for (i=mHistory.size()-1; i>=0; i--) {
5065 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5066 if (r.packageName.equals(name)) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08005067 Log.i(TAG, " Force finishing activity " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005068 if (r.app != null) {
5069 r.app.removed = true;
5070 }
5071 r.app = null;
5072 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5073 }
5074 }
5075
5076 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5077 for (ServiceRecord service : mServices.values()) {
5078 if (service.packageName.equals(name)) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08005079 Log.i(TAG, " Force stopping service " + service);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005080 if (service.app != null) {
5081 service.app.removed = true;
5082 }
5083 service.app = null;
5084 services.add(service);
5085 }
5086 }
5087
5088 N = services.size();
5089 for (i=0; i<N; i++) {
5090 bringDownServiceLocked(services.get(i), true);
5091 }
5092
5093 resumeTopActivityLocked(null);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08005094 if (purgeCache) {
5095 AttributeCache ac = AttributeCache.instance();
5096 if (ac != null) {
5097 ac.removePackage(name);
5098 }
5099 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005100 }
5101
5102 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5103 final String name = app.processName;
5104 final int uid = app.info.uid;
Dianne Hackborn03abb812010-01-04 18:43:19 -08005105 if (DEBUG_PROCESSES) Log.d(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005106 TAG, "Force removing process " + app + " (" + name
5107 + "/" + uid + ")");
5108
5109 mProcessNames.remove(name, uid);
5110 boolean needRestart = false;
5111 if (app.pid > 0 && app.pid != MY_PID) {
5112 int pid = app.pid;
5113 synchronized (mPidsSelfLocked) {
5114 mPidsSelfLocked.remove(pid);
5115 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5116 }
5117 handleAppDiedLocked(app, true);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08005118 mLruProcesses.remove(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005119 Process.killProcess(pid);
5120
5121 if (app.persistent) {
5122 if (!callerWillRestart) {
5123 addAppLocked(app.info);
5124 } else {
5125 needRestart = true;
5126 }
5127 }
5128 } else {
5129 mRemovedProcesses.add(app);
5130 }
5131
5132 return needRestart;
5133 }
5134
5135 private final void processStartTimedOutLocked(ProcessRecord app) {
5136 final int pid = app.pid;
5137 boolean gone = false;
5138 synchronized (mPidsSelfLocked) {
5139 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5140 if (knownApp != null && knownApp.thread == null) {
5141 mPidsSelfLocked.remove(pid);
5142 gone = true;
5143 }
5144 }
5145
5146 if (gone) {
5147 Log.w(TAG, "Process " + app + " failed to attach");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005148 EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, pid, app.info.uid,
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005149 app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005150 mProcessNames.remove(app.processName, app.info.uid);
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005151 // Take care of any launching providers waiting for this process.
5152 checkAppInLaunchingProvidersLocked(app, true);
5153 // Take care of any services that are waiting for the process.
5154 for (int i=0; i<mPendingServices.size(); i++) {
5155 ServiceRecord sr = mPendingServices.get(i);
5156 if (app.info.uid == sr.appInfo.uid
5157 && app.processName.equals(sr.processName)) {
5158 Log.w(TAG, "Forcing bringing down service: " + sr);
5159 mPendingServices.remove(i);
5160 i--;
5161 bringDownServiceLocked(sr, true);
5162 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005163 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005164 Process.killProcess(pid);
Christopher Tate181fafa2009-05-14 11:12:14 -07005165 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5166 Log.w(TAG, "Unattached app died before backup, skipping");
5167 try {
5168 IBackupManager bm = IBackupManager.Stub.asInterface(
5169 ServiceManager.getService(Context.BACKUP_SERVICE));
5170 bm.agentDisconnected(app.info.packageName);
5171 } catch (RemoteException e) {
5172 // Can't happen; the backup manager is local
5173 }
5174 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005175 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5176 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5177 mPendingBroadcast = null;
5178 scheduleBroadcastsLocked();
5179 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005180 } else {
5181 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5182 }
5183 }
5184
5185 private final boolean attachApplicationLocked(IApplicationThread thread,
5186 int pid) {
5187
5188 // Find the application record that is being attached... either via
5189 // the pid if we are running in multiple processes, or just pull the
5190 // next app record if we are emulating process with anonymous threads.
5191 ProcessRecord app;
5192 if (pid != MY_PID && pid >= 0) {
5193 synchronized (mPidsSelfLocked) {
5194 app = mPidsSelfLocked.get(pid);
5195 }
5196 } else if (mStartingProcesses.size() > 0) {
5197 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005198 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005199 } else {
5200 app = null;
5201 }
5202
5203 if (app == null) {
5204 Log.w(TAG, "No pending application record for pid " + pid
5205 + " (IApplicationThread " + thread + "); dropping process");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005206 EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005207 if (pid > 0 && pid != MY_PID) {
5208 Process.killProcess(pid);
5209 } else {
5210 try {
5211 thread.scheduleExit();
5212 } catch (Exception e) {
5213 // Ignore exceptions.
5214 }
5215 }
5216 return false;
5217 }
5218
5219 // If this application record is still attached to a previous
5220 // process, clean it up now.
5221 if (app.thread != null) {
5222 handleAppDiedLocked(app, true);
5223 }
5224
5225 // Tell the process all about itself.
5226
5227 if (localLOGV) Log.v(
5228 TAG, "Binding process pid " + pid + " to record " + app);
5229
5230 String processName = app.processName;
5231 try {
5232 thread.asBinder().linkToDeath(new AppDeathRecipient(
5233 app, pid, thread), 0);
5234 } catch (RemoteException e) {
5235 app.resetPackageList();
5236 startProcessLocked(app, "link fail", processName);
5237 return false;
5238 }
5239
Doug Zongker2bec3d42009-12-04 12:52:44 -08005240 EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005241
5242 app.thread = thread;
5243 app.curAdj = app.setAdj = -100;
Dianne Hackborn09c916b2009-12-08 14:50:51 -08005244 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
5245 app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005246 app.forcingToForeground = null;
5247 app.foregroundServices = false;
5248 app.debugging = false;
5249
5250 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5251
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005252 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5253 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005254
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005255 if (!normalMode) {
5256 Log.i(TAG, "Launching preboot mode app: " + app);
5257 }
5258
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005259 if (localLOGV) Log.v(
5260 TAG, "New app record " + app
5261 + " thread=" + thread.asBinder() + " pid=" + pid);
5262 try {
5263 int testMode = IApplicationThread.DEBUG_OFF;
5264 if (mDebugApp != null && mDebugApp.equals(processName)) {
5265 testMode = mWaitForDebugger
5266 ? IApplicationThread.DEBUG_WAIT
5267 : IApplicationThread.DEBUG_ON;
5268 app.debugging = true;
5269 if (mDebugTransient) {
5270 mDebugApp = mOrigDebugApp;
5271 mWaitForDebugger = mOrigWaitForDebugger;
5272 }
5273 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005274
Christopher Tate181fafa2009-05-14 11:12:14 -07005275 // If the app is being launched for restore or full backup, set it up specially
5276 boolean isRestrictedBackupMode = false;
5277 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5278 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5279 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5280 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005281
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005282 ensurePackageDexOpt(app.instrumentationInfo != null
5283 ? app.instrumentationInfo.packageName
5284 : app.info.packageName);
5285 if (app.instrumentationClass != null) {
5286 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005287 }
Dianne Hackborndc6b6352009-09-30 14:20:09 -07005288 if (DEBUG_CONFIGURATION) Log.v(TAG, "Binding proc "
5289 + processName + " with config " + mConfiguration);
Dianne Hackborn1655be42009-05-08 14:29:01 -07005290 thread.bindApplication(processName, app.instrumentationInfo != null
5291 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005292 app.instrumentationClass, app.instrumentationProfileFile,
5293 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005294 isRestrictedBackupMode || !normalMode,
5295 mConfiguration, getCommonServicesLocked());
Dianne Hackborndd71fc82009-12-16 19:24:32 -08005296 updateLruProcessLocked(app, false, true);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005297 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005298 } catch (Exception e) {
5299 // todo: Yikes! What should we do? For now we will try to
5300 // start another process, but that could easily get us in
5301 // an infinite loop of restarting processes...
5302 Log.w(TAG, "Exception thrown during bind!", e);
5303
5304 app.resetPackageList();
5305 startProcessLocked(app, "bind fail", processName);
5306 return false;
5307 }
5308
5309 // Remove this record from the list of starting applications.
5310 mPersistentStartingProcesses.remove(app);
5311 mProcessesOnHold.remove(app);
5312
5313 boolean badApp = false;
5314 boolean didSomething = false;
5315
5316 // See if the top visible activity is waiting to run in this process...
5317 HistoryRecord hr = topRunningActivityLocked(null);
5318 if (hr != null) {
5319 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5320 && processName.equals(hr.processName)) {
5321 try {
5322 if (realStartActivityLocked(hr, app, true, true)) {
5323 didSomething = true;
5324 }
5325 } catch (Exception e) {
5326 Log.w(TAG, "Exception in new application when starting activity "
5327 + hr.intent.getComponent().flattenToShortString(), e);
5328 badApp = true;
5329 }
5330 } else {
5331 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5332 }
5333 }
5334
5335 // Find any services that should be running in this process...
5336 if (!badApp && mPendingServices.size() > 0) {
5337 ServiceRecord sr = null;
5338 try {
5339 for (int i=0; i<mPendingServices.size(); i++) {
5340 sr = mPendingServices.get(i);
5341 if (app.info.uid != sr.appInfo.uid
5342 || !processName.equals(sr.processName)) {
5343 continue;
5344 }
5345
5346 mPendingServices.remove(i);
5347 i--;
5348 realStartServiceLocked(sr, app);
5349 didSomething = true;
5350 }
5351 } catch (Exception e) {
5352 Log.w(TAG, "Exception in new application when starting service "
5353 + sr.shortName, e);
5354 badApp = true;
5355 }
5356 }
5357
5358 // Check if the next broadcast receiver is in this process...
5359 BroadcastRecord br = mPendingBroadcast;
5360 if (!badApp && br != null && br.curApp == app) {
5361 try {
5362 mPendingBroadcast = null;
5363 processCurBroadcastLocked(br, app);
5364 didSomething = true;
5365 } catch (Exception e) {
5366 Log.w(TAG, "Exception in new application when starting receiver "
5367 + br.curComponent.flattenToShortString(), e);
5368 badApp = true;
5369 logBroadcastReceiverDiscard(br);
5370 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5371 br.resultExtras, br.resultAbort, true);
5372 scheduleBroadcastsLocked();
5373 }
5374 }
5375
Christopher Tate181fafa2009-05-14 11:12:14 -07005376 // Check whether the next backup agent is in this process...
5377 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5378 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005379 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005380 try {
5381 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5382 } catch (Exception e) {
5383 Log.w(TAG, "Exception scheduling backup agent creation: ");
5384 e.printStackTrace();
5385 }
5386 }
5387
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005388 if (badApp) {
5389 // todo: Also need to kill application to deal with all
5390 // kinds of exceptions.
5391 handleAppDiedLocked(app, false);
5392 return false;
5393 }
5394
5395 if (!didSomething) {
5396 updateOomAdjLocked();
5397 }
5398
5399 return true;
5400 }
5401
5402 public final void attachApplication(IApplicationThread thread) {
5403 synchronized (this) {
5404 int callingPid = Binder.getCallingPid();
5405 final long origId = Binder.clearCallingIdentity();
5406 attachApplicationLocked(thread, callingPid);
5407 Binder.restoreCallingIdentity(origId);
5408 }
5409 }
5410
Dianne Hackborne88846e2009-09-30 21:34:25 -07005411 public final void activityIdle(IBinder token, Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005412 final long origId = Binder.clearCallingIdentity();
Dianne Hackborne88846e2009-09-30 21:34:25 -07005413 activityIdleInternal(token, false, config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005414 Binder.restoreCallingIdentity(origId);
5415 }
5416
5417 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5418 boolean remove) {
5419 int N = mStoppingActivities.size();
5420 if (N <= 0) return null;
5421
5422 ArrayList<HistoryRecord> stops = null;
5423
5424 final boolean nowVisible = mResumedActivity != null
5425 && mResumedActivity.nowVisible
5426 && !mResumedActivity.waitingVisible;
5427 for (int i=0; i<N; i++) {
5428 HistoryRecord s = mStoppingActivities.get(i);
5429 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5430 + nowVisible + " waitingVisible=" + s.waitingVisible
5431 + " finishing=" + s.finishing);
5432 if (s.waitingVisible && nowVisible) {
5433 mWaitingVisibleActivities.remove(s);
5434 s.waitingVisible = false;
5435 if (s.finishing) {
5436 // If this activity is finishing, it is sitting on top of
5437 // everyone else but we now know it is no longer needed...
5438 // so get rid of it. Otherwise, we need to go through the
5439 // normal flow and hide it once we determine that it is
5440 // hidden by the activities in front of it.
5441 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5442 mWindowManager.setAppVisibility(s, false);
5443 }
5444 }
5445 if (!s.waitingVisible && remove) {
5446 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5447 if (stops == null) {
5448 stops = new ArrayList<HistoryRecord>();
5449 }
5450 stops.add(s);
5451 mStoppingActivities.remove(i);
5452 N--;
5453 i--;
5454 }
5455 }
5456
5457 return stops;
5458 }
5459
5460 void enableScreenAfterBoot() {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005461 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005462 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005463 mWindowManager.enableScreenAfterBoot();
5464 }
5465
Dianne Hackborne88846e2009-09-30 21:34:25 -07005466 final void activityIdleInternal(IBinder token, boolean fromTimeout,
5467 Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005468 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5469
5470 ArrayList<HistoryRecord> stops = null;
5471 ArrayList<HistoryRecord> finishes = null;
5472 ArrayList<HistoryRecord> thumbnails = null;
5473 int NS = 0;
5474 int NF = 0;
5475 int NT = 0;
5476 IApplicationThread sendThumbnail = null;
5477 boolean booting = false;
5478 boolean enableScreen = false;
5479
5480 synchronized (this) {
5481 if (token != null) {
5482 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5483 }
5484
5485 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005486 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005487 if (index >= 0) {
5488 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5489
Dianne Hackborne88846e2009-09-30 21:34:25 -07005490 // This is a hack to semi-deal with a race condition
5491 // in the client where it can be constructed with a
5492 // newer configuration from when we asked it to launch.
5493 // We'll update with whatever configuration it now says
5494 // it used to launch.
5495 if (config != null) {
5496 r.configuration = config;
5497 }
5498
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005499 // No longer need to keep the device awake.
5500 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5501 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5502 mLaunchingActivity.release();
5503 }
5504
5505 // We are now idle. If someone is waiting for a thumbnail from
5506 // us, we can now deliver.
5507 r.idle = true;
5508 scheduleAppGcsLocked();
5509 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5510 sendThumbnail = r.app.thread;
5511 r.thumbnailNeeded = false;
5512 }
5513
5514 // If this activity is fullscreen, set up to hide those under it.
5515
5516 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5517 ensureActivitiesVisibleLocked(null, 0);
5518
5519 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5520 if (!mBooted && !fromTimeout) {
5521 mBooted = true;
5522 enableScreen = true;
5523 }
5524 }
5525
5526 // Atomically retrieve all of the other things to do.
5527 stops = processStoppingActivitiesLocked(true);
5528 NS = stops != null ? stops.size() : 0;
5529 if ((NF=mFinishingActivities.size()) > 0) {
5530 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5531 mFinishingActivities.clear();
5532 }
5533 if ((NT=mCancelledThumbnails.size()) > 0) {
5534 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5535 mCancelledThumbnails.clear();
5536 }
5537
5538 booting = mBooting;
5539 mBooting = false;
5540 }
5541
5542 int i;
5543
5544 // Send thumbnail if requested.
5545 if (sendThumbnail != null) {
5546 try {
5547 sendThumbnail.requestThumbnail(token);
5548 } catch (Exception e) {
5549 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5550 sendPendingThumbnail(null, token, null, null, true);
5551 }
5552 }
5553
5554 // Stop any activities that are scheduled to do so but have been
5555 // waiting for the next one to start.
5556 for (i=0; i<NS; i++) {
5557 HistoryRecord r = (HistoryRecord)stops.get(i);
5558 synchronized (this) {
5559 if (r.finishing) {
5560 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5561 } else {
5562 stopActivityLocked(r);
5563 }
5564 }
5565 }
5566
5567 // Finish any activities that are scheduled to do so but have been
5568 // waiting for the next one to start.
5569 for (i=0; i<NF; i++) {
5570 HistoryRecord r = (HistoryRecord)finishes.get(i);
5571 synchronized (this) {
5572 destroyActivityLocked(r, true);
5573 }
5574 }
5575
5576 // Report back to any thumbnail receivers.
5577 for (i=0; i<NT; i++) {
5578 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5579 sendPendingThumbnail(r, null, null, null, true);
5580 }
5581
5582 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005583 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005584 }
5585
5586 trimApplications();
5587 //dump();
5588 //mWindowManager.dump();
5589
5590 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005591 enableScreenAfterBoot();
5592 }
5593 }
5594
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005595 final void finishBooting() {
5596 // Ensure that any processes we had put on hold are now started
5597 // up.
5598 final int NP = mProcessesOnHold.size();
5599 if (NP > 0) {
5600 ArrayList<ProcessRecord> procs =
5601 new ArrayList<ProcessRecord>(mProcessesOnHold);
5602 for (int ip=0; ip<NP; ip++) {
5603 this.startProcessLocked(procs.get(ip), "on-hold", null);
5604 }
5605 }
5606 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5607 // Tell anyone interested that we are done booting!
5608 synchronized (this) {
5609 broadcastIntentLocked(null, null,
5610 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5611 null, null, 0, null, null,
5612 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5613 false, false, MY_PID, Process.SYSTEM_UID);
5614 }
5615 }
5616 }
5617
5618 final void ensureBootCompleted() {
5619 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005620 boolean enableScreen;
5621 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005622 booting = mBooting;
5623 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005624 enableScreen = !mBooted;
5625 mBooted = true;
5626 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005627
5628 if (booting) {
5629 finishBooting();
5630 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005631
5632 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005633 enableScreenAfterBoot();
5634 }
5635 }
5636
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005637 public final void activityPaused(IBinder token, Bundle icicle) {
5638 // Refuse possible leaked file descriptors
5639 if (icicle != null && icicle.hasFileDescriptors()) {
5640 throw new IllegalArgumentException("File descriptors passed in Bundle");
5641 }
5642
5643 final long origId = Binder.clearCallingIdentity();
5644 activityPaused(token, icicle, false);
5645 Binder.restoreCallingIdentity(origId);
5646 }
5647
5648 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5649 if (DEBUG_PAUSE) Log.v(
5650 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5651 + ", timeout=" + timeout);
5652
5653 HistoryRecord r = null;
5654
5655 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005656 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005657 if (index >= 0) {
5658 r = (HistoryRecord)mHistory.get(index);
5659 if (!timeout) {
5660 r.icicle = icicle;
5661 r.haveState = true;
5662 }
5663 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5664 if (mPausingActivity == r) {
5665 r.state = ActivityState.PAUSED;
5666 completePauseLocked();
5667 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005668 EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005669 System.identityHashCode(r), r.shortComponentName,
5670 mPausingActivity != null
5671 ? mPausingActivity.shortComponentName : "(none)");
5672 }
5673 }
5674 }
5675 }
5676
5677 public final void activityStopped(IBinder token, Bitmap thumbnail,
5678 CharSequence description) {
5679 if (localLOGV) Log.v(
5680 TAG, "Activity stopped: token=" + token);
5681
5682 HistoryRecord r = null;
5683
5684 final long origId = Binder.clearCallingIdentity();
5685
5686 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005687 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005688 if (index >= 0) {
5689 r = (HistoryRecord)mHistory.get(index);
5690 r.thumbnail = thumbnail;
5691 r.description = description;
5692 r.stopped = true;
5693 r.state = ActivityState.STOPPED;
5694 if (!r.finishing) {
5695 if (r.configDestroy) {
5696 destroyActivityLocked(r, true);
5697 resumeTopActivityLocked(null);
5698 }
5699 }
5700 }
5701 }
5702
5703 if (r != null) {
5704 sendPendingThumbnail(r, null, null, null, false);
5705 }
5706
5707 trimApplications();
5708
5709 Binder.restoreCallingIdentity(origId);
5710 }
5711
5712 public final void activityDestroyed(IBinder token) {
5713 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5714 synchronized (this) {
5715 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5716
Dianne Hackborn75b03852009-06-12 15:43:26 -07005717 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005718 if (index >= 0) {
5719 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5720 if (r.state == ActivityState.DESTROYING) {
5721 final long origId = Binder.clearCallingIdentity();
5722 removeActivityFromHistoryLocked(r);
5723 Binder.restoreCallingIdentity(origId);
5724 }
5725 }
5726 }
5727 }
5728
5729 public String getCallingPackage(IBinder token) {
5730 synchronized (this) {
5731 HistoryRecord r = getCallingRecordLocked(token);
Dianne Hackborn9bbcb912009-10-20 15:42:38 -07005732 return r != null && r.app != null ? r.info.packageName : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005733 }
5734 }
5735
5736 public ComponentName getCallingActivity(IBinder token) {
5737 synchronized (this) {
5738 HistoryRecord r = getCallingRecordLocked(token);
5739 return r != null ? r.intent.getComponent() : null;
5740 }
5741 }
5742
5743 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005744 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005745 if (index >= 0) {
5746 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5747 if (r != null) {
5748 return r.resultTo;
5749 }
5750 }
5751 return null;
5752 }
5753
5754 public ComponentName getActivityClassForToken(IBinder token) {
5755 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005756 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005757 if (index >= 0) {
5758 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5759 return r.intent.getComponent();
5760 }
5761 return null;
5762 }
5763 }
5764
5765 public String getPackageForToken(IBinder token) {
5766 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005767 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005768 if (index >= 0) {
5769 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5770 return r.packageName;
5771 }
5772 return null;
5773 }
5774 }
5775
5776 public IIntentSender getIntentSender(int type,
5777 String packageName, IBinder token, String resultWho,
5778 int requestCode, Intent intent, String resolvedType, int flags) {
5779 // Refuse possible leaked file descriptors
5780 if (intent != null && intent.hasFileDescriptors() == true) {
5781 throw new IllegalArgumentException("File descriptors passed in Intent");
5782 }
5783
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005784 if (type == INTENT_SENDER_BROADCAST) {
5785 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5786 throw new IllegalArgumentException(
5787 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5788 }
5789 }
5790
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005791 synchronized(this) {
5792 int callingUid = Binder.getCallingUid();
5793 try {
5794 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5795 Process.supportsProcesses()) {
5796 int uid = ActivityThread.getPackageManager()
5797 .getPackageUid(packageName);
5798 if (uid != Binder.getCallingUid()) {
5799 String msg = "Permission Denial: getIntentSender() from pid="
5800 + Binder.getCallingPid()
5801 + ", uid=" + Binder.getCallingUid()
5802 + ", (need uid=" + uid + ")"
5803 + " is not allowed to send as package " + packageName;
5804 Log.w(TAG, msg);
5805 throw new SecurityException(msg);
5806 }
5807 }
5808 } catch (RemoteException e) {
5809 throw new SecurityException(e);
5810 }
5811 HistoryRecord activity = null;
5812 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005813 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005814 if (index < 0) {
5815 return null;
5816 }
5817 activity = (HistoryRecord)mHistory.get(index);
5818 if (activity.finishing) {
5819 return null;
5820 }
5821 }
5822
5823 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5824 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5825 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5826 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5827 |PendingIntent.FLAG_UPDATE_CURRENT);
5828
5829 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5830 type, packageName, activity, resultWho,
5831 requestCode, intent, resolvedType, flags);
5832 WeakReference<PendingIntentRecord> ref;
5833 ref = mIntentSenderRecords.get(key);
5834 PendingIntentRecord rec = ref != null ? ref.get() : null;
5835 if (rec != null) {
5836 if (!cancelCurrent) {
5837 if (updateCurrent) {
5838 rec.key.requestIntent.replaceExtras(intent);
5839 }
5840 return rec;
5841 }
5842 rec.canceled = true;
5843 mIntentSenderRecords.remove(key);
5844 }
5845 if (noCreate) {
5846 return rec;
5847 }
5848 rec = new PendingIntentRecord(this, key, callingUid);
5849 mIntentSenderRecords.put(key, rec.ref);
5850 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5851 if (activity.pendingResults == null) {
5852 activity.pendingResults
5853 = new HashSet<WeakReference<PendingIntentRecord>>();
5854 }
5855 activity.pendingResults.add(rec.ref);
5856 }
5857 return rec;
5858 }
5859 }
5860
5861 public void cancelIntentSender(IIntentSender sender) {
5862 if (!(sender instanceof PendingIntentRecord)) {
5863 return;
5864 }
5865 synchronized(this) {
5866 PendingIntentRecord rec = (PendingIntentRecord)sender;
5867 try {
5868 int uid = ActivityThread.getPackageManager()
5869 .getPackageUid(rec.key.packageName);
5870 if (uid != Binder.getCallingUid()) {
5871 String msg = "Permission Denial: cancelIntentSender() from pid="
5872 + Binder.getCallingPid()
5873 + ", uid=" + Binder.getCallingUid()
5874 + " is not allowed to cancel packges "
5875 + rec.key.packageName;
5876 Log.w(TAG, msg);
5877 throw new SecurityException(msg);
5878 }
5879 } catch (RemoteException e) {
5880 throw new SecurityException(e);
5881 }
5882 cancelIntentSenderLocked(rec, true);
5883 }
5884 }
5885
5886 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5887 rec.canceled = true;
5888 mIntentSenderRecords.remove(rec.key);
5889 if (cleanActivity && rec.key.activity != null) {
5890 rec.key.activity.pendingResults.remove(rec.ref);
5891 }
5892 }
5893
5894 public String getPackageForIntentSender(IIntentSender pendingResult) {
5895 if (!(pendingResult instanceof PendingIntentRecord)) {
5896 return null;
5897 }
5898 synchronized(this) {
5899 try {
5900 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5901 return res.key.packageName;
5902 } catch (ClassCastException e) {
5903 }
5904 }
5905 return null;
5906 }
5907
5908 public void setProcessLimit(int max) {
5909 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5910 "setProcessLimit()");
5911 mProcessLimit = max;
5912 }
5913
5914 public int getProcessLimit() {
5915 return mProcessLimit;
5916 }
5917
5918 void foregroundTokenDied(ForegroundToken token) {
5919 synchronized (ActivityManagerService.this) {
5920 synchronized (mPidsSelfLocked) {
5921 ForegroundToken cur
5922 = mForegroundProcesses.get(token.pid);
5923 if (cur != token) {
5924 return;
5925 }
5926 mForegroundProcesses.remove(token.pid);
5927 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5928 if (pr == null) {
5929 return;
5930 }
5931 pr.forcingToForeground = null;
5932 pr.foregroundServices = false;
5933 }
5934 updateOomAdjLocked();
5935 }
5936 }
5937
5938 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5939 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5940 "setProcessForeground()");
5941 synchronized(this) {
5942 boolean changed = false;
5943
5944 synchronized (mPidsSelfLocked) {
5945 ProcessRecord pr = mPidsSelfLocked.get(pid);
5946 if (pr == null) {
5947 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5948 return;
5949 }
5950 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5951 if (oldToken != null) {
5952 oldToken.token.unlinkToDeath(oldToken, 0);
5953 mForegroundProcesses.remove(pid);
5954 pr.forcingToForeground = null;
5955 changed = true;
5956 }
5957 if (isForeground && token != null) {
5958 ForegroundToken newToken = new ForegroundToken() {
5959 public void binderDied() {
5960 foregroundTokenDied(this);
5961 }
5962 };
5963 newToken.pid = pid;
5964 newToken.token = token;
5965 try {
5966 token.linkToDeath(newToken, 0);
5967 mForegroundProcesses.put(pid, newToken);
5968 pr.forcingToForeground = token;
5969 changed = true;
5970 } catch (RemoteException e) {
5971 // If the process died while doing this, we will later
5972 // do the cleanup with the process death link.
5973 }
5974 }
5975 }
5976
5977 if (changed) {
5978 updateOomAdjLocked();
5979 }
5980 }
5981 }
5982
5983 // =========================================================
5984 // PERMISSIONS
5985 // =========================================================
5986
5987 static class PermissionController extends IPermissionController.Stub {
5988 ActivityManagerService mActivityManagerService;
5989 PermissionController(ActivityManagerService activityManagerService) {
5990 mActivityManagerService = activityManagerService;
5991 }
5992
5993 public boolean checkPermission(String permission, int pid, int uid) {
5994 return mActivityManagerService.checkPermission(permission, pid,
5995 uid) == PackageManager.PERMISSION_GRANTED;
5996 }
5997 }
5998
5999 /**
6000 * This can be called with or without the global lock held.
6001 */
6002 int checkComponentPermission(String permission, int pid, int uid,
6003 int reqUid) {
6004 // We might be performing an operation on behalf of an indirect binder
6005 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
6006 // client identity accordingly before proceeding.
6007 Identity tlsIdentity = sCallerIdentity.get();
6008 if (tlsIdentity != null) {
6009 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
6010 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
6011 uid = tlsIdentity.uid;
6012 pid = tlsIdentity.pid;
6013 }
6014
6015 // Root, system server and our own process get to do everything.
6016 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
6017 !Process.supportsProcesses()) {
6018 return PackageManager.PERMISSION_GRANTED;
6019 }
6020 // If the target requires a specific UID, always fail for others.
6021 if (reqUid >= 0 && uid != reqUid) {
root0369a7c2009-03-23 15:20:47 +01006022 Log.w(TAG, "Permission denied: checkComponentPermission() reqUid=" + reqUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006023 return PackageManager.PERMISSION_DENIED;
6024 }
6025 if (permission == null) {
6026 return PackageManager.PERMISSION_GRANTED;
6027 }
6028 try {
6029 return ActivityThread.getPackageManager()
6030 .checkUidPermission(permission, uid);
6031 } catch (RemoteException e) {
6032 // Should never happen, but if it does... deny!
6033 Log.e(TAG, "PackageManager is dead?!?", e);
6034 }
6035 return PackageManager.PERMISSION_DENIED;
6036 }
6037
6038 /**
6039 * As the only public entry point for permissions checking, this method
6040 * can enforce the semantic that requesting a check on a null global
6041 * permission is automatically denied. (Internally a null permission
6042 * string is used when calling {@link #checkComponentPermission} in cases
6043 * when only uid-based security is needed.)
6044 *
6045 * This can be called with or without the global lock held.
6046 */
6047 public int checkPermission(String permission, int pid, int uid) {
6048 if (permission == null) {
6049 return PackageManager.PERMISSION_DENIED;
6050 }
6051 return checkComponentPermission(permission, pid, uid, -1);
6052 }
6053
6054 /**
6055 * Binder IPC calls go through the public entry point.
6056 * This can be called with or without the global lock held.
6057 */
6058 int checkCallingPermission(String permission) {
6059 return checkPermission(permission,
6060 Binder.getCallingPid(),
6061 Binder.getCallingUid());
6062 }
6063
6064 /**
6065 * This can be called with or without the global lock held.
6066 */
6067 void enforceCallingPermission(String permission, String func) {
6068 if (checkCallingPermission(permission)
6069 == PackageManager.PERMISSION_GRANTED) {
6070 return;
6071 }
6072
6073 String msg = "Permission Denial: " + func + " from pid="
6074 + Binder.getCallingPid()
6075 + ", uid=" + Binder.getCallingUid()
6076 + " requires " + permission;
6077 Log.w(TAG, msg);
6078 throw new SecurityException(msg);
6079 }
6080
6081 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6082 ProviderInfo pi, int uid, int modeFlags) {
6083 try {
6084 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6085 if ((pi.readPermission != null) &&
6086 (pm.checkUidPermission(pi.readPermission, uid)
6087 != PackageManager.PERMISSION_GRANTED)) {
6088 return false;
6089 }
6090 }
6091 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6092 if ((pi.writePermission != null) &&
6093 (pm.checkUidPermission(pi.writePermission, uid)
6094 != PackageManager.PERMISSION_GRANTED)) {
6095 return false;
6096 }
6097 }
6098 return true;
6099 } catch (RemoteException e) {
6100 return false;
6101 }
6102 }
6103
6104 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6105 int modeFlags) {
6106 // Root gets to do everything.
6107 if (uid == 0 || !Process.supportsProcesses()) {
6108 return true;
6109 }
6110 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6111 if (perms == null) return false;
6112 UriPermission perm = perms.get(uri);
6113 if (perm == null) return false;
6114 return (modeFlags&perm.modeFlags) == modeFlags;
6115 }
6116
6117 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6118 // Another redirected-binder-call permissions check as in
6119 // {@link checkComponentPermission}.
6120 Identity tlsIdentity = sCallerIdentity.get();
6121 if (tlsIdentity != null) {
6122 uid = tlsIdentity.uid;
6123 pid = tlsIdentity.pid;
6124 }
6125
6126 // Our own process gets to do everything.
6127 if (pid == MY_PID) {
6128 return PackageManager.PERMISSION_GRANTED;
6129 }
6130 synchronized(this) {
6131 return checkUriPermissionLocked(uri, uid, modeFlags)
6132 ? PackageManager.PERMISSION_GRANTED
6133 : PackageManager.PERMISSION_DENIED;
6134 }
6135 }
6136
6137 private void grantUriPermissionLocked(int callingUid,
6138 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6139 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6140 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6141 if (modeFlags == 0) {
6142 return;
6143 }
6144
6145 final IPackageManager pm = ActivityThread.getPackageManager();
6146
6147 // If this is not a content: uri, we can't do anything with it.
6148 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6149 return;
6150 }
6151
6152 String name = uri.getAuthority();
6153 ProviderInfo pi = null;
6154 ContentProviderRecord cpr
6155 = (ContentProviderRecord)mProvidersByName.get(name);
6156 if (cpr != null) {
6157 pi = cpr.info;
6158 } else {
6159 try {
6160 pi = pm.resolveContentProvider(name,
6161 PackageManager.GET_URI_PERMISSION_PATTERNS);
6162 } catch (RemoteException ex) {
6163 }
6164 }
6165 if (pi == null) {
6166 Log.w(TAG, "No content provider found for: " + name);
6167 return;
6168 }
6169
6170 int targetUid;
6171 try {
6172 targetUid = pm.getPackageUid(targetPkg);
6173 if (targetUid < 0) {
6174 return;
6175 }
6176 } catch (RemoteException ex) {
6177 return;
6178 }
6179
6180 // First... does the target actually need this permission?
6181 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6182 // No need to grant the target this permission.
6183 return;
6184 }
6185
6186 // Second... maybe someone else has already granted the
6187 // permission?
6188 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6189 // No need to grant the target this permission.
6190 return;
6191 }
6192
6193 // Third... is the provider allowing granting of URI permissions?
6194 if (!pi.grantUriPermissions) {
6195 throw new SecurityException("Provider " + pi.packageName
6196 + "/" + pi.name
6197 + " does not allow granting of Uri permissions (uri "
6198 + uri + ")");
6199 }
6200 if (pi.uriPermissionPatterns != null) {
6201 final int N = pi.uriPermissionPatterns.length;
6202 boolean allowed = false;
6203 for (int i=0; i<N; i++) {
6204 if (pi.uriPermissionPatterns[i] != null
6205 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6206 allowed = true;
6207 break;
6208 }
6209 }
6210 if (!allowed) {
6211 throw new SecurityException("Provider " + pi.packageName
6212 + "/" + pi.name
6213 + " does not allow granting of permission to path of Uri "
6214 + uri);
6215 }
6216 }
6217
6218 // Fourth... does the caller itself have permission to access
6219 // this uri?
6220 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6221 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6222 throw new SecurityException("Uid " + callingUid
6223 + " does not have permission to uri " + uri);
6224 }
6225 }
6226
6227 // Okay! So here we are: the caller has the assumed permission
6228 // to the uri, and the target doesn't. Let's now give this to
6229 // the target.
6230
6231 HashMap<Uri, UriPermission> targetUris
6232 = mGrantedUriPermissions.get(targetUid);
6233 if (targetUris == null) {
6234 targetUris = new HashMap<Uri, UriPermission>();
6235 mGrantedUriPermissions.put(targetUid, targetUris);
6236 }
6237
6238 UriPermission perm = targetUris.get(uri);
6239 if (perm == null) {
6240 perm = new UriPermission(targetUid, uri);
6241 targetUris.put(uri, perm);
6242
6243 }
6244 perm.modeFlags |= modeFlags;
6245 if (activity == null) {
6246 perm.globalModeFlags |= modeFlags;
6247 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6248 perm.readActivities.add(activity);
6249 if (activity.readUriPermissions == null) {
6250 activity.readUriPermissions = new HashSet<UriPermission>();
6251 }
6252 activity.readUriPermissions.add(perm);
6253 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6254 perm.writeActivities.add(activity);
6255 if (activity.writeUriPermissions == null) {
6256 activity.writeUriPermissions = new HashSet<UriPermission>();
6257 }
6258 activity.writeUriPermissions.add(perm);
6259 }
6260 }
6261
6262 private void grantUriPermissionFromIntentLocked(int callingUid,
6263 String targetPkg, Intent intent, HistoryRecord activity) {
6264 if (intent == null) {
6265 return;
6266 }
6267 Uri data = intent.getData();
6268 if (data == null) {
6269 return;
6270 }
6271 grantUriPermissionLocked(callingUid, targetPkg, data,
6272 intent.getFlags(), activity);
6273 }
6274
6275 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6276 Uri uri, int modeFlags) {
6277 synchronized(this) {
6278 final ProcessRecord r = getRecordForAppLocked(caller);
6279 if (r == null) {
6280 throw new SecurityException("Unable to find app for caller "
6281 + caller
6282 + " when granting permission to uri " + uri);
6283 }
6284 if (targetPkg == null) {
6285 Log.w(TAG, "grantUriPermission: null target");
6286 return;
6287 }
6288 if (uri == null) {
6289 Log.w(TAG, "grantUriPermission: null uri");
6290 return;
6291 }
6292
6293 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6294 null);
6295 }
6296 }
6297
6298 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6299 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6300 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6301 HashMap<Uri, UriPermission> perms
6302 = mGrantedUriPermissions.get(perm.uid);
6303 if (perms != null) {
6304 perms.remove(perm.uri);
6305 if (perms.size() == 0) {
6306 mGrantedUriPermissions.remove(perm.uid);
6307 }
6308 }
6309 }
6310 }
6311
6312 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6313 if (activity.readUriPermissions != null) {
6314 for (UriPermission perm : activity.readUriPermissions) {
6315 perm.readActivities.remove(activity);
6316 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6317 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6318 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6319 removeUriPermissionIfNeededLocked(perm);
6320 }
6321 }
6322 }
6323 if (activity.writeUriPermissions != null) {
6324 for (UriPermission perm : activity.writeUriPermissions) {
6325 perm.writeActivities.remove(activity);
6326 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6327 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6328 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6329 removeUriPermissionIfNeededLocked(perm);
6330 }
6331 }
6332 }
6333 }
6334
6335 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6336 int modeFlags) {
6337 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6338 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6339 if (modeFlags == 0) {
6340 return;
6341 }
6342
6343 final IPackageManager pm = ActivityThread.getPackageManager();
6344
6345 final String authority = uri.getAuthority();
6346 ProviderInfo pi = null;
6347 ContentProviderRecord cpr
6348 = (ContentProviderRecord)mProvidersByName.get(authority);
6349 if (cpr != null) {
6350 pi = cpr.info;
6351 } else {
6352 try {
6353 pi = pm.resolveContentProvider(authority,
6354 PackageManager.GET_URI_PERMISSION_PATTERNS);
6355 } catch (RemoteException ex) {
6356 }
6357 }
6358 if (pi == null) {
6359 Log.w(TAG, "No content provider found for: " + authority);
6360 return;
6361 }
6362
6363 // Does the caller have this permission on the URI?
6364 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6365 // Right now, if you are not the original owner of the permission,
6366 // you are not allowed to revoke it.
6367 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6368 throw new SecurityException("Uid " + callingUid
6369 + " does not have permission to uri " + uri);
6370 //}
6371 }
6372
6373 // Go through all of the permissions and remove any that match.
6374 final List<String> SEGMENTS = uri.getPathSegments();
6375 if (SEGMENTS != null) {
6376 final int NS = SEGMENTS.size();
6377 int N = mGrantedUriPermissions.size();
6378 for (int i=0; i<N; i++) {
6379 HashMap<Uri, UriPermission> perms
6380 = mGrantedUriPermissions.valueAt(i);
6381 Iterator<UriPermission> it = perms.values().iterator();
6382 toploop:
6383 while (it.hasNext()) {
6384 UriPermission perm = it.next();
6385 Uri targetUri = perm.uri;
6386 if (!authority.equals(targetUri.getAuthority())) {
6387 continue;
6388 }
6389 List<String> targetSegments = targetUri.getPathSegments();
6390 if (targetSegments == null) {
6391 continue;
6392 }
6393 if (targetSegments.size() < NS) {
6394 continue;
6395 }
6396 for (int j=0; j<NS; j++) {
6397 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6398 continue toploop;
6399 }
6400 }
6401 perm.clearModes(modeFlags);
6402 if (perm.modeFlags == 0) {
6403 it.remove();
6404 }
6405 }
6406 if (perms.size() == 0) {
6407 mGrantedUriPermissions.remove(
6408 mGrantedUriPermissions.keyAt(i));
6409 N--;
6410 i--;
6411 }
6412 }
6413 }
6414 }
6415
6416 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6417 int modeFlags) {
6418 synchronized(this) {
6419 final ProcessRecord r = getRecordForAppLocked(caller);
6420 if (r == null) {
6421 throw new SecurityException("Unable to find app for caller "
6422 + caller
6423 + " when revoking permission to uri " + uri);
6424 }
6425 if (uri == null) {
6426 Log.w(TAG, "revokeUriPermission: null uri");
6427 return;
6428 }
6429
6430 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6431 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6432 if (modeFlags == 0) {
6433 return;
6434 }
6435
6436 final IPackageManager pm = ActivityThread.getPackageManager();
6437
6438 final String authority = uri.getAuthority();
6439 ProviderInfo pi = null;
6440 ContentProviderRecord cpr
6441 = (ContentProviderRecord)mProvidersByName.get(authority);
6442 if (cpr != null) {
6443 pi = cpr.info;
6444 } else {
6445 try {
6446 pi = pm.resolveContentProvider(authority,
6447 PackageManager.GET_URI_PERMISSION_PATTERNS);
6448 } catch (RemoteException ex) {
6449 }
6450 }
6451 if (pi == null) {
6452 Log.w(TAG, "No content provider found for: " + authority);
6453 return;
6454 }
6455
6456 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6457 }
6458 }
6459
6460 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6461 synchronized (this) {
6462 ProcessRecord app =
6463 who != null ? getRecordForAppLocked(who) : null;
6464 if (app == null) return;
6465
6466 Message msg = Message.obtain();
6467 msg.what = WAIT_FOR_DEBUGGER_MSG;
6468 msg.obj = app;
6469 msg.arg1 = waiting ? 1 : 0;
6470 mHandler.sendMessage(msg);
6471 }
6472 }
6473
6474 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6475 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006476 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006477 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006478 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006479 }
6480
6481 // =========================================================
6482 // TASK MANAGEMENT
6483 // =========================================================
6484
6485 public List getTasks(int maxNum, int flags,
6486 IThumbnailReceiver receiver) {
6487 ArrayList list = new ArrayList();
6488
6489 PendingThumbnailsRecord pending = null;
6490 IApplicationThread topThumbnail = null;
6491 HistoryRecord topRecord = null;
6492
6493 synchronized(this) {
6494 if (localLOGV) Log.v(
6495 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6496 + ", receiver=" + receiver);
6497
6498 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6499 != PackageManager.PERMISSION_GRANTED) {
6500 if (receiver != null) {
6501 // If the caller wants to wait for pending thumbnails,
6502 // it ain't gonna get them.
6503 try {
6504 receiver.finished();
6505 } catch (RemoteException ex) {
6506 }
6507 }
6508 String msg = "Permission Denial: getTasks() from pid="
6509 + Binder.getCallingPid()
6510 + ", uid=" + Binder.getCallingUid()
6511 + " requires " + android.Manifest.permission.GET_TASKS;
6512 Log.w(TAG, msg);
6513 throw new SecurityException(msg);
6514 }
6515
6516 int pos = mHistory.size()-1;
6517 HistoryRecord next =
6518 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6519 HistoryRecord top = null;
6520 CharSequence topDescription = null;
6521 TaskRecord curTask = null;
6522 int numActivities = 0;
6523 int numRunning = 0;
6524 while (pos >= 0 && maxNum > 0) {
6525 final HistoryRecord r = next;
6526 pos--;
6527 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6528
6529 // Initialize state for next task if needed.
6530 if (top == null ||
6531 (top.state == ActivityState.INITIALIZING
6532 && top.task == r.task)) {
6533 top = r;
6534 topDescription = r.description;
6535 curTask = r.task;
6536 numActivities = numRunning = 0;
6537 }
6538
6539 // Add 'r' into the current task.
6540 numActivities++;
6541 if (r.app != null && r.app.thread != null) {
6542 numRunning++;
6543 }
6544 if (topDescription == null) {
6545 topDescription = r.description;
6546 }
6547
6548 if (localLOGV) Log.v(
6549 TAG, r.intent.getComponent().flattenToShortString()
6550 + ": task=" + r.task);
6551
6552 // If the next one is a different task, generate a new
6553 // TaskInfo entry for what we have.
6554 if (next == null || next.task != curTask) {
6555 ActivityManager.RunningTaskInfo ci
6556 = new ActivityManager.RunningTaskInfo();
6557 ci.id = curTask.taskId;
6558 ci.baseActivity = r.intent.getComponent();
6559 ci.topActivity = top.intent.getComponent();
6560 ci.thumbnail = top.thumbnail;
6561 ci.description = topDescription;
6562 ci.numActivities = numActivities;
6563 ci.numRunning = numRunning;
6564 //System.out.println(
6565 // "#" + maxNum + ": " + " descr=" + ci.description);
6566 if (ci.thumbnail == null && receiver != null) {
6567 if (localLOGV) Log.v(
6568 TAG, "State=" + top.state + "Idle=" + top.idle
6569 + " app=" + top.app
6570 + " thr=" + (top.app != null ? top.app.thread : null));
6571 if (top.state == ActivityState.RESUMED
6572 || top.state == ActivityState.PAUSING) {
6573 if (top.idle && top.app != null
6574 && top.app.thread != null) {
6575 topRecord = top;
6576 topThumbnail = top.app.thread;
6577 } else {
6578 top.thumbnailNeeded = true;
6579 }
6580 }
6581 if (pending == null) {
6582 pending = new PendingThumbnailsRecord(receiver);
6583 }
6584 pending.pendingRecords.add(top);
6585 }
6586 list.add(ci);
6587 maxNum--;
6588 top = null;
6589 }
6590 }
6591
6592 if (pending != null) {
6593 mPendingThumbnails.add(pending);
6594 }
6595 }
6596
6597 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6598
6599 if (topThumbnail != null) {
6600 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6601 try {
6602 topThumbnail.requestThumbnail(topRecord);
6603 } catch (Exception e) {
6604 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6605 sendPendingThumbnail(null, topRecord, null, null, true);
6606 }
6607 }
6608
6609 if (pending == null && receiver != null) {
6610 // In this case all thumbnails were available and the client
6611 // is being asked to be told when the remaining ones come in...
6612 // which is unusually, since the top-most currently running
6613 // activity should never have a canned thumbnail! Oh well.
6614 try {
6615 receiver.finished();
6616 } catch (RemoteException ex) {
6617 }
6618 }
6619
6620 return list;
6621 }
6622
6623 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6624 int flags) {
6625 synchronized (this) {
6626 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6627 "getRecentTasks()");
6628
6629 final int N = mRecentTasks.size();
6630 ArrayList<ActivityManager.RecentTaskInfo> res
6631 = new ArrayList<ActivityManager.RecentTaskInfo>(
6632 maxNum < N ? maxNum : N);
6633 for (int i=0; i<N && maxNum > 0; i++) {
6634 TaskRecord tr = mRecentTasks.get(i);
6635 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6636 || (tr.intent == null)
6637 || ((tr.intent.getFlags()
6638 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6639 ActivityManager.RecentTaskInfo rti
6640 = new ActivityManager.RecentTaskInfo();
6641 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6642 rti.baseIntent = new Intent(
6643 tr.intent != null ? tr.intent : tr.affinityIntent);
6644 rti.origActivity = tr.origActivity;
6645 res.add(rti);
6646 maxNum--;
6647 }
6648 }
6649 return res;
6650 }
6651 }
6652
6653 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6654 int j;
6655 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6656 TaskRecord jt = startTask;
6657
6658 // First look backwards
6659 for (j=startIndex-1; j>=0; j--) {
6660 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6661 if (r.task != jt) {
6662 jt = r.task;
6663 if (affinity.equals(jt.affinity)) {
6664 return j;
6665 }
6666 }
6667 }
6668
6669 // Now look forwards
6670 final int N = mHistory.size();
6671 jt = startTask;
6672 for (j=startIndex+1; j<N; j++) {
6673 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6674 if (r.task != jt) {
6675 if (affinity.equals(jt.affinity)) {
6676 return j;
6677 }
6678 jt = r.task;
6679 }
6680 }
6681
6682 // Might it be at the top?
6683 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6684 return N-1;
6685 }
6686
6687 return -1;
6688 }
6689
6690 /**
6691 * Perform a reset of the given task, if needed as part of launching it.
6692 * Returns the new HistoryRecord at the top of the task.
6693 */
6694 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6695 HistoryRecord newActivity) {
6696 boolean forceReset = (newActivity.info.flags
6697 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6698 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6699 if ((newActivity.info.flags
6700 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6701 forceReset = true;
6702 }
6703 }
6704
6705 final TaskRecord task = taskTop.task;
6706
6707 // We are going to move through the history list so that we can look
6708 // at each activity 'target' with 'below' either the interesting
6709 // activity immediately below it in the stack or null.
6710 HistoryRecord target = null;
6711 int targetI = 0;
6712 int taskTopI = -1;
6713 int replyChainEnd = -1;
6714 int lastReparentPos = -1;
6715 for (int i=mHistory.size()-1; i>=-1; i--) {
6716 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6717
6718 if (below != null && below.finishing) {
6719 continue;
6720 }
6721 if (target == null) {
6722 target = below;
6723 targetI = i;
6724 // If we were in the middle of a reply chain before this
6725 // task, it doesn't appear like the root of the chain wants
6726 // anything interesting, so drop it.
6727 replyChainEnd = -1;
6728 continue;
6729 }
6730
6731 final int flags = target.info.flags;
6732
6733 final boolean finishOnTaskLaunch =
6734 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6735 final boolean allowTaskReparenting =
6736 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6737
6738 if (target.task == task) {
6739 // We are inside of the task being reset... we'll either
6740 // finish this activity, push it out for another task,
6741 // or leave it as-is. We only do this
6742 // for activities that are not the root of the task (since
6743 // if we finish the root, we may no longer have the task!).
6744 if (taskTopI < 0) {
6745 taskTopI = targetI;
6746 }
6747 if (below != null && below.task == task) {
6748 final boolean clearWhenTaskReset =
6749 (target.intent.getFlags()
6750 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006751 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006752 // If this activity is sending a reply to a previous
6753 // activity, we can't do anything with it now until
6754 // we reach the start of the reply chain.
6755 // XXX note that we are assuming the result is always
6756 // to the previous activity, which is almost always
6757 // the case but we really shouldn't count on.
6758 if (replyChainEnd < 0) {
6759 replyChainEnd = targetI;
6760 }
Ed Heyl73798232009-03-24 21:32:21 -07006761 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006762 && target.taskAffinity != null
6763 && !target.taskAffinity.equals(task.affinity)) {
6764 // If this activity has an affinity for another
6765 // task, then we need to move it out of here. We will
6766 // move it as far out of the way as possible, to the
6767 // bottom of the activity stack. This also keeps it
6768 // correctly ordered with any activities we previously
6769 // moved.
6770 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6771 if (target.taskAffinity != null
6772 && target.taskAffinity.equals(p.task.affinity)) {
6773 // If the activity currently at the bottom has the
6774 // same task affinity as the one we are moving,
6775 // then merge it into the same task.
6776 target.task = p.task;
6777 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6778 + " out to bottom task " + p.task);
6779 } else {
6780 mCurTask++;
6781 if (mCurTask <= 0) {
6782 mCurTask = 1;
6783 }
6784 target.task = new TaskRecord(mCurTask, target.info, null,
6785 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6786 target.task.affinityIntent = target.intent;
6787 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6788 + " out to new task " + target.task);
6789 }
6790 mWindowManager.setAppGroupId(target, task.taskId);
6791 if (replyChainEnd < 0) {
6792 replyChainEnd = targetI;
6793 }
6794 int dstPos = 0;
6795 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6796 p = (HistoryRecord)mHistory.get(srcPos);
6797 if (p.finishing) {
6798 continue;
6799 }
6800 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6801 + " out to target's task " + target.task);
6802 task.numActivities--;
6803 p.task = target.task;
6804 target.task.numActivities++;
6805 mHistory.remove(srcPos);
6806 mHistory.add(dstPos, p);
6807 mWindowManager.moveAppToken(dstPos, p);
6808 mWindowManager.setAppGroupId(p, p.task.taskId);
6809 dstPos++;
6810 if (VALIDATE_TOKENS) {
6811 mWindowManager.validateAppTokens(mHistory);
6812 }
6813 i++;
6814 }
6815 if (taskTop == p) {
6816 taskTop = below;
6817 }
6818 if (taskTopI == replyChainEnd) {
6819 taskTopI = -1;
6820 }
6821 replyChainEnd = -1;
6822 addRecentTask(target.task);
6823 } else if (forceReset || finishOnTaskLaunch
6824 || clearWhenTaskReset) {
6825 // If the activity should just be removed -- either
6826 // because it asks for it, or the task should be
6827 // cleared -- then finish it and anything that is
6828 // part of its reply chain.
6829 if (clearWhenTaskReset) {
6830 // In this case, we want to finish this activity
6831 // and everything above it, so be sneaky and pretend
6832 // like these are all in the reply chain.
6833 replyChainEnd = targetI+1;
6834 while (replyChainEnd < mHistory.size() &&
6835 ((HistoryRecord)mHistory.get(
6836 replyChainEnd)).task == task) {
6837 replyChainEnd++;
6838 }
6839 replyChainEnd--;
6840 } else if (replyChainEnd < 0) {
6841 replyChainEnd = targetI;
6842 }
6843 HistoryRecord p = null;
6844 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6845 p = (HistoryRecord)mHistory.get(srcPos);
6846 if (p.finishing) {
6847 continue;
6848 }
6849 if (finishActivityLocked(p, srcPos,
6850 Activity.RESULT_CANCELED, null, "reset")) {
6851 replyChainEnd--;
6852 srcPos--;
6853 }
6854 }
6855 if (taskTop == p) {
6856 taskTop = below;
6857 }
6858 if (taskTopI == replyChainEnd) {
6859 taskTopI = -1;
6860 }
6861 replyChainEnd = -1;
6862 } else {
6863 // If we were in the middle of a chain, well the
6864 // activity that started it all doesn't want anything
6865 // special, so leave it all as-is.
6866 replyChainEnd = -1;
6867 }
6868 } else {
6869 // Reached the bottom of the task -- any reply chain
6870 // should be left as-is.
6871 replyChainEnd = -1;
6872 }
6873
6874 } else if (target.resultTo != null) {
6875 // If this activity is sending a reply to a previous
6876 // activity, we can't do anything with it now until
6877 // we reach the start of the reply chain.
6878 // XXX note that we are assuming the result is always
6879 // to the previous activity, which is almost always
6880 // the case but we really shouldn't count on.
6881 if (replyChainEnd < 0) {
6882 replyChainEnd = targetI;
6883 }
6884
6885 } else if (taskTopI >= 0 && allowTaskReparenting
6886 && task.affinity != null
6887 && task.affinity.equals(target.taskAffinity)) {
6888 // We are inside of another task... if this activity has
6889 // an affinity for our task, then either remove it if we are
6890 // clearing or move it over to our task. Note that
6891 // we currently punt on the case where we are resetting a
6892 // task that is not at the top but who has activities above
6893 // with an affinity to it... this is really not a normal
6894 // case, and we will need to later pull that task to the front
6895 // and usually at that point we will do the reset and pick
6896 // up those remaining activities. (This only happens if
6897 // someone starts an activity in a new task from an activity
6898 // in a task that is not currently on top.)
6899 if (forceReset || finishOnTaskLaunch) {
6900 if (replyChainEnd < 0) {
6901 replyChainEnd = targetI;
6902 }
6903 HistoryRecord p = null;
6904 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6905 p = (HistoryRecord)mHistory.get(srcPos);
6906 if (p.finishing) {
6907 continue;
6908 }
6909 if (finishActivityLocked(p, srcPos,
6910 Activity.RESULT_CANCELED, null, "reset")) {
6911 taskTopI--;
6912 lastReparentPos--;
6913 replyChainEnd--;
6914 srcPos--;
6915 }
6916 }
6917 replyChainEnd = -1;
6918 } else {
6919 if (replyChainEnd < 0) {
6920 replyChainEnd = targetI;
6921 }
6922 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6923 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6924 if (p.finishing) {
6925 continue;
6926 }
6927 if (lastReparentPos < 0) {
6928 lastReparentPos = taskTopI;
6929 taskTop = p;
6930 } else {
6931 lastReparentPos--;
6932 }
6933 mHistory.remove(srcPos);
6934 p.task.numActivities--;
6935 p.task = task;
6936 mHistory.add(lastReparentPos, p);
6937 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6938 + " in to resetting task " + task);
6939 task.numActivities++;
6940 mWindowManager.moveAppToken(lastReparentPos, p);
6941 mWindowManager.setAppGroupId(p, p.task.taskId);
6942 if (VALIDATE_TOKENS) {
6943 mWindowManager.validateAppTokens(mHistory);
6944 }
6945 }
6946 replyChainEnd = -1;
6947
6948 // Now we've moved it in to place... but what if this is
6949 // a singleTop activity and we have put it on top of another
6950 // instance of the same activity? Then we drop the instance
6951 // below so it remains singleTop.
6952 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6953 for (int j=lastReparentPos-1; j>=0; j--) {
6954 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6955 if (p.finishing) {
6956 continue;
6957 }
6958 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6959 if (finishActivityLocked(p, j,
6960 Activity.RESULT_CANCELED, null, "replace")) {
6961 taskTopI--;
6962 lastReparentPos--;
6963 }
6964 }
6965 }
6966 }
6967 }
6968 }
6969
6970 target = below;
6971 targetI = i;
6972 }
6973
6974 return taskTop;
6975 }
6976
6977 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006978 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006979 */
6980 public void moveTaskToFront(int task) {
6981 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6982 "moveTaskToFront()");
6983
6984 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006985 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6986 Binder.getCallingUid(), "Task to front")) {
6987 return;
6988 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006989 final long origId = Binder.clearCallingIdentity();
6990 try {
6991 int N = mRecentTasks.size();
6992 for (int i=0; i<N; i++) {
6993 TaskRecord tr = mRecentTasks.get(i);
6994 if (tr.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07006995 moveTaskToFrontLocked(tr, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006996 return;
6997 }
6998 }
6999 for (int i=mHistory.size()-1; i>=0; i--) {
7000 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
7001 if (hr.task.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007002 moveTaskToFrontLocked(hr.task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007003 return;
7004 }
7005 }
7006 } finally {
7007 Binder.restoreCallingIdentity(origId);
7008 }
7009 }
7010 }
7011
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007012 private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007013 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
7014
7015 final int task = tr.taskId;
7016 int top = mHistory.size()-1;
7017
7018 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
7019 // nothing to do!
7020 return;
7021 }
7022
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007023 ArrayList moved = new ArrayList();
7024
7025 // Applying the affinities may have removed entries from the history,
7026 // so get the size again.
7027 top = mHistory.size()-1;
7028 int pos = top;
7029
7030 // Shift all activities with this task up to the top
7031 // of the stack, keeping them in the same internal order.
7032 while (pos >= 0) {
7033 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7034 if (localLOGV) Log.v(
7035 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7036 boolean first = true;
7037 if (r.task.taskId == task) {
7038 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
7039 mHistory.remove(pos);
7040 mHistory.add(top, r);
7041 moved.add(0, r);
7042 top--;
7043 if (first) {
7044 addRecentTask(r.task);
7045 first = false;
7046 }
7047 }
7048 pos--;
7049 }
7050
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007051 if (DEBUG_TRANSITION) Log.v(TAG,
7052 "Prepare to front transition: task=" + tr);
7053 if (reason != null &&
7054 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7055 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7056 HistoryRecord r = topRunningActivityLocked(null);
7057 if (r != null) {
7058 mNoAnimActivities.add(r);
7059 }
7060 } else {
7061 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7062 }
7063
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007064 mWindowManager.moveAppTokensToTop(moved);
7065 if (VALIDATE_TOKENS) {
7066 mWindowManager.validateAppTokens(mHistory);
7067 }
7068
7069 finishTaskMove(task);
Doug Zongker2bec3d42009-12-04 12:52:44 -08007070 EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007071 }
7072
7073 private final void finishTaskMove(int task) {
7074 resumeTopActivityLocked(null);
7075 }
7076
7077 public void moveTaskToBack(int task) {
7078 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7079 "moveTaskToBack()");
7080
7081 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007082 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7083 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7084 Binder.getCallingUid(), "Task to back")) {
7085 return;
7086 }
7087 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007088 final long origId = Binder.clearCallingIdentity();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007089 moveTaskToBackLocked(task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007090 Binder.restoreCallingIdentity(origId);
7091 }
7092 }
7093
7094 /**
7095 * Moves an activity, and all of the other activities within the same task, to the bottom
7096 * of the history stack. The activity's order within the task is unchanged.
7097 *
7098 * @param token A reference to the activity we wish to move
7099 * @param nonRoot If false then this only works if the activity is the root
7100 * of a task; if true it will work for any activity in a task.
7101 * @return Returns true if the move completed, false if not.
7102 */
7103 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7104 synchronized(this) {
7105 final long origId = Binder.clearCallingIdentity();
7106 int taskId = getTaskForActivityLocked(token, !nonRoot);
7107 if (taskId >= 0) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007108 return moveTaskToBackLocked(taskId, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007109 }
7110 Binder.restoreCallingIdentity(origId);
7111 }
7112 return false;
7113 }
7114
7115 /**
7116 * Worker method for rearranging history stack. Implements the function of moving all
7117 * activities for a specific task (gathering them if disjoint) into a single group at the
7118 * bottom of the stack.
7119 *
7120 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7121 * to premeptively cancel the move.
7122 *
7123 * @param task The taskId to collect and move to the bottom.
7124 * @return Returns true if the move completed, false if not.
7125 */
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007126 private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007127 Log.i(TAG, "moveTaskToBack: " + task);
7128
7129 // If we have a watcher, preflight the move before committing to it. First check
7130 // for *other* available tasks, but if none are available, then try again allowing the
7131 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007132 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007133 HistoryRecord next = topRunningActivityLocked(null, task);
7134 if (next == null) {
7135 next = topRunningActivityLocked(null, 0);
7136 }
7137 if (next != null) {
7138 // ask watcher if this is allowed
7139 boolean moveOK = true;
7140 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007141 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007142 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007143 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007144 }
7145 if (!moveOK) {
7146 return false;
7147 }
7148 }
7149 }
7150
7151 ArrayList moved = new ArrayList();
7152
7153 if (DEBUG_TRANSITION) Log.v(TAG,
7154 "Prepare to back transition: task=" + task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007155
7156 final int N = mHistory.size();
7157 int bottom = 0;
7158 int pos = 0;
7159
7160 // Shift all activities with this task down to the bottom
7161 // of the stack, keeping them in the same internal order.
7162 while (pos < N) {
7163 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7164 if (localLOGV) Log.v(
7165 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7166 if (r.task.taskId == task) {
7167 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7168 mHistory.remove(pos);
7169 mHistory.add(bottom, r);
7170 moved.add(r);
7171 bottom++;
7172 }
7173 pos++;
7174 }
7175
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007176 if (reason != null &&
7177 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7178 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7179 HistoryRecord r = topRunningActivityLocked(null);
7180 if (r != null) {
7181 mNoAnimActivities.add(r);
7182 }
7183 } else {
Suchi Amalapurapuc9568e32009-11-05 18:51:16 -08007184 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007185 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007186 mWindowManager.moveAppTokensToBottom(moved);
7187 if (VALIDATE_TOKENS) {
7188 mWindowManager.validateAppTokens(mHistory);
7189 }
7190
7191 finishTaskMove(task);
7192 return true;
7193 }
7194
7195 public void moveTaskBackwards(int task) {
7196 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7197 "moveTaskBackwards()");
7198
7199 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007200 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7201 Binder.getCallingUid(), "Task backwards")) {
7202 return;
7203 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007204 final long origId = Binder.clearCallingIdentity();
7205 moveTaskBackwardsLocked(task);
7206 Binder.restoreCallingIdentity(origId);
7207 }
7208 }
7209
7210 private final void moveTaskBackwardsLocked(int task) {
7211 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7212 }
7213
7214 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7215 synchronized(this) {
7216 return getTaskForActivityLocked(token, onlyRoot);
7217 }
7218 }
7219
7220 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7221 final int N = mHistory.size();
7222 TaskRecord lastTask = null;
7223 for (int i=0; i<N; i++) {
7224 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7225 if (r == token) {
7226 if (!onlyRoot || lastTask != r.task) {
7227 return r.task.taskId;
7228 }
7229 return -1;
7230 }
7231 lastTask = r.task;
7232 }
7233
7234 return -1;
7235 }
7236
7237 /**
7238 * Returns the top activity in any existing task matching the given
7239 * Intent. Returns null if no such task is found.
7240 */
7241 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7242 ComponentName cls = intent.getComponent();
7243 if (info.targetActivity != null) {
7244 cls = new ComponentName(info.packageName, info.targetActivity);
7245 }
7246
7247 TaskRecord cp = null;
7248
7249 final int N = mHistory.size();
7250 for (int i=(N-1); i>=0; i--) {
7251 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7252 if (!r.finishing && r.task != cp
7253 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7254 cp = r.task;
7255 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7256 // + "/aff=" + r.task.affinity + " to new cls="
7257 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7258 if (r.task.affinity != null) {
7259 if (r.task.affinity.equals(info.taskAffinity)) {
7260 //Log.i(TAG, "Found matching affinity!");
7261 return r;
7262 }
7263 } else if (r.task.intent != null
7264 && r.task.intent.getComponent().equals(cls)) {
7265 //Log.i(TAG, "Found matching class!");
7266 //dump();
7267 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7268 return r;
7269 } else if (r.task.affinityIntent != null
7270 && r.task.affinityIntent.getComponent().equals(cls)) {
7271 //Log.i(TAG, "Found matching class!");
7272 //dump();
7273 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7274 return r;
7275 }
7276 }
7277 }
7278
7279 return null;
7280 }
7281
7282 /**
7283 * Returns the first activity (starting from the top of the stack) that
7284 * is the same as the given activity. Returns null if no such activity
7285 * is found.
7286 */
7287 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7288 ComponentName cls = intent.getComponent();
7289 if (info.targetActivity != null) {
7290 cls = new ComponentName(info.packageName, info.targetActivity);
7291 }
7292
7293 final int N = mHistory.size();
7294 for (int i=(N-1); i>=0; i--) {
7295 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7296 if (!r.finishing) {
7297 if (r.intent.getComponent().equals(cls)) {
7298 //Log.i(TAG, "Found matching class!");
7299 //dump();
7300 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7301 return r;
7302 }
7303 }
7304 }
7305
7306 return null;
7307 }
7308
7309 public void finishOtherInstances(IBinder token, ComponentName className) {
7310 synchronized(this) {
7311 final long origId = Binder.clearCallingIdentity();
7312
7313 int N = mHistory.size();
7314 TaskRecord lastTask = null;
7315 for (int i=0; i<N; i++) {
7316 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7317 if (r.realActivity.equals(className)
7318 && r != token && lastTask != r.task) {
7319 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7320 null, "others")) {
7321 i--;
7322 N--;
7323 }
7324 }
7325 lastTask = r.task;
7326 }
7327
7328 Binder.restoreCallingIdentity(origId);
7329 }
7330 }
7331
7332 // =========================================================
7333 // THUMBNAILS
7334 // =========================================================
7335
7336 public void reportThumbnail(IBinder token,
7337 Bitmap thumbnail, CharSequence description) {
7338 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7339 final long origId = Binder.clearCallingIdentity();
7340 sendPendingThumbnail(null, token, thumbnail, description, true);
7341 Binder.restoreCallingIdentity(origId);
7342 }
7343
7344 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7345 Bitmap thumbnail, CharSequence description, boolean always) {
7346 TaskRecord task = null;
7347 ArrayList receivers = null;
7348
7349 //System.out.println("Send pending thumbnail: " + r);
7350
7351 synchronized(this) {
7352 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007353 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007354 if (index < 0) {
7355 return;
7356 }
7357 r = (HistoryRecord)mHistory.get(index);
7358 }
7359 if (thumbnail == null) {
7360 thumbnail = r.thumbnail;
7361 description = r.description;
7362 }
7363 if (thumbnail == null && !always) {
7364 // If there is no thumbnail, and this entry is not actually
7365 // going away, then abort for now and pick up the next
7366 // thumbnail we get.
7367 return;
7368 }
7369 task = r.task;
7370
7371 int N = mPendingThumbnails.size();
7372 int i=0;
7373 while (i<N) {
7374 PendingThumbnailsRecord pr =
7375 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7376 //System.out.println("Looking in " + pr.pendingRecords);
7377 if (pr.pendingRecords.remove(r)) {
7378 if (receivers == null) {
7379 receivers = new ArrayList();
7380 }
7381 receivers.add(pr);
7382 if (pr.pendingRecords.size() == 0) {
7383 pr.finished = true;
7384 mPendingThumbnails.remove(i);
7385 N--;
7386 continue;
7387 }
7388 }
7389 i++;
7390 }
7391 }
7392
7393 if (receivers != null) {
7394 final int N = receivers.size();
7395 for (int i=0; i<N; i++) {
7396 try {
7397 PendingThumbnailsRecord pr =
7398 (PendingThumbnailsRecord)receivers.get(i);
7399 pr.receiver.newThumbnail(
7400 task != null ? task.taskId : -1, thumbnail, description);
7401 if (pr.finished) {
7402 pr.receiver.finished();
7403 }
7404 } catch (Exception e) {
7405 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7406 }
7407 }
7408 }
7409 }
7410
7411 // =========================================================
7412 // CONTENT PROVIDERS
7413 // =========================================================
7414
7415 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7416 List providers = null;
7417 try {
7418 providers = ActivityThread.getPackageManager().
7419 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007420 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007421 } catch (RemoteException ex) {
7422 }
7423 if (providers != null) {
7424 final int N = providers.size();
7425 for (int i=0; i<N; i++) {
7426 ProviderInfo cpi =
7427 (ProviderInfo)providers.get(i);
7428 ContentProviderRecord cpr =
7429 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7430 if (cpr == null) {
7431 cpr = new ContentProviderRecord(cpi, app.info);
7432 mProvidersByClass.put(cpi.name, cpr);
7433 }
7434 app.pubProviders.put(cpi.name, cpr);
7435 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007436 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007437 }
7438 }
7439 return providers;
7440 }
7441
7442 private final String checkContentProviderPermissionLocked(
7443 ProviderInfo cpi, ProcessRecord r, int mode) {
7444 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7445 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7446 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7447 cpi.exported ? -1 : cpi.applicationInfo.uid)
7448 == PackageManager.PERMISSION_GRANTED
7449 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7450 return null;
7451 }
7452 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7453 cpi.exported ? -1 : cpi.applicationInfo.uid)
7454 == PackageManager.PERMISSION_GRANTED) {
7455 return null;
7456 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007457
7458 PathPermission[] pps = cpi.pathPermissions;
7459 if (pps != null) {
7460 int i = pps.length;
7461 while (i > 0) {
7462 i--;
7463 PathPermission pp = pps[i];
7464 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7465 cpi.exported ? -1 : cpi.applicationInfo.uid)
7466 == PackageManager.PERMISSION_GRANTED
7467 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7468 return null;
7469 }
7470 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7471 cpi.exported ? -1 : cpi.applicationInfo.uid)
7472 == PackageManager.PERMISSION_GRANTED) {
7473 return null;
7474 }
7475 }
7476 }
7477
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007478 String msg = "Permission Denial: opening provider " + cpi.name
7479 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7480 + ", uid=" + callingUid + ") requires "
7481 + cpi.readPermission + " or " + cpi.writePermission;
7482 Log.w(TAG, msg);
7483 return msg;
7484 }
7485
7486 private final ContentProviderHolder getContentProviderImpl(
7487 IApplicationThread caller, String name) {
7488 ContentProviderRecord cpr;
7489 ProviderInfo cpi = null;
7490
7491 synchronized(this) {
7492 ProcessRecord r = null;
7493 if (caller != null) {
7494 r = getRecordForAppLocked(caller);
7495 if (r == null) {
7496 throw new SecurityException(
7497 "Unable to find app for caller " + caller
7498 + " (pid=" + Binder.getCallingPid()
7499 + ") when getting content provider " + name);
7500 }
7501 }
7502
7503 // First check if this content provider has been published...
7504 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7505 if (cpr != null) {
7506 cpi = cpr.info;
7507 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7508 return new ContentProviderHolder(cpi,
7509 cpi.readPermission != null
7510 ? cpi.readPermission : cpi.writePermission);
7511 }
7512
7513 if (r != null && cpr.canRunHere(r)) {
7514 // This provider has been published or is in the process
7515 // of being published... but it is also allowed to run
7516 // in the caller's process, so don't make a connection
7517 // and just let the caller instantiate its own instance.
7518 if (cpr.provider != null) {
7519 // don't give caller the provider object, it needs
7520 // to make its own.
7521 cpr = new ContentProviderRecord(cpr);
7522 }
7523 return cpr;
7524 }
7525
7526 final long origId = Binder.clearCallingIdentity();
7527
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007528 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007529 // return it right away.
7530 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007531 if (DEBUG_PROVIDER) Log.v(TAG,
7532 "Adding provider requested by "
7533 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007534 + cpr.info.processName);
7535 Integer cnt = r.conProviders.get(cpr);
7536 if (cnt == null) {
7537 r.conProviders.put(cpr, new Integer(1));
7538 } else {
7539 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7540 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007541 cpr.clients.add(r);
7542 } else {
7543 cpr.externals++;
7544 }
7545
7546 if (cpr.app != null) {
7547 updateOomAdjLocked(cpr.app);
7548 }
7549
7550 Binder.restoreCallingIdentity(origId);
7551
7552 } else {
7553 try {
7554 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007555 resolveContentProvider(name,
7556 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007557 } catch (RemoteException ex) {
7558 }
7559 if (cpi == null) {
7560 return null;
7561 }
7562
7563 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7564 return new ContentProviderHolder(cpi,
7565 cpi.readPermission != null
7566 ? cpi.readPermission : cpi.writePermission);
7567 }
7568
7569 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7570 final boolean firstClass = cpr == null;
7571 if (firstClass) {
7572 try {
7573 ApplicationInfo ai =
7574 ActivityThread.getPackageManager().
7575 getApplicationInfo(
7576 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007577 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007578 if (ai == null) {
7579 Log.w(TAG, "No package info for content provider "
7580 + cpi.name);
7581 return null;
7582 }
7583 cpr = new ContentProviderRecord(cpi, ai);
7584 } catch (RemoteException ex) {
7585 // pm is in same process, this will never happen.
7586 }
7587 }
7588
7589 if (r != null && cpr.canRunHere(r)) {
7590 // If this is a multiprocess provider, then just return its
7591 // info and allow the caller to instantiate it. Only do
7592 // this if the provider is the same user as the caller's
7593 // process, or can run as root (so can be in any process).
7594 return cpr;
7595 }
7596
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007597 if (DEBUG_PROVIDER) {
7598 RuntimeException e = new RuntimeException("here");
7599 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7600 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007601 }
7602
7603 // This is single process, and our app is now connecting to it.
7604 // See if we are already in the process of launching this
7605 // provider.
7606 final int N = mLaunchingProviders.size();
7607 int i;
7608 for (i=0; i<N; i++) {
7609 if (mLaunchingProviders.get(i) == cpr) {
7610 break;
7611 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007612 }
7613
7614 // If the provider is not already being launched, then get it
7615 // started.
7616 if (i >= N) {
7617 final long origId = Binder.clearCallingIdentity();
7618 ProcessRecord proc = startProcessLocked(cpi.processName,
7619 cpr.appInfo, false, 0, "content provider",
7620 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007621 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007622 if (proc == null) {
7623 Log.w(TAG, "Unable to launch app "
7624 + cpi.applicationInfo.packageName + "/"
7625 + cpi.applicationInfo.uid + " for provider "
7626 + name + ": process is bad");
7627 return null;
7628 }
7629 cpr.launchingApp = proc;
7630 mLaunchingProviders.add(cpr);
7631 Binder.restoreCallingIdentity(origId);
7632 }
7633
7634 // Make sure the provider is published (the same provider class
7635 // may be published under multiple names).
7636 if (firstClass) {
7637 mProvidersByClass.put(cpi.name, cpr);
7638 }
7639 mProvidersByName.put(name, cpr);
7640
7641 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007642 if (DEBUG_PROVIDER) Log.v(TAG,
7643 "Adding provider requested by "
7644 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007645 + cpr.info.processName);
7646 Integer cnt = r.conProviders.get(cpr);
7647 if (cnt == null) {
7648 r.conProviders.put(cpr, new Integer(1));
7649 } else {
7650 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7651 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007652 cpr.clients.add(r);
7653 } else {
7654 cpr.externals++;
7655 }
7656 }
7657 }
7658
7659 // Wait for the provider to be published...
7660 synchronized (cpr) {
7661 while (cpr.provider == null) {
7662 if (cpr.launchingApp == null) {
7663 Log.w(TAG, "Unable to launch app "
7664 + cpi.applicationInfo.packageName + "/"
7665 + cpi.applicationInfo.uid + " for provider "
7666 + name + ": launching app became null");
Doug Zongker2bec3d42009-12-04 12:52:44 -08007667 EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007668 cpi.applicationInfo.packageName,
7669 cpi.applicationInfo.uid, name);
7670 return null;
7671 }
7672 try {
7673 cpr.wait();
7674 } catch (InterruptedException ex) {
7675 }
7676 }
7677 }
7678 return cpr;
7679 }
7680
7681 public final ContentProviderHolder getContentProvider(
7682 IApplicationThread caller, String name) {
7683 if (caller == null) {
7684 String msg = "null IApplicationThread when getting content provider "
7685 + name;
7686 Log.w(TAG, msg);
7687 throw new SecurityException(msg);
7688 }
7689
7690 return getContentProviderImpl(caller, name);
7691 }
7692
7693 private ContentProviderHolder getContentProviderExternal(String name) {
7694 return getContentProviderImpl(null, name);
7695 }
7696
7697 /**
7698 * Drop a content provider from a ProcessRecord's bookkeeping
7699 * @param cpr
7700 */
7701 public void removeContentProvider(IApplicationThread caller, String name) {
7702 synchronized (this) {
7703 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7704 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007705 // remove from mProvidersByClass
7706 if (DEBUG_PROVIDER) Log.v(TAG, name +
7707 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007708 return;
7709 }
7710 final ProcessRecord r = getRecordForAppLocked(caller);
7711 if (r == null) {
7712 throw new SecurityException(
7713 "Unable to find app for caller " + caller +
7714 " when removing content provider " + name);
7715 }
7716 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007717 ContentProviderRecord localCpr = (ContentProviderRecord)
7718 mProvidersByClass.get(cpr.info.name);
7719 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7720 + r.info.processName + " from process "
7721 + localCpr.appInfo.processName);
7722 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007723 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007724 Log.w(TAG, "removeContentProvider called on local provider: "
7725 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007726 return;
7727 } else {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007728 Integer cnt = r.conProviders.get(localCpr);
7729 if (cnt == null || cnt.intValue() <= 1) {
7730 localCpr.clients.remove(r);
7731 r.conProviders.remove(localCpr);
7732 } else {
7733 r.conProviders.put(localCpr, new Integer(cnt.intValue()-1));
7734 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007735 }
7736 updateOomAdjLocked();
7737 }
7738 }
7739
7740 private void removeContentProviderExternal(String name) {
7741 synchronized (this) {
7742 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7743 if(cpr == null) {
7744 //remove from mProvidersByClass
7745 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7746 return;
7747 }
7748
7749 //update content provider record entry info
7750 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7751 localCpr.externals--;
7752 if (localCpr.externals < 0) {
7753 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7754 }
7755 updateOomAdjLocked();
7756 }
7757 }
7758
7759 public final void publishContentProviders(IApplicationThread caller,
7760 List<ContentProviderHolder> providers) {
7761 if (providers == null) {
7762 return;
7763 }
7764
7765 synchronized(this) {
7766 final ProcessRecord r = getRecordForAppLocked(caller);
7767 if (r == null) {
7768 throw new SecurityException(
7769 "Unable to find app for caller " + caller
7770 + " (pid=" + Binder.getCallingPid()
7771 + ") when publishing content providers");
7772 }
7773
7774 final long origId = Binder.clearCallingIdentity();
7775
7776 final int N = providers.size();
7777 for (int i=0; i<N; i++) {
7778 ContentProviderHolder src = providers.get(i);
7779 if (src == null || src.info == null || src.provider == null) {
7780 continue;
7781 }
7782 ContentProviderRecord dst =
7783 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7784 if (dst != null) {
7785 mProvidersByClass.put(dst.info.name, dst);
7786 String names[] = dst.info.authority.split(";");
7787 for (int j = 0; j < names.length; j++) {
7788 mProvidersByName.put(names[j], dst);
7789 }
7790
7791 int NL = mLaunchingProviders.size();
7792 int j;
7793 for (j=0; j<NL; j++) {
7794 if (mLaunchingProviders.get(j) == dst) {
7795 mLaunchingProviders.remove(j);
7796 j--;
7797 NL--;
7798 }
7799 }
7800 synchronized (dst) {
7801 dst.provider = src.provider;
7802 dst.app = r;
7803 dst.notifyAll();
7804 }
7805 updateOomAdjLocked(r);
7806 }
7807 }
7808
7809 Binder.restoreCallingIdentity(origId);
7810 }
7811 }
7812
7813 public static final void installSystemProviders() {
7814 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7815 List providers = mSelf.generateApplicationProvidersLocked(app);
7816 mSystemThread.installSystemProviders(providers);
7817 }
7818
7819 // =========================================================
7820 // GLOBAL MANAGEMENT
7821 // =========================================================
7822
7823 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7824 ApplicationInfo info, String customProcess) {
7825 String proc = customProcess != null ? customProcess : info.processName;
7826 BatteryStatsImpl.Uid.Proc ps = null;
7827 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7828 synchronized (stats) {
7829 ps = stats.getProcessStatsLocked(info.uid, proc);
7830 }
7831 return new ProcessRecord(ps, thread, info, proc);
7832 }
7833
7834 final ProcessRecord addAppLocked(ApplicationInfo info) {
7835 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7836
7837 if (app == null) {
7838 app = newProcessRecordLocked(null, info, null);
7839 mProcessNames.put(info.processName, info.uid, app);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08007840 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007841 }
7842
7843 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7844 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7845 app.persistent = true;
7846 app.maxAdj = CORE_SERVER_ADJ;
7847 }
7848 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7849 mPersistentStartingProcesses.add(app);
7850 startProcessLocked(app, "added application", app.processName);
7851 }
7852
7853 return app;
7854 }
7855
7856 public void unhandledBack() {
7857 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7858 "unhandledBack()");
7859
7860 synchronized(this) {
7861 int count = mHistory.size();
Dianne Hackborn03abb812010-01-04 18:43:19 -08007862 if (DEBUG_SWITCH) Log.d(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007863 TAG, "Performing unhandledBack(): stack size = " + count);
7864 if (count > 1) {
7865 final long origId = Binder.clearCallingIdentity();
7866 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7867 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7868 Binder.restoreCallingIdentity(origId);
7869 }
7870 }
7871 }
7872
7873 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7874 String name = uri.getAuthority();
7875 ContentProviderHolder cph = getContentProviderExternal(name);
7876 ParcelFileDescriptor pfd = null;
7877 if (cph != null) {
7878 // We record the binder invoker's uid in thread-local storage before
7879 // going to the content provider to open the file. Later, in the code
7880 // that handles all permissions checks, we look for this uid and use
7881 // that rather than the Activity Manager's own uid. The effect is that
7882 // we do the check against the caller's permissions even though it looks
7883 // to the content provider like the Activity Manager itself is making
7884 // the request.
7885 sCallerIdentity.set(new Identity(
7886 Binder.getCallingPid(), Binder.getCallingUid()));
7887 try {
7888 pfd = cph.provider.openFile(uri, "r");
7889 } catch (FileNotFoundException e) {
7890 // do nothing; pfd will be returned null
7891 } finally {
7892 // Ensure that whatever happens, we clean up the identity state
7893 sCallerIdentity.remove();
7894 }
7895
7896 // We've got the fd now, so we're done with the provider.
7897 removeContentProviderExternal(name);
7898 } else {
7899 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7900 }
7901 return pfd;
7902 }
7903
7904 public void goingToSleep() {
7905 synchronized(this) {
7906 mSleeping = true;
7907 mWindowManager.setEventDispatching(false);
7908
7909 if (mResumedActivity != null) {
7910 pauseIfSleepingLocked();
7911 } else {
7912 Log.w(TAG, "goingToSleep with no resumed activity!");
7913 }
7914 }
7915 }
7916
Dianne Hackborn55280a92009-05-07 15:53:46 -07007917 public boolean shutdown(int timeout) {
7918 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7919 != PackageManager.PERMISSION_GRANTED) {
7920 throw new SecurityException("Requires permission "
7921 + android.Manifest.permission.SHUTDOWN);
7922 }
7923
7924 boolean timedout = false;
7925
7926 synchronized(this) {
7927 mShuttingDown = true;
7928 mWindowManager.setEventDispatching(false);
7929
7930 if (mResumedActivity != null) {
7931 pauseIfSleepingLocked();
7932 final long endTime = System.currentTimeMillis() + timeout;
7933 while (mResumedActivity != null || mPausingActivity != null) {
7934 long delay = endTime - System.currentTimeMillis();
7935 if (delay <= 0) {
7936 Log.w(TAG, "Activity manager shutdown timed out");
7937 timedout = true;
7938 break;
7939 }
7940 try {
7941 this.wait();
7942 } catch (InterruptedException e) {
7943 }
7944 }
7945 }
7946 }
7947
7948 mUsageStatsService.shutdown();
7949 mBatteryStatsService.shutdown();
7950
7951 return timedout;
7952 }
7953
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007954 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007955 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007956 if (!mGoingToSleep.isHeld()) {
7957 mGoingToSleep.acquire();
7958 if (mLaunchingActivity.isHeld()) {
7959 mLaunchingActivity.release();
7960 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7961 }
7962 }
7963
7964 // If we are not currently pausing an activity, get the current
7965 // one to pause. If we are pausing one, we will just let that stuff
7966 // run and release the wake lock when all done.
7967 if (mPausingActivity == null) {
7968 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7969 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7970 startPausingLocked(false, true);
7971 }
7972 }
7973 }
7974
7975 public void wakingUp() {
7976 synchronized(this) {
7977 if (mGoingToSleep.isHeld()) {
7978 mGoingToSleep.release();
7979 }
7980 mWindowManager.setEventDispatching(true);
7981 mSleeping = false;
7982 resumeTopActivityLocked(null);
7983 }
7984 }
7985
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007986 public void stopAppSwitches() {
7987 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7988 != PackageManager.PERMISSION_GRANTED) {
7989 throw new SecurityException("Requires permission "
7990 + android.Manifest.permission.STOP_APP_SWITCHES);
7991 }
7992
7993 synchronized(this) {
7994 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7995 + APP_SWITCH_DELAY_TIME;
7996 mDidAppSwitch = false;
7997 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7998 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7999 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
8000 }
8001 }
8002
8003 public void resumeAppSwitches() {
8004 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8005 != PackageManager.PERMISSION_GRANTED) {
8006 throw new SecurityException("Requires permission "
8007 + android.Manifest.permission.STOP_APP_SWITCHES);
8008 }
8009
8010 synchronized(this) {
8011 // Note that we don't execute any pending app switches... we will
8012 // let those wait until either the timeout, or the next start
8013 // activity request.
8014 mAppSwitchesAllowedTime = 0;
8015 }
8016 }
8017
8018 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
8019 String name) {
8020 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
8021 return true;
8022 }
8023
8024 final int perm = checkComponentPermission(
8025 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
8026 callingUid, -1);
8027 if (perm == PackageManager.PERMISSION_GRANTED) {
8028 return true;
8029 }
8030
8031 Log.w(TAG, name + " request from " + callingUid + " stopped");
8032 return false;
8033 }
8034
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008035 public void setDebugApp(String packageName, boolean waitForDebugger,
8036 boolean persistent) {
8037 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
8038 "setDebugApp()");
8039
8040 // Note that this is not really thread safe if there are multiple
8041 // callers into it at the same time, but that's not a situation we
8042 // care about.
8043 if (persistent) {
8044 final ContentResolver resolver = mContext.getContentResolver();
8045 Settings.System.putString(
8046 resolver, Settings.System.DEBUG_APP,
8047 packageName);
8048 Settings.System.putInt(
8049 resolver, Settings.System.WAIT_FOR_DEBUGGER,
8050 waitForDebugger ? 1 : 0);
8051 }
8052
8053 synchronized (this) {
8054 if (!persistent) {
8055 mOrigDebugApp = mDebugApp;
8056 mOrigWaitForDebugger = mWaitForDebugger;
8057 }
8058 mDebugApp = packageName;
8059 mWaitForDebugger = waitForDebugger;
8060 mDebugTransient = !persistent;
8061 if (packageName != null) {
8062 final long origId = Binder.clearCallingIdentity();
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08008063 forceStopPackageLocked(packageName, -1, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008064 Binder.restoreCallingIdentity(origId);
8065 }
8066 }
8067 }
8068
8069 public void setAlwaysFinish(boolean enabled) {
8070 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
8071 "setAlwaysFinish()");
8072
8073 Settings.System.putInt(
8074 mContext.getContentResolver(),
8075 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
8076
8077 synchronized (this) {
8078 mAlwaysFinishActivities = enabled;
8079 }
8080 }
8081
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008082 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008083 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008084 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008085 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008086 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008087 }
8088 }
8089
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08008090 public boolean isUserAMonkey() {
8091 // For now the fact that there is a controller implies
8092 // we have a monkey.
8093 synchronized (this) {
8094 return mController != null;
8095 }
8096 }
8097
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008098 public void registerActivityWatcher(IActivityWatcher watcher) {
8099 mWatchers.register(watcher);
8100 }
8101
8102 public void unregisterActivityWatcher(IActivityWatcher watcher) {
8103 mWatchers.unregister(watcher);
8104 }
8105
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008106 public final void enterSafeMode() {
8107 synchronized(this) {
8108 // It only makes sense to do this before the system is ready
8109 // and started launching other packages.
8110 if (!mSystemReady) {
8111 try {
8112 ActivityThread.getPackageManager().enterSafeMode();
8113 } catch (RemoteException e) {
8114 }
8115
8116 View v = LayoutInflater.from(mContext).inflate(
8117 com.android.internal.R.layout.safe_mode, null);
8118 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8119 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8120 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8121 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8122 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8123 lp.format = v.getBackground().getOpacity();
8124 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8125 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8126 ((WindowManager)mContext.getSystemService(
8127 Context.WINDOW_SERVICE)).addView(v, lp);
8128 }
8129 }
8130 }
8131
8132 public void noteWakeupAlarm(IIntentSender sender) {
8133 if (!(sender instanceof PendingIntentRecord)) {
8134 return;
8135 }
8136 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8137 synchronized (stats) {
8138 if (mBatteryStatsService.isOnBattery()) {
8139 mBatteryStatsService.enforceCallingPermission();
8140 PendingIntentRecord rec = (PendingIntentRecord)sender;
8141 int MY_UID = Binder.getCallingUid();
8142 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8143 BatteryStatsImpl.Uid.Pkg pkg =
8144 stats.getPackageStatsLocked(uid, rec.key.packageName);
8145 pkg.incWakeupsLocked();
8146 }
8147 }
8148 }
8149
8150 public boolean killPidsForMemory(int[] pids) {
8151 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8152 throw new SecurityException("killPidsForMemory only available to the system");
8153 }
8154
8155 // XXX Note: don't acquire main activity lock here, because the window
8156 // manager calls in with its locks held.
8157
8158 boolean killed = false;
8159 synchronized (mPidsSelfLocked) {
8160 int[] types = new int[pids.length];
8161 int worstType = 0;
8162 for (int i=0; i<pids.length; i++) {
8163 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8164 if (proc != null) {
8165 int type = proc.setAdj;
8166 types[i] = type;
8167 if (type > worstType) {
8168 worstType = type;
8169 }
8170 }
8171 }
8172
8173 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8174 // then constrain it so we will kill all hidden procs.
8175 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8176 worstType = HIDDEN_APP_MIN_ADJ;
8177 }
8178 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8179 for (int i=0; i<pids.length; i++) {
8180 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8181 if (proc == null) {
8182 continue;
8183 }
8184 int adj = proc.setAdj;
8185 if (adj >= worstType) {
8186 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8187 + adj + ")");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008188 EventLog.writeEvent(EventLogTags.AM_KILL_FOR_MEMORY, proc.pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008189 proc.processName, adj);
8190 killed = true;
8191 Process.killProcess(pids[i]);
8192 }
8193 }
8194 }
8195 return killed;
8196 }
8197
8198 public void reportPss(IApplicationThread caller, int pss) {
8199 Watchdog.PssRequestor req;
8200 String name;
8201 ProcessRecord callerApp;
8202 synchronized (this) {
8203 if (caller == null) {
8204 return;
8205 }
8206 callerApp = getRecordForAppLocked(caller);
8207 if (callerApp == null) {
8208 return;
8209 }
8210 callerApp.lastPss = pss;
8211 req = callerApp;
8212 name = callerApp.processName;
8213 }
8214 Watchdog.getInstance().reportPss(req, name, pss);
8215 if (!callerApp.persistent) {
8216 removeRequestedPss(callerApp);
8217 }
8218 }
8219
8220 public void requestPss(Runnable completeCallback) {
8221 ArrayList<ProcessRecord> procs;
8222 synchronized (this) {
8223 mRequestPssCallback = completeCallback;
8224 mRequestPssList.clear();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008225 for (int i=mLruProcesses.size()-1; i>=0; i--) {
8226 ProcessRecord proc = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008227 if (!proc.persistent) {
8228 mRequestPssList.add(proc);
8229 }
8230 }
8231 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8232 }
8233
8234 int oldPri = Process.getThreadPriority(Process.myTid());
8235 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8236 for (int i=procs.size()-1; i>=0; i--) {
8237 ProcessRecord proc = procs.get(i);
8238 proc.lastPss = 0;
8239 proc.requestPss();
8240 }
8241 Process.setThreadPriority(oldPri);
8242 }
8243
8244 void removeRequestedPss(ProcessRecord proc) {
8245 Runnable callback = null;
8246 synchronized (this) {
8247 if (mRequestPssList.remove(proc)) {
8248 if (mRequestPssList.size() == 0) {
8249 callback = mRequestPssCallback;
8250 mRequestPssCallback = null;
8251 }
8252 }
8253 }
8254
8255 if (callback != null) {
8256 callback.run();
8257 }
8258 }
8259
8260 public void collectPss(Watchdog.PssStats stats) {
8261 stats.mEmptyPss = 0;
8262 stats.mEmptyCount = 0;
8263 stats.mBackgroundPss = 0;
8264 stats.mBackgroundCount = 0;
8265 stats.mServicePss = 0;
8266 stats.mServiceCount = 0;
8267 stats.mVisiblePss = 0;
8268 stats.mVisibleCount = 0;
8269 stats.mForegroundPss = 0;
8270 stats.mForegroundCount = 0;
8271 stats.mNoPssCount = 0;
8272 synchronized (this) {
8273 int i;
8274 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8275 ? mProcDeaths.length : stats.mProcDeaths.length;
8276 int aggr = 0;
8277 for (i=0; i<NPD; i++) {
8278 aggr += mProcDeaths[i];
8279 stats.mProcDeaths[i] = aggr;
8280 }
8281 while (i<stats.mProcDeaths.length) {
8282 stats.mProcDeaths[i] = 0;
8283 i++;
8284 }
8285
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008286 for (i=mLruProcesses.size()-1; i>=0; i--) {
8287 ProcessRecord proc = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008288 if (proc.persistent) {
8289 continue;
8290 }
8291 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8292 if (proc.lastPss == 0) {
8293 stats.mNoPssCount++;
8294 continue;
8295 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008296 if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8297 if (proc.empty) {
8298 stats.mEmptyPss += proc.lastPss;
8299 stats.mEmptyCount++;
8300 } else {
8301 stats.mBackgroundPss += proc.lastPss;
8302 stats.mBackgroundCount++;
8303 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008304 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8305 stats.mVisiblePss += proc.lastPss;
8306 stats.mVisibleCount++;
8307 } else {
8308 stats.mForegroundPss += proc.lastPss;
8309 stats.mForegroundCount++;
8310 }
8311 }
8312 }
8313 }
8314
8315 public final void startRunning(String pkg, String cls, String action,
8316 String data) {
8317 synchronized(this) {
8318 if (mStartRunning) {
8319 return;
8320 }
8321 mStartRunning = true;
8322 mTopComponent = pkg != null && cls != null
8323 ? new ComponentName(pkg, cls) : null;
8324 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8325 mTopData = data;
8326 if (!mSystemReady) {
8327 return;
8328 }
8329 }
8330
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008331 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008332 }
8333
8334 private void retrieveSettings() {
8335 final ContentResolver resolver = mContext.getContentResolver();
8336 String debugApp = Settings.System.getString(
8337 resolver, Settings.System.DEBUG_APP);
8338 boolean waitForDebugger = Settings.System.getInt(
8339 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8340 boolean alwaysFinishActivities = Settings.System.getInt(
8341 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8342
8343 Configuration configuration = new Configuration();
8344 Settings.System.getConfiguration(resolver, configuration);
8345
8346 synchronized (this) {
8347 mDebugApp = mOrigDebugApp = debugApp;
8348 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8349 mAlwaysFinishActivities = alwaysFinishActivities;
8350 // This happens before any activities are started, so we can
8351 // change mConfiguration in-place.
8352 mConfiguration.updateFrom(configuration);
Dianne Hackborndc6b6352009-09-30 14:20:09 -07008353 if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008354 }
8355 }
8356
8357 public boolean testIsSystemReady() {
8358 // no need to synchronize(this) just to read & return the value
8359 return mSystemReady;
8360 }
8361
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008362 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008363 // In the simulator, startRunning will never have been called, which
8364 // normally sets a few crucial variables. Do it here instead.
8365 if (!Process.supportsProcesses()) {
8366 mStartRunning = true;
8367 mTopAction = Intent.ACTION_MAIN;
8368 }
8369
8370 synchronized(this) {
8371 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008372 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008373 return;
8374 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008375
8376 // Check to see if there are any update receivers to run.
8377 if (!mDidUpdate) {
8378 if (mWaitingUpdate) {
8379 return;
8380 }
8381 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8382 List<ResolveInfo> ris = null;
8383 try {
8384 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8385 intent, null, 0);
8386 } catch (RemoteException e) {
8387 }
8388 if (ris != null) {
8389 for (int i=ris.size()-1; i>=0; i--) {
8390 if ((ris.get(i).activityInfo.applicationInfo.flags
8391 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8392 ris.remove(i);
8393 }
8394 }
8395 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8396 for (int i=0; i<ris.size(); i++) {
8397 ActivityInfo ai = ris.get(i).activityInfo;
8398 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8399 IIntentReceiver finisher = null;
Dianne Hackbornd6847842010-01-12 18:14:19 -08008400 if (i == ris.size()-1) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008401 finisher = new IIntentReceiver.Stub() {
8402 public void performReceive(Intent intent, int resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -07008403 String data, Bundle extras, boolean ordered,
8404 boolean sticky)
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008405 throws RemoteException {
8406 synchronized (ActivityManagerService.this) {
8407 mDidUpdate = true;
8408 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008409 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008410 }
8411 };
8412 }
8413 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8414 broadcastIntentLocked(null, null, intent, null, finisher,
8415 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornd6847842010-01-12 18:14:19 -08008416 if (finisher != null) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008417 mWaitingUpdate = true;
8418 }
8419 }
8420 }
8421 if (mWaitingUpdate) {
8422 return;
8423 }
8424 mDidUpdate = true;
8425 }
8426
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008427 mSystemReady = true;
8428 if (!mStartRunning) {
8429 return;
8430 }
8431 }
8432
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008433 ArrayList<ProcessRecord> procsToKill = null;
8434 synchronized(mPidsSelfLocked) {
8435 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8436 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8437 if (!isAllowedWhileBooting(proc.info)){
8438 if (procsToKill == null) {
8439 procsToKill = new ArrayList<ProcessRecord>();
8440 }
8441 procsToKill.add(proc);
8442 }
8443 }
8444 }
8445
8446 if (procsToKill != null) {
8447 synchronized(this) {
8448 for (int i=procsToKill.size()-1; i>=0; i--) {
8449 ProcessRecord proc = procsToKill.get(i);
8450 Log.i(TAG, "Removing system update proc: " + proc);
8451 removeProcessLocked(proc, true);
8452 }
8453 }
8454 }
8455
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008456 Log.i(TAG, "System now ready");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008457 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008458 SystemClock.uptimeMillis());
8459
8460 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008461 // Make sure we have no pre-ready processes sitting around.
8462
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008463 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8464 ResolveInfo ri = mContext.getPackageManager()
8465 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008466 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008467 CharSequence errorMsg = null;
8468 if (ri != null) {
8469 ActivityInfo ai = ri.activityInfo;
8470 ApplicationInfo app = ai.applicationInfo;
8471 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8472 mTopAction = Intent.ACTION_FACTORY_TEST;
8473 mTopData = null;
8474 mTopComponent = new ComponentName(app.packageName,
8475 ai.name);
8476 } else {
8477 errorMsg = mContext.getResources().getText(
8478 com.android.internal.R.string.factorytest_not_system);
8479 }
8480 } else {
8481 errorMsg = mContext.getResources().getText(
8482 com.android.internal.R.string.factorytest_no_action);
8483 }
8484 if (errorMsg != null) {
8485 mTopAction = null;
8486 mTopData = null;
8487 mTopComponent = null;
8488 Message msg = Message.obtain();
8489 msg.what = SHOW_FACTORY_ERROR_MSG;
8490 msg.getData().putCharSequence("msg", errorMsg);
8491 mHandler.sendMessage(msg);
8492 }
8493 }
8494 }
8495
8496 retrieveSettings();
8497
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008498 if (goingCallback != null) goingCallback.run();
8499
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008500 synchronized (this) {
8501 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8502 try {
8503 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008504 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008505 if (apps != null) {
8506 int N = apps.size();
8507 int i;
8508 for (i=0; i<N; i++) {
8509 ApplicationInfo info
8510 = (ApplicationInfo)apps.get(i);
8511 if (info != null &&
8512 !info.packageName.equals("android")) {
8513 addAppLocked(info);
8514 }
8515 }
8516 }
8517 } catch (RemoteException ex) {
8518 // pm is in same process, this will never happen.
8519 }
8520 }
8521
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008522 // Start up initial activity.
8523 mBooting = true;
8524
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008525 try {
8526 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8527 Message msg = Message.obtain();
8528 msg.what = SHOW_UID_ERROR_MSG;
8529 mHandler.sendMessage(msg);
8530 }
8531 } catch (RemoteException e) {
8532 }
8533
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008534 resumeTopActivityLocked(null);
8535 }
8536 }
8537
Dan Egnorb7f03672009-12-09 16:22:32 -08008538 private boolean makeAppCrashingLocked(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008539 String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008540 app.crashing = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008541 app.crashingReport = generateProcessError(app,
Dan Egnor60d87622009-12-16 16:32:58 -08008542 ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008543 startAppProblemLocked(app);
8544 app.stopFreezingAllLocked();
8545 return handleAppCrashLocked(app);
8546 }
8547
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008548 private ComponentName getErrorReportReceiver(ProcessRecord app) {
Doug Zongker43866e02010-01-07 12:09:54 -08008549 // check if error reporting is enabled in secure settings
8550 int enabled = Settings.Secure.getInt(mContext.getContentResolver(),
8551 Settings.Secure.SEND_ACTION_APP_ERROR, 0);
Jacek Surazskia2339432009-09-18 15:01:26 +02008552 if (enabled == 0) {
8553 return null;
8554 }
8555
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008556 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008557
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008558 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008559 // look for receiver in the installer package
8560 String candidate = pm.getInstallerPackageName(app.info.packageName);
8561 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8562 if (result != null) {
8563 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008564 }
8565
Jacek Surazski82a73df2009-06-17 14:33:18 +02008566 // if the error app is on the system image, look for system apps
8567 // error receiver
8568 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8569 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8570 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8571 if (result != null) {
8572 return result;
8573 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008574 }
8575
Jacek Surazski82a73df2009-06-17 14:33:18 +02008576 // if there is a default receiver, try that
8577 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8578 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008579 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008580 // should not happen
8581 Log.e(TAG, "error talking to PackageManager", e);
8582 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008583 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008584 }
8585
8586 /**
8587 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8588 *
8589 * @param pm PackageManager isntance
8590 * @param errorPackage package which caused the error
8591 * @param receiverPackage candidate package to receive the error
8592 * @return activity component within receiverPackage which handles
8593 * ACTION_APP_ERROR, or null if not found
8594 */
8595 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8596 String receiverPackage) throws RemoteException {
8597 if (receiverPackage == null || receiverPackage.length() == 0) {
8598 return null;
8599 }
8600
8601 // break the loop if it's the error report receiver package that crashed
8602 if (receiverPackage.equals(errorPackage)) {
8603 return null;
8604 }
8605
8606 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8607 intent.setPackage(receiverPackage);
8608 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8609 if (info == null || info.activityInfo == null) {
8610 return null;
8611 }
8612 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008613 }
8614
Dan Egnorb7f03672009-12-09 16:22:32 -08008615 private void makeAppNotRespondingLocked(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008616 String activity, String shortMsg, String longMsg) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008617 app.notResponding = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008618 app.notRespondingReport = generateProcessError(app,
Dan Egnor60d87622009-12-16 16:32:58 -08008619 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING,
8620 activity, shortMsg, longMsg, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008621 startAppProblemLocked(app);
8622 app.stopFreezingAllLocked();
8623 }
8624
8625 /**
8626 * Generate a process error record, suitable for attachment to a ProcessRecord.
8627 *
8628 * @param app The ProcessRecord in which the error occurred.
8629 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8630 * ActivityManager.AppErrorStateInfo
Dan Egnor60d87622009-12-16 16:32:58 -08008631 * @param activity The activity associated with the crash, if known.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008632 * @param shortMsg Short message describing the crash.
8633 * @param longMsg Long message describing the crash.
Dan Egnorb7f03672009-12-09 16:22:32 -08008634 * @param stackTrace Full crash stack trace, may be null.
8635 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008636 * @return Returns a fully-formed AppErrorStateInfo record.
8637 */
8638 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008639 int condition, String activity, String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008640 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
Dan Egnorb7f03672009-12-09 16:22:32 -08008641
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008642 report.condition = condition;
8643 report.processName = app.processName;
8644 report.pid = app.pid;
8645 report.uid = app.info.uid;
Dan Egnor60d87622009-12-16 16:32:58 -08008646 report.tag = activity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008647 report.shortMsg = shortMsg;
8648 report.longMsg = longMsg;
Dan Egnorb7f03672009-12-09 16:22:32 -08008649 report.stackTrace = stackTrace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008650
8651 return report;
8652 }
8653
Dan Egnor42471dd2010-01-07 17:25:22 -08008654 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008655 synchronized (this) {
8656 app.crashing = false;
8657 app.crashingReport = null;
8658 app.notResponding = false;
8659 app.notRespondingReport = null;
8660 if (app.anrDialog == fromDialog) {
8661 app.anrDialog = null;
8662 }
8663 if (app.waitDialog == fromDialog) {
8664 app.waitDialog = null;
8665 }
8666 if (app.pid > 0 && app.pid != MY_PID) {
Dan Egnor42471dd2010-01-07 17:25:22 -08008667 handleAppCrashLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008668 Log.i(ActivityManagerService.TAG, "Killing process "
8669 + app.processName
8670 + " (pid=" + app.pid + ") at user's request");
8671 Process.killProcess(app.pid);
8672 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008673 }
8674 }
Dan Egnor42471dd2010-01-07 17:25:22 -08008675
Dan Egnorb7f03672009-12-09 16:22:32 -08008676 private boolean handleAppCrashLocked(ProcessRecord app) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008677 long now = SystemClock.uptimeMillis();
8678
8679 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8680 app.info.uid);
8681 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8682 // This process loses!
8683 Log.w(TAG, "Process " + app.info.processName
8684 + " has crashed too many times: killing!");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008685 EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008686 app.info.processName, app.info.uid);
8687 killServicesLocked(app, false);
8688 for (int i=mHistory.size()-1; i>=0; i--) {
8689 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8690 if (r.app == app) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08008691 Log.w(TAG, " Force finishing activity "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008692 + r.intent.getComponent().flattenToShortString());
8693 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8694 }
8695 }
8696 if (!app.persistent) {
8697 // We don't want to start this process again until the user
8698 // explicitly does so... but for persistent process, we really
8699 // need to keep it running. If a persistent process is actually
8700 // repeatedly crashing, then badness for everyone.
Doug Zongker2bec3d42009-12-04 12:52:44 -08008701 EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008702 app.info.processName);
8703 mBadProcesses.put(app.info.processName, app.info.uid, now);
8704 app.bad = true;
8705 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8706 app.removed = true;
8707 removeProcessLocked(app, false);
8708 return false;
8709 }
8710 }
8711
8712 // Bump up the crash count of any services currently running in the proc.
8713 if (app.services.size() != 0) {
8714 // Any services running in the application need to be placed
8715 // back in the pending list.
8716 Iterator it = app.services.iterator();
8717 while (it.hasNext()) {
8718 ServiceRecord sr = (ServiceRecord)it.next();
8719 sr.crashCount++;
8720 }
8721 }
8722
8723 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8724 return true;
8725 }
8726
8727 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008728 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008729 skipCurrentReceiverLocked(app);
8730 }
8731
8732 void skipCurrentReceiverLocked(ProcessRecord app) {
8733 boolean reschedule = false;
8734 BroadcastRecord r = app.curReceiver;
8735 if (r != null) {
8736 // The current broadcast is waiting for this app's receiver
8737 // to be finished. Looks like that's not going to happen, so
8738 // let the broadcast continue.
8739 logBroadcastReceiverDiscard(r);
8740 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8741 r.resultExtras, r.resultAbort, true);
8742 reschedule = true;
8743 }
8744 r = mPendingBroadcast;
8745 if (r != null && r.curApp == app) {
8746 if (DEBUG_BROADCAST) Log.v(TAG,
8747 "skip & discard pending app " + r);
8748 logBroadcastReceiverDiscard(r);
8749 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8750 r.resultExtras, r.resultAbort, true);
8751 reschedule = true;
8752 }
8753 if (reschedule) {
8754 scheduleBroadcastsLocked();
8755 }
8756 }
8757
Dan Egnor60d87622009-12-16 16:32:58 -08008758 /**
8759 * Used by {@link com.android.internal.os.RuntimeInit} to report when an application crashes.
8760 * The application process will exit immediately after this call returns.
8761 * @param app object of the crashing app, null for the system server
8762 * @param crashInfo describing the exception
8763 */
8764 public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) {
8765 ProcessRecord r = findAppProcess(app);
8766
8767 EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
8768 app == null ? "system" : (r == null ? "unknown" : r.processName),
Dan Egnor2780e732010-01-22 14:47:35 -08008769 r == null ? -1 : r.info.flags,
Dan Egnor60d87622009-12-16 16:32:58 -08008770 crashInfo.exceptionClassName,
8771 crashInfo.exceptionMessage,
8772 crashInfo.throwFileName,
8773 crashInfo.throwLineNumber);
8774
Dan Egnor42471dd2010-01-07 17:25:22 -08008775 addErrorToDropBox("crash", r, null, null, null, null, null, crashInfo);
Dan Egnor60d87622009-12-16 16:32:58 -08008776
8777 crashApplication(r, crashInfo);
8778 }
8779
8780 /**
8781 * Used by {@link Log} via {@link com.android.internal.os.RuntimeInit} to report serious errors.
8782 * @param app object of the crashing app, null for the system server
8783 * @param tag reported by the caller
8784 * @param crashInfo describing the context of the error
8785 * @return true if the process should exit immediately (WTF is fatal)
8786 */
8787 public boolean handleApplicationWtf(IBinder app, String tag,
Dan Egnorb7f03672009-12-09 16:22:32 -08008788 ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnor60d87622009-12-16 16:32:58 -08008789 ProcessRecord r = findAppProcess(app);
8790
8791 EventLog.writeEvent(EventLogTags.AM_WTF, Binder.getCallingPid(),
8792 app == null ? "system" : (r == null ? "unknown" : r.processName),
Dan Egnor2780e732010-01-22 14:47:35 -08008793 r == null ? -1 : r.info.flags,
Dan Egnor60d87622009-12-16 16:32:58 -08008794 tag, crashInfo.exceptionMessage);
8795
Dan Egnor42471dd2010-01-07 17:25:22 -08008796 addErrorToDropBox("wtf", r, null, null, tag, null, null, crashInfo);
Dan Egnor60d87622009-12-16 16:32:58 -08008797
Doug Zongker43866e02010-01-07 12:09:54 -08008798 if (Settings.Secure.getInt(mContext.getContentResolver(),
8799 Settings.Secure.WTF_IS_FATAL, 0) != 0) {
Dan Egnor60d87622009-12-16 16:32:58 -08008800 crashApplication(r, crashInfo);
8801 return true;
8802 } else {
8803 return false;
8804 }
8805 }
8806
8807 /**
8808 * @param app object of some object (as stored in {@link com.android.internal.os.RuntimeInit})
8809 * @return the corresponding {@link ProcessRecord} object, or null if none could be found
8810 */
8811 private ProcessRecord findAppProcess(IBinder app) {
8812 if (app == null) {
8813 return null;
8814 }
8815
8816 synchronized (this) {
8817 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8818 final int NA = apps.size();
8819 for (int ia=0; ia<NA; ia++) {
8820 ProcessRecord p = apps.valueAt(ia);
8821 if (p.thread != null && p.thread.asBinder() == app) {
8822 return p;
8823 }
8824 }
8825 }
8826
8827 Log.w(TAG, "Can't find mystery application: " + app);
8828 return null;
8829 }
8830 }
8831
8832 /**
Dan Egnor42471dd2010-01-07 17:25:22 -08008833 * Write a description of an error (crash, WTF, ANR) to the drop box.
Dan Egnor60d87622009-12-16 16:32:58 -08008834 * @param eventType to include in the drop box tag ("crash", "wtf", etc.)
Dan Egnor42471dd2010-01-07 17:25:22 -08008835 * @param process which caused the error, null means the system server
8836 * @param activity which triggered the error, null if unknown
8837 * @param parent activity related to the error, null if unknown
8838 * @param subject line related to the error, null if absent
8839 * @param report in long form describing the error, null if absent
8840 * @param logFile to include in the report, null if none
8841 * @param crashInfo giving an application stack trace, null if absent
Dan Egnor60d87622009-12-16 16:32:58 -08008842 */
Dan Egnor42471dd2010-01-07 17:25:22 -08008843 private void addErrorToDropBox(String eventType,
8844 ProcessRecord process, HistoryRecord activity, HistoryRecord parent,
8845 String subject, String report, File logFile,
Dan Egnor60d87622009-12-16 16:32:58 -08008846 ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnor42471dd2010-01-07 17:25:22 -08008847 String dropboxTag;
8848 if (process == null || process.pid == MY_PID) {
Dan Egnor60d87622009-12-16 16:32:58 -08008849 dropboxTag = "system_server_" + eventType;
Dan Egnor42471dd2010-01-07 17:25:22 -08008850 } else if ((process.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
Dan Egnor60d87622009-12-16 16:32:58 -08008851 dropboxTag = "system_app_" + eventType;
8852 } else {
8853 dropboxTag = "data_app_" + eventType;
8854 }
8855
8856 DropBoxManager dbox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
8857 if (dbox != null && dbox.isTagEnabled(dropboxTag)) {
8858 StringBuilder sb = new StringBuilder(1024);
Dan Egnor42471dd2010-01-07 17:25:22 -08008859 if (process == null || process.pid == MY_PID) {
Dan Egnor60d87622009-12-16 16:32:58 -08008860 sb.append("Process: system_server\n");
8861 } else {
Dan Egnor42471dd2010-01-07 17:25:22 -08008862 sb.append("Process: ").append(process.processName).append("\n");
Dan Egnor66c40e72010-01-26 16:23:11 -08008863 }
8864 if (process != null) {
8865 int flags = process.info.flags;
8866 IPackageManager pm = ActivityThread.getPackageManager();
8867 sb.append("Flags: 0x").append(Integer.toString(flags, 16)).append("\n");
8868 for (String pkg : process.pkgList) {
8869 sb.append("Package: ").append(pkg);
8870 try {
8871 PackageInfo pi = pm.getPackageInfo(pkg, 0);
8872 if (pi != null) {
8873 sb.append(" v").append(pi.versionCode);
8874 if (pi.versionName != null) {
8875 sb.append(" (").append(pi.versionName).append(")");
8876 }
8877 }
8878 } catch (RemoteException e) {
8879 Log.e(TAG, "Error getting package info: " + pkg, e);
8880 }
8881 sb.append("\n");
8882 }
Dan Egnor42471dd2010-01-07 17:25:22 -08008883 }
8884 if (activity != null) {
8885 sb.append("Activity: ").append(activity.shortComponentName).append("\n");
8886 }
8887 if (parent != null && parent.app != null && parent.app.pid != process.pid) {
8888 sb.append("Parent-Process: ").append(parent.app.processName).append("\n");
8889 }
8890 if (parent != null && parent != activity) {
8891 sb.append("Parent-Activity: ").append(parent.shortComponentName).append("\n");
8892 }
8893 if (subject != null) {
8894 sb.append("Subject: ").append(subject).append("\n");
8895 }
8896 sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
8897 sb.append("\n");
8898 if (report != null) {
8899 sb.append(report);
8900 }
8901 if (logFile != null) {
8902 try {
8903 sb.append(FileUtils.readTextFile(logFile, 128 * 1024, "\n\n[[TRUNCATED]]"));
8904 } catch (IOException e) {
8905 Log.e(TAG, "Error reading " + logFile, e);
Dan Egnor60d87622009-12-16 16:32:58 -08008906 }
8907 }
Dan Egnor60d87622009-12-16 16:32:58 -08008908 if (crashInfo != null && crashInfo.stackTrace != null) {
Dan Egnor42471dd2010-01-07 17:25:22 -08008909 sb.append(crashInfo.stackTrace);
Dan Egnor60d87622009-12-16 16:32:58 -08008910 }
8911 dbox.addText(dropboxTag, sb.toString());
8912 }
8913 }
8914
8915 /**
8916 * Bring up the "unexpected error" dialog box for a crashing app.
8917 * Deal with edge cases (intercepts from instrumented applications,
8918 * ActivityController, error intent receivers, that sort of thing).
8919 * @param r the application crashing
8920 * @param crashInfo describing the failure
8921 */
8922 private void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnorb7f03672009-12-09 16:22:32 -08008923 long timeMillis = System.currentTimeMillis();
8924 String shortMsg = crashInfo.exceptionClassName;
8925 String longMsg = crashInfo.exceptionMessage;
8926 String stackTrace = crashInfo.stackTrace;
8927 if (shortMsg != null && longMsg != null) {
8928 longMsg = shortMsg + ": " + longMsg;
8929 } else if (shortMsg != null) {
8930 longMsg = shortMsg;
8931 }
8932
Dan Egnor60d87622009-12-16 16:32:58 -08008933 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008934 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008935 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008936 try {
8937 String name = r != null ? r.processName : null;
8938 int pid = r != null ? r.pid : Binder.getCallingPid();
Dan Egnor60d87622009-12-16 16:32:58 -08008939 if (!mController.appCrashed(name, pid,
Dan Egnorb7f03672009-12-09 16:22:32 -08008940 shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008941 Log.w(TAG, "Force-killing crashed app " + name
8942 + " at watcher's request");
8943 Process.killProcess(pid);
Dan Egnorb7f03672009-12-09 16:22:32 -08008944 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008945 }
8946 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008947 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008948 }
8949 }
8950
8951 final long origId = Binder.clearCallingIdentity();
8952
8953 // If this process is running instrumentation, finish it.
8954 if (r != null && r.instrumentationClass != null) {
8955 Log.w(TAG, "Error in app " + r.processName
8956 + " running instrumentation " + r.instrumentationClass + ":");
8957 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8958 if (longMsg != null) Log.w(TAG, " " + longMsg);
8959 Bundle info = new Bundle();
8960 info.putString("shortMsg", shortMsg);
8961 info.putString("longMsg", longMsg);
8962 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8963 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08008964 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008965 }
8966
Dan Egnor60d87622009-12-16 16:32:58 -08008967 // If we can't identify the process or it's already exceeded its crash quota,
8968 // quit right away without showing a crash dialog.
8969 if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008970 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08008971 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008972 }
8973
8974 Message msg = Message.obtain();
8975 msg.what = SHOW_ERROR_MSG;
8976 HashMap data = new HashMap();
8977 data.put("result", result);
8978 data.put("app", r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008979 msg.obj = data;
8980 mHandler.sendMessage(msg);
8981
8982 Binder.restoreCallingIdentity(origId);
8983 }
8984
8985 int res = result.get();
8986
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008987 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008988 synchronized (this) {
8989 if (r != null) {
8990 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8991 SystemClock.uptimeMillis());
8992 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008993 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
Dan Egnorb7f03672009-12-09 16:22:32 -08008994 appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008995 }
8996 }
8997
8998 if (appErrorIntent != null) {
8999 try {
9000 mContext.startActivity(appErrorIntent);
9001 } catch (ActivityNotFoundException e) {
9002 Log.w(TAG, "bug report receiver dissappeared", e);
9003 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009004 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009005 }
Dan Egnorb7f03672009-12-09 16:22:32 -08009006
9007 Intent createAppErrorIntentLocked(ProcessRecord r,
9008 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
9009 ApplicationErrorReport report = createAppErrorReportLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009010 if (report == null) {
9011 return null;
9012 }
9013 Intent result = new Intent(Intent.ACTION_APP_ERROR);
9014 result.setComponent(r.errorReportReceiver);
9015 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
9016 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
9017 return result;
9018 }
9019
Dan Egnorb7f03672009-12-09 16:22:32 -08009020 private ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r,
9021 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009022 if (r.errorReportReceiver == null) {
9023 return null;
9024 }
9025
9026 if (!r.crashing && !r.notResponding) {
9027 return null;
9028 }
9029
Dan Egnorb7f03672009-12-09 16:22:32 -08009030 ApplicationErrorReport report = new ApplicationErrorReport();
9031 report.packageName = r.info.packageName;
9032 report.installerPackageName = r.errorReportReceiver.getPackageName();
9033 report.processName = r.processName;
9034 report.time = timeMillis;
Jacek Surazskie0ee6ef2010-01-07 16:23:03 +01009035 report.systemApp = (r.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009036
Dan Egnorb7f03672009-12-09 16:22:32 -08009037 if (r.crashing) {
9038 report.type = ApplicationErrorReport.TYPE_CRASH;
9039 report.crashInfo = crashInfo;
9040 } else if (r.notResponding) {
9041 report.type = ApplicationErrorReport.TYPE_ANR;
9042 report.anrInfo = new ApplicationErrorReport.AnrInfo();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009043
Dan Egnorb7f03672009-12-09 16:22:32 -08009044 report.anrInfo.activity = r.notRespondingReport.tag;
9045 report.anrInfo.cause = r.notRespondingReport.shortMsg;
9046 report.anrInfo.info = r.notRespondingReport.longMsg;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009047 }
9048
Dan Egnorb7f03672009-12-09 16:22:32 -08009049 return report;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009050 }
9051
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009052 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
9053 // assume our apps are happy - lazy create the list
9054 List<ActivityManager.ProcessErrorStateInfo> errList = null;
9055
9056 synchronized (this) {
9057
9058 // iterate across all processes
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009059 for (int i=mLruProcesses.size()-1; i>=0; i--) {
9060 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009061 if ((app.thread != null) && (app.crashing || app.notResponding)) {
9062 // This one's in trouble, so we'll generate a report for it
9063 // crashes are higher priority (in case there's a crash *and* an anr)
9064 ActivityManager.ProcessErrorStateInfo report = null;
9065 if (app.crashing) {
9066 report = app.crashingReport;
9067 } else if (app.notResponding) {
9068 report = app.notRespondingReport;
9069 }
9070
9071 if (report != null) {
9072 if (errList == null) {
9073 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
9074 }
9075 errList.add(report);
9076 } else {
9077 Log.w(TAG, "Missing app error report, app = " + app.processName +
9078 " crashing = " + app.crashing +
9079 " notResponding = " + app.notResponding);
9080 }
9081 }
9082 }
9083 }
9084
9085 return errList;
9086 }
9087
9088 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
9089 // Lazy instantiation of list
9090 List<ActivityManager.RunningAppProcessInfo> runList = null;
9091 synchronized (this) {
9092 // Iterate across all processes
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009093 for (int i=mLruProcesses.size()-1; i>=0; i--) {
9094 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009095 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
9096 // Generate process state info for running application
9097 ActivityManager.RunningAppProcessInfo currApp =
9098 new ActivityManager.RunningAppProcessInfo(app.processName,
9099 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07009100 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009101 int adj = app.curAdj;
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009102 if (adj >= EMPTY_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009103 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
9104 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
9105 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08009106 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
9107 } else if (adj >= HOME_APP_ADJ) {
9108 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
9109 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009110 } else if (adj >= SECONDARY_SERVER_ADJ) {
9111 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
9112 } else if (adj >= VISIBLE_APP_ADJ) {
9113 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
9114 } else {
9115 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
9116 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009117 currApp.importanceReasonCode = app.adjTypeCode;
9118 if (app.adjSource instanceof ProcessRecord) {
9119 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
9120 } else if (app.adjSource instanceof HistoryRecord) {
9121 HistoryRecord r = (HistoryRecord)app.adjSource;
9122 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
9123 }
9124 if (app.adjTarget instanceof ComponentName) {
9125 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
9126 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009127 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
9128 // + " lru=" + currApp.lru);
9129 if (runList == null) {
9130 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
9131 }
9132 runList.add(currApp);
9133 }
9134 }
9135 }
9136 return runList;
9137 }
9138
9139 @Override
9140 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009141 if (checkCallingPermission(android.Manifest.permission.DUMP)
9142 != PackageManager.PERMISSION_GRANTED) {
9143 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9144 + Binder.getCallingPid()
9145 + ", uid=" + Binder.getCallingUid()
9146 + " without permission "
9147 + android.Manifest.permission.DUMP);
9148 return;
9149 }
9150
9151 boolean dumpAll = false;
9152
9153 int opti = 0;
9154 while (opti < args.length) {
9155 String opt = args[opti];
9156 if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
9157 break;
9158 }
9159 opti++;
9160 if ("-a".equals(opt)) {
9161 dumpAll = true;
9162 } else if ("-h".equals(opt)) {
9163 pw.println("Activity manager dump options:");
9164 pw.println(" [-a] [h- [cmd] ...");
9165 pw.println(" cmd may be one of:");
9166 pw.println(" activities: activity stack state");
9167 pw.println(" broadcasts: broadcast state");
9168 pw.println(" intents: pending intent state");
9169 pw.println(" processes: process state");
9170 pw.println(" providers: content provider state");
9171 pw.println(" services: service state");
9172 pw.println(" service [name]: service client-side state");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009173 return;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009174 } else {
9175 pw.println("Unknown argument: " + opt + "; use -h for help");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009176 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009177 }
9178
9179 // Is the caller requesting to dump a particular piece of data?
9180 if (opti < args.length) {
9181 String cmd = args[opti];
9182 opti++;
9183 if ("activities".equals(cmd) || "a".equals(cmd)) {
9184 synchronized (this) {
9185 dumpActivitiesLocked(fd, pw, args, opti, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009186 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009187 return;
9188 } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
9189 synchronized (this) {
9190 dumpBroadcastsLocked(fd, pw, args, opti, true);
9191 }
9192 return;
9193 } else if ("intents".equals(cmd) || "i".equals(cmd)) {
9194 synchronized (this) {
9195 dumpPendingIntentsLocked(fd, pw, args, opti, true);
9196 }
9197 return;
9198 } else if ("processes".equals(cmd) || "p".equals(cmd)) {
9199 synchronized (this) {
9200 dumpProcessesLocked(fd, pw, args, opti, true);
9201 }
9202 return;
9203 } else if ("providers".equals(cmd) || "prov".equals(cmd)) {
9204 synchronized (this) {
9205 dumpProvidersLocked(fd, pw, args, opti, true);
9206 }
9207 return;
9208 } else if ("service".equals(cmd)) {
9209 dumpService(fd, pw, args, opti, true);
9210 return;
9211 } else if ("services".equals(cmd) || "s".equals(cmd)) {
9212 synchronized (this) {
9213 dumpServicesLocked(fd, pw, args, opti, true);
9214 }
9215 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009216 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009217 }
9218
9219 // No piece of data specified, dump everything.
9220 synchronized (this) {
9221 boolean needSep;
9222 if (dumpAll) {
9223 pw.println("Providers in Current Activity Manager State:");
9224 }
9225 needSep = dumpProvidersLocked(fd, pw, args, opti, dumpAll);
9226 if (needSep) {
9227 pw.println(" ");
9228 }
9229 if (dumpAll) {
9230 pw.println("-------------------------------------------------------------------------------");
9231 pw.println("Broadcasts in Current Activity Manager State:");
9232 }
9233 needSep = dumpBroadcastsLocked(fd, pw, args, opti, dumpAll);
9234 if (needSep) {
9235 pw.println(" ");
9236 }
9237 if (dumpAll) {
9238 pw.println("-------------------------------------------------------------------------------");
9239 pw.println("Services in Current Activity Manager State:");
9240 }
9241 needSep = dumpServicesLocked(fd, pw, args, opti, dumpAll);
9242 if (needSep) {
9243 pw.println(" ");
9244 }
9245 if (dumpAll) {
9246 pw.println("-------------------------------------------------------------------------------");
9247 pw.println("PendingIntents in Current Activity Manager State:");
9248 }
9249 needSep = dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll);
9250 if (needSep) {
9251 pw.println(" ");
9252 }
9253 if (dumpAll) {
9254 pw.println("-------------------------------------------------------------------------------");
9255 pw.println("Activities in Current Activity Manager State:");
9256 }
9257 needSep = dumpActivitiesLocked(fd, pw, args, opti, dumpAll, !dumpAll);
9258 if (needSep) {
9259 pw.println(" ");
9260 }
9261 if (dumpAll) {
9262 pw.println("-------------------------------------------------------------------------------");
9263 pw.println("Processes in Current Activity Manager State:");
9264 }
9265 dumpProcessesLocked(fd, pw, args, opti, dumpAll);
9266 }
9267 }
9268
9269 boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9270 int opti, boolean dumpAll, boolean needHeader) {
9271 if (needHeader) {
9272 pw.println(" Activity stack:");
9273 }
9274 dumpHistoryList(pw, mHistory, " ", "Hist", true);
9275 pw.println(" ");
9276 pw.println(" Running activities (most recent first):");
9277 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
9278 if (mWaitingVisibleActivities.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009279 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009280 pw.println(" Activities waiting for another to become visible:");
9281 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
9282 }
9283 if (mStoppingActivities.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009284 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009285 pw.println(" Activities waiting to stop:");
9286 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
9287 }
9288 if (mFinishingActivities.size() > 0) {
9289 pw.println(" ");
9290 pw.println(" Activities waiting to finish:");
9291 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
9292 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009293
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009294 pw.println(" ");
9295 pw.println(" mPausingActivity: " + mPausingActivity);
9296 pw.println(" mResumedActivity: " + mResumedActivity);
9297 pw.println(" mFocusedActivity: " + mFocusedActivity);
9298 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009299
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009300 if (dumpAll && mRecentTasks.size() > 0) {
9301 pw.println(" ");
9302 pw.println("Recent tasks in Current Activity Manager State:");
9303
9304 final int N = mRecentTasks.size();
9305 for (int i=0; i<N; i++) {
9306 TaskRecord tr = mRecentTasks.get(i);
9307 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
9308 pw.println(tr);
9309 mRecentTasks.get(i).dump(pw, " ");
9310 }
9311 }
9312
9313 pw.println(" ");
9314 pw.println(" mCurTask: " + mCurTask);
9315
9316 return true;
9317 }
9318
9319 boolean dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9320 int opti, boolean dumpAll) {
9321 boolean needSep = false;
9322 int numPers = 0;
9323
9324 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009325 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
9326 final int NA = procs.size();
9327 for (int ia=0; ia<NA; ia++) {
9328 if (!needSep) {
9329 pw.println(" All known processes:");
9330 needSep = true;
9331 }
9332 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009333 pw.print(r.persistent ? " *PERS*" : " *APP*");
9334 pw.print(" UID "); pw.print(procs.keyAt(ia));
9335 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009336 r.dump(pw, " ");
9337 if (r.persistent) {
9338 numPers++;
9339 }
9340 }
9341 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009342 }
9343
9344 if (mLruProcesses.size() > 0) {
9345 if (needSep) pw.println(" ");
9346 needSep = true;
9347 pw.println(" Running processes (most recent first):");
9348 dumpProcessList(pw, this, mLruProcesses, " ",
9349 "App ", "PERS", true);
9350 needSep = true;
9351 }
9352
9353 synchronized (mPidsSelfLocked) {
9354 if (mPidsSelfLocked.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009355 if (needSep) pw.println(" ");
9356 needSep = true;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009357 pw.println(" PID mappings:");
9358 for (int i=0; i<mPidsSelfLocked.size(); i++) {
9359 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9360 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009361 }
9362 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009363 }
9364
9365 if (mForegroundProcesses.size() > 0) {
9366 if (needSep) pw.println(" ");
9367 needSep = true;
9368 pw.println(" Foreground Processes:");
9369 for (int i=0; i<mForegroundProcesses.size(); i++) {
9370 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9371 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009372 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009373 }
9374
9375 if (mPersistentStartingProcesses.size() > 0) {
9376 if (needSep) pw.println(" ");
9377 needSep = true;
9378 pw.println(" Persisent processes that are starting:");
9379 dumpProcessList(pw, this, mPersistentStartingProcesses, " ",
9380 "Starting Norm", "Restarting PERS", false);
9381 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009382
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009383 if (mStartingProcesses.size() > 0) {
9384 if (needSep) pw.println(" ");
9385 needSep = true;
9386 pw.println(" Processes that are starting:");
9387 dumpProcessList(pw, this, mStartingProcesses, " ",
9388 "Starting Norm", "Starting PERS", false);
9389 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009390
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009391 if (mRemovedProcesses.size() > 0) {
9392 if (needSep) pw.println(" ");
9393 needSep = true;
9394 pw.println(" Processes that are being removed:");
9395 dumpProcessList(pw, this, mRemovedProcesses, " ",
9396 "Removed Norm", "Removed PERS", false);
9397 }
9398
9399 if (mProcessesOnHold.size() > 0) {
9400 if (needSep) pw.println(" ");
9401 needSep = true;
9402 pw.println(" Processes that are on old until the system is ready:");
9403 dumpProcessList(pw, this, mProcessesOnHold, " ",
9404 "OnHold Norm", "OnHold PERS", false);
9405 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009406
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009407 if (mProcessesToGc.size() > 0) {
9408 if (needSep) pw.println(" ");
9409 needSep = true;
9410 pw.println(" Processes that are waiting to GC:");
9411 long now = SystemClock.uptimeMillis();
9412 for (int i=0; i<mProcessesToGc.size(); i++) {
9413 ProcessRecord proc = mProcessesToGc.get(i);
9414 pw.print(" Process "); pw.println(proc);
9415 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9416 pw.print(", last gced=");
9417 pw.print(now-proc.lastRequestedGc);
9418 pw.print(" ms ago, last lowMem=");
9419 pw.print(now-proc.lastLowMemory);
9420 pw.println(" ms ago");
9421
9422 }
9423 }
9424
9425 if (mProcessCrashTimes.getMap().size() > 0) {
9426 if (needSep) pw.println(" ");
9427 needSep = true;
9428 pw.println(" Time since processes crashed:");
9429 long now = SystemClock.uptimeMillis();
9430 for (Map.Entry<String, SparseArray<Long>> procs
9431 : mProcessCrashTimes.getMap().entrySet()) {
9432 SparseArray<Long> uids = procs.getValue();
9433 final int N = uids.size();
9434 for (int i=0; i<N; i++) {
9435 pw.print(" Process "); pw.print(procs.getKey());
9436 pw.print(" uid "); pw.print(uids.keyAt(i));
9437 pw.print(": last crashed ");
9438 pw.print((now-uids.valueAt(i)));
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009439 pw.println(" ms ago");
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009440 }
9441 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009442 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009443
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009444 if (mBadProcesses.getMap().size() > 0) {
9445 if (needSep) pw.println(" ");
9446 needSep = true;
9447 pw.println(" Bad processes:");
9448 for (Map.Entry<String, SparseArray<Long>> procs
9449 : mBadProcesses.getMap().entrySet()) {
9450 SparseArray<Long> uids = procs.getValue();
9451 final int N = uids.size();
9452 for (int i=0; i<N; i++) {
9453 pw.print(" Bad process "); pw.print(procs.getKey());
9454 pw.print(" uid "); pw.print(uids.keyAt(i));
9455 pw.print(": crashed at time ");
9456 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009457 }
9458 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009459 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009460
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009461 pw.println(" ");
9462 pw.println(" mHomeProcess: " + mHomeProcess);
9463 pw.println(" mConfiguration: " + mConfiguration);
9464 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
9465 if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
9466 || mOrigWaitForDebugger) {
9467 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9468 + " mDebugTransient=" + mDebugTransient
9469 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9470 }
9471 if (mAlwaysFinishActivities || mController != null) {
9472 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
9473 + " mController=" + mController);
9474 }
9475 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009476 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009477 pw.println(" mStartRunning=" + mStartRunning
9478 + " mSystemReady=" + mSystemReady
9479 + " mBooting=" + mBooting
9480 + " mBooted=" + mBooted
9481 + " mFactoryTest=" + mFactoryTest);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009482 pw.println(" mGoingToSleep=" + mGoingToSleep);
9483 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009484 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009485
9486 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009487 }
9488
9489 /**
9490 * There are three ways to call this:
9491 * - no service specified: dump all the services
9492 * - a flattened component name that matched an existing service was specified as the
9493 * first arg: dump that one service
9494 * - the first arg isn't the flattened component name of an existing service:
9495 * dump all services whose component contains the first arg as a substring
9496 */
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009497 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args,
9498 int opti, boolean dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009499 String[] newArgs;
9500 String componentNameString;
9501 ServiceRecord r;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009502 if (opti <= args.length) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009503 componentNameString = null;
9504 newArgs = EMPTY_STRING_ARRAY;
9505 r = null;
9506 } else {
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009507 componentNameString = args[opti];
9508 opti++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009509 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9510 r = componentName != null ? mServices.get(componentName) : null;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009511 newArgs = new String[args.length - opti];
9512 if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009513 }
9514
9515 if (r != null) {
9516 dumpService(fd, pw, r, newArgs);
9517 } else {
9518 for (ServiceRecord r1 : mServices.values()) {
9519 if (componentNameString == null
9520 || r1.name.flattenToString().contains(componentNameString)) {
9521 dumpService(fd, pw, r1, newArgs);
9522 }
9523 }
9524 }
9525 }
9526
9527 /**
9528 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9529 * there is a thread associated with the service.
9530 */
9531 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9532 pw.println(" Service " + r.name.flattenToString());
9533 if (r.app != null && r.app.thread != null) {
9534 try {
9535 // flush anything that is already in the PrintWriter since the thread is going
9536 // to write to the file descriptor directly
9537 pw.flush();
9538 r.app.thread.dumpService(fd, r, args);
9539 pw.print("\n");
9540 } catch (RemoteException e) {
9541 pw.println("got a RemoteException while dumping the service");
9542 }
9543 }
9544 }
9545
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009546 boolean dumpBroadcastsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9547 int opti, boolean dumpAll) {
9548 boolean needSep = false;
9549
9550 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009551 if (mRegisteredReceivers.size() > 0) {
9552 pw.println(" ");
9553 pw.println(" Registered Receivers:");
9554 Iterator it = mRegisteredReceivers.values().iterator();
9555 while (it.hasNext()) {
9556 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009557 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009558 r.dump(pw, " ");
9559 }
9560 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009561
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009562 pw.println(" ");
9563 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009564 mReceiverResolver.dump(pw, " ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009565 needSep = true;
9566 }
9567
9568 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9569 || mPendingBroadcast != null) {
9570 if (mParallelBroadcasts.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009571 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009572 pw.println(" Active broadcasts:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009573 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009574 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9575 pw.println(" Broadcast #" + i + ":");
9576 mParallelBroadcasts.get(i).dump(pw, " ");
9577 }
9578 if (mOrderedBroadcasts.size() > 0) {
9579 pw.println(" ");
9580 pw.println(" Active serialized broadcasts:");
9581 }
9582 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9583 pw.println(" Serialized Broadcast #" + i + ":");
9584 mOrderedBroadcasts.get(i).dump(pw, " ");
9585 }
9586 pw.println(" ");
9587 pw.println(" Pending broadcast:");
9588 if (mPendingBroadcast != null) {
9589 mPendingBroadcast.dump(pw, " ");
9590 } else {
9591 pw.println(" (null)");
9592 }
9593 needSep = true;
9594 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009595
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009596 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009597 pw.println(" ");
Dianne Hackborn12527f92009-11-11 17:39:50 -08009598 pw.println(" Historical broadcasts:");
9599 for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
9600 BroadcastRecord r = mBroadcastHistory[i];
9601 if (r == null) {
9602 break;
9603 }
9604 pw.println(" Historical Broadcast #" + i + ":");
9605 r.dump(pw, " ");
9606 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009607 needSep = true;
9608 }
9609
9610 if (mStickyBroadcasts != null) {
Dianne Hackborn12527f92009-11-11 17:39:50 -08009611 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009612 pw.println(" Sticky broadcasts:");
9613 StringBuilder sb = new StringBuilder(128);
9614 for (Map.Entry<String, ArrayList<Intent>> ent
9615 : mStickyBroadcasts.entrySet()) {
9616 pw.print(" * Sticky action "); pw.print(ent.getKey());
9617 pw.println(":");
9618 ArrayList<Intent> intents = ent.getValue();
9619 final int N = intents.size();
9620 for (int i=0; i<N; i++) {
9621 sb.setLength(0);
9622 sb.append(" Intent: ");
9623 intents.get(i).toShortString(sb, true, false);
9624 pw.println(sb.toString());
9625 Bundle bundle = intents.get(i).getExtras();
9626 if (bundle != null) {
9627 pw.print(" ");
9628 pw.println(bundle.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009629 }
9630 }
9631 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009632 needSep = true;
9633 }
9634
9635 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009636 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009637 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009638 pw.println(" mHandler:");
9639 mHandler.dump(new PrintWriterPrinter(pw), " ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009640 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009641 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009642
9643 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009644 }
9645
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009646 boolean dumpServicesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9647 int opti, boolean dumpAll) {
9648 boolean needSep = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009649
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009650 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009651 if (mServices.size() > 0) {
9652 pw.println(" Active services:");
9653 Iterator<ServiceRecord> it = mServices.values().iterator();
9654 while (it.hasNext()) {
9655 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009656 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009657 r.dump(pw, " ");
9658 }
9659 needSep = true;
9660 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009661 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009662
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009663 if (mPendingServices.size() > 0) {
9664 if (needSep) pw.println(" ");
9665 pw.println(" Pending services:");
9666 for (int i=0; i<mPendingServices.size(); i++) {
9667 ServiceRecord r = mPendingServices.get(i);
9668 pw.print(" * Pending "); pw.println(r);
9669 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009670 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009671 needSep = true;
9672 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009673
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009674 if (mRestartingServices.size() > 0) {
9675 if (needSep) pw.println(" ");
9676 pw.println(" Restarting services:");
9677 for (int i=0; i<mRestartingServices.size(); i++) {
9678 ServiceRecord r = mRestartingServices.get(i);
9679 pw.print(" * Restarting "); pw.println(r);
9680 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009681 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009682 needSep = true;
9683 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009684
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009685 if (mStoppingServices.size() > 0) {
9686 if (needSep) pw.println(" ");
9687 pw.println(" Stopping services:");
9688 for (int i=0; i<mStoppingServices.size(); i++) {
9689 ServiceRecord r = mStoppingServices.get(i);
9690 pw.print(" * Stopping "); pw.println(r);
9691 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009692 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009693 needSep = true;
9694 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009695
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009696 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009697 if (mServiceConnections.size() > 0) {
9698 if (needSep) pw.println(" ");
9699 pw.println(" Connection bindings to services:");
9700 Iterator<ConnectionRecord> it
9701 = mServiceConnections.values().iterator();
9702 while (it.hasNext()) {
9703 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009704 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009705 r.dump(pw, " ");
9706 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009707 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009708 }
9709 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009710
9711 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009712 }
9713
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009714 boolean dumpProvidersLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9715 int opti, boolean dumpAll) {
9716 boolean needSep = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009717
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009718 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009719 if (mProvidersByClass.size() > 0) {
9720 if (needSep) pw.println(" ");
9721 pw.println(" Published content providers (by class):");
9722 Iterator it = mProvidersByClass.entrySet().iterator();
9723 while (it.hasNext()) {
9724 Map.Entry e = (Map.Entry)it.next();
9725 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009726 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009727 r.dump(pw, " ");
9728 }
9729 needSep = true;
9730 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009731
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009732 if (mProvidersByName.size() > 0) {
9733 pw.println(" ");
9734 pw.println(" Authority to provider mappings:");
9735 Iterator it = mProvidersByName.entrySet().iterator();
9736 while (it.hasNext()) {
9737 Map.Entry e = (Map.Entry)it.next();
9738 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9739 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9740 pw.println(r);
9741 }
9742 needSep = true;
9743 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009744 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009745
9746 if (mLaunchingProviders.size() > 0) {
9747 if (needSep) pw.println(" ");
9748 pw.println(" Launching content providers:");
9749 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
9750 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9751 pw.println(mLaunchingProviders.get(i));
9752 }
9753 needSep = true;
9754 }
9755
9756 if (mGrantedUriPermissions.size() > 0) {
9757 pw.println();
9758 pw.println("Granted Uri Permissions:");
9759 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9760 int uid = mGrantedUriPermissions.keyAt(i);
9761 HashMap<Uri, UriPermission> perms
9762 = mGrantedUriPermissions.valueAt(i);
9763 pw.print(" * UID "); pw.print(uid);
9764 pw.println(" holds:");
9765 for (UriPermission perm : perms.values()) {
9766 pw.print(" "); pw.println(perm);
9767 perm.dump(pw, " ");
9768 }
9769 }
9770 needSep = true;
9771 }
9772
9773 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009774 }
9775
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009776 boolean dumpPendingIntentsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9777 int opti, boolean dumpAll) {
9778 boolean needSep = false;
9779
9780 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009781 if (this.mIntentSenderRecords.size() > 0) {
9782 Iterator<WeakReference<PendingIntentRecord>> it
9783 = mIntentSenderRecords.values().iterator();
9784 while (it.hasNext()) {
9785 WeakReference<PendingIntentRecord> ref = it.next();
9786 PendingIntentRecord rec = ref != null ? ref.get(): null;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009787 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009788 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009789 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009790 rec.dump(pw, " ");
9791 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009792 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009793 }
9794 }
9795 }
9796 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009797
9798 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009799 }
9800
9801 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009802 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009803 TaskRecord lastTask = null;
9804 for (int i=list.size()-1; i>=0; i--) {
9805 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009806 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009807 if (lastTask != r.task) {
9808 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009809 pw.print(prefix);
9810 pw.print(full ? "* " : " ");
9811 pw.println(lastTask);
9812 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009813 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009814 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009815 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009816 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9817 pw.print(" #"); pw.print(i); pw.print(": ");
9818 pw.println(r);
9819 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009820 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009821 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009822 }
9823 }
9824
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009825 private static String buildOomTag(String prefix, String space, int val, int base) {
9826 if (val == base) {
9827 if (space == null) return prefix;
9828 return prefix + " ";
9829 }
9830 return prefix + "+" + Integer.toString(val-base);
9831 }
9832
9833 private static final int dumpProcessList(PrintWriter pw,
9834 ActivityManagerService service, List list,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009835 String prefix, String normalLabel, String persistentLabel,
9836 boolean inclOomAdj) {
9837 int numPers = 0;
9838 for (int i=list.size()-1; i>=0; i--) {
9839 ProcessRecord r = (ProcessRecord)list.get(i);
9840 if (false) {
9841 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9842 + " #" + i + ":");
9843 r.dump(pw, prefix + " ");
9844 } else if (inclOomAdj) {
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009845 String oomAdj;
9846 if (r.setAdj >= EMPTY_APP_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009847 oomAdj = buildOomTag("empty", null, r.setAdj, EMPTY_APP_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009848 } else if (r.setAdj >= HIDDEN_APP_MIN_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009849 oomAdj = buildOomTag("bak", " ", r.setAdj, HIDDEN_APP_MIN_ADJ);
9850 } else if (r.setAdj >= HOME_APP_ADJ) {
9851 oomAdj = buildOomTag("home ", null, r.setAdj, HOME_APP_ADJ);
9852 } else if (r.setAdj >= SECONDARY_SERVER_ADJ) {
9853 oomAdj = buildOomTag("svc", " ", r.setAdj, SECONDARY_SERVER_ADJ);
9854 } else if (r.setAdj >= BACKUP_APP_ADJ) {
9855 oomAdj = buildOomTag("bckup", null, r.setAdj, BACKUP_APP_ADJ);
9856 } else if (r.setAdj >= VISIBLE_APP_ADJ) {
9857 oomAdj = buildOomTag("vis ", null, r.setAdj, VISIBLE_APP_ADJ);
9858 } else if (r.setAdj >= FOREGROUND_APP_ADJ) {
9859 oomAdj = buildOomTag("fore ", null, r.setAdj, FOREGROUND_APP_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009860 } else if (r.setAdj >= CORE_SERVER_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009861 oomAdj = buildOomTag("core ", null, r.setAdj, CORE_SERVER_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009862 } else if (r.setAdj >= SYSTEM_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009863 oomAdj = buildOomTag("sys ", null, r.setAdj, SYSTEM_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009864 } else {
9865 oomAdj = Integer.toString(r.setAdj);
9866 }
9867 String schedGroup;
9868 switch (r.setSchedGroup) {
9869 case Process.THREAD_GROUP_BG_NONINTERACTIVE:
9870 schedGroup = "B";
9871 break;
9872 case Process.THREAD_GROUP_DEFAULT:
9873 schedGroup = "F";
9874 break;
9875 default:
9876 schedGroup = Integer.toString(r.setSchedGroup);
9877 break;
9878 }
9879 pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009880 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009881 i, oomAdj, schedGroup, r.toShortString(), r.adjType));
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009882 if (r.adjSource != null || r.adjTarget != null) {
9883 pw.println(prefix + " " + r.adjTarget
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009884 + "<=" + r.adjSource);
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009885 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009886 } else {
9887 pw.println(String.format("%s%s #%2d: %s",
9888 prefix, (r.persistent ? persistentLabel : normalLabel),
9889 i, r.toString()));
9890 }
9891 if (r.persistent) {
9892 numPers++;
9893 }
9894 }
9895 return numPers;
9896 }
9897
9898 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9899 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009900 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009901 long uptime = SystemClock.uptimeMillis();
9902 long realtime = SystemClock.elapsedRealtime();
9903
9904 if (isCheckinRequest) {
9905 // short checkin version
9906 pw.println(uptime + "," + realtime);
9907 pw.flush();
9908 } else {
9909 pw.println("Applications Memory Usage (kB):");
9910 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9911 }
9912 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9913 ProcessRecord r = (ProcessRecord)list.get(i);
9914 if (r.thread != null) {
9915 if (!isCheckinRequest) {
9916 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9917 pw.flush();
9918 }
9919 try {
9920 r.thread.asBinder().dump(fd, args);
9921 } catch (RemoteException e) {
9922 if (!isCheckinRequest) {
9923 pw.println("Got RemoteException!");
9924 pw.flush();
9925 }
9926 }
9927 }
9928 }
9929 }
9930
9931 /**
9932 * Searches array of arguments for the specified string
9933 * @param args array of argument strings
9934 * @param value value to search for
9935 * @return true if the value is contained in the array
9936 */
9937 private static boolean scanArgs(String[] args, String value) {
9938 if (args != null) {
9939 for (String arg : args) {
9940 if (value.equals(arg)) {
9941 return true;
9942 }
9943 }
9944 }
9945 return false;
9946 }
9947
Dianne Hackborn75b03852009-06-12 15:43:26 -07009948 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009949 int count = mHistory.size();
9950
9951 // convert the token to an entry in the history.
9952 HistoryRecord r = null;
9953 int index = -1;
9954 for (int i=count-1; i>=0; i--) {
9955 Object o = mHistory.get(i);
9956 if (o == token) {
9957 r = (HistoryRecord)o;
9958 index = i;
9959 break;
9960 }
9961 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009962
9963 return index;
9964 }
9965
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009966 private final void killServicesLocked(ProcessRecord app,
9967 boolean allowRestart) {
9968 // Report disconnected services.
9969 if (false) {
9970 // XXX we are letting the client link to the service for
9971 // death notifications.
9972 if (app.services.size() > 0) {
9973 Iterator it = app.services.iterator();
9974 while (it.hasNext()) {
9975 ServiceRecord r = (ServiceRecord)it.next();
9976 if (r.connections.size() > 0) {
9977 Iterator<ConnectionRecord> jt
9978 = r.connections.values().iterator();
9979 while (jt.hasNext()) {
9980 ConnectionRecord c = jt.next();
9981 if (c.binding.client != app) {
9982 try {
9983 //c.conn.connected(r.className, null);
9984 } catch (Exception e) {
9985 // todo: this should be asynchronous!
9986 Log.w(TAG, "Exception thrown disconnected servce "
9987 + r.shortName
9988 + " from app " + app.processName, e);
9989 }
9990 }
9991 }
9992 }
9993 }
9994 }
9995 }
9996
9997 // Clean up any connections this application has to other services.
9998 if (app.connections.size() > 0) {
9999 Iterator<ConnectionRecord> it = app.connections.iterator();
10000 while (it.hasNext()) {
10001 ConnectionRecord r = it.next();
10002 removeConnectionLocked(r, app, null);
10003 }
10004 }
10005 app.connections.clear();
10006
10007 if (app.services.size() != 0) {
10008 // Any services running in the application need to be placed
10009 // back in the pending list.
10010 Iterator it = app.services.iterator();
10011 while (it.hasNext()) {
10012 ServiceRecord sr = (ServiceRecord)it.next();
10013 synchronized (sr.stats.getBatteryStats()) {
10014 sr.stats.stopLaunchedLocked();
10015 }
10016 sr.app = null;
10017 sr.executeNesting = 0;
10018 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010019
10020 boolean hasClients = sr.bindings.size() > 0;
10021 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010022 Iterator<IntentBindRecord> bindings
10023 = sr.bindings.values().iterator();
10024 while (bindings.hasNext()) {
10025 IntentBindRecord b = bindings.next();
10026 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
10027 + ": shouldUnbind=" + b.hasBound);
10028 b.binder = null;
10029 b.requested = b.received = b.hasBound = false;
10030 }
10031 }
10032
10033 if (sr.crashCount >= 2) {
10034 Log.w(TAG, "Service crashed " + sr.crashCount
10035 + " times, stopping: " + sr);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010036 EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010037 sr.crashCount, sr.shortName, app.pid);
10038 bringDownServiceLocked(sr, true);
10039 } else if (!allowRestart) {
10040 bringDownServiceLocked(sr, true);
10041 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010042 boolean canceled = scheduleServiceRestartLocked(sr, true);
10043
10044 // Should the service remain running? Note that in the
10045 // extreme case of so many attempts to deliver a command
10046 // that it failed, that we also will stop it here.
10047 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
10048 if (sr.pendingStarts.size() == 0) {
10049 sr.startRequested = false;
10050 if (!hasClients) {
10051 // Whoops, no reason to restart!
10052 bringDownServiceLocked(sr, true);
10053 }
10054 }
10055 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010056 }
10057 }
10058
10059 if (!allowRestart) {
10060 app.services.clear();
10061 }
10062 }
10063
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010064 // Make sure we have no more records on the stopping list.
10065 int i = mStoppingServices.size();
10066 while (i > 0) {
10067 i--;
10068 ServiceRecord sr = mStoppingServices.get(i);
10069 if (sr.app == app) {
10070 mStoppingServices.remove(i);
10071 }
10072 }
10073
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010074 app.executingServices.clear();
10075 }
10076
10077 private final void removeDyingProviderLocked(ProcessRecord proc,
10078 ContentProviderRecord cpr) {
10079 synchronized (cpr) {
10080 cpr.launchingApp = null;
10081 cpr.notifyAll();
10082 }
10083
10084 mProvidersByClass.remove(cpr.info.name);
10085 String names[] = cpr.info.authority.split(";");
10086 for (int j = 0; j < names.length; j++) {
10087 mProvidersByName.remove(names[j]);
10088 }
10089
10090 Iterator<ProcessRecord> cit = cpr.clients.iterator();
10091 while (cit.hasNext()) {
10092 ProcessRecord capp = cit.next();
10093 if (!capp.persistent && capp.thread != null
10094 && capp.pid != 0
10095 && capp.pid != MY_PID) {
10096 Log.i(TAG, "Killing app " + capp.processName
10097 + " (pid " + capp.pid
10098 + ") because provider " + cpr.info.name
10099 + " is in dying process " + proc.processName);
10100 Process.killProcess(capp.pid);
10101 }
10102 }
10103
10104 mLaunchingProviders.remove(cpr);
10105 }
10106
10107 /**
10108 * Main code for cleaning up a process when it has gone away. This is
10109 * called both as a result of the process dying, or directly when stopping
10110 * a process when running in single process mode.
10111 */
10112 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
10113 boolean restarting, int index) {
10114 if (index >= 0) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080010115 mLruProcesses.remove(index);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010116 }
10117
Dianne Hackborn36124872009-10-08 16:22:03 -070010118 mProcessesToGc.remove(app);
10119
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010120 // Dismiss any open dialogs.
10121 if (app.crashDialog != null) {
10122 app.crashDialog.dismiss();
10123 app.crashDialog = null;
10124 }
10125 if (app.anrDialog != null) {
10126 app.anrDialog.dismiss();
10127 app.anrDialog = null;
10128 }
10129 if (app.waitDialog != null) {
10130 app.waitDialog.dismiss();
10131 app.waitDialog = null;
10132 }
10133
10134 app.crashing = false;
10135 app.notResponding = false;
10136
10137 app.resetPackageList();
10138 app.thread = null;
10139 app.forcingToForeground = null;
10140 app.foregroundServices = false;
10141
10142 killServicesLocked(app, true);
10143
10144 boolean restart = false;
10145
10146 int NL = mLaunchingProviders.size();
10147
10148 // Remove published content providers.
10149 if (!app.pubProviders.isEmpty()) {
10150 Iterator it = app.pubProviders.values().iterator();
10151 while (it.hasNext()) {
10152 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
10153 cpr.provider = null;
10154 cpr.app = null;
10155
10156 // See if someone is waiting for this provider... in which
10157 // case we don't remove it, but just let it restart.
10158 int i = 0;
10159 if (!app.bad) {
10160 for (; i<NL; i++) {
10161 if (mLaunchingProviders.get(i) == cpr) {
10162 restart = true;
10163 break;
10164 }
10165 }
10166 } else {
10167 i = NL;
10168 }
10169
10170 if (i >= NL) {
10171 removeDyingProviderLocked(app, cpr);
10172 NL = mLaunchingProviders.size();
10173 }
10174 }
10175 app.pubProviders.clear();
10176 }
10177
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010178 // Take care of any launching providers waiting for this process.
10179 if (checkAppInLaunchingProvidersLocked(app, false)) {
10180 restart = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010181 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010182
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010183 // Unregister from connected content providers.
10184 if (!app.conProviders.isEmpty()) {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -070010185 Iterator it = app.conProviders.keySet().iterator();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010186 while (it.hasNext()) {
10187 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
10188 cpr.clients.remove(app);
10189 }
10190 app.conProviders.clear();
10191 }
10192
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010193 // At this point there may be remaining entries in mLaunchingProviders
10194 // where we were the only one waiting, so they are no longer of use.
10195 // Look for these and clean up if found.
10196 // XXX Commented out for now. Trying to figure out a way to reproduce
10197 // the actual situation to identify what is actually going on.
10198 if (false) {
10199 for (int i=0; i<NL; i++) {
10200 ContentProviderRecord cpr = (ContentProviderRecord)
10201 mLaunchingProviders.get(i);
10202 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
10203 synchronized (cpr) {
10204 cpr.launchingApp = null;
10205 cpr.notifyAll();
10206 }
10207 }
10208 }
10209 }
10210
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010211 skipCurrentReceiverLocked(app);
10212
10213 // Unregister any receivers.
10214 if (app.receivers.size() > 0) {
10215 Iterator<ReceiverList> it = app.receivers.iterator();
10216 while (it.hasNext()) {
10217 removeReceiverLocked(it.next());
10218 }
10219 app.receivers.clear();
10220 }
10221
Christopher Tate181fafa2009-05-14 11:12:14 -070010222 // If the app is undergoing backup, tell the backup manager about it
10223 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
10224 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
10225 try {
10226 IBackupManager bm = IBackupManager.Stub.asInterface(
10227 ServiceManager.getService(Context.BACKUP_SERVICE));
10228 bm.agentDisconnected(app.info.packageName);
10229 } catch (RemoteException e) {
10230 // can't happen; backup manager is local
10231 }
10232 }
10233
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010234 // If the caller is restarting this app, then leave it in its
10235 // current lists and let the caller take care of it.
10236 if (restarting) {
10237 return;
10238 }
10239
10240 if (!app.persistent) {
10241 if (DEBUG_PROCESSES) Log.v(TAG,
10242 "Removing non-persistent process during cleanup: " + app);
10243 mProcessNames.remove(app.processName, app.info.uid);
10244 } else if (!app.removed) {
10245 // This app is persistent, so we need to keep its record around.
10246 // If it is not already on the pending app list, add it there
10247 // and start a new process for it.
10248 app.thread = null;
10249 app.forcingToForeground = null;
10250 app.foregroundServices = false;
10251 if (mPersistentStartingProcesses.indexOf(app) < 0) {
10252 mPersistentStartingProcesses.add(app);
10253 restart = true;
10254 }
10255 }
10256 mProcessesOnHold.remove(app);
10257
The Android Open Source Project4df24232009-03-05 14:34:35 -080010258 if (app == mHomeProcess) {
10259 mHomeProcess = null;
10260 }
10261
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010262 if (restart) {
10263 // We have components that still need to be running in the
10264 // process, so re-launch it.
10265 mProcessNames.put(app.processName, app.info.uid, app);
10266 startProcessLocked(app, "restart", app.processName);
10267 } else if (app.pid > 0 && app.pid != MY_PID) {
10268 // Goodbye!
10269 synchronized (mPidsSelfLocked) {
10270 mPidsSelfLocked.remove(app.pid);
10271 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
10272 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -070010273 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010274 }
10275 }
10276
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010277 boolean checkAppInLaunchingProvidersLocked(ProcessRecord app, boolean alwaysBad) {
10278 // Look through the content providers we are waiting to have launched,
10279 // and if any run in this process then either schedule a restart of
10280 // the process or kill the client waiting for it if this process has
10281 // gone bad.
10282 int NL = mLaunchingProviders.size();
10283 boolean restart = false;
10284 for (int i=0; i<NL; i++) {
10285 ContentProviderRecord cpr = (ContentProviderRecord)
10286 mLaunchingProviders.get(i);
10287 if (cpr.launchingApp == app) {
10288 if (!alwaysBad && !app.bad) {
10289 restart = true;
10290 } else {
10291 removeDyingProviderLocked(app, cpr);
10292 NL = mLaunchingProviders.size();
10293 }
10294 }
10295 }
10296 return restart;
10297 }
10298
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010299 // =========================================================
10300 // SERVICES
10301 // =========================================================
10302
10303 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
10304 ActivityManager.RunningServiceInfo info =
10305 new ActivityManager.RunningServiceInfo();
10306 info.service = r.name;
10307 if (r.app != null) {
10308 info.pid = r.app.pid;
10309 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010310 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010311 info.process = r.processName;
10312 info.foreground = r.isForeground;
10313 info.activeSince = r.createTime;
10314 info.started = r.startRequested;
10315 info.clientCount = r.connections.size();
10316 info.crashCount = r.crashCount;
10317 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010318 if (r.isForeground) {
10319 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
10320 }
10321 if (r.startRequested) {
10322 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
10323 }
Dan Egnor42471dd2010-01-07 17:25:22 -080010324 if (r.app != null && r.app.pid == MY_PID) {
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010325 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
10326 }
10327 if (r.app != null && r.app.persistent) {
10328 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
10329 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010330 for (ConnectionRecord conn : r.connections.values()) {
10331 if (conn.clientLabel != 0) {
10332 info.clientPackage = conn.binding.client.info.packageName;
10333 info.clientLabel = conn.clientLabel;
10334 break;
10335 }
10336 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010337 return info;
10338 }
10339
10340 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
10341 int flags) {
10342 synchronized (this) {
10343 ArrayList<ActivityManager.RunningServiceInfo> res
10344 = new ArrayList<ActivityManager.RunningServiceInfo>();
10345
10346 if (mServices.size() > 0) {
10347 Iterator<ServiceRecord> it = mServices.values().iterator();
10348 while (it.hasNext() && res.size() < maxNum) {
10349 res.add(makeRunningServiceInfoLocked(it.next()));
10350 }
10351 }
10352
10353 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
10354 ServiceRecord r = mRestartingServices.get(i);
10355 ActivityManager.RunningServiceInfo info =
10356 makeRunningServiceInfoLocked(r);
10357 info.restarting = r.nextRestartTime;
10358 res.add(info);
10359 }
10360
10361 return res;
10362 }
10363 }
10364
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010365 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
10366 synchronized (this) {
10367 ServiceRecord r = mServices.get(name);
10368 if (r != null) {
10369 for (ConnectionRecord conn : r.connections.values()) {
10370 if (conn.clientIntent != null) {
10371 return conn.clientIntent;
10372 }
10373 }
10374 }
10375 }
10376 return null;
10377 }
10378
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010379 private final ServiceRecord findServiceLocked(ComponentName name,
10380 IBinder token) {
10381 ServiceRecord r = mServices.get(name);
10382 return r == token ? r : null;
10383 }
10384
10385 private final class ServiceLookupResult {
10386 final ServiceRecord record;
10387 final String permission;
10388
10389 ServiceLookupResult(ServiceRecord _record, String _permission) {
10390 record = _record;
10391 permission = _permission;
10392 }
10393 };
10394
10395 private ServiceLookupResult findServiceLocked(Intent service,
10396 String resolvedType) {
10397 ServiceRecord r = null;
10398 if (service.getComponent() != null) {
10399 r = mServices.get(service.getComponent());
10400 }
10401 if (r == null) {
10402 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10403 r = mServicesByIntent.get(filter);
10404 }
10405
10406 if (r == null) {
10407 try {
10408 ResolveInfo rInfo =
10409 ActivityThread.getPackageManager().resolveService(
10410 service, resolvedType, 0);
10411 ServiceInfo sInfo =
10412 rInfo != null ? rInfo.serviceInfo : null;
10413 if (sInfo == null) {
10414 return null;
10415 }
10416
10417 ComponentName name = new ComponentName(
10418 sInfo.applicationInfo.packageName, sInfo.name);
10419 r = mServices.get(name);
10420 } catch (RemoteException ex) {
10421 // pm is in same process, this will never happen.
10422 }
10423 }
10424 if (r != null) {
10425 int callingPid = Binder.getCallingPid();
10426 int callingUid = Binder.getCallingUid();
10427 if (checkComponentPermission(r.permission,
10428 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10429 != PackageManager.PERMISSION_GRANTED) {
10430 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10431 + " from pid=" + callingPid
10432 + ", uid=" + callingUid
10433 + " requires " + r.permission);
10434 return new ServiceLookupResult(null, r.permission);
10435 }
10436 return new ServiceLookupResult(r, null);
10437 }
10438 return null;
10439 }
10440
10441 private class ServiceRestarter implements Runnable {
10442 private ServiceRecord mService;
10443
10444 void setService(ServiceRecord service) {
10445 mService = service;
10446 }
10447
10448 public void run() {
10449 synchronized(ActivityManagerService.this) {
10450 performServiceRestartLocked(mService);
10451 }
10452 }
10453 }
10454
10455 private ServiceLookupResult retrieveServiceLocked(Intent service,
10456 String resolvedType, int callingPid, int callingUid) {
10457 ServiceRecord r = null;
10458 if (service.getComponent() != null) {
10459 r = mServices.get(service.getComponent());
10460 }
10461 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10462 r = mServicesByIntent.get(filter);
10463 if (r == null) {
10464 try {
10465 ResolveInfo rInfo =
10466 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010467 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010468 ServiceInfo sInfo =
10469 rInfo != null ? rInfo.serviceInfo : null;
10470 if (sInfo == null) {
10471 Log.w(TAG, "Unable to start service " + service +
10472 ": not found");
10473 return null;
10474 }
10475
10476 ComponentName name = new ComponentName(
10477 sInfo.applicationInfo.packageName, sInfo.name);
10478 r = mServices.get(name);
10479 if (r == null) {
10480 filter = new Intent.FilterComparison(service.cloneFilter());
10481 ServiceRestarter res = new ServiceRestarter();
10482 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10483 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10484 synchronized (stats) {
10485 ss = stats.getServiceStatsLocked(
10486 sInfo.applicationInfo.uid, sInfo.packageName,
10487 sInfo.name);
10488 }
Dianne Hackbornb1c4a2a2010-01-19 15:36:42 -080010489 r = new ServiceRecord(this, ss, name, filter, sInfo, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010490 res.setService(r);
10491 mServices.put(name, r);
10492 mServicesByIntent.put(filter, r);
10493
10494 // Make sure this component isn't in the pending list.
10495 int N = mPendingServices.size();
10496 for (int i=0; i<N; i++) {
10497 ServiceRecord pr = mPendingServices.get(i);
10498 if (pr.name.equals(name)) {
10499 mPendingServices.remove(i);
10500 i--;
10501 N--;
10502 }
10503 }
10504 }
10505 } catch (RemoteException ex) {
10506 // pm is in same process, this will never happen.
10507 }
10508 }
10509 if (r != null) {
10510 if (checkComponentPermission(r.permission,
10511 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10512 != PackageManager.PERMISSION_GRANTED) {
10513 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10514 + " from pid=" + Binder.getCallingPid()
10515 + ", uid=" + Binder.getCallingUid()
10516 + " requires " + r.permission);
10517 return new ServiceLookupResult(null, r.permission);
10518 }
10519 return new ServiceLookupResult(r, null);
10520 }
10521 return null;
10522 }
10523
10524 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10525 long now = SystemClock.uptimeMillis();
10526 if (r.executeNesting == 0 && r.app != null) {
10527 if (r.app.executingServices.size() == 0) {
10528 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10529 msg.obj = r.app;
10530 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10531 }
10532 r.app.executingServices.add(r);
10533 }
10534 r.executeNesting++;
10535 r.executingStart = now;
10536 }
10537
10538 private final void sendServiceArgsLocked(ServiceRecord r,
10539 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010540 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010541 if (N == 0) {
10542 return;
10543 }
10544
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010545 int i = 0;
10546 while (i < N) {
10547 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010548 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010549 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010550 + r.name + " " + r.intent + " args=" + si.intent);
Dianne Hackbornfed534e2009-09-23 00:42:12 -070010551 if (si.intent == null && N > 1) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010552 // If somehow we got a dummy start at the front, then
10553 // just drop it here.
10554 i++;
10555 continue;
10556 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010557 bumpServiceExecutingLocked(r);
10558 if (!oomAdjusted) {
10559 oomAdjusted = true;
10560 updateOomAdjLocked(r.app);
10561 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010562 int flags = 0;
10563 if (si.deliveryCount > 0) {
10564 flags |= Service.START_FLAG_RETRY;
10565 }
10566 if (si.doneExecutingCount > 0) {
10567 flags |= Service.START_FLAG_REDELIVERY;
10568 }
10569 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10570 si.deliveredTime = SystemClock.uptimeMillis();
10571 r.deliveredStarts.add(si);
10572 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010573 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010574 } catch (RemoteException e) {
10575 // Remote process gone... we'll let the normal cleanup take
10576 // care of this.
10577 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010578 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010579 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010580 break;
10581 }
10582 }
10583 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010584 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010585 } else {
10586 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010587 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010588 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010589 }
10590 }
10591 }
10592
10593 private final boolean requestServiceBindingLocked(ServiceRecord r,
10594 IntentBindRecord i, boolean rebind) {
10595 if (r.app == null || r.app.thread == null) {
10596 // If service is not currently running, can't yet bind.
10597 return false;
10598 }
10599 if ((!i.requested || rebind) && i.apps.size() > 0) {
10600 try {
10601 bumpServiceExecutingLocked(r);
10602 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10603 + ": shouldUnbind=" + i.hasBound);
10604 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10605 if (!rebind) {
10606 i.requested = true;
10607 }
10608 i.hasBound = true;
10609 i.doRebind = false;
10610 } catch (RemoteException e) {
10611 return false;
10612 }
10613 }
10614 return true;
10615 }
10616
10617 private final void requestServiceBindingsLocked(ServiceRecord r) {
10618 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10619 while (bindings.hasNext()) {
10620 IntentBindRecord i = bindings.next();
10621 if (!requestServiceBindingLocked(r, i, false)) {
10622 break;
10623 }
10624 }
10625 }
10626
10627 private final void realStartServiceLocked(ServiceRecord r,
10628 ProcessRecord app) throws RemoteException {
10629 if (app.thread == null) {
10630 throw new RemoteException();
10631 }
10632
10633 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010634 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010635
10636 app.services.add(r);
10637 bumpServiceExecutingLocked(r);
Dianne Hackborndd71fc82009-12-16 19:24:32 -080010638 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010639
10640 boolean created = false;
10641 try {
10642 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10643 + r.name + " " + r.intent);
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010644 mStringBuilder.setLength(0);
10645 r.intent.getIntent().toShortString(mStringBuilder, false, true);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010646 EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010647 System.identityHashCode(r), r.shortName,
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010648 mStringBuilder.toString(), r.app.pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010649 synchronized (r.stats.getBatteryStats()) {
10650 r.stats.startLaunchedLocked();
10651 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010652 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010653 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010654 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010655 created = true;
10656 } finally {
10657 if (!created) {
10658 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010659 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010660 }
10661 }
10662
10663 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010664
10665 // If the service is in the started state, and there are no
10666 // pending arguments, then fake up one so its onStartCommand() will
10667 // be called.
10668 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10669 r.lastStartId++;
10670 if (r.lastStartId < 1) {
10671 r.lastStartId = 1;
10672 }
10673 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10674 }
10675
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010676 sendServiceArgsLocked(r, true);
10677 }
10678
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010679 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10680 boolean allowCancel) {
10681 boolean canceled = false;
10682
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010683 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010684 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010685 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010686
10687 // Any delivered but not yet finished starts should be put back
10688 // on the pending list.
10689 final int N = r.deliveredStarts.size();
10690 if (N > 0) {
10691 for (int i=N-1; i>=0; i--) {
10692 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10693 if (si.intent == null) {
10694 // We'll generate this again if needed.
10695 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10696 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10697 r.pendingStarts.add(0, si);
10698 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10699 dur *= 2;
10700 if (minDuration < dur) minDuration = dur;
10701 if (resetTime < dur) resetTime = dur;
10702 } else {
10703 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10704 + r.name);
10705 canceled = true;
10706 }
10707 }
10708 r.deliveredStarts.clear();
10709 }
10710
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010711 r.totalRestartCount++;
10712 if (r.restartDelay == 0) {
10713 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010714 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010715 } else {
10716 // If it has been a "reasonably long time" since the service
10717 // was started, then reset our restart duration back to
10718 // the beginning, so we don't infinitely increase the duration
10719 // on a service that just occasionally gets killed (which is
10720 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010721 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010722 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010723 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010724 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010725 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010726 if (r.restartDelay < minDuration) {
10727 r.restartDelay = minDuration;
10728 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010729 }
10730 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010731
10732 r.nextRestartTime = now + r.restartDelay;
10733
10734 // Make sure that we don't end up restarting a bunch of services
10735 // all at the same time.
10736 boolean repeat;
10737 do {
10738 repeat = false;
10739 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10740 ServiceRecord r2 = mRestartingServices.get(i);
10741 if (r2 != r && r.nextRestartTime
10742 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10743 && r.nextRestartTime
10744 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10745 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10746 r.restartDelay = r.nextRestartTime - now;
10747 repeat = true;
10748 break;
10749 }
10750 }
10751 } while (repeat);
10752
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010753 if (!mRestartingServices.contains(r)) {
10754 mRestartingServices.add(r);
10755 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010756
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010757 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010758
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010759 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010760 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010761 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10762 Log.w(TAG, "Scheduling restart of crashed service "
10763 + r.shortName + " in " + r.restartDelay + "ms");
Doug Zongker2bec3d42009-12-04 12:52:44 -080010764 EventLog.writeEvent(EventLogTags.AM_SCHEDULE_SERVICE_RESTART,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010765 r.shortName, r.restartDelay);
10766
10767 Message msg = Message.obtain();
10768 msg.what = SERVICE_ERROR_MSG;
10769 msg.obj = r;
10770 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010771
10772 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010773 }
10774
10775 final void performServiceRestartLocked(ServiceRecord r) {
10776 if (!mRestartingServices.contains(r)) {
10777 return;
10778 }
10779 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10780 }
10781
10782 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10783 if (r.restartDelay == 0) {
10784 return false;
10785 }
10786 r.resetRestartCounter();
10787 mRestartingServices.remove(r);
10788 mHandler.removeCallbacks(r.restarter);
10789 return true;
10790 }
10791
10792 private final boolean bringUpServiceLocked(ServiceRecord r,
10793 int intentFlags, boolean whileRestarting) {
10794 //Log.i(TAG, "Bring up service:");
10795 //r.dump(" ");
10796
Dianne Hackborn36124872009-10-08 16:22:03 -070010797 if (r.app != null && r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010798 sendServiceArgsLocked(r, false);
10799 return true;
10800 }
10801
10802 if (!whileRestarting && r.restartDelay > 0) {
10803 // If waiting for a restart, then do nothing.
10804 return true;
10805 }
10806
10807 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10808 + " " + r.intent);
10809
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010810 // We are now bringing the service up, so no longer in the
10811 // restarting state.
10812 mRestartingServices.remove(r);
10813
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010814 final String appName = r.processName;
10815 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10816 if (app != null && app.thread != null) {
10817 try {
10818 realStartServiceLocked(r, app);
10819 return true;
10820 } catch (RemoteException e) {
10821 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10822 }
10823
10824 // If a dead object exception was thrown -- fall through to
10825 // restart the application.
10826 }
10827
Dianne Hackborn36124872009-10-08 16:22:03 -070010828 // Not running -- get it started, and enqueue this service record
10829 // to be executed when the app comes up.
10830 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
10831 "service", r.name, false) == null) {
10832 Log.w(TAG, "Unable to launch app "
10833 + r.appInfo.packageName + "/"
10834 + r.appInfo.uid + " for service "
10835 + r.intent.getIntent() + ": process is bad");
10836 bringDownServiceLocked(r, true);
10837 return false;
10838 }
10839
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010840 if (!mPendingServices.contains(r)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010841 mPendingServices.add(r);
10842 }
Dianne Hackborn36124872009-10-08 16:22:03 -070010843
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010844 return true;
10845 }
10846
10847 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10848 //Log.i(TAG, "Bring down service:");
10849 //r.dump(" ");
10850
10851 // Does it still need to run?
10852 if (!force && r.startRequested) {
10853 return;
10854 }
10855 if (r.connections.size() > 0) {
10856 if (!force) {
10857 // XXX should probably keep a count of the number of auto-create
10858 // connections directly in the service.
10859 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10860 while (it.hasNext()) {
10861 ConnectionRecord cr = it.next();
10862 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10863 return;
10864 }
10865 }
10866 }
10867
10868 // Report to all of the connections that the service is no longer
10869 // available.
10870 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10871 while (it.hasNext()) {
10872 ConnectionRecord c = it.next();
10873 try {
10874 // todo: shouldn't be a synchronous call!
10875 c.conn.connected(r.name, null);
10876 } catch (Exception e) {
10877 Log.w(TAG, "Failure disconnecting service " + r.name +
10878 " to connection " + c.conn.asBinder() +
10879 " (in " + c.binding.client.processName + ")", e);
10880 }
10881 }
10882 }
10883
10884 // Tell the service that it has been unbound.
10885 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10886 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10887 while (it.hasNext()) {
10888 IntentBindRecord ibr = it.next();
10889 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10890 + ": hasBound=" + ibr.hasBound);
10891 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10892 try {
10893 bumpServiceExecutingLocked(r);
10894 updateOomAdjLocked(r.app);
10895 ibr.hasBound = false;
10896 r.app.thread.scheduleUnbindService(r,
10897 ibr.intent.getIntent());
10898 } catch (Exception e) {
10899 Log.w(TAG, "Exception when unbinding service "
10900 + r.shortName, e);
10901 serviceDoneExecutingLocked(r, true);
10902 }
10903 }
10904 }
10905 }
10906
10907 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10908 + " " + r.intent);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010909 EventLog.writeEvent(EventLogTags.AM_DESTROY_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010910 System.identityHashCode(r), r.shortName,
10911 (r.app != null) ? r.app.pid : -1);
10912
10913 mServices.remove(r.name);
10914 mServicesByIntent.remove(r.intent);
10915 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10916 r.totalRestartCount = 0;
10917 unscheduleServiceRestartLocked(r);
10918
10919 // Also make sure it is not on the pending list.
10920 int N = mPendingServices.size();
10921 for (int i=0; i<N; i++) {
10922 if (mPendingServices.get(i) == r) {
10923 mPendingServices.remove(i);
10924 if (DEBUG_SERVICE) Log.v(
10925 TAG, "Removed pending service: " + r.shortName);
10926 i--;
10927 N--;
10928 }
10929 }
10930
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010931 r.cancelNotification();
10932 r.isForeground = false;
10933 r.foregroundId = 0;
10934 r.foregroundNoti = null;
10935
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010936 // Clear start entries.
10937 r.deliveredStarts.clear();
10938 r.pendingStarts.clear();
10939
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010940 if (r.app != null) {
10941 synchronized (r.stats.getBatteryStats()) {
10942 r.stats.stopLaunchedLocked();
10943 }
10944 r.app.services.remove(r);
10945 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010946 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010947 if (DEBUG_SERVICE) Log.v(TAG,
10948 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010949 bumpServiceExecutingLocked(r);
10950 mStoppingServices.add(r);
10951 updateOomAdjLocked(r.app);
10952 r.app.thread.scheduleStopService(r);
10953 } catch (Exception e) {
10954 Log.w(TAG, "Exception when stopping service "
10955 + r.shortName, e);
10956 serviceDoneExecutingLocked(r, true);
10957 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010958 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010959 } else {
10960 if (DEBUG_SERVICE) Log.v(
10961 TAG, "Removed service that has no process: " + r.shortName);
10962 }
10963 } else {
10964 if (DEBUG_SERVICE) Log.v(
10965 TAG, "Removed service that is not running: " + r.shortName);
10966 }
10967 }
10968
10969 ComponentName startServiceLocked(IApplicationThread caller,
10970 Intent service, String resolvedType,
10971 int callingPid, int callingUid) {
10972 synchronized(this) {
10973 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10974 + " type=" + resolvedType + " args=" + service.getExtras());
10975
10976 if (caller != null) {
10977 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10978 if (callerApp == null) {
10979 throw new SecurityException(
10980 "Unable to find app for caller " + caller
10981 + " (pid=" + Binder.getCallingPid()
10982 + ") when starting service " + service);
10983 }
10984 }
10985
10986 ServiceLookupResult res =
10987 retrieveServiceLocked(service, resolvedType,
10988 callingPid, callingUid);
10989 if (res == null) {
10990 return null;
10991 }
10992 if (res.record == null) {
10993 return new ComponentName("!", res.permission != null
10994 ? res.permission : "private to package");
10995 }
10996 ServiceRecord r = res.record;
10997 if (unscheduleServiceRestartLocked(r)) {
10998 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10999 + r.shortName);
11000 }
11001 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011002 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011003 r.lastStartId++;
11004 if (r.lastStartId < 1) {
11005 r.lastStartId = 1;
11006 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011007 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011008 r.lastActivity = SystemClock.uptimeMillis();
11009 synchronized (r.stats.getBatteryStats()) {
11010 r.stats.startRunningLocked();
11011 }
11012 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
11013 return new ComponentName("!", "Service process is bad");
11014 }
11015 return r.name;
11016 }
11017 }
11018
11019 public ComponentName startService(IApplicationThread caller, Intent service,
11020 String resolvedType) {
11021 // Refuse possible leaked file descriptors
11022 if (service != null && service.hasFileDescriptors() == true) {
11023 throw new IllegalArgumentException("File descriptors passed in Intent");
11024 }
11025
11026 synchronized(this) {
11027 final int callingPid = Binder.getCallingPid();
11028 final int callingUid = Binder.getCallingUid();
11029 final long origId = Binder.clearCallingIdentity();
11030 ComponentName res = startServiceLocked(caller, service,
11031 resolvedType, callingPid, callingUid);
11032 Binder.restoreCallingIdentity(origId);
11033 return res;
11034 }
11035 }
11036
11037 ComponentName startServiceInPackage(int uid,
11038 Intent service, String resolvedType) {
11039 synchronized(this) {
11040 final long origId = Binder.clearCallingIdentity();
11041 ComponentName res = startServiceLocked(null, service,
11042 resolvedType, -1, uid);
11043 Binder.restoreCallingIdentity(origId);
11044 return res;
11045 }
11046 }
11047
11048 public int stopService(IApplicationThread caller, Intent service,
11049 String resolvedType) {
11050 // Refuse possible leaked file descriptors
11051 if (service != null && service.hasFileDescriptors() == true) {
11052 throw new IllegalArgumentException("File descriptors passed in Intent");
11053 }
11054
11055 synchronized(this) {
11056 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
11057 + " type=" + resolvedType);
11058
11059 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11060 if (caller != null && callerApp == null) {
11061 throw new SecurityException(
11062 "Unable to find app for caller " + caller
11063 + " (pid=" + Binder.getCallingPid()
11064 + ") when stopping service " + service);
11065 }
11066
11067 // If this service is active, make sure it is stopped.
11068 ServiceLookupResult r = findServiceLocked(service, resolvedType);
11069 if (r != null) {
11070 if (r.record != null) {
11071 synchronized (r.record.stats.getBatteryStats()) {
11072 r.record.stats.stopRunningLocked();
11073 }
11074 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011075 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011076 final long origId = Binder.clearCallingIdentity();
11077 bringDownServiceLocked(r.record, false);
11078 Binder.restoreCallingIdentity(origId);
11079 return 1;
11080 }
11081 return -1;
11082 }
11083 }
11084
11085 return 0;
11086 }
11087
11088 public IBinder peekService(Intent service, String resolvedType) {
11089 // Refuse possible leaked file descriptors
11090 if (service != null && service.hasFileDescriptors() == true) {
11091 throw new IllegalArgumentException("File descriptors passed in Intent");
11092 }
11093
11094 IBinder ret = null;
11095
11096 synchronized(this) {
11097 ServiceLookupResult r = findServiceLocked(service, resolvedType);
11098
11099 if (r != null) {
11100 // r.record is null if findServiceLocked() failed the caller permission check
11101 if (r.record == null) {
11102 throw new SecurityException(
11103 "Permission Denial: Accessing service " + r.record.name
11104 + " from pid=" + Binder.getCallingPid()
11105 + ", uid=" + Binder.getCallingUid()
11106 + " requires " + r.permission);
11107 }
11108 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
11109 if (ib != null) {
11110 ret = ib.binder;
11111 }
11112 }
11113 }
11114
11115 return ret;
11116 }
11117
11118 public boolean stopServiceToken(ComponentName className, IBinder token,
11119 int startId) {
11120 synchronized(this) {
11121 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
11122 + " " + token + " startId=" + startId);
11123 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011124 if (r != null) {
11125 if (startId >= 0) {
11126 // Asked to only stop if done with all work. Note that
11127 // to avoid leaks, we will take this as dropping all
11128 // start items up to and including this one.
11129 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11130 if (si != null) {
11131 while (r.deliveredStarts.size() > 0) {
11132 if (r.deliveredStarts.remove(0) == si) {
11133 break;
11134 }
11135 }
11136 }
11137
11138 if (r.lastStartId != startId) {
11139 return false;
11140 }
11141
11142 if (r.deliveredStarts.size() > 0) {
11143 Log.w(TAG, "stopServiceToken startId " + startId
11144 + " is last, but have " + r.deliveredStarts.size()
11145 + " remaining args");
11146 }
11147 }
11148
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011149 synchronized (r.stats.getBatteryStats()) {
11150 r.stats.stopRunningLocked();
11151 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011152 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011153 }
11154 final long origId = Binder.clearCallingIdentity();
11155 bringDownServiceLocked(r, false);
11156 Binder.restoreCallingIdentity(origId);
11157 return true;
11158 }
11159 }
11160 return false;
11161 }
11162
11163 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011164 int id, Notification notification, boolean removeNotification) {
11165 final long origId = Binder.clearCallingIdentity();
11166 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011167 synchronized(this) {
11168 ServiceRecord r = findServiceLocked(className, token);
11169 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011170 if (id != 0) {
11171 if (notification == null) {
11172 throw new IllegalArgumentException("null notification");
11173 }
11174 if (r.foregroundId != id) {
11175 r.cancelNotification();
11176 r.foregroundId = id;
11177 }
11178 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
11179 r.foregroundNoti = notification;
11180 r.isForeground = true;
11181 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011182 if (r.app != null) {
11183 updateServiceForegroundLocked(r.app, true);
11184 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011185 } else {
11186 if (r.isForeground) {
11187 r.isForeground = false;
11188 if (r.app != null) {
11189 updateServiceForegroundLocked(r.app, true);
11190 }
11191 }
11192 if (removeNotification) {
11193 r.cancelNotification();
11194 r.foregroundId = 0;
11195 r.foregroundNoti = null;
11196 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011197 }
11198 }
11199 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011200 } finally {
11201 Binder.restoreCallingIdentity(origId);
11202 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011203 }
11204
11205 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
11206 boolean anyForeground = false;
11207 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
11208 if (sr.isForeground) {
11209 anyForeground = true;
11210 break;
11211 }
11212 }
11213 if (anyForeground != proc.foregroundServices) {
11214 proc.foregroundServices = anyForeground;
11215 if (oomAdj) {
11216 updateOomAdjLocked();
11217 }
11218 }
11219 }
11220
11221 public int bindService(IApplicationThread caller, IBinder token,
11222 Intent service, String resolvedType,
11223 IServiceConnection connection, int flags) {
11224 // Refuse possible leaked file descriptors
11225 if (service != null && service.hasFileDescriptors() == true) {
11226 throw new IllegalArgumentException("File descriptors passed in Intent");
11227 }
11228
11229 synchronized(this) {
11230 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
11231 + " type=" + resolvedType + " conn=" + connection.asBinder()
11232 + " flags=0x" + Integer.toHexString(flags));
11233 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11234 if (callerApp == null) {
11235 throw new SecurityException(
11236 "Unable to find app for caller " + caller
11237 + " (pid=" + Binder.getCallingPid()
11238 + ") when binding service " + service);
11239 }
11240
11241 HistoryRecord activity = null;
11242 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070011243 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011244 if (aindex < 0) {
11245 Log.w(TAG, "Binding with unknown activity: " + token);
11246 return 0;
11247 }
11248 activity = (HistoryRecord)mHistory.get(aindex);
11249 }
11250
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011251 int clientLabel = 0;
11252 PendingIntent clientIntent = null;
11253
11254 if (callerApp.info.uid == Process.SYSTEM_UID) {
11255 // Hacky kind of thing -- allow system stuff to tell us
11256 // what they are, so we can report this elsewhere for
11257 // others to know why certain services are running.
11258 try {
11259 clientIntent = (PendingIntent)service.getParcelableExtra(
11260 Intent.EXTRA_CLIENT_INTENT);
11261 } catch (RuntimeException e) {
11262 }
11263 if (clientIntent != null) {
11264 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
11265 if (clientLabel != 0) {
11266 // There are no useful extras in the intent, trash them.
11267 // System code calling with this stuff just needs to know
11268 // this will happen.
11269 service = service.cloneFilter();
11270 }
11271 }
11272 }
11273
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011274 ServiceLookupResult res =
11275 retrieveServiceLocked(service, resolvedType,
11276 Binder.getCallingPid(), Binder.getCallingUid());
11277 if (res == null) {
11278 return 0;
11279 }
11280 if (res.record == null) {
11281 return -1;
11282 }
11283 ServiceRecord s = res.record;
11284
11285 final long origId = Binder.clearCallingIdentity();
11286
11287 if (unscheduleServiceRestartLocked(s)) {
11288 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
11289 + s.shortName);
11290 }
11291
11292 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
11293 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011294 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011295
11296 IBinder binder = connection.asBinder();
11297 s.connections.put(binder, c);
11298 b.connections.add(c);
11299 if (activity != null) {
11300 if (activity.connections == null) {
11301 activity.connections = new HashSet<ConnectionRecord>();
11302 }
11303 activity.connections.add(c);
11304 }
11305 b.client.connections.add(c);
11306 mServiceConnections.put(binder, c);
11307
11308 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
11309 s.lastActivity = SystemClock.uptimeMillis();
11310 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
11311 return 0;
11312 }
11313 }
11314
11315 if (s.app != null) {
11316 // This could have made the service more important.
11317 updateOomAdjLocked(s.app);
11318 }
11319
11320 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
11321 + ": received=" + b.intent.received
11322 + " apps=" + b.intent.apps.size()
11323 + " doRebind=" + b.intent.doRebind);
11324
11325 if (s.app != null && b.intent.received) {
11326 // Service is already running, so we can immediately
11327 // publish the connection.
11328 try {
11329 c.conn.connected(s.name, b.intent.binder);
11330 } catch (Exception e) {
11331 Log.w(TAG, "Failure sending service " + s.shortName
11332 + " to connection " + c.conn.asBinder()
11333 + " (in " + c.binding.client.processName + ")", e);
11334 }
11335
11336 // If this is the first app connected back to this binding,
11337 // and the service had previously asked to be told when
11338 // rebound, then do so.
11339 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
11340 requestServiceBindingLocked(s, b.intent, true);
11341 }
11342 } else if (!b.intent.requested) {
11343 requestServiceBindingLocked(s, b.intent, false);
11344 }
11345
11346 Binder.restoreCallingIdentity(origId);
11347 }
11348
11349 return 1;
11350 }
11351
11352 private void removeConnectionLocked(
11353 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
11354 IBinder binder = c.conn.asBinder();
11355 AppBindRecord b = c.binding;
11356 ServiceRecord s = b.service;
11357 s.connections.remove(binder);
11358 b.connections.remove(c);
11359 if (c.activity != null && c.activity != skipAct) {
11360 if (c.activity.connections != null) {
11361 c.activity.connections.remove(c);
11362 }
11363 }
11364 if (b.client != skipApp) {
11365 b.client.connections.remove(c);
11366 }
11367 mServiceConnections.remove(binder);
11368
11369 if (b.connections.size() == 0) {
11370 b.intent.apps.remove(b.client);
11371 }
11372
11373 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
11374 + ": shouldUnbind=" + b.intent.hasBound);
11375 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
11376 && b.intent.hasBound) {
11377 try {
11378 bumpServiceExecutingLocked(s);
11379 updateOomAdjLocked(s.app);
11380 b.intent.hasBound = false;
11381 // Assume the client doesn't want to know about a rebind;
11382 // we will deal with that later if it asks for one.
11383 b.intent.doRebind = false;
11384 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
11385 } catch (Exception e) {
11386 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
11387 serviceDoneExecutingLocked(s, true);
11388 }
11389 }
11390
11391 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
11392 bringDownServiceLocked(s, false);
11393 }
11394 }
11395
11396 public boolean unbindService(IServiceConnection connection) {
11397 synchronized (this) {
11398 IBinder binder = connection.asBinder();
11399 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11400 ConnectionRecord r = mServiceConnections.get(binder);
11401 if (r == null) {
11402 Log.w(TAG, "Unbind failed: could not find connection for "
11403 + connection.asBinder());
11404 return false;
11405 }
11406
11407 final long origId = Binder.clearCallingIdentity();
11408
11409 removeConnectionLocked(r, null, null);
11410
11411 if (r.binding.service.app != null) {
11412 // This could have made the service less important.
11413 updateOomAdjLocked(r.binding.service.app);
11414 }
11415
11416 Binder.restoreCallingIdentity(origId);
11417 }
11418
11419 return true;
11420 }
11421
11422 public void publishService(IBinder token, Intent intent, IBinder service) {
11423 // Refuse possible leaked file descriptors
11424 if (intent != null && intent.hasFileDescriptors() == true) {
11425 throw new IllegalArgumentException("File descriptors passed in Intent");
11426 }
11427
11428 synchronized(this) {
11429 if (!(token instanceof ServiceRecord)) {
11430 throw new IllegalArgumentException("Invalid service token");
11431 }
11432 ServiceRecord r = (ServiceRecord)token;
11433
11434 final long origId = Binder.clearCallingIdentity();
11435
11436 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11437 + " " + intent + ": " + service);
11438 if (r != null) {
11439 Intent.FilterComparison filter
11440 = new Intent.FilterComparison(intent);
11441 IntentBindRecord b = r.bindings.get(filter);
11442 if (b != null && !b.received) {
11443 b.binder = service;
11444 b.requested = true;
11445 b.received = true;
11446 if (r.connections.size() > 0) {
11447 Iterator<ConnectionRecord> it
11448 = r.connections.values().iterator();
11449 while (it.hasNext()) {
11450 ConnectionRecord c = it.next();
11451 if (!filter.equals(c.binding.intent.intent)) {
11452 if (DEBUG_SERVICE) Log.v(
11453 TAG, "Not publishing to: " + c);
11454 if (DEBUG_SERVICE) Log.v(
11455 TAG, "Bound intent: " + c.binding.intent.intent);
11456 if (DEBUG_SERVICE) Log.v(
11457 TAG, "Published intent: " + intent);
11458 continue;
11459 }
11460 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11461 try {
11462 c.conn.connected(r.name, service);
11463 } catch (Exception e) {
11464 Log.w(TAG, "Failure sending service " + r.name +
11465 " to connection " + c.conn.asBinder() +
11466 " (in " + c.binding.client.processName + ")", e);
11467 }
11468 }
11469 }
11470 }
11471
11472 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11473
11474 Binder.restoreCallingIdentity(origId);
11475 }
11476 }
11477 }
11478
11479 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11480 // Refuse possible leaked file descriptors
11481 if (intent != null && intent.hasFileDescriptors() == true) {
11482 throw new IllegalArgumentException("File descriptors passed in Intent");
11483 }
11484
11485 synchronized(this) {
11486 if (!(token instanceof ServiceRecord)) {
11487 throw new IllegalArgumentException("Invalid service token");
11488 }
11489 ServiceRecord r = (ServiceRecord)token;
11490
11491 final long origId = Binder.clearCallingIdentity();
11492
11493 if (r != null) {
11494 Intent.FilterComparison filter
11495 = new Intent.FilterComparison(intent);
11496 IntentBindRecord b = r.bindings.get(filter);
11497 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11498 + " at " + b + ": apps="
11499 + (b != null ? b.apps.size() : 0));
11500 if (b != null) {
11501 if (b.apps.size() > 0) {
11502 // Applications have already bound since the last
11503 // unbind, so just rebind right here.
11504 requestServiceBindingLocked(r, b, true);
11505 } else {
11506 // Note to tell the service the next time there is
11507 // a new client.
11508 b.doRebind = true;
11509 }
11510 }
11511
11512 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11513
11514 Binder.restoreCallingIdentity(origId);
11515 }
11516 }
11517 }
11518
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011519 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011520 synchronized(this) {
11521 if (!(token instanceof ServiceRecord)) {
11522 throw new IllegalArgumentException("Invalid service token");
11523 }
11524 ServiceRecord r = (ServiceRecord)token;
11525 boolean inStopping = mStoppingServices.contains(token);
11526 if (r != null) {
11527 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11528 + ": nesting=" + r.executeNesting
11529 + ", inStopping=" + inStopping);
11530 if (r != token) {
11531 Log.w(TAG, "Done executing service " + r.name
11532 + " with incorrect token: given " + token
11533 + ", expected " + r);
11534 return;
11535 }
11536
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011537 if (type == 1) {
11538 // This is a call from a service start... take care of
11539 // book-keeping.
11540 r.callStart = true;
11541 switch (res) {
11542 case Service.START_STICKY_COMPATIBILITY:
11543 case Service.START_STICKY: {
11544 // We are done with the associated start arguments.
11545 r.findDeliveredStart(startId, true);
11546 // Don't stop if killed.
11547 r.stopIfKilled = false;
11548 break;
11549 }
11550 case Service.START_NOT_STICKY: {
11551 // We are done with the associated start arguments.
11552 r.findDeliveredStart(startId, true);
11553 if (r.lastStartId == startId) {
11554 // There is no more work, and this service
11555 // doesn't want to hang around if killed.
11556 r.stopIfKilled = true;
11557 }
11558 break;
11559 }
11560 case Service.START_REDELIVER_INTENT: {
11561 // We'll keep this item until they explicitly
11562 // call stop for it, but keep track of the fact
11563 // that it was delivered.
11564 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11565 if (si != null) {
11566 si.deliveryCount = 0;
11567 si.doneExecutingCount++;
11568 // Don't stop if killed.
11569 r.stopIfKilled = true;
11570 }
11571 break;
11572 }
11573 default:
11574 throw new IllegalArgumentException(
11575 "Unknown service start result: " + res);
11576 }
11577 if (res == Service.START_STICKY_COMPATIBILITY) {
11578 r.callStart = false;
11579 }
11580 }
11581
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011582 final long origId = Binder.clearCallingIdentity();
11583 serviceDoneExecutingLocked(r, inStopping);
11584 Binder.restoreCallingIdentity(origId);
11585 } else {
11586 Log.w(TAG, "Done executing unknown service " + r.name
11587 + " with token " + token);
11588 }
11589 }
11590 }
11591
11592 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11593 r.executeNesting--;
11594 if (r.executeNesting <= 0 && r.app != null) {
11595 r.app.executingServices.remove(r);
11596 if (r.app.executingServices.size() == 0) {
11597 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11598 }
11599 if (inStopping) {
11600 mStoppingServices.remove(r);
11601 }
11602 updateOomAdjLocked(r.app);
11603 }
11604 }
11605
11606 void serviceTimeout(ProcessRecord proc) {
11607 synchronized(this) {
11608 if (proc.executingServices.size() == 0 || proc.thread == null) {
11609 return;
11610 }
11611 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11612 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11613 ServiceRecord timeout = null;
11614 long nextTime = 0;
11615 while (it.hasNext()) {
11616 ServiceRecord sr = it.next();
11617 if (sr.executingStart < maxTime) {
11618 timeout = sr;
11619 break;
11620 }
11621 if (sr.executingStart > nextTime) {
11622 nextTime = sr.executingStart;
11623 }
11624 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -080011625 if (timeout != null && mLruProcesses.contains(proc)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011626 Log.w(TAG, "Timeout executing service: " + timeout);
Dan Egnor42471dd2010-01-07 17:25:22 -080011627 appNotRespondingLocked(proc, null, null, "Executing service " + timeout.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011628 } else {
11629 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11630 msg.obj = proc;
11631 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11632 }
11633 }
11634 }
11635
11636 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011637 // BACKUP AND RESTORE
11638 // =========================================================
11639
11640 // Cause the target app to be launched if necessary and its backup agent
11641 // instantiated. The backup agent will invoke backupAgentCreated() on the
11642 // activity manager to announce its creation.
11643 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11644 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11645 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11646
11647 synchronized(this) {
11648 // !!! TODO: currently no check here that we're already bound
11649 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11650 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11651 synchronized (stats) {
11652 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11653 }
11654
11655 BackupRecord r = new BackupRecord(ss, app, backupMode);
11656 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11657 // startProcessLocked() returns existing proc's record if it's already running
11658 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011659 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011660 if (proc == null) {
11661 Log.e(TAG, "Unable to start backup agent process " + r);
11662 return false;
11663 }
11664
11665 r.app = proc;
11666 mBackupTarget = r;
11667 mBackupAppName = app.packageName;
11668
Christopher Tate6fa95972009-06-05 18:43:55 -070011669 // Try not to kill the process during backup
11670 updateOomAdjLocked(proc);
11671
Christopher Tate181fafa2009-05-14 11:12:14 -070011672 // If the process is already attached, schedule the creation of the backup agent now.
11673 // If it is not yet live, this will be done when it attaches to the framework.
11674 if (proc.thread != null) {
11675 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11676 try {
11677 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11678 } catch (RemoteException e) {
Christopher Tate436344a2009-09-30 16:17:37 -070011679 // Will time out on the backup manager side
Christopher Tate181fafa2009-05-14 11:12:14 -070011680 }
11681 } else {
11682 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11683 }
11684 // Invariants: at this point, the target app process exists and the application
11685 // is either already running or in the process of coming up. mBackupTarget and
11686 // mBackupAppName describe the app, so that when it binds back to the AM we
11687 // know that it's scheduled for a backup-agent operation.
11688 }
11689
11690 return true;
11691 }
11692
11693 // A backup agent has just come up
11694 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11695 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11696 + " = " + agent);
11697
11698 synchronized(this) {
11699 if (!agentPackageName.equals(mBackupAppName)) {
11700 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11701 return;
11702 }
11703
Christopher Tate043dadc2009-06-02 16:11:00 -070011704 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011705 try {
11706 IBackupManager bm = IBackupManager.Stub.asInterface(
11707 ServiceManager.getService(Context.BACKUP_SERVICE));
11708 bm.agentConnected(agentPackageName, agent);
11709 } catch (RemoteException e) {
11710 // can't happen; the backup manager service is local
11711 } catch (Exception e) {
11712 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11713 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011714 } finally {
11715 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011716 }
11717 }
11718 }
11719
11720 // done with this agent
11721 public void unbindBackupAgent(ApplicationInfo appInfo) {
11722 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011723 if (appInfo == null) {
11724 Log.w(TAG, "unbind backup agent for null app");
11725 return;
11726 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011727
11728 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011729 if (mBackupAppName == null) {
11730 Log.w(TAG, "Unbinding backup agent with no active backup");
11731 return;
11732 }
11733
Christopher Tate181fafa2009-05-14 11:12:14 -070011734 if (!mBackupAppName.equals(appInfo.packageName)) {
11735 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11736 return;
11737 }
11738
Christopher Tate6fa95972009-06-05 18:43:55 -070011739 ProcessRecord proc = mBackupTarget.app;
11740 mBackupTarget = null;
11741 mBackupAppName = null;
11742
11743 // Not backing this app up any more; reset its OOM adjustment
11744 updateOomAdjLocked(proc);
11745
Christopher Tatec7b31e32009-06-10 15:49:30 -070011746 // If the app crashed during backup, 'thread' will be null here
11747 if (proc.thread != null) {
11748 try {
11749 proc.thread.scheduleDestroyBackupAgent(appInfo);
11750 } catch (Exception e) {
11751 Log.e(TAG, "Exception when unbinding backup agent:");
11752 e.printStackTrace();
11753 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011754 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011755 }
11756 }
11757 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011758 // BROADCASTS
11759 // =========================================================
11760
11761 private final List getStickies(String action, IntentFilter filter,
11762 List cur) {
11763 final ContentResolver resolver = mContext.getContentResolver();
11764 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11765 if (list == null) {
11766 return cur;
11767 }
11768 int N = list.size();
11769 for (int i=0; i<N; i++) {
11770 Intent intent = list.get(i);
11771 if (filter.match(resolver, intent, true, TAG) >= 0) {
11772 if (cur == null) {
11773 cur = new ArrayList<Intent>();
11774 }
11775 cur.add(intent);
11776 }
11777 }
11778 return cur;
11779 }
11780
11781 private final void scheduleBroadcastsLocked() {
11782 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11783 + mBroadcastsScheduled);
11784
11785 if (mBroadcastsScheduled) {
11786 return;
11787 }
11788 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11789 mBroadcastsScheduled = true;
11790 }
11791
11792 public Intent registerReceiver(IApplicationThread caller,
11793 IIntentReceiver receiver, IntentFilter filter, String permission) {
11794 synchronized(this) {
11795 ProcessRecord callerApp = null;
11796 if (caller != null) {
11797 callerApp = getRecordForAppLocked(caller);
11798 if (callerApp == null) {
11799 throw new SecurityException(
11800 "Unable to find app for caller " + caller
11801 + " (pid=" + Binder.getCallingPid()
11802 + ") when registering receiver " + receiver);
11803 }
11804 }
11805
11806 List allSticky = null;
11807
11808 // Look for any matching sticky broadcasts...
11809 Iterator actions = filter.actionsIterator();
11810 if (actions != null) {
11811 while (actions.hasNext()) {
11812 String action = (String)actions.next();
11813 allSticky = getStickies(action, filter, allSticky);
11814 }
11815 } else {
11816 allSticky = getStickies(null, filter, allSticky);
11817 }
11818
11819 // The first sticky in the list is returned directly back to
11820 // the client.
11821 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11822
11823 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11824 + ": " + sticky);
11825
11826 if (receiver == null) {
11827 return sticky;
11828 }
11829
11830 ReceiverList rl
11831 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11832 if (rl == null) {
11833 rl = new ReceiverList(this, callerApp,
11834 Binder.getCallingPid(),
11835 Binder.getCallingUid(), receiver);
11836 if (rl.app != null) {
11837 rl.app.receivers.add(rl);
11838 } else {
11839 try {
11840 receiver.asBinder().linkToDeath(rl, 0);
11841 } catch (RemoteException e) {
11842 return sticky;
11843 }
11844 rl.linkedToDeath = true;
11845 }
11846 mRegisteredReceivers.put(receiver.asBinder(), rl);
11847 }
11848 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11849 rl.add(bf);
11850 if (!bf.debugCheck()) {
11851 Log.w(TAG, "==> For Dynamic broadast");
11852 }
11853 mReceiverResolver.addFilter(bf);
11854
11855 // Enqueue broadcasts for all existing stickies that match
11856 // this filter.
11857 if (allSticky != null) {
11858 ArrayList receivers = new ArrayList();
11859 receivers.add(bf);
11860
11861 int N = allSticky.size();
11862 for (int i=0; i<N; i++) {
11863 Intent intent = (Intent)allSticky.get(i);
11864 BroadcastRecord r = new BroadcastRecord(intent, null,
11865 null, -1, -1, null, receivers, null, 0, null, null,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011866 false, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011867 if (mParallelBroadcasts.size() == 0) {
11868 scheduleBroadcastsLocked();
11869 }
11870 mParallelBroadcasts.add(r);
11871 }
11872 }
11873
11874 return sticky;
11875 }
11876 }
11877
11878 public void unregisterReceiver(IIntentReceiver receiver) {
11879 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11880
11881 boolean doNext = false;
11882
11883 synchronized(this) {
11884 ReceiverList rl
11885 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11886 if (rl != null) {
11887 if (rl.curBroadcast != null) {
11888 BroadcastRecord r = rl.curBroadcast;
11889 doNext = finishReceiverLocked(
11890 receiver.asBinder(), r.resultCode, r.resultData,
11891 r.resultExtras, r.resultAbort, true);
11892 }
11893
11894 if (rl.app != null) {
11895 rl.app.receivers.remove(rl);
11896 }
11897 removeReceiverLocked(rl);
11898 if (rl.linkedToDeath) {
11899 rl.linkedToDeath = false;
11900 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11901 }
11902 }
11903 }
11904
11905 if (!doNext) {
11906 return;
11907 }
11908
11909 final long origId = Binder.clearCallingIdentity();
11910 processNextBroadcast(false);
11911 trimApplications();
11912 Binder.restoreCallingIdentity(origId);
11913 }
11914
11915 void removeReceiverLocked(ReceiverList rl) {
11916 mRegisteredReceivers.remove(rl.receiver.asBinder());
11917 int N = rl.size();
11918 for (int i=0; i<N; i++) {
11919 mReceiverResolver.removeFilter(rl.get(i));
11920 }
11921 }
11922
11923 private final int broadcastIntentLocked(ProcessRecord callerApp,
11924 String callerPackage, Intent intent, String resolvedType,
11925 IIntentReceiver resultTo, int resultCode, String resultData,
11926 Bundle map, String requiredPermission,
11927 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11928 intent = new Intent(intent);
11929
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011930 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011931 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11932 + " ordered=" + ordered);
11933 if ((resultTo != null) && !ordered) {
11934 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11935 }
11936
11937 // Handle special intents: if this broadcast is from the package
11938 // manager about a package being removed, we need to remove all of
11939 // its activities from the history stack.
11940 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11941 intent.getAction());
11942 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11943 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
Suchi Amalapurapub56ae202010-02-04 22:51:07 -080011944 || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011945 || uidRemoved) {
11946 if (checkComponentPermission(
11947 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11948 callingPid, callingUid, -1)
11949 == PackageManager.PERMISSION_GRANTED) {
11950 if (uidRemoved) {
11951 final Bundle intentExtras = intent.getExtras();
11952 final int uid = intentExtras != null
11953 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11954 if (uid >= 0) {
11955 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11956 synchronized (bs) {
11957 bs.removeUidStatsLocked(uid);
11958 }
11959 }
11960 } else {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080011961 // If resources are unvailble just force stop all
11962 // those packages and flush the attribute cache as well.
Suchi Amalapurapub56ae202010-02-04 22:51:07 -080011963 if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080011964 String list[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
11965 if (list != null && (list.length > 0)) {
11966 for (String pkg : list) {
11967 forceStopPackageLocked(pkg, -1, false, true);
11968 }
11969 }
11970 } else {
11971 Uri data = intent.getData();
11972 String ssp;
11973 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11974 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11975 forceStopPackageLocked(ssp,
11976 intent.getIntExtra(Intent.EXTRA_UID, -1), false, true);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011977 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011978 }
11979 }
11980 }
11981 } else {
11982 String msg = "Permission Denial: " + intent.getAction()
11983 + " broadcast from " + callerPackage + " (pid=" + callingPid
11984 + ", uid=" + callingUid + ")"
11985 + " requires "
11986 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11987 Log.w(TAG, msg);
11988 throw new SecurityException(msg);
11989 }
11990 }
11991
11992 /*
11993 * If this is the time zone changed action, queue up a message that will reset the timezone
11994 * of all currently running processes. This message will get queued up before the broadcast
11995 * happens.
11996 */
11997 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11998 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11999 }
12000
Dianne Hackborn854060af2009-07-09 18:14:31 -070012001 /*
12002 * Prevent non-system code (defined here to be non-persistent
12003 * processes) from sending protected broadcasts.
12004 */
12005 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
12006 || callingUid == Process.SHELL_UID || callingUid == 0) {
12007 // Always okay.
12008 } else if (callerApp == null || !callerApp.persistent) {
12009 try {
12010 if (ActivityThread.getPackageManager().isProtectedBroadcast(
12011 intent.getAction())) {
12012 String msg = "Permission Denial: not allowed to send broadcast "
12013 + intent.getAction() + " from pid="
12014 + callingPid + ", uid=" + callingUid;
12015 Log.w(TAG, msg);
12016 throw new SecurityException(msg);
12017 }
12018 } catch (RemoteException e) {
12019 Log.w(TAG, "Remote exception", e);
12020 return BROADCAST_SUCCESS;
12021 }
12022 }
12023
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012024 // Add to the sticky list if requested.
12025 if (sticky) {
12026 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
12027 callingPid, callingUid)
12028 != PackageManager.PERMISSION_GRANTED) {
12029 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
12030 + callingPid + ", uid=" + callingUid
12031 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
12032 Log.w(TAG, msg);
12033 throw new SecurityException(msg);
12034 }
12035 if (requiredPermission != null) {
12036 Log.w(TAG, "Can't broadcast sticky intent " + intent
12037 + " and enforce permission " + requiredPermission);
12038 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
12039 }
12040 if (intent.getComponent() != null) {
12041 throw new SecurityException(
12042 "Sticky broadcasts can't target a specific component");
12043 }
12044 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12045 if (list == null) {
12046 list = new ArrayList<Intent>();
12047 mStickyBroadcasts.put(intent.getAction(), list);
12048 }
12049 int N = list.size();
12050 int i;
12051 for (i=0; i<N; i++) {
12052 if (intent.filterEquals(list.get(i))) {
12053 // This sticky already exists, replace it.
12054 list.set(i, new Intent(intent));
12055 break;
12056 }
12057 }
12058 if (i >= N) {
12059 list.add(new Intent(intent));
12060 }
12061 }
12062
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012063 // Figure out who all will receive this broadcast.
12064 List receivers = null;
12065 List<BroadcastFilter> registeredReceivers = null;
12066 try {
12067 if (intent.getComponent() != null) {
12068 // Broadcast is going to one specific receiver class...
12069 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070012070 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012071 if (ai != null) {
12072 receivers = new ArrayList();
12073 ResolveInfo ri = new ResolveInfo();
12074 ri.activityInfo = ai;
12075 receivers.add(ri);
12076 }
12077 } else {
12078 // Need to resolve the intent to interested receivers...
12079 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
12080 == 0) {
12081 receivers =
12082 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012083 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012084 }
Mihai Preda074edef2009-05-18 17:13:31 +020012085 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012086 }
12087 } catch (RemoteException ex) {
12088 // pm is in same process, this will never happen.
12089 }
12090
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012091 final boolean replacePending =
12092 (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
12093
12094 if (DEBUG_BROADCAST) Log.v(TAG, "Enqueing broadcast: " + intent.getAction()
12095 + " replacePending=" + replacePending);
12096
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012097 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
12098 if (!ordered && NR > 0) {
12099 // If we are not serializing this broadcast, then send the
12100 // registered receivers separately so they don't wait for the
12101 // components to be launched.
12102 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
12103 callerPackage, callingPid, callingUid, requiredPermission,
12104 registeredReceivers, resultTo, resultCode, resultData, map,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012105 ordered, sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012106 if (DEBUG_BROADCAST) Log.v(
12107 TAG, "Enqueueing parallel broadcast " + r
12108 + ": prev had " + mParallelBroadcasts.size());
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012109 boolean replaced = false;
12110 if (replacePending) {
12111 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
12112 if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
12113 if (DEBUG_BROADCAST) Log.v(TAG,
12114 "***** DROPPING PARALLEL: " + intent);
12115 mParallelBroadcasts.set(i, r);
12116 replaced = true;
12117 break;
12118 }
12119 }
12120 }
12121 if (!replaced) {
12122 mParallelBroadcasts.add(r);
12123 scheduleBroadcastsLocked();
12124 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012125 registeredReceivers = null;
12126 NR = 0;
12127 }
12128
12129 // Merge into one list.
12130 int ir = 0;
12131 if (receivers != null) {
12132 // A special case for PACKAGE_ADDED: do not allow the package
12133 // being added to see this broadcast. This prevents them from
12134 // using this as a back door to get run as soon as they are
12135 // installed. Maybe in the future we want to have a special install
12136 // broadcast or such for apps, but we'd like to deliberately make
12137 // this decision.
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080012138 String skipPackages[] = null;
12139 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())
12140 || intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())
12141 || intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
12142 Uri data = intent.getData();
12143 if (data != null) {
12144 String pkgName = data.getSchemeSpecificPart();
12145 if (pkgName != null) {
12146 skipPackages = new String[] { pkgName };
12147 }
12148 }
Suchi Amalapurapub56ae202010-02-04 22:51:07 -080012149 } else if (intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080012150 skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
The Android Open Source Project10592532009-03-18 17:39:46 -070012151 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080012152 if (skipPackages != null && (skipPackages.length > 0)) {
12153 for (String skipPackage : skipPackages) {
12154 if (skipPackage != null) {
12155 int NT = receivers.size();
12156 for (int it=0; it<NT; it++) {
12157 ResolveInfo curt = (ResolveInfo)receivers.get(it);
12158 if (curt.activityInfo.packageName.equals(skipPackage)) {
12159 receivers.remove(it);
12160 it--;
12161 NT--;
12162 }
12163 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012164 }
12165 }
12166 }
12167
12168 int NT = receivers != null ? receivers.size() : 0;
12169 int it = 0;
12170 ResolveInfo curt = null;
12171 BroadcastFilter curr = null;
12172 while (it < NT && ir < NR) {
12173 if (curt == null) {
12174 curt = (ResolveInfo)receivers.get(it);
12175 }
12176 if (curr == null) {
12177 curr = registeredReceivers.get(ir);
12178 }
12179 if (curr.getPriority() >= curt.priority) {
12180 // Insert this broadcast record into the final list.
12181 receivers.add(it, curr);
12182 ir++;
12183 curr = null;
12184 it++;
12185 NT++;
12186 } else {
12187 // Skip to the next ResolveInfo in the final list.
12188 it++;
12189 curt = null;
12190 }
12191 }
12192 }
12193 while (ir < NR) {
12194 if (receivers == null) {
12195 receivers = new ArrayList();
12196 }
12197 receivers.add(registeredReceivers.get(ir));
12198 ir++;
12199 }
12200
12201 if ((receivers != null && receivers.size() > 0)
12202 || resultTo != null) {
12203 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
12204 callerPackage, callingPid, callingUid, requiredPermission,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012205 receivers, resultTo, resultCode, resultData, map, ordered,
12206 sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012207 if (DEBUG_BROADCAST) Log.v(
12208 TAG, "Enqueueing ordered broadcast " + r
12209 + ": prev had " + mOrderedBroadcasts.size());
12210 if (DEBUG_BROADCAST) {
12211 int seq = r.intent.getIntExtra("seq", -1);
12212 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
12213 }
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012214 boolean replaced = false;
12215 if (replacePending) {
12216 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
12217 if (intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
12218 if (DEBUG_BROADCAST) Log.v(TAG,
12219 "***** DROPPING ORDERED: " + intent);
12220 mOrderedBroadcasts.set(i, r);
12221 replaced = true;
12222 break;
12223 }
12224 }
12225 }
12226 if (!replaced) {
12227 mOrderedBroadcasts.add(r);
12228 scheduleBroadcastsLocked();
12229 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012230 }
12231
12232 return BROADCAST_SUCCESS;
12233 }
12234
12235 public final int broadcastIntent(IApplicationThread caller,
12236 Intent intent, String resolvedType, IIntentReceiver resultTo,
12237 int resultCode, String resultData, Bundle map,
12238 String requiredPermission, boolean serialized, boolean sticky) {
12239 // Refuse possible leaked file descriptors
12240 if (intent != null && intent.hasFileDescriptors() == true) {
12241 throw new IllegalArgumentException("File descriptors passed in Intent");
12242 }
12243
12244 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012245 int flags = intent.getFlags();
12246
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012247 if (!mSystemReady) {
12248 // if the caller really truly claims to know what they're doing, go
12249 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012250 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
12251 intent = new Intent(intent);
12252 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
12253 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
12254 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
12255 + " before boot completion");
12256 throw new IllegalStateException("Cannot broadcast before boot completed");
12257 }
12258 }
12259
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012260 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
12261 throw new IllegalArgumentException(
12262 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
12263 }
12264
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012265 final ProcessRecord callerApp = getRecordForAppLocked(caller);
12266 final int callingPid = Binder.getCallingPid();
12267 final int callingUid = Binder.getCallingUid();
12268 final long origId = Binder.clearCallingIdentity();
12269 int res = broadcastIntentLocked(callerApp,
12270 callerApp != null ? callerApp.info.packageName : null,
12271 intent, resolvedType, resultTo,
12272 resultCode, resultData, map, requiredPermission, serialized,
12273 sticky, callingPid, callingUid);
12274 Binder.restoreCallingIdentity(origId);
12275 return res;
12276 }
12277 }
12278
12279 int broadcastIntentInPackage(String packageName, int uid,
12280 Intent intent, String resolvedType, IIntentReceiver resultTo,
12281 int resultCode, String resultData, Bundle map,
12282 String requiredPermission, boolean serialized, boolean sticky) {
12283 synchronized(this) {
12284 final long origId = Binder.clearCallingIdentity();
12285 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
12286 resultTo, resultCode, resultData, map, requiredPermission,
12287 serialized, sticky, -1, uid);
12288 Binder.restoreCallingIdentity(origId);
12289 return res;
12290 }
12291 }
12292
12293 public final void unbroadcastIntent(IApplicationThread caller,
12294 Intent intent) {
12295 // Refuse possible leaked file descriptors
12296 if (intent != null && intent.hasFileDescriptors() == true) {
12297 throw new IllegalArgumentException("File descriptors passed in Intent");
12298 }
12299
12300 synchronized(this) {
12301 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
12302 != PackageManager.PERMISSION_GRANTED) {
12303 String msg = "Permission Denial: unbroadcastIntent() from pid="
12304 + Binder.getCallingPid()
12305 + ", uid=" + Binder.getCallingUid()
12306 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
12307 Log.w(TAG, msg);
12308 throw new SecurityException(msg);
12309 }
12310 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12311 if (list != null) {
12312 int N = list.size();
12313 int i;
12314 for (i=0; i<N; i++) {
12315 if (intent.filterEquals(list.get(i))) {
12316 list.remove(i);
12317 break;
12318 }
12319 }
12320 }
12321 }
12322 }
12323
12324 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
12325 String resultData, Bundle resultExtras, boolean resultAbort,
12326 boolean explicit) {
12327 if (mOrderedBroadcasts.size() == 0) {
12328 if (explicit) {
12329 Log.w(TAG, "finishReceiver called but no pending broadcasts");
12330 }
12331 return false;
12332 }
12333 BroadcastRecord r = mOrderedBroadcasts.get(0);
12334 if (r.receiver == null) {
12335 if (explicit) {
12336 Log.w(TAG, "finishReceiver called but none active");
12337 }
12338 return false;
12339 }
12340 if (r.receiver != receiver) {
12341 Log.w(TAG, "finishReceiver called but active receiver is different");
12342 return false;
12343 }
12344 int state = r.state;
12345 r.state = r.IDLE;
12346 if (state == r.IDLE) {
12347 if (explicit) {
12348 Log.w(TAG, "finishReceiver called but state is IDLE");
12349 }
12350 }
12351 r.receiver = null;
12352 r.intent.setComponent(null);
12353 if (r.curApp != null) {
12354 r.curApp.curReceiver = null;
12355 }
12356 if (r.curFilter != null) {
12357 r.curFilter.receiverList.curBroadcast = null;
12358 }
12359 r.curFilter = null;
12360 r.curApp = null;
12361 r.curComponent = null;
12362 r.curReceiver = null;
12363 mPendingBroadcast = null;
12364
12365 r.resultCode = resultCode;
12366 r.resultData = resultData;
12367 r.resultExtras = resultExtras;
12368 r.resultAbort = resultAbort;
12369
12370 // We will process the next receiver right now if this is finishing
12371 // an app receiver (which is always asynchronous) or after we have
12372 // come back from calling a receiver.
12373 return state == BroadcastRecord.APP_RECEIVE
12374 || state == BroadcastRecord.CALL_DONE_RECEIVE;
12375 }
12376
12377 public void finishReceiver(IBinder who, int resultCode, String resultData,
12378 Bundle resultExtras, boolean resultAbort) {
12379 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
12380
12381 // Refuse possible leaked file descriptors
12382 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
12383 throw new IllegalArgumentException("File descriptors passed in Bundle");
12384 }
12385
12386 boolean doNext;
12387
12388 final long origId = Binder.clearCallingIdentity();
12389
12390 synchronized(this) {
12391 doNext = finishReceiverLocked(
12392 who, resultCode, resultData, resultExtras, resultAbort, true);
12393 }
12394
12395 if (doNext) {
12396 processNextBroadcast(false);
12397 }
12398 trimApplications();
12399
12400 Binder.restoreCallingIdentity(origId);
12401 }
12402
12403 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
12404 if (r.nextReceiver > 0) {
12405 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12406 if (curReceiver instanceof BroadcastFilter) {
12407 BroadcastFilter bf = (BroadcastFilter) curReceiver;
Doug Zongker2bec3d42009-12-04 12:52:44 -080012408 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012409 System.identityHashCode(r),
12410 r.intent.getAction(),
12411 r.nextReceiver - 1,
12412 System.identityHashCode(bf));
12413 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -080012414 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012415 System.identityHashCode(r),
12416 r.intent.getAction(),
12417 r.nextReceiver - 1,
12418 ((ResolveInfo)curReceiver).toString());
12419 }
12420 } else {
12421 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
12422 + r);
Doug Zongker2bec3d42009-12-04 12:52:44 -080012423 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012424 System.identityHashCode(r),
12425 r.intent.getAction(),
12426 r.nextReceiver,
12427 "NONE");
12428 }
12429 }
12430
12431 private final void broadcastTimeout() {
12432 synchronized (this) {
12433 if (mOrderedBroadcasts.size() == 0) {
12434 return;
12435 }
12436 long now = SystemClock.uptimeMillis();
12437 BroadcastRecord r = mOrderedBroadcasts.get(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012438 if ((r.receiverTime+BROADCAST_TIMEOUT) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012439 if (DEBUG_BROADCAST) Log.v(TAG,
12440 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012441 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012442 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012443 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012444 return;
12445 }
12446
12447 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012448 r.receiverTime = now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012449 r.anrCount++;
12450
12451 // Current receiver has passed its expiration date.
12452 if (r.nextReceiver <= 0) {
12453 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12454 return;
12455 }
12456
12457 ProcessRecord app = null;
12458
12459 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12460 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12461 logBroadcastReceiverDiscard(r);
12462 if (curReceiver instanceof BroadcastFilter) {
12463 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12464 if (bf.receiverList.pid != 0
12465 && bf.receiverList.pid != MY_PID) {
12466 synchronized (this.mPidsSelfLocked) {
12467 app = this.mPidsSelfLocked.get(
12468 bf.receiverList.pid);
12469 }
12470 }
12471 } else {
12472 app = r.curApp;
12473 }
12474
12475 if (app != null) {
Dan Egnorb7f03672009-12-09 16:22:32 -080012476 appNotRespondingLocked(app, null, null, "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012477 }
12478
12479 if (mPendingBroadcast == r) {
12480 mPendingBroadcast = null;
12481 }
12482
12483 // Move on to the next receiver.
12484 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12485 r.resultExtras, r.resultAbort, true);
12486 scheduleBroadcastsLocked();
12487 }
12488 }
12489
12490 private final void processCurBroadcastLocked(BroadcastRecord r,
12491 ProcessRecord app) throws RemoteException {
12492 if (app.thread == null) {
12493 throw new RemoteException();
12494 }
12495 r.receiver = app.thread.asBinder();
12496 r.curApp = app;
12497 app.curReceiver = r;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080012498 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012499
12500 // Tell the application to launch this receiver.
12501 r.intent.setComponent(r.curComponent);
12502
12503 boolean started = false;
12504 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012505 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012506 "Delivering to component " + r.curComponent
12507 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012508 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012509 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12510 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12511 started = true;
12512 } finally {
12513 if (!started) {
12514 r.receiver = null;
12515 r.curApp = null;
12516 app.curReceiver = null;
12517 }
12518 }
12519
12520 }
12521
12522 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012523 Intent intent, int resultCode, String data, Bundle extras,
12524 boolean ordered, boolean sticky) throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012525 if (app != null && app.thread != null) {
12526 // If we have an app thread, do the call through that so it is
12527 // correctly ordered with other one-way calls.
12528 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012529 data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012530 } else {
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012531 receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012532 }
12533 }
12534
12535 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12536 BroadcastFilter filter, boolean ordered) {
12537 boolean skip = false;
12538 if (filter.requiredPermission != null) {
12539 int perm = checkComponentPermission(filter.requiredPermission,
12540 r.callingPid, r.callingUid, -1);
12541 if (perm != PackageManager.PERMISSION_GRANTED) {
12542 Log.w(TAG, "Permission Denial: broadcasting "
12543 + r.intent.toString()
12544 + " from " + r.callerPackage + " (pid="
12545 + r.callingPid + ", uid=" + r.callingUid + ")"
12546 + " requires " + filter.requiredPermission
12547 + " due to registered receiver " + filter);
12548 skip = true;
12549 }
12550 }
12551 if (r.requiredPermission != null) {
12552 int perm = checkComponentPermission(r.requiredPermission,
12553 filter.receiverList.pid, filter.receiverList.uid, -1);
12554 if (perm != PackageManager.PERMISSION_GRANTED) {
12555 Log.w(TAG, "Permission Denial: receiving "
12556 + r.intent.toString()
12557 + " to " + filter.receiverList.app
12558 + " (pid=" + filter.receiverList.pid
12559 + ", uid=" + filter.receiverList.uid + ")"
12560 + " requires " + r.requiredPermission
12561 + " due to sender " + r.callerPackage
12562 + " (uid " + r.callingUid + ")");
12563 skip = true;
12564 }
12565 }
12566
12567 if (!skip) {
12568 // If this is not being sent as an ordered broadcast, then we
12569 // don't want to touch the fields that keep track of the current
12570 // state of ordered broadcasts.
12571 if (ordered) {
12572 r.receiver = filter.receiverList.receiver.asBinder();
12573 r.curFilter = filter;
12574 filter.receiverList.curBroadcast = r;
12575 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012576 if (filter.receiverList.app != null) {
12577 // Bump hosting application to no longer be in background
12578 // scheduling class. Note that we can't do that if there
12579 // isn't an app... but we can only be in that case for
12580 // things that directly call the IActivityManager API, which
12581 // are already core system stuff so don't matter for this.
12582 r.curApp = filter.receiverList.app;
12583 filter.receiverList.app.curReceiver = r;
12584 updateOomAdjLocked();
12585 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012586 }
12587 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012588 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012589 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012590 Log.i(TAG, "Delivering to " + filter.receiverList.app
12591 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012592 }
12593 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12594 new Intent(r.intent), r.resultCode,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012595 r.resultData, r.resultExtras, r.ordered, r.initialSticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012596 if (ordered) {
12597 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12598 }
12599 } catch (RemoteException e) {
12600 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12601 if (ordered) {
12602 r.receiver = null;
12603 r.curFilter = null;
12604 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012605 if (filter.receiverList.app != null) {
12606 filter.receiverList.app.curReceiver = null;
12607 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012608 }
12609 }
12610 }
12611 }
12612
Dianne Hackborn12527f92009-11-11 17:39:50 -080012613 private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
12614 if (r.callingUid < 0) {
12615 // This was from a registerReceiver() call; ignore it.
12616 return;
12617 }
12618 System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
12619 MAX_BROADCAST_HISTORY-1);
12620 r.finishTime = SystemClock.uptimeMillis();
12621 mBroadcastHistory[0] = r;
12622 }
12623
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012624 private final void processNextBroadcast(boolean fromMsg) {
12625 synchronized(this) {
12626 BroadcastRecord r;
12627
12628 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12629 + mParallelBroadcasts.size() + " broadcasts, "
12630 + mOrderedBroadcasts.size() + " serialized broadcasts");
12631
12632 updateCpuStats();
12633
12634 if (fromMsg) {
12635 mBroadcastsScheduled = false;
12636 }
12637
12638 // First, deliver any non-serialized broadcasts right away.
12639 while (mParallelBroadcasts.size() > 0) {
12640 r = mParallelBroadcasts.remove(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012641 r.dispatchTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012642 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012643 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12644 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012645 for (int i=0; i<N; i++) {
12646 Object target = r.receivers.get(i);
12647 if (DEBUG_BROADCAST) Log.v(TAG,
12648 "Delivering non-serialized to registered "
12649 + target + ": " + r);
12650 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12651 }
Dianne Hackborn12527f92009-11-11 17:39:50 -080012652 addBroadcastToHistoryLocked(r);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012653 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12654 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012655 }
12656
12657 // Now take care of the next serialized one...
12658
12659 // If we are waiting for a process to come up to handle the next
12660 // broadcast, then do nothing at this point. Just in case, we
12661 // check that the process we're waiting for still exists.
12662 if (mPendingBroadcast != null) {
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -070012663 if (DEBUG_BROADCAST_LIGHT) {
12664 Log.v(TAG, "processNextBroadcast: waiting for "
12665 + mPendingBroadcast.curApp);
12666 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012667
12668 boolean isDead;
12669 synchronized (mPidsSelfLocked) {
12670 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12671 }
12672 if (!isDead) {
12673 // It's still alive, so keep waiting
12674 return;
12675 } else {
12676 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12677 + " died before responding to broadcast");
12678 mPendingBroadcast = null;
12679 }
12680 }
12681
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012682 boolean looped = false;
12683
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012684 do {
12685 if (mOrderedBroadcasts.size() == 0) {
12686 // No more broadcasts pending, so all done!
12687 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012688 if (looped) {
12689 // If we had finished the last ordered broadcast, then
12690 // make sure all processes have correct oom and sched
12691 // adjustments.
12692 updateOomAdjLocked();
12693 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012694 return;
12695 }
12696 r = mOrderedBroadcasts.get(0);
12697 boolean forceReceive = false;
12698
12699 // Ensure that even if something goes awry with the timeout
12700 // detection, we catch "hung" broadcasts here, discard them,
12701 // and continue to make progress.
12702 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12703 long now = SystemClock.uptimeMillis();
12704 if (r.dispatchTime > 0) {
12705 if ((numReceivers > 0) &&
12706 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12707 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12708 + " now=" + now
12709 + " dispatchTime=" + r.dispatchTime
Dianne Hackborn12527f92009-11-11 17:39:50 -080012710 + " startTime=" + r.receiverTime
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012711 + " intent=" + r.intent
12712 + " numReceivers=" + numReceivers
12713 + " nextReceiver=" + r.nextReceiver
12714 + " state=" + r.state);
12715 broadcastTimeout(); // forcibly finish this broadcast
12716 forceReceive = true;
12717 r.state = BroadcastRecord.IDLE;
12718 }
12719 }
12720
12721 if (r.state != BroadcastRecord.IDLE) {
12722 if (DEBUG_BROADCAST) Log.d(TAG,
12723 "processNextBroadcast() called when not idle (state="
12724 + r.state + ")");
12725 return;
12726 }
12727
12728 if (r.receivers == null || r.nextReceiver >= numReceivers
12729 || r.resultAbort || forceReceive) {
12730 // No more receivers for this broadcast! Send the final
12731 // result if requested...
12732 if (r.resultTo != null) {
12733 try {
12734 if (DEBUG_BROADCAST) {
12735 int seq = r.intent.getIntExtra("seq", -1);
12736 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12737 + " seq=" + seq + " app=" + r.callerApp);
12738 }
12739 performReceive(r.callerApp, r.resultTo,
12740 new Intent(r.intent), r.resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012741 r.resultData, r.resultExtras, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012742 } catch (RemoteException e) {
12743 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12744 }
12745 }
12746
12747 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12748 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12749
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012750 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12751 + r);
12752
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012753 // ... and on to the next...
Dianne Hackborn12527f92009-11-11 17:39:50 -080012754 addBroadcastToHistoryLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012755 mOrderedBroadcasts.remove(0);
12756 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012757 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012758 continue;
12759 }
12760 } while (r == null);
12761
12762 // Get the next receiver...
12763 int recIdx = r.nextReceiver++;
12764
12765 // Keep track of when this receiver started, and make sure there
12766 // is a timeout message pending to kill it if need be.
Dianne Hackborn12527f92009-11-11 17:39:50 -080012767 r.receiverTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012768 if (recIdx == 0) {
Dianne Hackborn12527f92009-11-11 17:39:50 -080012769 r.dispatchTime = r.receiverTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012770
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012771 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12772 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012773 if (DEBUG_BROADCAST) Log.v(TAG,
12774 "Submitting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012775 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012776 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012777 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012778 }
12779
12780 Object nextReceiver = r.receivers.get(recIdx);
12781 if (nextReceiver instanceof BroadcastFilter) {
12782 // Simple case: this is a registered receiver who gets
12783 // a direct call.
12784 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12785 if (DEBUG_BROADCAST) Log.v(TAG,
12786 "Delivering serialized to registered "
12787 + filter + ": " + r);
12788 deliverToRegisteredReceiver(r, filter, r.ordered);
12789 if (r.receiver == null || !r.ordered) {
12790 // The receiver has already finished, so schedule to
12791 // process the next one.
12792 r.state = BroadcastRecord.IDLE;
12793 scheduleBroadcastsLocked();
12794 }
12795 return;
12796 }
12797
12798 // Hard case: need to instantiate the receiver, possibly
12799 // starting its application process to host it.
12800
12801 ResolveInfo info =
12802 (ResolveInfo)nextReceiver;
12803
12804 boolean skip = false;
12805 int perm = checkComponentPermission(info.activityInfo.permission,
12806 r.callingPid, r.callingUid,
12807 info.activityInfo.exported
12808 ? -1 : info.activityInfo.applicationInfo.uid);
12809 if (perm != PackageManager.PERMISSION_GRANTED) {
12810 Log.w(TAG, "Permission Denial: broadcasting "
12811 + r.intent.toString()
12812 + " from " + r.callerPackage + " (pid=" + r.callingPid
12813 + ", uid=" + r.callingUid + ")"
12814 + " requires " + info.activityInfo.permission
12815 + " due to receiver " + info.activityInfo.packageName
12816 + "/" + info.activityInfo.name);
12817 skip = true;
12818 }
12819 if (r.callingUid != Process.SYSTEM_UID &&
12820 r.requiredPermission != null) {
12821 try {
12822 perm = ActivityThread.getPackageManager().
12823 checkPermission(r.requiredPermission,
12824 info.activityInfo.applicationInfo.packageName);
12825 } catch (RemoteException e) {
12826 perm = PackageManager.PERMISSION_DENIED;
12827 }
12828 if (perm != PackageManager.PERMISSION_GRANTED) {
12829 Log.w(TAG, "Permission Denial: receiving "
12830 + r.intent + " to "
12831 + info.activityInfo.applicationInfo.packageName
12832 + " requires " + r.requiredPermission
12833 + " due to sender " + r.callerPackage
12834 + " (uid " + r.callingUid + ")");
12835 skip = true;
12836 }
12837 }
12838 if (r.curApp != null && r.curApp.crashing) {
12839 // If the target process is crashing, just skip it.
12840 skip = true;
12841 }
12842
12843 if (skip) {
12844 r.receiver = null;
12845 r.curFilter = null;
12846 r.state = BroadcastRecord.IDLE;
12847 scheduleBroadcastsLocked();
12848 return;
12849 }
12850
12851 r.state = BroadcastRecord.APP_RECEIVE;
12852 String targetProcess = info.activityInfo.processName;
12853 r.curComponent = new ComponentName(
12854 info.activityInfo.applicationInfo.packageName,
12855 info.activityInfo.name);
12856 r.curReceiver = info.activityInfo;
12857
12858 // Is this receiver's application already running?
12859 ProcessRecord app = getProcessRecordLocked(targetProcess,
12860 info.activityInfo.applicationInfo.uid);
12861 if (app != null && app.thread != null) {
12862 try {
12863 processCurBroadcastLocked(r, app);
12864 return;
12865 } catch (RemoteException e) {
12866 Log.w(TAG, "Exception when sending broadcast to "
12867 + r.curComponent, e);
12868 }
12869
12870 // If a dead object exception was thrown -- fall through to
12871 // restart the application.
12872 }
12873
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012874 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012875 if ((r.curApp=startProcessLocked(targetProcess,
12876 info.activityInfo.applicationInfo, true,
12877 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012878 "broadcast", r.curComponent,
12879 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12880 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012881 // Ah, this recipient is unavailable. Finish it if necessary,
12882 // and mark the broadcast record as ready for the next.
12883 Log.w(TAG, "Unable to launch app "
12884 + info.activityInfo.applicationInfo.packageName + "/"
12885 + info.activityInfo.applicationInfo.uid + " for broadcast "
12886 + r.intent + ": process is bad");
12887 logBroadcastReceiverDiscard(r);
12888 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12889 r.resultExtras, r.resultAbort, true);
12890 scheduleBroadcastsLocked();
12891 r.state = BroadcastRecord.IDLE;
12892 return;
12893 }
12894
12895 mPendingBroadcast = r;
12896 }
12897 }
12898
12899 // =========================================================
12900 // INSTRUMENTATION
12901 // =========================================================
12902
12903 public boolean startInstrumentation(ComponentName className,
12904 String profileFile, int flags, Bundle arguments,
12905 IInstrumentationWatcher watcher) {
12906 // Refuse possible leaked file descriptors
12907 if (arguments != null && arguments.hasFileDescriptors()) {
12908 throw new IllegalArgumentException("File descriptors passed in Bundle");
12909 }
12910
12911 synchronized(this) {
12912 InstrumentationInfo ii = null;
12913 ApplicationInfo ai = null;
12914 try {
12915 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012916 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012917 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012918 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012919 } catch (PackageManager.NameNotFoundException e) {
12920 }
12921 if (ii == null) {
12922 reportStartInstrumentationFailure(watcher, className,
12923 "Unable to find instrumentation info for: " + className);
12924 return false;
12925 }
12926 if (ai == null) {
12927 reportStartInstrumentationFailure(watcher, className,
12928 "Unable to find instrumentation target package: " + ii.targetPackage);
12929 return false;
12930 }
12931
12932 int match = mContext.getPackageManager().checkSignatures(
12933 ii.targetPackage, ii.packageName);
12934 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12935 String msg = "Permission Denial: starting instrumentation "
12936 + className + " from pid="
12937 + Binder.getCallingPid()
12938 + ", uid=" + Binder.getCallingPid()
12939 + " not allowed because package " + ii.packageName
12940 + " does not have a signature matching the target "
12941 + ii.targetPackage;
12942 reportStartInstrumentationFailure(watcher, className, msg);
12943 throw new SecurityException(msg);
12944 }
12945
12946 final long origId = Binder.clearCallingIdentity();
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080012947 forceStopPackageLocked(ii.targetPackage, -1, true, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012948 ProcessRecord app = addAppLocked(ai);
12949 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012950 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012951 app.instrumentationProfileFile = profileFile;
12952 app.instrumentationArguments = arguments;
12953 app.instrumentationWatcher = watcher;
12954 app.instrumentationResultClass = className;
12955 Binder.restoreCallingIdentity(origId);
12956 }
12957
12958 return true;
12959 }
12960
12961 /**
12962 * Report errors that occur while attempting to start Instrumentation. Always writes the
12963 * error to the logs, but if somebody is watching, send the report there too. This enables
12964 * the "am" command to report errors with more information.
12965 *
12966 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12967 * @param cn The component name of the instrumentation.
12968 * @param report The error report.
12969 */
12970 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12971 ComponentName cn, String report) {
12972 Log.w(TAG, report);
12973 try {
12974 if (watcher != null) {
12975 Bundle results = new Bundle();
12976 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12977 results.putString("Error", report);
12978 watcher.instrumentationStatus(cn, -1, results);
12979 }
12980 } catch (RemoteException e) {
12981 Log.w(TAG, e);
12982 }
12983 }
12984
12985 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12986 if (app.instrumentationWatcher != null) {
12987 try {
12988 // NOTE: IInstrumentationWatcher *must* be oneway here
12989 app.instrumentationWatcher.instrumentationFinished(
12990 app.instrumentationClass,
12991 resultCode,
12992 results);
12993 } catch (RemoteException e) {
12994 }
12995 }
12996 app.instrumentationWatcher = null;
12997 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012998 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012999 app.instrumentationProfileFile = null;
13000 app.instrumentationArguments = null;
13001
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080013002 forceStopPackageLocked(app.processName, -1, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013003 }
13004
13005 public void finishInstrumentation(IApplicationThread target,
13006 int resultCode, Bundle results) {
13007 // Refuse possible leaked file descriptors
13008 if (results != null && results.hasFileDescriptors()) {
13009 throw new IllegalArgumentException("File descriptors passed in Intent");
13010 }
13011
13012 synchronized(this) {
13013 ProcessRecord app = getRecordForAppLocked(target);
13014 if (app == null) {
13015 Log.w(TAG, "finishInstrumentation: no app for " + target);
13016 return;
13017 }
13018 final long origId = Binder.clearCallingIdentity();
13019 finishInstrumentationLocked(app, resultCode, results);
13020 Binder.restoreCallingIdentity(origId);
13021 }
13022 }
13023
13024 // =========================================================
13025 // CONFIGURATION
13026 // =========================================================
13027
13028 public ConfigurationInfo getDeviceConfigurationInfo() {
13029 ConfigurationInfo config = new ConfigurationInfo();
13030 synchronized (this) {
13031 config.reqTouchScreen = mConfiguration.touchscreen;
13032 config.reqKeyboardType = mConfiguration.keyboard;
13033 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070013034 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
13035 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013036 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
13037 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070013038 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
13039 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013040 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
13041 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070013042 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013043 }
13044 return config;
13045 }
13046
13047 public Configuration getConfiguration() {
13048 Configuration ci;
13049 synchronized(this) {
13050 ci = new Configuration(mConfiguration);
13051 }
13052 return ci;
13053 }
13054
13055 public void updateConfiguration(Configuration values) {
13056 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
13057 "updateConfiguration()");
13058
13059 synchronized(this) {
13060 if (values == null && mWindowManager != null) {
13061 // sentinel: fetch the current configuration from the window manager
13062 values = mWindowManager.computeNewConfiguration();
13063 }
13064
13065 final long origId = Binder.clearCallingIdentity();
13066 updateConfigurationLocked(values, null);
13067 Binder.restoreCallingIdentity(origId);
13068 }
13069 }
13070
13071 /**
13072 * Do either or both things: (1) change the current configuration, and (2)
13073 * make sure the given activity is running with the (now) current
13074 * configuration. Returns true if the activity has been left running, or
13075 * false if <var>starting</var> is being destroyed to match the new
13076 * configuration.
13077 */
13078 public boolean updateConfigurationLocked(Configuration values,
13079 HistoryRecord starting) {
13080 int changes = 0;
13081
13082 boolean kept = true;
13083
13084 if (values != null) {
13085 Configuration newConfig = new Configuration(mConfiguration);
13086 changes = newConfig.updateFrom(values);
13087 if (changes != 0) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013088 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013089 Log.i(TAG, "Updating configuration to: " + values);
13090 }
13091
Doug Zongker2bec3d42009-12-04 12:52:44 -080013092 EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013093
13094 if (values.locale != null) {
13095 saveLocaleLocked(values.locale,
13096 !values.locale.equals(mConfiguration.locale),
13097 values.userSetLocale);
13098 }
13099
13100 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070013101 Log.i(TAG, "Config changed: " + newConfig);
Dianne Hackborn826d17c2009-11-12 12:55:51 -080013102
13103 AttributeCache ac = AttributeCache.instance();
13104 if (ac != null) {
13105 ac.updateConfiguration(mConfiguration);
13106 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013107
13108 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
13109 msg.obj = new Configuration(mConfiguration);
13110 mHandler.sendMessage(msg);
13111
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013112 for (int i=mLruProcesses.size()-1; i>=0; i--) {
13113 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013114 try {
13115 if (app.thread != null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013116 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending to proc "
13117 + app.processName + " new config " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013118 app.thread.scheduleConfigurationChanged(mConfiguration);
13119 }
13120 } catch (Exception e) {
13121 }
13122 }
13123 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080013124 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
13125 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013126 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
13127 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackborn362d5b92009-11-11 18:04:39 -080013128 if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
13129 broadcastIntentLocked(null, null,
13130 new Intent(Intent.ACTION_LOCALE_CHANGED),
13131 null, null, 0, null, null,
13132 null, false, false, MY_PID, Process.SYSTEM_UID);
13133 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013134 }
13135 }
13136
13137 if (changes != 0 && starting == null) {
13138 // If the configuration changed, and the caller is not already
13139 // in the process of starting an activity, then find the top
13140 // activity to check if its configuration needs to change.
13141 starting = topRunningActivityLocked(null);
13142 }
13143
13144 if (starting != null) {
13145 kept = ensureActivityConfigurationLocked(starting, changes);
13146 if (kept) {
13147 // If this didn't result in the starting activity being
13148 // destroyed, then we need to make sure at this point that all
13149 // other activities are made visible.
13150 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
13151 + ", ensuring others are correct.");
13152 ensureActivitiesVisibleLocked(starting, changes);
13153 }
13154 }
13155
13156 return kept;
13157 }
13158
13159 private final boolean relaunchActivityLocked(HistoryRecord r,
13160 int changes, boolean andResume) {
13161 List<ResultInfo> results = null;
13162 List<Intent> newIntents = null;
13163 if (andResume) {
13164 results = r.results;
13165 newIntents = r.newIntents;
13166 }
13167 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
13168 + " with results=" + results + " newIntents=" + newIntents
13169 + " andResume=" + andResume);
Doug Zongker2bec3d42009-12-04 12:52:44 -080013170 EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
13171 : EventLogTags.AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013172 r.task.taskId, r.shortComponentName);
13173
13174 r.startFreezingScreenLocked(r.app, 0);
13175
13176 try {
13177 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
13178 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
Dianne Hackborn871ecdc2009-12-11 15:24:33 -080013179 changes, !andResume, mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013180 // Note: don't need to call pauseIfSleepingLocked() here, because
13181 // the caller will only pass in 'andResume' if this activity is
13182 // currently resumed, which implies we aren't sleeping.
13183 } catch (RemoteException e) {
13184 return false;
13185 }
13186
13187 if (andResume) {
13188 r.results = null;
13189 r.newIntents = null;
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -070013190 reportResumedActivityLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013191 }
13192
13193 return true;
13194 }
13195
13196 /**
13197 * Make sure the given activity matches the current configuration. Returns
13198 * false if the activity had to be destroyed. Returns true if the
13199 * configuration is the same, or the activity will remain running as-is
13200 * for whatever reason. Ensures the HistoryRecord is updated with the
13201 * correct configuration and all other bookkeeping is handled.
13202 */
13203 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
13204 int globalChanges) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013205 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13206 "Ensuring correct configuration: " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013207
13208 // Short circuit: if the two configurations are the exact same
13209 // object (the common case), then there is nothing to do.
13210 Configuration newConfig = mConfiguration;
13211 if (r.configuration == newConfig) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013212 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13213 "Configuration unchanged in " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013214 return true;
13215 }
13216
13217 // We don't worry about activities that are finishing.
13218 if (r.finishing) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013219 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013220 "Configuration doesn't matter in finishing " + r);
13221 r.stopFreezingScreenLocked(false);
13222 return true;
13223 }
13224
13225 // Okay we now are going to make this activity have the new config.
13226 // But then we need to figure out how it needs to deal with that.
13227 Configuration oldConfig = r.configuration;
13228 r.configuration = newConfig;
13229
13230 // If the activity isn't currently running, just leave the new
13231 // configuration and it will pick that up next time it starts.
13232 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013233 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013234 "Configuration doesn't matter not running " + r);
13235 r.stopFreezingScreenLocked(false);
13236 return true;
13237 }
13238
13239 // If the activity isn't persistent, there is a chance we will
13240 // need to restart it.
13241 if (!r.persistent) {
13242
13243 // Figure out what has changed between the two configurations.
13244 int changes = oldConfig.diff(newConfig);
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013245 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
13246 Log.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013247 + Integer.toHexString(changes) + ", handles=0x"
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013248 + Integer.toHexString(r.info.configChanges)
13249 + ", newConfig=" + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013250 }
13251 if ((changes&(~r.info.configChanges)) != 0) {
13252 // Aha, the activity isn't handling the change, so DIE DIE DIE.
13253 r.configChangeFlags |= changes;
13254 r.startFreezingScreenLocked(r.app, globalChanges);
13255 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013256 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13257 "Switch is destroying non-running " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013258 destroyActivityLocked(r, true);
13259 } else if (r.state == ActivityState.PAUSING) {
13260 // A little annoying: we are waiting for this activity to
13261 // finish pausing. Let's not do anything now, but just
13262 // flag that it needs to be restarted when done pausing.
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013263 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13264 "Switch is skipping already pausing " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013265 r.configDestroy = true;
13266 return true;
13267 } else if (r.state == ActivityState.RESUMED) {
13268 // Try to optimize this case: the configuration is changing
13269 // and we need to restart the top, resumed activity.
13270 // Instead of doing the normal handshaking, just say
13271 // "restart!".
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013272 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13273 "Switch is restarting resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013274 relaunchActivityLocked(r, r.configChangeFlags, true);
13275 r.configChangeFlags = 0;
13276 } else {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013277 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13278 "Switch is restarting non-resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013279 relaunchActivityLocked(r, r.configChangeFlags, false);
13280 r.configChangeFlags = 0;
13281 }
13282
13283 // All done... tell the caller we weren't able to keep this
13284 // activity around.
13285 return false;
13286 }
13287 }
13288
13289 // Default case: the activity can handle this new configuration, so
13290 // hand it over. Note that we don't need to give it the new
13291 // configuration, since we always send configuration changes to all
13292 // process when they happen so it can just use whatever configuration
13293 // it last got.
13294 if (r.app != null && r.app.thread != null) {
13295 try {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013296 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending new config to " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013297 r.app.thread.scheduleActivityConfigurationChanged(r);
13298 } catch (RemoteException e) {
13299 // If process died, whatever.
13300 }
13301 }
13302 r.stopFreezingScreenLocked(false);
13303
13304 return true;
13305 }
13306
13307 /**
13308 * Save the locale. You must be inside a synchronized (this) block.
13309 */
13310 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
13311 if(isDiff) {
13312 SystemProperties.set("user.language", l.getLanguage());
13313 SystemProperties.set("user.region", l.getCountry());
13314 }
13315
13316 if(isPersist) {
13317 SystemProperties.set("persist.sys.language", l.getLanguage());
13318 SystemProperties.set("persist.sys.country", l.getCountry());
13319 SystemProperties.set("persist.sys.localevar", l.getVariant());
13320 }
13321 }
13322
13323 // =========================================================
13324 // LIFETIME MANAGEMENT
13325 // =========================================================
13326
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013327 private final int computeOomAdjLocked(ProcessRecord app, int hiddenAdj,
13328 ProcessRecord TOP_APP, boolean recursed) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013329 if (mAdjSeq == app.adjSeq) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013330 // This adjustment has already been computed. If we are calling
13331 // from the top, we may have already computed our adjustment with
13332 // an earlier hidden adjustment that isn't really for us... if
13333 // so, use the new hidden adjustment.
13334 if (!recursed && app.hidden) {
13335 app.curAdj = hiddenAdj;
13336 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013337 return app.curAdj;
13338 }
13339
13340 if (app.thread == null) {
13341 app.adjSeq = mAdjSeq;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013342 app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013343 return (app.curAdj=EMPTY_APP_ADJ);
13344 }
13345
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013346 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
13347 // The max adjustment doesn't allow this app to be anything
13348 // below foreground, so it is not worth doing work for it.
13349 app.adjType = "fixed";
13350 app.adjSeq = mAdjSeq;
13351 app.curRawAdj = app.maxAdj;
13352 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
13353 return (app.curAdj=app.maxAdj);
13354 }
13355
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013356 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013357 app.adjSource = null;
13358 app.adjTarget = null;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013359 app.empty = false;
13360 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013361
The Android Open Source Project4df24232009-03-05 14:34:35 -080013362 // Determine the importance of the process, starting with most
13363 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013364 int adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013365 int schedGroup;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013366 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013367 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013368 // The last app on the list is the foreground app.
13369 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013370 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013371 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013372 } else if (app.instrumentationClass != null) {
13373 // Don't want to kill running instrumentation.
13374 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013375 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013376 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013377 } else if (app.persistentActivities > 0) {
13378 // Special persistent activities... shouldn't be used these days.
13379 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013380 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013381 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013382 } else if (app.curReceiver != null ||
13383 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
13384 // An app that is currently receiving a broadcast also
13385 // counts as being in the foreground.
13386 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013387 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013388 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013389 } else if (app.executingServices.size() > 0) {
13390 // An app that is currently executing a service callback also
13391 // counts as being in the foreground.
13392 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013393 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013394 app.adjType = "exec-service";
13395 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013396 // The user is aware of this app, so make it visible.
13397 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013398 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013399 app.adjType = "foreground-service";
13400 } else if (app.forcingToForeground != null) {
13401 // The user is aware of this app, so make it visible.
13402 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013403 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013404 app.adjType = "force-foreground";
13405 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080013406 } else if (app == mHomeProcess) {
13407 // This process is hosting what we currently consider to be the
13408 // home app, so we don't want to let it go into the background.
13409 adj = HOME_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013410 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013411 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013412 } else if ((N=app.activities.size()) != 0) {
13413 // This app is in the background with paused activities.
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013414 app.hidden = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013415 adj = hiddenAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013416 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013417 app.adjType = "bg-activities";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013418 N = app.activities.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013419 for (int j=0; j<N; j++) {
13420 if (((HistoryRecord)app.activities.get(j)).visible) {
13421 // This app has a visible activity!
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013422 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013423 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013424 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013425 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013426 break;
13427 }
13428 }
13429 } else {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013430 // A very not-needed process. If this is lower in the lru list,
13431 // we will push it in to the empty bucket.
13432 app.hidden = true;
13433 app.empty = true;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013434 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013435 adj = hiddenAdj;
13436 app.adjType = "bg-empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013437 }
13438
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013439 //Log.i(TAG, "OOM " + app + ": initial adj=" + adj);
13440
The Android Open Source Project4df24232009-03-05 14:34:35 -080013441 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013442 // there are applications dependent on our services or providers, but
13443 // this gives us a baseline and makes sure we don't get into an
13444 // infinite recursion.
13445 app.adjSeq = mAdjSeq;
13446 app.curRawAdj = adj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013447
Christopher Tate6fa95972009-06-05 18:43:55 -070013448 if (mBackupTarget != null && app == mBackupTarget.app) {
13449 // If possible we want to avoid killing apps while they're being backed up
13450 if (adj > BACKUP_APP_ADJ) {
13451 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
13452 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013453 app.adjType = "backup";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013454 app.hidden = false;
Christopher Tate6fa95972009-06-05 18:43:55 -070013455 }
13456 }
13457
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013458 if (app.services.size() != 0 && (adj > FOREGROUND_APP_ADJ
13459 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013460 final long now = SystemClock.uptimeMillis();
13461 // This process is more important if the top activity is
13462 // bound to the service.
13463 Iterator jt = app.services.iterator();
13464 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13465 ServiceRecord s = (ServiceRecord)jt.next();
13466 if (s.startRequested) {
13467 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
13468 // This service has seen some activity within
13469 // recent memory, so we will keep its process ahead
13470 // of the background processes.
13471 if (adj > SECONDARY_SERVER_ADJ) {
13472 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013473 app.adjType = "started-services";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013474 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013475 }
13476 }
13477 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013478 if (s.connections.size() > 0 && (adj > FOREGROUND_APP_ADJ
13479 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013480 Iterator<ConnectionRecord> kt
13481 = s.connections.values().iterator();
13482 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13483 // XXX should compute this based on the max of
13484 // all connected clients.
13485 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013486 if (cr.binding.client == app) {
13487 // Binding to ourself is not interesting.
13488 continue;
13489 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013490 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
13491 ProcessRecord client = cr.binding.client;
13492 int myHiddenAdj = hiddenAdj;
13493 if (myHiddenAdj > client.hiddenAdj) {
13494 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
13495 myHiddenAdj = client.hiddenAdj;
13496 } else {
13497 myHiddenAdj = VISIBLE_APP_ADJ;
13498 }
13499 }
13500 int clientAdj = computeOomAdjLocked(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013501 client, myHiddenAdj, TOP_APP, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013502 if (adj > clientAdj) {
13503 adj = clientAdj > VISIBLE_APP_ADJ
13504 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013505 if (!client.hidden) {
13506 app.hidden = false;
13507 }
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013508 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013509 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13510 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013511 app.adjSource = cr.binding.client;
13512 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013513 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013514 if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
13515 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13516 schedGroup = Process.THREAD_GROUP_DEFAULT;
13517 }
13518 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013519 }
13520 HistoryRecord a = cr.activity;
13521 //if (a != null) {
13522 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13523 //}
13524 if (a != null && adj > FOREGROUND_APP_ADJ &&
13525 (a.state == ActivityState.RESUMED
13526 || a.state == ActivityState.PAUSING)) {
13527 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013528 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013529 app.hidden = false;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013530 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013531 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13532 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013533 app.adjSource = a;
13534 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013535 }
13536 }
13537 }
13538 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013539
13540 // Finally, f this process has active services running in it, we
13541 // would like to avoid killing it unless it would prevent the current
13542 // application from running. By default we put the process in
13543 // with the rest of the background processes; as we scan through
13544 // its services we may bump it up from there.
13545 if (adj > hiddenAdj) {
13546 adj = hiddenAdj;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013547 app.hidden = false;
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013548 app.adjType = "bg-services";
13549 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013550 }
13551
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013552 if (app.pubProviders.size() != 0 && (adj > FOREGROUND_APP_ADJ
13553 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013554 Iterator jt = app.pubProviders.values().iterator();
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013555 while (jt.hasNext() && (adj > FOREGROUND_APP_ADJ
13556 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013557 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13558 if (cpr.clients.size() != 0) {
13559 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13560 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13561 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013562 if (client == app) {
13563 // Being our own client is not interesting.
13564 continue;
13565 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013566 int myHiddenAdj = hiddenAdj;
13567 if (myHiddenAdj > client.hiddenAdj) {
13568 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13569 myHiddenAdj = client.hiddenAdj;
13570 } else {
13571 myHiddenAdj = FOREGROUND_APP_ADJ;
13572 }
13573 }
13574 int clientAdj = computeOomAdjLocked(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013575 client, myHiddenAdj, TOP_APP, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013576 if (adj > clientAdj) {
13577 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013578 ? clientAdj : FOREGROUND_APP_ADJ;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013579 if (!client.hidden) {
13580 app.hidden = false;
13581 }
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013582 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013583 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13584 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013585 app.adjSource = client;
13586 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013587 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013588 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13589 schedGroup = Process.THREAD_GROUP_DEFAULT;
13590 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013591 }
13592 }
13593 // If the provider has external (non-framework) process
13594 // dependencies, ensure that its adjustment is at least
13595 // FOREGROUND_APP_ADJ.
13596 if (cpr.externals != 0) {
13597 if (adj > FOREGROUND_APP_ADJ) {
13598 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013599 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013600 app.hidden = false;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013601 app.adjType = "provider";
13602 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013603 }
13604 }
13605 }
13606 }
13607
13608 app.curRawAdj = adj;
13609
13610 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13611 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13612 if (adj > app.maxAdj) {
13613 adj = app.maxAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013614 if (app.maxAdj <= VISIBLE_APP_ADJ) {
13615 schedGroup = Process.THREAD_GROUP_DEFAULT;
13616 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013617 }
13618
13619 app.curAdj = adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013620 app.curSchedGroup = schedGroup;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013621
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013622 return adj;
13623 }
13624
13625 /**
13626 * Ask a given process to GC right now.
13627 */
13628 final void performAppGcLocked(ProcessRecord app) {
13629 try {
13630 app.lastRequestedGc = SystemClock.uptimeMillis();
13631 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013632 if (app.reportLowMemory) {
13633 app.reportLowMemory = false;
13634 app.thread.scheduleLowMemory();
13635 } else {
13636 app.thread.processInBackground();
13637 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013638 }
13639 } catch (Exception e) {
13640 // whatever.
13641 }
13642 }
13643
13644 /**
13645 * Returns true if things are idle enough to perform GCs.
13646 */
13647 private final boolean canGcNow() {
13648 return mParallelBroadcasts.size() == 0
13649 && mOrderedBroadcasts.size() == 0
13650 && (mSleeping || (mResumedActivity != null &&
13651 mResumedActivity.idle));
13652 }
13653
13654 /**
13655 * Perform GCs on all processes that are waiting for it, but only
13656 * if things are idle.
13657 */
13658 final void performAppGcsLocked() {
13659 final int N = mProcessesToGc.size();
13660 if (N <= 0) {
13661 return;
13662 }
13663 if (canGcNow()) {
13664 while (mProcessesToGc.size() > 0) {
13665 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013666 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13667 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13668 <= SystemClock.uptimeMillis()) {
13669 // To avoid spamming the system, we will GC processes one
13670 // at a time, waiting a few seconds between each.
13671 performAppGcLocked(proc);
13672 scheduleAppGcsLocked();
13673 return;
13674 } else {
13675 // It hasn't been long enough since we last GCed this
13676 // process... put it in the list to wait for its time.
13677 addProcessToGcListLocked(proc);
13678 break;
13679 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013680 }
13681 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013682
13683 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013684 }
13685 }
13686
13687 /**
13688 * If all looks good, perform GCs on all processes waiting for them.
13689 */
13690 final void performAppGcsIfAppropriateLocked() {
13691 if (canGcNow()) {
13692 performAppGcsLocked();
13693 return;
13694 }
13695 // Still not idle, wait some more.
13696 scheduleAppGcsLocked();
13697 }
13698
13699 /**
13700 * Schedule the execution of all pending app GCs.
13701 */
13702 final void scheduleAppGcsLocked() {
13703 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013704
13705 if (mProcessesToGc.size() > 0) {
13706 // Schedule a GC for the time to the next process.
13707 ProcessRecord proc = mProcessesToGc.get(0);
13708 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13709
13710 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13711 long now = SystemClock.uptimeMillis();
13712 if (when < (now+GC_TIMEOUT)) {
13713 when = now + GC_TIMEOUT;
13714 }
13715 mHandler.sendMessageAtTime(msg, when);
13716 }
13717 }
13718
13719 /**
13720 * Add a process to the array of processes waiting to be GCed. Keeps the
13721 * list in sorted order by the last GC time. The process can't already be
13722 * on the list.
13723 */
13724 final void addProcessToGcListLocked(ProcessRecord proc) {
13725 boolean added = false;
13726 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13727 if (mProcessesToGc.get(i).lastRequestedGc <
13728 proc.lastRequestedGc) {
13729 added = true;
13730 mProcessesToGc.add(i+1, proc);
13731 break;
13732 }
13733 }
13734 if (!added) {
13735 mProcessesToGc.add(0, proc);
13736 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013737 }
13738
13739 /**
13740 * Set up to ask a process to GC itself. This will either do it
13741 * immediately, or put it on the list of processes to gc the next
13742 * time things are idle.
13743 */
13744 final void scheduleAppGcLocked(ProcessRecord app) {
13745 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013746 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013747 return;
13748 }
13749 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013750 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013751 scheduleAppGcsLocked();
13752 }
13753 }
13754
13755 private final boolean updateOomAdjLocked(
13756 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13757 app.hiddenAdj = hiddenAdj;
13758
13759 if (app.thread == null) {
13760 return true;
13761 }
13762
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013763 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013764
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013765 if ((app.pid != 0 && app.pid != MY_PID) || Process.supportsProcesses()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013766 if (app.curRawAdj != app.setRawAdj) {
13767 if (app.curRawAdj > FOREGROUND_APP_ADJ
13768 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13769 // If this app is transitioning from foreground to
13770 // non-foreground, have it do a gc.
13771 scheduleAppGcLocked(app);
13772 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13773 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13774 // Likewise do a gc when an app is moving in to the
13775 // background (such as a service stopping).
13776 scheduleAppGcLocked(app);
13777 }
13778 app.setRawAdj = app.curRawAdj;
13779 }
13780 if (adj != app.setAdj) {
13781 if (Process.setOomAdj(app.pid, adj)) {
13782 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13783 TAG, "Set app " + app.processName +
13784 " oom adj to " + adj);
13785 app.setAdj = adj;
13786 } else {
13787 return false;
13788 }
13789 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013790 if (app.setSchedGroup != app.curSchedGroup) {
13791 app.setSchedGroup = app.curSchedGroup;
13792 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13793 "Setting process group of " + app.processName
13794 + " to " + app.curSchedGroup);
13795 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013796 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013797 try {
13798 Process.setProcessGroup(app.pid, app.curSchedGroup);
13799 } catch (Exception e) {
13800 Log.w(TAG, "Failed setting process group of " + app.pid
13801 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013802 e.printStackTrace();
13803 } finally {
13804 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013805 }
13806 }
13807 if (false) {
13808 if (app.thread != null) {
13809 try {
13810 app.thread.setSchedulingGroup(app.curSchedGroup);
13811 } catch (RemoteException e) {
13812 }
13813 }
13814 }
13815 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013816 }
13817
13818 return true;
13819 }
13820
13821 private final HistoryRecord resumedAppLocked() {
13822 HistoryRecord resumedActivity = mResumedActivity;
13823 if (resumedActivity == null || resumedActivity.app == null) {
13824 resumedActivity = mPausingActivity;
13825 if (resumedActivity == null || resumedActivity.app == null) {
13826 resumedActivity = topRunningActivityLocked(null);
13827 }
13828 }
13829 return resumedActivity;
13830 }
13831
13832 private final boolean updateOomAdjLocked(ProcessRecord app) {
13833 final HistoryRecord TOP_ACT = resumedAppLocked();
13834 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13835 int curAdj = app.curAdj;
13836 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13837 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13838
13839 mAdjSeq++;
13840
13841 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13842 if (res) {
13843 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13844 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13845 if (nowHidden != wasHidden) {
13846 // Changed to/from hidden state, so apps after it in the LRU
13847 // list may also be changed.
13848 updateOomAdjLocked();
13849 }
13850 }
13851 return res;
13852 }
13853
13854 private final boolean updateOomAdjLocked() {
13855 boolean didOomAdj = true;
13856 final HistoryRecord TOP_ACT = resumedAppLocked();
13857 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13858
13859 if (false) {
13860 RuntimeException e = new RuntimeException();
13861 e.fillInStackTrace();
13862 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13863 }
13864
13865 mAdjSeq++;
13866
13867 // First try updating the OOM adjustment for each of the
13868 // application processes based on their current state.
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013869 int i = mLruProcesses.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013870 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13871 while (i > 0) {
13872 i--;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013873 ProcessRecord app = mLruProcesses.get(i);
13874 //Log.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013875 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013876 if (curHiddenAdj < EMPTY_APP_ADJ
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013877 && app.curAdj == curHiddenAdj) {
13878 curHiddenAdj++;
13879 }
13880 } else {
13881 didOomAdj = false;
13882 }
13883 }
13884
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013885 // If we return false, we will fall back on killing processes to
13886 // have a fixed limit. Do this if a limit has been requested; else
13887 // only return false if one of the adjustments failed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013888 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13889 }
13890
13891 private final void trimApplications() {
13892 synchronized (this) {
13893 int i;
13894
13895 // First remove any unused application processes whose package
13896 // has been removed.
13897 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13898 final ProcessRecord app = mRemovedProcesses.get(i);
13899 if (app.activities.size() == 0
13900 && app.curReceiver == null && app.services.size() == 0) {
13901 Log.i(
13902 TAG, "Exiting empty application process "
13903 + app.processName + " ("
13904 + (app.thread != null ? app.thread.asBinder() : null)
13905 + ")\n");
13906 if (app.pid > 0 && app.pid != MY_PID) {
13907 Process.killProcess(app.pid);
13908 } else {
13909 try {
13910 app.thread.scheduleExit();
13911 } catch (Exception e) {
13912 // Ignore exceptions.
13913 }
13914 }
13915 cleanUpApplicationRecordLocked(app, false, -1);
13916 mRemovedProcesses.remove(i);
13917
13918 if (app.persistent) {
13919 if (app.persistent) {
13920 addAppLocked(app.info);
13921 }
13922 }
13923 }
13924 }
13925
13926 // Now try updating the OOM adjustment for each of the
13927 // application processes based on their current state.
13928 // If the setOomAdj() API is not supported, then go with our
13929 // back-up plan...
13930 if (!updateOomAdjLocked()) {
13931
13932 // Count how many processes are running services.
13933 int numServiceProcs = 0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013934 for (i=mLruProcesses.size()-1; i>=0; i--) {
13935 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013936
13937 if (app.persistent || app.services.size() != 0
13938 || app.curReceiver != null
13939 || app.persistentActivities > 0) {
13940 // Don't count processes holding services against our
13941 // maximum process count.
13942 if (localLOGV) Log.v(
13943 TAG, "Not trimming app " + app + " with services: "
13944 + app.services);
13945 numServiceProcs++;
13946 }
13947 }
13948
13949 int curMaxProcs = mProcessLimit;
13950 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13951 if (mAlwaysFinishActivities) {
13952 curMaxProcs = 1;
13953 }
13954 curMaxProcs += numServiceProcs;
13955
13956 // Quit as many processes as we can to get down to the desired
13957 // process count. First remove any processes that no longer
13958 // have activites running in them.
13959 for ( i=0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013960 i<mLruProcesses.size()
13961 && mLruProcesses.size() > curMaxProcs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013962 i++) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013963 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013964 // Quit an application only if it is not currently
13965 // running any activities.
13966 if (!app.persistent && app.activities.size() == 0
13967 && app.curReceiver == null && app.services.size() == 0) {
13968 Log.i(
13969 TAG, "Exiting empty application process "
13970 + app.processName + " ("
13971 + (app.thread != null ? app.thread.asBinder() : null)
13972 + ")\n");
13973 if (app.pid > 0 && app.pid != MY_PID) {
13974 Process.killProcess(app.pid);
13975 } else {
13976 try {
13977 app.thread.scheduleExit();
13978 } catch (Exception e) {
13979 // Ignore exceptions.
13980 }
13981 }
13982 // todo: For now we assume the application is not buggy
13983 // or evil, and will quit as a result of our request.
13984 // Eventually we need to drive this off of the death
13985 // notification, and kill the process if it takes too long.
13986 cleanUpApplicationRecordLocked(app, false, i);
13987 i--;
13988 }
13989 }
13990
13991 // If we still have too many processes, now from the least
13992 // recently used process we start finishing activities.
13993 if (Config.LOGV) Log.v(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013994 TAG, "*** NOW HAVE " + mLruProcesses.size() +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013995 " of " + curMaxProcs + " processes");
13996 for ( i=0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013997 i<mLruProcesses.size()
13998 && mLruProcesses.size() > curMaxProcs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013999 i++) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014000 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014001 // Quit the application only if we have a state saved for
14002 // all of its activities.
14003 boolean canQuit = !app.persistent && app.curReceiver == null
14004 && app.services.size() == 0
14005 && app.persistentActivities == 0;
14006 int NUMA = app.activities.size();
14007 int j;
14008 if (Config.LOGV) Log.v(
14009 TAG, "Looking to quit " + app.processName);
14010 for (j=0; j<NUMA && canQuit; j++) {
14011 HistoryRecord r = (HistoryRecord)app.activities.get(j);
14012 if (Config.LOGV) Log.v(
14013 TAG, " " + r.intent.getComponent().flattenToShortString()
14014 + ": frozen=" + r.haveState + ", visible=" + r.visible);
14015 canQuit = (r.haveState || !r.stateNotNeeded)
14016 && !r.visible && r.stopped;
14017 }
14018 if (canQuit) {
14019 // Finish all of the activities, and then the app itself.
14020 for (j=0; j<NUMA; j++) {
14021 HistoryRecord r = (HistoryRecord)app.activities.get(j);
14022 if (!r.finishing) {
14023 destroyActivityLocked(r, false);
14024 }
14025 r.resultTo = null;
14026 }
14027 Log.i(TAG, "Exiting application process "
14028 + app.processName + " ("
14029 + (app.thread != null ? app.thread.asBinder() : null)
14030 + ")\n");
14031 if (app.pid > 0 && app.pid != MY_PID) {
14032 Process.killProcess(app.pid);
14033 } else {
14034 try {
14035 app.thread.scheduleExit();
14036 } catch (Exception e) {
14037 // Ignore exceptions.
14038 }
14039 }
14040 // todo: For now we assume the application is not buggy
14041 // or evil, and will quit as a result of our request.
14042 // Eventually we need to drive this off of the death
14043 // notification, and kill the process if it takes too long.
14044 cleanUpApplicationRecordLocked(app, false, i);
14045 i--;
14046 //dump();
14047 }
14048 }
14049
14050 }
14051
14052 int curMaxActivities = MAX_ACTIVITIES;
14053 if (mAlwaysFinishActivities) {
14054 curMaxActivities = 1;
14055 }
14056
14057 // Finally, if there are too many activities now running, try to
14058 // finish as many as we can to get back down to the limit.
14059 for ( i=0;
14060 i<mLRUActivities.size()
14061 && mLRUActivities.size() > curMaxActivities;
14062 i++) {
14063 final HistoryRecord r
14064 = (HistoryRecord)mLRUActivities.get(i);
14065
14066 // We can finish this one if we have its icicle saved and
14067 // it is not persistent.
14068 if ((r.haveState || !r.stateNotNeeded) && !r.visible
14069 && r.stopped && !r.persistent && !r.finishing) {
14070 final int origSize = mLRUActivities.size();
14071 destroyActivityLocked(r, true);
14072
14073 // This will remove it from the LRU list, so keep
14074 // our index at the same value. Note that this check to
14075 // see if the size changes is just paranoia -- if
14076 // something unexpected happens, we don't want to end up
14077 // in an infinite loop.
14078 if (origSize > mLRUActivities.size()) {
14079 i--;
14080 }
14081 }
14082 }
14083 }
14084 }
14085
14086 /** This method sends the specified signal to each of the persistent apps */
14087 public void signalPersistentProcesses(int sig) throws RemoteException {
14088 if (sig != Process.SIGNAL_USR1) {
14089 throw new SecurityException("Only SIGNAL_USR1 is allowed");
14090 }
14091
14092 synchronized (this) {
14093 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
14094 != PackageManager.PERMISSION_GRANTED) {
14095 throw new SecurityException("Requires permission "
14096 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
14097 }
14098
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014099 for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
14100 ProcessRecord r = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014101 if (r.thread != null && r.persistent) {
14102 Process.sendSignal(r.pid, sig);
14103 }
14104 }
14105 }
14106 }
14107
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014108 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014109 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014110
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014111 try {
14112 synchronized (this) {
14113 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
14114 // its own permission.
14115 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
14116 != PackageManager.PERMISSION_GRANTED) {
14117 throw new SecurityException("Requires permission "
14118 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014119 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014120
14121 if (start && fd == null) {
14122 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014123 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014124
14125 ProcessRecord proc = null;
14126 try {
14127 int pid = Integer.parseInt(process);
14128 synchronized (mPidsSelfLocked) {
14129 proc = mPidsSelfLocked.get(pid);
14130 }
14131 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014132 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014133
14134 if (proc == null) {
14135 HashMap<String, SparseArray<ProcessRecord>> all
14136 = mProcessNames.getMap();
14137 SparseArray<ProcessRecord> procs = all.get(process);
14138 if (procs != null && procs.size() > 0) {
14139 proc = procs.valueAt(0);
14140 }
14141 }
14142
14143 if (proc == null || proc.thread == null) {
14144 throw new IllegalArgumentException("Unknown process: " + process);
14145 }
14146
14147 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
14148 if (isSecure) {
14149 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
14150 throw new SecurityException("Process not debuggable: " + proc);
14151 }
14152 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014153
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014154 proc.thread.profilerControl(start, path, fd);
14155 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014156 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014157 }
14158 } catch (RemoteException e) {
14159 throw new IllegalStateException("Process disappeared");
14160 } finally {
14161 if (fd != null) {
14162 try {
14163 fd.close();
14164 } catch (IOException e) {
14165 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014166 }
14167 }
14168 }
14169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014170 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
14171 public void monitor() {
14172 synchronized (this) { }
14173 }
14174}