blob: bf436b6e13817d4cb95d0b3dd2703139d57615ed [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006-2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.am;
18
19import com.android.internal.os.BatteryStatsImpl;
Dianne Hackbornde7faf62009-06-30 13:27:30 -070020import com.android.server.AttributeCache;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import com.android.server.IntentResolver;
22import com.android.server.ProcessMap;
23import com.android.server.ProcessStats;
24import com.android.server.SystemServer;
25import com.android.server.Watchdog;
26import com.android.server.WindowManagerService;
27
Dianne Hackborndd71fc82009-12-16 19:24:32 -080028import dalvik.system.Zygote;
29
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import android.app.Activity;
31import android.app.ActivityManager;
32import android.app.ActivityManagerNative;
33import android.app.ActivityThread;
34import android.app.AlertDialog;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020035import android.app.ApplicationErrorReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.app.Dialog;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070037import android.app.IActivityController;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.app.IActivityWatcher;
39import android.app.IApplicationThread;
40import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080041import android.app.IServiceConnection;
42import android.app.IThumbnailReceiver;
43import android.app.Instrumentation;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070044import android.app.Notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.app.PendingIntent;
46import android.app.ResultInfo;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070047import android.app.Service;
Christopher Tate181fafa2009-05-14 11:12:14 -070048import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020049import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.content.ComponentName;
51import android.content.ContentResolver;
52import android.content.Context;
53import android.content.Intent;
54import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070055import android.content.IIntentReceiver;
56import android.content.IIntentSender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -070057import android.content.IntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080058import android.content.pm.ActivityInfo;
59import android.content.pm.ApplicationInfo;
60import android.content.pm.ConfigurationInfo;
61import android.content.pm.IPackageDataObserver;
62import android.content.pm.IPackageManager;
63import android.content.pm.InstrumentationInfo;
64import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070065import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080066import android.content.pm.ProviderInfo;
67import android.content.pm.ResolveInfo;
68import android.content.pm.ServiceInfo;
69import android.content.res.Configuration;
70import android.graphics.Bitmap;
71import android.net.Uri;
72import android.os.Binder;
73import android.os.Bundle;
Dan Egnor60d87622009-12-16 16:32:58 -080074import android.os.Build;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070075import android.os.Debug;
Dan Egnor60d87622009-12-16 16:32:58 -080076import android.os.DropBoxManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080077import android.os.Environment;
78import android.os.FileUtils;
79import android.os.Handler;
80import android.os.IBinder;
81import android.os.IPermissionController;
82import android.os.Looper;
83import android.os.Message;
84import android.os.Parcel;
85import android.os.ParcelFileDescriptor;
86import android.os.PowerManager;
87import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070088import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089import android.os.RemoteException;
90import android.os.ServiceManager;
91import android.os.SystemClock;
92import android.os.SystemProperties;
93import android.provider.Checkin;
94import android.provider.Settings;
95import android.text.TextUtils;
96import android.util.Config;
97import android.util.EventLog;
98import android.util.Log;
99import android.util.PrintWriterPrinter;
100import android.util.SparseArray;
101import android.view.Gravity;
102import android.view.LayoutInflater;
103import android.view.View;
104import android.view.WindowManager;
105import android.view.WindowManagerPolicy;
106
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107import java.io.File;
108import java.io.FileDescriptor;
109import java.io.FileInputStream;
110import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200111import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112import java.io.PrintWriter;
113import java.lang.IllegalStateException;
114import java.lang.ref.WeakReference;
115import java.util.ArrayList;
116import java.util.HashMap;
117import java.util.HashSet;
118import java.util.Iterator;
119import java.util.List;
120import java.util.Locale;
121import java.util.Map;
122
123public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
124 static final String TAG = "ActivityManager";
125 static final boolean DEBUG = false;
126 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
127 static final boolean DEBUG_SWITCH = localLOGV || false;
128 static final boolean DEBUG_TASKS = localLOGV || false;
129 static final boolean DEBUG_PAUSE = localLOGV || false;
130 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
131 static final boolean DEBUG_TRANSITION = localLOGV || false;
132 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700133 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 static final boolean DEBUG_SERVICE = localLOGV || false;
135 static final boolean DEBUG_VISBILITY = localLOGV || false;
136 static final boolean DEBUG_PROCESSES = localLOGV || false;
Dianne Hackborna1e989b2009-09-01 19:54:29 -0700137 static final boolean DEBUG_PROVIDER = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700139 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate436344a2009-09-30 16:17:37 -0700140 static final boolean DEBUG_BACKUP = localLOGV || false;
Dianne Hackborndc6b6352009-09-30 14:20:09 -0700141 static final boolean DEBUG_CONFIGURATION = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 static final boolean VALIDATE_TOKENS = false;
143 static final boolean SHOW_ACTIVITY_START_TIME = true;
144
145 // Control over CPU and battery monitoring.
146 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
147 static final boolean MONITOR_CPU_USAGE = true;
148 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
149 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
150 static final boolean MONITOR_THREAD_CPU_USAGE = false;
151
Dianne Hackborn1655be42009-05-08 14:29:01 -0700152 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700153 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700154
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 private static final String SYSTEM_SECURE = "ro.secure";
156
157 // This is the maximum number of application processes we would like
158 // to have running. Due to the asynchronous nature of things, we can
159 // temporarily go beyond this limit.
160 static final int MAX_PROCESSES = 2;
161
162 // Set to false to leave processes running indefinitely, relying on
163 // the kernel killing them as resources are required.
164 static final boolean ENFORCE_PROCESS_LIMIT = false;
165
166 // This is the maximum number of activities that we would like to have
167 // running at a given time.
168 static final int MAX_ACTIVITIES = 20;
169
170 // Maximum number of recent tasks that we can remember.
171 static final int MAX_RECENT_TASKS = 20;
172
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700173 // Amount of time after a call to stopAppSwitches() during which we will
174 // prevent further untrusted switches from happening.
175 static final long APP_SWITCH_DELAY_TIME = 5*1000;
176
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177 // How long until we reset a task when the user returns to it. Currently
178 // 30 minutes.
179 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
180
181 // Set to true to disable the icon that is shown while a new activity
182 // is being started.
183 static final boolean SHOW_APP_STARTING_ICON = true;
184
185 // How long we wait until giving up on the last activity to pause. This
186 // is short because it directly impacts the responsiveness of starting the
187 // next activity.
188 static final int PAUSE_TIMEOUT = 500;
189
190 /**
191 * How long we can hold the launch wake lock before giving up.
192 */
193 static final int LAUNCH_TIMEOUT = 10*1000;
194
195 // How long we wait for a launched process to attach to the activity manager
196 // before we decide it's never going to come up for real.
197 static final int PROC_START_TIMEOUT = 10*1000;
198
199 // How long we wait until giving up on the last activity telling us it
200 // is idle.
201 static final int IDLE_TIMEOUT = 10*1000;
202
203 // How long to wait after going idle before forcing apps to GC.
204 static final int GC_TIMEOUT = 5*1000;
205
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700206 // The minimum amount of time between successive GC requests for a process.
207 static final int GC_MIN_INTERVAL = 60*1000;
208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 // How long we wait until giving up on an activity telling us it has
210 // finished destroying itself.
211 static final int DESTROY_TIMEOUT = 10*1000;
212
213 // How long we allow a receiver to run before giving up on it.
214 static final int BROADCAST_TIMEOUT = 10*1000;
215
216 // How long we wait for a service to finish executing.
217 static final int SERVICE_TIMEOUT = 20*1000;
218
219 // How long a service needs to be running until restarting its process
220 // is no longer considered to be a relaunch of the service.
221 static final int SERVICE_RESTART_DURATION = 5*1000;
222
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700223 // How long a service needs to be running until it will start back at
224 // SERVICE_RESTART_DURATION after being killed.
225 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
226
227 // Multiplying factor to increase restart duration time by, for each time
228 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
229 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
230
231 // The minimum amount of time between restarting services that we allow.
232 // That is, when multiple services are restarting, we won't allow each
233 // to restart less than this amount of time from the last one.
234 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
235
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236 // Maximum amount of time for there to be no activity on a service before
237 // we consider it non-essential and allow its process to go on the
238 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700239 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240
241 // How long we wait until we timeout on key dispatching.
242 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
243
244 // The minimum time we allow between crashes, for us to consider this
245 // application to be bad and stop and its services and reject broadcasts.
246 static final int MIN_CRASH_INTERVAL = 60*1000;
247
248 // How long we wait until we timeout on key dispatching during instrumentation.
249 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
250
251 // OOM adjustments for processes in various states:
252
253 // This is a process without anything currently running in it. Definitely
254 // the first to go! Value set in system/rootdir/init.rc on startup.
255 // This value is initalized in the constructor, careful when refering to
256 // this static variable externally.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800257 static final int EMPTY_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258
259 // This is a process only hosting activities that are not visible,
260 // so it can be killed without any disruption. Value set in
261 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800262 static final int HIDDEN_APP_MAX_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 static int HIDDEN_APP_MIN_ADJ;
264
The Android Open Source Project4df24232009-03-05 14:34:35 -0800265 // This is a process holding the home application -- we want to try
266 // avoiding killing it, even if it would normally be in the background,
267 // because the user interacts with it so much.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800268 static final int HOME_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800269
Christopher Tate6fa95972009-06-05 18:43:55 -0700270 // This is a process currently hosting a backup operation. Killing it
271 // is not entirely fatal but is generally a bad idea.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800272 static final int BACKUP_APP_ADJ;
Christopher Tate6fa95972009-06-05 18:43:55 -0700273
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274 // This is a process holding a secondary server -- killing it will not
275 // have much of an impact as far as the user is concerned. Value set in
276 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800277 static final int SECONDARY_SERVER_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800278
279 // This is a process only hosting activities that are visible to the
280 // user, so we'd prefer they don't disappear. Value set in
281 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800282 static final int VISIBLE_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800283
284 // This is the process running the current foreground app. We'd really
285 // rather not kill it! Value set in system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800286 static final int FOREGROUND_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800287
288 // This is a process running a core server, such as telephony. Definitely
289 // don't want to kill it, but doing so is not completely fatal.
290 static final int CORE_SERVER_ADJ = -12;
291
292 // The system process runs at the default adjustment.
293 static final int SYSTEM_ADJ = -16;
294
295 // Memory pages are 4K.
296 static final int PAGE_SIZE = 4*1024;
297
Jacek Surazski82a73df2009-06-17 14:33:18 +0200298 // System property defining error report receiver for system apps
299 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
300
301 // System property defining default error report receiver
302 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
303
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800304 // Corresponding memory levels for above adjustments.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800305 static final int EMPTY_APP_MEM;
306 static final int HIDDEN_APP_MEM;
307 static final int HOME_APP_MEM;
308 static final int BACKUP_APP_MEM;
309 static final int SECONDARY_SERVER_MEM;
310 static final int VISIBLE_APP_MEM;
311 static final int FOREGROUND_APP_MEM;
312
313 // The minimum number of hidden apps we want to be able to keep around,
314 // without empty apps being able to push them out of memory.
315 static final int MIN_HIDDEN_APPS = 2;
316
317 // We put empty content processes after any hidden processes that have
318 // been idle for less than 30 seconds.
319 static final long CONTENT_APP_IDLE_OFFSET = 30*1000;
320
321 // We put empty content processes after any hidden processes that have
322 // been idle for less than 60 seconds.
323 static final long EMPTY_APP_IDLE_OFFSET = 60*1000;
324
325 static {
326 // These values are set in system/rootdir/init.rc on startup.
327 FOREGROUND_APP_ADJ =
328 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
329 VISIBLE_APP_ADJ =
330 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
331 SECONDARY_SERVER_ADJ =
332 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
333 BACKUP_APP_ADJ =
334 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
335 HOME_APP_ADJ =
336 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
337 HIDDEN_APP_MIN_ADJ =
338 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
339 EMPTY_APP_ADJ =
340 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
341 HIDDEN_APP_MAX_ADJ = EMPTY_APP_ADJ-1;
342 FOREGROUND_APP_MEM =
343 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
344 VISIBLE_APP_MEM =
345 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
346 SECONDARY_SERVER_MEM =
347 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
348 BACKUP_APP_MEM =
349 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
350 HOME_APP_MEM =
351 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
352 HIDDEN_APP_MEM =
353 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
354 EMPTY_APP_MEM =
355 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
356 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357
358 final int MY_PID;
359
360 static final String[] EMPTY_STRING_ARRAY = new String[0];
361
362 enum ActivityState {
363 INITIALIZING,
364 RESUMED,
365 PAUSING,
366 PAUSED,
367 STOPPING,
368 STOPPED,
369 FINISHING,
370 DESTROYING,
371 DESTROYED
372 }
373
374 /**
375 * The back history of all previous (and possibly still
376 * running) activities. It contains HistoryRecord objects.
377 */
378 final ArrayList mHistory = new ArrayList();
379
380 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700381 * Description of a request to start a new activity, which has been held
382 * due to app switches being disabled.
383 */
384 class PendingActivityLaunch {
385 HistoryRecord r;
386 HistoryRecord sourceRecord;
387 Uri[] grantedUriPermissions;
388 int grantedMode;
389 boolean onlyIfNeeded;
390 }
391
392 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
393 = new ArrayList<PendingActivityLaunch>();
394
395 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 * List of all active broadcasts that are to be executed immediately
397 * (without waiting for another broadcast to finish). Currently this only
398 * contains broadcasts to registered receivers, to avoid spinning up
399 * a bunch of processes to execute IntentReceiver components.
400 */
401 final ArrayList<BroadcastRecord> mParallelBroadcasts
402 = new ArrayList<BroadcastRecord>();
403
404 /**
405 * List of all active broadcasts that are to be executed one at a time.
406 * The object at the top of the list is the currently activity broadcasts;
407 * those after it are waiting for the top to finish..
408 */
409 final ArrayList<BroadcastRecord> mOrderedBroadcasts
410 = new ArrayList<BroadcastRecord>();
411
412 /**
Dianne Hackborn12527f92009-11-11 17:39:50 -0800413 * Historical data of past broadcasts, for debugging.
414 */
415 static final int MAX_BROADCAST_HISTORY = 100;
416 final BroadcastRecord[] mBroadcastHistory
417 = new BroadcastRecord[MAX_BROADCAST_HISTORY];
418
419 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420 * Set when we current have a BROADCAST_INTENT_MSG in flight.
421 */
422 boolean mBroadcastsScheduled = false;
423
424 /**
425 * Set to indicate whether to issue an onUserLeaving callback when a
426 * newly launched activity is being brought in front of us.
427 */
428 boolean mUserLeaving = false;
429
430 /**
431 * When we are in the process of pausing an activity, before starting the
432 * next one, this variable holds the activity that is currently being paused.
433 */
434 HistoryRecord mPausingActivity = null;
435
436 /**
437 * Current activity that is resumed, or null if there is none.
438 */
439 HistoryRecord mResumedActivity = null;
440
441 /**
442 * Activity we have told the window manager to have key focus.
443 */
444 HistoryRecord mFocusedActivity = null;
445
446 /**
447 * This is the last activity that we put into the paused state. This is
448 * used to determine if we need to do an activity transition while sleeping,
449 * when we normally hold the top activity paused.
450 */
451 HistoryRecord mLastPausedActivity = null;
452
453 /**
454 * List of activities that are waiting for a new activity
455 * to become visible before completing whatever operation they are
456 * supposed to do.
457 */
458 final ArrayList mWaitingVisibleActivities = new ArrayList();
459
460 /**
461 * List of activities that are ready to be stopped, but waiting
462 * for the next activity to settle down before doing so. It contains
463 * HistoryRecord objects.
464 */
465 final ArrayList<HistoryRecord> mStoppingActivities
466 = new ArrayList<HistoryRecord>();
467
468 /**
Dianne Hackbornbfe319e2009-09-21 00:34:05 -0700469 * Animations that for the current transition have requested not to
470 * be considered for the transition animation.
471 */
472 final ArrayList<HistoryRecord> mNoAnimActivities
473 = new ArrayList<HistoryRecord>();
474
475 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 * List of intents that were used to start the most recent tasks.
477 */
478 final ArrayList<TaskRecord> mRecentTasks
479 = new ArrayList<TaskRecord>();
480
481 /**
482 * List of activities that are ready to be finished, but waiting
483 * for the previous activity to settle down before doing so. It contains
484 * HistoryRecord objects.
485 */
486 final ArrayList mFinishingActivities = new ArrayList();
487
488 /**
489 * All of the applications we currently have running organized by name.
490 * The keys are strings of the application package name (as
491 * returned by the package manager), and the keys are ApplicationRecord
492 * objects.
493 */
494 final ProcessMap<ProcessRecord> mProcessNames
495 = new ProcessMap<ProcessRecord>();
496
497 /**
498 * The last time that various processes have crashed.
499 */
500 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
501
502 /**
503 * Set of applications that we consider to be bad, and will reject
504 * incoming broadcasts from (which the user has no control over).
505 * Processes are added to this set when they have crashed twice within
506 * a minimum amount of time; they are removed from it when they are
507 * later restarted (hopefully due to some user action). The value is the
508 * time it was added to the list.
509 */
510 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
511
512 /**
513 * All of the processes we currently have running organized by pid.
514 * The keys are the pid running the application.
515 *
516 * <p>NOTE: This object is protected by its own lock, NOT the global
517 * activity manager lock!
518 */
519 final SparseArray<ProcessRecord> mPidsSelfLocked
520 = new SparseArray<ProcessRecord>();
521
522 /**
523 * All of the processes that have been forced to be foreground. The key
524 * is the pid of the caller who requested it (we hold a death
525 * link on it).
526 */
527 abstract class ForegroundToken implements IBinder.DeathRecipient {
528 int pid;
529 IBinder token;
530 }
531 final SparseArray<ForegroundToken> mForegroundProcesses
532 = new SparseArray<ForegroundToken>();
533
534 /**
535 * List of records for processes that someone had tried to start before the
536 * system was ready. We don't start them at that point, but ensure they
537 * are started by the time booting is complete.
538 */
539 final ArrayList<ProcessRecord> mProcessesOnHold
540 = new ArrayList<ProcessRecord>();
541
542 /**
543 * List of records for processes that we have started and are waiting
544 * for them to call back. This is really only needed when running in
545 * single processes mode, in which case we do not have a unique pid for
546 * each process.
547 */
548 final ArrayList<ProcessRecord> mStartingProcesses
549 = new ArrayList<ProcessRecord>();
550
551 /**
552 * List of persistent applications that are in the process
553 * of being started.
554 */
555 final ArrayList<ProcessRecord> mPersistentStartingProcesses
556 = new ArrayList<ProcessRecord>();
557
558 /**
559 * Processes that are being forcibly torn down.
560 */
561 final ArrayList<ProcessRecord> mRemovedProcesses
562 = new ArrayList<ProcessRecord>();
563
564 /**
565 * List of running applications, sorted by recent usage.
566 * The first entry in the list is the least recently used.
567 * It contains ApplicationRecord objects. This list does NOT include
568 * any persistent application records (since we never want to exit them).
569 */
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800570 final ArrayList<ProcessRecord> mLruProcesses
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800571 = new ArrayList<ProcessRecord>();
572
573 /**
574 * List of processes that should gc as soon as things are idle.
575 */
576 final ArrayList<ProcessRecord> mProcessesToGc
577 = new ArrayList<ProcessRecord>();
578
579 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800580 * This is the process holding what we currently consider to be
581 * the "home" activity.
582 */
583 private ProcessRecord mHomeProcess;
584
585 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 * List of running activities, sorted by recent usage.
587 * The first entry in the list is the least recently used.
588 * It contains HistoryRecord objects.
589 */
590 private final ArrayList mLRUActivities = new ArrayList();
591
592 /**
593 * Set of PendingResultRecord objects that are currently active.
594 */
595 final HashSet mPendingResultRecords = new HashSet();
596
597 /**
598 * Set of IntentSenderRecord objects that are currently active.
599 */
600 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
601 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
602
603 /**
604 * Intent broadcast that we have tried to start, but are
605 * waiting for its application's process to be created. We only
606 * need one (instead of a list) because we always process broadcasts
607 * one at a time, so no others can be started while waiting for this
608 * one.
609 */
610 BroadcastRecord mPendingBroadcast = null;
611
612 /**
613 * Keeps track of all IIntentReceivers that have been registered for
614 * broadcasts. Hash keys are the receiver IBinder, hash value is
615 * a ReceiverList.
616 */
617 final HashMap mRegisteredReceivers = new HashMap();
618
619 /**
620 * Resolver for broadcast intents to registered receivers.
621 * Holds BroadcastFilter (subclass of IntentFilter).
622 */
623 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
624 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
625 @Override
626 protected boolean allowFilterResult(
627 BroadcastFilter filter, List<BroadcastFilter> dest) {
628 IBinder target = filter.receiverList.receiver.asBinder();
629 for (int i=dest.size()-1; i>=0; i--) {
630 if (dest.get(i).receiverList.receiver.asBinder() == target) {
631 return false;
632 }
633 }
634 return true;
635 }
636 };
637
638 /**
639 * State of all active sticky broadcasts. Keys are the action of the
640 * sticky Intent, values are an ArrayList of all broadcasted intents with
641 * that action (which should usually be one).
642 */
643 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
644 new HashMap<String, ArrayList<Intent>>();
645
646 /**
647 * All currently running services.
648 */
649 final HashMap<ComponentName, ServiceRecord> mServices =
650 new HashMap<ComponentName, ServiceRecord>();
651
652 /**
653 * All currently running services indexed by the Intent used to start them.
654 */
655 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
656 new HashMap<Intent.FilterComparison, ServiceRecord>();
657
658 /**
659 * All currently bound service connections. Keys are the IBinder of
660 * the client's IServiceConnection.
661 */
662 final HashMap<IBinder, ConnectionRecord> mServiceConnections
663 = new HashMap<IBinder, ConnectionRecord>();
664
665 /**
666 * List of services that we have been asked to start,
667 * but haven't yet been able to. It is used to hold start requests
668 * while waiting for their corresponding application thread to get
669 * going.
670 */
671 final ArrayList<ServiceRecord> mPendingServices
672 = new ArrayList<ServiceRecord>();
673
674 /**
675 * List of services that are scheduled to restart following a crash.
676 */
677 final ArrayList<ServiceRecord> mRestartingServices
678 = new ArrayList<ServiceRecord>();
679
680 /**
681 * List of services that are in the process of being stopped.
682 */
683 final ArrayList<ServiceRecord> mStoppingServices
684 = new ArrayList<ServiceRecord>();
685
686 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700687 * Backup/restore process management
688 */
689 String mBackupAppName = null;
690 BackupRecord mBackupTarget = null;
691
692 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800693 * List of PendingThumbnailsRecord objects of clients who are still
694 * waiting to receive all of the thumbnails for a task.
695 */
696 final ArrayList mPendingThumbnails = new ArrayList();
697
698 /**
699 * List of HistoryRecord objects that have been finished and must
700 * still report back to a pending thumbnail receiver.
701 */
702 final ArrayList mCancelledThumbnails = new ArrayList();
703
704 /**
705 * All of the currently running global content providers. Keys are a
706 * string containing the provider name and values are a
707 * ContentProviderRecord object containing the data about it. Note
708 * that a single provider may be published under multiple names, so
709 * there may be multiple entries here for a single one in mProvidersByClass.
710 */
711 final HashMap mProvidersByName = new HashMap();
712
713 /**
714 * All of the currently running global content providers. Keys are a
715 * string containing the provider's implementation class and values are a
716 * ContentProviderRecord object containing the data about it.
717 */
718 final HashMap mProvidersByClass = new HashMap();
719
720 /**
721 * List of content providers who have clients waiting for them. The
722 * application is currently being launched and the provider will be
723 * removed from this list once it is published.
724 */
725 final ArrayList mLaunchingProviders = new ArrayList();
726
727 /**
728 * Global set of specific Uri permissions that have been granted.
729 */
730 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
731 = new SparseArray<HashMap<Uri, UriPermission>>();
732
733 /**
734 * Thread-local storage used to carry caller permissions over through
735 * indirect content-provider access.
736 * @see #ActivityManagerService.openContentUri()
737 */
738 private class Identity {
739 public int pid;
740 public int uid;
741
742 Identity(int _pid, int _uid) {
743 pid = _pid;
744 uid = _uid;
745 }
746 }
747 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
748
749 /**
750 * All information we have collected about the runtime performance of
751 * any user id that can impact battery performance.
752 */
753 final BatteryStatsService mBatteryStatsService;
754
755 /**
756 * information about component usage
757 */
758 final UsageStatsService mUsageStatsService;
759
760 /**
761 * Current configuration information. HistoryRecord objects are given
762 * a reference to this object to indicate which configuration they are
763 * currently running in, so this object must be kept immutable.
764 */
765 Configuration mConfiguration = new Configuration();
766
767 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700768 * Hardware-reported OpenGLES version.
769 */
770 final int GL_ES_VERSION;
771
772 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800773 * List of initialization arguments to pass to all processes when binding applications to them.
774 * For example, references to the commonly used services.
775 */
776 HashMap<String, IBinder> mAppBindArgs;
777
778 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700779 * Temporary to avoid allocations. Protected by main lock.
780 */
781 final StringBuilder mStringBuilder = new StringBuilder(256);
782
783 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800784 * Used to control how we initialize the service.
785 */
786 boolean mStartRunning = false;
787 ComponentName mTopComponent;
788 String mTopAction;
789 String mTopData;
790 boolean mSystemReady = false;
791 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700792 boolean mWaitingUpdate = false;
793 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800794
795 Context mContext;
796
797 int mFactoryTest;
798
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700799 boolean mCheckedForSetup;
800
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800801 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700802 * The time at which we will allow normal application switches again,
803 * after a call to {@link #stopAppSwitches()}.
804 */
805 long mAppSwitchesAllowedTime;
806
807 /**
808 * This is set to true after the first switch after mAppSwitchesAllowedTime
809 * is set; any switches after that will clear the time.
810 */
811 boolean mDidAppSwitch;
812
813 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800814 * Set while we are wanting to sleep, to prevent any
815 * activities from being started/resumed.
816 */
817 boolean mSleeping = false;
818
819 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700820 * Set if we are shutting down the system, similar to sleeping.
821 */
822 boolean mShuttingDown = false;
823
824 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800825 * Set when the system is going to sleep, until we have
826 * successfully paused the current activity and released our wake lock.
827 * At that point the system is allowed to actually sleep.
828 */
829 PowerManager.WakeLock mGoingToSleep;
830
831 /**
832 * We don't want to allow the device to go to sleep while in the process
833 * of launching an activity. This is primarily to allow alarm intent
834 * receivers to launch an activity and get that to run before the device
835 * goes back to sleep.
836 */
837 PowerManager.WakeLock mLaunchingActivity;
838
839 /**
840 * Task identifier that activities are currently being started
841 * in. Incremented each time a new task is created.
842 * todo: Replace this with a TokenSpace class that generates non-repeating
843 * integers that won't wrap.
844 */
845 int mCurTask = 1;
846
847 /**
848 * Current sequence id for oom_adj computation traversal.
849 */
850 int mAdjSeq = 0;
851
852 /**
853 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
854 * is set, indicating the user wants processes started in such a way
855 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
856 * running in each process (thus no pre-initialized process, etc).
857 */
858 boolean mSimpleProcessManagement = false;
859
860 /**
861 * System monitoring: number of processes that died since the last
862 * N procs were started.
863 */
864 int[] mProcDeaths = new int[20];
865
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700866 /**
867 * This is set if we had to do a delayed dexopt of an app before launching
868 * it, to increasing the ANR timeouts in that case.
869 */
870 boolean mDidDexOpt;
871
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800872 String mDebugApp = null;
873 boolean mWaitForDebugger = false;
874 boolean mDebugTransient = false;
875 String mOrigDebugApp = null;
876 boolean mOrigWaitForDebugger = false;
877 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700878 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800879
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700880 final RemoteCallbackList<IActivityWatcher> mWatchers
881 = new RemoteCallbackList<IActivityWatcher>();
882
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800883 /**
884 * Callback of last caller to {@link #requestPss}.
885 */
886 Runnable mRequestPssCallback;
887
888 /**
889 * Remaining processes for which we are waiting results from the last
890 * call to {@link #requestPss}.
891 */
892 final ArrayList<ProcessRecord> mRequestPssList
893 = new ArrayList<ProcessRecord>();
894
895 /**
896 * Runtime statistics collection thread. This object's lock is used to
897 * protect all related state.
898 */
899 final Thread mProcessStatsThread;
900
901 /**
902 * Used to collect process stats when showing not responding dialog.
903 * Protected by mProcessStatsThread.
904 */
905 final ProcessStats mProcessStats = new ProcessStats(
906 MONITOR_THREAD_CPU_USAGE);
907 long mLastCpuTime = 0;
908 long mLastWriteTime = 0;
909
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700910 long mInitialStartTime = 0;
911
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800912 /**
913 * Set to true after the system has finished booting.
914 */
915 boolean mBooted = false;
916
917 int mProcessLimit = 0;
918
919 WindowManagerService mWindowManager;
920
921 static ActivityManagerService mSelf;
922 static ActivityThread mSystemThread;
923
924 private final class AppDeathRecipient implements IBinder.DeathRecipient {
925 final ProcessRecord mApp;
926 final int mPid;
927 final IApplicationThread mAppThread;
928
929 AppDeathRecipient(ProcessRecord app, int pid,
930 IApplicationThread thread) {
931 if (localLOGV) Log.v(
932 TAG, "New death recipient " + this
933 + " for thread " + thread.asBinder());
934 mApp = app;
935 mPid = pid;
936 mAppThread = thread;
937 }
938
939 public void binderDied() {
940 if (localLOGV) Log.v(
941 TAG, "Death received in " + this
942 + " for thread " + mAppThread.asBinder());
943 removeRequestedPss(mApp);
944 synchronized(ActivityManagerService.this) {
945 appDiedLocked(mApp, mPid, mAppThread);
946 }
947 }
948 }
949
950 static final int SHOW_ERROR_MSG = 1;
951 static final int SHOW_NOT_RESPONDING_MSG = 2;
952 static final int SHOW_FACTORY_ERROR_MSG = 3;
953 static final int UPDATE_CONFIGURATION_MSG = 4;
954 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
955 static final int WAIT_FOR_DEBUGGER_MSG = 6;
956 static final int BROADCAST_INTENT_MSG = 7;
957 static final int BROADCAST_TIMEOUT_MSG = 8;
958 static final int PAUSE_TIMEOUT_MSG = 9;
959 static final int IDLE_TIMEOUT_MSG = 10;
960 static final int IDLE_NOW_MSG = 11;
961 static final int SERVICE_TIMEOUT_MSG = 12;
962 static final int UPDATE_TIME_ZONE = 13;
963 static final int SHOW_UID_ERROR_MSG = 14;
964 static final int IM_FEELING_LUCKY_MSG = 15;
965 static final int LAUNCH_TIMEOUT_MSG = 16;
966 static final int DESTROY_TIMEOUT_MSG = 17;
967 static final int SERVICE_ERROR_MSG = 18;
968 static final int RESUME_TOP_ACTIVITY_MSG = 19;
969 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700970 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700971 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800972
973 AlertDialog mUidAlert;
974
975 final Handler mHandler = new Handler() {
976 //public Handler() {
977 // if (localLOGV) Log.v(TAG, "Handler started!");
978 //}
979
980 public void handleMessage(Message msg) {
981 switch (msg.what) {
982 case SHOW_ERROR_MSG: {
983 HashMap data = (HashMap) msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 synchronized (ActivityManagerService.this) {
985 ProcessRecord proc = (ProcessRecord)data.get("app");
986 if (proc != null && proc.crashDialog != null) {
987 Log.e(TAG, "App already has crash dialog: " + proc);
988 return;
989 }
990 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700991 if (!mSleeping && !mShuttingDown) {
Dan Egnorb7f03672009-12-09 16:22:32 -0800992 Dialog d = new AppErrorDialog(mContext, res, proc);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800993 d.show();
994 proc.crashDialog = d;
995 } else {
996 // The device is asleep, so just pretend that the user
997 // saw a crash dialog and hit "force quit".
998 res.set(0);
999 }
1000 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001001
1002 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001003 } break;
1004 case SHOW_NOT_RESPONDING_MSG: {
1005 synchronized (ActivityManagerService.this) {
1006 HashMap data = (HashMap) msg.obj;
1007 ProcessRecord proc = (ProcessRecord)data.get("app");
1008 if (proc != null && proc.anrDialog != null) {
1009 Log.e(TAG, "App already has anr dialog: " + proc);
1010 return;
1011 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001012
1013 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
1014 null, null, 0, null, null, null,
1015 false, false, MY_PID, Process.SYSTEM_UID);
1016
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
1018 mContext, proc, (HistoryRecord)data.get("activity"));
1019 d.show();
1020 proc.anrDialog = d;
1021 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001022
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001023 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001024 } break;
1025 case SHOW_FACTORY_ERROR_MSG: {
1026 Dialog d = new FactoryErrorDialog(
1027 mContext, msg.getData().getCharSequence("msg"));
1028 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001029 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001030 } break;
1031 case UPDATE_CONFIGURATION_MSG: {
1032 final ContentResolver resolver = mContext.getContentResolver();
1033 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1034 } break;
1035 case GC_BACKGROUND_PROCESSES_MSG: {
1036 synchronized (ActivityManagerService.this) {
1037 performAppGcsIfAppropriateLocked();
1038 }
1039 } break;
1040 case WAIT_FOR_DEBUGGER_MSG: {
1041 synchronized (ActivityManagerService.this) {
1042 ProcessRecord app = (ProcessRecord)msg.obj;
1043 if (msg.arg1 != 0) {
1044 if (!app.waitedForDebugger) {
1045 Dialog d = new AppWaitingForDebuggerDialog(
1046 ActivityManagerService.this,
1047 mContext, app);
1048 app.waitDialog = d;
1049 app.waitedForDebugger = true;
1050 d.show();
1051 }
1052 } else {
1053 if (app.waitDialog != null) {
1054 app.waitDialog.dismiss();
1055 app.waitDialog = null;
1056 }
1057 }
1058 }
1059 } break;
1060 case BROADCAST_INTENT_MSG: {
1061 if (DEBUG_BROADCAST) Log.v(
1062 TAG, "Received BROADCAST_INTENT_MSG");
1063 processNextBroadcast(true);
1064 } break;
1065 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001066 if (mDidDexOpt) {
1067 mDidDexOpt = false;
1068 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1069 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1070 return;
1071 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001072 broadcastTimeout();
1073 } break;
1074 case PAUSE_TIMEOUT_MSG: {
1075 IBinder token = (IBinder)msg.obj;
1076 // We don't at this point know if the activity is fullscreen,
1077 // so we need to be conservative and assume it isn't.
1078 Log.w(TAG, "Activity pause timeout for " + token);
1079 activityPaused(token, null, true);
1080 } break;
1081 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001082 if (mDidDexOpt) {
1083 mDidDexOpt = false;
1084 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1085 nmsg.obj = msg.obj;
1086 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1087 return;
1088 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001089 // We don't at this point know if the activity is fullscreen,
1090 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001091 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001092 Log.w(TAG, "Activity idle timeout for " + token);
Dianne Hackborne88846e2009-09-30 21:34:25 -07001093 activityIdleInternal(token, true, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001094 } break;
1095 case DESTROY_TIMEOUT_MSG: {
1096 IBinder token = (IBinder)msg.obj;
1097 // We don't at this point know if the activity is fullscreen,
1098 // so we need to be conservative and assume it isn't.
1099 Log.w(TAG, "Activity destroy timeout for " + token);
1100 activityDestroyed(token);
1101 } break;
1102 case IDLE_NOW_MSG: {
1103 IBinder token = (IBinder)msg.obj;
Dianne Hackborne88846e2009-09-30 21:34:25 -07001104 activityIdle(token, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001105 } break;
1106 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001107 if (mDidDexOpt) {
1108 mDidDexOpt = false;
1109 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1110 nmsg.obj = msg.obj;
1111 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1112 return;
1113 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001114 serviceTimeout((ProcessRecord)msg.obj);
1115 } break;
1116 case UPDATE_TIME_ZONE: {
1117 synchronized (ActivityManagerService.this) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001118 for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
1119 ProcessRecord r = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001120 if (r.thread != null) {
1121 try {
1122 r.thread.updateTimeZone();
1123 } catch (RemoteException ex) {
1124 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1125 }
1126 }
1127 }
1128 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001129 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001130 case SHOW_UID_ERROR_MSG: {
1131 // XXX This is a temporary dialog, no need to localize.
1132 AlertDialog d = new BaseErrorDialog(mContext);
1133 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1134 d.setCancelable(false);
1135 d.setTitle("System UIDs Inconsistent");
1136 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1137 d.setButton("I'm Feeling Lucky",
1138 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1139 mUidAlert = d;
1140 d.show();
1141 } break;
1142 case IM_FEELING_LUCKY_MSG: {
1143 if (mUidAlert != null) {
1144 mUidAlert.dismiss();
1145 mUidAlert = null;
1146 }
1147 } break;
1148 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001149 if (mDidDexOpt) {
1150 mDidDexOpt = false;
1151 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1152 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1153 return;
1154 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001155 synchronized (ActivityManagerService.this) {
1156 if (mLaunchingActivity.isHeld()) {
1157 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1158 mLaunchingActivity.release();
1159 }
1160 }
1161 } break;
1162 case SERVICE_ERROR_MSG: {
1163 ServiceRecord srv = (ServiceRecord)msg.obj;
1164 // This needs to be *un*synchronized to avoid deadlock.
1165 Checkin.logEvent(mContext.getContentResolver(),
1166 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1167 srv.name.toShortString());
1168 } break;
1169 case RESUME_TOP_ACTIVITY_MSG: {
1170 synchronized (ActivityManagerService.this) {
1171 resumeTopActivityLocked(null);
1172 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001173 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001174 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001175 if (mDidDexOpt) {
1176 mDidDexOpt = false;
1177 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1178 nmsg.obj = msg.obj;
1179 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1180 return;
1181 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001182 ProcessRecord app = (ProcessRecord)msg.obj;
1183 synchronized (ActivityManagerService.this) {
1184 processStartTimedOutLocked(app);
1185 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001186 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001187 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1188 synchronized (ActivityManagerService.this) {
1189 doPendingActivityLaunchesLocked(true);
1190 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001191 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001192 case KILL_APPLICATION_MSG: {
1193 synchronized (ActivityManagerService.this) {
1194 int uid = msg.arg1;
1195 boolean restart = (msg.arg2 == 1);
1196 String pkg = (String) msg.obj;
1197 uninstallPackageLocked(pkg, uid, restart);
1198 }
1199 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001200 }
1201 }
1202 };
1203
1204 public static void setSystemProcess() {
1205 try {
1206 ActivityManagerService m = mSelf;
1207
1208 ServiceManager.addService("activity", m);
1209 ServiceManager.addService("meminfo", new MemBinder(m));
1210 if (MONITOR_CPU_USAGE) {
1211 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1212 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001213 ServiceManager.addService("permission", new PermissionController(m));
1214
1215 ApplicationInfo info =
1216 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001217 "android", STOCK_PM_FLAGS);
Mike Cleron432b7132009-09-24 15:28:29 -07001218 mSystemThread.installSystemApplicationInfo(info);
1219
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001220 synchronized (mSelf) {
1221 ProcessRecord app = mSelf.newProcessRecordLocked(
1222 mSystemThread.getApplicationThread(), info,
1223 info.processName);
1224 app.persistent = true;
1225 app.pid = Process.myPid();
1226 app.maxAdj = SYSTEM_ADJ;
1227 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1228 synchronized (mSelf.mPidsSelfLocked) {
1229 mSelf.mPidsSelfLocked.put(app.pid, app);
1230 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001231 mSelf.updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001232 }
1233 } catch (PackageManager.NameNotFoundException e) {
1234 throw new RuntimeException(
1235 "Unable to find android system package", e);
1236 }
1237 }
1238
1239 public void setWindowManager(WindowManagerService wm) {
1240 mWindowManager = wm;
1241 }
1242
1243 public static final Context main(int factoryTest) {
1244 AThread thr = new AThread();
1245 thr.start();
1246
1247 synchronized (thr) {
1248 while (thr.mService == null) {
1249 try {
1250 thr.wait();
1251 } catch (InterruptedException e) {
1252 }
1253 }
1254 }
1255
1256 ActivityManagerService m = thr.mService;
1257 mSelf = m;
1258 ActivityThread at = ActivityThread.systemMain();
1259 mSystemThread = at;
1260 Context context = at.getSystemContext();
1261 m.mContext = context;
1262 m.mFactoryTest = factoryTest;
1263 PowerManager pm =
1264 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1265 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1266 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1267 m.mLaunchingActivity.setReferenceCounted(false);
1268
1269 m.mBatteryStatsService.publish(context);
1270 m.mUsageStatsService.publish(context);
1271
1272 synchronized (thr) {
1273 thr.mReady = true;
1274 thr.notifyAll();
1275 }
1276
1277 m.startRunning(null, null, null, null);
1278
1279 return context;
1280 }
1281
1282 public static ActivityManagerService self() {
1283 return mSelf;
1284 }
1285
1286 static class AThread extends Thread {
1287 ActivityManagerService mService;
1288 boolean mReady = false;
1289
1290 public AThread() {
1291 super("ActivityManager");
1292 }
1293
1294 public void run() {
1295 Looper.prepare();
1296
1297 android.os.Process.setThreadPriority(
1298 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1299
1300 ActivityManagerService m = new ActivityManagerService();
1301
1302 synchronized (this) {
1303 mService = m;
1304 notifyAll();
1305 }
1306
1307 synchronized (this) {
1308 while (!mReady) {
1309 try {
1310 wait();
1311 } catch (InterruptedException e) {
1312 }
1313 }
1314 }
1315
1316 Looper.loop();
1317 }
1318 }
1319
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001320 static class MemBinder extends Binder {
1321 ActivityManagerService mActivityManagerService;
1322 MemBinder(ActivityManagerService activityManagerService) {
1323 mActivityManagerService = activityManagerService;
1324 }
1325
1326 @Override
1327 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1328 ActivityManagerService service = mActivityManagerService;
1329 ArrayList<ProcessRecord> procs;
1330 synchronized (mActivityManagerService) {
1331 if (args != null && args.length > 0
1332 && args[0].charAt(0) != '-') {
1333 procs = new ArrayList<ProcessRecord>();
1334 int pid = -1;
1335 try {
1336 pid = Integer.parseInt(args[0]);
1337 } catch (NumberFormatException e) {
1338
1339 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001340 for (int i=service.mLruProcesses.size()-1; i>=0; i--) {
1341 ProcessRecord proc = service.mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001342 if (proc.pid == pid) {
1343 procs.add(proc);
1344 } else if (proc.processName.equals(args[0])) {
1345 procs.add(proc);
1346 }
1347 }
1348 if (procs.size() <= 0) {
1349 pw.println("No process found for: " + args[0]);
1350 return;
1351 }
1352 } else {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001353 procs = service.mLruProcesses;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001354 }
1355 }
1356 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1357 }
1358 }
1359
1360 static class CpuBinder extends Binder {
1361 ActivityManagerService mActivityManagerService;
1362 CpuBinder(ActivityManagerService activityManagerService) {
1363 mActivityManagerService = activityManagerService;
1364 }
1365
1366 @Override
1367 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1368 synchronized (mActivityManagerService.mProcessStatsThread) {
1369 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1370 }
1371 }
1372 }
1373
1374 private ActivityManagerService() {
1375 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1376 if (v != null && Integer.getInteger(v) != 0) {
1377 mSimpleProcessManagement = true;
1378 }
1379 v = System.getenv("ANDROID_DEBUG_APP");
1380 if (v != null) {
1381 mSimpleProcessManagement = true;
1382 }
1383
Dianne Hackborn2c6c5e62009-10-08 17:55:49 -07001384 Log.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
1385
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001386 MY_PID = Process.myPid();
1387
1388 File dataDir = Environment.getDataDirectory();
1389 File systemDir = new File(dataDir, "system");
1390 systemDir.mkdirs();
1391 mBatteryStatsService = new BatteryStatsService(new File(
1392 systemDir, "batterystats.bin").toString());
1393 mBatteryStatsService.getActiveStatistics().readLocked();
1394 mBatteryStatsService.getActiveStatistics().writeLocked();
1395
1396 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001397 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398
Jack Palevichb90d28c2009-07-22 15:35:24 -07001399 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1400 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1401
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001402 mConfiguration.makeDefault();
1403 mProcessStats.init();
1404
1405 // Add ourself to the Watchdog monitors.
1406 Watchdog.getInstance().addMonitor(this);
1407
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001408 mProcessStatsThread = new Thread("ProcessStats") {
1409 public void run() {
1410 while (true) {
1411 try {
1412 try {
1413 synchronized(this) {
1414 final long now = SystemClock.uptimeMillis();
1415 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1416 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1417 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1418 // + ", write delay=" + nextWriteDelay);
1419 if (nextWriteDelay < nextCpuDelay) {
1420 nextCpuDelay = nextWriteDelay;
1421 }
1422 if (nextCpuDelay > 0) {
1423 this.wait(nextCpuDelay);
1424 }
1425 }
1426 } catch (InterruptedException e) {
1427 }
1428
1429 updateCpuStatsNow();
1430 } catch (Exception e) {
1431 Log.e(TAG, "Unexpected exception collecting process stats", e);
1432 }
1433 }
1434 }
1435 };
1436 mProcessStatsThread.start();
1437 }
1438
1439 @Override
1440 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1441 throws RemoteException {
1442 try {
1443 return super.onTransact(code, data, reply, flags);
1444 } catch (RuntimeException e) {
1445 // The activity manager only throws security exceptions, so let's
1446 // log all others.
1447 if (!(e instanceof SecurityException)) {
1448 Log.e(TAG, "Activity Manager Crash", e);
1449 }
1450 throw e;
1451 }
1452 }
1453
1454 void updateCpuStats() {
1455 synchronized (mProcessStatsThread) {
1456 final long now = SystemClock.uptimeMillis();
1457 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1458 mProcessStatsThread.notify();
1459 }
1460 }
1461 }
1462
1463 void updateCpuStatsNow() {
1464 synchronized (mProcessStatsThread) {
1465 final long now = SystemClock.uptimeMillis();
1466 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001467
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001468 if (MONITOR_CPU_USAGE &&
1469 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1470 mLastCpuTime = now;
1471 haveNewCpuStats = true;
1472 mProcessStats.update();
1473 //Log.i(TAG, mProcessStats.printCurrentState());
1474 //Log.i(TAG, "Total CPU usage: "
1475 // + mProcessStats.getTotalCpuPercent() + "%");
1476
1477 // Log the cpu usage if the property is set.
1478 if ("true".equals(SystemProperties.get("events.cpu"))) {
1479 int user = mProcessStats.getLastUserTime();
1480 int system = mProcessStats.getLastSystemTime();
1481 int iowait = mProcessStats.getLastIoWaitTime();
1482 int irq = mProcessStats.getLastIrqTime();
1483 int softIrq = mProcessStats.getLastSoftIrqTime();
1484 int idle = mProcessStats.getLastIdleTime();
1485
1486 int total = user + system + iowait + irq + softIrq + idle;
1487 if (total == 0) total = 1;
1488
Doug Zongker2bec3d42009-12-04 12:52:44 -08001489 EventLog.writeEvent(EventLogTags.CPU,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001490 ((user+system+iowait+irq+softIrq) * 100) / total,
1491 (user * 100) / total,
1492 (system * 100) / total,
1493 (iowait * 100) / total,
1494 (irq * 100) / total,
1495 (softIrq * 100) / total);
1496 }
1497 }
1498
Amith Yamasanie43530a2009-08-21 13:11:37 -07001499 long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
Amith Yamasani819f9282009-06-24 23:18:15 -07001500 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001501 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001502 synchronized(mPidsSelfLocked) {
1503 if (haveNewCpuStats) {
1504 if (mBatteryStatsService.isOnBattery()) {
1505 final int N = mProcessStats.countWorkingStats();
1506 for (int i=0; i<N; i++) {
1507 ProcessStats.Stats st
1508 = mProcessStats.getWorkingStats(i);
1509 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1510 if (pr != null) {
1511 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1512 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001513 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001514 } else {
1515 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001516 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001517 if (ps != null) {
1518 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001519 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001520 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001521 }
1522 }
1523 }
1524 }
1525 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001526
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001527 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1528 mLastWriteTime = now;
1529 mBatteryStatsService.getActiveStatistics().writeLocked();
1530 }
1531 }
1532 }
1533 }
1534
1535 /**
1536 * Initialize the application bind args. These are passed to each
1537 * process when the bindApplication() IPC is sent to the process. They're
1538 * lazily setup to make sure the services are running when they're asked for.
1539 */
1540 private HashMap<String, IBinder> getCommonServicesLocked() {
1541 if (mAppBindArgs == null) {
1542 mAppBindArgs = new HashMap<String, IBinder>();
1543
1544 // Setup the application init args
1545 mAppBindArgs.put("package", ServiceManager.getService("package"));
1546 mAppBindArgs.put("window", ServiceManager.getService("window"));
1547 mAppBindArgs.put(Context.ALARM_SERVICE,
1548 ServiceManager.getService(Context.ALARM_SERVICE));
1549 }
1550 return mAppBindArgs;
1551 }
1552
1553 private final void setFocusedActivityLocked(HistoryRecord r) {
1554 if (mFocusedActivity != r) {
1555 mFocusedActivity = r;
1556 mWindowManager.setFocusedApp(r, true);
1557 }
1558 }
1559
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001560 private final void updateLruProcessLocked(ProcessRecord app,
1561 boolean oomAdj, boolean updateActivityTime) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001562 // put it on the LRU to keep track of when it should be exited.
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001563 int lrui = mLruProcesses.indexOf(app);
1564 if (lrui >= 0) mLruProcesses.remove(lrui);
1565
1566 int i = mLruProcesses.size()-1;
1567 int skipTop = 0;
1568
1569 // compute the new weight for this process.
1570 if (updateActivityTime) {
1571 app.lastActivityTime = SystemClock.uptimeMillis();
1572 }
1573 if (app.activities.size() > 0) {
1574 // If this process has activities, we more strongly want to keep
1575 // it around.
1576 app.lruWeight = app.lastActivityTime;
1577 } else if (app.pubProviders.size() > 0) {
1578 // If this process contains content providers, we want to keep
1579 // it a little more strongly.
1580 app.lruWeight = app.lastActivityTime - CONTENT_APP_IDLE_OFFSET;
1581 // Also don't let it kick out the first few "real" hidden processes.
1582 skipTop = MIN_HIDDEN_APPS;
1583 } else {
1584 // If this process doesn't have activities, we less strongly
1585 // want to keep it around, and generally want to avoid getting
1586 // in front of any very recently used activities.
1587 app.lruWeight = app.lastActivityTime - EMPTY_APP_IDLE_OFFSET;
1588 // Also don't let it kick out the first few "real" hidden processes.
1589 skipTop = MIN_HIDDEN_APPS;
1590 }
1591 while (i >= 0) {
1592 ProcessRecord p = mLruProcesses.get(i);
1593 // If this app shouldn't be in front of the first N background
1594 // apps, then skip over that many that are currently hidden.
1595 if (skipTop > 0 && p.setAdj >= HIDDEN_APP_MIN_ADJ) {
1596 skipTop--;
1597 }
1598 if (p.lruWeight <= app.lruWeight){
1599 mLruProcesses.add(i+1, app);
1600 break;
1601 }
1602 i--;
1603 }
1604 if (i < 0) {
1605 mLruProcesses.add(0, app);
1606 }
1607
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001608 //Log.i(TAG, "Putting proc to front: " + app.processName);
1609 if (oomAdj) {
1610 updateOomAdjLocked();
1611 }
1612 }
1613
1614 private final boolean updateLRUListLocked(HistoryRecord r) {
1615 final boolean hadit = mLRUActivities.remove(r);
1616 mLRUActivities.add(r);
1617 return hadit;
1618 }
1619
1620 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1621 int i = mHistory.size()-1;
1622 while (i >= 0) {
1623 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1624 if (!r.finishing && r != notTop) {
1625 return r;
1626 }
1627 i--;
1628 }
1629 return null;
1630 }
1631
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001632 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1633 int i = mHistory.size()-1;
1634 while (i >= 0) {
1635 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1636 if (!r.finishing && !r.delayedResume && r != notTop) {
1637 return r;
1638 }
1639 i--;
1640 }
1641 return null;
1642 }
1643
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001644 /**
1645 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001646 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001647 *
1648 * @param token If non-null, any history records matching this token will be skipped.
1649 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1650 *
1651 * @return Returns the HistoryRecord of the next activity on the stack.
1652 */
1653 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1654 int i = mHistory.size()-1;
1655 while (i >= 0) {
1656 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1657 // Note: the taskId check depends on real taskId fields being non-zero
1658 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1659 return r;
1660 }
1661 i--;
1662 }
1663 return null;
1664 }
1665
1666 private final ProcessRecord getProcessRecordLocked(
1667 String processName, int uid) {
1668 if (uid == Process.SYSTEM_UID) {
1669 // The system gets to run in any process. If there are multiple
1670 // processes with the same uid, just pick the first (this
1671 // should never happen).
1672 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1673 processName);
1674 return procs != null ? procs.valueAt(0) : null;
1675 }
1676 ProcessRecord proc = mProcessNames.get(processName, uid);
1677 return proc;
1678 }
1679
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001680 private void ensurePackageDexOpt(String packageName) {
1681 IPackageManager pm = ActivityThread.getPackageManager();
1682 try {
1683 if (pm.performDexOpt(packageName)) {
1684 mDidDexOpt = true;
1685 }
1686 } catch (RemoteException e) {
1687 }
1688 }
1689
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001690 private boolean isNextTransitionForward() {
1691 int transit = mWindowManager.getPendingAppTransition();
1692 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1693 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1694 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1695 }
1696
1697 private final boolean realStartActivityLocked(HistoryRecord r,
1698 ProcessRecord app, boolean andResume, boolean checkConfig)
1699 throws RemoteException {
1700
1701 r.startFreezingScreenLocked(app, 0);
1702 mWindowManager.setAppVisibility(r, true);
1703
1704 // Have the window manager re-evaluate the orientation of
1705 // the screen based on the new activity order. Note that
1706 // as a result of this, it can call back into the activity
1707 // manager with a new orientation. We don't care about that,
1708 // because the activity is not currently running so we are
1709 // just restarting it anyway.
1710 if (checkConfig) {
1711 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001712 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 r.mayFreezeScreenLocked(app) ? r : null);
1714 updateConfigurationLocked(config, r);
1715 }
1716
1717 r.app = app;
1718
1719 if (localLOGV) Log.v(TAG, "Launching: " + r);
1720
1721 int idx = app.activities.indexOf(r);
1722 if (idx < 0) {
1723 app.activities.add(r);
1724 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001725 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001726
1727 try {
1728 if (app.thread == null) {
1729 throw new RemoteException();
1730 }
1731 List<ResultInfo> results = null;
1732 List<Intent> newIntents = null;
1733 if (andResume) {
1734 results = r.results;
1735 newIntents = r.newIntents;
1736 }
1737 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1738 + " icicle=" + r.icicle
1739 + " with results=" + results + " newIntents=" + newIntents
1740 + " andResume=" + andResume);
1741 if (andResume) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08001742 EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001743 System.identityHashCode(r),
1744 r.task.taskId, r.shortComponentName);
1745 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001746 if (r.isHomeActivity) {
1747 mHomeProcess = app;
1748 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001749 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001750 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001751 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001752 r.info, r.icicle, results, newIntents, !andResume,
1753 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001754 } catch (RemoteException e) {
1755 if (r.launchFailed) {
1756 // This is the second time we failed -- finish activity
1757 // and give up.
1758 Log.e(TAG, "Second failure launching "
1759 + r.intent.getComponent().flattenToShortString()
1760 + ", giving up", e);
1761 appDiedLocked(app, app.pid, app.thread);
1762 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1763 "2nd-crash");
1764 return false;
1765 }
1766
1767 // This is the first time we failed -- restart process and
1768 // retry.
1769 app.activities.remove(r);
1770 throw e;
1771 }
1772
1773 r.launchFailed = false;
1774 if (updateLRUListLocked(r)) {
1775 Log.w(TAG, "Activity " + r
1776 + " being launched, but already in LRU list");
1777 }
1778
1779 if (andResume) {
1780 // As part of the process of launching, ActivityThread also performs
1781 // a resume.
1782 r.state = ActivityState.RESUMED;
1783 r.icicle = null;
1784 r.haveState = false;
1785 r.stopped = false;
1786 mResumedActivity = r;
1787 r.task.touchActiveTime();
1788 completeResumeLocked(r);
1789 pauseIfSleepingLocked();
1790 } else {
1791 // This activity is not starting in the resumed state... which
1792 // should look like we asked it to pause+stop (but remain visible),
1793 // and it has done so and reported back the current icicle and
1794 // other state.
1795 r.state = ActivityState.STOPPED;
1796 r.stopped = true;
1797 }
1798
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001799 // Launch the new version setup screen if needed. We do this -after-
1800 // launching the initial activity (that is, home), so that it can have
1801 // a chance to initialize itself while in the background, making the
1802 // switch back to it faster and look better.
1803 startSetupActivityLocked();
1804
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001805 return true;
1806 }
1807
1808 private final void startSpecificActivityLocked(HistoryRecord r,
1809 boolean andResume, boolean checkConfig) {
1810 // Is this activity's application already running?
1811 ProcessRecord app = getProcessRecordLocked(r.processName,
1812 r.info.applicationInfo.uid);
1813
1814 if (r.startTime == 0) {
1815 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001816 if (mInitialStartTime == 0) {
1817 mInitialStartTime = r.startTime;
1818 }
1819 } else if (mInitialStartTime == 0) {
1820 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001821 }
1822
1823 if (app != null && app.thread != null) {
1824 try {
1825 realStartActivityLocked(r, app, andResume, checkConfig);
1826 return;
1827 } catch (RemoteException e) {
1828 Log.w(TAG, "Exception when starting activity "
1829 + r.intent.getComponent().flattenToShortString(), e);
1830 }
1831
1832 // If a dead object exception was thrown -- fall through to
1833 // restart the application.
1834 }
1835
1836 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001837 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001838 }
1839
1840 private final ProcessRecord startProcessLocked(String processName,
1841 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001842 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001843 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1844 // We don't have to do anything more if:
1845 // (1) There is an existing application record; and
1846 // (2) The caller doesn't think it is dead, OR there is no thread
1847 // object attached to it so we know it couldn't have crashed; and
1848 // (3) There is a pid assigned to it, so it is either starting or
1849 // already running.
1850 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1851 + " app=" + app + " knownToBeDead=" + knownToBeDead
1852 + " thread=" + (app != null ? app.thread : null)
1853 + " pid=" + (app != null ? app.pid : -1));
1854 if (app != null &&
1855 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1856 return app;
1857 }
1858
1859 String hostingNameStr = hostingName != null
1860 ? hostingName.flattenToShortString() : null;
1861
1862 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1863 // If we are in the background, then check to see if this process
1864 // is bad. If so, we will just silently fail.
1865 if (mBadProcesses.get(info.processName, info.uid) != null) {
1866 return null;
1867 }
1868 } else {
1869 // When the user is explicitly starting a process, then clear its
1870 // crash count so that we won't make it bad until they see at
1871 // least one crash dialog again, and make the process good again
1872 // if it had been bad.
1873 mProcessCrashTimes.remove(info.processName, info.uid);
1874 if (mBadProcesses.get(info.processName, info.uid) != null) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08001875 EventLog.writeEvent(EventLogTags.AM_PROC_GOOD, info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001876 info.processName);
1877 mBadProcesses.remove(info.processName, info.uid);
1878 if (app != null) {
1879 app.bad = false;
1880 }
1881 }
1882 }
1883
1884 if (app == null) {
1885 app = newProcessRecordLocked(null, info, processName);
1886 mProcessNames.put(processName, info.uid, app);
1887 } else {
1888 // If this is a new package in the process, add the package to the list
1889 app.addPackage(info.packageName);
1890 }
1891
1892 // If the system is not ready yet, then hold off on starting this
1893 // process until it is.
1894 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001895 && !isAllowedWhileBooting(info)
1896 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001897 if (!mProcessesOnHold.contains(app)) {
1898 mProcessesOnHold.add(app);
1899 }
1900 return app;
1901 }
1902
1903 startProcessLocked(app, hostingType, hostingNameStr);
1904 return (app.pid != 0) ? app : null;
1905 }
1906
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001907 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1908 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1909 }
1910
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001911 private final void startProcessLocked(ProcessRecord app,
1912 String hostingType, String hostingNameStr) {
1913 if (app.pid > 0 && app.pid != MY_PID) {
1914 synchronized (mPidsSelfLocked) {
1915 mPidsSelfLocked.remove(app.pid);
1916 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1917 }
1918 app.pid = 0;
1919 }
1920
1921 mProcessesOnHold.remove(app);
1922
1923 updateCpuStats();
1924
1925 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1926 mProcDeaths[0] = 0;
1927
1928 try {
1929 int uid = app.info.uid;
1930 int[] gids = null;
1931 try {
1932 gids = mContext.getPackageManager().getPackageGids(
1933 app.info.packageName);
1934 } catch (PackageManager.NameNotFoundException e) {
1935 Log.w(TAG, "Unable to retrieve gids", e);
1936 }
1937 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1938 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1939 && mTopComponent != null
1940 && app.processName.equals(mTopComponent.getPackageName())) {
1941 uid = 0;
1942 }
1943 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1944 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1945 uid = 0;
1946 }
1947 }
1948 int debugFlags = 0;
1949 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1950 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1951 }
1952 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1953 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1954 }
1955 if ("1".equals(SystemProperties.get("debug.assert"))) {
1956 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1957 }
1958 int pid = Process.start("android.app.ActivityThread",
1959 mSimpleProcessManagement ? app.processName : null, uid, uid,
1960 gids, debugFlags, null);
1961 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1962 synchronized (bs) {
1963 if (bs.isOnBattery()) {
1964 app.batteryStats.incStartsLocked();
1965 }
1966 }
1967
Doug Zongker2bec3d42009-12-04 12:52:44 -08001968 EventLog.writeEvent(EventLogTags.AM_PROC_START, pid, uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001969 app.processName, hostingType,
1970 hostingNameStr != null ? hostingNameStr : "");
1971
1972 if (app.persistent) {
1973 Watchdog.getInstance().processStarted(app, app.processName, pid);
1974 }
1975
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001976 StringBuilder buf = mStringBuilder;
1977 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001978 buf.append("Start proc ");
1979 buf.append(app.processName);
1980 buf.append(" for ");
1981 buf.append(hostingType);
1982 if (hostingNameStr != null) {
1983 buf.append(" ");
1984 buf.append(hostingNameStr);
1985 }
1986 buf.append(": pid=");
1987 buf.append(pid);
1988 buf.append(" uid=");
1989 buf.append(uid);
1990 buf.append(" gids={");
1991 if (gids != null) {
1992 for (int gi=0; gi<gids.length; gi++) {
1993 if (gi != 0) buf.append(", ");
1994 buf.append(gids[gi]);
1995
1996 }
1997 }
1998 buf.append("}");
1999 Log.i(TAG, buf.toString());
2000 if (pid == 0 || pid == MY_PID) {
2001 // Processes are being emulated with threads.
2002 app.pid = MY_PID;
2003 app.removed = false;
2004 mStartingProcesses.add(app);
2005 } else if (pid > 0) {
2006 app.pid = pid;
2007 app.removed = false;
2008 synchronized (mPidsSelfLocked) {
2009 this.mPidsSelfLocked.put(pid, app);
2010 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2011 msg.obj = app;
2012 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2013 }
2014 } else {
2015 app.pid = 0;
2016 RuntimeException e = new RuntimeException(
2017 "Failure starting process " + app.processName
2018 + ": returned pid=" + pid);
2019 Log.e(TAG, e.getMessage(), e);
2020 }
2021 } catch (RuntimeException e) {
2022 // XXX do better error recovery.
2023 app.pid = 0;
2024 Log.e(TAG, "Failure starting process " + app.processName, e);
2025 }
2026 }
2027
2028 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2029 if (mPausingActivity != null) {
2030 RuntimeException e = new RuntimeException();
2031 Log.e(TAG, "Trying to pause when pause is already pending for "
2032 + mPausingActivity, e);
2033 }
2034 HistoryRecord prev = mResumedActivity;
2035 if (prev == null) {
2036 RuntimeException e = new RuntimeException();
2037 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2038 resumeTopActivityLocked(null);
2039 return;
2040 }
2041 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2042 mResumedActivity = null;
2043 mPausingActivity = prev;
2044 mLastPausedActivity = prev;
2045 prev.state = ActivityState.PAUSING;
2046 prev.task.touchActiveTime();
2047
2048 updateCpuStats();
2049
2050 if (prev.app != null && prev.app.thread != null) {
2051 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2052 try {
Doug Zongker2bec3d42009-12-04 12:52:44 -08002053 EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002054 System.identityHashCode(prev),
2055 prev.shortComponentName);
2056 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2057 prev.configChangeFlags);
2058 updateUsageStats(prev, false);
2059 } catch (Exception e) {
2060 // Ignore exception, if process died other code will cleanup.
2061 Log.w(TAG, "Exception thrown during pause", e);
2062 mPausingActivity = null;
2063 mLastPausedActivity = null;
2064 }
2065 } else {
2066 mPausingActivity = null;
2067 mLastPausedActivity = null;
2068 }
2069
2070 // If we are not going to sleep, we want to ensure the device is
2071 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002072 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002073 mLaunchingActivity.acquire();
2074 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2075 // To be safe, don't allow the wake lock to be held for too long.
2076 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2077 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2078 }
2079 }
2080
2081
2082 if (mPausingActivity != null) {
2083 // Have the window manager pause its key dispatching until the new
2084 // activity has started. If we're pausing the activity just because
2085 // the screen is being turned off and the UI is sleeping, don't interrupt
2086 // key dispatch; the same activity will pick it up again on wakeup.
2087 if (!uiSleeping) {
2088 prev.pauseKeyDispatchingLocked();
2089 } else {
2090 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2091 }
2092
2093 // Schedule a pause timeout in case the app doesn't respond.
2094 // We don't give it much time because this directly impacts the
2095 // responsiveness seen by the user.
2096 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2097 msg.obj = prev;
2098 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2099 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2100 } else {
2101 // This activity failed to schedule the
2102 // pause, so just treat it as being paused now.
2103 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2104 resumeTopActivityLocked(null);
2105 }
2106 }
2107
2108 private final void completePauseLocked() {
2109 HistoryRecord prev = mPausingActivity;
2110 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2111
2112 if (prev != null) {
2113 if (prev.finishing) {
2114 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2115 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2116 } else if (prev.app != null) {
2117 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2118 if (prev.waitingVisible) {
2119 prev.waitingVisible = false;
2120 mWaitingVisibleActivities.remove(prev);
2121 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2122 TAG, "Complete pause, no longer waiting: " + prev);
2123 }
2124 if (prev.configDestroy) {
2125 // The previous is being paused because the configuration
2126 // is changing, which means it is actually stopping...
2127 // To juggle the fact that we are also starting a new
2128 // instance right now, we need to first completely stop
2129 // the current instance before starting the new one.
2130 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2131 destroyActivityLocked(prev, true);
2132 } else {
2133 mStoppingActivities.add(prev);
2134 if (mStoppingActivities.size() > 3) {
2135 // If we already have a few activities waiting to stop,
2136 // then give up on things going idle and start clearing
2137 // them out.
2138 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2139 Message msg = Message.obtain();
2140 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2141 mHandler.sendMessage(msg);
2142 }
2143 }
2144 } else {
2145 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2146 prev = null;
2147 }
2148 mPausingActivity = null;
2149 }
2150
Dianne Hackborn55280a92009-05-07 15:53:46 -07002151 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002152 resumeTopActivityLocked(prev);
2153 } else {
2154 if (mGoingToSleep.isHeld()) {
2155 mGoingToSleep.release();
2156 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002157 if (mShuttingDown) {
2158 notifyAll();
2159 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002160 }
2161
2162 if (prev != null) {
2163 prev.resumeKeyDispatchingLocked();
2164 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002165
2166 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2167 long diff = 0;
2168 synchronized (mProcessStatsThread) {
2169 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2170 }
2171 if (diff > 0) {
2172 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2173 synchronized (bsi) {
2174 BatteryStatsImpl.Uid.Proc ps =
2175 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2176 prev.info.packageName);
2177 if (ps != null) {
2178 ps.addForegroundTimeLocked(diff);
2179 }
2180 }
2181 }
2182 }
2183 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002184 }
2185
2186 /**
2187 * Once we know that we have asked an application to put an activity in
2188 * the resumed state (either by launching it or explicitly telling it),
2189 * this function updates the rest of our state to match that fact.
2190 */
2191 private final void completeResumeLocked(HistoryRecord next) {
2192 next.idle = false;
2193 next.results = null;
2194 next.newIntents = null;
2195
2196 // schedule an idle timeout in case the app doesn't do it for us.
2197 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2198 msg.obj = next;
2199 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2200
2201 if (false) {
2202 // The activity was never told to pause, so just keep
2203 // things going as-is. To maintain our own state,
2204 // we need to emulate it coming back and saying it is
2205 // idle.
2206 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2207 msg.obj = next;
2208 mHandler.sendMessage(msg);
2209 }
2210
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002211 reportResumedActivityLocked(next);
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002212
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002213 next.thumbnail = null;
2214 setFocusedActivityLocked(next);
2215 next.resumeKeyDispatchingLocked();
2216 ensureActivitiesVisibleLocked(null, 0);
2217 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002218 mNoAnimActivities.clear();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002219
2220 // Mark the point when the activity is resuming
2221 // TODO: To be more accurate, the mark should be before the onCreate,
2222 // not after the onResume. But for subsequent starts, onResume is fine.
2223 if (next.app != null) {
2224 synchronized (mProcessStatsThread) {
2225 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2226 }
2227 } else {
2228 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2229 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002230 }
2231
2232 /**
2233 * Make sure that all activities that need to be visible (that is, they
2234 * currently can be seen by the user) actually are.
2235 */
2236 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2237 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2238 if (DEBUG_VISBILITY) Log.v(
2239 TAG, "ensureActivitiesVisible behind " + top
2240 + " configChanges=0x" + Integer.toHexString(configChanges));
2241
2242 // If the top activity is not fullscreen, then we need to
2243 // make sure any activities under it are now visible.
2244 final int count = mHistory.size();
2245 int i = count-1;
2246 while (mHistory.get(i) != top) {
2247 i--;
2248 }
2249 HistoryRecord r;
2250 boolean behindFullscreen = false;
2251 for (; i>=0; i--) {
2252 r = (HistoryRecord)mHistory.get(i);
2253 if (DEBUG_VISBILITY) Log.v(
2254 TAG, "Make visible? " + r + " finishing=" + r.finishing
2255 + " state=" + r.state);
2256 if (r.finishing) {
2257 continue;
2258 }
2259
2260 final boolean doThisProcess = onlyThisProcess == null
2261 || onlyThisProcess.equals(r.processName);
2262
2263 // First: if this is not the current activity being started, make
2264 // sure it matches the current configuration.
2265 if (r != starting && doThisProcess) {
2266 ensureActivityConfigurationLocked(r, 0);
2267 }
2268
2269 if (r.app == null || r.app.thread == null) {
2270 if (onlyThisProcess == null
2271 || onlyThisProcess.equals(r.processName)) {
2272 // This activity needs to be visible, but isn't even
2273 // running... get it started, but don't resume it
2274 // at this point.
2275 if (DEBUG_VISBILITY) Log.v(
2276 TAG, "Start and freeze screen for " + r);
2277 if (r != starting) {
2278 r.startFreezingScreenLocked(r.app, configChanges);
2279 }
2280 if (!r.visible) {
2281 if (DEBUG_VISBILITY) Log.v(
2282 TAG, "Starting and making visible: " + r);
2283 mWindowManager.setAppVisibility(r, true);
2284 }
2285 if (r != starting) {
2286 startSpecificActivityLocked(r, false, false);
2287 }
2288 }
2289
2290 } else if (r.visible) {
2291 // If this activity is already visible, then there is nothing
2292 // else to do here.
2293 if (DEBUG_VISBILITY) Log.v(
2294 TAG, "Skipping: already visible at " + r);
2295 r.stopFreezingScreenLocked(false);
2296
2297 } else if (onlyThisProcess == null) {
2298 // This activity is not currently visible, but is running.
2299 // Tell it to become visible.
2300 r.visible = true;
2301 if (r.state != ActivityState.RESUMED && r != starting) {
2302 // If this activity is paused, tell it
2303 // to now show its window.
2304 if (DEBUG_VISBILITY) Log.v(
2305 TAG, "Making visible and scheduling visibility: " + r);
2306 try {
2307 mWindowManager.setAppVisibility(r, true);
2308 r.app.thread.scheduleWindowVisibility(r, true);
2309 r.stopFreezingScreenLocked(false);
2310 } catch (Exception e) {
2311 // Just skip on any failure; we'll make it
2312 // visible when it next restarts.
2313 Log.w(TAG, "Exception thrown making visibile: "
2314 + r.intent.getComponent(), e);
2315 }
2316 }
2317 }
2318
2319 // Aggregate current change flags.
2320 configChanges |= r.configChangeFlags;
2321
2322 if (r.fullscreen) {
2323 // At this point, nothing else needs to be shown
2324 if (DEBUG_VISBILITY) Log.v(
2325 TAG, "Stopping: fullscreen at " + r);
2326 behindFullscreen = true;
2327 i--;
2328 break;
2329 }
2330 }
2331
2332 // Now for any activities that aren't visible to the user, make
2333 // sure they no longer are keeping the screen frozen.
2334 while (i >= 0) {
2335 r = (HistoryRecord)mHistory.get(i);
2336 if (DEBUG_VISBILITY) Log.v(
2337 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2338 + " state=" + r.state
2339 + " behindFullscreen=" + behindFullscreen);
2340 if (!r.finishing) {
2341 if (behindFullscreen) {
2342 if (r.visible) {
2343 if (DEBUG_VISBILITY) Log.v(
2344 TAG, "Making invisible: " + r);
2345 r.visible = false;
2346 try {
2347 mWindowManager.setAppVisibility(r, false);
2348 if ((r.state == ActivityState.STOPPING
2349 || r.state == ActivityState.STOPPED)
2350 && r.app != null && r.app.thread != null) {
2351 if (DEBUG_VISBILITY) Log.v(
2352 TAG, "Scheduling invisibility: " + r);
2353 r.app.thread.scheduleWindowVisibility(r, false);
2354 }
2355 } catch (Exception e) {
2356 // Just skip on any failure; we'll make it
2357 // visible when it next restarts.
2358 Log.w(TAG, "Exception thrown making hidden: "
2359 + r.intent.getComponent(), e);
2360 }
2361 } else {
2362 if (DEBUG_VISBILITY) Log.v(
2363 TAG, "Already invisible: " + r);
2364 }
2365 } else if (r.fullscreen) {
2366 if (DEBUG_VISBILITY) Log.v(
2367 TAG, "Now behindFullscreen: " + r);
2368 behindFullscreen = true;
2369 }
2370 }
2371 i--;
2372 }
2373 }
2374
2375 /**
2376 * Version of ensureActivitiesVisible that can easily be called anywhere.
2377 */
2378 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2379 int configChanges) {
2380 HistoryRecord r = topRunningActivityLocked(null);
2381 if (r != null) {
2382 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2383 }
2384 }
2385
2386 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2387 if (resumed) {
2388 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2389 } else {
2390 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2391 }
2392 }
2393
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002394 private boolean startHomeActivityLocked() {
2395 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2396 && mTopAction == null) {
2397 // We are running in factory test mode, but unable to find
2398 // the factory test app, so just sit around displaying the
2399 // error message and don't try to start anything.
2400 return false;
2401 }
2402 Intent intent = new Intent(
2403 mTopAction,
2404 mTopData != null ? Uri.parse(mTopData) : null);
2405 intent.setComponent(mTopComponent);
2406 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2407 intent.addCategory(Intent.CATEGORY_HOME);
2408 }
2409 ActivityInfo aInfo =
2410 intent.resolveActivityInfo(mContext.getPackageManager(),
2411 STOCK_PM_FLAGS);
2412 if (aInfo != null) {
2413 intent.setComponent(new ComponentName(
2414 aInfo.applicationInfo.packageName, aInfo.name));
2415 // Don't do this if the home app is currently being
2416 // instrumented.
2417 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2418 aInfo.applicationInfo.uid);
2419 if (app == null || app.instrumentationClass == null) {
2420 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2421 startActivityLocked(null, intent, null, null, 0, aInfo,
2422 null, null, 0, 0, 0, false, false);
2423 }
2424 }
2425
2426
2427 return true;
2428 }
2429
2430 /**
2431 * Starts the "new version setup screen" if appropriate.
2432 */
2433 private void startSetupActivityLocked() {
2434 // Only do this once per boot.
2435 if (mCheckedForSetup) {
2436 return;
2437 }
2438
2439 // We will show this screen if the current one is a different
2440 // version than the last one shown, and we are not running in
2441 // low-level factory test mode.
2442 final ContentResolver resolver = mContext.getContentResolver();
2443 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2444 Settings.Secure.getInt(resolver,
2445 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2446 mCheckedForSetup = true;
2447
2448 // See if we should be showing the platform update setup UI.
2449 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2450 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2451 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2452
2453 // We don't allow third party apps to replace this.
2454 ResolveInfo ri = null;
2455 for (int i=0; ris != null && i<ris.size(); i++) {
2456 if ((ris.get(i).activityInfo.applicationInfo.flags
2457 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2458 ri = ris.get(i);
2459 break;
2460 }
2461 }
2462
2463 if (ri != null) {
2464 String vers = ri.activityInfo.metaData != null
2465 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2466 : null;
2467 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2468 vers = ri.activityInfo.applicationInfo.metaData.getString(
2469 Intent.METADATA_SETUP_VERSION);
2470 }
2471 String lastVers = Settings.Secure.getString(
2472 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2473 if (vers != null && !vers.equals(lastVers)) {
2474 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2475 intent.setComponent(new ComponentName(
2476 ri.activityInfo.packageName, ri.activityInfo.name));
2477 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2478 null, null, 0, 0, 0, false, false);
2479 }
2480 }
2481 }
2482 }
2483
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002484 private void reportResumedActivityLocked(HistoryRecord r) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002485 //Log.i(TAG, "**** REPORT RESUME: " + r);
2486
2487 final int identHash = System.identityHashCode(r);
2488 updateUsageStats(r, true);
2489
2490 int i = mWatchers.beginBroadcast();
2491 while (i > 0) {
2492 i--;
2493 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2494 if (w != null) {
2495 try {
2496 w.activityResuming(identHash);
2497 } catch (RemoteException e) {
2498 }
2499 }
2500 }
2501 mWatchers.finishBroadcast();
2502 }
2503
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002504 /**
2505 * Ensure that the top activity in the stack is resumed.
2506 *
2507 * @param prev The previously resumed activity, for when in the process
2508 * of pausing; can be null to call from elsewhere.
2509 *
2510 * @return Returns true if something is being resumed, or false if
2511 * nothing happened.
2512 */
2513 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2514 // Find the first activity that is not finishing.
2515 HistoryRecord next = topRunningActivityLocked(null);
2516
2517 // Remember how we'll process this pause/resume situation, and ensure
2518 // that the state is reset however we wind up proceeding.
2519 final boolean userLeaving = mUserLeaving;
2520 mUserLeaving = false;
2521
2522 if (next == null) {
2523 // There are no more activities! Let's just start up the
2524 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002525 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002526 }
2527
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002528 next.delayedResume = false;
2529
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002530 // If the top activity is the resumed one, nothing to do.
2531 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2532 // Make sure we have executed any pending transitions, since there
2533 // should be nothing left to do at this point.
2534 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002535 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002536 return false;
2537 }
2538
2539 // If we are sleeping, and there is no resumed activity, and the top
2540 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002541 if ((mSleeping || mShuttingDown)
2542 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002543 // Make sure we have executed any pending transitions, since there
2544 // should be nothing left to do at this point.
2545 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002546 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002547 return false;
2548 }
2549
2550 // The activity may be waiting for stop, but that is no longer
2551 // appropriate for it.
2552 mStoppingActivities.remove(next);
2553 mWaitingVisibleActivities.remove(next);
2554
2555 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2556
2557 // If we are currently pausing an activity, then don't do anything
2558 // until that is done.
2559 if (mPausingActivity != null) {
2560 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2561 return false;
2562 }
2563
2564 // We need to start pausing the current activity so the top one
2565 // can be resumed...
2566 if (mResumedActivity != null) {
2567 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2568 startPausingLocked(userLeaving, false);
2569 return true;
2570 }
2571
2572 if (prev != null && prev != next) {
2573 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2574 prev.waitingVisible = true;
2575 mWaitingVisibleActivities.add(prev);
2576 if (DEBUG_SWITCH) Log.v(
2577 TAG, "Resuming top, waiting visible to hide: " + prev);
2578 } else {
2579 // The next activity is already visible, so hide the previous
2580 // activity's windows right now so we can show the new one ASAP.
2581 // We only do this if the previous is finishing, which should mean
2582 // it is on top of the one being resumed so hiding it quickly
2583 // is good. Otherwise, we want to do the normal route of allowing
2584 // the resumed activity to be shown so we can decide if the
2585 // previous should actually be hidden depending on whether the
2586 // new one is found to be full-screen or not.
2587 if (prev.finishing) {
2588 mWindowManager.setAppVisibility(prev, false);
2589 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2590 + prev + ", waitingVisible="
2591 + (prev != null ? prev.waitingVisible : null)
2592 + ", nowVisible=" + next.nowVisible);
2593 } else {
2594 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2595 + prev + ", waitingVisible="
2596 + (prev != null ? prev.waitingVisible : null)
2597 + ", nowVisible=" + next.nowVisible);
2598 }
2599 }
2600 }
2601
2602 // We are starting up the next activity, so tell the window manager
2603 // that the previous one will be hidden soon. This way it can know
2604 // to ignore it when computing the desired screen orientation.
2605 if (prev != null) {
2606 if (prev.finishing) {
2607 if (DEBUG_TRANSITION) Log.v(TAG,
2608 "Prepare close transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002609 if (mNoAnimActivities.contains(prev)) {
2610 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2611 } else {
2612 mWindowManager.prepareAppTransition(prev.task == next.task
2613 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2614 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2615 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002616 mWindowManager.setAppWillBeHidden(prev);
2617 mWindowManager.setAppVisibility(prev, false);
2618 } else {
2619 if (DEBUG_TRANSITION) Log.v(TAG,
2620 "Prepare open transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002621 if (mNoAnimActivities.contains(next)) {
2622 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2623 } else {
2624 mWindowManager.prepareAppTransition(prev.task == next.task
2625 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2626 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2627 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002628 }
2629 if (false) {
2630 mWindowManager.setAppWillBeHidden(prev);
2631 mWindowManager.setAppVisibility(prev, false);
2632 }
2633 } else if (mHistory.size() > 1) {
2634 if (DEBUG_TRANSITION) Log.v(TAG,
2635 "Prepare open transition: no previous");
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002636 if (mNoAnimActivities.contains(next)) {
2637 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2638 } else {
2639 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2640 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002641 }
2642
2643 if (next.app != null && next.app.thread != null) {
2644 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2645
2646 // This activity is now becoming visible.
2647 mWindowManager.setAppVisibility(next, true);
2648
2649 HistoryRecord lastResumedActivity = mResumedActivity;
2650 ActivityState lastState = next.state;
2651
2652 updateCpuStats();
2653
2654 next.state = ActivityState.RESUMED;
2655 mResumedActivity = next;
2656 next.task.touchActiveTime();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08002657 updateLruProcessLocked(next.app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002658 updateLRUListLocked(next);
2659
2660 // Have the window manager re-evaluate the orientation of
2661 // the screen based on the new activity order.
Eric Fischerd4d04de2009-10-27 18:55:57 -07002662 boolean updated;
2663 synchronized (this) {
2664 Configuration config = mWindowManager.updateOrientationFromAppTokens(
2665 mConfiguration,
2666 next.mayFreezeScreenLocked(next.app) ? next : null);
2667 if (config != null) {
2668 /*
2669 * Explicitly restore the locale to the one from the
2670 * old configuration, since the one that comes back from
2671 * the window manager has the default (boot) locale.
2672 *
2673 * It looks like previously the locale picker only worked
2674 * by coincidence: usually it would do its setting of
2675 * the locale after the activity transition, so it didn't
2676 * matter that this lost it. With the synchronized
2677 * block now keeping them from happening at the same time,
2678 * this one always would happen second and undo what the
2679 * locale picker had just done.
2680 */
2681 config.locale = mConfiguration.locale;
2682 next.frozenBeforeDestroy = true;
2683 }
2684 updated = updateConfigurationLocked(config, next);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002685 }
Eric Fischerd4d04de2009-10-27 18:55:57 -07002686 if (!updated) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002687 // The configuration update wasn't able to keep the existing
2688 // instance of the activity, and instead started a new one.
2689 // We should be all done, but let's just make sure our activity
2690 // is still at the top and schedule another run if something
2691 // weird happened.
2692 HistoryRecord nextNext = topRunningActivityLocked(null);
2693 if (DEBUG_SWITCH) Log.i(TAG,
2694 "Activity config changed during resume: " + next
2695 + ", new next: " + nextNext);
2696 if (nextNext != next) {
2697 // Do over!
2698 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2699 }
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07002700 setFocusedActivityLocked(next);
2701 ensureActivitiesVisibleLocked(null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002702 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002703 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002704 return true;
2705 }
2706
2707 try {
2708 // Deliver all pending results.
2709 ArrayList a = next.results;
2710 if (a != null) {
2711 final int N = a.size();
2712 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002713 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002714 TAG, "Delivering results to " + next
2715 + ": " + a);
2716 next.app.thread.scheduleSendResult(next, a);
2717 }
2718 }
2719
2720 if (next.newIntents != null) {
2721 next.app.thread.scheduleNewIntent(next.newIntents, next);
2722 }
2723
Doug Zongker2bec3d42009-12-04 12:52:44 -08002724 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002725 System.identityHashCode(next),
2726 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002727
2728 next.app.thread.scheduleResumeActivity(next,
2729 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002730
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002731 pauseIfSleepingLocked();
2732
2733 } catch (Exception e) {
2734 // Whoops, need to restart this activity!
2735 next.state = lastState;
2736 mResumedActivity = lastResumedActivity;
2737 if (Config.LOGD) Log.d(TAG,
2738 "Restarting because process died: " + next);
2739 if (!next.hasBeenLaunched) {
2740 next.hasBeenLaunched = true;
2741 } else {
2742 if (SHOW_APP_STARTING_ICON) {
2743 mWindowManager.setAppStartingWindow(
2744 next, next.packageName, next.theme,
2745 next.nonLocalizedLabel,
2746 next.labelRes, next.icon, null, true);
2747 }
2748 }
2749 startSpecificActivityLocked(next, true, false);
2750 return true;
2751 }
2752
2753 // From this point on, if something goes wrong there is no way
2754 // to recover the activity.
2755 try {
2756 next.visible = true;
2757 completeResumeLocked(next);
2758 } catch (Exception e) {
2759 // If any exception gets thrown, toss away this
2760 // activity and try the next one.
2761 Log.w(TAG, "Exception thrown during resume of " + next, e);
2762 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2763 "resume-exception");
2764 return true;
2765 }
2766
2767 // Didn't need to use the icicle, and it is now out of date.
2768 next.icicle = null;
2769 next.haveState = false;
2770 next.stopped = false;
2771
2772 } else {
2773 // Whoops, need to restart this activity!
2774 if (!next.hasBeenLaunched) {
2775 next.hasBeenLaunched = true;
2776 } else {
2777 if (SHOW_APP_STARTING_ICON) {
2778 mWindowManager.setAppStartingWindow(
2779 next, next.packageName, next.theme,
2780 next.nonLocalizedLabel,
2781 next.labelRes, next.icon, null, true);
2782 }
2783 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2784 }
2785 startSpecificActivityLocked(next, true, true);
2786 }
2787
2788 return true;
2789 }
2790
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002791 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2792 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002793 final int NH = mHistory.size();
2794
2795 int addPos = -1;
2796
2797 if (!newTask) {
2798 // If starting in an existing task, find where that is...
2799 HistoryRecord next = null;
2800 boolean startIt = true;
2801 for (int i = NH-1; i >= 0; i--) {
2802 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2803 if (p.finishing) {
2804 continue;
2805 }
2806 if (p.task == r.task) {
2807 // Here it is! Now, if this is not yet visible to the
2808 // user, then just add it without starting; it will
2809 // get started when the user navigates back to it.
2810 addPos = i+1;
2811 if (!startIt) {
2812 mHistory.add(addPos, r);
2813 r.inHistory = true;
2814 r.task.numActivities++;
2815 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2816 r.info.screenOrientation, r.fullscreen);
2817 if (VALIDATE_TOKENS) {
2818 mWindowManager.validateAppTokens(mHistory);
2819 }
2820 return;
2821 }
2822 break;
2823 }
2824 if (p.fullscreen) {
2825 startIt = false;
2826 }
2827 next = p;
2828 }
2829 }
2830
2831 // Place a new activity at top of stack, so it is next to interact
2832 // with the user.
2833 if (addPos < 0) {
2834 addPos = mHistory.size();
2835 }
2836
2837 // If we are not placing the new activity frontmost, we do not want
2838 // to deliver the onUserLeaving callback to the actual frontmost
2839 // activity
2840 if (addPos < NH) {
2841 mUserLeaving = false;
2842 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2843 }
2844
2845 // Slot the activity into the history stack and proceed
2846 mHistory.add(addPos, r);
2847 r.inHistory = true;
2848 r.frontOfTask = newTask;
2849 r.task.numActivities++;
2850 if (NH > 0) {
2851 // We want to show the starting preview window if we are
2852 // switching to a new task, or the next activity's process is
2853 // not currently running.
2854 boolean showStartingIcon = newTask;
2855 ProcessRecord proc = r.app;
2856 if (proc == null) {
2857 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2858 }
2859 if (proc == null || proc.thread == null) {
2860 showStartingIcon = true;
2861 }
2862 if (DEBUG_TRANSITION) Log.v(TAG,
2863 "Prepare open transition: starting " + r);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002864 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
2865 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2866 mNoAnimActivities.add(r);
2867 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
2868 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
2869 mNoAnimActivities.remove(r);
2870 } else {
2871 mWindowManager.prepareAppTransition(newTask
2872 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2873 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2874 mNoAnimActivities.remove(r);
2875 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002876 mWindowManager.addAppToken(
2877 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2878 boolean doShow = true;
2879 if (newTask) {
2880 // Even though this activity is starting fresh, we still need
2881 // to reset it to make sure we apply affinities to move any
2882 // existing activities from other tasks in to it.
2883 // If the caller has requested that the target task be
2884 // reset, then do so.
2885 if ((r.intent.getFlags()
2886 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2887 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002888 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002889 }
2890 }
2891 if (SHOW_APP_STARTING_ICON && doShow) {
2892 // Figure out if we are transitioning from another activity that is
2893 // "has the same starting icon" as the next one. This allows the
2894 // window manager to keep the previous window it had previously
2895 // created, if it still had one.
2896 HistoryRecord prev = mResumedActivity;
2897 if (prev != null) {
2898 // We don't want to reuse the previous starting preview if:
2899 // (1) The current activity is in a different task.
2900 if (prev.task != r.task) prev = null;
2901 // (2) The current activity is already displayed.
2902 else if (prev.nowVisible) prev = null;
2903 }
2904 mWindowManager.setAppStartingWindow(
2905 r, r.packageName, r.theme, r.nonLocalizedLabel,
2906 r.labelRes, r.icon, prev, showStartingIcon);
2907 }
2908 } else {
2909 // If this is the first activity, don't do any fancy animations,
2910 // because there is nothing for it to animate on top of.
2911 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2912 r.info.screenOrientation, r.fullscreen);
2913 }
2914 if (VALIDATE_TOKENS) {
2915 mWindowManager.validateAppTokens(mHistory);
2916 }
2917
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002918 if (doResume) {
2919 resumeTopActivityLocked(null);
2920 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002921 }
2922
2923 /**
2924 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002925 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2926 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002927 * an instance of that activity in the stack and, if found, finish all
2928 * activities on top of it and return the instance.
2929 *
2930 * @param newR Description of the new activity being started.
2931 * @return Returns the old activity that should be continue to be used,
2932 * or null if none was found.
2933 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002934 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002935 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002936 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002937
2938 // First find the requested task.
2939 while (i > 0) {
2940 i--;
2941 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2942 if (r.task.taskId == taskId) {
2943 i++;
2944 break;
2945 }
2946 }
2947
2948 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002949 while (i > 0) {
2950 i--;
2951 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2952 if (r.finishing) {
2953 continue;
2954 }
2955 if (r.task.taskId != taskId) {
2956 return null;
2957 }
2958 if (r.realActivity.equals(newR.realActivity)) {
2959 // Here it is! Now finish everything in front...
2960 HistoryRecord ret = r;
2961 if (doClear) {
2962 while (i < (mHistory.size()-1)) {
2963 i++;
2964 r = (HistoryRecord)mHistory.get(i);
2965 if (r.finishing) {
2966 continue;
2967 }
2968 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2969 null, "clear")) {
2970 i--;
2971 }
2972 }
2973 }
2974
2975 // Finally, if this is a normal launch mode (that is, not
2976 // expecting onNewIntent()), then we will finish the current
2977 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002978 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
2979 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002980 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002981 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002982 if (index >= 0) {
2983 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2984 null, "clear");
2985 }
2986 return null;
2987 }
2988 }
2989
2990 return ret;
2991 }
2992 }
2993
2994 return null;
2995 }
2996
2997 /**
2998 * Find the activity in the history stack within the given task. Returns
2999 * the index within the history at which it's found, or < 0 if not found.
3000 */
3001 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
3002 int i = mHistory.size();
3003 while (i > 0) {
3004 i--;
3005 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
3006 if (candidate.task.taskId != task) {
3007 break;
3008 }
3009 if (candidate.realActivity.equals(r.realActivity)) {
3010 return i;
3011 }
3012 }
3013
3014 return -1;
3015 }
3016
3017 /**
3018 * Reorder the history stack so that the activity at the given index is
3019 * brought to the front.
3020 */
3021 private final HistoryRecord moveActivityToFrontLocked(int where) {
3022 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3023 int top = mHistory.size();
3024 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3025 mHistory.add(top, newTop);
3026 oldTop.frontOfTask = false;
3027 newTop.frontOfTask = true;
3028 return newTop;
3029 }
3030
3031 /**
3032 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3033 * method will be called at the proper time.
3034 */
3035 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3036 boolean sent = false;
3037 if (r.state == ActivityState.RESUMED
3038 && r.app != null && r.app.thread != null) {
3039 try {
3040 ArrayList<Intent> ar = new ArrayList<Intent>();
3041 ar.add(new Intent(intent));
3042 r.app.thread.scheduleNewIntent(ar, r);
3043 sent = true;
3044 } catch (Exception e) {
3045 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3046 }
3047 }
3048 if (!sent) {
3049 r.addNewIntentLocked(new Intent(intent));
3050 }
3051 }
3052
3053 private final void logStartActivity(int tag, HistoryRecord r,
3054 TaskRecord task) {
3055 EventLog.writeEvent(tag,
3056 System.identityHashCode(r), task.taskId,
3057 r.shortComponentName, r.intent.getAction(),
3058 r.intent.getType(), r.intent.getDataString(),
3059 r.intent.getFlags());
3060 }
3061
3062 private final int startActivityLocked(IApplicationThread caller,
3063 Intent intent, String resolvedType,
3064 Uri[] grantedUriPermissions,
3065 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3066 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003067 int callingPid, int callingUid, boolean onlyIfNeeded,
3068 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003069 Log.i(TAG, "Starting activity: " + intent);
3070
3071 HistoryRecord sourceRecord = null;
3072 HistoryRecord resultRecord = null;
3073 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003074 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003075 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003076 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3077 if (index >= 0) {
3078 sourceRecord = (HistoryRecord)mHistory.get(index);
3079 if (requestCode >= 0 && !sourceRecord.finishing) {
3080 resultRecord = sourceRecord;
3081 }
3082 }
3083 }
3084
3085 int launchFlags = intent.getFlags();
3086
3087 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3088 && sourceRecord != null) {
3089 // Transfer the result target from the source activity to the new
3090 // one being started, including any failures.
3091 if (requestCode >= 0) {
3092 return START_FORWARD_AND_REQUEST_CONFLICT;
3093 }
3094 resultRecord = sourceRecord.resultTo;
3095 resultWho = sourceRecord.resultWho;
3096 requestCode = sourceRecord.requestCode;
3097 sourceRecord.resultTo = null;
3098 if (resultRecord != null) {
3099 resultRecord.removeResultsLocked(
3100 sourceRecord, resultWho, requestCode);
3101 }
3102 }
3103
3104 int err = START_SUCCESS;
3105
3106 if (intent.getComponent() == null) {
3107 // We couldn't find a class that can handle the given Intent.
3108 // That's the end of that!
3109 err = START_INTENT_NOT_RESOLVED;
3110 }
3111
3112 if (err == START_SUCCESS && aInfo == null) {
3113 // We couldn't find the specific class specified in the Intent.
3114 // Also the end of the line.
3115 err = START_CLASS_NOT_FOUND;
3116 }
3117
3118 ProcessRecord callerApp = null;
3119 if (err == START_SUCCESS && caller != null) {
3120 callerApp = getRecordForAppLocked(caller);
3121 if (callerApp != null) {
3122 callingPid = callerApp.pid;
3123 callingUid = callerApp.info.uid;
3124 } else {
3125 Log.w(TAG, "Unable to find app for caller " + caller
3126 + " (pid=" + callingPid + ") when starting: "
3127 + intent.toString());
3128 err = START_PERMISSION_DENIED;
3129 }
3130 }
3131
3132 if (err != START_SUCCESS) {
3133 if (resultRecord != null) {
3134 sendActivityResultLocked(-1,
3135 resultRecord, resultWho, requestCode,
3136 Activity.RESULT_CANCELED, null);
3137 }
3138 return err;
3139 }
3140
3141 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3142 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3143 if (perm != PackageManager.PERMISSION_GRANTED) {
3144 if (resultRecord != null) {
3145 sendActivityResultLocked(-1,
3146 resultRecord, resultWho, requestCode,
3147 Activity.RESULT_CANCELED, null);
3148 }
3149 String msg = "Permission Denial: starting " + intent.toString()
3150 + " from " + callerApp + " (pid=" + callingPid
3151 + ", uid=" + callingUid + ")"
3152 + " requires " + aInfo.permission;
3153 Log.w(TAG, msg);
3154 throw new SecurityException(msg);
3155 }
3156
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003157 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003158 boolean abort = false;
3159 try {
3160 // The Intent we give to the watcher has the extra data
3161 // stripped off, since it can contain private information.
3162 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003163 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003164 aInfo.applicationInfo.packageName);
3165 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003166 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003167 }
3168
3169 if (abort) {
3170 if (resultRecord != null) {
3171 sendActivityResultLocked(-1,
3172 resultRecord, resultWho, requestCode,
3173 Activity.RESULT_CANCELED, null);
3174 }
3175 // We pretend to the caller that it was really started, but
3176 // they will just get a cancel result.
3177 return START_SUCCESS;
3178 }
3179 }
3180
3181 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3182 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003183 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003184
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003185 if (mResumedActivity == null
3186 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3187 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3188 PendingActivityLaunch pal = new PendingActivityLaunch();
3189 pal.r = r;
3190 pal.sourceRecord = sourceRecord;
3191 pal.grantedUriPermissions = grantedUriPermissions;
3192 pal.grantedMode = grantedMode;
3193 pal.onlyIfNeeded = onlyIfNeeded;
3194 mPendingActivityLaunches.add(pal);
3195 return START_SWITCHES_CANCELED;
3196 }
3197 }
3198
3199 if (mDidAppSwitch) {
3200 // This is the second allowed switch since we stopped switches,
3201 // so now just generally allow switches. Use case: user presses
3202 // home (switches disabled, switch to home, mDidAppSwitch now true);
3203 // user taps a home icon (coming from home so allowed, we hit here
3204 // and now allow anyone to switch again).
3205 mAppSwitchesAllowedTime = 0;
3206 } else {
3207 mDidAppSwitch = true;
3208 }
3209
3210 doPendingActivityLaunchesLocked(false);
3211
3212 return startActivityUncheckedLocked(r, sourceRecord,
3213 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3214 }
3215
3216 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3217 final int N = mPendingActivityLaunches.size();
3218 if (N <= 0) {
3219 return;
3220 }
3221 for (int i=0; i<N; i++) {
3222 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3223 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3224 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3225 doResume && i == (N-1));
3226 }
3227 mPendingActivityLaunches.clear();
3228 }
3229
3230 private final int startActivityUncheckedLocked(HistoryRecord r,
3231 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3232 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3233 final Intent intent = r.intent;
3234 final int callingUid = r.launchedFromUid;
3235
3236 int launchFlags = intent.getFlags();
3237
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003238 // We'll invoke onUserLeaving before onPause only if the launching
3239 // activity did not explicitly state that this is an automated launch.
3240 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3241 if (DEBUG_USER_LEAVING) Log.v(TAG,
3242 "startActivity() => mUserLeaving=" + mUserLeaving);
3243
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003244 // If the caller has asked not to resume at this point, we make note
3245 // of this in the record so that we can skip it when trying to find
3246 // the top running activity.
3247 if (!doResume) {
3248 r.delayedResume = true;
3249 }
3250
3251 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3252 != 0 ? r : null;
3253
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003254 // If the onlyIfNeeded flag is set, then we can do this if the activity
3255 // being launched is the same as the one making the call... or, as
3256 // a special case, if we do not know the caller then we count the
3257 // current top activity as the caller.
3258 if (onlyIfNeeded) {
3259 HistoryRecord checkedCaller = sourceRecord;
3260 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003261 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003262 }
3263 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3264 // Caller is not the same as launcher, so always needed.
3265 onlyIfNeeded = false;
3266 }
3267 }
3268
3269 if (grantedUriPermissions != null && callingUid > 0) {
3270 for (int i=0; i<grantedUriPermissions.length; i++) {
3271 grantUriPermissionLocked(callingUid, r.packageName,
3272 grantedUriPermissions[i], grantedMode, r);
3273 }
3274 }
3275
3276 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3277 intent, r);
3278
3279 if (sourceRecord == null) {
3280 // This activity is not being started from another... in this
3281 // case we -always- start a new task.
3282 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3283 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3284 + intent);
3285 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3286 }
3287 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3288 // The original activity who is starting us is running as a single
3289 // instance... this new activity it is starting must go on its
3290 // own task.
3291 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3292 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3293 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3294 // The activity being started is a single instance... it always
3295 // gets launched into its own task.
3296 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3297 }
3298
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003299 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003300 // For whatever reason this activity is being launched into a new
3301 // task... yet the caller has requested a result back. Well, that
3302 // is pretty messed up, so instead immediately send back a cancel
3303 // and let the new task continue launched as normal without a
3304 // dependency on its originator.
3305 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3306 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003307 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003308 Activity.RESULT_CANCELED, null);
3309 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003310 }
3311
3312 boolean addingToTask = false;
3313 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3314 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3315 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3316 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3317 // If bring to front is requested, and no result is requested, and
3318 // we can find a task that was started with this same
3319 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003320 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003321 // See if there is a task to bring to the front. If this is
3322 // a SINGLE_INSTANCE activity, there can be one and only one
3323 // instance of it in the history, and it is always in its own
3324 // unique task, so we do a special search.
3325 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3326 ? findTaskLocked(intent, r.info)
3327 : findActivityLocked(intent, r.info);
3328 if (taskTop != null) {
3329 if (taskTop.task.intent == null) {
3330 // This task was started because of movement of
3331 // the activity based on affinity... now that we
3332 // are actually launching it, we can assign the
3333 // base intent.
3334 taskTop.task.setIntent(intent, r.info);
3335 }
3336 // If the target task is not in the front, then we need
3337 // to bring it to the front... except... well, with
3338 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3339 // to have the same behavior as if a new instance was
3340 // being started, which means not bringing it to the front
3341 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003342 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003343 if (curTop.task != taskTop.task) {
3344 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3345 boolean callerAtFront = sourceRecord == null
3346 || curTop.task == sourceRecord.task;
3347 if (callerAtFront) {
3348 // We really do want to push this one into the
3349 // user's face, right now.
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07003350 moveTaskToFrontLocked(taskTop.task, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003351 }
3352 }
3353 // If the caller has requested that the target task be
3354 // reset, then do so.
3355 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3356 taskTop = resetTaskIfNeededLocked(taskTop, r);
3357 }
3358 if (onlyIfNeeded) {
3359 // We don't need to start a new activity, and
3360 // the client said not to do anything if that
3361 // is the case, so this is it! And for paranoia, make
3362 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003363 if (doResume) {
3364 resumeTopActivityLocked(null);
3365 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003366 return START_RETURN_INTENT_TO_CALLER;
3367 }
3368 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3369 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3370 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3371 // In this situation we want to remove all activities
3372 // from the task up to the one being started. In most
3373 // cases this means we are resetting the task to its
3374 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003375 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003376 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003377 if (top != null) {
3378 if (top.frontOfTask) {
3379 // Activity aliases may mean we use different
3380 // intents for the top activity, so make sure
3381 // the task now has the identity of the new
3382 // intent.
3383 top.task.setIntent(r.intent, r.info);
3384 }
Doug Zongker2bec3d42009-12-04 12:52:44 -08003385 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003386 deliverNewIntentLocked(top, r.intent);
3387 } else {
3388 // A special case: we need to
3389 // start the activity because it is not currently
3390 // running, and the caller has asked to clear the
3391 // current task to have this activity at the top.
3392 addingToTask = true;
3393 // Now pretend like this activity is being started
3394 // by the top of its task, so it is put in the
3395 // right place.
3396 sourceRecord = taskTop;
3397 }
3398 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3399 // In this case the top activity on the task is the
3400 // same as the one being launched, so we take that
3401 // as a request to bring the task to the foreground.
3402 // If the top activity in the task is the root
3403 // activity, deliver this new intent to it if it
3404 // desires.
3405 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3406 && taskTop.realActivity.equals(r.realActivity)) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003407 logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003408 if (taskTop.frontOfTask) {
3409 taskTop.task.setIntent(r.intent, r.info);
3410 }
3411 deliverNewIntentLocked(taskTop, r.intent);
3412 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3413 // In this case we are launching the root activity
3414 // of the task, but with a different intent. We
3415 // should start a new instance on top.
3416 addingToTask = true;
3417 sourceRecord = taskTop;
3418 }
3419 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3420 // In this case an activity is being launched in to an
3421 // existing task, without resetting that task. This
3422 // is typically the situation of launching an activity
3423 // from a notification or shortcut. We want to place
3424 // the new activity on top of the current task.
3425 addingToTask = true;
3426 sourceRecord = taskTop;
3427 } else if (!taskTop.task.rootWasReset) {
3428 // In this case we are launching in to an existing task
3429 // that has not yet been started from its front door.
3430 // The current task has been brought to the front.
3431 // Ideally, we'd probably like to place this new task
3432 // at the bottom of its stack, but that's a little hard
3433 // to do with the current organization of the code so
3434 // for now we'll just drop it.
3435 taskTop.task.setIntent(r.intent, r.info);
3436 }
3437 if (!addingToTask) {
3438 // We didn't do anything... but it was needed (a.k.a., client
3439 // don't use that intent!) And for paranoia, make
3440 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003441 if (doResume) {
3442 resumeTopActivityLocked(null);
3443 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003444 return START_TASK_TO_FRONT;
3445 }
3446 }
3447 }
3448 }
3449
3450 //String uri = r.intent.toURI();
3451 //Intent intent2 = new Intent(uri);
3452 //Log.i(TAG, "Given intent: " + r.intent);
3453 //Log.i(TAG, "URI is: " + uri);
3454 //Log.i(TAG, "To intent: " + intent2);
3455
3456 if (r.packageName != null) {
3457 // If the activity being launched is the same as the one currently
3458 // at the top, then we need to check if it should only be launched
3459 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003460 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3461 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003462 if (top.realActivity.equals(r.realActivity)) {
3463 if (top.app != null && top.app.thread != null) {
3464 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3465 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3466 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003467 logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003468 // For paranoia, make sure we have correctly
3469 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003470 if (doResume) {
3471 resumeTopActivityLocked(null);
3472 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003473 if (onlyIfNeeded) {
3474 // We don't need to start a new activity, and
3475 // the client said not to do anything if that
3476 // is the case, so this is it!
3477 return START_RETURN_INTENT_TO_CALLER;
3478 }
3479 deliverNewIntentLocked(top, r.intent);
3480 return START_DELIVERED_TO_TOP;
3481 }
3482 }
3483 }
3484 }
3485
3486 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003487 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003488 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003489 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003490 Activity.RESULT_CANCELED, null);
3491 }
3492 return START_CLASS_NOT_FOUND;
3493 }
3494
3495 boolean newTask = false;
3496
3497 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003498 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003499 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3500 // todo: should do better management of integers.
3501 mCurTask++;
3502 if (mCurTask <= 0) {
3503 mCurTask = 1;
3504 }
3505 r.task = new TaskRecord(mCurTask, r.info, intent,
3506 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3507 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3508 + " in new task " + r.task);
3509 newTask = true;
3510 addRecentTask(r.task);
3511
3512 } else if (sourceRecord != null) {
3513 if (!addingToTask &&
3514 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3515 // In this case, we are adding the activity to an existing
3516 // task, but the caller has asked to clear that task if the
3517 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003518 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003519 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003520 if (top != null) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003521 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003522 deliverNewIntentLocked(top, r.intent);
3523 // For paranoia, make sure we have correctly
3524 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003525 if (doResume) {
3526 resumeTopActivityLocked(null);
3527 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003528 return START_DELIVERED_TO_TOP;
3529 }
3530 } else if (!addingToTask &&
3531 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3532 // In this case, we are launching an activity in our own task
3533 // that may already be running somewhere in the history, and
3534 // we want to shuffle it to the front of the stack if so.
3535 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3536 if (where >= 0) {
3537 HistoryRecord top = moveActivityToFrontLocked(where);
Doug Zongker2bec3d42009-12-04 12:52:44 -08003538 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003539 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003540 if (doResume) {
3541 resumeTopActivityLocked(null);
3542 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003543 return START_DELIVERED_TO_TOP;
3544 }
3545 }
3546 // An existing activity is starting this new activity, so we want
3547 // to keep the new one in the same task as the one that is starting
3548 // it.
3549 r.task = sourceRecord.task;
3550 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3551 + " in existing task " + r.task);
3552
3553 } else {
3554 // This not being started from an existing activity, and not part
3555 // of a new task... just put it in the top task, though these days
3556 // this case should never happen.
3557 final int N = mHistory.size();
3558 HistoryRecord prev =
3559 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3560 r.task = prev != null
3561 ? prev.task
3562 : new TaskRecord(mCurTask, r.info, intent,
3563 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3564 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3565 + " in new guessed " + r.task);
3566 }
3567 if (newTask) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003568 EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003569 }
Doug Zongker2bec3d42009-12-04 12:52:44 -08003570 logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003571 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003572 return START_SUCCESS;
3573 }
3574
3575 public final int startActivity(IApplicationThread caller,
3576 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3577 int grantedMode, IBinder resultTo,
3578 String resultWho, int requestCode, boolean onlyIfNeeded,
3579 boolean debug) {
3580 // Refuse possible leaked file descriptors
3581 if (intent != null && intent.hasFileDescriptors()) {
3582 throw new IllegalArgumentException("File descriptors passed in Intent");
3583 }
3584
The Android Open Source Project4df24232009-03-05 14:34:35 -08003585 final boolean componentSpecified = intent.getComponent() != null;
3586
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003587 // Don't modify the client's object!
3588 intent = new Intent(intent);
3589
3590 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003591 ActivityInfo aInfo;
3592 try {
3593 ResolveInfo rInfo =
3594 ActivityThread.getPackageManager().resolveIntent(
3595 intent, resolvedType,
3596 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003597 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003598 aInfo = rInfo != null ? rInfo.activityInfo : null;
3599 } catch (RemoteException e) {
3600 aInfo = null;
3601 }
3602
3603 if (aInfo != null) {
3604 // Store the found target back into the intent, because now that
3605 // we have it we never want to do this again. For example, if the
3606 // user navigates back to this point in the history, we should
3607 // always restart the exact same activity.
3608 intent.setComponent(new ComponentName(
3609 aInfo.applicationInfo.packageName, aInfo.name));
3610
3611 // Don't debug things in the system process
3612 if (debug) {
3613 if (!aInfo.processName.equals("system")) {
3614 setDebugApp(aInfo.processName, true, false);
3615 }
3616 }
3617 }
3618
3619 synchronized(this) {
3620 final long origId = Binder.clearCallingIdentity();
3621 int res = startActivityLocked(caller, intent, resolvedType,
3622 grantedUriPermissions, grantedMode, aInfo,
3623 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003624 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003625 Binder.restoreCallingIdentity(origId);
3626 return res;
3627 }
3628 }
3629
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003630 public int startActivityIntentSender(IApplicationThread caller,
3631 IntentSender intent, Intent fillInIntent, String resolvedType,
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003632 IBinder resultTo, String resultWho, int requestCode,
3633 int flagsMask, int flagsValues) {
3634 // Refuse possible leaked file descriptors
3635 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3636 throw new IllegalArgumentException("File descriptors passed in Intent");
3637 }
3638
3639 IIntentSender sender = intent.getTarget();
3640 if (!(sender instanceof PendingIntentRecord)) {
3641 throw new IllegalArgumentException("Bad PendingIntent object");
3642 }
3643
3644 PendingIntentRecord pir = (PendingIntentRecord)sender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003645
3646 synchronized (this) {
3647 // If this is coming from the currently resumed activity, it is
3648 // effectively saying that app switches are allowed at this point.
3649 if (mResumedActivity != null
3650 && mResumedActivity.info.applicationInfo.uid ==
3651 Binder.getCallingUid()) {
3652 mAppSwitchesAllowedTime = 0;
3653 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003654 }
3655
3656 return pir.sendInner(0, fillInIntent, resolvedType,
3657 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3658 }
3659
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003660 public boolean startNextMatchingActivity(IBinder callingActivity,
3661 Intent intent) {
3662 // Refuse possible leaked file descriptors
3663 if (intent != null && intent.hasFileDescriptors() == true) {
3664 throw new IllegalArgumentException("File descriptors passed in Intent");
3665 }
3666
3667 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003668 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003669 if (index < 0) {
3670 return false;
3671 }
3672 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3673 if (r.app == null || r.app.thread == null) {
3674 // The caller is not running... d'oh!
3675 return false;
3676 }
3677 intent = new Intent(intent);
3678 // The caller is not allowed to change the data.
3679 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3680 // And we are resetting to find the next component...
3681 intent.setComponent(null);
3682
3683 ActivityInfo aInfo = null;
3684 try {
3685 List<ResolveInfo> resolves =
3686 ActivityThread.getPackageManager().queryIntentActivities(
3687 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003688 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003689
3690 // Look for the original activity in the list...
3691 final int N = resolves != null ? resolves.size() : 0;
3692 for (int i=0; i<N; i++) {
3693 ResolveInfo rInfo = resolves.get(i);
3694 if (rInfo.activityInfo.packageName.equals(r.packageName)
3695 && rInfo.activityInfo.name.equals(r.info.name)) {
3696 // We found the current one... the next matching is
3697 // after it.
3698 i++;
3699 if (i<N) {
3700 aInfo = resolves.get(i).activityInfo;
3701 }
3702 break;
3703 }
3704 }
3705 } catch (RemoteException e) {
3706 }
3707
3708 if (aInfo == null) {
3709 // Nobody who is next!
3710 return false;
3711 }
3712
3713 intent.setComponent(new ComponentName(
3714 aInfo.applicationInfo.packageName, aInfo.name));
3715 intent.setFlags(intent.getFlags()&~(
3716 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3717 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3718 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3719 Intent.FLAG_ACTIVITY_NEW_TASK));
3720
3721 // Okay now we need to start the new activity, replacing the
3722 // currently running activity. This is a little tricky because
3723 // we want to start the new one as if the current one is finished,
3724 // but not finish the current one first so that there is no flicker.
3725 // And thus...
3726 final boolean wasFinishing = r.finishing;
3727 r.finishing = true;
3728
3729 // Propagate reply information over to the new activity.
3730 final HistoryRecord resultTo = r.resultTo;
3731 final String resultWho = r.resultWho;
3732 final int requestCode = r.requestCode;
3733 r.resultTo = null;
3734 if (resultTo != null) {
3735 resultTo.removeResultsLocked(r, resultWho, requestCode);
3736 }
3737
3738 final long origId = Binder.clearCallingIdentity();
3739 // XXX we are not dealing with propagating grantedUriPermissions...
3740 // those are not yet exposed to user code, so there is no need.
3741 int res = startActivityLocked(r.app.thread, intent,
3742 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003743 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003744 Binder.restoreCallingIdentity(origId);
3745
3746 r.finishing = wasFinishing;
3747 if (res != START_SUCCESS) {
3748 return false;
3749 }
3750 return true;
3751 }
3752 }
3753
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003754 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003755 Intent intent, String resolvedType, IBinder resultTo,
3756 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003757
3758 // This is so super not safe, that only the system (or okay root)
3759 // can do it.
3760 final int callingUid = Binder.getCallingUid();
3761 if (callingUid != 0 && callingUid != Process.myUid()) {
3762 throw new SecurityException(
3763 "startActivityInPackage only available to the system");
3764 }
3765
The Android Open Source Project4df24232009-03-05 14:34:35 -08003766 final boolean componentSpecified = intent.getComponent() != null;
3767
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003768 // Don't modify the client's object!
3769 intent = new Intent(intent);
3770
3771 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003772 ActivityInfo aInfo;
3773 try {
3774 ResolveInfo rInfo =
3775 ActivityThread.getPackageManager().resolveIntent(
3776 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003777 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003778 aInfo = rInfo != null ? rInfo.activityInfo : null;
3779 } catch (RemoteException e) {
3780 aInfo = null;
3781 }
3782
3783 if (aInfo != null) {
3784 // Store the found target back into the intent, because now that
3785 // we have it we never want to do this again. For example, if the
3786 // user navigates back to this point in the history, we should
3787 // always restart the exact same activity.
3788 intent.setComponent(new ComponentName(
3789 aInfo.applicationInfo.packageName, aInfo.name));
3790 }
3791
3792 synchronized(this) {
3793 return startActivityLocked(null, intent, resolvedType,
3794 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003795 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003796 }
3797 }
3798
3799 private final void addRecentTask(TaskRecord task) {
3800 // Remove any existing entries that are the same kind of task.
3801 int N = mRecentTasks.size();
3802 for (int i=0; i<N; i++) {
3803 TaskRecord tr = mRecentTasks.get(i);
3804 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3805 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3806 mRecentTasks.remove(i);
3807 i--;
3808 N--;
3809 if (task.intent == null) {
3810 // If the new recent task we are adding is not fully
3811 // specified, then replace it with the existing recent task.
3812 task = tr;
3813 }
3814 }
3815 }
3816 if (N >= MAX_RECENT_TASKS) {
3817 mRecentTasks.remove(N-1);
3818 }
3819 mRecentTasks.add(0, task);
3820 }
3821
3822 public void setRequestedOrientation(IBinder token,
3823 int requestedOrientation) {
3824 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003825 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003826 if (index < 0) {
3827 return;
3828 }
3829 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3830 final long origId = Binder.clearCallingIdentity();
3831 mWindowManager.setAppOrientation(r, requestedOrientation);
3832 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003833 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003834 r.mayFreezeScreenLocked(r.app) ? r : null);
3835 if (config != null) {
3836 r.frozenBeforeDestroy = true;
3837 if (!updateConfigurationLocked(config, r)) {
3838 resumeTopActivityLocked(null);
3839 }
3840 }
3841 Binder.restoreCallingIdentity(origId);
3842 }
3843 }
3844
3845 public int getRequestedOrientation(IBinder token) {
3846 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003847 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003848 if (index < 0) {
3849 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3850 }
3851 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3852 return mWindowManager.getAppOrientation(r);
3853 }
3854 }
3855
3856 private final void stopActivityLocked(HistoryRecord r) {
3857 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3858 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3859 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3860 if (!r.finishing) {
3861 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3862 "no-history");
3863 }
3864 } else if (r.app != null && r.app.thread != null) {
3865 if (mFocusedActivity == r) {
3866 setFocusedActivityLocked(topRunningActivityLocked(null));
3867 }
3868 r.resumeKeyDispatchingLocked();
3869 try {
3870 r.stopped = false;
3871 r.state = ActivityState.STOPPING;
3872 if (DEBUG_VISBILITY) Log.v(
3873 TAG, "Stopping visible=" + r.visible + " for " + r);
3874 if (!r.visible) {
3875 mWindowManager.setAppVisibility(r, false);
3876 }
3877 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3878 } catch (Exception e) {
3879 // Maybe just ignore exceptions here... if the process
3880 // has crashed, our death notification will clean things
3881 // up.
3882 Log.w(TAG, "Exception thrown during pause", e);
3883 // Just in case, assume it to be stopped.
3884 r.stopped = true;
3885 r.state = ActivityState.STOPPED;
3886 if (r.configDestroy) {
3887 destroyActivityLocked(r, true);
3888 }
3889 }
3890 }
3891 }
3892
3893 /**
3894 * @return Returns true if the activity is being finished, false if for
3895 * some reason it is being left as-is.
3896 */
3897 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3898 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003899 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003900 TAG, "Finishing activity: token=" + token
3901 + ", result=" + resultCode + ", data=" + resultData);
3902
Dianne Hackborn75b03852009-06-12 15:43:26 -07003903 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003904 if (index < 0) {
3905 return false;
3906 }
3907 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3908
3909 // Is this the last activity left?
3910 boolean lastActivity = true;
3911 for (int i=mHistory.size()-1; i>=0; i--) {
3912 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3913 if (!p.finishing && p != r) {
3914 lastActivity = false;
3915 break;
3916 }
3917 }
3918
3919 // If this is the last activity, but it is the home activity, then
3920 // just don't finish it.
3921 if (lastActivity) {
3922 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3923 return false;
3924 }
3925 }
3926
3927 finishActivityLocked(r, index, resultCode, resultData, reason);
3928 return true;
3929 }
3930
3931 /**
3932 * @return Returns true if this activity has been removed from the history
3933 * list, or false if it is still in the list and will be removed later.
3934 */
3935 private final boolean finishActivityLocked(HistoryRecord r, int index,
3936 int resultCode, Intent resultData, String reason) {
3937 if (r.finishing) {
3938 Log.w(TAG, "Duplicate finish request for " + r);
3939 return false;
3940 }
3941
3942 r.finishing = true;
Doug Zongker2bec3d42009-12-04 12:52:44 -08003943 EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003944 System.identityHashCode(r),
3945 r.task.taskId, r.shortComponentName, reason);
3946 r.task.numActivities--;
3947 if (r.frontOfTask && index < (mHistory.size()-1)) {
3948 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3949 if (next.task == r.task) {
3950 next.frontOfTask = true;
3951 }
3952 }
3953
3954 r.pauseKeyDispatchingLocked();
3955 if (mFocusedActivity == r) {
3956 setFocusedActivityLocked(topRunningActivityLocked(null));
3957 }
3958
3959 // send the result
3960 HistoryRecord resultTo = r.resultTo;
3961 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003962 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3963 + " who=" + r.resultWho + " req=" + r.requestCode
3964 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003965 if (r.info.applicationInfo.uid > 0) {
3966 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3967 r.packageName, resultData, r);
3968 }
3969 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3970 resultData);
3971 r.resultTo = null;
3972 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003973 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003974
3975 // Make sure this HistoryRecord is not holding on to other resources,
3976 // because clients have remote IPC references to this object so we
3977 // can't assume that will go away and want to avoid circular IPC refs.
3978 r.results = null;
3979 r.pendingResults = null;
3980 r.newIntents = null;
3981 r.icicle = null;
3982
3983 if (mPendingThumbnails.size() > 0) {
3984 // There are clients waiting to receive thumbnails so, in case
3985 // this is an activity that someone is waiting for, add it
3986 // to the pending list so we can correctly update the clients.
3987 mCancelledThumbnails.add(r);
3988 }
3989
3990 if (mResumedActivity == r) {
3991 boolean endTask = index <= 0
3992 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3993 if (DEBUG_TRANSITION) Log.v(TAG,
3994 "Prepare close transition: finishing " + r);
3995 mWindowManager.prepareAppTransition(endTask
3996 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3997 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3998
3999 // Tell window manager to prepare for this one to be removed.
4000 mWindowManager.setAppVisibility(r, false);
4001
4002 if (mPausingActivity == null) {
4003 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
4004 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
4005 startPausingLocked(false, false);
4006 }
4007
4008 } else if (r.state != ActivityState.PAUSING) {
4009 // If the activity is PAUSING, we will complete the finish once
4010 // it is done pausing; else we can just directly finish it here.
4011 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
4012 return finishCurrentActivityLocked(r, index,
4013 FINISH_AFTER_PAUSE) == null;
4014 } else {
4015 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
4016 }
4017
4018 return false;
4019 }
4020
4021 private static final int FINISH_IMMEDIATELY = 0;
4022 private static final int FINISH_AFTER_PAUSE = 1;
4023 private static final int FINISH_AFTER_VISIBLE = 2;
4024
4025 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4026 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004027 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004028 if (index < 0) {
4029 return null;
4030 }
4031
4032 return finishCurrentActivityLocked(r, index, mode);
4033 }
4034
4035 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4036 int index, int mode) {
4037 // First things first: if this activity is currently visible,
4038 // and the resumed activity is not yet visible, then hold off on
4039 // finishing until the resumed one becomes visible.
4040 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4041 if (!mStoppingActivities.contains(r)) {
4042 mStoppingActivities.add(r);
4043 if (mStoppingActivities.size() > 3) {
4044 // If we already have a few activities waiting to stop,
4045 // then give up on things going idle and start clearing
4046 // them out.
4047 Message msg = Message.obtain();
4048 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4049 mHandler.sendMessage(msg);
4050 }
4051 }
4052 r.state = ActivityState.STOPPING;
4053 updateOomAdjLocked();
4054 return r;
4055 }
4056
4057 // make sure the record is cleaned out of other places.
4058 mStoppingActivities.remove(r);
4059 mWaitingVisibleActivities.remove(r);
4060 if (mResumedActivity == r) {
4061 mResumedActivity = null;
4062 }
4063 final ActivityState prevState = r.state;
4064 r.state = ActivityState.FINISHING;
4065
4066 if (mode == FINISH_IMMEDIATELY
4067 || prevState == ActivityState.STOPPED
4068 || prevState == ActivityState.INITIALIZING) {
4069 // If this activity is already stopped, we can just finish
4070 // it right now.
4071 return destroyActivityLocked(r, true) ? null : r;
4072 } else {
4073 // Need to go through the full pause cycle to get this
4074 // activity into the stopped state and then finish it.
4075 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4076 mFinishingActivities.add(r);
4077 resumeTopActivityLocked(null);
4078 }
4079 return r;
4080 }
4081
4082 /**
4083 * This is the internal entry point for handling Activity.finish().
4084 *
4085 * @param token The Binder token referencing the Activity we want to finish.
4086 * @param resultCode Result code, if any, from this Activity.
4087 * @param resultData Result data (Intent), if any, from this Activity.
4088 *
Alexey Tarasov83bad3d2009-08-12 15:05:43 +11004089 * @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 -08004090 */
4091 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4092 // Refuse possible leaked file descriptors
4093 if (resultData != null && resultData.hasFileDescriptors() == true) {
4094 throw new IllegalArgumentException("File descriptors passed in Intent");
4095 }
4096
4097 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004098 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004099 // Find the first activity that is not finishing.
4100 HistoryRecord next = topRunningActivityLocked(token, 0);
4101 if (next != null) {
4102 // ask watcher if this is allowed
4103 boolean resumeOK = true;
4104 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004105 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004106 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004107 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004108 }
4109
4110 if (!resumeOK) {
4111 return false;
4112 }
4113 }
4114 }
4115 final long origId = Binder.clearCallingIdentity();
4116 boolean res = requestFinishActivityLocked(token, resultCode,
4117 resultData, "app-request");
4118 Binder.restoreCallingIdentity(origId);
4119 return res;
4120 }
4121 }
4122
4123 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4124 String resultWho, int requestCode, int resultCode, Intent data) {
4125
4126 if (callingUid > 0) {
4127 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4128 data, r);
4129 }
4130
The Android Open Source Project10592532009-03-18 17:39:46 -07004131 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4132 + " : who=" + resultWho + " req=" + requestCode
4133 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004134 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4135 try {
4136 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4137 list.add(new ResultInfo(resultWho, requestCode,
4138 resultCode, data));
4139 r.app.thread.scheduleSendResult(r, list);
4140 return;
4141 } catch (Exception e) {
4142 Log.w(TAG, "Exception thrown sending result to " + r, e);
4143 }
4144 }
4145
4146 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4147 }
4148
4149 public final void finishSubActivity(IBinder token, String resultWho,
4150 int requestCode) {
4151 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004152 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004153 if (index < 0) {
4154 return;
4155 }
4156 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4157
4158 final long origId = Binder.clearCallingIdentity();
4159
4160 int i;
4161 for (i=mHistory.size()-1; i>=0; i--) {
4162 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4163 if (r.resultTo == self && r.requestCode == requestCode) {
4164 if ((r.resultWho == null && resultWho == null) ||
4165 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4166 finishActivityLocked(r, i,
4167 Activity.RESULT_CANCELED, null, "request-sub");
4168 }
4169 }
4170 }
4171
4172 Binder.restoreCallingIdentity(origId);
4173 }
4174 }
4175
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07004176 public void overridePendingTransition(IBinder token, String packageName,
4177 int enterAnim, int exitAnim) {
4178 synchronized(this) {
4179 int index = indexOfTokenLocked(token);
4180 if (index < 0) {
4181 return;
4182 }
4183 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4184
4185 final long origId = Binder.clearCallingIdentity();
4186
4187 if (self.state == ActivityState.RESUMED
4188 || self.state == ActivityState.PAUSING) {
4189 mWindowManager.overridePendingAppTransition(packageName,
4190 enterAnim, exitAnim);
4191 }
4192
4193 Binder.restoreCallingIdentity(origId);
4194 }
4195 }
4196
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004197 /**
4198 * Perform clean-up of service connections in an activity record.
4199 */
4200 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4201 // Throw away any services that have been bound by this activity.
4202 if (r.connections != null) {
4203 Iterator<ConnectionRecord> it = r.connections.iterator();
4204 while (it.hasNext()) {
4205 ConnectionRecord c = it.next();
4206 removeConnectionLocked(c, null, r);
4207 }
4208 r.connections = null;
4209 }
4210 }
4211
4212 /**
4213 * Perform the common clean-up of an activity record. This is called both
4214 * as part of destroyActivityLocked() (when destroying the client-side
4215 * representation) and cleaning things up as a result of its hosting
4216 * processing going away, in which case there is no remaining client-side
4217 * state to destroy so only the cleanup here is needed.
4218 */
4219 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4220 if (mResumedActivity == r) {
4221 mResumedActivity = null;
4222 }
4223 if (mFocusedActivity == r) {
4224 mFocusedActivity = null;
4225 }
4226
4227 r.configDestroy = false;
4228 r.frozenBeforeDestroy = false;
4229
4230 // Make sure this record is no longer in the pending finishes list.
4231 // This could happen, for example, if we are trimming activities
4232 // down to the max limit while they are still waiting to finish.
4233 mFinishingActivities.remove(r);
4234 mWaitingVisibleActivities.remove(r);
4235
4236 // Remove any pending results.
4237 if (r.finishing && r.pendingResults != null) {
4238 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4239 PendingIntentRecord rec = apr.get();
4240 if (rec != null) {
4241 cancelIntentSenderLocked(rec, false);
4242 }
4243 }
4244 r.pendingResults = null;
4245 }
4246
4247 if (cleanServices) {
4248 cleanUpActivityServicesLocked(r);
4249 }
4250
4251 if (mPendingThumbnails.size() > 0) {
4252 // There are clients waiting to receive thumbnails so, in case
4253 // this is an activity that someone is waiting for, add it
4254 // to the pending list so we can correctly update the clients.
4255 mCancelledThumbnails.add(r);
4256 }
4257
4258 // Get rid of any pending idle timeouts.
4259 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4260 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4261 }
4262
4263 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4264 if (r.state != ActivityState.DESTROYED) {
4265 mHistory.remove(r);
4266 r.inHistory = false;
4267 r.state = ActivityState.DESTROYED;
4268 mWindowManager.removeAppToken(r);
4269 if (VALIDATE_TOKENS) {
4270 mWindowManager.validateAppTokens(mHistory);
4271 }
4272 cleanUpActivityServicesLocked(r);
4273 removeActivityUriPermissionsLocked(r);
4274 }
4275 }
4276
4277 /**
4278 * Destroy the current CLIENT SIDE instance of an activity. This may be
4279 * called both when actually finishing an activity, or when performing
4280 * a configuration switch where we destroy the current client-side object
4281 * but then create a new client-side object for this same HistoryRecord.
4282 */
4283 private final boolean destroyActivityLocked(HistoryRecord r,
4284 boolean removeFromApp) {
4285 if (DEBUG_SWITCH) Log.v(
4286 TAG, "Removing activity: token=" + r
4287 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
Doug Zongker2bec3d42009-12-04 12:52:44 -08004288 EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004289 System.identityHashCode(r),
4290 r.task.taskId, r.shortComponentName);
4291
4292 boolean removedFromHistory = false;
4293
4294 cleanUpActivityLocked(r, false);
4295
4296 if (r.app != null) {
4297 if (removeFromApp) {
4298 int idx = r.app.activities.indexOf(r);
4299 if (idx >= 0) {
4300 r.app.activities.remove(idx);
4301 }
4302 if (r.persistent) {
4303 decPersistentCountLocked(r.app);
4304 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004305 if (r.app.activities.size() == 0) {
4306 // No longer have activities, so update location in
4307 // LRU list.
4308 updateLruProcessLocked(r.app, true, false);
4309 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004310 }
4311
4312 boolean skipDestroy = false;
4313
4314 try {
4315 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4316 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4317 r.configChangeFlags);
4318 } catch (Exception e) {
4319 // We can just ignore exceptions here... if the process
4320 // has crashed, our death notification will clean things
4321 // up.
4322 //Log.w(TAG, "Exception thrown during finish", e);
4323 if (r.finishing) {
4324 removeActivityFromHistoryLocked(r);
4325 removedFromHistory = true;
4326 skipDestroy = true;
4327 }
4328 }
4329
4330 r.app = null;
4331 r.nowVisible = false;
4332
4333 if (r.finishing && !skipDestroy) {
4334 r.state = ActivityState.DESTROYING;
4335 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4336 msg.obj = r;
4337 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4338 } else {
4339 r.state = ActivityState.DESTROYED;
4340 }
4341 } else {
4342 // remove this record from the history.
4343 if (r.finishing) {
4344 removeActivityFromHistoryLocked(r);
4345 removedFromHistory = true;
4346 } else {
4347 r.state = ActivityState.DESTROYED;
4348 }
4349 }
4350
4351 r.configChangeFlags = 0;
4352
4353 if (!mLRUActivities.remove(r)) {
4354 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4355 }
4356
4357 return removedFromHistory;
4358 }
4359
4360 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4361 ProcessRecord app)
4362 {
4363 int i = list.size();
4364 if (localLOGV) Log.v(
4365 TAG, "Removing app " + app + " from list " + list
4366 + " with " + i + " entries");
4367 while (i > 0) {
4368 i--;
4369 HistoryRecord r = (HistoryRecord)list.get(i);
4370 if (localLOGV) Log.v(
4371 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4372 if (r.app == app) {
4373 if (localLOGV) Log.v(TAG, "Removing this entry!");
4374 list.remove(i);
4375 }
4376 }
4377 }
4378
4379 /**
4380 * Main function for removing an existing process from the activity manager
4381 * as a result of that process going away. Clears out all connections
4382 * to the process.
4383 */
4384 private final void handleAppDiedLocked(ProcessRecord app,
4385 boolean restarting) {
4386 cleanUpApplicationRecordLocked(app, restarting, -1);
4387 if (!restarting) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004388 mLruProcesses.remove(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004389 }
4390
4391 // Just in case...
4392 if (mPausingActivity != null && mPausingActivity.app == app) {
4393 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4394 mPausingActivity = null;
4395 }
4396 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4397 mLastPausedActivity = null;
4398 }
4399
4400 // Remove this application's activities from active lists.
4401 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4402 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4403 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4404 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4405
4406 boolean atTop = true;
4407 boolean hasVisibleActivities = false;
4408
4409 // Clean out the history list.
4410 int i = mHistory.size();
4411 if (localLOGV) Log.v(
4412 TAG, "Removing app " + app + " from history with " + i + " entries");
4413 while (i > 0) {
4414 i--;
4415 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4416 if (localLOGV) Log.v(
4417 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4418 if (r.app == app) {
4419 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4420 if (localLOGV) Log.v(
4421 TAG, "Removing this entry! frozen=" + r.haveState
4422 + " finishing=" + r.finishing);
4423 mHistory.remove(i);
4424
4425 r.inHistory = false;
4426 mWindowManager.removeAppToken(r);
4427 if (VALIDATE_TOKENS) {
4428 mWindowManager.validateAppTokens(mHistory);
4429 }
4430 removeActivityUriPermissionsLocked(r);
4431
4432 } else {
4433 // We have the current state for this activity, so
4434 // it can be restarted later when needed.
4435 if (localLOGV) Log.v(
4436 TAG, "Keeping entry, setting app to null");
4437 if (r.visible) {
4438 hasVisibleActivities = true;
4439 }
4440 r.app = null;
4441 r.nowVisible = false;
4442 if (!r.haveState) {
4443 r.icicle = null;
4444 }
4445 }
4446
4447 cleanUpActivityLocked(r, true);
4448 r.state = ActivityState.STOPPED;
4449 }
4450 atTop = false;
4451 }
4452
4453 app.activities.clear();
4454
4455 if (app.instrumentationClass != null) {
4456 Log.w(TAG, "Crash of app " + app.processName
4457 + " running instrumentation " + app.instrumentationClass);
4458 Bundle info = new Bundle();
4459 info.putString("shortMsg", "Process crashed.");
4460 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4461 }
4462
4463 if (!restarting) {
4464 if (!resumeTopActivityLocked(null)) {
4465 // If there was nothing to resume, and we are not already
4466 // restarting this process, but there is a visible activity that
4467 // is hosted by the process... then make sure all visible
4468 // activities are running, taking care of restarting this
4469 // process.
4470 if (hasVisibleActivities) {
4471 ensureActivitiesVisibleLocked(null, 0);
4472 }
4473 }
4474 }
4475 }
4476
4477 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4478 IBinder threadBinder = thread.asBinder();
4479
4480 // Find the application record.
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004481 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4482 ProcessRecord rec = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004483 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4484 return i;
4485 }
4486 }
4487 return -1;
4488 }
4489
4490 private final ProcessRecord getRecordForAppLocked(
4491 IApplicationThread thread) {
4492 if (thread == null) {
4493 return null;
4494 }
4495
4496 int appIndex = getLRURecordIndexForAppLocked(thread);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004497 return appIndex >= 0 ? mLruProcesses.get(appIndex) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004498 }
4499
4500 private final void appDiedLocked(ProcessRecord app, int pid,
4501 IApplicationThread thread) {
4502
4503 mProcDeaths[0]++;
4504
4505 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4506 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4507 + ") has died.");
Doug Zongker2bec3d42009-12-04 12:52:44 -08004508 EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004509 if (localLOGV) Log.v(
4510 TAG, "Dying app: " + app + ", pid: " + pid
4511 + ", thread: " + thread.asBinder());
4512 boolean doLowMem = app.instrumentationClass == null;
4513 handleAppDiedLocked(app, false);
4514
4515 if (doLowMem) {
4516 // If there are no longer any background processes running,
4517 // and the app that died was not running instrumentation,
4518 // then tell everyone we are now low on memory.
4519 boolean haveBg = false;
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004520 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4521 ProcessRecord rec = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004522 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4523 haveBg = true;
4524 break;
4525 }
4526 }
4527
4528 if (!haveBg) {
4529 Log.i(TAG, "Low Memory: No more background processes.");
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004530 EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mLruProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004531 long now = SystemClock.uptimeMillis();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004532 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4533 ProcessRecord rec = mLruProcesses.get(i);
Dianne Hackborn36124872009-10-08 16:22:03 -07004534 if (rec != app && rec.thread != null &&
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004535 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4536 // The low memory report is overriding any current
4537 // state for a GC request. Make sure to do
4538 // visible/foreground processes first.
4539 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4540 rec.lastRequestedGc = 0;
4541 } else {
4542 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004543 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004544 rec.reportLowMemory = true;
4545 rec.lastLowMemory = now;
4546 mProcessesToGc.remove(rec);
4547 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004548 }
4549 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004550 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004551 }
4552 }
4553 } else if (Config.LOGD) {
4554 Log.d(TAG, "Received spurious death notification for thread "
4555 + thread.asBinder());
4556 }
4557 }
4558
4559 final String readFile(String filename) {
4560 try {
4561 FileInputStream fs = new FileInputStream(filename);
4562 byte[] inp = new byte[8192];
4563 int size = fs.read(inp);
4564 fs.close();
4565 return new String(inp, 0, 0, size);
4566 } catch (java.io.IOException e) {
4567 }
4568 return "";
4569 }
4570
4571 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004572 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004573 if (app.notResponding || app.crashing) {
4574 return;
4575 }
4576
4577 // Log the ANR to the event log.
Doug Zongker2bec3d42009-12-04 12:52:44 -08004578 EventLog.writeEvent(EventLogTags.ANR, app.pid, app.processName, annotation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004579
4580 // If we are on a secure build and the application is not interesting to the user (it is
4581 // not visible or in the background), just kill it instead of displaying a dialog.
4582 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4583 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4584 Process.killProcess(app.pid);
4585 return;
4586 }
4587
4588 // DeviceMonitor.start();
4589
4590 String processInfo = null;
4591 if (MONITOR_CPU_USAGE) {
4592 updateCpuStatsNow();
4593 synchronized (mProcessStatsThread) {
4594 processInfo = mProcessStats.printCurrentState();
4595 }
4596 }
4597
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004598 StringBuilder info = mStringBuilder;
4599 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004600 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004601 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004602 if (reportedActivity != null && reportedActivity.app != null) {
4603 info.append(" (last in ");
4604 info.append(reportedActivity.app.processName);
4605 info.append(")");
4606 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004607 if (annotation != null) {
4608 info.append("\nAnnotation: ");
4609 info.append(annotation);
4610 }
4611 if (MONITOR_CPU_USAGE) {
4612 info.append("\nCPU usage:\n");
4613 info.append(processInfo);
4614 }
4615 Log.i(TAG, info.toString());
4616
4617 // The application is not responding. Dump as many thread traces as we can.
4618 boolean fileDump = prepareTraceFile(true);
4619 if (!fileDump) {
4620 // Dumping traces to the log, just dump the process that isn't responding so
4621 // we don't overflow the log
4622 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4623 } else {
4624 // Dumping traces to a file so dump all active processes we know about
4625 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004626 // First, these are the most important processes.
4627 final int[] imppids = new int[3];
4628 int i=0;
4629 imppids[0] = app.pid;
4630 i++;
4631 if (reportedActivity != null && reportedActivity.app != null
4632 && reportedActivity.app.thread != null
4633 && reportedActivity.app.pid != app.pid) {
4634 imppids[i] = reportedActivity.app.pid;
4635 i++;
4636 }
4637 imppids[i] = Process.myPid();
4638 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4639 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4640 synchronized (this) {
4641 try {
4642 wait(200);
4643 } catch (InterruptedException e) {
4644 }
4645 }
4646 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004647 for (i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
4648 ProcessRecord r = mLruProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004649 boolean done = false;
4650 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4651 if (imppids[j] == r.pid) {
4652 done = true;
4653 break;
4654 }
4655 }
4656 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004657 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004658 synchronized (this) {
4659 try {
4660 wait(200);
4661 } catch (InterruptedException e) {
4662 }
4663 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004664 }
4665 }
4666 }
4667 }
4668
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004669 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004670 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004671 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004672 app.pid, info.toString());
4673 if (res != 0) {
4674 if (res < 0) {
4675 // wait until the SIGQUIT has had a chance to process before killing the
4676 // process.
4677 try {
4678 wait(2000);
4679 } catch (InterruptedException e) {
4680 }
4681
4682 Process.killProcess(app.pid);
4683 return;
4684 }
4685 }
4686 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004687 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004688 }
4689 }
4690
4691 makeAppNotRespondingLocked(app,
4692 activity != null ? activity.shortComponentName : null,
4693 annotation != null ? "ANR " + annotation : "ANR",
Dan Egnorb7f03672009-12-09 16:22:32 -08004694 info.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004695 Message msg = Message.obtain();
4696 HashMap map = new HashMap();
4697 msg.what = SHOW_NOT_RESPONDING_MSG;
4698 msg.obj = map;
4699 map.put("app", app);
4700 if (activity != null) {
4701 map.put("activity", activity);
4702 }
4703
4704 mHandler.sendMessage(msg);
4705 return;
4706 }
4707
4708 /**
4709 * If a stack trace file has been configured, prepare the filesystem
4710 * by creating the directory if it doesn't exist and optionally
4711 * removing the old trace file.
4712 *
4713 * @param removeExisting If set, the existing trace file will be removed.
4714 * @return Returns true if the trace file preparations succeeded
4715 */
4716 public static boolean prepareTraceFile(boolean removeExisting) {
4717 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4718 boolean fileReady = false;
4719 if (!TextUtils.isEmpty(tracesPath)) {
4720 File f = new File(tracesPath);
4721 if (!f.exists()) {
4722 // Ensure the enclosing directory exists
4723 File dir = f.getParentFile();
4724 if (!dir.exists()) {
4725 fileReady = dir.mkdirs();
4726 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004727 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004728 } else if (dir.isDirectory()) {
4729 fileReady = true;
4730 }
4731 } else if (removeExisting) {
4732 // Remove the previous traces file, so we don't fill the disk.
4733 // The VM will recreate it
4734 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4735 fileReady = f.delete();
4736 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004737
4738 if (removeExisting) {
4739 try {
4740 f.createNewFile();
4741 FileUtils.setPermissions(f.getAbsolutePath(),
4742 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4743 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4744 fileReady = true;
4745 } catch (IOException e) {
4746 Log.w(TAG, "Unable to make ANR traces file", e);
4747 }
4748 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004749 }
4750
4751 return fileReady;
4752 }
4753
4754
4755 private final void decPersistentCountLocked(ProcessRecord app)
4756 {
4757 app.persistentActivities--;
4758 if (app.persistentActivities > 0) {
4759 // Still more of 'em...
4760 return;
4761 }
4762 if (app.persistent) {
4763 // Ah, but the application itself is persistent. Whatever!
4764 return;
4765 }
4766
4767 // App is no longer persistent... make sure it and the ones
4768 // following it in the LRU list have the correc oom_adj.
4769 updateOomAdjLocked();
4770 }
4771
4772 public void setPersistent(IBinder token, boolean isPersistent) {
4773 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4774 != PackageManager.PERMISSION_GRANTED) {
4775 String msg = "Permission Denial: setPersistent() from pid="
4776 + Binder.getCallingPid()
4777 + ", uid=" + Binder.getCallingUid()
4778 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4779 Log.w(TAG, msg);
4780 throw new SecurityException(msg);
4781 }
4782
4783 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004784 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004785 if (index < 0) {
4786 return;
4787 }
4788 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4789 ProcessRecord app = r.app;
4790
4791 if (localLOGV) Log.v(
4792 TAG, "Setting persistence " + isPersistent + ": " + r);
4793
4794 if (isPersistent) {
4795 if (r.persistent) {
4796 // Okay okay, I heard you already!
4797 if (localLOGV) Log.v(TAG, "Already persistent!");
4798 return;
4799 }
4800 r.persistent = true;
4801 app.persistentActivities++;
4802 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4803 if (app.persistentActivities > 1) {
4804 // We aren't the first...
4805 if (localLOGV) Log.v(TAG, "Not the first!");
4806 return;
4807 }
4808 if (app.persistent) {
4809 // This would be redundant.
4810 if (localLOGV) Log.v(TAG, "App is persistent!");
4811 return;
4812 }
4813
4814 // App is now persistent... make sure it and the ones
4815 // following it now have the correct oom_adj.
4816 final long origId = Binder.clearCallingIdentity();
4817 updateOomAdjLocked();
4818 Binder.restoreCallingIdentity(origId);
4819
4820 } else {
4821 if (!r.persistent) {
4822 // Okay okay, I heard you already!
4823 return;
4824 }
4825 r.persistent = false;
4826 final long origId = Binder.clearCallingIdentity();
4827 decPersistentCountLocked(app);
4828 Binder.restoreCallingIdentity(origId);
4829
4830 }
4831 }
4832 }
4833
4834 public boolean clearApplicationUserData(final String packageName,
4835 final IPackageDataObserver observer) {
4836 int uid = Binder.getCallingUid();
4837 int pid = Binder.getCallingPid();
4838 long callingId = Binder.clearCallingIdentity();
4839 try {
4840 IPackageManager pm = ActivityThread.getPackageManager();
4841 int pkgUid = -1;
4842 synchronized(this) {
4843 try {
4844 pkgUid = pm.getPackageUid(packageName);
4845 } catch (RemoteException e) {
4846 }
4847 if (pkgUid == -1) {
4848 Log.w(TAG, "Invalid packageName:" + packageName);
4849 return false;
4850 }
4851 if (uid == pkgUid || checkComponentPermission(
4852 android.Manifest.permission.CLEAR_APP_USER_DATA,
4853 pid, uid, -1)
4854 == PackageManager.PERMISSION_GRANTED) {
4855 restartPackageLocked(packageName, pkgUid);
4856 } else {
4857 throw new SecurityException(pid+" does not have permission:"+
4858 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4859 "for process:"+packageName);
4860 }
4861 }
4862
4863 try {
4864 //clear application user data
4865 pm.clearApplicationUserData(packageName, observer);
4866 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4867 Uri.fromParts("package", packageName, null));
4868 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4869 broadcastIntentLocked(null, null, intent,
4870 null, null, 0, null, null, null,
4871 false, false, MY_PID, Process.SYSTEM_UID);
4872 } catch (RemoteException e) {
4873 }
4874 } finally {
4875 Binder.restoreCallingIdentity(callingId);
4876 }
4877 return true;
4878 }
4879
4880 public void restartPackage(final String packageName) {
4881 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4882 != PackageManager.PERMISSION_GRANTED) {
4883 String msg = "Permission Denial: restartPackage() from pid="
4884 + Binder.getCallingPid()
4885 + ", uid=" + Binder.getCallingUid()
4886 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4887 Log.w(TAG, msg);
4888 throw new SecurityException(msg);
4889 }
4890
4891 long callingId = Binder.clearCallingIdentity();
4892 try {
4893 IPackageManager pm = ActivityThread.getPackageManager();
4894 int pkgUid = -1;
4895 synchronized(this) {
4896 try {
4897 pkgUid = pm.getPackageUid(packageName);
4898 } catch (RemoteException e) {
4899 }
4900 if (pkgUid == -1) {
4901 Log.w(TAG, "Invalid packageName: " + packageName);
4902 return;
4903 }
4904 restartPackageLocked(packageName, pkgUid);
4905 }
4906 } finally {
4907 Binder.restoreCallingIdentity(callingId);
4908 }
4909 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004910
4911 /*
4912 * The pkg name and uid have to be specified.
4913 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4914 */
4915 public void killApplicationWithUid(String pkg, int uid) {
4916 if (pkg == null) {
4917 return;
4918 }
4919 // Make sure the uid is valid.
4920 if (uid < 0) {
4921 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4922 return;
4923 }
4924 int callerUid = Binder.getCallingUid();
4925 // Only the system server can kill an application
4926 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004927 // Post an aysnc message to kill the application
4928 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4929 msg.arg1 = uid;
4930 msg.arg2 = 0;
4931 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004932 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004933 } else {
4934 throw new SecurityException(callerUid + " cannot kill pkg: " +
4935 pkg);
4936 }
4937 }
4938
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004939 public void closeSystemDialogs(String reason) {
4940 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4941 if (reason != null) {
4942 intent.putExtra("reason", reason);
4943 }
4944
4945 final int uid = Binder.getCallingUid();
4946 final long origId = Binder.clearCallingIdentity();
4947 synchronized (this) {
4948 int i = mWatchers.beginBroadcast();
4949 while (i > 0) {
4950 i--;
4951 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4952 if (w != null) {
4953 try {
4954 w.closingSystemDialogs(reason);
4955 } catch (RemoteException e) {
4956 }
4957 }
4958 }
4959 mWatchers.finishBroadcast();
4960
Dianne Hackbornffa42482009-09-23 22:20:11 -07004961 mWindowManager.closeSystemDialogs(reason);
4962
4963 for (i=mHistory.size()-1; i>=0; i--) {
4964 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4965 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
4966 finishActivityLocked(r, i,
4967 Activity.RESULT_CANCELED, null, "close-sys");
4968 }
4969 }
4970
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004971 broadcastIntentLocked(null, null, intent, null,
4972 null, 0, null, null, null, false, false, -1, uid);
4973 }
4974 Binder.restoreCallingIdentity(origId);
4975 }
4976
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004977 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004978 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004979 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
4980 for (int i=pids.length-1; i>=0; i--) {
4981 infos[i] = new Debug.MemoryInfo();
4982 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004983 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004984 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004985 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07004986
4987 public void killApplicationProcess(String processName, int uid) {
4988 if (processName == null) {
4989 return;
4990 }
4991
4992 int callerUid = Binder.getCallingUid();
4993 // Only the system server can kill an application
4994 if (callerUid == Process.SYSTEM_UID) {
4995 synchronized (this) {
4996 ProcessRecord app = getProcessRecordLocked(processName, uid);
4997 if (app != null) {
4998 try {
4999 app.thread.scheduleSuicide();
5000 } catch (RemoteException e) {
5001 // If the other end already died, then our work here is done.
5002 }
5003 } else {
5004 Log.w(TAG, "Process/uid not found attempting kill of "
5005 + processName + " / " + uid);
5006 }
5007 }
5008 } else {
5009 throw new SecurityException(callerUid + " cannot kill app process: " +
5010 processName);
5011 }
5012 }
5013
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005014 private void restartPackageLocked(final String packageName, int uid) {
5015 uninstallPackageLocked(packageName, uid, false);
5016 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
5017 Uri.fromParts("package", packageName, null));
5018 intent.putExtra(Intent.EXTRA_UID, uid);
5019 broadcastIntentLocked(null, null, intent,
5020 null, null, 0, null, null, null,
5021 false, false, MY_PID, Process.SYSTEM_UID);
5022 }
5023
5024 private final void uninstallPackageLocked(String name, int uid,
5025 boolean callerWillRestart) {
5026 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
5027
5028 int i, N;
5029
5030 final String procNamePrefix = name + ":";
5031 if (uid < 0) {
5032 try {
5033 uid = ActivityThread.getPackageManager().getPackageUid(name);
5034 } catch (RemoteException e) {
5035 }
5036 }
5037
5038 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
5039 while (badApps.hasNext()) {
5040 SparseArray<Long> ba = badApps.next();
5041 if (ba.get(uid) != null) {
5042 badApps.remove();
5043 }
5044 }
5045
5046 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
5047
5048 // Remove all processes this package may have touched: all with the
5049 // same UID (except for the system or root user), and all whose name
5050 // matches the package name.
5051 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5052 final int NA = apps.size();
5053 for (int ia=0; ia<NA; ia++) {
5054 ProcessRecord app = apps.valueAt(ia);
5055 if (app.removed) {
5056 procs.add(app);
5057 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5058 || app.processName.equals(name)
5059 || app.processName.startsWith(procNamePrefix)) {
5060 app.removed = true;
5061 procs.add(app);
5062 }
5063 }
5064 }
5065
5066 N = procs.size();
5067 for (i=0; i<N; i++) {
5068 removeProcessLocked(procs.get(i), callerWillRestart);
5069 }
5070
5071 for (i=mHistory.size()-1; i>=0; i--) {
5072 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5073 if (r.packageName.equals(name)) {
5074 if (Config.LOGD) Log.d(
5075 TAG, " Force finishing activity "
5076 + r.intent.getComponent().flattenToShortString());
5077 if (r.app != null) {
5078 r.app.removed = true;
5079 }
5080 r.app = null;
5081 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5082 }
5083 }
5084
5085 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5086 for (ServiceRecord service : mServices.values()) {
5087 if (service.packageName.equals(name)) {
5088 if (service.app != null) {
5089 service.app.removed = true;
5090 }
5091 service.app = null;
5092 services.add(service);
5093 }
5094 }
5095
5096 N = services.size();
5097 for (i=0; i<N; i++) {
5098 bringDownServiceLocked(services.get(i), true);
5099 }
5100
5101 resumeTopActivityLocked(null);
5102 }
5103
5104 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5105 final String name = app.processName;
5106 final int uid = app.info.uid;
5107 if (Config.LOGD) Log.d(
5108 TAG, "Force removing process " + app + " (" + name
5109 + "/" + uid + ")");
5110
5111 mProcessNames.remove(name, uid);
5112 boolean needRestart = false;
5113 if (app.pid > 0 && app.pid != MY_PID) {
5114 int pid = app.pid;
5115 synchronized (mPidsSelfLocked) {
5116 mPidsSelfLocked.remove(pid);
5117 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5118 }
5119 handleAppDiedLocked(app, true);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08005120 mLruProcesses.remove(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005121 Process.killProcess(pid);
5122
5123 if (app.persistent) {
5124 if (!callerWillRestart) {
5125 addAppLocked(app.info);
5126 } else {
5127 needRestart = true;
5128 }
5129 }
5130 } else {
5131 mRemovedProcesses.add(app);
5132 }
5133
5134 return needRestart;
5135 }
5136
5137 private final void processStartTimedOutLocked(ProcessRecord app) {
5138 final int pid = app.pid;
5139 boolean gone = false;
5140 synchronized (mPidsSelfLocked) {
5141 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5142 if (knownApp != null && knownApp.thread == null) {
5143 mPidsSelfLocked.remove(pid);
5144 gone = true;
5145 }
5146 }
5147
5148 if (gone) {
5149 Log.w(TAG, "Process " + app + " failed to attach");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005150 EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, pid, app.info.uid,
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005151 app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005152 mProcessNames.remove(app.processName, app.info.uid);
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005153 // Take care of any launching providers waiting for this process.
5154 checkAppInLaunchingProvidersLocked(app, true);
5155 // Take care of any services that are waiting for the process.
5156 for (int i=0; i<mPendingServices.size(); i++) {
5157 ServiceRecord sr = mPendingServices.get(i);
5158 if (app.info.uid == sr.appInfo.uid
5159 && app.processName.equals(sr.processName)) {
5160 Log.w(TAG, "Forcing bringing down service: " + sr);
5161 mPendingServices.remove(i);
5162 i--;
5163 bringDownServiceLocked(sr, true);
5164 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005165 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005166 Process.killProcess(pid);
Christopher Tate181fafa2009-05-14 11:12:14 -07005167 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5168 Log.w(TAG, "Unattached app died before backup, skipping");
5169 try {
5170 IBackupManager bm = IBackupManager.Stub.asInterface(
5171 ServiceManager.getService(Context.BACKUP_SERVICE));
5172 bm.agentDisconnected(app.info.packageName);
5173 } catch (RemoteException e) {
5174 // Can't happen; the backup manager is local
5175 }
5176 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005177 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5178 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5179 mPendingBroadcast = null;
5180 scheduleBroadcastsLocked();
5181 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005182 } else {
5183 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5184 }
5185 }
5186
5187 private final boolean attachApplicationLocked(IApplicationThread thread,
5188 int pid) {
5189
5190 // Find the application record that is being attached... either via
5191 // the pid if we are running in multiple processes, or just pull the
5192 // next app record if we are emulating process with anonymous threads.
5193 ProcessRecord app;
5194 if (pid != MY_PID && pid >= 0) {
5195 synchronized (mPidsSelfLocked) {
5196 app = mPidsSelfLocked.get(pid);
5197 }
5198 } else if (mStartingProcesses.size() > 0) {
5199 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005200 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005201 } else {
5202 app = null;
5203 }
5204
5205 if (app == null) {
5206 Log.w(TAG, "No pending application record for pid " + pid
5207 + " (IApplicationThread " + thread + "); dropping process");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005208 EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005209 if (pid > 0 && pid != MY_PID) {
5210 Process.killProcess(pid);
5211 } else {
5212 try {
5213 thread.scheduleExit();
5214 } catch (Exception e) {
5215 // Ignore exceptions.
5216 }
5217 }
5218 return false;
5219 }
5220
5221 // If this application record is still attached to a previous
5222 // process, clean it up now.
5223 if (app.thread != null) {
5224 handleAppDiedLocked(app, true);
5225 }
5226
5227 // Tell the process all about itself.
5228
5229 if (localLOGV) Log.v(
5230 TAG, "Binding process pid " + pid + " to record " + app);
5231
5232 String processName = app.processName;
5233 try {
5234 thread.asBinder().linkToDeath(new AppDeathRecipient(
5235 app, pid, thread), 0);
5236 } catch (RemoteException e) {
5237 app.resetPackageList();
5238 startProcessLocked(app, "link fail", processName);
5239 return false;
5240 }
5241
Doug Zongker2bec3d42009-12-04 12:52:44 -08005242 EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005243
5244 app.thread = thread;
5245 app.curAdj = app.setAdj = -100;
Dianne Hackborn09c916b2009-12-08 14:50:51 -08005246 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
5247 app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005248 app.forcingToForeground = null;
5249 app.foregroundServices = false;
5250 app.debugging = false;
5251
5252 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5253
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005254 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5255 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005256
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005257 if (!normalMode) {
5258 Log.i(TAG, "Launching preboot mode app: " + app);
5259 }
5260
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005261 if (localLOGV) Log.v(
5262 TAG, "New app record " + app
5263 + " thread=" + thread.asBinder() + " pid=" + pid);
5264 try {
5265 int testMode = IApplicationThread.DEBUG_OFF;
5266 if (mDebugApp != null && mDebugApp.equals(processName)) {
5267 testMode = mWaitForDebugger
5268 ? IApplicationThread.DEBUG_WAIT
5269 : IApplicationThread.DEBUG_ON;
5270 app.debugging = true;
5271 if (mDebugTransient) {
5272 mDebugApp = mOrigDebugApp;
5273 mWaitForDebugger = mOrigWaitForDebugger;
5274 }
5275 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005276
Christopher Tate181fafa2009-05-14 11:12:14 -07005277 // If the app is being launched for restore or full backup, set it up specially
5278 boolean isRestrictedBackupMode = false;
5279 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5280 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5281 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5282 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005283
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005284 ensurePackageDexOpt(app.instrumentationInfo != null
5285 ? app.instrumentationInfo.packageName
5286 : app.info.packageName);
5287 if (app.instrumentationClass != null) {
5288 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005289 }
Dianne Hackborndc6b6352009-09-30 14:20:09 -07005290 if (DEBUG_CONFIGURATION) Log.v(TAG, "Binding proc "
5291 + processName + " with config " + mConfiguration);
Dianne Hackborn1655be42009-05-08 14:29:01 -07005292 thread.bindApplication(processName, app.instrumentationInfo != null
5293 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005294 app.instrumentationClass, app.instrumentationProfileFile,
5295 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005296 isRestrictedBackupMode || !normalMode,
5297 mConfiguration, getCommonServicesLocked());
Dianne Hackborndd71fc82009-12-16 19:24:32 -08005298 updateLruProcessLocked(app, false, true);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005299 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005300 } catch (Exception e) {
5301 // todo: Yikes! What should we do? For now we will try to
5302 // start another process, but that could easily get us in
5303 // an infinite loop of restarting processes...
5304 Log.w(TAG, "Exception thrown during bind!", e);
5305
5306 app.resetPackageList();
5307 startProcessLocked(app, "bind fail", processName);
5308 return false;
5309 }
5310
5311 // Remove this record from the list of starting applications.
5312 mPersistentStartingProcesses.remove(app);
5313 mProcessesOnHold.remove(app);
5314
5315 boolean badApp = false;
5316 boolean didSomething = false;
5317
5318 // See if the top visible activity is waiting to run in this process...
5319 HistoryRecord hr = topRunningActivityLocked(null);
5320 if (hr != null) {
5321 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5322 && processName.equals(hr.processName)) {
5323 try {
5324 if (realStartActivityLocked(hr, app, true, true)) {
5325 didSomething = true;
5326 }
5327 } catch (Exception e) {
5328 Log.w(TAG, "Exception in new application when starting activity "
5329 + hr.intent.getComponent().flattenToShortString(), e);
5330 badApp = true;
5331 }
5332 } else {
5333 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5334 }
5335 }
5336
5337 // Find any services that should be running in this process...
5338 if (!badApp && mPendingServices.size() > 0) {
5339 ServiceRecord sr = null;
5340 try {
5341 for (int i=0; i<mPendingServices.size(); i++) {
5342 sr = mPendingServices.get(i);
5343 if (app.info.uid != sr.appInfo.uid
5344 || !processName.equals(sr.processName)) {
5345 continue;
5346 }
5347
5348 mPendingServices.remove(i);
5349 i--;
5350 realStartServiceLocked(sr, app);
5351 didSomething = true;
5352 }
5353 } catch (Exception e) {
5354 Log.w(TAG, "Exception in new application when starting service "
5355 + sr.shortName, e);
5356 badApp = true;
5357 }
5358 }
5359
5360 // Check if the next broadcast receiver is in this process...
5361 BroadcastRecord br = mPendingBroadcast;
5362 if (!badApp && br != null && br.curApp == app) {
5363 try {
5364 mPendingBroadcast = null;
5365 processCurBroadcastLocked(br, app);
5366 didSomething = true;
5367 } catch (Exception e) {
5368 Log.w(TAG, "Exception in new application when starting receiver "
5369 + br.curComponent.flattenToShortString(), e);
5370 badApp = true;
5371 logBroadcastReceiverDiscard(br);
5372 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5373 br.resultExtras, br.resultAbort, true);
5374 scheduleBroadcastsLocked();
5375 }
5376 }
5377
Christopher Tate181fafa2009-05-14 11:12:14 -07005378 // Check whether the next backup agent is in this process...
5379 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5380 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005381 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005382 try {
5383 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5384 } catch (Exception e) {
5385 Log.w(TAG, "Exception scheduling backup agent creation: ");
5386 e.printStackTrace();
5387 }
5388 }
5389
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005390 if (badApp) {
5391 // todo: Also need to kill application to deal with all
5392 // kinds of exceptions.
5393 handleAppDiedLocked(app, false);
5394 return false;
5395 }
5396
5397 if (!didSomething) {
5398 updateOomAdjLocked();
5399 }
5400
5401 return true;
5402 }
5403
5404 public final void attachApplication(IApplicationThread thread) {
5405 synchronized (this) {
5406 int callingPid = Binder.getCallingPid();
5407 final long origId = Binder.clearCallingIdentity();
5408 attachApplicationLocked(thread, callingPid);
5409 Binder.restoreCallingIdentity(origId);
5410 }
5411 }
5412
Dianne Hackborne88846e2009-09-30 21:34:25 -07005413 public final void activityIdle(IBinder token, Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005414 final long origId = Binder.clearCallingIdentity();
Dianne Hackborne88846e2009-09-30 21:34:25 -07005415 activityIdleInternal(token, false, config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005416 Binder.restoreCallingIdentity(origId);
5417 }
5418
5419 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5420 boolean remove) {
5421 int N = mStoppingActivities.size();
5422 if (N <= 0) return null;
5423
5424 ArrayList<HistoryRecord> stops = null;
5425
5426 final boolean nowVisible = mResumedActivity != null
5427 && mResumedActivity.nowVisible
5428 && !mResumedActivity.waitingVisible;
5429 for (int i=0; i<N; i++) {
5430 HistoryRecord s = mStoppingActivities.get(i);
5431 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5432 + nowVisible + " waitingVisible=" + s.waitingVisible
5433 + " finishing=" + s.finishing);
5434 if (s.waitingVisible && nowVisible) {
5435 mWaitingVisibleActivities.remove(s);
5436 s.waitingVisible = false;
5437 if (s.finishing) {
5438 // If this activity is finishing, it is sitting on top of
5439 // everyone else but we now know it is no longer needed...
5440 // so get rid of it. Otherwise, we need to go through the
5441 // normal flow and hide it once we determine that it is
5442 // hidden by the activities in front of it.
5443 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5444 mWindowManager.setAppVisibility(s, false);
5445 }
5446 }
5447 if (!s.waitingVisible && remove) {
5448 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5449 if (stops == null) {
5450 stops = new ArrayList<HistoryRecord>();
5451 }
5452 stops.add(s);
5453 mStoppingActivities.remove(i);
5454 N--;
5455 i--;
5456 }
5457 }
5458
5459 return stops;
5460 }
5461
5462 void enableScreenAfterBoot() {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005463 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005464 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005465 mWindowManager.enableScreenAfterBoot();
5466 }
5467
Dianne Hackborne88846e2009-09-30 21:34:25 -07005468 final void activityIdleInternal(IBinder token, boolean fromTimeout,
5469 Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005470 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5471
5472 ArrayList<HistoryRecord> stops = null;
5473 ArrayList<HistoryRecord> finishes = null;
5474 ArrayList<HistoryRecord> thumbnails = null;
5475 int NS = 0;
5476 int NF = 0;
5477 int NT = 0;
5478 IApplicationThread sendThumbnail = null;
5479 boolean booting = false;
5480 boolean enableScreen = false;
5481
5482 synchronized (this) {
5483 if (token != null) {
5484 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5485 }
5486
5487 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005488 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005489 if (index >= 0) {
5490 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5491
Dianne Hackborne88846e2009-09-30 21:34:25 -07005492 // This is a hack to semi-deal with a race condition
5493 // in the client where it can be constructed with a
5494 // newer configuration from when we asked it to launch.
5495 // We'll update with whatever configuration it now says
5496 // it used to launch.
5497 if (config != null) {
5498 r.configuration = config;
5499 }
5500
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005501 // No longer need to keep the device awake.
5502 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5503 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5504 mLaunchingActivity.release();
5505 }
5506
5507 // We are now idle. If someone is waiting for a thumbnail from
5508 // us, we can now deliver.
5509 r.idle = true;
5510 scheduleAppGcsLocked();
5511 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5512 sendThumbnail = r.app.thread;
5513 r.thumbnailNeeded = false;
5514 }
5515
5516 // If this activity is fullscreen, set up to hide those under it.
5517
5518 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5519 ensureActivitiesVisibleLocked(null, 0);
5520
5521 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5522 if (!mBooted && !fromTimeout) {
5523 mBooted = true;
5524 enableScreen = true;
5525 }
5526 }
5527
5528 // Atomically retrieve all of the other things to do.
5529 stops = processStoppingActivitiesLocked(true);
5530 NS = stops != null ? stops.size() : 0;
5531 if ((NF=mFinishingActivities.size()) > 0) {
5532 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5533 mFinishingActivities.clear();
5534 }
5535 if ((NT=mCancelledThumbnails.size()) > 0) {
5536 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5537 mCancelledThumbnails.clear();
5538 }
5539
5540 booting = mBooting;
5541 mBooting = false;
5542 }
5543
5544 int i;
5545
5546 // Send thumbnail if requested.
5547 if (sendThumbnail != null) {
5548 try {
5549 sendThumbnail.requestThumbnail(token);
5550 } catch (Exception e) {
5551 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5552 sendPendingThumbnail(null, token, null, null, true);
5553 }
5554 }
5555
5556 // Stop any activities that are scheduled to do so but have been
5557 // waiting for the next one to start.
5558 for (i=0; i<NS; i++) {
5559 HistoryRecord r = (HistoryRecord)stops.get(i);
5560 synchronized (this) {
5561 if (r.finishing) {
5562 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5563 } else {
5564 stopActivityLocked(r);
5565 }
5566 }
5567 }
5568
5569 // Finish any activities that are scheduled to do so but have been
5570 // waiting for the next one to start.
5571 for (i=0; i<NF; i++) {
5572 HistoryRecord r = (HistoryRecord)finishes.get(i);
5573 synchronized (this) {
5574 destroyActivityLocked(r, true);
5575 }
5576 }
5577
5578 // Report back to any thumbnail receivers.
5579 for (i=0; i<NT; i++) {
5580 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5581 sendPendingThumbnail(r, null, null, null, true);
5582 }
5583
5584 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005585 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005586 }
5587
5588 trimApplications();
5589 //dump();
5590 //mWindowManager.dump();
5591
5592 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005593 enableScreenAfterBoot();
5594 }
5595 }
5596
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005597 final void finishBooting() {
5598 // Ensure that any processes we had put on hold are now started
5599 // up.
5600 final int NP = mProcessesOnHold.size();
5601 if (NP > 0) {
5602 ArrayList<ProcessRecord> procs =
5603 new ArrayList<ProcessRecord>(mProcessesOnHold);
5604 for (int ip=0; ip<NP; ip++) {
5605 this.startProcessLocked(procs.get(ip), "on-hold", null);
5606 }
5607 }
5608 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5609 // Tell anyone interested that we are done booting!
5610 synchronized (this) {
5611 broadcastIntentLocked(null, null,
5612 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5613 null, null, 0, null, null,
5614 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5615 false, false, MY_PID, Process.SYSTEM_UID);
5616 }
5617 }
5618 }
5619
5620 final void ensureBootCompleted() {
5621 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005622 boolean enableScreen;
5623 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005624 booting = mBooting;
5625 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005626 enableScreen = !mBooted;
5627 mBooted = true;
5628 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005629
5630 if (booting) {
5631 finishBooting();
5632 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005633
5634 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005635 enableScreenAfterBoot();
5636 }
5637 }
5638
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005639 public final void activityPaused(IBinder token, Bundle icicle) {
5640 // Refuse possible leaked file descriptors
5641 if (icicle != null && icicle.hasFileDescriptors()) {
5642 throw new IllegalArgumentException("File descriptors passed in Bundle");
5643 }
5644
5645 final long origId = Binder.clearCallingIdentity();
5646 activityPaused(token, icicle, false);
5647 Binder.restoreCallingIdentity(origId);
5648 }
5649
5650 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5651 if (DEBUG_PAUSE) Log.v(
5652 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5653 + ", timeout=" + timeout);
5654
5655 HistoryRecord r = null;
5656
5657 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005658 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005659 if (index >= 0) {
5660 r = (HistoryRecord)mHistory.get(index);
5661 if (!timeout) {
5662 r.icicle = icicle;
5663 r.haveState = true;
5664 }
5665 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5666 if (mPausingActivity == r) {
5667 r.state = ActivityState.PAUSED;
5668 completePauseLocked();
5669 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005670 EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005671 System.identityHashCode(r), r.shortComponentName,
5672 mPausingActivity != null
5673 ? mPausingActivity.shortComponentName : "(none)");
5674 }
5675 }
5676 }
5677 }
5678
5679 public final void activityStopped(IBinder token, Bitmap thumbnail,
5680 CharSequence description) {
5681 if (localLOGV) Log.v(
5682 TAG, "Activity stopped: token=" + token);
5683
5684 HistoryRecord r = null;
5685
5686 final long origId = Binder.clearCallingIdentity();
5687
5688 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005689 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005690 if (index >= 0) {
5691 r = (HistoryRecord)mHistory.get(index);
5692 r.thumbnail = thumbnail;
5693 r.description = description;
5694 r.stopped = true;
5695 r.state = ActivityState.STOPPED;
5696 if (!r.finishing) {
5697 if (r.configDestroy) {
5698 destroyActivityLocked(r, true);
5699 resumeTopActivityLocked(null);
5700 }
5701 }
5702 }
5703 }
5704
5705 if (r != null) {
5706 sendPendingThumbnail(r, null, null, null, false);
5707 }
5708
5709 trimApplications();
5710
5711 Binder.restoreCallingIdentity(origId);
5712 }
5713
5714 public final void activityDestroyed(IBinder token) {
5715 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5716 synchronized (this) {
5717 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5718
Dianne Hackborn75b03852009-06-12 15:43:26 -07005719 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005720 if (index >= 0) {
5721 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5722 if (r.state == ActivityState.DESTROYING) {
5723 final long origId = Binder.clearCallingIdentity();
5724 removeActivityFromHistoryLocked(r);
5725 Binder.restoreCallingIdentity(origId);
5726 }
5727 }
5728 }
5729 }
5730
5731 public String getCallingPackage(IBinder token) {
5732 synchronized (this) {
5733 HistoryRecord r = getCallingRecordLocked(token);
Dianne Hackborn9bbcb912009-10-20 15:42:38 -07005734 return r != null && r.app != null ? r.info.packageName : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005735 }
5736 }
5737
5738 public ComponentName getCallingActivity(IBinder token) {
5739 synchronized (this) {
5740 HistoryRecord r = getCallingRecordLocked(token);
5741 return r != null ? r.intent.getComponent() : null;
5742 }
5743 }
5744
5745 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005746 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005747 if (index >= 0) {
5748 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5749 if (r != null) {
5750 return r.resultTo;
5751 }
5752 }
5753 return null;
5754 }
5755
5756 public ComponentName getActivityClassForToken(IBinder token) {
5757 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005758 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005759 if (index >= 0) {
5760 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5761 return r.intent.getComponent();
5762 }
5763 return null;
5764 }
5765 }
5766
5767 public String getPackageForToken(IBinder token) {
5768 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005769 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005770 if (index >= 0) {
5771 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5772 return r.packageName;
5773 }
5774 return null;
5775 }
5776 }
5777
5778 public IIntentSender getIntentSender(int type,
5779 String packageName, IBinder token, String resultWho,
5780 int requestCode, Intent intent, String resolvedType, int flags) {
5781 // Refuse possible leaked file descriptors
5782 if (intent != null && intent.hasFileDescriptors() == true) {
5783 throw new IllegalArgumentException("File descriptors passed in Intent");
5784 }
5785
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005786 if (type == INTENT_SENDER_BROADCAST) {
5787 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5788 throw new IllegalArgumentException(
5789 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5790 }
5791 }
5792
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005793 synchronized(this) {
5794 int callingUid = Binder.getCallingUid();
5795 try {
5796 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5797 Process.supportsProcesses()) {
5798 int uid = ActivityThread.getPackageManager()
5799 .getPackageUid(packageName);
5800 if (uid != Binder.getCallingUid()) {
5801 String msg = "Permission Denial: getIntentSender() from pid="
5802 + Binder.getCallingPid()
5803 + ", uid=" + Binder.getCallingUid()
5804 + ", (need uid=" + uid + ")"
5805 + " is not allowed to send as package " + packageName;
5806 Log.w(TAG, msg);
5807 throw new SecurityException(msg);
5808 }
5809 }
5810 } catch (RemoteException e) {
5811 throw new SecurityException(e);
5812 }
5813 HistoryRecord activity = null;
5814 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005815 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005816 if (index < 0) {
5817 return null;
5818 }
5819 activity = (HistoryRecord)mHistory.get(index);
5820 if (activity.finishing) {
5821 return null;
5822 }
5823 }
5824
5825 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5826 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5827 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5828 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5829 |PendingIntent.FLAG_UPDATE_CURRENT);
5830
5831 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5832 type, packageName, activity, resultWho,
5833 requestCode, intent, resolvedType, flags);
5834 WeakReference<PendingIntentRecord> ref;
5835 ref = mIntentSenderRecords.get(key);
5836 PendingIntentRecord rec = ref != null ? ref.get() : null;
5837 if (rec != null) {
5838 if (!cancelCurrent) {
5839 if (updateCurrent) {
5840 rec.key.requestIntent.replaceExtras(intent);
5841 }
5842 return rec;
5843 }
5844 rec.canceled = true;
5845 mIntentSenderRecords.remove(key);
5846 }
5847 if (noCreate) {
5848 return rec;
5849 }
5850 rec = new PendingIntentRecord(this, key, callingUid);
5851 mIntentSenderRecords.put(key, rec.ref);
5852 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5853 if (activity.pendingResults == null) {
5854 activity.pendingResults
5855 = new HashSet<WeakReference<PendingIntentRecord>>();
5856 }
5857 activity.pendingResults.add(rec.ref);
5858 }
5859 return rec;
5860 }
5861 }
5862
5863 public void cancelIntentSender(IIntentSender sender) {
5864 if (!(sender instanceof PendingIntentRecord)) {
5865 return;
5866 }
5867 synchronized(this) {
5868 PendingIntentRecord rec = (PendingIntentRecord)sender;
5869 try {
5870 int uid = ActivityThread.getPackageManager()
5871 .getPackageUid(rec.key.packageName);
5872 if (uid != Binder.getCallingUid()) {
5873 String msg = "Permission Denial: cancelIntentSender() from pid="
5874 + Binder.getCallingPid()
5875 + ", uid=" + Binder.getCallingUid()
5876 + " is not allowed to cancel packges "
5877 + rec.key.packageName;
5878 Log.w(TAG, msg);
5879 throw new SecurityException(msg);
5880 }
5881 } catch (RemoteException e) {
5882 throw new SecurityException(e);
5883 }
5884 cancelIntentSenderLocked(rec, true);
5885 }
5886 }
5887
5888 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5889 rec.canceled = true;
5890 mIntentSenderRecords.remove(rec.key);
5891 if (cleanActivity && rec.key.activity != null) {
5892 rec.key.activity.pendingResults.remove(rec.ref);
5893 }
5894 }
5895
5896 public String getPackageForIntentSender(IIntentSender pendingResult) {
5897 if (!(pendingResult instanceof PendingIntentRecord)) {
5898 return null;
5899 }
5900 synchronized(this) {
5901 try {
5902 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5903 return res.key.packageName;
5904 } catch (ClassCastException e) {
5905 }
5906 }
5907 return null;
5908 }
5909
5910 public void setProcessLimit(int max) {
5911 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5912 "setProcessLimit()");
5913 mProcessLimit = max;
5914 }
5915
5916 public int getProcessLimit() {
5917 return mProcessLimit;
5918 }
5919
5920 void foregroundTokenDied(ForegroundToken token) {
5921 synchronized (ActivityManagerService.this) {
5922 synchronized (mPidsSelfLocked) {
5923 ForegroundToken cur
5924 = mForegroundProcesses.get(token.pid);
5925 if (cur != token) {
5926 return;
5927 }
5928 mForegroundProcesses.remove(token.pid);
5929 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5930 if (pr == null) {
5931 return;
5932 }
5933 pr.forcingToForeground = null;
5934 pr.foregroundServices = false;
5935 }
5936 updateOomAdjLocked();
5937 }
5938 }
5939
5940 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5941 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5942 "setProcessForeground()");
5943 synchronized(this) {
5944 boolean changed = false;
5945
5946 synchronized (mPidsSelfLocked) {
5947 ProcessRecord pr = mPidsSelfLocked.get(pid);
5948 if (pr == null) {
5949 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5950 return;
5951 }
5952 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5953 if (oldToken != null) {
5954 oldToken.token.unlinkToDeath(oldToken, 0);
5955 mForegroundProcesses.remove(pid);
5956 pr.forcingToForeground = null;
5957 changed = true;
5958 }
5959 if (isForeground && token != null) {
5960 ForegroundToken newToken = new ForegroundToken() {
5961 public void binderDied() {
5962 foregroundTokenDied(this);
5963 }
5964 };
5965 newToken.pid = pid;
5966 newToken.token = token;
5967 try {
5968 token.linkToDeath(newToken, 0);
5969 mForegroundProcesses.put(pid, newToken);
5970 pr.forcingToForeground = token;
5971 changed = true;
5972 } catch (RemoteException e) {
5973 // If the process died while doing this, we will later
5974 // do the cleanup with the process death link.
5975 }
5976 }
5977 }
5978
5979 if (changed) {
5980 updateOomAdjLocked();
5981 }
5982 }
5983 }
5984
5985 // =========================================================
5986 // PERMISSIONS
5987 // =========================================================
5988
5989 static class PermissionController extends IPermissionController.Stub {
5990 ActivityManagerService mActivityManagerService;
5991 PermissionController(ActivityManagerService activityManagerService) {
5992 mActivityManagerService = activityManagerService;
5993 }
5994
5995 public boolean checkPermission(String permission, int pid, int uid) {
5996 return mActivityManagerService.checkPermission(permission, pid,
5997 uid) == PackageManager.PERMISSION_GRANTED;
5998 }
5999 }
6000
6001 /**
6002 * This can be called with or without the global lock held.
6003 */
6004 int checkComponentPermission(String permission, int pid, int uid,
6005 int reqUid) {
6006 // We might be performing an operation on behalf of an indirect binder
6007 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
6008 // client identity accordingly before proceeding.
6009 Identity tlsIdentity = sCallerIdentity.get();
6010 if (tlsIdentity != null) {
6011 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
6012 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
6013 uid = tlsIdentity.uid;
6014 pid = tlsIdentity.pid;
6015 }
6016
6017 // Root, system server and our own process get to do everything.
6018 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
6019 !Process.supportsProcesses()) {
6020 return PackageManager.PERMISSION_GRANTED;
6021 }
6022 // If the target requires a specific UID, always fail for others.
6023 if (reqUid >= 0 && uid != reqUid) {
root0369a7c2009-03-23 15:20:47 +01006024 Log.w(TAG, "Permission denied: checkComponentPermission() reqUid=" + reqUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006025 return PackageManager.PERMISSION_DENIED;
6026 }
6027 if (permission == null) {
6028 return PackageManager.PERMISSION_GRANTED;
6029 }
6030 try {
6031 return ActivityThread.getPackageManager()
6032 .checkUidPermission(permission, uid);
6033 } catch (RemoteException e) {
6034 // Should never happen, but if it does... deny!
6035 Log.e(TAG, "PackageManager is dead?!?", e);
6036 }
6037 return PackageManager.PERMISSION_DENIED;
6038 }
6039
6040 /**
6041 * As the only public entry point for permissions checking, this method
6042 * can enforce the semantic that requesting a check on a null global
6043 * permission is automatically denied. (Internally a null permission
6044 * string is used when calling {@link #checkComponentPermission} in cases
6045 * when only uid-based security is needed.)
6046 *
6047 * This can be called with or without the global lock held.
6048 */
6049 public int checkPermission(String permission, int pid, int uid) {
6050 if (permission == null) {
6051 return PackageManager.PERMISSION_DENIED;
6052 }
6053 return checkComponentPermission(permission, pid, uid, -1);
6054 }
6055
6056 /**
6057 * Binder IPC calls go through the public entry point.
6058 * This can be called with or without the global lock held.
6059 */
6060 int checkCallingPermission(String permission) {
6061 return checkPermission(permission,
6062 Binder.getCallingPid(),
6063 Binder.getCallingUid());
6064 }
6065
6066 /**
6067 * This can be called with or without the global lock held.
6068 */
6069 void enforceCallingPermission(String permission, String func) {
6070 if (checkCallingPermission(permission)
6071 == PackageManager.PERMISSION_GRANTED) {
6072 return;
6073 }
6074
6075 String msg = "Permission Denial: " + func + " from pid="
6076 + Binder.getCallingPid()
6077 + ", uid=" + Binder.getCallingUid()
6078 + " requires " + permission;
6079 Log.w(TAG, msg);
6080 throw new SecurityException(msg);
6081 }
6082
6083 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6084 ProviderInfo pi, int uid, int modeFlags) {
6085 try {
6086 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6087 if ((pi.readPermission != null) &&
6088 (pm.checkUidPermission(pi.readPermission, uid)
6089 != PackageManager.PERMISSION_GRANTED)) {
6090 return false;
6091 }
6092 }
6093 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6094 if ((pi.writePermission != null) &&
6095 (pm.checkUidPermission(pi.writePermission, uid)
6096 != PackageManager.PERMISSION_GRANTED)) {
6097 return false;
6098 }
6099 }
6100 return true;
6101 } catch (RemoteException e) {
6102 return false;
6103 }
6104 }
6105
6106 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6107 int modeFlags) {
6108 // Root gets to do everything.
6109 if (uid == 0 || !Process.supportsProcesses()) {
6110 return true;
6111 }
6112 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6113 if (perms == null) return false;
6114 UriPermission perm = perms.get(uri);
6115 if (perm == null) return false;
6116 return (modeFlags&perm.modeFlags) == modeFlags;
6117 }
6118
6119 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6120 // Another redirected-binder-call permissions check as in
6121 // {@link checkComponentPermission}.
6122 Identity tlsIdentity = sCallerIdentity.get();
6123 if (tlsIdentity != null) {
6124 uid = tlsIdentity.uid;
6125 pid = tlsIdentity.pid;
6126 }
6127
6128 // Our own process gets to do everything.
6129 if (pid == MY_PID) {
6130 return PackageManager.PERMISSION_GRANTED;
6131 }
6132 synchronized(this) {
6133 return checkUriPermissionLocked(uri, uid, modeFlags)
6134 ? PackageManager.PERMISSION_GRANTED
6135 : PackageManager.PERMISSION_DENIED;
6136 }
6137 }
6138
6139 private void grantUriPermissionLocked(int callingUid,
6140 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6141 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6142 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6143 if (modeFlags == 0) {
6144 return;
6145 }
6146
6147 final IPackageManager pm = ActivityThread.getPackageManager();
6148
6149 // If this is not a content: uri, we can't do anything with it.
6150 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6151 return;
6152 }
6153
6154 String name = uri.getAuthority();
6155 ProviderInfo pi = null;
6156 ContentProviderRecord cpr
6157 = (ContentProviderRecord)mProvidersByName.get(name);
6158 if (cpr != null) {
6159 pi = cpr.info;
6160 } else {
6161 try {
6162 pi = pm.resolveContentProvider(name,
6163 PackageManager.GET_URI_PERMISSION_PATTERNS);
6164 } catch (RemoteException ex) {
6165 }
6166 }
6167 if (pi == null) {
6168 Log.w(TAG, "No content provider found for: " + name);
6169 return;
6170 }
6171
6172 int targetUid;
6173 try {
6174 targetUid = pm.getPackageUid(targetPkg);
6175 if (targetUid < 0) {
6176 return;
6177 }
6178 } catch (RemoteException ex) {
6179 return;
6180 }
6181
6182 // First... does the target actually need this permission?
6183 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6184 // No need to grant the target this permission.
6185 return;
6186 }
6187
6188 // Second... maybe someone else has already granted the
6189 // permission?
6190 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6191 // No need to grant the target this permission.
6192 return;
6193 }
6194
6195 // Third... is the provider allowing granting of URI permissions?
6196 if (!pi.grantUriPermissions) {
6197 throw new SecurityException("Provider " + pi.packageName
6198 + "/" + pi.name
6199 + " does not allow granting of Uri permissions (uri "
6200 + uri + ")");
6201 }
6202 if (pi.uriPermissionPatterns != null) {
6203 final int N = pi.uriPermissionPatterns.length;
6204 boolean allowed = false;
6205 for (int i=0; i<N; i++) {
6206 if (pi.uriPermissionPatterns[i] != null
6207 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6208 allowed = true;
6209 break;
6210 }
6211 }
6212 if (!allowed) {
6213 throw new SecurityException("Provider " + pi.packageName
6214 + "/" + pi.name
6215 + " does not allow granting of permission to path of Uri "
6216 + uri);
6217 }
6218 }
6219
6220 // Fourth... does the caller itself have permission to access
6221 // this uri?
6222 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6223 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6224 throw new SecurityException("Uid " + callingUid
6225 + " does not have permission to uri " + uri);
6226 }
6227 }
6228
6229 // Okay! So here we are: the caller has the assumed permission
6230 // to the uri, and the target doesn't. Let's now give this to
6231 // the target.
6232
6233 HashMap<Uri, UriPermission> targetUris
6234 = mGrantedUriPermissions.get(targetUid);
6235 if (targetUris == null) {
6236 targetUris = new HashMap<Uri, UriPermission>();
6237 mGrantedUriPermissions.put(targetUid, targetUris);
6238 }
6239
6240 UriPermission perm = targetUris.get(uri);
6241 if (perm == null) {
6242 perm = new UriPermission(targetUid, uri);
6243 targetUris.put(uri, perm);
6244
6245 }
6246 perm.modeFlags |= modeFlags;
6247 if (activity == null) {
6248 perm.globalModeFlags |= modeFlags;
6249 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6250 perm.readActivities.add(activity);
6251 if (activity.readUriPermissions == null) {
6252 activity.readUriPermissions = new HashSet<UriPermission>();
6253 }
6254 activity.readUriPermissions.add(perm);
6255 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6256 perm.writeActivities.add(activity);
6257 if (activity.writeUriPermissions == null) {
6258 activity.writeUriPermissions = new HashSet<UriPermission>();
6259 }
6260 activity.writeUriPermissions.add(perm);
6261 }
6262 }
6263
6264 private void grantUriPermissionFromIntentLocked(int callingUid,
6265 String targetPkg, Intent intent, HistoryRecord activity) {
6266 if (intent == null) {
6267 return;
6268 }
6269 Uri data = intent.getData();
6270 if (data == null) {
6271 return;
6272 }
6273 grantUriPermissionLocked(callingUid, targetPkg, data,
6274 intent.getFlags(), activity);
6275 }
6276
6277 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6278 Uri uri, int modeFlags) {
6279 synchronized(this) {
6280 final ProcessRecord r = getRecordForAppLocked(caller);
6281 if (r == null) {
6282 throw new SecurityException("Unable to find app for caller "
6283 + caller
6284 + " when granting permission to uri " + uri);
6285 }
6286 if (targetPkg == null) {
6287 Log.w(TAG, "grantUriPermission: null target");
6288 return;
6289 }
6290 if (uri == null) {
6291 Log.w(TAG, "grantUriPermission: null uri");
6292 return;
6293 }
6294
6295 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6296 null);
6297 }
6298 }
6299
6300 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6301 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6302 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6303 HashMap<Uri, UriPermission> perms
6304 = mGrantedUriPermissions.get(perm.uid);
6305 if (perms != null) {
6306 perms.remove(perm.uri);
6307 if (perms.size() == 0) {
6308 mGrantedUriPermissions.remove(perm.uid);
6309 }
6310 }
6311 }
6312 }
6313
6314 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6315 if (activity.readUriPermissions != null) {
6316 for (UriPermission perm : activity.readUriPermissions) {
6317 perm.readActivities.remove(activity);
6318 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6319 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6320 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6321 removeUriPermissionIfNeededLocked(perm);
6322 }
6323 }
6324 }
6325 if (activity.writeUriPermissions != null) {
6326 for (UriPermission perm : activity.writeUriPermissions) {
6327 perm.writeActivities.remove(activity);
6328 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6329 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6330 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6331 removeUriPermissionIfNeededLocked(perm);
6332 }
6333 }
6334 }
6335 }
6336
6337 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6338 int modeFlags) {
6339 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6340 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6341 if (modeFlags == 0) {
6342 return;
6343 }
6344
6345 final IPackageManager pm = ActivityThread.getPackageManager();
6346
6347 final String authority = uri.getAuthority();
6348 ProviderInfo pi = null;
6349 ContentProviderRecord cpr
6350 = (ContentProviderRecord)mProvidersByName.get(authority);
6351 if (cpr != null) {
6352 pi = cpr.info;
6353 } else {
6354 try {
6355 pi = pm.resolveContentProvider(authority,
6356 PackageManager.GET_URI_PERMISSION_PATTERNS);
6357 } catch (RemoteException ex) {
6358 }
6359 }
6360 if (pi == null) {
6361 Log.w(TAG, "No content provider found for: " + authority);
6362 return;
6363 }
6364
6365 // Does the caller have this permission on the URI?
6366 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6367 // Right now, if you are not the original owner of the permission,
6368 // you are not allowed to revoke it.
6369 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6370 throw new SecurityException("Uid " + callingUid
6371 + " does not have permission to uri " + uri);
6372 //}
6373 }
6374
6375 // Go through all of the permissions and remove any that match.
6376 final List<String> SEGMENTS = uri.getPathSegments();
6377 if (SEGMENTS != null) {
6378 final int NS = SEGMENTS.size();
6379 int N = mGrantedUriPermissions.size();
6380 for (int i=0; i<N; i++) {
6381 HashMap<Uri, UriPermission> perms
6382 = mGrantedUriPermissions.valueAt(i);
6383 Iterator<UriPermission> it = perms.values().iterator();
6384 toploop:
6385 while (it.hasNext()) {
6386 UriPermission perm = it.next();
6387 Uri targetUri = perm.uri;
6388 if (!authority.equals(targetUri.getAuthority())) {
6389 continue;
6390 }
6391 List<String> targetSegments = targetUri.getPathSegments();
6392 if (targetSegments == null) {
6393 continue;
6394 }
6395 if (targetSegments.size() < NS) {
6396 continue;
6397 }
6398 for (int j=0; j<NS; j++) {
6399 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6400 continue toploop;
6401 }
6402 }
6403 perm.clearModes(modeFlags);
6404 if (perm.modeFlags == 0) {
6405 it.remove();
6406 }
6407 }
6408 if (perms.size() == 0) {
6409 mGrantedUriPermissions.remove(
6410 mGrantedUriPermissions.keyAt(i));
6411 N--;
6412 i--;
6413 }
6414 }
6415 }
6416 }
6417
6418 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6419 int modeFlags) {
6420 synchronized(this) {
6421 final ProcessRecord r = getRecordForAppLocked(caller);
6422 if (r == null) {
6423 throw new SecurityException("Unable to find app for caller "
6424 + caller
6425 + " when revoking permission to uri " + uri);
6426 }
6427 if (uri == null) {
6428 Log.w(TAG, "revokeUriPermission: null uri");
6429 return;
6430 }
6431
6432 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6433 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6434 if (modeFlags == 0) {
6435 return;
6436 }
6437
6438 final IPackageManager pm = ActivityThread.getPackageManager();
6439
6440 final String authority = uri.getAuthority();
6441 ProviderInfo pi = null;
6442 ContentProviderRecord cpr
6443 = (ContentProviderRecord)mProvidersByName.get(authority);
6444 if (cpr != null) {
6445 pi = cpr.info;
6446 } else {
6447 try {
6448 pi = pm.resolveContentProvider(authority,
6449 PackageManager.GET_URI_PERMISSION_PATTERNS);
6450 } catch (RemoteException ex) {
6451 }
6452 }
6453 if (pi == null) {
6454 Log.w(TAG, "No content provider found for: " + authority);
6455 return;
6456 }
6457
6458 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6459 }
6460 }
6461
6462 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6463 synchronized (this) {
6464 ProcessRecord app =
6465 who != null ? getRecordForAppLocked(who) : null;
6466 if (app == null) return;
6467
6468 Message msg = Message.obtain();
6469 msg.what = WAIT_FOR_DEBUGGER_MSG;
6470 msg.obj = app;
6471 msg.arg1 = waiting ? 1 : 0;
6472 mHandler.sendMessage(msg);
6473 }
6474 }
6475
6476 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6477 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006478 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006479 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006480 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006481 }
6482
6483 // =========================================================
6484 // TASK MANAGEMENT
6485 // =========================================================
6486
6487 public List getTasks(int maxNum, int flags,
6488 IThumbnailReceiver receiver) {
6489 ArrayList list = new ArrayList();
6490
6491 PendingThumbnailsRecord pending = null;
6492 IApplicationThread topThumbnail = null;
6493 HistoryRecord topRecord = null;
6494
6495 synchronized(this) {
6496 if (localLOGV) Log.v(
6497 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6498 + ", receiver=" + receiver);
6499
6500 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6501 != PackageManager.PERMISSION_GRANTED) {
6502 if (receiver != null) {
6503 // If the caller wants to wait for pending thumbnails,
6504 // it ain't gonna get them.
6505 try {
6506 receiver.finished();
6507 } catch (RemoteException ex) {
6508 }
6509 }
6510 String msg = "Permission Denial: getTasks() from pid="
6511 + Binder.getCallingPid()
6512 + ", uid=" + Binder.getCallingUid()
6513 + " requires " + android.Manifest.permission.GET_TASKS;
6514 Log.w(TAG, msg);
6515 throw new SecurityException(msg);
6516 }
6517
6518 int pos = mHistory.size()-1;
6519 HistoryRecord next =
6520 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6521 HistoryRecord top = null;
6522 CharSequence topDescription = null;
6523 TaskRecord curTask = null;
6524 int numActivities = 0;
6525 int numRunning = 0;
6526 while (pos >= 0 && maxNum > 0) {
6527 final HistoryRecord r = next;
6528 pos--;
6529 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6530
6531 // Initialize state for next task if needed.
6532 if (top == null ||
6533 (top.state == ActivityState.INITIALIZING
6534 && top.task == r.task)) {
6535 top = r;
6536 topDescription = r.description;
6537 curTask = r.task;
6538 numActivities = numRunning = 0;
6539 }
6540
6541 // Add 'r' into the current task.
6542 numActivities++;
6543 if (r.app != null && r.app.thread != null) {
6544 numRunning++;
6545 }
6546 if (topDescription == null) {
6547 topDescription = r.description;
6548 }
6549
6550 if (localLOGV) Log.v(
6551 TAG, r.intent.getComponent().flattenToShortString()
6552 + ": task=" + r.task);
6553
6554 // If the next one is a different task, generate a new
6555 // TaskInfo entry for what we have.
6556 if (next == null || next.task != curTask) {
6557 ActivityManager.RunningTaskInfo ci
6558 = new ActivityManager.RunningTaskInfo();
6559 ci.id = curTask.taskId;
6560 ci.baseActivity = r.intent.getComponent();
6561 ci.topActivity = top.intent.getComponent();
6562 ci.thumbnail = top.thumbnail;
6563 ci.description = topDescription;
6564 ci.numActivities = numActivities;
6565 ci.numRunning = numRunning;
6566 //System.out.println(
6567 // "#" + maxNum + ": " + " descr=" + ci.description);
6568 if (ci.thumbnail == null && receiver != null) {
6569 if (localLOGV) Log.v(
6570 TAG, "State=" + top.state + "Idle=" + top.idle
6571 + " app=" + top.app
6572 + " thr=" + (top.app != null ? top.app.thread : null));
6573 if (top.state == ActivityState.RESUMED
6574 || top.state == ActivityState.PAUSING) {
6575 if (top.idle && top.app != null
6576 && top.app.thread != null) {
6577 topRecord = top;
6578 topThumbnail = top.app.thread;
6579 } else {
6580 top.thumbnailNeeded = true;
6581 }
6582 }
6583 if (pending == null) {
6584 pending = new PendingThumbnailsRecord(receiver);
6585 }
6586 pending.pendingRecords.add(top);
6587 }
6588 list.add(ci);
6589 maxNum--;
6590 top = null;
6591 }
6592 }
6593
6594 if (pending != null) {
6595 mPendingThumbnails.add(pending);
6596 }
6597 }
6598
6599 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6600
6601 if (topThumbnail != null) {
6602 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6603 try {
6604 topThumbnail.requestThumbnail(topRecord);
6605 } catch (Exception e) {
6606 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6607 sendPendingThumbnail(null, topRecord, null, null, true);
6608 }
6609 }
6610
6611 if (pending == null && receiver != null) {
6612 // In this case all thumbnails were available and the client
6613 // is being asked to be told when the remaining ones come in...
6614 // which is unusually, since the top-most currently running
6615 // activity should never have a canned thumbnail! Oh well.
6616 try {
6617 receiver.finished();
6618 } catch (RemoteException ex) {
6619 }
6620 }
6621
6622 return list;
6623 }
6624
6625 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6626 int flags) {
6627 synchronized (this) {
6628 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6629 "getRecentTasks()");
6630
6631 final int N = mRecentTasks.size();
6632 ArrayList<ActivityManager.RecentTaskInfo> res
6633 = new ArrayList<ActivityManager.RecentTaskInfo>(
6634 maxNum < N ? maxNum : N);
6635 for (int i=0; i<N && maxNum > 0; i++) {
6636 TaskRecord tr = mRecentTasks.get(i);
6637 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6638 || (tr.intent == null)
6639 || ((tr.intent.getFlags()
6640 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6641 ActivityManager.RecentTaskInfo rti
6642 = new ActivityManager.RecentTaskInfo();
6643 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6644 rti.baseIntent = new Intent(
6645 tr.intent != null ? tr.intent : tr.affinityIntent);
6646 rti.origActivity = tr.origActivity;
6647 res.add(rti);
6648 maxNum--;
6649 }
6650 }
6651 return res;
6652 }
6653 }
6654
6655 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6656 int j;
6657 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6658 TaskRecord jt = startTask;
6659
6660 // First look backwards
6661 for (j=startIndex-1; j>=0; j--) {
6662 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6663 if (r.task != jt) {
6664 jt = r.task;
6665 if (affinity.equals(jt.affinity)) {
6666 return j;
6667 }
6668 }
6669 }
6670
6671 // Now look forwards
6672 final int N = mHistory.size();
6673 jt = startTask;
6674 for (j=startIndex+1; j<N; j++) {
6675 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6676 if (r.task != jt) {
6677 if (affinity.equals(jt.affinity)) {
6678 return j;
6679 }
6680 jt = r.task;
6681 }
6682 }
6683
6684 // Might it be at the top?
6685 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6686 return N-1;
6687 }
6688
6689 return -1;
6690 }
6691
6692 /**
6693 * Perform a reset of the given task, if needed as part of launching it.
6694 * Returns the new HistoryRecord at the top of the task.
6695 */
6696 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6697 HistoryRecord newActivity) {
6698 boolean forceReset = (newActivity.info.flags
6699 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6700 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6701 if ((newActivity.info.flags
6702 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6703 forceReset = true;
6704 }
6705 }
6706
6707 final TaskRecord task = taskTop.task;
6708
6709 // We are going to move through the history list so that we can look
6710 // at each activity 'target' with 'below' either the interesting
6711 // activity immediately below it in the stack or null.
6712 HistoryRecord target = null;
6713 int targetI = 0;
6714 int taskTopI = -1;
6715 int replyChainEnd = -1;
6716 int lastReparentPos = -1;
6717 for (int i=mHistory.size()-1; i>=-1; i--) {
6718 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6719
6720 if (below != null && below.finishing) {
6721 continue;
6722 }
6723 if (target == null) {
6724 target = below;
6725 targetI = i;
6726 // If we were in the middle of a reply chain before this
6727 // task, it doesn't appear like the root of the chain wants
6728 // anything interesting, so drop it.
6729 replyChainEnd = -1;
6730 continue;
6731 }
6732
6733 final int flags = target.info.flags;
6734
6735 final boolean finishOnTaskLaunch =
6736 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6737 final boolean allowTaskReparenting =
6738 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6739
6740 if (target.task == task) {
6741 // We are inside of the task being reset... we'll either
6742 // finish this activity, push it out for another task,
6743 // or leave it as-is. We only do this
6744 // for activities that are not the root of the task (since
6745 // if we finish the root, we may no longer have the task!).
6746 if (taskTopI < 0) {
6747 taskTopI = targetI;
6748 }
6749 if (below != null && below.task == task) {
6750 final boolean clearWhenTaskReset =
6751 (target.intent.getFlags()
6752 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006753 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006754 // If this activity is sending a reply to a previous
6755 // activity, we can't do anything with it now until
6756 // we reach the start of the reply chain.
6757 // XXX note that we are assuming the result is always
6758 // to the previous activity, which is almost always
6759 // the case but we really shouldn't count on.
6760 if (replyChainEnd < 0) {
6761 replyChainEnd = targetI;
6762 }
Ed Heyl73798232009-03-24 21:32:21 -07006763 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006764 && target.taskAffinity != null
6765 && !target.taskAffinity.equals(task.affinity)) {
6766 // If this activity has an affinity for another
6767 // task, then we need to move it out of here. We will
6768 // move it as far out of the way as possible, to the
6769 // bottom of the activity stack. This also keeps it
6770 // correctly ordered with any activities we previously
6771 // moved.
6772 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6773 if (target.taskAffinity != null
6774 && target.taskAffinity.equals(p.task.affinity)) {
6775 // If the activity currently at the bottom has the
6776 // same task affinity as the one we are moving,
6777 // then merge it into the same task.
6778 target.task = p.task;
6779 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6780 + " out to bottom task " + p.task);
6781 } else {
6782 mCurTask++;
6783 if (mCurTask <= 0) {
6784 mCurTask = 1;
6785 }
6786 target.task = new TaskRecord(mCurTask, target.info, null,
6787 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6788 target.task.affinityIntent = target.intent;
6789 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6790 + " out to new task " + target.task);
6791 }
6792 mWindowManager.setAppGroupId(target, task.taskId);
6793 if (replyChainEnd < 0) {
6794 replyChainEnd = targetI;
6795 }
6796 int dstPos = 0;
6797 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6798 p = (HistoryRecord)mHistory.get(srcPos);
6799 if (p.finishing) {
6800 continue;
6801 }
6802 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6803 + " out to target's task " + target.task);
6804 task.numActivities--;
6805 p.task = target.task;
6806 target.task.numActivities++;
6807 mHistory.remove(srcPos);
6808 mHistory.add(dstPos, p);
6809 mWindowManager.moveAppToken(dstPos, p);
6810 mWindowManager.setAppGroupId(p, p.task.taskId);
6811 dstPos++;
6812 if (VALIDATE_TOKENS) {
6813 mWindowManager.validateAppTokens(mHistory);
6814 }
6815 i++;
6816 }
6817 if (taskTop == p) {
6818 taskTop = below;
6819 }
6820 if (taskTopI == replyChainEnd) {
6821 taskTopI = -1;
6822 }
6823 replyChainEnd = -1;
6824 addRecentTask(target.task);
6825 } else if (forceReset || finishOnTaskLaunch
6826 || clearWhenTaskReset) {
6827 // If the activity should just be removed -- either
6828 // because it asks for it, or the task should be
6829 // cleared -- then finish it and anything that is
6830 // part of its reply chain.
6831 if (clearWhenTaskReset) {
6832 // In this case, we want to finish this activity
6833 // and everything above it, so be sneaky and pretend
6834 // like these are all in the reply chain.
6835 replyChainEnd = targetI+1;
6836 while (replyChainEnd < mHistory.size() &&
6837 ((HistoryRecord)mHistory.get(
6838 replyChainEnd)).task == task) {
6839 replyChainEnd++;
6840 }
6841 replyChainEnd--;
6842 } else if (replyChainEnd < 0) {
6843 replyChainEnd = targetI;
6844 }
6845 HistoryRecord p = null;
6846 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6847 p = (HistoryRecord)mHistory.get(srcPos);
6848 if (p.finishing) {
6849 continue;
6850 }
6851 if (finishActivityLocked(p, srcPos,
6852 Activity.RESULT_CANCELED, null, "reset")) {
6853 replyChainEnd--;
6854 srcPos--;
6855 }
6856 }
6857 if (taskTop == p) {
6858 taskTop = below;
6859 }
6860 if (taskTopI == replyChainEnd) {
6861 taskTopI = -1;
6862 }
6863 replyChainEnd = -1;
6864 } else {
6865 // If we were in the middle of a chain, well the
6866 // activity that started it all doesn't want anything
6867 // special, so leave it all as-is.
6868 replyChainEnd = -1;
6869 }
6870 } else {
6871 // Reached the bottom of the task -- any reply chain
6872 // should be left as-is.
6873 replyChainEnd = -1;
6874 }
6875
6876 } else if (target.resultTo != null) {
6877 // If this activity is sending a reply to a previous
6878 // activity, we can't do anything with it now until
6879 // we reach the start of the reply chain.
6880 // XXX note that we are assuming the result is always
6881 // to the previous activity, which is almost always
6882 // the case but we really shouldn't count on.
6883 if (replyChainEnd < 0) {
6884 replyChainEnd = targetI;
6885 }
6886
6887 } else if (taskTopI >= 0 && allowTaskReparenting
6888 && task.affinity != null
6889 && task.affinity.equals(target.taskAffinity)) {
6890 // We are inside of another task... if this activity has
6891 // an affinity for our task, then either remove it if we are
6892 // clearing or move it over to our task. Note that
6893 // we currently punt on the case where we are resetting a
6894 // task that is not at the top but who has activities above
6895 // with an affinity to it... this is really not a normal
6896 // case, and we will need to later pull that task to the front
6897 // and usually at that point we will do the reset and pick
6898 // up those remaining activities. (This only happens if
6899 // someone starts an activity in a new task from an activity
6900 // in a task that is not currently on top.)
6901 if (forceReset || finishOnTaskLaunch) {
6902 if (replyChainEnd < 0) {
6903 replyChainEnd = targetI;
6904 }
6905 HistoryRecord p = null;
6906 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6907 p = (HistoryRecord)mHistory.get(srcPos);
6908 if (p.finishing) {
6909 continue;
6910 }
6911 if (finishActivityLocked(p, srcPos,
6912 Activity.RESULT_CANCELED, null, "reset")) {
6913 taskTopI--;
6914 lastReparentPos--;
6915 replyChainEnd--;
6916 srcPos--;
6917 }
6918 }
6919 replyChainEnd = -1;
6920 } else {
6921 if (replyChainEnd < 0) {
6922 replyChainEnd = targetI;
6923 }
6924 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6925 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6926 if (p.finishing) {
6927 continue;
6928 }
6929 if (lastReparentPos < 0) {
6930 lastReparentPos = taskTopI;
6931 taskTop = p;
6932 } else {
6933 lastReparentPos--;
6934 }
6935 mHistory.remove(srcPos);
6936 p.task.numActivities--;
6937 p.task = task;
6938 mHistory.add(lastReparentPos, p);
6939 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6940 + " in to resetting task " + task);
6941 task.numActivities++;
6942 mWindowManager.moveAppToken(lastReparentPos, p);
6943 mWindowManager.setAppGroupId(p, p.task.taskId);
6944 if (VALIDATE_TOKENS) {
6945 mWindowManager.validateAppTokens(mHistory);
6946 }
6947 }
6948 replyChainEnd = -1;
6949
6950 // Now we've moved it in to place... but what if this is
6951 // a singleTop activity and we have put it on top of another
6952 // instance of the same activity? Then we drop the instance
6953 // below so it remains singleTop.
6954 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6955 for (int j=lastReparentPos-1; j>=0; j--) {
6956 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6957 if (p.finishing) {
6958 continue;
6959 }
6960 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6961 if (finishActivityLocked(p, j,
6962 Activity.RESULT_CANCELED, null, "replace")) {
6963 taskTopI--;
6964 lastReparentPos--;
6965 }
6966 }
6967 }
6968 }
6969 }
6970 }
6971
6972 target = below;
6973 targetI = i;
6974 }
6975
6976 return taskTop;
6977 }
6978
6979 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006980 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006981 */
6982 public void moveTaskToFront(int task) {
6983 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6984 "moveTaskToFront()");
6985
6986 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006987 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6988 Binder.getCallingUid(), "Task to front")) {
6989 return;
6990 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006991 final long origId = Binder.clearCallingIdentity();
6992 try {
6993 int N = mRecentTasks.size();
6994 for (int i=0; i<N; i++) {
6995 TaskRecord tr = mRecentTasks.get(i);
6996 if (tr.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07006997 moveTaskToFrontLocked(tr, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006998 return;
6999 }
7000 }
7001 for (int i=mHistory.size()-1; i>=0; i--) {
7002 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
7003 if (hr.task.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007004 moveTaskToFrontLocked(hr.task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007005 return;
7006 }
7007 }
7008 } finally {
7009 Binder.restoreCallingIdentity(origId);
7010 }
7011 }
7012 }
7013
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007014 private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007015 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
7016
7017 final int task = tr.taskId;
7018 int top = mHistory.size()-1;
7019
7020 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
7021 // nothing to do!
7022 return;
7023 }
7024
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007025 ArrayList moved = new ArrayList();
7026
7027 // Applying the affinities may have removed entries from the history,
7028 // so get the size again.
7029 top = mHistory.size()-1;
7030 int pos = top;
7031
7032 // Shift all activities with this task up to the top
7033 // of the stack, keeping them in the same internal order.
7034 while (pos >= 0) {
7035 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7036 if (localLOGV) Log.v(
7037 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7038 boolean first = true;
7039 if (r.task.taskId == task) {
7040 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
7041 mHistory.remove(pos);
7042 mHistory.add(top, r);
7043 moved.add(0, r);
7044 top--;
7045 if (first) {
7046 addRecentTask(r.task);
7047 first = false;
7048 }
7049 }
7050 pos--;
7051 }
7052
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007053 if (DEBUG_TRANSITION) Log.v(TAG,
7054 "Prepare to front transition: task=" + tr);
7055 if (reason != null &&
7056 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7057 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7058 HistoryRecord r = topRunningActivityLocked(null);
7059 if (r != null) {
7060 mNoAnimActivities.add(r);
7061 }
7062 } else {
7063 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7064 }
7065
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007066 mWindowManager.moveAppTokensToTop(moved);
7067 if (VALIDATE_TOKENS) {
7068 mWindowManager.validateAppTokens(mHistory);
7069 }
7070
7071 finishTaskMove(task);
Doug Zongker2bec3d42009-12-04 12:52:44 -08007072 EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007073 }
7074
7075 private final void finishTaskMove(int task) {
7076 resumeTopActivityLocked(null);
7077 }
7078
7079 public void moveTaskToBack(int task) {
7080 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7081 "moveTaskToBack()");
7082
7083 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007084 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7085 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7086 Binder.getCallingUid(), "Task to back")) {
7087 return;
7088 }
7089 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007090 final long origId = Binder.clearCallingIdentity();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007091 moveTaskToBackLocked(task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007092 Binder.restoreCallingIdentity(origId);
7093 }
7094 }
7095
7096 /**
7097 * Moves an activity, and all of the other activities within the same task, to the bottom
7098 * of the history stack. The activity's order within the task is unchanged.
7099 *
7100 * @param token A reference to the activity we wish to move
7101 * @param nonRoot If false then this only works if the activity is the root
7102 * of a task; if true it will work for any activity in a task.
7103 * @return Returns true if the move completed, false if not.
7104 */
7105 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7106 synchronized(this) {
7107 final long origId = Binder.clearCallingIdentity();
7108 int taskId = getTaskForActivityLocked(token, !nonRoot);
7109 if (taskId >= 0) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007110 return moveTaskToBackLocked(taskId, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007111 }
7112 Binder.restoreCallingIdentity(origId);
7113 }
7114 return false;
7115 }
7116
7117 /**
7118 * Worker method for rearranging history stack. Implements the function of moving all
7119 * activities for a specific task (gathering them if disjoint) into a single group at the
7120 * bottom of the stack.
7121 *
7122 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7123 * to premeptively cancel the move.
7124 *
7125 * @param task The taskId to collect and move to the bottom.
7126 * @return Returns true if the move completed, false if not.
7127 */
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007128 private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007129 Log.i(TAG, "moveTaskToBack: " + task);
7130
7131 // If we have a watcher, preflight the move before committing to it. First check
7132 // for *other* available tasks, but if none are available, then try again allowing the
7133 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007134 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007135 HistoryRecord next = topRunningActivityLocked(null, task);
7136 if (next == null) {
7137 next = topRunningActivityLocked(null, 0);
7138 }
7139 if (next != null) {
7140 // ask watcher if this is allowed
7141 boolean moveOK = true;
7142 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007143 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007144 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007145 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007146 }
7147 if (!moveOK) {
7148 return false;
7149 }
7150 }
7151 }
7152
7153 ArrayList moved = new ArrayList();
7154
7155 if (DEBUG_TRANSITION) Log.v(TAG,
7156 "Prepare to back transition: task=" + task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007157
7158 final int N = mHistory.size();
7159 int bottom = 0;
7160 int pos = 0;
7161
7162 // Shift all activities with this task down to the bottom
7163 // of the stack, keeping them in the same internal order.
7164 while (pos < N) {
7165 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7166 if (localLOGV) Log.v(
7167 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7168 if (r.task.taskId == task) {
7169 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7170 mHistory.remove(pos);
7171 mHistory.add(bottom, r);
7172 moved.add(r);
7173 bottom++;
7174 }
7175 pos++;
7176 }
7177
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007178 if (reason != null &&
7179 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7180 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7181 HistoryRecord r = topRunningActivityLocked(null);
7182 if (r != null) {
7183 mNoAnimActivities.add(r);
7184 }
7185 } else {
Suchi Amalapurapuc9568e32009-11-05 18:51:16 -08007186 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007187 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007188 mWindowManager.moveAppTokensToBottom(moved);
7189 if (VALIDATE_TOKENS) {
7190 mWindowManager.validateAppTokens(mHistory);
7191 }
7192
7193 finishTaskMove(task);
7194 return true;
7195 }
7196
7197 public void moveTaskBackwards(int task) {
7198 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7199 "moveTaskBackwards()");
7200
7201 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007202 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7203 Binder.getCallingUid(), "Task backwards")) {
7204 return;
7205 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007206 final long origId = Binder.clearCallingIdentity();
7207 moveTaskBackwardsLocked(task);
7208 Binder.restoreCallingIdentity(origId);
7209 }
7210 }
7211
7212 private final void moveTaskBackwardsLocked(int task) {
7213 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7214 }
7215
7216 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7217 synchronized(this) {
7218 return getTaskForActivityLocked(token, onlyRoot);
7219 }
7220 }
7221
7222 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7223 final int N = mHistory.size();
7224 TaskRecord lastTask = null;
7225 for (int i=0; i<N; i++) {
7226 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7227 if (r == token) {
7228 if (!onlyRoot || lastTask != r.task) {
7229 return r.task.taskId;
7230 }
7231 return -1;
7232 }
7233 lastTask = r.task;
7234 }
7235
7236 return -1;
7237 }
7238
7239 /**
7240 * Returns the top activity in any existing task matching the given
7241 * Intent. Returns null if no such task is found.
7242 */
7243 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7244 ComponentName cls = intent.getComponent();
7245 if (info.targetActivity != null) {
7246 cls = new ComponentName(info.packageName, info.targetActivity);
7247 }
7248
7249 TaskRecord cp = null;
7250
7251 final int N = mHistory.size();
7252 for (int i=(N-1); i>=0; i--) {
7253 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7254 if (!r.finishing && r.task != cp
7255 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7256 cp = r.task;
7257 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7258 // + "/aff=" + r.task.affinity + " to new cls="
7259 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7260 if (r.task.affinity != null) {
7261 if (r.task.affinity.equals(info.taskAffinity)) {
7262 //Log.i(TAG, "Found matching affinity!");
7263 return r;
7264 }
7265 } else if (r.task.intent != null
7266 && r.task.intent.getComponent().equals(cls)) {
7267 //Log.i(TAG, "Found matching class!");
7268 //dump();
7269 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7270 return r;
7271 } else if (r.task.affinityIntent != null
7272 && r.task.affinityIntent.getComponent().equals(cls)) {
7273 //Log.i(TAG, "Found matching class!");
7274 //dump();
7275 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7276 return r;
7277 }
7278 }
7279 }
7280
7281 return null;
7282 }
7283
7284 /**
7285 * Returns the first activity (starting from the top of the stack) that
7286 * is the same as the given activity. Returns null if no such activity
7287 * is found.
7288 */
7289 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7290 ComponentName cls = intent.getComponent();
7291 if (info.targetActivity != null) {
7292 cls = new ComponentName(info.packageName, info.targetActivity);
7293 }
7294
7295 final int N = mHistory.size();
7296 for (int i=(N-1); i>=0; i--) {
7297 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7298 if (!r.finishing) {
7299 if (r.intent.getComponent().equals(cls)) {
7300 //Log.i(TAG, "Found matching class!");
7301 //dump();
7302 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7303 return r;
7304 }
7305 }
7306 }
7307
7308 return null;
7309 }
7310
7311 public void finishOtherInstances(IBinder token, ComponentName className) {
7312 synchronized(this) {
7313 final long origId = Binder.clearCallingIdentity();
7314
7315 int N = mHistory.size();
7316 TaskRecord lastTask = null;
7317 for (int i=0; i<N; i++) {
7318 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7319 if (r.realActivity.equals(className)
7320 && r != token && lastTask != r.task) {
7321 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7322 null, "others")) {
7323 i--;
7324 N--;
7325 }
7326 }
7327 lastTask = r.task;
7328 }
7329
7330 Binder.restoreCallingIdentity(origId);
7331 }
7332 }
7333
7334 // =========================================================
7335 // THUMBNAILS
7336 // =========================================================
7337
7338 public void reportThumbnail(IBinder token,
7339 Bitmap thumbnail, CharSequence description) {
7340 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7341 final long origId = Binder.clearCallingIdentity();
7342 sendPendingThumbnail(null, token, thumbnail, description, true);
7343 Binder.restoreCallingIdentity(origId);
7344 }
7345
7346 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7347 Bitmap thumbnail, CharSequence description, boolean always) {
7348 TaskRecord task = null;
7349 ArrayList receivers = null;
7350
7351 //System.out.println("Send pending thumbnail: " + r);
7352
7353 synchronized(this) {
7354 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007355 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007356 if (index < 0) {
7357 return;
7358 }
7359 r = (HistoryRecord)mHistory.get(index);
7360 }
7361 if (thumbnail == null) {
7362 thumbnail = r.thumbnail;
7363 description = r.description;
7364 }
7365 if (thumbnail == null && !always) {
7366 // If there is no thumbnail, and this entry is not actually
7367 // going away, then abort for now and pick up the next
7368 // thumbnail we get.
7369 return;
7370 }
7371 task = r.task;
7372
7373 int N = mPendingThumbnails.size();
7374 int i=0;
7375 while (i<N) {
7376 PendingThumbnailsRecord pr =
7377 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7378 //System.out.println("Looking in " + pr.pendingRecords);
7379 if (pr.pendingRecords.remove(r)) {
7380 if (receivers == null) {
7381 receivers = new ArrayList();
7382 }
7383 receivers.add(pr);
7384 if (pr.pendingRecords.size() == 0) {
7385 pr.finished = true;
7386 mPendingThumbnails.remove(i);
7387 N--;
7388 continue;
7389 }
7390 }
7391 i++;
7392 }
7393 }
7394
7395 if (receivers != null) {
7396 final int N = receivers.size();
7397 for (int i=0; i<N; i++) {
7398 try {
7399 PendingThumbnailsRecord pr =
7400 (PendingThumbnailsRecord)receivers.get(i);
7401 pr.receiver.newThumbnail(
7402 task != null ? task.taskId : -1, thumbnail, description);
7403 if (pr.finished) {
7404 pr.receiver.finished();
7405 }
7406 } catch (Exception e) {
7407 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7408 }
7409 }
7410 }
7411 }
7412
7413 // =========================================================
7414 // CONTENT PROVIDERS
7415 // =========================================================
7416
7417 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7418 List providers = null;
7419 try {
7420 providers = ActivityThread.getPackageManager().
7421 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007422 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007423 } catch (RemoteException ex) {
7424 }
7425 if (providers != null) {
7426 final int N = providers.size();
7427 for (int i=0; i<N; i++) {
7428 ProviderInfo cpi =
7429 (ProviderInfo)providers.get(i);
7430 ContentProviderRecord cpr =
7431 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7432 if (cpr == null) {
7433 cpr = new ContentProviderRecord(cpi, app.info);
7434 mProvidersByClass.put(cpi.name, cpr);
7435 }
7436 app.pubProviders.put(cpi.name, cpr);
7437 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007438 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007439 }
7440 }
7441 return providers;
7442 }
7443
7444 private final String checkContentProviderPermissionLocked(
7445 ProviderInfo cpi, ProcessRecord r, int mode) {
7446 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7447 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7448 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7449 cpi.exported ? -1 : cpi.applicationInfo.uid)
7450 == PackageManager.PERMISSION_GRANTED
7451 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7452 return null;
7453 }
7454 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7455 cpi.exported ? -1 : cpi.applicationInfo.uid)
7456 == PackageManager.PERMISSION_GRANTED) {
7457 return null;
7458 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007459
7460 PathPermission[] pps = cpi.pathPermissions;
7461 if (pps != null) {
7462 int i = pps.length;
7463 while (i > 0) {
7464 i--;
7465 PathPermission pp = pps[i];
7466 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7467 cpi.exported ? -1 : cpi.applicationInfo.uid)
7468 == PackageManager.PERMISSION_GRANTED
7469 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7470 return null;
7471 }
7472 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7473 cpi.exported ? -1 : cpi.applicationInfo.uid)
7474 == PackageManager.PERMISSION_GRANTED) {
7475 return null;
7476 }
7477 }
7478 }
7479
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007480 String msg = "Permission Denial: opening provider " + cpi.name
7481 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7482 + ", uid=" + callingUid + ") requires "
7483 + cpi.readPermission + " or " + cpi.writePermission;
7484 Log.w(TAG, msg);
7485 return msg;
7486 }
7487
7488 private final ContentProviderHolder getContentProviderImpl(
7489 IApplicationThread caller, String name) {
7490 ContentProviderRecord cpr;
7491 ProviderInfo cpi = null;
7492
7493 synchronized(this) {
7494 ProcessRecord r = null;
7495 if (caller != null) {
7496 r = getRecordForAppLocked(caller);
7497 if (r == null) {
7498 throw new SecurityException(
7499 "Unable to find app for caller " + caller
7500 + " (pid=" + Binder.getCallingPid()
7501 + ") when getting content provider " + name);
7502 }
7503 }
7504
7505 // First check if this content provider has been published...
7506 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7507 if (cpr != null) {
7508 cpi = cpr.info;
7509 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7510 return new ContentProviderHolder(cpi,
7511 cpi.readPermission != null
7512 ? cpi.readPermission : cpi.writePermission);
7513 }
7514
7515 if (r != null && cpr.canRunHere(r)) {
7516 // This provider has been published or is in the process
7517 // of being published... but it is also allowed to run
7518 // in the caller's process, so don't make a connection
7519 // and just let the caller instantiate its own instance.
7520 if (cpr.provider != null) {
7521 // don't give caller the provider object, it needs
7522 // to make its own.
7523 cpr = new ContentProviderRecord(cpr);
7524 }
7525 return cpr;
7526 }
7527
7528 final long origId = Binder.clearCallingIdentity();
7529
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007530 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007531 // return it right away.
7532 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007533 if (DEBUG_PROVIDER) Log.v(TAG,
7534 "Adding provider requested by "
7535 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007536 + cpr.info.processName);
7537 Integer cnt = r.conProviders.get(cpr);
7538 if (cnt == null) {
7539 r.conProviders.put(cpr, new Integer(1));
7540 } else {
7541 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7542 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007543 cpr.clients.add(r);
7544 } else {
7545 cpr.externals++;
7546 }
7547
7548 if (cpr.app != null) {
7549 updateOomAdjLocked(cpr.app);
7550 }
7551
7552 Binder.restoreCallingIdentity(origId);
7553
7554 } else {
7555 try {
7556 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007557 resolveContentProvider(name,
7558 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007559 } catch (RemoteException ex) {
7560 }
7561 if (cpi == null) {
7562 return null;
7563 }
7564
7565 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7566 return new ContentProviderHolder(cpi,
7567 cpi.readPermission != null
7568 ? cpi.readPermission : cpi.writePermission);
7569 }
7570
7571 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7572 final boolean firstClass = cpr == null;
7573 if (firstClass) {
7574 try {
7575 ApplicationInfo ai =
7576 ActivityThread.getPackageManager().
7577 getApplicationInfo(
7578 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007579 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007580 if (ai == null) {
7581 Log.w(TAG, "No package info for content provider "
7582 + cpi.name);
7583 return null;
7584 }
7585 cpr = new ContentProviderRecord(cpi, ai);
7586 } catch (RemoteException ex) {
7587 // pm is in same process, this will never happen.
7588 }
7589 }
7590
7591 if (r != null && cpr.canRunHere(r)) {
7592 // If this is a multiprocess provider, then just return its
7593 // info and allow the caller to instantiate it. Only do
7594 // this if the provider is the same user as the caller's
7595 // process, or can run as root (so can be in any process).
7596 return cpr;
7597 }
7598
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007599 if (DEBUG_PROVIDER) {
7600 RuntimeException e = new RuntimeException("here");
7601 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7602 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007603 }
7604
7605 // This is single process, and our app is now connecting to it.
7606 // See if we are already in the process of launching this
7607 // provider.
7608 final int N = mLaunchingProviders.size();
7609 int i;
7610 for (i=0; i<N; i++) {
7611 if (mLaunchingProviders.get(i) == cpr) {
7612 break;
7613 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007614 }
7615
7616 // If the provider is not already being launched, then get it
7617 // started.
7618 if (i >= N) {
7619 final long origId = Binder.clearCallingIdentity();
7620 ProcessRecord proc = startProcessLocked(cpi.processName,
7621 cpr.appInfo, false, 0, "content provider",
7622 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007623 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007624 if (proc == null) {
7625 Log.w(TAG, "Unable to launch app "
7626 + cpi.applicationInfo.packageName + "/"
7627 + cpi.applicationInfo.uid + " for provider "
7628 + name + ": process is bad");
7629 return null;
7630 }
7631 cpr.launchingApp = proc;
7632 mLaunchingProviders.add(cpr);
7633 Binder.restoreCallingIdentity(origId);
7634 }
7635
7636 // Make sure the provider is published (the same provider class
7637 // may be published under multiple names).
7638 if (firstClass) {
7639 mProvidersByClass.put(cpi.name, cpr);
7640 }
7641 mProvidersByName.put(name, cpr);
7642
7643 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007644 if (DEBUG_PROVIDER) Log.v(TAG,
7645 "Adding provider requested by "
7646 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007647 + cpr.info.processName);
7648 Integer cnt = r.conProviders.get(cpr);
7649 if (cnt == null) {
7650 r.conProviders.put(cpr, new Integer(1));
7651 } else {
7652 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7653 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007654 cpr.clients.add(r);
7655 } else {
7656 cpr.externals++;
7657 }
7658 }
7659 }
7660
7661 // Wait for the provider to be published...
7662 synchronized (cpr) {
7663 while (cpr.provider == null) {
7664 if (cpr.launchingApp == null) {
7665 Log.w(TAG, "Unable to launch app "
7666 + cpi.applicationInfo.packageName + "/"
7667 + cpi.applicationInfo.uid + " for provider "
7668 + name + ": launching app became null");
Doug Zongker2bec3d42009-12-04 12:52:44 -08007669 EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007670 cpi.applicationInfo.packageName,
7671 cpi.applicationInfo.uid, name);
7672 return null;
7673 }
7674 try {
7675 cpr.wait();
7676 } catch (InterruptedException ex) {
7677 }
7678 }
7679 }
7680 return cpr;
7681 }
7682
7683 public final ContentProviderHolder getContentProvider(
7684 IApplicationThread caller, String name) {
7685 if (caller == null) {
7686 String msg = "null IApplicationThread when getting content provider "
7687 + name;
7688 Log.w(TAG, msg);
7689 throw new SecurityException(msg);
7690 }
7691
7692 return getContentProviderImpl(caller, name);
7693 }
7694
7695 private ContentProviderHolder getContentProviderExternal(String name) {
7696 return getContentProviderImpl(null, name);
7697 }
7698
7699 /**
7700 * Drop a content provider from a ProcessRecord's bookkeeping
7701 * @param cpr
7702 */
7703 public void removeContentProvider(IApplicationThread caller, String name) {
7704 synchronized (this) {
7705 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7706 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007707 // remove from mProvidersByClass
7708 if (DEBUG_PROVIDER) Log.v(TAG, name +
7709 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007710 return;
7711 }
7712 final ProcessRecord r = getRecordForAppLocked(caller);
7713 if (r == null) {
7714 throw new SecurityException(
7715 "Unable to find app for caller " + caller +
7716 " when removing content provider " + name);
7717 }
7718 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007719 ContentProviderRecord localCpr = (ContentProviderRecord)
7720 mProvidersByClass.get(cpr.info.name);
7721 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7722 + r.info.processName + " from process "
7723 + localCpr.appInfo.processName);
7724 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007725 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007726 Log.w(TAG, "removeContentProvider called on local provider: "
7727 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007728 return;
7729 } else {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007730 Integer cnt = r.conProviders.get(localCpr);
7731 if (cnt == null || cnt.intValue() <= 1) {
7732 localCpr.clients.remove(r);
7733 r.conProviders.remove(localCpr);
7734 } else {
7735 r.conProviders.put(localCpr, new Integer(cnt.intValue()-1));
7736 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007737 }
7738 updateOomAdjLocked();
7739 }
7740 }
7741
7742 private void removeContentProviderExternal(String name) {
7743 synchronized (this) {
7744 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7745 if(cpr == null) {
7746 //remove from mProvidersByClass
7747 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7748 return;
7749 }
7750
7751 //update content provider record entry info
7752 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7753 localCpr.externals--;
7754 if (localCpr.externals < 0) {
7755 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7756 }
7757 updateOomAdjLocked();
7758 }
7759 }
7760
7761 public final void publishContentProviders(IApplicationThread caller,
7762 List<ContentProviderHolder> providers) {
7763 if (providers == null) {
7764 return;
7765 }
7766
7767 synchronized(this) {
7768 final ProcessRecord r = getRecordForAppLocked(caller);
7769 if (r == null) {
7770 throw new SecurityException(
7771 "Unable to find app for caller " + caller
7772 + " (pid=" + Binder.getCallingPid()
7773 + ") when publishing content providers");
7774 }
7775
7776 final long origId = Binder.clearCallingIdentity();
7777
7778 final int N = providers.size();
7779 for (int i=0; i<N; i++) {
7780 ContentProviderHolder src = providers.get(i);
7781 if (src == null || src.info == null || src.provider == null) {
7782 continue;
7783 }
7784 ContentProviderRecord dst =
7785 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7786 if (dst != null) {
7787 mProvidersByClass.put(dst.info.name, dst);
7788 String names[] = dst.info.authority.split(";");
7789 for (int j = 0; j < names.length; j++) {
7790 mProvidersByName.put(names[j], dst);
7791 }
7792
7793 int NL = mLaunchingProviders.size();
7794 int j;
7795 for (j=0; j<NL; j++) {
7796 if (mLaunchingProviders.get(j) == dst) {
7797 mLaunchingProviders.remove(j);
7798 j--;
7799 NL--;
7800 }
7801 }
7802 synchronized (dst) {
7803 dst.provider = src.provider;
7804 dst.app = r;
7805 dst.notifyAll();
7806 }
7807 updateOomAdjLocked(r);
7808 }
7809 }
7810
7811 Binder.restoreCallingIdentity(origId);
7812 }
7813 }
7814
7815 public static final void installSystemProviders() {
7816 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7817 List providers = mSelf.generateApplicationProvidersLocked(app);
7818 mSystemThread.installSystemProviders(providers);
7819 }
7820
7821 // =========================================================
7822 // GLOBAL MANAGEMENT
7823 // =========================================================
7824
7825 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7826 ApplicationInfo info, String customProcess) {
7827 String proc = customProcess != null ? customProcess : info.processName;
7828 BatteryStatsImpl.Uid.Proc ps = null;
7829 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7830 synchronized (stats) {
7831 ps = stats.getProcessStatsLocked(info.uid, proc);
7832 }
7833 return new ProcessRecord(ps, thread, info, proc);
7834 }
7835
7836 final ProcessRecord addAppLocked(ApplicationInfo info) {
7837 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7838
7839 if (app == null) {
7840 app = newProcessRecordLocked(null, info, null);
7841 mProcessNames.put(info.processName, info.uid, app);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08007842 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007843 }
7844
7845 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7846 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7847 app.persistent = true;
7848 app.maxAdj = CORE_SERVER_ADJ;
7849 }
7850 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7851 mPersistentStartingProcesses.add(app);
7852 startProcessLocked(app, "added application", app.processName);
7853 }
7854
7855 return app;
7856 }
7857
7858 public void unhandledBack() {
7859 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7860 "unhandledBack()");
7861
7862 synchronized(this) {
7863 int count = mHistory.size();
7864 if (Config.LOGD) Log.d(
7865 TAG, "Performing unhandledBack(): stack size = " + count);
7866 if (count > 1) {
7867 final long origId = Binder.clearCallingIdentity();
7868 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7869 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7870 Binder.restoreCallingIdentity(origId);
7871 }
7872 }
7873 }
7874
7875 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7876 String name = uri.getAuthority();
7877 ContentProviderHolder cph = getContentProviderExternal(name);
7878 ParcelFileDescriptor pfd = null;
7879 if (cph != null) {
7880 // We record the binder invoker's uid in thread-local storage before
7881 // going to the content provider to open the file. Later, in the code
7882 // that handles all permissions checks, we look for this uid and use
7883 // that rather than the Activity Manager's own uid. The effect is that
7884 // we do the check against the caller's permissions even though it looks
7885 // to the content provider like the Activity Manager itself is making
7886 // the request.
7887 sCallerIdentity.set(new Identity(
7888 Binder.getCallingPid(), Binder.getCallingUid()));
7889 try {
7890 pfd = cph.provider.openFile(uri, "r");
7891 } catch (FileNotFoundException e) {
7892 // do nothing; pfd will be returned null
7893 } finally {
7894 // Ensure that whatever happens, we clean up the identity state
7895 sCallerIdentity.remove();
7896 }
7897
7898 // We've got the fd now, so we're done with the provider.
7899 removeContentProviderExternal(name);
7900 } else {
7901 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7902 }
7903 return pfd;
7904 }
7905
7906 public void goingToSleep() {
7907 synchronized(this) {
7908 mSleeping = true;
7909 mWindowManager.setEventDispatching(false);
7910
7911 if (mResumedActivity != null) {
7912 pauseIfSleepingLocked();
7913 } else {
7914 Log.w(TAG, "goingToSleep with no resumed activity!");
7915 }
7916 }
7917 }
7918
Dianne Hackborn55280a92009-05-07 15:53:46 -07007919 public boolean shutdown(int timeout) {
7920 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7921 != PackageManager.PERMISSION_GRANTED) {
7922 throw new SecurityException("Requires permission "
7923 + android.Manifest.permission.SHUTDOWN);
7924 }
7925
7926 boolean timedout = false;
7927
7928 synchronized(this) {
7929 mShuttingDown = true;
7930 mWindowManager.setEventDispatching(false);
7931
7932 if (mResumedActivity != null) {
7933 pauseIfSleepingLocked();
7934 final long endTime = System.currentTimeMillis() + timeout;
7935 while (mResumedActivity != null || mPausingActivity != null) {
7936 long delay = endTime - System.currentTimeMillis();
7937 if (delay <= 0) {
7938 Log.w(TAG, "Activity manager shutdown timed out");
7939 timedout = true;
7940 break;
7941 }
7942 try {
7943 this.wait();
7944 } catch (InterruptedException e) {
7945 }
7946 }
7947 }
7948 }
7949
7950 mUsageStatsService.shutdown();
7951 mBatteryStatsService.shutdown();
7952
7953 return timedout;
7954 }
7955
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007956 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007957 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007958 if (!mGoingToSleep.isHeld()) {
7959 mGoingToSleep.acquire();
7960 if (mLaunchingActivity.isHeld()) {
7961 mLaunchingActivity.release();
7962 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7963 }
7964 }
7965
7966 // If we are not currently pausing an activity, get the current
7967 // one to pause. If we are pausing one, we will just let that stuff
7968 // run and release the wake lock when all done.
7969 if (mPausingActivity == null) {
7970 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7971 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7972 startPausingLocked(false, true);
7973 }
7974 }
7975 }
7976
7977 public void wakingUp() {
7978 synchronized(this) {
7979 if (mGoingToSleep.isHeld()) {
7980 mGoingToSleep.release();
7981 }
7982 mWindowManager.setEventDispatching(true);
7983 mSleeping = false;
7984 resumeTopActivityLocked(null);
7985 }
7986 }
7987
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007988 public void stopAppSwitches() {
7989 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7990 != PackageManager.PERMISSION_GRANTED) {
7991 throw new SecurityException("Requires permission "
7992 + android.Manifest.permission.STOP_APP_SWITCHES);
7993 }
7994
7995 synchronized(this) {
7996 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7997 + APP_SWITCH_DELAY_TIME;
7998 mDidAppSwitch = false;
7999 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8000 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8001 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
8002 }
8003 }
8004
8005 public void resumeAppSwitches() {
8006 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8007 != PackageManager.PERMISSION_GRANTED) {
8008 throw new SecurityException("Requires permission "
8009 + android.Manifest.permission.STOP_APP_SWITCHES);
8010 }
8011
8012 synchronized(this) {
8013 // Note that we don't execute any pending app switches... we will
8014 // let those wait until either the timeout, or the next start
8015 // activity request.
8016 mAppSwitchesAllowedTime = 0;
8017 }
8018 }
8019
8020 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
8021 String name) {
8022 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
8023 return true;
8024 }
8025
8026 final int perm = checkComponentPermission(
8027 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
8028 callingUid, -1);
8029 if (perm == PackageManager.PERMISSION_GRANTED) {
8030 return true;
8031 }
8032
8033 Log.w(TAG, name + " request from " + callingUid + " stopped");
8034 return false;
8035 }
8036
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008037 public void setDebugApp(String packageName, boolean waitForDebugger,
8038 boolean persistent) {
8039 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
8040 "setDebugApp()");
8041
8042 // Note that this is not really thread safe if there are multiple
8043 // callers into it at the same time, but that's not a situation we
8044 // care about.
8045 if (persistent) {
8046 final ContentResolver resolver = mContext.getContentResolver();
8047 Settings.System.putString(
8048 resolver, Settings.System.DEBUG_APP,
8049 packageName);
8050 Settings.System.putInt(
8051 resolver, Settings.System.WAIT_FOR_DEBUGGER,
8052 waitForDebugger ? 1 : 0);
8053 }
8054
8055 synchronized (this) {
8056 if (!persistent) {
8057 mOrigDebugApp = mDebugApp;
8058 mOrigWaitForDebugger = mWaitForDebugger;
8059 }
8060 mDebugApp = packageName;
8061 mWaitForDebugger = waitForDebugger;
8062 mDebugTransient = !persistent;
8063 if (packageName != null) {
8064 final long origId = Binder.clearCallingIdentity();
8065 uninstallPackageLocked(packageName, -1, false);
8066 Binder.restoreCallingIdentity(origId);
8067 }
8068 }
8069 }
8070
8071 public void setAlwaysFinish(boolean enabled) {
8072 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
8073 "setAlwaysFinish()");
8074
8075 Settings.System.putInt(
8076 mContext.getContentResolver(),
8077 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
8078
8079 synchronized (this) {
8080 mAlwaysFinishActivities = enabled;
8081 }
8082 }
8083
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008084 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008085 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008086 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008087 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008088 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008089 }
8090 }
8091
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008092 public void registerActivityWatcher(IActivityWatcher watcher) {
8093 mWatchers.register(watcher);
8094 }
8095
8096 public void unregisterActivityWatcher(IActivityWatcher watcher) {
8097 mWatchers.unregister(watcher);
8098 }
8099
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008100 public final void enterSafeMode() {
8101 synchronized(this) {
8102 // It only makes sense to do this before the system is ready
8103 // and started launching other packages.
8104 if (!mSystemReady) {
8105 try {
8106 ActivityThread.getPackageManager().enterSafeMode();
8107 } catch (RemoteException e) {
8108 }
8109
8110 View v = LayoutInflater.from(mContext).inflate(
8111 com.android.internal.R.layout.safe_mode, null);
8112 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8113 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8114 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8115 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8116 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8117 lp.format = v.getBackground().getOpacity();
8118 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8119 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8120 ((WindowManager)mContext.getSystemService(
8121 Context.WINDOW_SERVICE)).addView(v, lp);
8122 }
8123 }
8124 }
8125
8126 public void noteWakeupAlarm(IIntentSender sender) {
8127 if (!(sender instanceof PendingIntentRecord)) {
8128 return;
8129 }
8130 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8131 synchronized (stats) {
8132 if (mBatteryStatsService.isOnBattery()) {
8133 mBatteryStatsService.enforceCallingPermission();
8134 PendingIntentRecord rec = (PendingIntentRecord)sender;
8135 int MY_UID = Binder.getCallingUid();
8136 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8137 BatteryStatsImpl.Uid.Pkg pkg =
8138 stats.getPackageStatsLocked(uid, rec.key.packageName);
8139 pkg.incWakeupsLocked();
8140 }
8141 }
8142 }
8143
8144 public boolean killPidsForMemory(int[] pids) {
8145 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8146 throw new SecurityException("killPidsForMemory only available to the system");
8147 }
8148
8149 // XXX Note: don't acquire main activity lock here, because the window
8150 // manager calls in with its locks held.
8151
8152 boolean killed = false;
8153 synchronized (mPidsSelfLocked) {
8154 int[] types = new int[pids.length];
8155 int worstType = 0;
8156 for (int i=0; i<pids.length; i++) {
8157 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8158 if (proc != null) {
8159 int type = proc.setAdj;
8160 types[i] = type;
8161 if (type > worstType) {
8162 worstType = type;
8163 }
8164 }
8165 }
8166
8167 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8168 // then constrain it so we will kill all hidden procs.
8169 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8170 worstType = HIDDEN_APP_MIN_ADJ;
8171 }
8172 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8173 for (int i=0; i<pids.length; i++) {
8174 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8175 if (proc == null) {
8176 continue;
8177 }
8178 int adj = proc.setAdj;
8179 if (adj >= worstType) {
8180 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8181 + adj + ")");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008182 EventLog.writeEvent(EventLogTags.AM_KILL_FOR_MEMORY, proc.pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008183 proc.processName, adj);
8184 killed = true;
8185 Process.killProcess(pids[i]);
8186 }
8187 }
8188 }
8189 return killed;
8190 }
8191
8192 public void reportPss(IApplicationThread caller, int pss) {
8193 Watchdog.PssRequestor req;
8194 String name;
8195 ProcessRecord callerApp;
8196 synchronized (this) {
8197 if (caller == null) {
8198 return;
8199 }
8200 callerApp = getRecordForAppLocked(caller);
8201 if (callerApp == null) {
8202 return;
8203 }
8204 callerApp.lastPss = pss;
8205 req = callerApp;
8206 name = callerApp.processName;
8207 }
8208 Watchdog.getInstance().reportPss(req, name, pss);
8209 if (!callerApp.persistent) {
8210 removeRequestedPss(callerApp);
8211 }
8212 }
8213
8214 public void requestPss(Runnable completeCallback) {
8215 ArrayList<ProcessRecord> procs;
8216 synchronized (this) {
8217 mRequestPssCallback = completeCallback;
8218 mRequestPssList.clear();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008219 for (int i=mLruProcesses.size()-1; i>=0; i--) {
8220 ProcessRecord proc = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008221 if (!proc.persistent) {
8222 mRequestPssList.add(proc);
8223 }
8224 }
8225 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8226 }
8227
8228 int oldPri = Process.getThreadPriority(Process.myTid());
8229 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8230 for (int i=procs.size()-1; i>=0; i--) {
8231 ProcessRecord proc = procs.get(i);
8232 proc.lastPss = 0;
8233 proc.requestPss();
8234 }
8235 Process.setThreadPriority(oldPri);
8236 }
8237
8238 void removeRequestedPss(ProcessRecord proc) {
8239 Runnable callback = null;
8240 synchronized (this) {
8241 if (mRequestPssList.remove(proc)) {
8242 if (mRequestPssList.size() == 0) {
8243 callback = mRequestPssCallback;
8244 mRequestPssCallback = null;
8245 }
8246 }
8247 }
8248
8249 if (callback != null) {
8250 callback.run();
8251 }
8252 }
8253
8254 public void collectPss(Watchdog.PssStats stats) {
8255 stats.mEmptyPss = 0;
8256 stats.mEmptyCount = 0;
8257 stats.mBackgroundPss = 0;
8258 stats.mBackgroundCount = 0;
8259 stats.mServicePss = 0;
8260 stats.mServiceCount = 0;
8261 stats.mVisiblePss = 0;
8262 stats.mVisibleCount = 0;
8263 stats.mForegroundPss = 0;
8264 stats.mForegroundCount = 0;
8265 stats.mNoPssCount = 0;
8266 synchronized (this) {
8267 int i;
8268 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8269 ? mProcDeaths.length : stats.mProcDeaths.length;
8270 int aggr = 0;
8271 for (i=0; i<NPD; i++) {
8272 aggr += mProcDeaths[i];
8273 stats.mProcDeaths[i] = aggr;
8274 }
8275 while (i<stats.mProcDeaths.length) {
8276 stats.mProcDeaths[i] = 0;
8277 i++;
8278 }
8279
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008280 for (i=mLruProcesses.size()-1; i>=0; i--) {
8281 ProcessRecord proc = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008282 if (proc.persistent) {
8283 continue;
8284 }
8285 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8286 if (proc.lastPss == 0) {
8287 stats.mNoPssCount++;
8288 continue;
8289 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008290 if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8291 if (proc.empty) {
8292 stats.mEmptyPss += proc.lastPss;
8293 stats.mEmptyCount++;
8294 } else {
8295 stats.mBackgroundPss += proc.lastPss;
8296 stats.mBackgroundCount++;
8297 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008298 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8299 stats.mVisiblePss += proc.lastPss;
8300 stats.mVisibleCount++;
8301 } else {
8302 stats.mForegroundPss += proc.lastPss;
8303 stats.mForegroundCount++;
8304 }
8305 }
8306 }
8307 }
8308
8309 public final void startRunning(String pkg, String cls, String action,
8310 String data) {
8311 synchronized(this) {
8312 if (mStartRunning) {
8313 return;
8314 }
8315 mStartRunning = true;
8316 mTopComponent = pkg != null && cls != null
8317 ? new ComponentName(pkg, cls) : null;
8318 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8319 mTopData = data;
8320 if (!mSystemReady) {
8321 return;
8322 }
8323 }
8324
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008325 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008326 }
8327
8328 private void retrieveSettings() {
8329 final ContentResolver resolver = mContext.getContentResolver();
8330 String debugApp = Settings.System.getString(
8331 resolver, Settings.System.DEBUG_APP);
8332 boolean waitForDebugger = Settings.System.getInt(
8333 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8334 boolean alwaysFinishActivities = Settings.System.getInt(
8335 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8336
8337 Configuration configuration = new Configuration();
8338 Settings.System.getConfiguration(resolver, configuration);
8339
8340 synchronized (this) {
8341 mDebugApp = mOrigDebugApp = debugApp;
8342 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8343 mAlwaysFinishActivities = alwaysFinishActivities;
8344 // This happens before any activities are started, so we can
8345 // change mConfiguration in-place.
8346 mConfiguration.updateFrom(configuration);
Dianne Hackborndc6b6352009-09-30 14:20:09 -07008347 if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008348 }
8349 }
8350
8351 public boolean testIsSystemReady() {
8352 // no need to synchronize(this) just to read & return the value
8353 return mSystemReady;
8354 }
8355
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008356 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008357 // In the simulator, startRunning will never have been called, which
8358 // normally sets a few crucial variables. Do it here instead.
8359 if (!Process.supportsProcesses()) {
8360 mStartRunning = true;
8361 mTopAction = Intent.ACTION_MAIN;
8362 }
8363
8364 synchronized(this) {
8365 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008366 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008367 return;
8368 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008369
8370 // Check to see if there are any update receivers to run.
8371 if (!mDidUpdate) {
8372 if (mWaitingUpdate) {
8373 return;
8374 }
8375 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8376 List<ResolveInfo> ris = null;
8377 try {
8378 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8379 intent, null, 0);
8380 } catch (RemoteException e) {
8381 }
8382 if (ris != null) {
8383 for (int i=ris.size()-1; i>=0; i--) {
8384 if ((ris.get(i).activityInfo.applicationInfo.flags
8385 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8386 ris.remove(i);
8387 }
8388 }
8389 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8390 for (int i=0; i<ris.size(); i++) {
8391 ActivityInfo ai = ris.get(i).activityInfo;
8392 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8393 IIntentReceiver finisher = null;
8394 if (i == 0) {
8395 finisher = new IIntentReceiver.Stub() {
8396 public void performReceive(Intent intent, int resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -07008397 String data, Bundle extras, boolean ordered,
8398 boolean sticky)
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008399 throws RemoteException {
8400 synchronized (ActivityManagerService.this) {
8401 mDidUpdate = true;
8402 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008403 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008404 }
8405 };
8406 }
8407 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8408 broadcastIntentLocked(null, null, intent, null, finisher,
8409 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
8410 if (i == 0) {
8411 mWaitingUpdate = true;
8412 }
8413 }
8414 }
8415 if (mWaitingUpdate) {
8416 return;
8417 }
8418 mDidUpdate = true;
8419 }
8420
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008421 mSystemReady = true;
8422 if (!mStartRunning) {
8423 return;
8424 }
8425 }
8426
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008427 ArrayList<ProcessRecord> procsToKill = null;
8428 synchronized(mPidsSelfLocked) {
8429 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8430 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8431 if (!isAllowedWhileBooting(proc.info)){
8432 if (procsToKill == null) {
8433 procsToKill = new ArrayList<ProcessRecord>();
8434 }
8435 procsToKill.add(proc);
8436 }
8437 }
8438 }
8439
8440 if (procsToKill != null) {
8441 synchronized(this) {
8442 for (int i=procsToKill.size()-1; i>=0; i--) {
8443 ProcessRecord proc = procsToKill.get(i);
8444 Log.i(TAG, "Removing system update proc: " + proc);
8445 removeProcessLocked(proc, true);
8446 }
8447 }
8448 }
8449
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008450 Log.i(TAG, "System now ready");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008451 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008452 SystemClock.uptimeMillis());
8453
8454 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008455 // Make sure we have no pre-ready processes sitting around.
8456
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008457 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8458 ResolveInfo ri = mContext.getPackageManager()
8459 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008460 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008461 CharSequence errorMsg = null;
8462 if (ri != null) {
8463 ActivityInfo ai = ri.activityInfo;
8464 ApplicationInfo app = ai.applicationInfo;
8465 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8466 mTopAction = Intent.ACTION_FACTORY_TEST;
8467 mTopData = null;
8468 mTopComponent = new ComponentName(app.packageName,
8469 ai.name);
8470 } else {
8471 errorMsg = mContext.getResources().getText(
8472 com.android.internal.R.string.factorytest_not_system);
8473 }
8474 } else {
8475 errorMsg = mContext.getResources().getText(
8476 com.android.internal.R.string.factorytest_no_action);
8477 }
8478 if (errorMsg != null) {
8479 mTopAction = null;
8480 mTopData = null;
8481 mTopComponent = null;
8482 Message msg = Message.obtain();
8483 msg.what = SHOW_FACTORY_ERROR_MSG;
8484 msg.getData().putCharSequence("msg", errorMsg);
8485 mHandler.sendMessage(msg);
8486 }
8487 }
8488 }
8489
8490 retrieveSettings();
8491
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008492 if (goingCallback != null) goingCallback.run();
8493
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008494 synchronized (this) {
8495 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8496 try {
8497 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008498 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008499 if (apps != null) {
8500 int N = apps.size();
8501 int i;
8502 for (i=0; i<N; i++) {
8503 ApplicationInfo info
8504 = (ApplicationInfo)apps.get(i);
8505 if (info != null &&
8506 !info.packageName.equals("android")) {
8507 addAppLocked(info);
8508 }
8509 }
8510 }
8511 } catch (RemoteException ex) {
8512 // pm is in same process, this will never happen.
8513 }
8514 }
8515
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008516 // Start up initial activity.
8517 mBooting = true;
8518
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008519 try {
8520 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8521 Message msg = Message.obtain();
8522 msg.what = SHOW_UID_ERROR_MSG;
8523 mHandler.sendMessage(msg);
8524 }
8525 } catch (RemoteException e) {
8526 }
8527
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008528 resumeTopActivityLocked(null);
8529 }
8530 }
8531
Dan Egnorb7f03672009-12-09 16:22:32 -08008532 private boolean makeAppCrashingLocked(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008533 String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008534 app.crashing = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008535 app.crashingReport = generateProcessError(app,
Dan Egnor60d87622009-12-16 16:32:58 -08008536 ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008537 startAppProblemLocked(app);
8538 app.stopFreezingAllLocked();
8539 return handleAppCrashLocked(app);
8540 }
8541
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008542 private ComponentName getErrorReportReceiver(ProcessRecord app) {
Jacek Surazskia2339432009-09-18 15:01:26 +02008543 // check if error reporting is enabled in Gservices
8544 int enabled = Settings.Gservices.getInt(mContext.getContentResolver(),
8545 Settings.Gservices.SEND_ACTION_APP_ERROR, 0);
8546 if (enabled == 0) {
8547 return null;
8548 }
8549
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008550 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008551
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008552 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008553 // look for receiver in the installer package
8554 String candidate = pm.getInstallerPackageName(app.info.packageName);
8555 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8556 if (result != null) {
8557 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008558 }
8559
Jacek Surazski82a73df2009-06-17 14:33:18 +02008560 // if the error app is on the system image, look for system apps
8561 // error receiver
8562 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8563 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8564 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8565 if (result != null) {
8566 return result;
8567 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008568 }
8569
Jacek Surazski82a73df2009-06-17 14:33:18 +02008570 // if there is a default receiver, try that
8571 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8572 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008573 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008574 // should not happen
8575 Log.e(TAG, "error talking to PackageManager", e);
8576 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008577 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008578 }
8579
8580 /**
8581 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8582 *
8583 * @param pm PackageManager isntance
8584 * @param errorPackage package which caused the error
8585 * @param receiverPackage candidate package to receive the error
8586 * @return activity component within receiverPackage which handles
8587 * ACTION_APP_ERROR, or null if not found
8588 */
8589 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8590 String receiverPackage) throws RemoteException {
8591 if (receiverPackage == null || receiverPackage.length() == 0) {
8592 return null;
8593 }
8594
8595 // break the loop if it's the error report receiver package that crashed
8596 if (receiverPackage.equals(errorPackage)) {
8597 return null;
8598 }
8599
8600 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8601 intent.setPackage(receiverPackage);
8602 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8603 if (info == null || info.activityInfo == null) {
8604 return null;
8605 }
8606 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008607 }
8608
Dan Egnorb7f03672009-12-09 16:22:32 -08008609 private void makeAppNotRespondingLocked(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008610 String activity, String shortMsg, String longMsg) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008611 app.notResponding = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008612 app.notRespondingReport = generateProcessError(app,
Dan Egnor60d87622009-12-16 16:32:58 -08008613 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING,
8614 activity, shortMsg, longMsg, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008615 startAppProblemLocked(app);
8616 app.stopFreezingAllLocked();
8617 }
8618
8619 /**
8620 * Generate a process error record, suitable for attachment to a ProcessRecord.
8621 *
8622 * @param app The ProcessRecord in which the error occurred.
8623 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8624 * ActivityManager.AppErrorStateInfo
Dan Egnor60d87622009-12-16 16:32:58 -08008625 * @param activity The activity associated with the crash, if known.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008626 * @param shortMsg Short message describing the crash.
8627 * @param longMsg Long message describing the crash.
Dan Egnorb7f03672009-12-09 16:22:32 -08008628 * @param stackTrace Full crash stack trace, may be null.
8629 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008630 * @return Returns a fully-formed AppErrorStateInfo record.
8631 */
8632 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008633 int condition, String activity, String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008634 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
Dan Egnorb7f03672009-12-09 16:22:32 -08008635
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008636 report.condition = condition;
8637 report.processName = app.processName;
8638 report.pid = app.pid;
8639 report.uid = app.info.uid;
Dan Egnor60d87622009-12-16 16:32:58 -08008640 report.tag = activity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008641 report.shortMsg = shortMsg;
8642 report.longMsg = longMsg;
Dan Egnorb7f03672009-12-09 16:22:32 -08008643 report.stackTrace = stackTrace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008644
8645 return report;
8646 }
8647
8648 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8649 boolean crashed) {
8650 synchronized (this) {
8651 app.crashing = false;
8652 app.crashingReport = null;
8653 app.notResponding = false;
8654 app.notRespondingReport = null;
8655 if (app.anrDialog == fromDialog) {
8656 app.anrDialog = null;
8657 }
8658 if (app.waitDialog == fromDialog) {
8659 app.waitDialog = null;
8660 }
8661 if (app.pid > 0 && app.pid != MY_PID) {
8662 if (crashed) {
8663 handleAppCrashLocked(app);
8664 }
8665 Log.i(ActivityManagerService.TAG, "Killing process "
8666 + app.processName
8667 + " (pid=" + app.pid + ") at user's request");
8668 Process.killProcess(app.pid);
8669 }
8670
8671 }
8672 }
8673
Dan Egnorb7f03672009-12-09 16:22:32 -08008674 private boolean handleAppCrashLocked(ProcessRecord app) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008675 long now = SystemClock.uptimeMillis();
8676
8677 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8678 app.info.uid);
8679 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8680 // This process loses!
8681 Log.w(TAG, "Process " + app.info.processName
8682 + " has crashed too many times: killing!");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008683 EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008684 app.info.processName, app.info.uid);
8685 killServicesLocked(app, false);
8686 for (int i=mHistory.size()-1; i>=0; i--) {
8687 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8688 if (r.app == app) {
8689 if (Config.LOGD) Log.d(
8690 TAG, " Force finishing activity "
8691 + r.intent.getComponent().flattenToShortString());
8692 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8693 }
8694 }
8695 if (!app.persistent) {
8696 // We don't want to start this process again until the user
8697 // explicitly does so... but for persistent process, we really
8698 // need to keep it running. If a persistent process is actually
8699 // repeatedly crashing, then badness for everyone.
Doug Zongker2bec3d42009-12-04 12:52:44 -08008700 EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008701 app.info.processName);
8702 mBadProcesses.put(app.info.processName, app.info.uid, now);
8703 app.bad = true;
8704 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8705 app.removed = true;
8706 removeProcessLocked(app, false);
8707 return false;
8708 }
8709 }
8710
8711 // Bump up the crash count of any services currently running in the proc.
8712 if (app.services.size() != 0) {
8713 // Any services running in the application need to be placed
8714 // back in the pending list.
8715 Iterator it = app.services.iterator();
8716 while (it.hasNext()) {
8717 ServiceRecord sr = (ServiceRecord)it.next();
8718 sr.crashCount++;
8719 }
8720 }
8721
8722 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8723 return true;
8724 }
8725
8726 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008727 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008728 skipCurrentReceiverLocked(app);
8729 }
8730
8731 void skipCurrentReceiverLocked(ProcessRecord app) {
8732 boolean reschedule = false;
8733 BroadcastRecord r = app.curReceiver;
8734 if (r != null) {
8735 // The current broadcast is waiting for this app's receiver
8736 // to be finished. Looks like that's not going to happen, so
8737 // let the broadcast continue.
8738 logBroadcastReceiverDiscard(r);
8739 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8740 r.resultExtras, r.resultAbort, true);
8741 reschedule = true;
8742 }
8743 r = mPendingBroadcast;
8744 if (r != null && r.curApp == app) {
8745 if (DEBUG_BROADCAST) Log.v(TAG,
8746 "skip & discard pending app " + r);
8747 logBroadcastReceiverDiscard(r);
8748 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8749 r.resultExtras, r.resultAbort, true);
8750 reschedule = true;
8751 }
8752 if (reschedule) {
8753 scheduleBroadcastsLocked();
8754 }
8755 }
8756
Dan Egnor60d87622009-12-16 16:32:58 -08008757 /**
8758 * Used by {@link com.android.internal.os.RuntimeInit} to report when an application crashes.
8759 * The application process will exit immediately after this call returns.
8760 * @param app object of the crashing app, null for the system server
8761 * @param crashInfo describing the exception
8762 */
8763 public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) {
8764 ProcessRecord r = findAppProcess(app);
8765
8766 EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
8767 app == null ? "system" : (r == null ? "unknown" : r.processName),
8768 crashInfo.exceptionClassName,
8769 crashInfo.exceptionMessage,
8770 crashInfo.throwFileName,
8771 crashInfo.throwLineNumber);
8772
8773 addExceptionToDropBox("crash", r, null, crashInfo);
8774
8775 crashApplication(r, crashInfo);
8776 }
8777
8778 /**
8779 * Used by {@link Log} via {@link com.android.internal.os.RuntimeInit} to report serious errors.
8780 * @param app object of the crashing app, null for the system server
8781 * @param tag reported by the caller
8782 * @param crashInfo describing the context of the error
8783 * @return true if the process should exit immediately (WTF is fatal)
8784 */
8785 public boolean handleApplicationWtf(IBinder app, String tag,
Dan Egnorb7f03672009-12-09 16:22:32 -08008786 ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnor60d87622009-12-16 16:32:58 -08008787 ProcessRecord r = findAppProcess(app);
8788
8789 EventLog.writeEvent(EventLogTags.AM_WTF, Binder.getCallingPid(),
8790 app == null ? "system" : (r == null ? "unknown" : r.processName),
8791 tag, crashInfo.exceptionMessage);
8792
8793 addExceptionToDropBox("wtf", r, tag, crashInfo);
8794
8795 if (Settings.Gservices.getInt(mContext.getContentResolver(),
8796 Settings.Gservices.WTF_IS_FATAL, 0) != 0) {
8797 crashApplication(r, crashInfo);
8798 return true;
8799 } else {
8800 return false;
8801 }
8802 }
8803
8804 /**
8805 * @param app object of some object (as stored in {@link com.android.internal.os.RuntimeInit})
8806 * @return the corresponding {@link ProcessRecord} object, or null if none could be found
8807 */
8808 private ProcessRecord findAppProcess(IBinder app) {
8809 if (app == null) {
8810 return null;
8811 }
8812
8813 synchronized (this) {
8814 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8815 final int NA = apps.size();
8816 for (int ia=0; ia<NA; ia++) {
8817 ProcessRecord p = apps.valueAt(ia);
8818 if (p.thread != null && p.thread.asBinder() == app) {
8819 return p;
8820 }
8821 }
8822 }
8823
8824 Log.w(TAG, "Can't find mystery application: " + app);
8825 return null;
8826 }
8827 }
8828
8829 /**
8830 * Write a description of an exception (from a crash or WTF report) to the drop box.
8831 * @param eventType to include in the drop box tag ("crash", "wtf", etc.)
8832 * @param r the process which crashed, null for the system server
8833 * @param tag supplied by the application (in the case of WTF), or null
8834 * @param crashInfo describing the exception
8835 */
8836 private void addExceptionToDropBox(String eventType, ProcessRecord r, String tag,
8837 ApplicationErrorReport.CrashInfo crashInfo) {
8838 String dropboxTag, processName;
8839 if (r == null) {
8840 dropboxTag = "system_server_" + eventType;
8841 } else if ((r.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
8842 dropboxTag = "system_app_" + eventType;
8843 } else {
8844 dropboxTag = "data_app_" + eventType;
8845 }
8846
8847 DropBoxManager dbox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
8848 if (dbox != null && dbox.isTagEnabled(dropboxTag)) {
8849 StringBuilder sb = new StringBuilder(1024);
8850 sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
8851 if (r == null) {
8852 sb.append("Process: system_server\n");
8853 } else {
8854 sb.append("Package: ").append(r.info.packageName).append("\n");
8855 if (!r.processName.equals(r.info.packageName)) {
8856 sb.append("Process: ").append(r.processName).append("\n");
8857 }
8858 }
8859 if (tag != null) {
8860 sb.append("Tag: ").append(tag).append("\n");
8861 }
8862 if (crashInfo != null && crashInfo.stackTrace != null) {
8863 sb.append("\n").append(crashInfo.stackTrace);
8864 }
8865 dbox.addText(dropboxTag, sb.toString());
8866 }
8867 }
8868
8869 /**
8870 * Bring up the "unexpected error" dialog box for a crashing app.
8871 * Deal with edge cases (intercepts from instrumented applications,
8872 * ActivityController, error intent receivers, that sort of thing).
8873 * @param r the application crashing
8874 * @param crashInfo describing the failure
8875 */
8876 private void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnorb7f03672009-12-09 16:22:32 -08008877 long timeMillis = System.currentTimeMillis();
8878 String shortMsg = crashInfo.exceptionClassName;
8879 String longMsg = crashInfo.exceptionMessage;
8880 String stackTrace = crashInfo.stackTrace;
8881 if (shortMsg != null && longMsg != null) {
8882 longMsg = shortMsg + ": " + longMsg;
8883 } else if (shortMsg != null) {
8884 longMsg = shortMsg;
8885 }
8886
Dan Egnor60d87622009-12-16 16:32:58 -08008887 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008888 synchronized (this) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008889 if (r != null) {
8890 // The application has crashed. Send the SIGQUIT to the process so
8891 // that it can dump its state.
8892 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8893 //Log.i(TAG, "Current system threads:");
8894 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8895 }
8896
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008897 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008898 try {
8899 String name = r != null ? r.processName : null;
8900 int pid = r != null ? r.pid : Binder.getCallingPid();
Dan Egnor60d87622009-12-16 16:32:58 -08008901 if (!mController.appCrashed(name, pid,
Dan Egnorb7f03672009-12-09 16:22:32 -08008902 shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008903 Log.w(TAG, "Force-killing crashed app " + name
8904 + " at watcher's request");
8905 Process.killProcess(pid);
Dan Egnorb7f03672009-12-09 16:22:32 -08008906 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008907 }
8908 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008909 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008910 }
8911 }
8912
8913 final long origId = Binder.clearCallingIdentity();
8914
8915 // If this process is running instrumentation, finish it.
8916 if (r != null && r.instrumentationClass != null) {
8917 Log.w(TAG, "Error in app " + r.processName
8918 + " running instrumentation " + r.instrumentationClass + ":");
8919 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8920 if (longMsg != null) Log.w(TAG, " " + longMsg);
8921 Bundle info = new Bundle();
8922 info.putString("shortMsg", shortMsg);
8923 info.putString("longMsg", longMsg);
8924 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8925 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08008926 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008927 }
8928
Dan Egnor60d87622009-12-16 16:32:58 -08008929 // If we can't identify the process or it's already exceeded its crash quota,
8930 // quit right away without showing a crash dialog.
8931 if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008932 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08008933 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008934 }
8935
8936 Message msg = Message.obtain();
8937 msg.what = SHOW_ERROR_MSG;
8938 HashMap data = new HashMap();
8939 data.put("result", result);
8940 data.put("app", r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008941 msg.obj = data;
8942 mHandler.sendMessage(msg);
8943
8944 Binder.restoreCallingIdentity(origId);
8945 }
8946
8947 int res = result.get();
8948
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008949 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008950 synchronized (this) {
8951 if (r != null) {
8952 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8953 SystemClock.uptimeMillis());
8954 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008955 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
Dan Egnorb7f03672009-12-09 16:22:32 -08008956 appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008957 }
8958 }
8959
8960 if (appErrorIntent != null) {
8961 try {
8962 mContext.startActivity(appErrorIntent);
8963 } catch (ActivityNotFoundException e) {
8964 Log.w(TAG, "bug report receiver dissappeared", e);
8965 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008966 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008967 }
Dan Egnorb7f03672009-12-09 16:22:32 -08008968
8969 Intent createAppErrorIntentLocked(ProcessRecord r,
8970 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
8971 ApplicationErrorReport report = createAppErrorReportLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008972 if (report == null) {
8973 return null;
8974 }
8975 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8976 result.setComponent(r.errorReportReceiver);
8977 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8978 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8979 return result;
8980 }
8981
Dan Egnorb7f03672009-12-09 16:22:32 -08008982 private ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r,
8983 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008984 if (r.errorReportReceiver == null) {
8985 return null;
8986 }
8987
8988 if (!r.crashing && !r.notResponding) {
8989 return null;
8990 }
8991
Dan Egnorb7f03672009-12-09 16:22:32 -08008992 ApplicationErrorReport report = new ApplicationErrorReport();
8993 report.packageName = r.info.packageName;
8994 report.installerPackageName = r.errorReportReceiver.getPackageName();
8995 report.processName = r.processName;
8996 report.time = timeMillis;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008997
Dan Egnorb7f03672009-12-09 16:22:32 -08008998 if (r.crashing) {
8999 report.type = ApplicationErrorReport.TYPE_CRASH;
9000 report.crashInfo = crashInfo;
9001 } else if (r.notResponding) {
9002 report.type = ApplicationErrorReport.TYPE_ANR;
9003 report.anrInfo = new ApplicationErrorReport.AnrInfo();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009004
Dan Egnorb7f03672009-12-09 16:22:32 -08009005 report.anrInfo.activity = r.notRespondingReport.tag;
9006 report.anrInfo.cause = r.notRespondingReport.shortMsg;
9007 report.anrInfo.info = r.notRespondingReport.longMsg;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009008 }
9009
Dan Egnorb7f03672009-12-09 16:22:32 -08009010 return report;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009011 }
9012
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009013 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
9014 // assume our apps are happy - lazy create the list
9015 List<ActivityManager.ProcessErrorStateInfo> errList = null;
9016
9017 synchronized (this) {
9018
9019 // iterate across all processes
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009020 for (int i=mLruProcesses.size()-1; i>=0; i--) {
9021 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009022 if ((app.thread != null) && (app.crashing || app.notResponding)) {
9023 // This one's in trouble, so we'll generate a report for it
9024 // crashes are higher priority (in case there's a crash *and* an anr)
9025 ActivityManager.ProcessErrorStateInfo report = null;
9026 if (app.crashing) {
9027 report = app.crashingReport;
9028 } else if (app.notResponding) {
9029 report = app.notRespondingReport;
9030 }
9031
9032 if (report != null) {
9033 if (errList == null) {
9034 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
9035 }
9036 errList.add(report);
9037 } else {
9038 Log.w(TAG, "Missing app error report, app = " + app.processName +
9039 " crashing = " + app.crashing +
9040 " notResponding = " + app.notResponding);
9041 }
9042 }
9043 }
9044 }
9045
9046 return errList;
9047 }
9048
9049 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
9050 // Lazy instantiation of list
9051 List<ActivityManager.RunningAppProcessInfo> runList = null;
9052 synchronized (this) {
9053 // Iterate across all processes
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009054 for (int i=mLruProcesses.size()-1; i>=0; i--) {
9055 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009056 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
9057 // Generate process state info for running application
9058 ActivityManager.RunningAppProcessInfo currApp =
9059 new ActivityManager.RunningAppProcessInfo(app.processName,
9060 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07009061 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009062 int adj = app.curAdj;
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009063 if (adj >= EMPTY_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009064 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
9065 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
9066 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08009067 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
9068 } else if (adj >= HOME_APP_ADJ) {
9069 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
9070 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009071 } else if (adj >= SECONDARY_SERVER_ADJ) {
9072 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
9073 } else if (adj >= VISIBLE_APP_ADJ) {
9074 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
9075 } else {
9076 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
9077 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009078 currApp.importanceReasonCode = app.adjTypeCode;
9079 if (app.adjSource instanceof ProcessRecord) {
9080 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
9081 } else if (app.adjSource instanceof HistoryRecord) {
9082 HistoryRecord r = (HistoryRecord)app.adjSource;
9083 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
9084 }
9085 if (app.adjTarget instanceof ComponentName) {
9086 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
9087 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009088 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
9089 // + " lru=" + currApp.lru);
9090 if (runList == null) {
9091 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
9092 }
9093 runList.add(currApp);
9094 }
9095 }
9096 }
9097 return runList;
9098 }
9099
9100 @Override
9101 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009102 if (checkCallingPermission(android.Manifest.permission.DUMP)
9103 != PackageManager.PERMISSION_GRANTED) {
9104 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9105 + Binder.getCallingPid()
9106 + ", uid=" + Binder.getCallingUid()
9107 + " without permission "
9108 + android.Manifest.permission.DUMP);
9109 return;
9110 }
9111
9112 boolean dumpAll = false;
9113
9114 int opti = 0;
9115 while (opti < args.length) {
9116 String opt = args[opti];
9117 if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
9118 break;
9119 }
9120 opti++;
9121 if ("-a".equals(opt)) {
9122 dumpAll = true;
9123 } else if ("-h".equals(opt)) {
9124 pw.println("Activity manager dump options:");
9125 pw.println(" [-a] [h- [cmd] ...");
9126 pw.println(" cmd may be one of:");
9127 pw.println(" activities: activity stack state");
9128 pw.println(" broadcasts: broadcast state");
9129 pw.println(" intents: pending intent state");
9130 pw.println(" processes: process state");
9131 pw.println(" providers: content provider state");
9132 pw.println(" services: service state");
9133 pw.println(" service [name]: service client-side state");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009134 return;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009135 } else {
9136 pw.println("Unknown argument: " + opt + "; use -h for help");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009137 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009138 }
9139
9140 // Is the caller requesting to dump a particular piece of data?
9141 if (opti < args.length) {
9142 String cmd = args[opti];
9143 opti++;
9144 if ("activities".equals(cmd) || "a".equals(cmd)) {
9145 synchronized (this) {
9146 dumpActivitiesLocked(fd, pw, args, opti, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009147 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009148 return;
9149 } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
9150 synchronized (this) {
9151 dumpBroadcastsLocked(fd, pw, args, opti, true);
9152 }
9153 return;
9154 } else if ("intents".equals(cmd) || "i".equals(cmd)) {
9155 synchronized (this) {
9156 dumpPendingIntentsLocked(fd, pw, args, opti, true);
9157 }
9158 return;
9159 } else if ("processes".equals(cmd) || "p".equals(cmd)) {
9160 synchronized (this) {
9161 dumpProcessesLocked(fd, pw, args, opti, true);
9162 }
9163 return;
9164 } else if ("providers".equals(cmd) || "prov".equals(cmd)) {
9165 synchronized (this) {
9166 dumpProvidersLocked(fd, pw, args, opti, true);
9167 }
9168 return;
9169 } else if ("service".equals(cmd)) {
9170 dumpService(fd, pw, args, opti, true);
9171 return;
9172 } else if ("services".equals(cmd) || "s".equals(cmd)) {
9173 synchronized (this) {
9174 dumpServicesLocked(fd, pw, args, opti, true);
9175 }
9176 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009177 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009178 }
9179
9180 // No piece of data specified, dump everything.
9181 synchronized (this) {
9182 boolean needSep;
9183 if (dumpAll) {
9184 pw.println("Providers in Current Activity Manager State:");
9185 }
9186 needSep = dumpProvidersLocked(fd, pw, args, opti, dumpAll);
9187 if (needSep) {
9188 pw.println(" ");
9189 }
9190 if (dumpAll) {
9191 pw.println("-------------------------------------------------------------------------------");
9192 pw.println("Broadcasts in Current Activity Manager State:");
9193 }
9194 needSep = dumpBroadcastsLocked(fd, pw, args, opti, dumpAll);
9195 if (needSep) {
9196 pw.println(" ");
9197 }
9198 if (dumpAll) {
9199 pw.println("-------------------------------------------------------------------------------");
9200 pw.println("Services in Current Activity Manager State:");
9201 }
9202 needSep = dumpServicesLocked(fd, pw, args, opti, dumpAll);
9203 if (needSep) {
9204 pw.println(" ");
9205 }
9206 if (dumpAll) {
9207 pw.println("-------------------------------------------------------------------------------");
9208 pw.println("PendingIntents in Current Activity Manager State:");
9209 }
9210 needSep = dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll);
9211 if (needSep) {
9212 pw.println(" ");
9213 }
9214 if (dumpAll) {
9215 pw.println("-------------------------------------------------------------------------------");
9216 pw.println("Activities in Current Activity Manager State:");
9217 }
9218 needSep = dumpActivitiesLocked(fd, pw, args, opti, dumpAll, !dumpAll);
9219 if (needSep) {
9220 pw.println(" ");
9221 }
9222 if (dumpAll) {
9223 pw.println("-------------------------------------------------------------------------------");
9224 pw.println("Processes in Current Activity Manager State:");
9225 }
9226 dumpProcessesLocked(fd, pw, args, opti, dumpAll);
9227 }
9228 }
9229
9230 boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9231 int opti, boolean dumpAll, boolean needHeader) {
9232 if (needHeader) {
9233 pw.println(" Activity stack:");
9234 }
9235 dumpHistoryList(pw, mHistory, " ", "Hist", true);
9236 pw.println(" ");
9237 pw.println(" Running activities (most recent first):");
9238 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
9239 if (mWaitingVisibleActivities.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009240 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009241 pw.println(" Activities waiting for another to become visible:");
9242 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
9243 }
9244 if (mStoppingActivities.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009245 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009246 pw.println(" Activities waiting to stop:");
9247 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
9248 }
9249 if (mFinishingActivities.size() > 0) {
9250 pw.println(" ");
9251 pw.println(" Activities waiting to finish:");
9252 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
9253 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009254
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009255 pw.println(" ");
9256 pw.println(" mPausingActivity: " + mPausingActivity);
9257 pw.println(" mResumedActivity: " + mResumedActivity);
9258 pw.println(" mFocusedActivity: " + mFocusedActivity);
9259 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009260
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009261 if (dumpAll && mRecentTasks.size() > 0) {
9262 pw.println(" ");
9263 pw.println("Recent tasks in Current Activity Manager State:");
9264
9265 final int N = mRecentTasks.size();
9266 for (int i=0; i<N; i++) {
9267 TaskRecord tr = mRecentTasks.get(i);
9268 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
9269 pw.println(tr);
9270 mRecentTasks.get(i).dump(pw, " ");
9271 }
9272 }
9273
9274 pw.println(" ");
9275 pw.println(" mCurTask: " + mCurTask);
9276
9277 return true;
9278 }
9279
9280 boolean dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9281 int opti, boolean dumpAll) {
9282 boolean needSep = false;
9283 int numPers = 0;
9284
9285 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009286 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
9287 final int NA = procs.size();
9288 for (int ia=0; ia<NA; ia++) {
9289 if (!needSep) {
9290 pw.println(" All known processes:");
9291 needSep = true;
9292 }
9293 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009294 pw.print(r.persistent ? " *PERS*" : " *APP*");
9295 pw.print(" UID "); pw.print(procs.keyAt(ia));
9296 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009297 r.dump(pw, " ");
9298 if (r.persistent) {
9299 numPers++;
9300 }
9301 }
9302 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009303 }
9304
9305 if (mLruProcesses.size() > 0) {
9306 if (needSep) pw.println(" ");
9307 needSep = true;
9308 pw.println(" Running processes (most recent first):");
9309 dumpProcessList(pw, this, mLruProcesses, " ",
9310 "App ", "PERS", true);
9311 needSep = true;
9312 }
9313
9314 synchronized (mPidsSelfLocked) {
9315 if (mPidsSelfLocked.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009316 if (needSep) pw.println(" ");
9317 needSep = true;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009318 pw.println(" PID mappings:");
9319 for (int i=0; i<mPidsSelfLocked.size(); i++) {
9320 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9321 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009322 }
9323 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009324 }
9325
9326 if (mForegroundProcesses.size() > 0) {
9327 if (needSep) pw.println(" ");
9328 needSep = true;
9329 pw.println(" Foreground Processes:");
9330 for (int i=0; i<mForegroundProcesses.size(); i++) {
9331 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9332 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009333 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009334 }
9335
9336 if (mPersistentStartingProcesses.size() > 0) {
9337 if (needSep) pw.println(" ");
9338 needSep = true;
9339 pw.println(" Persisent processes that are starting:");
9340 dumpProcessList(pw, this, mPersistentStartingProcesses, " ",
9341 "Starting Norm", "Restarting PERS", false);
9342 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009343
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009344 if (mStartingProcesses.size() > 0) {
9345 if (needSep) pw.println(" ");
9346 needSep = true;
9347 pw.println(" Processes that are starting:");
9348 dumpProcessList(pw, this, mStartingProcesses, " ",
9349 "Starting Norm", "Starting PERS", false);
9350 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009351
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009352 if (mRemovedProcesses.size() > 0) {
9353 if (needSep) pw.println(" ");
9354 needSep = true;
9355 pw.println(" Processes that are being removed:");
9356 dumpProcessList(pw, this, mRemovedProcesses, " ",
9357 "Removed Norm", "Removed PERS", false);
9358 }
9359
9360 if (mProcessesOnHold.size() > 0) {
9361 if (needSep) pw.println(" ");
9362 needSep = true;
9363 pw.println(" Processes that are on old until the system is ready:");
9364 dumpProcessList(pw, this, mProcessesOnHold, " ",
9365 "OnHold Norm", "OnHold PERS", false);
9366 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009367
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009368 if (mProcessesToGc.size() > 0) {
9369 if (needSep) pw.println(" ");
9370 needSep = true;
9371 pw.println(" Processes that are waiting to GC:");
9372 long now = SystemClock.uptimeMillis();
9373 for (int i=0; i<mProcessesToGc.size(); i++) {
9374 ProcessRecord proc = mProcessesToGc.get(i);
9375 pw.print(" Process "); pw.println(proc);
9376 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9377 pw.print(", last gced=");
9378 pw.print(now-proc.lastRequestedGc);
9379 pw.print(" ms ago, last lowMem=");
9380 pw.print(now-proc.lastLowMemory);
9381 pw.println(" ms ago");
9382
9383 }
9384 }
9385
9386 if (mProcessCrashTimes.getMap().size() > 0) {
9387 if (needSep) pw.println(" ");
9388 needSep = true;
9389 pw.println(" Time since processes crashed:");
9390 long now = SystemClock.uptimeMillis();
9391 for (Map.Entry<String, SparseArray<Long>> procs
9392 : mProcessCrashTimes.getMap().entrySet()) {
9393 SparseArray<Long> uids = procs.getValue();
9394 final int N = uids.size();
9395 for (int i=0; i<N; i++) {
9396 pw.print(" Process "); pw.print(procs.getKey());
9397 pw.print(" uid "); pw.print(uids.keyAt(i));
9398 pw.print(": last crashed ");
9399 pw.print((now-uids.valueAt(i)));
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009400 pw.println(" ms ago");
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009401 }
9402 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009403 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009404
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009405 if (mBadProcesses.getMap().size() > 0) {
9406 if (needSep) pw.println(" ");
9407 needSep = true;
9408 pw.println(" Bad processes:");
9409 for (Map.Entry<String, SparseArray<Long>> procs
9410 : mBadProcesses.getMap().entrySet()) {
9411 SparseArray<Long> uids = procs.getValue();
9412 final int N = uids.size();
9413 for (int i=0; i<N; i++) {
9414 pw.print(" Bad process "); pw.print(procs.getKey());
9415 pw.print(" uid "); pw.print(uids.keyAt(i));
9416 pw.print(": crashed at time ");
9417 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009418 }
9419 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009420 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009421
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009422 pw.println(" ");
9423 pw.println(" mHomeProcess: " + mHomeProcess);
9424 pw.println(" mConfiguration: " + mConfiguration);
9425 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
9426 if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
9427 || mOrigWaitForDebugger) {
9428 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9429 + " mDebugTransient=" + mDebugTransient
9430 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9431 }
9432 if (mAlwaysFinishActivities || mController != null) {
9433 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
9434 + " mController=" + mController);
9435 }
9436 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009437 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009438 pw.println(" mStartRunning=" + mStartRunning
9439 + " mSystemReady=" + mSystemReady
9440 + " mBooting=" + mBooting
9441 + " mBooted=" + mBooted
9442 + " mFactoryTest=" + mFactoryTest);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009443 pw.println(" mGoingToSleep=" + mGoingToSleep);
9444 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009445 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009446
9447 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009448 }
9449
9450 /**
9451 * There are three ways to call this:
9452 * - no service specified: dump all the services
9453 * - a flattened component name that matched an existing service was specified as the
9454 * first arg: dump that one service
9455 * - the first arg isn't the flattened component name of an existing service:
9456 * dump all services whose component contains the first arg as a substring
9457 */
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009458 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args,
9459 int opti, boolean dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009460 String[] newArgs;
9461 String componentNameString;
9462 ServiceRecord r;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009463 if (opti <= args.length) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009464 componentNameString = null;
9465 newArgs = EMPTY_STRING_ARRAY;
9466 r = null;
9467 } else {
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009468 componentNameString = args[opti];
9469 opti++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009470 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9471 r = componentName != null ? mServices.get(componentName) : null;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009472 newArgs = new String[args.length - opti];
9473 if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009474 }
9475
9476 if (r != null) {
9477 dumpService(fd, pw, r, newArgs);
9478 } else {
9479 for (ServiceRecord r1 : mServices.values()) {
9480 if (componentNameString == null
9481 || r1.name.flattenToString().contains(componentNameString)) {
9482 dumpService(fd, pw, r1, newArgs);
9483 }
9484 }
9485 }
9486 }
9487
9488 /**
9489 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9490 * there is a thread associated with the service.
9491 */
9492 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9493 pw.println(" Service " + r.name.flattenToString());
9494 if (r.app != null && r.app.thread != null) {
9495 try {
9496 // flush anything that is already in the PrintWriter since the thread is going
9497 // to write to the file descriptor directly
9498 pw.flush();
9499 r.app.thread.dumpService(fd, r, args);
9500 pw.print("\n");
9501 } catch (RemoteException e) {
9502 pw.println("got a RemoteException while dumping the service");
9503 }
9504 }
9505 }
9506
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009507 boolean dumpBroadcastsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9508 int opti, boolean dumpAll) {
9509 boolean needSep = false;
9510
9511 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009512 if (mRegisteredReceivers.size() > 0) {
9513 pw.println(" ");
9514 pw.println(" Registered Receivers:");
9515 Iterator it = mRegisteredReceivers.values().iterator();
9516 while (it.hasNext()) {
9517 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009518 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009519 r.dump(pw, " ");
9520 }
9521 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009522
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009523 pw.println(" ");
9524 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009525 mReceiverResolver.dump(pw, " ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009526 needSep = true;
9527 }
9528
9529 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9530 || mPendingBroadcast != null) {
9531 if (mParallelBroadcasts.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009532 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009533 pw.println(" Active broadcasts:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009534 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009535 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9536 pw.println(" Broadcast #" + i + ":");
9537 mParallelBroadcasts.get(i).dump(pw, " ");
9538 }
9539 if (mOrderedBroadcasts.size() > 0) {
9540 pw.println(" ");
9541 pw.println(" Active serialized broadcasts:");
9542 }
9543 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9544 pw.println(" Serialized Broadcast #" + i + ":");
9545 mOrderedBroadcasts.get(i).dump(pw, " ");
9546 }
9547 pw.println(" ");
9548 pw.println(" Pending broadcast:");
9549 if (mPendingBroadcast != null) {
9550 mPendingBroadcast.dump(pw, " ");
9551 } else {
9552 pw.println(" (null)");
9553 }
9554 needSep = true;
9555 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009556
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009557 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009558 pw.println(" ");
Dianne Hackborn12527f92009-11-11 17:39:50 -08009559 pw.println(" Historical broadcasts:");
9560 for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
9561 BroadcastRecord r = mBroadcastHistory[i];
9562 if (r == null) {
9563 break;
9564 }
9565 pw.println(" Historical Broadcast #" + i + ":");
9566 r.dump(pw, " ");
9567 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009568 needSep = true;
9569 }
9570
9571 if (mStickyBroadcasts != null) {
Dianne Hackborn12527f92009-11-11 17:39:50 -08009572 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009573 pw.println(" Sticky broadcasts:");
9574 StringBuilder sb = new StringBuilder(128);
9575 for (Map.Entry<String, ArrayList<Intent>> ent
9576 : mStickyBroadcasts.entrySet()) {
9577 pw.print(" * Sticky action "); pw.print(ent.getKey());
9578 pw.println(":");
9579 ArrayList<Intent> intents = ent.getValue();
9580 final int N = intents.size();
9581 for (int i=0; i<N; i++) {
9582 sb.setLength(0);
9583 sb.append(" Intent: ");
9584 intents.get(i).toShortString(sb, true, false);
9585 pw.println(sb.toString());
9586 Bundle bundle = intents.get(i).getExtras();
9587 if (bundle != null) {
9588 pw.print(" ");
9589 pw.println(bundle.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009590 }
9591 }
9592 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009593 needSep = true;
9594 }
9595
9596 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009597 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009598 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009599 pw.println(" mHandler:");
9600 mHandler.dump(new PrintWriterPrinter(pw), " ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009601 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009602 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009603
9604 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009605 }
9606
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009607 boolean dumpServicesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9608 int opti, boolean dumpAll) {
9609 boolean needSep = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009610
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009611 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009612 if (mServices.size() > 0) {
9613 pw.println(" Active services:");
9614 Iterator<ServiceRecord> it = mServices.values().iterator();
9615 while (it.hasNext()) {
9616 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009617 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009618 r.dump(pw, " ");
9619 }
9620 needSep = true;
9621 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009622 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009623
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009624 if (mPendingServices.size() > 0) {
9625 if (needSep) pw.println(" ");
9626 pw.println(" Pending services:");
9627 for (int i=0; i<mPendingServices.size(); i++) {
9628 ServiceRecord r = mPendingServices.get(i);
9629 pw.print(" * Pending "); pw.println(r);
9630 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009631 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009632 needSep = true;
9633 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009634
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009635 if (mRestartingServices.size() > 0) {
9636 if (needSep) pw.println(" ");
9637 pw.println(" Restarting services:");
9638 for (int i=0; i<mRestartingServices.size(); i++) {
9639 ServiceRecord r = mRestartingServices.get(i);
9640 pw.print(" * Restarting "); pw.println(r);
9641 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009642 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009643 needSep = true;
9644 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009645
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009646 if (mStoppingServices.size() > 0) {
9647 if (needSep) pw.println(" ");
9648 pw.println(" Stopping services:");
9649 for (int i=0; i<mStoppingServices.size(); i++) {
9650 ServiceRecord r = mStoppingServices.get(i);
9651 pw.print(" * Stopping "); pw.println(r);
9652 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009653 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009654 needSep = true;
9655 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009656
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009657 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009658 if (mServiceConnections.size() > 0) {
9659 if (needSep) pw.println(" ");
9660 pw.println(" Connection bindings to services:");
9661 Iterator<ConnectionRecord> it
9662 = mServiceConnections.values().iterator();
9663 while (it.hasNext()) {
9664 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009665 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009666 r.dump(pw, " ");
9667 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009668 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009669 }
9670 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009671
9672 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009673 }
9674
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009675 boolean dumpProvidersLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9676 int opti, boolean dumpAll) {
9677 boolean needSep = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009678
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009679 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009680 if (mProvidersByClass.size() > 0) {
9681 if (needSep) pw.println(" ");
9682 pw.println(" Published content providers (by class):");
9683 Iterator it = mProvidersByClass.entrySet().iterator();
9684 while (it.hasNext()) {
9685 Map.Entry e = (Map.Entry)it.next();
9686 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009687 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009688 r.dump(pw, " ");
9689 }
9690 needSep = true;
9691 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009692
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009693 if (mProvidersByName.size() > 0) {
9694 pw.println(" ");
9695 pw.println(" Authority to provider mappings:");
9696 Iterator it = mProvidersByName.entrySet().iterator();
9697 while (it.hasNext()) {
9698 Map.Entry e = (Map.Entry)it.next();
9699 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9700 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9701 pw.println(r);
9702 }
9703 needSep = true;
9704 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009705 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009706
9707 if (mLaunchingProviders.size() > 0) {
9708 if (needSep) pw.println(" ");
9709 pw.println(" Launching content providers:");
9710 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
9711 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9712 pw.println(mLaunchingProviders.get(i));
9713 }
9714 needSep = true;
9715 }
9716
9717 if (mGrantedUriPermissions.size() > 0) {
9718 pw.println();
9719 pw.println("Granted Uri Permissions:");
9720 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9721 int uid = mGrantedUriPermissions.keyAt(i);
9722 HashMap<Uri, UriPermission> perms
9723 = mGrantedUriPermissions.valueAt(i);
9724 pw.print(" * UID "); pw.print(uid);
9725 pw.println(" holds:");
9726 for (UriPermission perm : perms.values()) {
9727 pw.print(" "); pw.println(perm);
9728 perm.dump(pw, " ");
9729 }
9730 }
9731 needSep = true;
9732 }
9733
9734 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009735 }
9736
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009737 boolean dumpPendingIntentsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9738 int opti, boolean dumpAll) {
9739 boolean needSep = false;
9740
9741 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009742 if (this.mIntentSenderRecords.size() > 0) {
9743 Iterator<WeakReference<PendingIntentRecord>> it
9744 = mIntentSenderRecords.values().iterator();
9745 while (it.hasNext()) {
9746 WeakReference<PendingIntentRecord> ref = it.next();
9747 PendingIntentRecord rec = ref != null ? ref.get(): null;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009748 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009749 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009750 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009751 rec.dump(pw, " ");
9752 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009753 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009754 }
9755 }
9756 }
9757 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009758
9759 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009760 }
9761
9762 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009763 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009764 TaskRecord lastTask = null;
9765 for (int i=list.size()-1; i>=0; i--) {
9766 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009767 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009768 if (lastTask != r.task) {
9769 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009770 pw.print(prefix);
9771 pw.print(full ? "* " : " ");
9772 pw.println(lastTask);
9773 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009774 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009775 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009776 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009777 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9778 pw.print(" #"); pw.print(i); pw.print(": ");
9779 pw.println(r);
9780 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009781 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009782 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009783 }
9784 }
9785
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009786 private static String buildOomTag(String prefix, String space, int val, int base) {
9787 if (val == base) {
9788 if (space == null) return prefix;
9789 return prefix + " ";
9790 }
9791 return prefix + "+" + Integer.toString(val-base);
9792 }
9793
9794 private static final int dumpProcessList(PrintWriter pw,
9795 ActivityManagerService service, List list,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009796 String prefix, String normalLabel, String persistentLabel,
9797 boolean inclOomAdj) {
9798 int numPers = 0;
9799 for (int i=list.size()-1; i>=0; i--) {
9800 ProcessRecord r = (ProcessRecord)list.get(i);
9801 if (false) {
9802 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9803 + " #" + i + ":");
9804 r.dump(pw, prefix + " ");
9805 } else if (inclOomAdj) {
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009806 String oomAdj;
9807 if (r.setAdj >= EMPTY_APP_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009808 oomAdj = buildOomTag("empty", null, r.setAdj, EMPTY_APP_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009809 } else if (r.setAdj >= HIDDEN_APP_MIN_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009810 oomAdj = buildOomTag("bak", " ", r.setAdj, HIDDEN_APP_MIN_ADJ);
9811 } else if (r.setAdj >= HOME_APP_ADJ) {
9812 oomAdj = buildOomTag("home ", null, r.setAdj, HOME_APP_ADJ);
9813 } else if (r.setAdj >= SECONDARY_SERVER_ADJ) {
9814 oomAdj = buildOomTag("svc", " ", r.setAdj, SECONDARY_SERVER_ADJ);
9815 } else if (r.setAdj >= BACKUP_APP_ADJ) {
9816 oomAdj = buildOomTag("bckup", null, r.setAdj, BACKUP_APP_ADJ);
9817 } else if (r.setAdj >= VISIBLE_APP_ADJ) {
9818 oomAdj = buildOomTag("vis ", null, r.setAdj, VISIBLE_APP_ADJ);
9819 } else if (r.setAdj >= FOREGROUND_APP_ADJ) {
9820 oomAdj = buildOomTag("fore ", null, r.setAdj, FOREGROUND_APP_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009821 } else if (r.setAdj >= CORE_SERVER_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009822 oomAdj = buildOomTag("core ", null, r.setAdj, CORE_SERVER_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009823 } else if (r.setAdj >= SYSTEM_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009824 oomAdj = buildOomTag("sys ", null, r.setAdj, SYSTEM_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009825 } else {
9826 oomAdj = Integer.toString(r.setAdj);
9827 }
9828 String schedGroup;
9829 switch (r.setSchedGroup) {
9830 case Process.THREAD_GROUP_BG_NONINTERACTIVE:
9831 schedGroup = "B";
9832 break;
9833 case Process.THREAD_GROUP_DEFAULT:
9834 schedGroup = "F";
9835 break;
9836 default:
9837 schedGroup = Integer.toString(r.setSchedGroup);
9838 break;
9839 }
9840 pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009841 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009842 i, oomAdj, schedGroup, r.toShortString(), r.adjType));
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009843 if (r.adjSource != null || r.adjTarget != null) {
9844 pw.println(prefix + " " + r.adjTarget
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009845 + "<=" + r.adjSource);
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009846 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009847 } else {
9848 pw.println(String.format("%s%s #%2d: %s",
9849 prefix, (r.persistent ? persistentLabel : normalLabel),
9850 i, r.toString()));
9851 }
9852 if (r.persistent) {
9853 numPers++;
9854 }
9855 }
9856 return numPers;
9857 }
9858
9859 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9860 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009861 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009862 long uptime = SystemClock.uptimeMillis();
9863 long realtime = SystemClock.elapsedRealtime();
9864
9865 if (isCheckinRequest) {
9866 // short checkin version
9867 pw.println(uptime + "," + realtime);
9868 pw.flush();
9869 } else {
9870 pw.println("Applications Memory Usage (kB):");
9871 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9872 }
9873 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9874 ProcessRecord r = (ProcessRecord)list.get(i);
9875 if (r.thread != null) {
9876 if (!isCheckinRequest) {
9877 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9878 pw.flush();
9879 }
9880 try {
9881 r.thread.asBinder().dump(fd, args);
9882 } catch (RemoteException e) {
9883 if (!isCheckinRequest) {
9884 pw.println("Got RemoteException!");
9885 pw.flush();
9886 }
9887 }
9888 }
9889 }
9890 }
9891
9892 /**
9893 * Searches array of arguments for the specified string
9894 * @param args array of argument strings
9895 * @param value value to search for
9896 * @return true if the value is contained in the array
9897 */
9898 private static boolean scanArgs(String[] args, String value) {
9899 if (args != null) {
9900 for (String arg : args) {
9901 if (value.equals(arg)) {
9902 return true;
9903 }
9904 }
9905 }
9906 return false;
9907 }
9908
Dianne Hackborn75b03852009-06-12 15:43:26 -07009909 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009910 int count = mHistory.size();
9911
9912 // convert the token to an entry in the history.
9913 HistoryRecord r = null;
9914 int index = -1;
9915 for (int i=count-1; i>=0; i--) {
9916 Object o = mHistory.get(i);
9917 if (o == token) {
9918 r = (HistoryRecord)o;
9919 index = i;
9920 break;
9921 }
9922 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009923
9924 return index;
9925 }
9926
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009927 private final void killServicesLocked(ProcessRecord app,
9928 boolean allowRestart) {
9929 // Report disconnected services.
9930 if (false) {
9931 // XXX we are letting the client link to the service for
9932 // death notifications.
9933 if (app.services.size() > 0) {
9934 Iterator it = app.services.iterator();
9935 while (it.hasNext()) {
9936 ServiceRecord r = (ServiceRecord)it.next();
9937 if (r.connections.size() > 0) {
9938 Iterator<ConnectionRecord> jt
9939 = r.connections.values().iterator();
9940 while (jt.hasNext()) {
9941 ConnectionRecord c = jt.next();
9942 if (c.binding.client != app) {
9943 try {
9944 //c.conn.connected(r.className, null);
9945 } catch (Exception e) {
9946 // todo: this should be asynchronous!
9947 Log.w(TAG, "Exception thrown disconnected servce "
9948 + r.shortName
9949 + " from app " + app.processName, e);
9950 }
9951 }
9952 }
9953 }
9954 }
9955 }
9956 }
9957
9958 // Clean up any connections this application has to other services.
9959 if (app.connections.size() > 0) {
9960 Iterator<ConnectionRecord> it = app.connections.iterator();
9961 while (it.hasNext()) {
9962 ConnectionRecord r = it.next();
9963 removeConnectionLocked(r, app, null);
9964 }
9965 }
9966 app.connections.clear();
9967
9968 if (app.services.size() != 0) {
9969 // Any services running in the application need to be placed
9970 // back in the pending list.
9971 Iterator it = app.services.iterator();
9972 while (it.hasNext()) {
9973 ServiceRecord sr = (ServiceRecord)it.next();
9974 synchronized (sr.stats.getBatteryStats()) {
9975 sr.stats.stopLaunchedLocked();
9976 }
9977 sr.app = null;
9978 sr.executeNesting = 0;
9979 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009980
9981 boolean hasClients = sr.bindings.size() > 0;
9982 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009983 Iterator<IntentBindRecord> bindings
9984 = sr.bindings.values().iterator();
9985 while (bindings.hasNext()) {
9986 IntentBindRecord b = bindings.next();
9987 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9988 + ": shouldUnbind=" + b.hasBound);
9989 b.binder = null;
9990 b.requested = b.received = b.hasBound = false;
9991 }
9992 }
9993
9994 if (sr.crashCount >= 2) {
9995 Log.w(TAG, "Service crashed " + sr.crashCount
9996 + " times, stopping: " + sr);
Doug Zongker2bec3d42009-12-04 12:52:44 -08009997 EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009998 sr.crashCount, sr.shortName, app.pid);
9999 bringDownServiceLocked(sr, true);
10000 } else if (!allowRestart) {
10001 bringDownServiceLocked(sr, true);
10002 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010003 boolean canceled = scheduleServiceRestartLocked(sr, true);
10004
10005 // Should the service remain running? Note that in the
10006 // extreme case of so many attempts to deliver a command
10007 // that it failed, that we also will stop it here.
10008 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
10009 if (sr.pendingStarts.size() == 0) {
10010 sr.startRequested = false;
10011 if (!hasClients) {
10012 // Whoops, no reason to restart!
10013 bringDownServiceLocked(sr, true);
10014 }
10015 }
10016 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010017 }
10018 }
10019
10020 if (!allowRestart) {
10021 app.services.clear();
10022 }
10023 }
10024
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010025 // Make sure we have no more records on the stopping list.
10026 int i = mStoppingServices.size();
10027 while (i > 0) {
10028 i--;
10029 ServiceRecord sr = mStoppingServices.get(i);
10030 if (sr.app == app) {
10031 mStoppingServices.remove(i);
10032 }
10033 }
10034
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010035 app.executingServices.clear();
10036 }
10037
10038 private final void removeDyingProviderLocked(ProcessRecord proc,
10039 ContentProviderRecord cpr) {
10040 synchronized (cpr) {
10041 cpr.launchingApp = null;
10042 cpr.notifyAll();
10043 }
10044
10045 mProvidersByClass.remove(cpr.info.name);
10046 String names[] = cpr.info.authority.split(";");
10047 for (int j = 0; j < names.length; j++) {
10048 mProvidersByName.remove(names[j]);
10049 }
10050
10051 Iterator<ProcessRecord> cit = cpr.clients.iterator();
10052 while (cit.hasNext()) {
10053 ProcessRecord capp = cit.next();
10054 if (!capp.persistent && capp.thread != null
10055 && capp.pid != 0
10056 && capp.pid != MY_PID) {
10057 Log.i(TAG, "Killing app " + capp.processName
10058 + " (pid " + capp.pid
10059 + ") because provider " + cpr.info.name
10060 + " is in dying process " + proc.processName);
10061 Process.killProcess(capp.pid);
10062 }
10063 }
10064
10065 mLaunchingProviders.remove(cpr);
10066 }
10067
10068 /**
10069 * Main code for cleaning up a process when it has gone away. This is
10070 * called both as a result of the process dying, or directly when stopping
10071 * a process when running in single process mode.
10072 */
10073 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
10074 boolean restarting, int index) {
10075 if (index >= 0) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080010076 mLruProcesses.remove(index);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010077 }
10078
Dianne Hackborn36124872009-10-08 16:22:03 -070010079 mProcessesToGc.remove(app);
10080
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010081 // Dismiss any open dialogs.
10082 if (app.crashDialog != null) {
10083 app.crashDialog.dismiss();
10084 app.crashDialog = null;
10085 }
10086 if (app.anrDialog != null) {
10087 app.anrDialog.dismiss();
10088 app.anrDialog = null;
10089 }
10090 if (app.waitDialog != null) {
10091 app.waitDialog.dismiss();
10092 app.waitDialog = null;
10093 }
10094
10095 app.crashing = false;
10096 app.notResponding = false;
10097
10098 app.resetPackageList();
10099 app.thread = null;
10100 app.forcingToForeground = null;
10101 app.foregroundServices = false;
10102
10103 killServicesLocked(app, true);
10104
10105 boolean restart = false;
10106
10107 int NL = mLaunchingProviders.size();
10108
10109 // Remove published content providers.
10110 if (!app.pubProviders.isEmpty()) {
10111 Iterator it = app.pubProviders.values().iterator();
10112 while (it.hasNext()) {
10113 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
10114 cpr.provider = null;
10115 cpr.app = null;
10116
10117 // See if someone is waiting for this provider... in which
10118 // case we don't remove it, but just let it restart.
10119 int i = 0;
10120 if (!app.bad) {
10121 for (; i<NL; i++) {
10122 if (mLaunchingProviders.get(i) == cpr) {
10123 restart = true;
10124 break;
10125 }
10126 }
10127 } else {
10128 i = NL;
10129 }
10130
10131 if (i >= NL) {
10132 removeDyingProviderLocked(app, cpr);
10133 NL = mLaunchingProviders.size();
10134 }
10135 }
10136 app.pubProviders.clear();
10137 }
10138
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010139 // Take care of any launching providers waiting for this process.
10140 if (checkAppInLaunchingProvidersLocked(app, false)) {
10141 restart = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010142 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010143
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010144 // Unregister from connected content providers.
10145 if (!app.conProviders.isEmpty()) {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -070010146 Iterator it = app.conProviders.keySet().iterator();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010147 while (it.hasNext()) {
10148 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
10149 cpr.clients.remove(app);
10150 }
10151 app.conProviders.clear();
10152 }
10153
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010154 // At this point there may be remaining entries in mLaunchingProviders
10155 // where we were the only one waiting, so they are no longer of use.
10156 // Look for these and clean up if found.
10157 // XXX Commented out for now. Trying to figure out a way to reproduce
10158 // the actual situation to identify what is actually going on.
10159 if (false) {
10160 for (int i=0; i<NL; i++) {
10161 ContentProviderRecord cpr = (ContentProviderRecord)
10162 mLaunchingProviders.get(i);
10163 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
10164 synchronized (cpr) {
10165 cpr.launchingApp = null;
10166 cpr.notifyAll();
10167 }
10168 }
10169 }
10170 }
10171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010172 skipCurrentReceiverLocked(app);
10173
10174 // Unregister any receivers.
10175 if (app.receivers.size() > 0) {
10176 Iterator<ReceiverList> it = app.receivers.iterator();
10177 while (it.hasNext()) {
10178 removeReceiverLocked(it.next());
10179 }
10180 app.receivers.clear();
10181 }
10182
Christopher Tate181fafa2009-05-14 11:12:14 -070010183 // If the app is undergoing backup, tell the backup manager about it
10184 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
10185 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
10186 try {
10187 IBackupManager bm = IBackupManager.Stub.asInterface(
10188 ServiceManager.getService(Context.BACKUP_SERVICE));
10189 bm.agentDisconnected(app.info.packageName);
10190 } catch (RemoteException e) {
10191 // can't happen; backup manager is local
10192 }
10193 }
10194
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010195 // If the caller is restarting this app, then leave it in its
10196 // current lists and let the caller take care of it.
10197 if (restarting) {
10198 return;
10199 }
10200
10201 if (!app.persistent) {
10202 if (DEBUG_PROCESSES) Log.v(TAG,
10203 "Removing non-persistent process during cleanup: " + app);
10204 mProcessNames.remove(app.processName, app.info.uid);
10205 } else if (!app.removed) {
10206 // This app is persistent, so we need to keep its record around.
10207 // If it is not already on the pending app list, add it there
10208 // and start a new process for it.
10209 app.thread = null;
10210 app.forcingToForeground = null;
10211 app.foregroundServices = false;
10212 if (mPersistentStartingProcesses.indexOf(app) < 0) {
10213 mPersistentStartingProcesses.add(app);
10214 restart = true;
10215 }
10216 }
10217 mProcessesOnHold.remove(app);
10218
The Android Open Source Project4df24232009-03-05 14:34:35 -080010219 if (app == mHomeProcess) {
10220 mHomeProcess = null;
10221 }
10222
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010223 if (restart) {
10224 // We have components that still need to be running in the
10225 // process, so re-launch it.
10226 mProcessNames.put(app.processName, app.info.uid, app);
10227 startProcessLocked(app, "restart", app.processName);
10228 } else if (app.pid > 0 && app.pid != MY_PID) {
10229 // Goodbye!
10230 synchronized (mPidsSelfLocked) {
10231 mPidsSelfLocked.remove(app.pid);
10232 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
10233 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -070010234 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010235 }
10236 }
10237
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010238 boolean checkAppInLaunchingProvidersLocked(ProcessRecord app, boolean alwaysBad) {
10239 // Look through the content providers we are waiting to have launched,
10240 // and if any run in this process then either schedule a restart of
10241 // the process or kill the client waiting for it if this process has
10242 // gone bad.
10243 int NL = mLaunchingProviders.size();
10244 boolean restart = false;
10245 for (int i=0; i<NL; i++) {
10246 ContentProviderRecord cpr = (ContentProviderRecord)
10247 mLaunchingProviders.get(i);
10248 if (cpr.launchingApp == app) {
10249 if (!alwaysBad && !app.bad) {
10250 restart = true;
10251 } else {
10252 removeDyingProviderLocked(app, cpr);
10253 NL = mLaunchingProviders.size();
10254 }
10255 }
10256 }
10257 return restart;
10258 }
10259
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010260 // =========================================================
10261 // SERVICES
10262 // =========================================================
10263
10264 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
10265 ActivityManager.RunningServiceInfo info =
10266 new ActivityManager.RunningServiceInfo();
10267 info.service = r.name;
10268 if (r.app != null) {
10269 info.pid = r.app.pid;
10270 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010271 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010272 info.process = r.processName;
10273 info.foreground = r.isForeground;
10274 info.activeSince = r.createTime;
10275 info.started = r.startRequested;
10276 info.clientCount = r.connections.size();
10277 info.crashCount = r.crashCount;
10278 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010279 if (r.isForeground) {
10280 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
10281 }
10282 if (r.startRequested) {
10283 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
10284 }
10285 if (r.app != null && r.app.pid == Process.myPid()) {
10286 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
10287 }
10288 if (r.app != null && r.app.persistent) {
10289 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
10290 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010291 for (ConnectionRecord conn : r.connections.values()) {
10292 if (conn.clientLabel != 0) {
10293 info.clientPackage = conn.binding.client.info.packageName;
10294 info.clientLabel = conn.clientLabel;
10295 break;
10296 }
10297 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010298 return info;
10299 }
10300
10301 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
10302 int flags) {
10303 synchronized (this) {
10304 ArrayList<ActivityManager.RunningServiceInfo> res
10305 = new ArrayList<ActivityManager.RunningServiceInfo>();
10306
10307 if (mServices.size() > 0) {
10308 Iterator<ServiceRecord> it = mServices.values().iterator();
10309 while (it.hasNext() && res.size() < maxNum) {
10310 res.add(makeRunningServiceInfoLocked(it.next()));
10311 }
10312 }
10313
10314 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
10315 ServiceRecord r = mRestartingServices.get(i);
10316 ActivityManager.RunningServiceInfo info =
10317 makeRunningServiceInfoLocked(r);
10318 info.restarting = r.nextRestartTime;
10319 res.add(info);
10320 }
10321
10322 return res;
10323 }
10324 }
10325
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010326 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
10327 synchronized (this) {
10328 ServiceRecord r = mServices.get(name);
10329 if (r != null) {
10330 for (ConnectionRecord conn : r.connections.values()) {
10331 if (conn.clientIntent != null) {
10332 return conn.clientIntent;
10333 }
10334 }
10335 }
10336 }
10337 return null;
10338 }
10339
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010340 private final ServiceRecord findServiceLocked(ComponentName name,
10341 IBinder token) {
10342 ServiceRecord r = mServices.get(name);
10343 return r == token ? r : null;
10344 }
10345
10346 private final class ServiceLookupResult {
10347 final ServiceRecord record;
10348 final String permission;
10349
10350 ServiceLookupResult(ServiceRecord _record, String _permission) {
10351 record = _record;
10352 permission = _permission;
10353 }
10354 };
10355
10356 private ServiceLookupResult findServiceLocked(Intent service,
10357 String resolvedType) {
10358 ServiceRecord r = null;
10359 if (service.getComponent() != null) {
10360 r = mServices.get(service.getComponent());
10361 }
10362 if (r == null) {
10363 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10364 r = mServicesByIntent.get(filter);
10365 }
10366
10367 if (r == null) {
10368 try {
10369 ResolveInfo rInfo =
10370 ActivityThread.getPackageManager().resolveService(
10371 service, resolvedType, 0);
10372 ServiceInfo sInfo =
10373 rInfo != null ? rInfo.serviceInfo : null;
10374 if (sInfo == null) {
10375 return null;
10376 }
10377
10378 ComponentName name = new ComponentName(
10379 sInfo.applicationInfo.packageName, sInfo.name);
10380 r = mServices.get(name);
10381 } catch (RemoteException ex) {
10382 // pm is in same process, this will never happen.
10383 }
10384 }
10385 if (r != null) {
10386 int callingPid = Binder.getCallingPid();
10387 int callingUid = Binder.getCallingUid();
10388 if (checkComponentPermission(r.permission,
10389 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10390 != PackageManager.PERMISSION_GRANTED) {
10391 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10392 + " from pid=" + callingPid
10393 + ", uid=" + callingUid
10394 + " requires " + r.permission);
10395 return new ServiceLookupResult(null, r.permission);
10396 }
10397 return new ServiceLookupResult(r, null);
10398 }
10399 return null;
10400 }
10401
10402 private class ServiceRestarter implements Runnable {
10403 private ServiceRecord mService;
10404
10405 void setService(ServiceRecord service) {
10406 mService = service;
10407 }
10408
10409 public void run() {
10410 synchronized(ActivityManagerService.this) {
10411 performServiceRestartLocked(mService);
10412 }
10413 }
10414 }
10415
10416 private ServiceLookupResult retrieveServiceLocked(Intent service,
10417 String resolvedType, int callingPid, int callingUid) {
10418 ServiceRecord r = null;
10419 if (service.getComponent() != null) {
10420 r = mServices.get(service.getComponent());
10421 }
10422 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10423 r = mServicesByIntent.get(filter);
10424 if (r == null) {
10425 try {
10426 ResolveInfo rInfo =
10427 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010428 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010429 ServiceInfo sInfo =
10430 rInfo != null ? rInfo.serviceInfo : null;
10431 if (sInfo == null) {
10432 Log.w(TAG, "Unable to start service " + service +
10433 ": not found");
10434 return null;
10435 }
10436
10437 ComponentName name = new ComponentName(
10438 sInfo.applicationInfo.packageName, sInfo.name);
10439 r = mServices.get(name);
10440 if (r == null) {
10441 filter = new Intent.FilterComparison(service.cloneFilter());
10442 ServiceRestarter res = new ServiceRestarter();
10443 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10444 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10445 synchronized (stats) {
10446 ss = stats.getServiceStatsLocked(
10447 sInfo.applicationInfo.uid, sInfo.packageName,
10448 sInfo.name);
10449 }
10450 r = new ServiceRecord(ss, name, filter, sInfo, res);
10451 res.setService(r);
10452 mServices.put(name, r);
10453 mServicesByIntent.put(filter, r);
10454
10455 // Make sure this component isn't in the pending list.
10456 int N = mPendingServices.size();
10457 for (int i=0; i<N; i++) {
10458 ServiceRecord pr = mPendingServices.get(i);
10459 if (pr.name.equals(name)) {
10460 mPendingServices.remove(i);
10461 i--;
10462 N--;
10463 }
10464 }
10465 }
10466 } catch (RemoteException ex) {
10467 // pm is in same process, this will never happen.
10468 }
10469 }
10470 if (r != null) {
10471 if (checkComponentPermission(r.permission,
10472 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10473 != PackageManager.PERMISSION_GRANTED) {
10474 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10475 + " from pid=" + Binder.getCallingPid()
10476 + ", uid=" + Binder.getCallingUid()
10477 + " requires " + r.permission);
10478 return new ServiceLookupResult(null, r.permission);
10479 }
10480 return new ServiceLookupResult(r, null);
10481 }
10482 return null;
10483 }
10484
10485 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10486 long now = SystemClock.uptimeMillis();
10487 if (r.executeNesting == 0 && r.app != null) {
10488 if (r.app.executingServices.size() == 0) {
10489 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10490 msg.obj = r.app;
10491 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10492 }
10493 r.app.executingServices.add(r);
10494 }
10495 r.executeNesting++;
10496 r.executingStart = now;
10497 }
10498
10499 private final void sendServiceArgsLocked(ServiceRecord r,
10500 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010501 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010502 if (N == 0) {
10503 return;
10504 }
10505
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010506 int i = 0;
10507 while (i < N) {
10508 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010509 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010510 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010511 + r.name + " " + r.intent + " args=" + si.intent);
Dianne Hackbornfed534e2009-09-23 00:42:12 -070010512 if (si.intent == null && N > 1) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010513 // If somehow we got a dummy start at the front, then
10514 // just drop it here.
10515 i++;
10516 continue;
10517 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010518 bumpServiceExecutingLocked(r);
10519 if (!oomAdjusted) {
10520 oomAdjusted = true;
10521 updateOomAdjLocked(r.app);
10522 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010523 int flags = 0;
10524 if (si.deliveryCount > 0) {
10525 flags |= Service.START_FLAG_RETRY;
10526 }
10527 if (si.doneExecutingCount > 0) {
10528 flags |= Service.START_FLAG_REDELIVERY;
10529 }
10530 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10531 si.deliveredTime = SystemClock.uptimeMillis();
10532 r.deliveredStarts.add(si);
10533 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010534 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010535 } catch (RemoteException e) {
10536 // Remote process gone... we'll let the normal cleanup take
10537 // care of this.
10538 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010539 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010540 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010541 break;
10542 }
10543 }
10544 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010545 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010546 } else {
10547 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010548 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010549 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010550 }
10551 }
10552 }
10553
10554 private final boolean requestServiceBindingLocked(ServiceRecord r,
10555 IntentBindRecord i, boolean rebind) {
10556 if (r.app == null || r.app.thread == null) {
10557 // If service is not currently running, can't yet bind.
10558 return false;
10559 }
10560 if ((!i.requested || rebind) && i.apps.size() > 0) {
10561 try {
10562 bumpServiceExecutingLocked(r);
10563 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10564 + ": shouldUnbind=" + i.hasBound);
10565 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10566 if (!rebind) {
10567 i.requested = true;
10568 }
10569 i.hasBound = true;
10570 i.doRebind = false;
10571 } catch (RemoteException e) {
10572 return false;
10573 }
10574 }
10575 return true;
10576 }
10577
10578 private final void requestServiceBindingsLocked(ServiceRecord r) {
10579 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10580 while (bindings.hasNext()) {
10581 IntentBindRecord i = bindings.next();
10582 if (!requestServiceBindingLocked(r, i, false)) {
10583 break;
10584 }
10585 }
10586 }
10587
10588 private final void realStartServiceLocked(ServiceRecord r,
10589 ProcessRecord app) throws RemoteException {
10590 if (app.thread == null) {
10591 throw new RemoteException();
10592 }
10593
10594 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010595 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010596
10597 app.services.add(r);
10598 bumpServiceExecutingLocked(r);
Dianne Hackborndd71fc82009-12-16 19:24:32 -080010599 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010600
10601 boolean created = false;
10602 try {
10603 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10604 + r.name + " " + r.intent);
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010605 mStringBuilder.setLength(0);
10606 r.intent.getIntent().toShortString(mStringBuilder, false, true);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010607 EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010608 System.identityHashCode(r), r.shortName,
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010609 mStringBuilder.toString(), r.app.pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010610 synchronized (r.stats.getBatteryStats()) {
10611 r.stats.startLaunchedLocked();
10612 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010613 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010614 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010615 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010616 created = true;
10617 } finally {
10618 if (!created) {
10619 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010620 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010621 }
10622 }
10623
10624 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010625
10626 // If the service is in the started state, and there are no
10627 // pending arguments, then fake up one so its onStartCommand() will
10628 // be called.
10629 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10630 r.lastStartId++;
10631 if (r.lastStartId < 1) {
10632 r.lastStartId = 1;
10633 }
10634 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10635 }
10636
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010637 sendServiceArgsLocked(r, true);
10638 }
10639
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010640 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10641 boolean allowCancel) {
10642 boolean canceled = false;
10643
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010644 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010645 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010646 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010647
10648 // Any delivered but not yet finished starts should be put back
10649 // on the pending list.
10650 final int N = r.deliveredStarts.size();
10651 if (N > 0) {
10652 for (int i=N-1; i>=0; i--) {
10653 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10654 if (si.intent == null) {
10655 // We'll generate this again if needed.
10656 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10657 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10658 r.pendingStarts.add(0, si);
10659 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10660 dur *= 2;
10661 if (minDuration < dur) minDuration = dur;
10662 if (resetTime < dur) resetTime = dur;
10663 } else {
10664 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10665 + r.name);
10666 canceled = true;
10667 }
10668 }
10669 r.deliveredStarts.clear();
10670 }
10671
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010672 r.totalRestartCount++;
10673 if (r.restartDelay == 0) {
10674 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010675 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010676 } else {
10677 // If it has been a "reasonably long time" since the service
10678 // was started, then reset our restart duration back to
10679 // the beginning, so we don't infinitely increase the duration
10680 // on a service that just occasionally gets killed (which is
10681 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010682 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010683 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010684 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010685 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010686 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010687 if (r.restartDelay < minDuration) {
10688 r.restartDelay = minDuration;
10689 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010690 }
10691 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010692
10693 r.nextRestartTime = now + r.restartDelay;
10694
10695 // Make sure that we don't end up restarting a bunch of services
10696 // all at the same time.
10697 boolean repeat;
10698 do {
10699 repeat = false;
10700 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10701 ServiceRecord r2 = mRestartingServices.get(i);
10702 if (r2 != r && r.nextRestartTime
10703 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10704 && r.nextRestartTime
10705 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10706 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10707 r.restartDelay = r.nextRestartTime - now;
10708 repeat = true;
10709 break;
10710 }
10711 }
10712 } while (repeat);
10713
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010714 if (!mRestartingServices.contains(r)) {
10715 mRestartingServices.add(r);
10716 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010717
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010718 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010719
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010720 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010721 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010722 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10723 Log.w(TAG, "Scheduling restart of crashed service "
10724 + r.shortName + " in " + r.restartDelay + "ms");
Doug Zongker2bec3d42009-12-04 12:52:44 -080010725 EventLog.writeEvent(EventLogTags.AM_SCHEDULE_SERVICE_RESTART,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010726 r.shortName, r.restartDelay);
10727
10728 Message msg = Message.obtain();
10729 msg.what = SERVICE_ERROR_MSG;
10730 msg.obj = r;
10731 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010732
10733 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010734 }
10735
10736 final void performServiceRestartLocked(ServiceRecord r) {
10737 if (!mRestartingServices.contains(r)) {
10738 return;
10739 }
10740 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10741 }
10742
10743 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10744 if (r.restartDelay == 0) {
10745 return false;
10746 }
10747 r.resetRestartCounter();
10748 mRestartingServices.remove(r);
10749 mHandler.removeCallbacks(r.restarter);
10750 return true;
10751 }
10752
10753 private final boolean bringUpServiceLocked(ServiceRecord r,
10754 int intentFlags, boolean whileRestarting) {
10755 //Log.i(TAG, "Bring up service:");
10756 //r.dump(" ");
10757
Dianne Hackborn36124872009-10-08 16:22:03 -070010758 if (r.app != null && r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010759 sendServiceArgsLocked(r, false);
10760 return true;
10761 }
10762
10763 if (!whileRestarting && r.restartDelay > 0) {
10764 // If waiting for a restart, then do nothing.
10765 return true;
10766 }
10767
10768 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10769 + " " + r.intent);
10770
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010771 // We are now bringing the service up, so no longer in the
10772 // restarting state.
10773 mRestartingServices.remove(r);
10774
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010775 final String appName = r.processName;
10776 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10777 if (app != null && app.thread != null) {
10778 try {
10779 realStartServiceLocked(r, app);
10780 return true;
10781 } catch (RemoteException e) {
10782 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10783 }
10784
10785 // If a dead object exception was thrown -- fall through to
10786 // restart the application.
10787 }
10788
Dianne Hackborn36124872009-10-08 16:22:03 -070010789 // Not running -- get it started, and enqueue this service record
10790 // to be executed when the app comes up.
10791 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
10792 "service", r.name, false) == null) {
10793 Log.w(TAG, "Unable to launch app "
10794 + r.appInfo.packageName + "/"
10795 + r.appInfo.uid + " for service "
10796 + r.intent.getIntent() + ": process is bad");
10797 bringDownServiceLocked(r, true);
10798 return false;
10799 }
10800
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010801 if (!mPendingServices.contains(r)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010802 mPendingServices.add(r);
10803 }
Dianne Hackborn36124872009-10-08 16:22:03 -070010804
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010805 return true;
10806 }
10807
10808 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10809 //Log.i(TAG, "Bring down service:");
10810 //r.dump(" ");
10811
10812 // Does it still need to run?
10813 if (!force && r.startRequested) {
10814 return;
10815 }
10816 if (r.connections.size() > 0) {
10817 if (!force) {
10818 // XXX should probably keep a count of the number of auto-create
10819 // connections directly in the service.
10820 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10821 while (it.hasNext()) {
10822 ConnectionRecord cr = it.next();
10823 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10824 return;
10825 }
10826 }
10827 }
10828
10829 // Report to all of the connections that the service is no longer
10830 // available.
10831 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10832 while (it.hasNext()) {
10833 ConnectionRecord c = it.next();
10834 try {
10835 // todo: shouldn't be a synchronous call!
10836 c.conn.connected(r.name, null);
10837 } catch (Exception e) {
10838 Log.w(TAG, "Failure disconnecting service " + r.name +
10839 " to connection " + c.conn.asBinder() +
10840 " (in " + c.binding.client.processName + ")", e);
10841 }
10842 }
10843 }
10844
10845 // Tell the service that it has been unbound.
10846 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10847 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10848 while (it.hasNext()) {
10849 IntentBindRecord ibr = it.next();
10850 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10851 + ": hasBound=" + ibr.hasBound);
10852 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10853 try {
10854 bumpServiceExecutingLocked(r);
10855 updateOomAdjLocked(r.app);
10856 ibr.hasBound = false;
10857 r.app.thread.scheduleUnbindService(r,
10858 ibr.intent.getIntent());
10859 } catch (Exception e) {
10860 Log.w(TAG, "Exception when unbinding service "
10861 + r.shortName, e);
10862 serviceDoneExecutingLocked(r, true);
10863 }
10864 }
10865 }
10866 }
10867
10868 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10869 + " " + r.intent);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010870 EventLog.writeEvent(EventLogTags.AM_DESTROY_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010871 System.identityHashCode(r), r.shortName,
10872 (r.app != null) ? r.app.pid : -1);
10873
10874 mServices.remove(r.name);
10875 mServicesByIntent.remove(r.intent);
10876 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10877 r.totalRestartCount = 0;
10878 unscheduleServiceRestartLocked(r);
10879
10880 // Also make sure it is not on the pending list.
10881 int N = mPendingServices.size();
10882 for (int i=0; i<N; i++) {
10883 if (mPendingServices.get(i) == r) {
10884 mPendingServices.remove(i);
10885 if (DEBUG_SERVICE) Log.v(
10886 TAG, "Removed pending service: " + r.shortName);
10887 i--;
10888 N--;
10889 }
10890 }
10891
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010892 r.cancelNotification();
10893 r.isForeground = false;
10894 r.foregroundId = 0;
10895 r.foregroundNoti = null;
10896
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010897 // Clear start entries.
10898 r.deliveredStarts.clear();
10899 r.pendingStarts.clear();
10900
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010901 if (r.app != null) {
10902 synchronized (r.stats.getBatteryStats()) {
10903 r.stats.stopLaunchedLocked();
10904 }
10905 r.app.services.remove(r);
10906 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010907 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010908 if (DEBUG_SERVICE) Log.v(TAG,
10909 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010910 bumpServiceExecutingLocked(r);
10911 mStoppingServices.add(r);
10912 updateOomAdjLocked(r.app);
10913 r.app.thread.scheduleStopService(r);
10914 } catch (Exception e) {
10915 Log.w(TAG, "Exception when stopping service "
10916 + r.shortName, e);
10917 serviceDoneExecutingLocked(r, true);
10918 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010919 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010920 } else {
10921 if (DEBUG_SERVICE) Log.v(
10922 TAG, "Removed service that has no process: " + r.shortName);
10923 }
10924 } else {
10925 if (DEBUG_SERVICE) Log.v(
10926 TAG, "Removed service that is not running: " + r.shortName);
10927 }
10928 }
10929
10930 ComponentName startServiceLocked(IApplicationThread caller,
10931 Intent service, String resolvedType,
10932 int callingPid, int callingUid) {
10933 synchronized(this) {
10934 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10935 + " type=" + resolvedType + " args=" + service.getExtras());
10936
10937 if (caller != null) {
10938 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10939 if (callerApp == null) {
10940 throw new SecurityException(
10941 "Unable to find app for caller " + caller
10942 + " (pid=" + Binder.getCallingPid()
10943 + ") when starting service " + service);
10944 }
10945 }
10946
10947 ServiceLookupResult res =
10948 retrieveServiceLocked(service, resolvedType,
10949 callingPid, callingUid);
10950 if (res == null) {
10951 return null;
10952 }
10953 if (res.record == null) {
10954 return new ComponentName("!", res.permission != null
10955 ? res.permission : "private to package");
10956 }
10957 ServiceRecord r = res.record;
10958 if (unscheduleServiceRestartLocked(r)) {
10959 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10960 + r.shortName);
10961 }
10962 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010963 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010964 r.lastStartId++;
10965 if (r.lastStartId < 1) {
10966 r.lastStartId = 1;
10967 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010968 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010969 r.lastActivity = SystemClock.uptimeMillis();
10970 synchronized (r.stats.getBatteryStats()) {
10971 r.stats.startRunningLocked();
10972 }
10973 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10974 return new ComponentName("!", "Service process is bad");
10975 }
10976 return r.name;
10977 }
10978 }
10979
10980 public ComponentName startService(IApplicationThread caller, Intent service,
10981 String resolvedType) {
10982 // Refuse possible leaked file descriptors
10983 if (service != null && service.hasFileDescriptors() == true) {
10984 throw new IllegalArgumentException("File descriptors passed in Intent");
10985 }
10986
10987 synchronized(this) {
10988 final int callingPid = Binder.getCallingPid();
10989 final int callingUid = Binder.getCallingUid();
10990 final long origId = Binder.clearCallingIdentity();
10991 ComponentName res = startServiceLocked(caller, service,
10992 resolvedType, callingPid, callingUid);
10993 Binder.restoreCallingIdentity(origId);
10994 return res;
10995 }
10996 }
10997
10998 ComponentName startServiceInPackage(int uid,
10999 Intent service, String resolvedType) {
11000 synchronized(this) {
11001 final long origId = Binder.clearCallingIdentity();
11002 ComponentName res = startServiceLocked(null, service,
11003 resolvedType, -1, uid);
11004 Binder.restoreCallingIdentity(origId);
11005 return res;
11006 }
11007 }
11008
11009 public int stopService(IApplicationThread caller, Intent service,
11010 String resolvedType) {
11011 // Refuse possible leaked file descriptors
11012 if (service != null && service.hasFileDescriptors() == true) {
11013 throw new IllegalArgumentException("File descriptors passed in Intent");
11014 }
11015
11016 synchronized(this) {
11017 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
11018 + " type=" + resolvedType);
11019
11020 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11021 if (caller != null && callerApp == null) {
11022 throw new SecurityException(
11023 "Unable to find app for caller " + caller
11024 + " (pid=" + Binder.getCallingPid()
11025 + ") when stopping service " + service);
11026 }
11027
11028 // If this service is active, make sure it is stopped.
11029 ServiceLookupResult r = findServiceLocked(service, resolvedType);
11030 if (r != null) {
11031 if (r.record != null) {
11032 synchronized (r.record.stats.getBatteryStats()) {
11033 r.record.stats.stopRunningLocked();
11034 }
11035 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011036 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011037 final long origId = Binder.clearCallingIdentity();
11038 bringDownServiceLocked(r.record, false);
11039 Binder.restoreCallingIdentity(origId);
11040 return 1;
11041 }
11042 return -1;
11043 }
11044 }
11045
11046 return 0;
11047 }
11048
11049 public IBinder peekService(Intent service, 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 IBinder ret = null;
11056
11057 synchronized(this) {
11058 ServiceLookupResult r = findServiceLocked(service, resolvedType);
11059
11060 if (r != null) {
11061 // r.record is null if findServiceLocked() failed the caller permission check
11062 if (r.record == null) {
11063 throw new SecurityException(
11064 "Permission Denial: Accessing service " + r.record.name
11065 + " from pid=" + Binder.getCallingPid()
11066 + ", uid=" + Binder.getCallingUid()
11067 + " requires " + r.permission);
11068 }
11069 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
11070 if (ib != null) {
11071 ret = ib.binder;
11072 }
11073 }
11074 }
11075
11076 return ret;
11077 }
11078
11079 public boolean stopServiceToken(ComponentName className, IBinder token,
11080 int startId) {
11081 synchronized(this) {
11082 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
11083 + " " + token + " startId=" + startId);
11084 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011085 if (r != null) {
11086 if (startId >= 0) {
11087 // Asked to only stop if done with all work. Note that
11088 // to avoid leaks, we will take this as dropping all
11089 // start items up to and including this one.
11090 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11091 if (si != null) {
11092 while (r.deliveredStarts.size() > 0) {
11093 if (r.deliveredStarts.remove(0) == si) {
11094 break;
11095 }
11096 }
11097 }
11098
11099 if (r.lastStartId != startId) {
11100 return false;
11101 }
11102
11103 if (r.deliveredStarts.size() > 0) {
11104 Log.w(TAG, "stopServiceToken startId " + startId
11105 + " is last, but have " + r.deliveredStarts.size()
11106 + " remaining args");
11107 }
11108 }
11109
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011110 synchronized (r.stats.getBatteryStats()) {
11111 r.stats.stopRunningLocked();
11112 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011113 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011114 }
11115 final long origId = Binder.clearCallingIdentity();
11116 bringDownServiceLocked(r, false);
11117 Binder.restoreCallingIdentity(origId);
11118 return true;
11119 }
11120 }
11121 return false;
11122 }
11123
11124 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011125 int id, Notification notification, boolean removeNotification) {
11126 final long origId = Binder.clearCallingIdentity();
11127 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011128 synchronized(this) {
11129 ServiceRecord r = findServiceLocked(className, token);
11130 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011131 if (id != 0) {
11132 if (notification == null) {
11133 throw new IllegalArgumentException("null notification");
11134 }
11135 if (r.foregroundId != id) {
11136 r.cancelNotification();
11137 r.foregroundId = id;
11138 }
11139 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
11140 r.foregroundNoti = notification;
11141 r.isForeground = true;
11142 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011143 if (r.app != null) {
11144 updateServiceForegroundLocked(r.app, true);
11145 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011146 } else {
11147 if (r.isForeground) {
11148 r.isForeground = false;
11149 if (r.app != null) {
11150 updateServiceForegroundLocked(r.app, true);
11151 }
11152 }
11153 if (removeNotification) {
11154 r.cancelNotification();
11155 r.foregroundId = 0;
11156 r.foregroundNoti = null;
11157 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011158 }
11159 }
11160 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011161 } finally {
11162 Binder.restoreCallingIdentity(origId);
11163 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011164 }
11165
11166 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
11167 boolean anyForeground = false;
11168 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
11169 if (sr.isForeground) {
11170 anyForeground = true;
11171 break;
11172 }
11173 }
11174 if (anyForeground != proc.foregroundServices) {
11175 proc.foregroundServices = anyForeground;
11176 if (oomAdj) {
11177 updateOomAdjLocked();
11178 }
11179 }
11180 }
11181
11182 public int bindService(IApplicationThread caller, IBinder token,
11183 Intent service, String resolvedType,
11184 IServiceConnection connection, int flags) {
11185 // Refuse possible leaked file descriptors
11186 if (service != null && service.hasFileDescriptors() == true) {
11187 throw new IllegalArgumentException("File descriptors passed in Intent");
11188 }
11189
11190 synchronized(this) {
11191 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
11192 + " type=" + resolvedType + " conn=" + connection.asBinder()
11193 + " flags=0x" + Integer.toHexString(flags));
11194 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11195 if (callerApp == null) {
11196 throw new SecurityException(
11197 "Unable to find app for caller " + caller
11198 + " (pid=" + Binder.getCallingPid()
11199 + ") when binding service " + service);
11200 }
11201
11202 HistoryRecord activity = null;
11203 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070011204 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011205 if (aindex < 0) {
11206 Log.w(TAG, "Binding with unknown activity: " + token);
11207 return 0;
11208 }
11209 activity = (HistoryRecord)mHistory.get(aindex);
11210 }
11211
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011212 int clientLabel = 0;
11213 PendingIntent clientIntent = null;
11214
11215 if (callerApp.info.uid == Process.SYSTEM_UID) {
11216 // Hacky kind of thing -- allow system stuff to tell us
11217 // what they are, so we can report this elsewhere for
11218 // others to know why certain services are running.
11219 try {
11220 clientIntent = (PendingIntent)service.getParcelableExtra(
11221 Intent.EXTRA_CLIENT_INTENT);
11222 } catch (RuntimeException e) {
11223 }
11224 if (clientIntent != null) {
11225 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
11226 if (clientLabel != 0) {
11227 // There are no useful extras in the intent, trash them.
11228 // System code calling with this stuff just needs to know
11229 // this will happen.
11230 service = service.cloneFilter();
11231 }
11232 }
11233 }
11234
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011235 ServiceLookupResult res =
11236 retrieveServiceLocked(service, resolvedType,
11237 Binder.getCallingPid(), Binder.getCallingUid());
11238 if (res == null) {
11239 return 0;
11240 }
11241 if (res.record == null) {
11242 return -1;
11243 }
11244 ServiceRecord s = res.record;
11245
11246 final long origId = Binder.clearCallingIdentity();
11247
11248 if (unscheduleServiceRestartLocked(s)) {
11249 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
11250 + s.shortName);
11251 }
11252
11253 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
11254 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011255 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011256
11257 IBinder binder = connection.asBinder();
11258 s.connections.put(binder, c);
11259 b.connections.add(c);
11260 if (activity != null) {
11261 if (activity.connections == null) {
11262 activity.connections = new HashSet<ConnectionRecord>();
11263 }
11264 activity.connections.add(c);
11265 }
11266 b.client.connections.add(c);
11267 mServiceConnections.put(binder, c);
11268
11269 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
11270 s.lastActivity = SystemClock.uptimeMillis();
11271 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
11272 return 0;
11273 }
11274 }
11275
11276 if (s.app != null) {
11277 // This could have made the service more important.
11278 updateOomAdjLocked(s.app);
11279 }
11280
11281 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
11282 + ": received=" + b.intent.received
11283 + " apps=" + b.intent.apps.size()
11284 + " doRebind=" + b.intent.doRebind);
11285
11286 if (s.app != null && b.intent.received) {
11287 // Service is already running, so we can immediately
11288 // publish the connection.
11289 try {
11290 c.conn.connected(s.name, b.intent.binder);
11291 } catch (Exception e) {
11292 Log.w(TAG, "Failure sending service " + s.shortName
11293 + " to connection " + c.conn.asBinder()
11294 + " (in " + c.binding.client.processName + ")", e);
11295 }
11296
11297 // If this is the first app connected back to this binding,
11298 // and the service had previously asked to be told when
11299 // rebound, then do so.
11300 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
11301 requestServiceBindingLocked(s, b.intent, true);
11302 }
11303 } else if (!b.intent.requested) {
11304 requestServiceBindingLocked(s, b.intent, false);
11305 }
11306
11307 Binder.restoreCallingIdentity(origId);
11308 }
11309
11310 return 1;
11311 }
11312
11313 private void removeConnectionLocked(
11314 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
11315 IBinder binder = c.conn.asBinder();
11316 AppBindRecord b = c.binding;
11317 ServiceRecord s = b.service;
11318 s.connections.remove(binder);
11319 b.connections.remove(c);
11320 if (c.activity != null && c.activity != skipAct) {
11321 if (c.activity.connections != null) {
11322 c.activity.connections.remove(c);
11323 }
11324 }
11325 if (b.client != skipApp) {
11326 b.client.connections.remove(c);
11327 }
11328 mServiceConnections.remove(binder);
11329
11330 if (b.connections.size() == 0) {
11331 b.intent.apps.remove(b.client);
11332 }
11333
11334 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
11335 + ": shouldUnbind=" + b.intent.hasBound);
11336 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
11337 && b.intent.hasBound) {
11338 try {
11339 bumpServiceExecutingLocked(s);
11340 updateOomAdjLocked(s.app);
11341 b.intent.hasBound = false;
11342 // Assume the client doesn't want to know about a rebind;
11343 // we will deal with that later if it asks for one.
11344 b.intent.doRebind = false;
11345 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
11346 } catch (Exception e) {
11347 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
11348 serviceDoneExecutingLocked(s, true);
11349 }
11350 }
11351
11352 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
11353 bringDownServiceLocked(s, false);
11354 }
11355 }
11356
11357 public boolean unbindService(IServiceConnection connection) {
11358 synchronized (this) {
11359 IBinder binder = connection.asBinder();
11360 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11361 ConnectionRecord r = mServiceConnections.get(binder);
11362 if (r == null) {
11363 Log.w(TAG, "Unbind failed: could not find connection for "
11364 + connection.asBinder());
11365 return false;
11366 }
11367
11368 final long origId = Binder.clearCallingIdentity();
11369
11370 removeConnectionLocked(r, null, null);
11371
11372 if (r.binding.service.app != null) {
11373 // This could have made the service less important.
11374 updateOomAdjLocked(r.binding.service.app);
11375 }
11376
11377 Binder.restoreCallingIdentity(origId);
11378 }
11379
11380 return true;
11381 }
11382
11383 public void publishService(IBinder token, Intent intent, IBinder service) {
11384 // Refuse possible leaked file descriptors
11385 if (intent != null && intent.hasFileDescriptors() == true) {
11386 throw new IllegalArgumentException("File descriptors passed in Intent");
11387 }
11388
11389 synchronized(this) {
11390 if (!(token instanceof ServiceRecord)) {
11391 throw new IllegalArgumentException("Invalid service token");
11392 }
11393 ServiceRecord r = (ServiceRecord)token;
11394
11395 final long origId = Binder.clearCallingIdentity();
11396
11397 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11398 + " " + intent + ": " + service);
11399 if (r != null) {
11400 Intent.FilterComparison filter
11401 = new Intent.FilterComparison(intent);
11402 IntentBindRecord b = r.bindings.get(filter);
11403 if (b != null && !b.received) {
11404 b.binder = service;
11405 b.requested = true;
11406 b.received = true;
11407 if (r.connections.size() > 0) {
11408 Iterator<ConnectionRecord> it
11409 = r.connections.values().iterator();
11410 while (it.hasNext()) {
11411 ConnectionRecord c = it.next();
11412 if (!filter.equals(c.binding.intent.intent)) {
11413 if (DEBUG_SERVICE) Log.v(
11414 TAG, "Not publishing to: " + c);
11415 if (DEBUG_SERVICE) Log.v(
11416 TAG, "Bound intent: " + c.binding.intent.intent);
11417 if (DEBUG_SERVICE) Log.v(
11418 TAG, "Published intent: " + intent);
11419 continue;
11420 }
11421 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11422 try {
11423 c.conn.connected(r.name, service);
11424 } catch (Exception e) {
11425 Log.w(TAG, "Failure sending service " + r.name +
11426 " to connection " + c.conn.asBinder() +
11427 " (in " + c.binding.client.processName + ")", e);
11428 }
11429 }
11430 }
11431 }
11432
11433 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11434
11435 Binder.restoreCallingIdentity(origId);
11436 }
11437 }
11438 }
11439
11440 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11441 // Refuse possible leaked file descriptors
11442 if (intent != null && intent.hasFileDescriptors() == true) {
11443 throw new IllegalArgumentException("File descriptors passed in Intent");
11444 }
11445
11446 synchronized(this) {
11447 if (!(token instanceof ServiceRecord)) {
11448 throw new IllegalArgumentException("Invalid service token");
11449 }
11450 ServiceRecord r = (ServiceRecord)token;
11451
11452 final long origId = Binder.clearCallingIdentity();
11453
11454 if (r != null) {
11455 Intent.FilterComparison filter
11456 = new Intent.FilterComparison(intent);
11457 IntentBindRecord b = r.bindings.get(filter);
11458 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11459 + " at " + b + ": apps="
11460 + (b != null ? b.apps.size() : 0));
11461 if (b != null) {
11462 if (b.apps.size() > 0) {
11463 // Applications have already bound since the last
11464 // unbind, so just rebind right here.
11465 requestServiceBindingLocked(r, b, true);
11466 } else {
11467 // Note to tell the service the next time there is
11468 // a new client.
11469 b.doRebind = true;
11470 }
11471 }
11472
11473 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11474
11475 Binder.restoreCallingIdentity(origId);
11476 }
11477 }
11478 }
11479
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011480 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011481 synchronized(this) {
11482 if (!(token instanceof ServiceRecord)) {
11483 throw new IllegalArgumentException("Invalid service token");
11484 }
11485 ServiceRecord r = (ServiceRecord)token;
11486 boolean inStopping = mStoppingServices.contains(token);
11487 if (r != null) {
11488 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11489 + ": nesting=" + r.executeNesting
11490 + ", inStopping=" + inStopping);
11491 if (r != token) {
11492 Log.w(TAG, "Done executing service " + r.name
11493 + " with incorrect token: given " + token
11494 + ", expected " + r);
11495 return;
11496 }
11497
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011498 if (type == 1) {
11499 // This is a call from a service start... take care of
11500 // book-keeping.
11501 r.callStart = true;
11502 switch (res) {
11503 case Service.START_STICKY_COMPATIBILITY:
11504 case Service.START_STICKY: {
11505 // We are done with the associated start arguments.
11506 r.findDeliveredStart(startId, true);
11507 // Don't stop if killed.
11508 r.stopIfKilled = false;
11509 break;
11510 }
11511 case Service.START_NOT_STICKY: {
11512 // We are done with the associated start arguments.
11513 r.findDeliveredStart(startId, true);
11514 if (r.lastStartId == startId) {
11515 // There is no more work, and this service
11516 // doesn't want to hang around if killed.
11517 r.stopIfKilled = true;
11518 }
11519 break;
11520 }
11521 case Service.START_REDELIVER_INTENT: {
11522 // We'll keep this item until they explicitly
11523 // call stop for it, but keep track of the fact
11524 // that it was delivered.
11525 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11526 if (si != null) {
11527 si.deliveryCount = 0;
11528 si.doneExecutingCount++;
11529 // Don't stop if killed.
11530 r.stopIfKilled = true;
11531 }
11532 break;
11533 }
11534 default:
11535 throw new IllegalArgumentException(
11536 "Unknown service start result: " + res);
11537 }
11538 if (res == Service.START_STICKY_COMPATIBILITY) {
11539 r.callStart = false;
11540 }
11541 }
11542
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011543 final long origId = Binder.clearCallingIdentity();
11544 serviceDoneExecutingLocked(r, inStopping);
11545 Binder.restoreCallingIdentity(origId);
11546 } else {
11547 Log.w(TAG, "Done executing unknown service " + r.name
11548 + " with token " + token);
11549 }
11550 }
11551 }
11552
11553 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11554 r.executeNesting--;
11555 if (r.executeNesting <= 0 && r.app != null) {
11556 r.app.executingServices.remove(r);
11557 if (r.app.executingServices.size() == 0) {
11558 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11559 }
11560 if (inStopping) {
11561 mStoppingServices.remove(r);
11562 }
11563 updateOomAdjLocked(r.app);
11564 }
11565 }
11566
11567 void serviceTimeout(ProcessRecord proc) {
11568 synchronized(this) {
11569 if (proc.executingServices.size() == 0 || proc.thread == null) {
11570 return;
11571 }
11572 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11573 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11574 ServiceRecord timeout = null;
11575 long nextTime = 0;
11576 while (it.hasNext()) {
11577 ServiceRecord sr = it.next();
11578 if (sr.executingStart < maxTime) {
11579 timeout = sr;
11580 break;
11581 }
11582 if (sr.executingStart > nextTime) {
11583 nextTime = sr.executingStart;
11584 }
11585 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -080011586 if (timeout != null && mLruProcesses.contains(proc)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011587 Log.w(TAG, "Timeout executing service: " + timeout);
Dan Egnorb7f03672009-12-09 16:22:32 -080011588 appNotRespondingLocked(proc, null, null, "Executing service " + timeout.name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011589 } else {
11590 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11591 msg.obj = proc;
11592 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11593 }
11594 }
11595 }
11596
11597 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011598 // BACKUP AND RESTORE
11599 // =========================================================
11600
11601 // Cause the target app to be launched if necessary and its backup agent
11602 // instantiated. The backup agent will invoke backupAgentCreated() on the
11603 // activity manager to announce its creation.
11604 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11605 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11606 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11607
11608 synchronized(this) {
11609 // !!! TODO: currently no check here that we're already bound
11610 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11611 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11612 synchronized (stats) {
11613 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11614 }
11615
11616 BackupRecord r = new BackupRecord(ss, app, backupMode);
11617 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11618 // startProcessLocked() returns existing proc's record if it's already running
11619 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011620 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011621 if (proc == null) {
11622 Log.e(TAG, "Unable to start backup agent process " + r);
11623 return false;
11624 }
11625
11626 r.app = proc;
11627 mBackupTarget = r;
11628 mBackupAppName = app.packageName;
11629
Christopher Tate6fa95972009-06-05 18:43:55 -070011630 // Try not to kill the process during backup
11631 updateOomAdjLocked(proc);
11632
Christopher Tate181fafa2009-05-14 11:12:14 -070011633 // If the process is already attached, schedule the creation of the backup agent now.
11634 // If it is not yet live, this will be done when it attaches to the framework.
11635 if (proc.thread != null) {
11636 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11637 try {
11638 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11639 } catch (RemoteException e) {
Christopher Tate436344a2009-09-30 16:17:37 -070011640 // Will time out on the backup manager side
Christopher Tate181fafa2009-05-14 11:12:14 -070011641 }
11642 } else {
11643 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11644 }
11645 // Invariants: at this point, the target app process exists and the application
11646 // is either already running or in the process of coming up. mBackupTarget and
11647 // mBackupAppName describe the app, so that when it binds back to the AM we
11648 // know that it's scheduled for a backup-agent operation.
11649 }
11650
11651 return true;
11652 }
11653
11654 // A backup agent has just come up
11655 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11656 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11657 + " = " + agent);
11658
11659 synchronized(this) {
11660 if (!agentPackageName.equals(mBackupAppName)) {
11661 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11662 return;
11663 }
11664
Christopher Tate043dadc2009-06-02 16:11:00 -070011665 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011666 try {
11667 IBackupManager bm = IBackupManager.Stub.asInterface(
11668 ServiceManager.getService(Context.BACKUP_SERVICE));
11669 bm.agentConnected(agentPackageName, agent);
11670 } catch (RemoteException e) {
11671 // can't happen; the backup manager service is local
11672 } catch (Exception e) {
11673 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11674 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011675 } finally {
11676 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011677 }
11678 }
11679 }
11680
11681 // done with this agent
11682 public void unbindBackupAgent(ApplicationInfo appInfo) {
11683 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011684 if (appInfo == null) {
11685 Log.w(TAG, "unbind backup agent for null app");
11686 return;
11687 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011688
11689 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011690 if (mBackupAppName == null) {
11691 Log.w(TAG, "Unbinding backup agent with no active backup");
11692 return;
11693 }
11694
Christopher Tate181fafa2009-05-14 11:12:14 -070011695 if (!mBackupAppName.equals(appInfo.packageName)) {
11696 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11697 return;
11698 }
11699
Christopher Tate6fa95972009-06-05 18:43:55 -070011700 ProcessRecord proc = mBackupTarget.app;
11701 mBackupTarget = null;
11702 mBackupAppName = null;
11703
11704 // Not backing this app up any more; reset its OOM adjustment
11705 updateOomAdjLocked(proc);
11706
Christopher Tatec7b31e32009-06-10 15:49:30 -070011707 // If the app crashed during backup, 'thread' will be null here
11708 if (proc.thread != null) {
11709 try {
11710 proc.thread.scheduleDestroyBackupAgent(appInfo);
11711 } catch (Exception e) {
11712 Log.e(TAG, "Exception when unbinding backup agent:");
11713 e.printStackTrace();
11714 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011715 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011716 }
11717 }
11718 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011719 // BROADCASTS
11720 // =========================================================
11721
11722 private final List getStickies(String action, IntentFilter filter,
11723 List cur) {
11724 final ContentResolver resolver = mContext.getContentResolver();
11725 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11726 if (list == null) {
11727 return cur;
11728 }
11729 int N = list.size();
11730 for (int i=0; i<N; i++) {
11731 Intent intent = list.get(i);
11732 if (filter.match(resolver, intent, true, TAG) >= 0) {
11733 if (cur == null) {
11734 cur = new ArrayList<Intent>();
11735 }
11736 cur.add(intent);
11737 }
11738 }
11739 return cur;
11740 }
11741
11742 private final void scheduleBroadcastsLocked() {
11743 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11744 + mBroadcastsScheduled);
11745
11746 if (mBroadcastsScheduled) {
11747 return;
11748 }
11749 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11750 mBroadcastsScheduled = true;
11751 }
11752
11753 public Intent registerReceiver(IApplicationThread caller,
11754 IIntentReceiver receiver, IntentFilter filter, String permission) {
11755 synchronized(this) {
11756 ProcessRecord callerApp = null;
11757 if (caller != null) {
11758 callerApp = getRecordForAppLocked(caller);
11759 if (callerApp == null) {
11760 throw new SecurityException(
11761 "Unable to find app for caller " + caller
11762 + " (pid=" + Binder.getCallingPid()
11763 + ") when registering receiver " + receiver);
11764 }
11765 }
11766
11767 List allSticky = null;
11768
11769 // Look for any matching sticky broadcasts...
11770 Iterator actions = filter.actionsIterator();
11771 if (actions != null) {
11772 while (actions.hasNext()) {
11773 String action = (String)actions.next();
11774 allSticky = getStickies(action, filter, allSticky);
11775 }
11776 } else {
11777 allSticky = getStickies(null, filter, allSticky);
11778 }
11779
11780 // The first sticky in the list is returned directly back to
11781 // the client.
11782 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11783
11784 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11785 + ": " + sticky);
11786
11787 if (receiver == null) {
11788 return sticky;
11789 }
11790
11791 ReceiverList rl
11792 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11793 if (rl == null) {
11794 rl = new ReceiverList(this, callerApp,
11795 Binder.getCallingPid(),
11796 Binder.getCallingUid(), receiver);
11797 if (rl.app != null) {
11798 rl.app.receivers.add(rl);
11799 } else {
11800 try {
11801 receiver.asBinder().linkToDeath(rl, 0);
11802 } catch (RemoteException e) {
11803 return sticky;
11804 }
11805 rl.linkedToDeath = true;
11806 }
11807 mRegisteredReceivers.put(receiver.asBinder(), rl);
11808 }
11809 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11810 rl.add(bf);
11811 if (!bf.debugCheck()) {
11812 Log.w(TAG, "==> For Dynamic broadast");
11813 }
11814 mReceiverResolver.addFilter(bf);
11815
11816 // Enqueue broadcasts for all existing stickies that match
11817 // this filter.
11818 if (allSticky != null) {
11819 ArrayList receivers = new ArrayList();
11820 receivers.add(bf);
11821
11822 int N = allSticky.size();
11823 for (int i=0; i<N; i++) {
11824 Intent intent = (Intent)allSticky.get(i);
11825 BroadcastRecord r = new BroadcastRecord(intent, null,
11826 null, -1, -1, null, receivers, null, 0, null, null,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011827 false, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011828 if (mParallelBroadcasts.size() == 0) {
11829 scheduleBroadcastsLocked();
11830 }
11831 mParallelBroadcasts.add(r);
11832 }
11833 }
11834
11835 return sticky;
11836 }
11837 }
11838
11839 public void unregisterReceiver(IIntentReceiver receiver) {
11840 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11841
11842 boolean doNext = false;
11843
11844 synchronized(this) {
11845 ReceiverList rl
11846 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11847 if (rl != null) {
11848 if (rl.curBroadcast != null) {
11849 BroadcastRecord r = rl.curBroadcast;
11850 doNext = finishReceiverLocked(
11851 receiver.asBinder(), r.resultCode, r.resultData,
11852 r.resultExtras, r.resultAbort, true);
11853 }
11854
11855 if (rl.app != null) {
11856 rl.app.receivers.remove(rl);
11857 }
11858 removeReceiverLocked(rl);
11859 if (rl.linkedToDeath) {
11860 rl.linkedToDeath = false;
11861 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11862 }
11863 }
11864 }
11865
11866 if (!doNext) {
11867 return;
11868 }
11869
11870 final long origId = Binder.clearCallingIdentity();
11871 processNextBroadcast(false);
11872 trimApplications();
11873 Binder.restoreCallingIdentity(origId);
11874 }
11875
11876 void removeReceiverLocked(ReceiverList rl) {
11877 mRegisteredReceivers.remove(rl.receiver.asBinder());
11878 int N = rl.size();
11879 for (int i=0; i<N; i++) {
11880 mReceiverResolver.removeFilter(rl.get(i));
11881 }
11882 }
11883
11884 private final int broadcastIntentLocked(ProcessRecord callerApp,
11885 String callerPackage, Intent intent, String resolvedType,
11886 IIntentReceiver resultTo, int resultCode, String resultData,
11887 Bundle map, String requiredPermission,
11888 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11889 intent = new Intent(intent);
11890
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011891 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011892 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11893 + " ordered=" + ordered);
11894 if ((resultTo != null) && !ordered) {
11895 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11896 }
11897
11898 // Handle special intents: if this broadcast is from the package
11899 // manager about a package being removed, we need to remove all of
11900 // its activities from the history stack.
11901 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11902 intent.getAction());
11903 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11904 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11905 || uidRemoved) {
11906 if (checkComponentPermission(
11907 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11908 callingPid, callingUid, -1)
11909 == PackageManager.PERMISSION_GRANTED) {
11910 if (uidRemoved) {
11911 final Bundle intentExtras = intent.getExtras();
11912 final int uid = intentExtras != null
11913 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11914 if (uid >= 0) {
11915 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11916 synchronized (bs) {
11917 bs.removeUidStatsLocked(uid);
11918 }
11919 }
11920 } else {
11921 Uri data = intent.getData();
11922 String ssp;
11923 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11924 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11925 uninstallPackageLocked(ssp,
11926 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011927 AttributeCache ac = AttributeCache.instance();
11928 if (ac != null) {
11929 ac.removePackage(ssp);
11930 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011931 }
11932 }
11933 }
11934 } else {
11935 String msg = "Permission Denial: " + intent.getAction()
11936 + " broadcast from " + callerPackage + " (pid=" + callingPid
11937 + ", uid=" + callingUid + ")"
11938 + " requires "
11939 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11940 Log.w(TAG, msg);
11941 throw new SecurityException(msg);
11942 }
11943 }
11944
11945 /*
11946 * If this is the time zone changed action, queue up a message that will reset the timezone
11947 * of all currently running processes. This message will get queued up before the broadcast
11948 * happens.
11949 */
11950 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11951 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11952 }
11953
Dianne Hackborn854060af2009-07-09 18:14:31 -070011954 /*
11955 * Prevent non-system code (defined here to be non-persistent
11956 * processes) from sending protected broadcasts.
11957 */
11958 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11959 || callingUid == Process.SHELL_UID || callingUid == 0) {
11960 // Always okay.
11961 } else if (callerApp == null || !callerApp.persistent) {
11962 try {
11963 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11964 intent.getAction())) {
11965 String msg = "Permission Denial: not allowed to send broadcast "
11966 + intent.getAction() + " from pid="
11967 + callingPid + ", uid=" + callingUid;
11968 Log.w(TAG, msg);
11969 throw new SecurityException(msg);
11970 }
11971 } catch (RemoteException e) {
11972 Log.w(TAG, "Remote exception", e);
11973 return BROADCAST_SUCCESS;
11974 }
11975 }
11976
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011977 // Add to the sticky list if requested.
11978 if (sticky) {
11979 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11980 callingPid, callingUid)
11981 != PackageManager.PERMISSION_GRANTED) {
11982 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11983 + callingPid + ", uid=" + callingUid
11984 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11985 Log.w(TAG, msg);
11986 throw new SecurityException(msg);
11987 }
11988 if (requiredPermission != null) {
11989 Log.w(TAG, "Can't broadcast sticky intent " + intent
11990 + " and enforce permission " + requiredPermission);
11991 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11992 }
11993 if (intent.getComponent() != null) {
11994 throw new SecurityException(
11995 "Sticky broadcasts can't target a specific component");
11996 }
11997 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11998 if (list == null) {
11999 list = new ArrayList<Intent>();
12000 mStickyBroadcasts.put(intent.getAction(), list);
12001 }
12002 int N = list.size();
12003 int i;
12004 for (i=0; i<N; i++) {
12005 if (intent.filterEquals(list.get(i))) {
12006 // This sticky already exists, replace it.
12007 list.set(i, new Intent(intent));
12008 break;
12009 }
12010 }
12011 if (i >= N) {
12012 list.add(new Intent(intent));
12013 }
12014 }
12015
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012016 // Figure out who all will receive this broadcast.
12017 List receivers = null;
12018 List<BroadcastFilter> registeredReceivers = null;
12019 try {
12020 if (intent.getComponent() != null) {
12021 // Broadcast is going to one specific receiver class...
12022 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070012023 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012024 if (ai != null) {
12025 receivers = new ArrayList();
12026 ResolveInfo ri = new ResolveInfo();
12027 ri.activityInfo = ai;
12028 receivers.add(ri);
12029 }
12030 } else {
12031 // Need to resolve the intent to interested receivers...
12032 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
12033 == 0) {
12034 receivers =
12035 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012036 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012037 }
Mihai Preda074edef2009-05-18 17:13:31 +020012038 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012039 }
12040 } catch (RemoteException ex) {
12041 // pm is in same process, this will never happen.
12042 }
12043
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012044 final boolean replacePending =
12045 (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
12046
12047 if (DEBUG_BROADCAST) Log.v(TAG, "Enqueing broadcast: " + intent.getAction()
12048 + " replacePending=" + replacePending);
12049
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012050 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
12051 if (!ordered && NR > 0) {
12052 // If we are not serializing this broadcast, then send the
12053 // registered receivers separately so they don't wait for the
12054 // components to be launched.
12055 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
12056 callerPackage, callingPid, callingUid, requiredPermission,
12057 registeredReceivers, resultTo, resultCode, resultData, map,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012058 ordered, sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012059 if (DEBUG_BROADCAST) Log.v(
12060 TAG, "Enqueueing parallel broadcast " + r
12061 + ": prev had " + mParallelBroadcasts.size());
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012062 boolean replaced = false;
12063 if (replacePending) {
12064 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
12065 if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
12066 if (DEBUG_BROADCAST) Log.v(TAG,
12067 "***** DROPPING PARALLEL: " + intent);
12068 mParallelBroadcasts.set(i, r);
12069 replaced = true;
12070 break;
12071 }
12072 }
12073 }
12074 if (!replaced) {
12075 mParallelBroadcasts.add(r);
12076 scheduleBroadcastsLocked();
12077 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012078 registeredReceivers = null;
12079 NR = 0;
12080 }
12081
12082 // Merge into one list.
12083 int ir = 0;
12084 if (receivers != null) {
12085 // A special case for PACKAGE_ADDED: do not allow the package
12086 // being added to see this broadcast. This prevents them from
12087 // using this as a back door to get run as soon as they are
12088 // installed. Maybe in the future we want to have a special install
12089 // broadcast or such for apps, but we'd like to deliberately make
12090 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070012091 boolean skip = false;
12092 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070012093 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070012094 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
12095 skip = true;
12096 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
12097 skip = true;
12098 }
12099 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012100 ? intent.getData().getSchemeSpecificPart()
12101 : null;
12102 if (skipPackage != null && receivers != null) {
12103 int NT = receivers.size();
12104 for (int it=0; it<NT; it++) {
12105 ResolveInfo curt = (ResolveInfo)receivers.get(it);
12106 if (curt.activityInfo.packageName.equals(skipPackage)) {
12107 receivers.remove(it);
12108 it--;
12109 NT--;
12110 }
12111 }
12112 }
12113
12114 int NT = receivers != null ? receivers.size() : 0;
12115 int it = 0;
12116 ResolveInfo curt = null;
12117 BroadcastFilter curr = null;
12118 while (it < NT && ir < NR) {
12119 if (curt == null) {
12120 curt = (ResolveInfo)receivers.get(it);
12121 }
12122 if (curr == null) {
12123 curr = registeredReceivers.get(ir);
12124 }
12125 if (curr.getPriority() >= curt.priority) {
12126 // Insert this broadcast record into the final list.
12127 receivers.add(it, curr);
12128 ir++;
12129 curr = null;
12130 it++;
12131 NT++;
12132 } else {
12133 // Skip to the next ResolveInfo in the final list.
12134 it++;
12135 curt = null;
12136 }
12137 }
12138 }
12139 while (ir < NR) {
12140 if (receivers == null) {
12141 receivers = new ArrayList();
12142 }
12143 receivers.add(registeredReceivers.get(ir));
12144 ir++;
12145 }
12146
12147 if ((receivers != null && receivers.size() > 0)
12148 || resultTo != null) {
12149 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
12150 callerPackage, callingPid, callingUid, requiredPermission,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012151 receivers, resultTo, resultCode, resultData, map, ordered,
12152 sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012153 if (DEBUG_BROADCAST) Log.v(
12154 TAG, "Enqueueing ordered broadcast " + r
12155 + ": prev had " + mOrderedBroadcasts.size());
12156 if (DEBUG_BROADCAST) {
12157 int seq = r.intent.getIntExtra("seq", -1);
12158 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
12159 }
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012160 boolean replaced = false;
12161 if (replacePending) {
12162 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
12163 if (intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
12164 if (DEBUG_BROADCAST) Log.v(TAG,
12165 "***** DROPPING ORDERED: " + intent);
12166 mOrderedBroadcasts.set(i, r);
12167 replaced = true;
12168 break;
12169 }
12170 }
12171 }
12172 if (!replaced) {
12173 mOrderedBroadcasts.add(r);
12174 scheduleBroadcastsLocked();
12175 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012176 }
12177
12178 return BROADCAST_SUCCESS;
12179 }
12180
12181 public final int broadcastIntent(IApplicationThread caller,
12182 Intent intent, String resolvedType, IIntentReceiver resultTo,
12183 int resultCode, String resultData, Bundle map,
12184 String requiredPermission, boolean serialized, boolean sticky) {
12185 // Refuse possible leaked file descriptors
12186 if (intent != null && intent.hasFileDescriptors() == true) {
12187 throw new IllegalArgumentException("File descriptors passed in Intent");
12188 }
12189
12190 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012191 int flags = intent.getFlags();
12192
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012193 if (!mSystemReady) {
12194 // if the caller really truly claims to know what they're doing, go
12195 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012196 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
12197 intent = new Intent(intent);
12198 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
12199 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
12200 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
12201 + " before boot completion");
12202 throw new IllegalStateException("Cannot broadcast before boot completed");
12203 }
12204 }
12205
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012206 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
12207 throw new IllegalArgumentException(
12208 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
12209 }
12210
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012211 final ProcessRecord callerApp = getRecordForAppLocked(caller);
12212 final int callingPid = Binder.getCallingPid();
12213 final int callingUid = Binder.getCallingUid();
12214 final long origId = Binder.clearCallingIdentity();
12215 int res = broadcastIntentLocked(callerApp,
12216 callerApp != null ? callerApp.info.packageName : null,
12217 intent, resolvedType, resultTo,
12218 resultCode, resultData, map, requiredPermission, serialized,
12219 sticky, callingPid, callingUid);
12220 Binder.restoreCallingIdentity(origId);
12221 return res;
12222 }
12223 }
12224
12225 int broadcastIntentInPackage(String packageName, int uid,
12226 Intent intent, String resolvedType, IIntentReceiver resultTo,
12227 int resultCode, String resultData, Bundle map,
12228 String requiredPermission, boolean serialized, boolean sticky) {
12229 synchronized(this) {
12230 final long origId = Binder.clearCallingIdentity();
12231 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
12232 resultTo, resultCode, resultData, map, requiredPermission,
12233 serialized, sticky, -1, uid);
12234 Binder.restoreCallingIdentity(origId);
12235 return res;
12236 }
12237 }
12238
12239 public final void unbroadcastIntent(IApplicationThread caller,
12240 Intent intent) {
12241 // Refuse possible leaked file descriptors
12242 if (intent != null && intent.hasFileDescriptors() == true) {
12243 throw new IllegalArgumentException("File descriptors passed in Intent");
12244 }
12245
12246 synchronized(this) {
12247 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
12248 != PackageManager.PERMISSION_GRANTED) {
12249 String msg = "Permission Denial: unbroadcastIntent() from pid="
12250 + Binder.getCallingPid()
12251 + ", uid=" + Binder.getCallingUid()
12252 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
12253 Log.w(TAG, msg);
12254 throw new SecurityException(msg);
12255 }
12256 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12257 if (list != null) {
12258 int N = list.size();
12259 int i;
12260 for (i=0; i<N; i++) {
12261 if (intent.filterEquals(list.get(i))) {
12262 list.remove(i);
12263 break;
12264 }
12265 }
12266 }
12267 }
12268 }
12269
12270 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
12271 String resultData, Bundle resultExtras, boolean resultAbort,
12272 boolean explicit) {
12273 if (mOrderedBroadcasts.size() == 0) {
12274 if (explicit) {
12275 Log.w(TAG, "finishReceiver called but no pending broadcasts");
12276 }
12277 return false;
12278 }
12279 BroadcastRecord r = mOrderedBroadcasts.get(0);
12280 if (r.receiver == null) {
12281 if (explicit) {
12282 Log.w(TAG, "finishReceiver called but none active");
12283 }
12284 return false;
12285 }
12286 if (r.receiver != receiver) {
12287 Log.w(TAG, "finishReceiver called but active receiver is different");
12288 return false;
12289 }
12290 int state = r.state;
12291 r.state = r.IDLE;
12292 if (state == r.IDLE) {
12293 if (explicit) {
12294 Log.w(TAG, "finishReceiver called but state is IDLE");
12295 }
12296 }
12297 r.receiver = null;
12298 r.intent.setComponent(null);
12299 if (r.curApp != null) {
12300 r.curApp.curReceiver = null;
12301 }
12302 if (r.curFilter != null) {
12303 r.curFilter.receiverList.curBroadcast = null;
12304 }
12305 r.curFilter = null;
12306 r.curApp = null;
12307 r.curComponent = null;
12308 r.curReceiver = null;
12309 mPendingBroadcast = null;
12310
12311 r.resultCode = resultCode;
12312 r.resultData = resultData;
12313 r.resultExtras = resultExtras;
12314 r.resultAbort = resultAbort;
12315
12316 // We will process the next receiver right now if this is finishing
12317 // an app receiver (which is always asynchronous) or after we have
12318 // come back from calling a receiver.
12319 return state == BroadcastRecord.APP_RECEIVE
12320 || state == BroadcastRecord.CALL_DONE_RECEIVE;
12321 }
12322
12323 public void finishReceiver(IBinder who, int resultCode, String resultData,
12324 Bundle resultExtras, boolean resultAbort) {
12325 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
12326
12327 // Refuse possible leaked file descriptors
12328 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
12329 throw new IllegalArgumentException("File descriptors passed in Bundle");
12330 }
12331
12332 boolean doNext;
12333
12334 final long origId = Binder.clearCallingIdentity();
12335
12336 synchronized(this) {
12337 doNext = finishReceiverLocked(
12338 who, resultCode, resultData, resultExtras, resultAbort, true);
12339 }
12340
12341 if (doNext) {
12342 processNextBroadcast(false);
12343 }
12344 trimApplications();
12345
12346 Binder.restoreCallingIdentity(origId);
12347 }
12348
12349 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
12350 if (r.nextReceiver > 0) {
12351 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12352 if (curReceiver instanceof BroadcastFilter) {
12353 BroadcastFilter bf = (BroadcastFilter) curReceiver;
Doug Zongker2bec3d42009-12-04 12:52:44 -080012354 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012355 System.identityHashCode(r),
12356 r.intent.getAction(),
12357 r.nextReceiver - 1,
12358 System.identityHashCode(bf));
12359 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -080012360 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012361 System.identityHashCode(r),
12362 r.intent.getAction(),
12363 r.nextReceiver - 1,
12364 ((ResolveInfo)curReceiver).toString());
12365 }
12366 } else {
12367 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
12368 + r);
Doug Zongker2bec3d42009-12-04 12:52:44 -080012369 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012370 System.identityHashCode(r),
12371 r.intent.getAction(),
12372 r.nextReceiver,
12373 "NONE");
12374 }
12375 }
12376
12377 private final void broadcastTimeout() {
12378 synchronized (this) {
12379 if (mOrderedBroadcasts.size() == 0) {
12380 return;
12381 }
12382 long now = SystemClock.uptimeMillis();
12383 BroadcastRecord r = mOrderedBroadcasts.get(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012384 if ((r.receiverTime+BROADCAST_TIMEOUT) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012385 if (DEBUG_BROADCAST) Log.v(TAG,
12386 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012387 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012388 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012389 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012390 return;
12391 }
12392
12393 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012394 r.receiverTime = now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012395 r.anrCount++;
12396
12397 // Current receiver has passed its expiration date.
12398 if (r.nextReceiver <= 0) {
12399 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12400 return;
12401 }
12402
12403 ProcessRecord app = null;
12404
12405 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12406 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12407 logBroadcastReceiverDiscard(r);
12408 if (curReceiver instanceof BroadcastFilter) {
12409 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12410 if (bf.receiverList.pid != 0
12411 && bf.receiverList.pid != MY_PID) {
12412 synchronized (this.mPidsSelfLocked) {
12413 app = this.mPidsSelfLocked.get(
12414 bf.receiverList.pid);
12415 }
12416 }
12417 } else {
12418 app = r.curApp;
12419 }
12420
12421 if (app != null) {
Dan Egnorb7f03672009-12-09 16:22:32 -080012422 appNotRespondingLocked(app, null, null, "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012423 }
12424
12425 if (mPendingBroadcast == r) {
12426 mPendingBroadcast = null;
12427 }
12428
12429 // Move on to the next receiver.
12430 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12431 r.resultExtras, r.resultAbort, true);
12432 scheduleBroadcastsLocked();
12433 }
12434 }
12435
12436 private final void processCurBroadcastLocked(BroadcastRecord r,
12437 ProcessRecord app) throws RemoteException {
12438 if (app.thread == null) {
12439 throw new RemoteException();
12440 }
12441 r.receiver = app.thread.asBinder();
12442 r.curApp = app;
12443 app.curReceiver = r;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080012444 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012445
12446 // Tell the application to launch this receiver.
12447 r.intent.setComponent(r.curComponent);
12448
12449 boolean started = false;
12450 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012451 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012452 "Delivering to component " + r.curComponent
12453 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012454 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012455 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12456 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12457 started = true;
12458 } finally {
12459 if (!started) {
12460 r.receiver = null;
12461 r.curApp = null;
12462 app.curReceiver = null;
12463 }
12464 }
12465
12466 }
12467
12468 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012469 Intent intent, int resultCode, String data, Bundle extras,
12470 boolean ordered, boolean sticky) throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012471 if (app != null && app.thread != null) {
12472 // If we have an app thread, do the call through that so it is
12473 // correctly ordered with other one-way calls.
12474 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012475 data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012476 } else {
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012477 receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012478 }
12479 }
12480
12481 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12482 BroadcastFilter filter, boolean ordered) {
12483 boolean skip = false;
12484 if (filter.requiredPermission != null) {
12485 int perm = checkComponentPermission(filter.requiredPermission,
12486 r.callingPid, r.callingUid, -1);
12487 if (perm != PackageManager.PERMISSION_GRANTED) {
12488 Log.w(TAG, "Permission Denial: broadcasting "
12489 + r.intent.toString()
12490 + " from " + r.callerPackage + " (pid="
12491 + r.callingPid + ", uid=" + r.callingUid + ")"
12492 + " requires " + filter.requiredPermission
12493 + " due to registered receiver " + filter);
12494 skip = true;
12495 }
12496 }
12497 if (r.requiredPermission != null) {
12498 int perm = checkComponentPermission(r.requiredPermission,
12499 filter.receiverList.pid, filter.receiverList.uid, -1);
12500 if (perm != PackageManager.PERMISSION_GRANTED) {
12501 Log.w(TAG, "Permission Denial: receiving "
12502 + r.intent.toString()
12503 + " to " + filter.receiverList.app
12504 + " (pid=" + filter.receiverList.pid
12505 + ", uid=" + filter.receiverList.uid + ")"
12506 + " requires " + r.requiredPermission
12507 + " due to sender " + r.callerPackage
12508 + " (uid " + r.callingUid + ")");
12509 skip = true;
12510 }
12511 }
12512
12513 if (!skip) {
12514 // If this is not being sent as an ordered broadcast, then we
12515 // don't want to touch the fields that keep track of the current
12516 // state of ordered broadcasts.
12517 if (ordered) {
12518 r.receiver = filter.receiverList.receiver.asBinder();
12519 r.curFilter = filter;
12520 filter.receiverList.curBroadcast = r;
12521 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012522 if (filter.receiverList.app != null) {
12523 // Bump hosting application to no longer be in background
12524 // scheduling class. Note that we can't do that if there
12525 // isn't an app... but we can only be in that case for
12526 // things that directly call the IActivityManager API, which
12527 // are already core system stuff so don't matter for this.
12528 r.curApp = filter.receiverList.app;
12529 filter.receiverList.app.curReceiver = r;
12530 updateOomAdjLocked();
12531 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012532 }
12533 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012534 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012535 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012536 Log.i(TAG, "Delivering to " + filter.receiverList.app
12537 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012538 }
12539 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12540 new Intent(r.intent), r.resultCode,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012541 r.resultData, r.resultExtras, r.ordered, r.initialSticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012542 if (ordered) {
12543 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12544 }
12545 } catch (RemoteException e) {
12546 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12547 if (ordered) {
12548 r.receiver = null;
12549 r.curFilter = null;
12550 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012551 if (filter.receiverList.app != null) {
12552 filter.receiverList.app.curReceiver = null;
12553 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012554 }
12555 }
12556 }
12557 }
12558
Dianne Hackborn12527f92009-11-11 17:39:50 -080012559 private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
12560 if (r.callingUid < 0) {
12561 // This was from a registerReceiver() call; ignore it.
12562 return;
12563 }
12564 System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
12565 MAX_BROADCAST_HISTORY-1);
12566 r.finishTime = SystemClock.uptimeMillis();
12567 mBroadcastHistory[0] = r;
12568 }
12569
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012570 private final void processNextBroadcast(boolean fromMsg) {
12571 synchronized(this) {
12572 BroadcastRecord r;
12573
12574 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12575 + mParallelBroadcasts.size() + " broadcasts, "
12576 + mOrderedBroadcasts.size() + " serialized broadcasts");
12577
12578 updateCpuStats();
12579
12580 if (fromMsg) {
12581 mBroadcastsScheduled = false;
12582 }
12583
12584 // First, deliver any non-serialized broadcasts right away.
12585 while (mParallelBroadcasts.size() > 0) {
12586 r = mParallelBroadcasts.remove(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012587 r.dispatchTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012588 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012589 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12590 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012591 for (int i=0; i<N; i++) {
12592 Object target = r.receivers.get(i);
12593 if (DEBUG_BROADCAST) Log.v(TAG,
12594 "Delivering non-serialized to registered "
12595 + target + ": " + r);
12596 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12597 }
Dianne Hackborn12527f92009-11-11 17:39:50 -080012598 addBroadcastToHistoryLocked(r);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012599 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12600 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012601 }
12602
12603 // Now take care of the next serialized one...
12604
12605 // If we are waiting for a process to come up to handle the next
12606 // broadcast, then do nothing at this point. Just in case, we
12607 // check that the process we're waiting for still exists.
12608 if (mPendingBroadcast != null) {
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -070012609 if (DEBUG_BROADCAST_LIGHT) {
12610 Log.v(TAG, "processNextBroadcast: waiting for "
12611 + mPendingBroadcast.curApp);
12612 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012613
12614 boolean isDead;
12615 synchronized (mPidsSelfLocked) {
12616 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12617 }
12618 if (!isDead) {
12619 // It's still alive, so keep waiting
12620 return;
12621 } else {
12622 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12623 + " died before responding to broadcast");
12624 mPendingBroadcast = null;
12625 }
12626 }
12627
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012628 boolean looped = false;
12629
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012630 do {
12631 if (mOrderedBroadcasts.size() == 0) {
12632 // No more broadcasts pending, so all done!
12633 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012634 if (looped) {
12635 // If we had finished the last ordered broadcast, then
12636 // make sure all processes have correct oom and sched
12637 // adjustments.
12638 updateOomAdjLocked();
12639 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012640 return;
12641 }
12642 r = mOrderedBroadcasts.get(0);
12643 boolean forceReceive = false;
12644
12645 // Ensure that even if something goes awry with the timeout
12646 // detection, we catch "hung" broadcasts here, discard them,
12647 // and continue to make progress.
12648 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12649 long now = SystemClock.uptimeMillis();
12650 if (r.dispatchTime > 0) {
12651 if ((numReceivers > 0) &&
12652 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12653 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12654 + " now=" + now
12655 + " dispatchTime=" + r.dispatchTime
Dianne Hackborn12527f92009-11-11 17:39:50 -080012656 + " startTime=" + r.receiverTime
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012657 + " intent=" + r.intent
12658 + " numReceivers=" + numReceivers
12659 + " nextReceiver=" + r.nextReceiver
12660 + " state=" + r.state);
12661 broadcastTimeout(); // forcibly finish this broadcast
12662 forceReceive = true;
12663 r.state = BroadcastRecord.IDLE;
12664 }
12665 }
12666
12667 if (r.state != BroadcastRecord.IDLE) {
12668 if (DEBUG_BROADCAST) Log.d(TAG,
12669 "processNextBroadcast() called when not idle (state="
12670 + r.state + ")");
12671 return;
12672 }
12673
12674 if (r.receivers == null || r.nextReceiver >= numReceivers
12675 || r.resultAbort || forceReceive) {
12676 // No more receivers for this broadcast! Send the final
12677 // result if requested...
12678 if (r.resultTo != null) {
12679 try {
12680 if (DEBUG_BROADCAST) {
12681 int seq = r.intent.getIntExtra("seq", -1);
12682 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12683 + " seq=" + seq + " app=" + r.callerApp);
12684 }
12685 performReceive(r.callerApp, r.resultTo,
12686 new Intent(r.intent), r.resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012687 r.resultData, r.resultExtras, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012688 } catch (RemoteException e) {
12689 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12690 }
12691 }
12692
12693 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12694 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12695
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012696 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12697 + r);
12698
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012699 // ... and on to the next...
Dianne Hackborn12527f92009-11-11 17:39:50 -080012700 addBroadcastToHistoryLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012701 mOrderedBroadcasts.remove(0);
12702 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012703 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012704 continue;
12705 }
12706 } while (r == null);
12707
12708 // Get the next receiver...
12709 int recIdx = r.nextReceiver++;
12710
12711 // Keep track of when this receiver started, and make sure there
12712 // is a timeout message pending to kill it if need be.
Dianne Hackborn12527f92009-11-11 17:39:50 -080012713 r.receiverTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012714 if (recIdx == 0) {
Dianne Hackborn12527f92009-11-11 17:39:50 -080012715 r.dispatchTime = r.receiverTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012716
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012717 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12718 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012719 if (DEBUG_BROADCAST) Log.v(TAG,
12720 "Submitting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012721 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012722 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012723 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012724 }
12725
12726 Object nextReceiver = r.receivers.get(recIdx);
12727 if (nextReceiver instanceof BroadcastFilter) {
12728 // Simple case: this is a registered receiver who gets
12729 // a direct call.
12730 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12731 if (DEBUG_BROADCAST) Log.v(TAG,
12732 "Delivering serialized to registered "
12733 + filter + ": " + r);
12734 deliverToRegisteredReceiver(r, filter, r.ordered);
12735 if (r.receiver == null || !r.ordered) {
12736 // The receiver has already finished, so schedule to
12737 // process the next one.
12738 r.state = BroadcastRecord.IDLE;
12739 scheduleBroadcastsLocked();
12740 }
12741 return;
12742 }
12743
12744 // Hard case: need to instantiate the receiver, possibly
12745 // starting its application process to host it.
12746
12747 ResolveInfo info =
12748 (ResolveInfo)nextReceiver;
12749
12750 boolean skip = false;
12751 int perm = checkComponentPermission(info.activityInfo.permission,
12752 r.callingPid, r.callingUid,
12753 info.activityInfo.exported
12754 ? -1 : info.activityInfo.applicationInfo.uid);
12755 if (perm != PackageManager.PERMISSION_GRANTED) {
12756 Log.w(TAG, "Permission Denial: broadcasting "
12757 + r.intent.toString()
12758 + " from " + r.callerPackage + " (pid=" + r.callingPid
12759 + ", uid=" + r.callingUid + ")"
12760 + " requires " + info.activityInfo.permission
12761 + " due to receiver " + info.activityInfo.packageName
12762 + "/" + info.activityInfo.name);
12763 skip = true;
12764 }
12765 if (r.callingUid != Process.SYSTEM_UID &&
12766 r.requiredPermission != null) {
12767 try {
12768 perm = ActivityThread.getPackageManager().
12769 checkPermission(r.requiredPermission,
12770 info.activityInfo.applicationInfo.packageName);
12771 } catch (RemoteException e) {
12772 perm = PackageManager.PERMISSION_DENIED;
12773 }
12774 if (perm != PackageManager.PERMISSION_GRANTED) {
12775 Log.w(TAG, "Permission Denial: receiving "
12776 + r.intent + " to "
12777 + info.activityInfo.applicationInfo.packageName
12778 + " requires " + r.requiredPermission
12779 + " due to sender " + r.callerPackage
12780 + " (uid " + r.callingUid + ")");
12781 skip = true;
12782 }
12783 }
12784 if (r.curApp != null && r.curApp.crashing) {
12785 // If the target process is crashing, just skip it.
12786 skip = true;
12787 }
12788
12789 if (skip) {
12790 r.receiver = null;
12791 r.curFilter = null;
12792 r.state = BroadcastRecord.IDLE;
12793 scheduleBroadcastsLocked();
12794 return;
12795 }
12796
12797 r.state = BroadcastRecord.APP_RECEIVE;
12798 String targetProcess = info.activityInfo.processName;
12799 r.curComponent = new ComponentName(
12800 info.activityInfo.applicationInfo.packageName,
12801 info.activityInfo.name);
12802 r.curReceiver = info.activityInfo;
12803
12804 // Is this receiver's application already running?
12805 ProcessRecord app = getProcessRecordLocked(targetProcess,
12806 info.activityInfo.applicationInfo.uid);
12807 if (app != null && app.thread != null) {
12808 try {
12809 processCurBroadcastLocked(r, app);
12810 return;
12811 } catch (RemoteException e) {
12812 Log.w(TAG, "Exception when sending broadcast to "
12813 + r.curComponent, e);
12814 }
12815
12816 // If a dead object exception was thrown -- fall through to
12817 // restart the application.
12818 }
12819
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012820 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012821 if ((r.curApp=startProcessLocked(targetProcess,
12822 info.activityInfo.applicationInfo, true,
12823 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012824 "broadcast", r.curComponent,
12825 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12826 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012827 // Ah, this recipient is unavailable. Finish it if necessary,
12828 // and mark the broadcast record as ready for the next.
12829 Log.w(TAG, "Unable to launch app "
12830 + info.activityInfo.applicationInfo.packageName + "/"
12831 + info.activityInfo.applicationInfo.uid + " for broadcast "
12832 + r.intent + ": process is bad");
12833 logBroadcastReceiverDiscard(r);
12834 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12835 r.resultExtras, r.resultAbort, true);
12836 scheduleBroadcastsLocked();
12837 r.state = BroadcastRecord.IDLE;
12838 return;
12839 }
12840
12841 mPendingBroadcast = r;
12842 }
12843 }
12844
12845 // =========================================================
12846 // INSTRUMENTATION
12847 // =========================================================
12848
12849 public boolean startInstrumentation(ComponentName className,
12850 String profileFile, int flags, Bundle arguments,
12851 IInstrumentationWatcher watcher) {
12852 // Refuse possible leaked file descriptors
12853 if (arguments != null && arguments.hasFileDescriptors()) {
12854 throw new IllegalArgumentException("File descriptors passed in Bundle");
12855 }
12856
12857 synchronized(this) {
12858 InstrumentationInfo ii = null;
12859 ApplicationInfo ai = null;
12860 try {
12861 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012862 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012863 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012864 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012865 } catch (PackageManager.NameNotFoundException e) {
12866 }
12867 if (ii == null) {
12868 reportStartInstrumentationFailure(watcher, className,
12869 "Unable to find instrumentation info for: " + className);
12870 return false;
12871 }
12872 if (ai == null) {
12873 reportStartInstrumentationFailure(watcher, className,
12874 "Unable to find instrumentation target package: " + ii.targetPackage);
12875 return false;
12876 }
12877
12878 int match = mContext.getPackageManager().checkSignatures(
12879 ii.targetPackage, ii.packageName);
12880 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12881 String msg = "Permission Denial: starting instrumentation "
12882 + className + " from pid="
12883 + Binder.getCallingPid()
12884 + ", uid=" + Binder.getCallingPid()
12885 + " not allowed because package " + ii.packageName
12886 + " does not have a signature matching the target "
12887 + ii.targetPackage;
12888 reportStartInstrumentationFailure(watcher, className, msg);
12889 throw new SecurityException(msg);
12890 }
12891
12892 final long origId = Binder.clearCallingIdentity();
12893 uninstallPackageLocked(ii.targetPackage, -1, true);
12894 ProcessRecord app = addAppLocked(ai);
12895 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012896 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012897 app.instrumentationProfileFile = profileFile;
12898 app.instrumentationArguments = arguments;
12899 app.instrumentationWatcher = watcher;
12900 app.instrumentationResultClass = className;
12901 Binder.restoreCallingIdentity(origId);
12902 }
12903
12904 return true;
12905 }
12906
12907 /**
12908 * Report errors that occur while attempting to start Instrumentation. Always writes the
12909 * error to the logs, but if somebody is watching, send the report there too. This enables
12910 * the "am" command to report errors with more information.
12911 *
12912 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12913 * @param cn The component name of the instrumentation.
12914 * @param report The error report.
12915 */
12916 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12917 ComponentName cn, String report) {
12918 Log.w(TAG, report);
12919 try {
12920 if (watcher != null) {
12921 Bundle results = new Bundle();
12922 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12923 results.putString("Error", report);
12924 watcher.instrumentationStatus(cn, -1, results);
12925 }
12926 } catch (RemoteException e) {
12927 Log.w(TAG, e);
12928 }
12929 }
12930
12931 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12932 if (app.instrumentationWatcher != null) {
12933 try {
12934 // NOTE: IInstrumentationWatcher *must* be oneway here
12935 app.instrumentationWatcher.instrumentationFinished(
12936 app.instrumentationClass,
12937 resultCode,
12938 results);
12939 } catch (RemoteException e) {
12940 }
12941 }
12942 app.instrumentationWatcher = null;
12943 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012944 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012945 app.instrumentationProfileFile = null;
12946 app.instrumentationArguments = null;
12947
12948 uninstallPackageLocked(app.processName, -1, false);
12949 }
12950
12951 public void finishInstrumentation(IApplicationThread target,
12952 int resultCode, Bundle results) {
12953 // Refuse possible leaked file descriptors
12954 if (results != null && results.hasFileDescriptors()) {
12955 throw new IllegalArgumentException("File descriptors passed in Intent");
12956 }
12957
12958 synchronized(this) {
12959 ProcessRecord app = getRecordForAppLocked(target);
12960 if (app == null) {
12961 Log.w(TAG, "finishInstrumentation: no app for " + target);
12962 return;
12963 }
12964 final long origId = Binder.clearCallingIdentity();
12965 finishInstrumentationLocked(app, resultCode, results);
12966 Binder.restoreCallingIdentity(origId);
12967 }
12968 }
12969
12970 // =========================================================
12971 // CONFIGURATION
12972 // =========================================================
12973
12974 public ConfigurationInfo getDeviceConfigurationInfo() {
12975 ConfigurationInfo config = new ConfigurationInfo();
12976 synchronized (this) {
12977 config.reqTouchScreen = mConfiguration.touchscreen;
12978 config.reqKeyboardType = mConfiguration.keyboard;
12979 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012980 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12981 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012982 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12983 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012984 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12985 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012986 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12987 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012988 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012989 }
12990 return config;
12991 }
12992
12993 public Configuration getConfiguration() {
12994 Configuration ci;
12995 synchronized(this) {
12996 ci = new Configuration(mConfiguration);
12997 }
12998 return ci;
12999 }
13000
13001 public void updateConfiguration(Configuration values) {
13002 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
13003 "updateConfiguration()");
13004
13005 synchronized(this) {
13006 if (values == null && mWindowManager != null) {
13007 // sentinel: fetch the current configuration from the window manager
13008 values = mWindowManager.computeNewConfiguration();
13009 }
13010
13011 final long origId = Binder.clearCallingIdentity();
13012 updateConfigurationLocked(values, null);
13013 Binder.restoreCallingIdentity(origId);
13014 }
13015 }
13016
13017 /**
13018 * Do either or both things: (1) change the current configuration, and (2)
13019 * make sure the given activity is running with the (now) current
13020 * configuration. Returns true if the activity has been left running, or
13021 * false if <var>starting</var> is being destroyed to match the new
13022 * configuration.
13023 */
13024 public boolean updateConfigurationLocked(Configuration values,
13025 HistoryRecord starting) {
13026 int changes = 0;
13027
13028 boolean kept = true;
13029
13030 if (values != null) {
13031 Configuration newConfig = new Configuration(mConfiguration);
13032 changes = newConfig.updateFrom(values);
13033 if (changes != 0) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013034 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013035 Log.i(TAG, "Updating configuration to: " + values);
13036 }
13037
Doug Zongker2bec3d42009-12-04 12:52:44 -080013038 EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013039
13040 if (values.locale != null) {
13041 saveLocaleLocked(values.locale,
13042 !values.locale.equals(mConfiguration.locale),
13043 values.userSetLocale);
13044 }
13045
13046 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070013047 Log.i(TAG, "Config changed: " + newConfig);
Dianne Hackborn826d17c2009-11-12 12:55:51 -080013048
13049 AttributeCache ac = AttributeCache.instance();
13050 if (ac != null) {
13051 ac.updateConfiguration(mConfiguration);
13052 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013053
13054 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
13055 msg.obj = new Configuration(mConfiguration);
13056 mHandler.sendMessage(msg);
13057
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013058 for (int i=mLruProcesses.size()-1; i>=0; i--) {
13059 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013060 try {
13061 if (app.thread != null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013062 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending to proc "
13063 + app.processName + " new config " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013064 app.thread.scheduleConfigurationChanged(mConfiguration);
13065 }
13066 } catch (Exception e) {
13067 }
13068 }
13069 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080013070 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
13071 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013072 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
13073 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackborn362d5b92009-11-11 18:04:39 -080013074 if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
13075 broadcastIntentLocked(null, null,
13076 new Intent(Intent.ACTION_LOCALE_CHANGED),
13077 null, null, 0, null, null,
13078 null, false, false, MY_PID, Process.SYSTEM_UID);
13079 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013080 }
13081 }
13082
13083 if (changes != 0 && starting == null) {
13084 // If the configuration changed, and the caller is not already
13085 // in the process of starting an activity, then find the top
13086 // activity to check if its configuration needs to change.
13087 starting = topRunningActivityLocked(null);
13088 }
13089
13090 if (starting != null) {
13091 kept = ensureActivityConfigurationLocked(starting, changes);
13092 if (kept) {
13093 // If this didn't result in the starting activity being
13094 // destroyed, then we need to make sure at this point that all
13095 // other activities are made visible.
13096 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
13097 + ", ensuring others are correct.");
13098 ensureActivitiesVisibleLocked(starting, changes);
13099 }
13100 }
13101
13102 return kept;
13103 }
13104
13105 private final boolean relaunchActivityLocked(HistoryRecord r,
13106 int changes, boolean andResume) {
13107 List<ResultInfo> results = null;
13108 List<Intent> newIntents = null;
13109 if (andResume) {
13110 results = r.results;
13111 newIntents = r.newIntents;
13112 }
13113 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
13114 + " with results=" + results + " newIntents=" + newIntents
13115 + " andResume=" + andResume);
Doug Zongker2bec3d42009-12-04 12:52:44 -080013116 EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
13117 : EventLogTags.AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013118 r.task.taskId, r.shortComponentName);
13119
13120 r.startFreezingScreenLocked(r.app, 0);
13121
13122 try {
13123 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
13124 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
Dianne Hackborn871ecdc2009-12-11 15:24:33 -080013125 changes, !andResume, mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013126 // Note: don't need to call pauseIfSleepingLocked() here, because
13127 // the caller will only pass in 'andResume' if this activity is
13128 // currently resumed, which implies we aren't sleeping.
13129 } catch (RemoteException e) {
13130 return false;
13131 }
13132
13133 if (andResume) {
13134 r.results = null;
13135 r.newIntents = null;
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -070013136 reportResumedActivityLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013137 }
13138
13139 return true;
13140 }
13141
13142 /**
13143 * Make sure the given activity matches the current configuration. Returns
13144 * false if the activity had to be destroyed. Returns true if the
13145 * configuration is the same, or the activity will remain running as-is
13146 * for whatever reason. Ensures the HistoryRecord is updated with the
13147 * correct configuration and all other bookkeeping is handled.
13148 */
13149 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
13150 int globalChanges) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013151 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13152 "Ensuring correct configuration: " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013153
13154 // Short circuit: if the two configurations are the exact same
13155 // object (the common case), then there is nothing to do.
13156 Configuration newConfig = mConfiguration;
13157 if (r.configuration == newConfig) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013158 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13159 "Configuration unchanged in " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013160 return true;
13161 }
13162
13163 // We don't worry about activities that are finishing.
13164 if (r.finishing) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013165 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013166 "Configuration doesn't matter in finishing " + r);
13167 r.stopFreezingScreenLocked(false);
13168 return true;
13169 }
13170
13171 // Okay we now are going to make this activity have the new config.
13172 // But then we need to figure out how it needs to deal with that.
13173 Configuration oldConfig = r.configuration;
13174 r.configuration = newConfig;
13175
13176 // If the activity isn't currently running, just leave the new
13177 // configuration and it will pick that up next time it starts.
13178 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013179 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013180 "Configuration doesn't matter not running " + r);
13181 r.stopFreezingScreenLocked(false);
13182 return true;
13183 }
13184
13185 // If the activity isn't persistent, there is a chance we will
13186 // need to restart it.
13187 if (!r.persistent) {
13188
13189 // Figure out what has changed between the two configurations.
13190 int changes = oldConfig.diff(newConfig);
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013191 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
13192 Log.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013193 + Integer.toHexString(changes) + ", handles=0x"
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013194 + Integer.toHexString(r.info.configChanges)
13195 + ", newConfig=" + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013196 }
13197 if ((changes&(~r.info.configChanges)) != 0) {
13198 // Aha, the activity isn't handling the change, so DIE DIE DIE.
13199 r.configChangeFlags |= changes;
13200 r.startFreezingScreenLocked(r.app, globalChanges);
13201 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013202 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13203 "Switch is destroying non-running " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013204 destroyActivityLocked(r, true);
13205 } else if (r.state == ActivityState.PAUSING) {
13206 // A little annoying: we are waiting for this activity to
13207 // finish pausing. Let's not do anything now, but just
13208 // flag that it needs to be restarted when done pausing.
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013209 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13210 "Switch is skipping already pausing " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013211 r.configDestroy = true;
13212 return true;
13213 } else if (r.state == ActivityState.RESUMED) {
13214 // Try to optimize this case: the configuration is changing
13215 // and we need to restart the top, resumed activity.
13216 // Instead of doing the normal handshaking, just say
13217 // "restart!".
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013218 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13219 "Switch is restarting resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013220 relaunchActivityLocked(r, r.configChangeFlags, true);
13221 r.configChangeFlags = 0;
13222 } else {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013223 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13224 "Switch is restarting non-resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013225 relaunchActivityLocked(r, r.configChangeFlags, false);
13226 r.configChangeFlags = 0;
13227 }
13228
13229 // All done... tell the caller we weren't able to keep this
13230 // activity around.
13231 return false;
13232 }
13233 }
13234
13235 // Default case: the activity can handle this new configuration, so
13236 // hand it over. Note that we don't need to give it the new
13237 // configuration, since we always send configuration changes to all
13238 // process when they happen so it can just use whatever configuration
13239 // it last got.
13240 if (r.app != null && r.app.thread != null) {
13241 try {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013242 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending new config to " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013243 r.app.thread.scheduleActivityConfigurationChanged(r);
13244 } catch (RemoteException e) {
13245 // If process died, whatever.
13246 }
13247 }
13248 r.stopFreezingScreenLocked(false);
13249
13250 return true;
13251 }
13252
13253 /**
13254 * Save the locale. You must be inside a synchronized (this) block.
13255 */
13256 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
13257 if(isDiff) {
13258 SystemProperties.set("user.language", l.getLanguage());
13259 SystemProperties.set("user.region", l.getCountry());
13260 }
13261
13262 if(isPersist) {
13263 SystemProperties.set("persist.sys.language", l.getLanguage());
13264 SystemProperties.set("persist.sys.country", l.getCountry());
13265 SystemProperties.set("persist.sys.localevar", l.getVariant());
13266 }
13267 }
13268
13269 // =========================================================
13270 // LIFETIME MANAGEMENT
13271 // =========================================================
13272
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013273 private final int computeOomAdjLocked(ProcessRecord app, int hiddenAdj,
13274 ProcessRecord TOP_APP, boolean recursed) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013275 if (mAdjSeq == app.adjSeq) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013276 // This adjustment has already been computed. If we are calling
13277 // from the top, we may have already computed our adjustment with
13278 // an earlier hidden adjustment that isn't really for us... if
13279 // so, use the new hidden adjustment.
13280 if (!recursed && app.hidden) {
13281 app.curAdj = hiddenAdj;
13282 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013283 return app.curAdj;
13284 }
13285
13286 if (app.thread == null) {
13287 app.adjSeq = mAdjSeq;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013288 app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013289 return (app.curAdj=EMPTY_APP_ADJ);
13290 }
13291
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013292 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
13293 // The max adjustment doesn't allow this app to be anything
13294 // below foreground, so it is not worth doing work for it.
13295 app.adjType = "fixed";
13296 app.adjSeq = mAdjSeq;
13297 app.curRawAdj = app.maxAdj;
13298 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
13299 return (app.curAdj=app.maxAdj);
13300 }
13301
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013302 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013303 app.adjSource = null;
13304 app.adjTarget = null;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013305 app.empty = false;
13306 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013307
The Android Open Source Project4df24232009-03-05 14:34:35 -080013308 // Determine the importance of the process, starting with most
13309 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013310 int adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013311 int schedGroup;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013312 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013313 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013314 // The last app on the list is the foreground app.
13315 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013316 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013317 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013318 } else if (app.instrumentationClass != null) {
13319 // Don't want to kill running instrumentation.
13320 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013321 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013322 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013323 } else if (app.persistentActivities > 0) {
13324 // Special persistent activities... shouldn't be used these days.
13325 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013326 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013327 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013328 } else if (app.curReceiver != null ||
13329 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
13330 // An app that is currently receiving a broadcast also
13331 // counts as being in the foreground.
13332 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013333 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013334 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013335 } else if (app.executingServices.size() > 0) {
13336 // An app that is currently executing a service callback also
13337 // counts as being in the foreground.
13338 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013339 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013340 app.adjType = "exec-service";
13341 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013342 // The user is aware of this app, so make it visible.
13343 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013344 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013345 app.adjType = "foreground-service";
13346 } else if (app.forcingToForeground != null) {
13347 // The user is aware of this app, so make it visible.
13348 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013349 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013350 app.adjType = "force-foreground";
13351 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080013352 } else if (app == mHomeProcess) {
13353 // This process is hosting what we currently consider to be the
13354 // home app, so we don't want to let it go into the background.
13355 adj = HOME_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013356 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013357 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013358 } else if ((N=app.activities.size()) != 0) {
13359 // This app is in the background with paused activities.
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013360 app.hidden = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013361 adj = hiddenAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013362 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013363 app.adjType = "bg-activities";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013364 N = app.activities.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013365 for (int j=0; j<N; j++) {
13366 if (((HistoryRecord)app.activities.get(j)).visible) {
13367 // This app has a visible activity!
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013368 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013369 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013370 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013371 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013372 break;
13373 }
13374 }
13375 } else {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013376 // A very not-needed process. If this is lower in the lru list,
13377 // we will push it in to the empty bucket.
13378 app.hidden = true;
13379 app.empty = true;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013380 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013381 adj = hiddenAdj;
13382 app.adjType = "bg-empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013383 }
13384
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013385 //Log.i(TAG, "OOM " + app + ": initial adj=" + adj);
13386
The Android Open Source Project4df24232009-03-05 14:34:35 -080013387 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013388 // there are applications dependent on our services or providers, but
13389 // this gives us a baseline and makes sure we don't get into an
13390 // infinite recursion.
13391 app.adjSeq = mAdjSeq;
13392 app.curRawAdj = adj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013393
Christopher Tate6fa95972009-06-05 18:43:55 -070013394 if (mBackupTarget != null && app == mBackupTarget.app) {
13395 // If possible we want to avoid killing apps while they're being backed up
13396 if (adj > BACKUP_APP_ADJ) {
13397 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
13398 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013399 app.adjType = "backup";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013400 app.hidden = false;
Christopher Tate6fa95972009-06-05 18:43:55 -070013401 }
13402 }
13403
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013404 if (app.services.size() != 0 && (adj > FOREGROUND_APP_ADJ
13405 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013406 final long now = SystemClock.uptimeMillis();
13407 // This process is more important if the top activity is
13408 // bound to the service.
13409 Iterator jt = app.services.iterator();
13410 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13411 ServiceRecord s = (ServiceRecord)jt.next();
13412 if (s.startRequested) {
13413 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
13414 // This service has seen some activity within
13415 // recent memory, so we will keep its process ahead
13416 // of the background processes.
13417 if (adj > SECONDARY_SERVER_ADJ) {
13418 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013419 app.adjType = "started-services";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013420 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013421 }
13422 }
13423 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013424 if (s.connections.size() > 0 && (adj > FOREGROUND_APP_ADJ
13425 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013426 Iterator<ConnectionRecord> kt
13427 = s.connections.values().iterator();
13428 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13429 // XXX should compute this based on the max of
13430 // all connected clients.
13431 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013432 if (cr.binding.client == app) {
13433 // Binding to ourself is not interesting.
13434 continue;
13435 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013436 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
13437 ProcessRecord client = cr.binding.client;
13438 int myHiddenAdj = hiddenAdj;
13439 if (myHiddenAdj > client.hiddenAdj) {
13440 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
13441 myHiddenAdj = client.hiddenAdj;
13442 } else {
13443 myHiddenAdj = VISIBLE_APP_ADJ;
13444 }
13445 }
13446 int clientAdj = computeOomAdjLocked(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013447 client, myHiddenAdj, TOP_APP, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013448 if (adj > clientAdj) {
13449 adj = clientAdj > VISIBLE_APP_ADJ
13450 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013451 if (!client.hidden) {
13452 app.hidden = false;
13453 }
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013454 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013455 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13456 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013457 app.adjSource = cr.binding.client;
13458 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013459 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013460 if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
13461 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13462 schedGroup = Process.THREAD_GROUP_DEFAULT;
13463 }
13464 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013465 }
13466 HistoryRecord a = cr.activity;
13467 //if (a != null) {
13468 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13469 //}
13470 if (a != null && adj > FOREGROUND_APP_ADJ &&
13471 (a.state == ActivityState.RESUMED
13472 || a.state == ActivityState.PAUSING)) {
13473 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013474 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013475 app.hidden = false;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013476 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013477 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13478 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013479 app.adjSource = a;
13480 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013481 }
13482 }
13483 }
13484 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013485
13486 // Finally, f this process has active services running in it, we
13487 // would like to avoid killing it unless it would prevent the current
13488 // application from running. By default we put the process in
13489 // with the rest of the background processes; as we scan through
13490 // its services we may bump it up from there.
13491 if (adj > hiddenAdj) {
13492 adj = hiddenAdj;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013493 app.hidden = false;
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013494 app.adjType = "bg-services";
13495 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013496 }
13497
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013498 if (app.pubProviders.size() != 0 && (adj > FOREGROUND_APP_ADJ
13499 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013500 Iterator jt = app.pubProviders.values().iterator();
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013501 while (jt.hasNext() && (adj > FOREGROUND_APP_ADJ
13502 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013503 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13504 if (cpr.clients.size() != 0) {
13505 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13506 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13507 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013508 if (client == app) {
13509 // Being our own client is not interesting.
13510 continue;
13511 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013512 int myHiddenAdj = hiddenAdj;
13513 if (myHiddenAdj > client.hiddenAdj) {
13514 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13515 myHiddenAdj = client.hiddenAdj;
13516 } else {
13517 myHiddenAdj = FOREGROUND_APP_ADJ;
13518 }
13519 }
13520 int clientAdj = computeOomAdjLocked(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013521 client, myHiddenAdj, TOP_APP, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013522 if (adj > clientAdj) {
13523 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013524 ? clientAdj : FOREGROUND_APP_ADJ;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013525 if (!client.hidden) {
13526 app.hidden = false;
13527 }
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013528 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013529 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13530 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013531 app.adjSource = client;
13532 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013533 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013534 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13535 schedGroup = Process.THREAD_GROUP_DEFAULT;
13536 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013537 }
13538 }
13539 // If the provider has external (non-framework) process
13540 // dependencies, ensure that its adjustment is at least
13541 // FOREGROUND_APP_ADJ.
13542 if (cpr.externals != 0) {
13543 if (adj > FOREGROUND_APP_ADJ) {
13544 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013545 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013546 app.hidden = false;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013547 app.adjType = "provider";
13548 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013549 }
13550 }
13551 }
13552 }
13553
13554 app.curRawAdj = adj;
13555
13556 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13557 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13558 if (adj > app.maxAdj) {
13559 adj = app.maxAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013560 if (app.maxAdj <= VISIBLE_APP_ADJ) {
13561 schedGroup = Process.THREAD_GROUP_DEFAULT;
13562 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013563 }
13564
13565 app.curAdj = adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013566 app.curSchedGroup = schedGroup;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013567
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013568 return adj;
13569 }
13570
13571 /**
13572 * Ask a given process to GC right now.
13573 */
13574 final void performAppGcLocked(ProcessRecord app) {
13575 try {
13576 app.lastRequestedGc = SystemClock.uptimeMillis();
13577 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013578 if (app.reportLowMemory) {
13579 app.reportLowMemory = false;
13580 app.thread.scheduleLowMemory();
13581 } else {
13582 app.thread.processInBackground();
13583 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013584 }
13585 } catch (Exception e) {
13586 // whatever.
13587 }
13588 }
13589
13590 /**
13591 * Returns true if things are idle enough to perform GCs.
13592 */
13593 private final boolean canGcNow() {
13594 return mParallelBroadcasts.size() == 0
13595 && mOrderedBroadcasts.size() == 0
13596 && (mSleeping || (mResumedActivity != null &&
13597 mResumedActivity.idle));
13598 }
13599
13600 /**
13601 * Perform GCs on all processes that are waiting for it, but only
13602 * if things are idle.
13603 */
13604 final void performAppGcsLocked() {
13605 final int N = mProcessesToGc.size();
13606 if (N <= 0) {
13607 return;
13608 }
13609 if (canGcNow()) {
13610 while (mProcessesToGc.size() > 0) {
13611 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013612 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13613 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13614 <= SystemClock.uptimeMillis()) {
13615 // To avoid spamming the system, we will GC processes one
13616 // at a time, waiting a few seconds between each.
13617 performAppGcLocked(proc);
13618 scheduleAppGcsLocked();
13619 return;
13620 } else {
13621 // It hasn't been long enough since we last GCed this
13622 // process... put it in the list to wait for its time.
13623 addProcessToGcListLocked(proc);
13624 break;
13625 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013626 }
13627 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013628
13629 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013630 }
13631 }
13632
13633 /**
13634 * If all looks good, perform GCs on all processes waiting for them.
13635 */
13636 final void performAppGcsIfAppropriateLocked() {
13637 if (canGcNow()) {
13638 performAppGcsLocked();
13639 return;
13640 }
13641 // Still not idle, wait some more.
13642 scheduleAppGcsLocked();
13643 }
13644
13645 /**
13646 * Schedule the execution of all pending app GCs.
13647 */
13648 final void scheduleAppGcsLocked() {
13649 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013650
13651 if (mProcessesToGc.size() > 0) {
13652 // Schedule a GC for the time to the next process.
13653 ProcessRecord proc = mProcessesToGc.get(0);
13654 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13655
13656 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13657 long now = SystemClock.uptimeMillis();
13658 if (when < (now+GC_TIMEOUT)) {
13659 when = now + GC_TIMEOUT;
13660 }
13661 mHandler.sendMessageAtTime(msg, when);
13662 }
13663 }
13664
13665 /**
13666 * Add a process to the array of processes waiting to be GCed. Keeps the
13667 * list in sorted order by the last GC time. The process can't already be
13668 * on the list.
13669 */
13670 final void addProcessToGcListLocked(ProcessRecord proc) {
13671 boolean added = false;
13672 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13673 if (mProcessesToGc.get(i).lastRequestedGc <
13674 proc.lastRequestedGc) {
13675 added = true;
13676 mProcessesToGc.add(i+1, proc);
13677 break;
13678 }
13679 }
13680 if (!added) {
13681 mProcessesToGc.add(0, proc);
13682 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013683 }
13684
13685 /**
13686 * Set up to ask a process to GC itself. This will either do it
13687 * immediately, or put it on the list of processes to gc the next
13688 * time things are idle.
13689 */
13690 final void scheduleAppGcLocked(ProcessRecord app) {
13691 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013692 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013693 return;
13694 }
13695 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013696 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013697 scheduleAppGcsLocked();
13698 }
13699 }
13700
13701 private final boolean updateOomAdjLocked(
13702 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13703 app.hiddenAdj = hiddenAdj;
13704
13705 if (app.thread == null) {
13706 return true;
13707 }
13708
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013709 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013710
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013711 if ((app.pid != 0 && app.pid != MY_PID) || Process.supportsProcesses()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013712 if (app.curRawAdj != app.setRawAdj) {
13713 if (app.curRawAdj > FOREGROUND_APP_ADJ
13714 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13715 // If this app is transitioning from foreground to
13716 // non-foreground, have it do a gc.
13717 scheduleAppGcLocked(app);
13718 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13719 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13720 // Likewise do a gc when an app is moving in to the
13721 // background (such as a service stopping).
13722 scheduleAppGcLocked(app);
13723 }
13724 app.setRawAdj = app.curRawAdj;
13725 }
13726 if (adj != app.setAdj) {
13727 if (Process.setOomAdj(app.pid, adj)) {
13728 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13729 TAG, "Set app " + app.processName +
13730 " oom adj to " + adj);
13731 app.setAdj = adj;
13732 } else {
13733 return false;
13734 }
13735 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013736 if (app.setSchedGroup != app.curSchedGroup) {
13737 app.setSchedGroup = app.curSchedGroup;
13738 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13739 "Setting process group of " + app.processName
13740 + " to " + app.curSchedGroup);
13741 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013742 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013743 try {
13744 Process.setProcessGroup(app.pid, app.curSchedGroup);
13745 } catch (Exception e) {
13746 Log.w(TAG, "Failed setting process group of " + app.pid
13747 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013748 e.printStackTrace();
13749 } finally {
13750 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013751 }
13752 }
13753 if (false) {
13754 if (app.thread != null) {
13755 try {
13756 app.thread.setSchedulingGroup(app.curSchedGroup);
13757 } catch (RemoteException e) {
13758 }
13759 }
13760 }
13761 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013762 }
13763
13764 return true;
13765 }
13766
13767 private final HistoryRecord resumedAppLocked() {
13768 HistoryRecord resumedActivity = mResumedActivity;
13769 if (resumedActivity == null || resumedActivity.app == null) {
13770 resumedActivity = mPausingActivity;
13771 if (resumedActivity == null || resumedActivity.app == null) {
13772 resumedActivity = topRunningActivityLocked(null);
13773 }
13774 }
13775 return resumedActivity;
13776 }
13777
13778 private final boolean updateOomAdjLocked(ProcessRecord app) {
13779 final HistoryRecord TOP_ACT = resumedAppLocked();
13780 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13781 int curAdj = app.curAdj;
13782 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13783 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13784
13785 mAdjSeq++;
13786
13787 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13788 if (res) {
13789 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13790 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13791 if (nowHidden != wasHidden) {
13792 // Changed to/from hidden state, so apps after it in the LRU
13793 // list may also be changed.
13794 updateOomAdjLocked();
13795 }
13796 }
13797 return res;
13798 }
13799
13800 private final boolean updateOomAdjLocked() {
13801 boolean didOomAdj = true;
13802 final HistoryRecord TOP_ACT = resumedAppLocked();
13803 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13804
13805 if (false) {
13806 RuntimeException e = new RuntimeException();
13807 e.fillInStackTrace();
13808 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13809 }
13810
13811 mAdjSeq++;
13812
13813 // First try updating the OOM adjustment for each of the
13814 // application processes based on their current state.
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013815 int i = mLruProcesses.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013816 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13817 while (i > 0) {
13818 i--;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013819 ProcessRecord app = mLruProcesses.get(i);
13820 //Log.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013821 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013822 if (curHiddenAdj < EMPTY_APP_ADJ
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013823 && app.curAdj == curHiddenAdj) {
13824 curHiddenAdj++;
13825 }
13826 } else {
13827 didOomAdj = false;
13828 }
13829 }
13830
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013831 // If we return false, we will fall back on killing processes to
13832 // have a fixed limit. Do this if a limit has been requested; else
13833 // only return false if one of the adjustments failed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013834 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13835 }
13836
13837 private final void trimApplications() {
13838 synchronized (this) {
13839 int i;
13840
13841 // First remove any unused application processes whose package
13842 // has been removed.
13843 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13844 final ProcessRecord app = mRemovedProcesses.get(i);
13845 if (app.activities.size() == 0
13846 && app.curReceiver == null && app.services.size() == 0) {
13847 Log.i(
13848 TAG, "Exiting empty application process "
13849 + app.processName + " ("
13850 + (app.thread != null ? app.thread.asBinder() : null)
13851 + ")\n");
13852 if (app.pid > 0 && app.pid != MY_PID) {
13853 Process.killProcess(app.pid);
13854 } else {
13855 try {
13856 app.thread.scheduleExit();
13857 } catch (Exception e) {
13858 // Ignore exceptions.
13859 }
13860 }
13861 cleanUpApplicationRecordLocked(app, false, -1);
13862 mRemovedProcesses.remove(i);
13863
13864 if (app.persistent) {
13865 if (app.persistent) {
13866 addAppLocked(app.info);
13867 }
13868 }
13869 }
13870 }
13871
13872 // Now try updating the OOM adjustment for each of the
13873 // application processes based on their current state.
13874 // If the setOomAdj() API is not supported, then go with our
13875 // back-up plan...
13876 if (!updateOomAdjLocked()) {
13877
13878 // Count how many processes are running services.
13879 int numServiceProcs = 0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013880 for (i=mLruProcesses.size()-1; i>=0; i--) {
13881 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013882
13883 if (app.persistent || app.services.size() != 0
13884 || app.curReceiver != null
13885 || app.persistentActivities > 0) {
13886 // Don't count processes holding services against our
13887 // maximum process count.
13888 if (localLOGV) Log.v(
13889 TAG, "Not trimming app " + app + " with services: "
13890 + app.services);
13891 numServiceProcs++;
13892 }
13893 }
13894
13895 int curMaxProcs = mProcessLimit;
13896 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13897 if (mAlwaysFinishActivities) {
13898 curMaxProcs = 1;
13899 }
13900 curMaxProcs += numServiceProcs;
13901
13902 // Quit as many processes as we can to get down to the desired
13903 // process count. First remove any processes that no longer
13904 // have activites running in them.
13905 for ( i=0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013906 i<mLruProcesses.size()
13907 && mLruProcesses.size() > curMaxProcs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013908 i++) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013909 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013910 // Quit an application only if it is not currently
13911 // running any activities.
13912 if (!app.persistent && app.activities.size() == 0
13913 && app.curReceiver == null && app.services.size() == 0) {
13914 Log.i(
13915 TAG, "Exiting empty application process "
13916 + app.processName + " ("
13917 + (app.thread != null ? app.thread.asBinder() : null)
13918 + ")\n");
13919 if (app.pid > 0 && app.pid != MY_PID) {
13920 Process.killProcess(app.pid);
13921 } else {
13922 try {
13923 app.thread.scheduleExit();
13924 } catch (Exception e) {
13925 // Ignore exceptions.
13926 }
13927 }
13928 // todo: For now we assume the application is not buggy
13929 // or evil, and will quit as a result of our request.
13930 // Eventually we need to drive this off of the death
13931 // notification, and kill the process if it takes too long.
13932 cleanUpApplicationRecordLocked(app, false, i);
13933 i--;
13934 }
13935 }
13936
13937 // If we still have too many processes, now from the least
13938 // recently used process we start finishing activities.
13939 if (Config.LOGV) Log.v(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013940 TAG, "*** NOW HAVE " + mLruProcesses.size() +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013941 " of " + curMaxProcs + " processes");
13942 for ( i=0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013943 i<mLruProcesses.size()
13944 && mLruProcesses.size() > curMaxProcs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013945 i++) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013946 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013947 // Quit the application only if we have a state saved for
13948 // all of its activities.
13949 boolean canQuit = !app.persistent && app.curReceiver == null
13950 && app.services.size() == 0
13951 && app.persistentActivities == 0;
13952 int NUMA = app.activities.size();
13953 int j;
13954 if (Config.LOGV) Log.v(
13955 TAG, "Looking to quit " + app.processName);
13956 for (j=0; j<NUMA && canQuit; j++) {
13957 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13958 if (Config.LOGV) Log.v(
13959 TAG, " " + r.intent.getComponent().flattenToShortString()
13960 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13961 canQuit = (r.haveState || !r.stateNotNeeded)
13962 && !r.visible && r.stopped;
13963 }
13964 if (canQuit) {
13965 // Finish all of the activities, and then the app itself.
13966 for (j=0; j<NUMA; j++) {
13967 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13968 if (!r.finishing) {
13969 destroyActivityLocked(r, false);
13970 }
13971 r.resultTo = null;
13972 }
13973 Log.i(TAG, "Exiting application process "
13974 + app.processName + " ("
13975 + (app.thread != null ? app.thread.asBinder() : null)
13976 + ")\n");
13977 if (app.pid > 0 && app.pid != MY_PID) {
13978 Process.killProcess(app.pid);
13979 } else {
13980 try {
13981 app.thread.scheduleExit();
13982 } catch (Exception e) {
13983 // Ignore exceptions.
13984 }
13985 }
13986 // todo: For now we assume the application is not buggy
13987 // or evil, and will quit as a result of our request.
13988 // Eventually we need to drive this off of the death
13989 // notification, and kill the process if it takes too long.
13990 cleanUpApplicationRecordLocked(app, false, i);
13991 i--;
13992 //dump();
13993 }
13994 }
13995
13996 }
13997
13998 int curMaxActivities = MAX_ACTIVITIES;
13999 if (mAlwaysFinishActivities) {
14000 curMaxActivities = 1;
14001 }
14002
14003 // Finally, if there are too many activities now running, try to
14004 // finish as many as we can to get back down to the limit.
14005 for ( i=0;
14006 i<mLRUActivities.size()
14007 && mLRUActivities.size() > curMaxActivities;
14008 i++) {
14009 final HistoryRecord r
14010 = (HistoryRecord)mLRUActivities.get(i);
14011
14012 // We can finish this one if we have its icicle saved and
14013 // it is not persistent.
14014 if ((r.haveState || !r.stateNotNeeded) && !r.visible
14015 && r.stopped && !r.persistent && !r.finishing) {
14016 final int origSize = mLRUActivities.size();
14017 destroyActivityLocked(r, true);
14018
14019 // This will remove it from the LRU list, so keep
14020 // our index at the same value. Note that this check to
14021 // see if the size changes is just paranoia -- if
14022 // something unexpected happens, we don't want to end up
14023 // in an infinite loop.
14024 if (origSize > mLRUActivities.size()) {
14025 i--;
14026 }
14027 }
14028 }
14029 }
14030 }
14031
14032 /** This method sends the specified signal to each of the persistent apps */
14033 public void signalPersistentProcesses(int sig) throws RemoteException {
14034 if (sig != Process.SIGNAL_USR1) {
14035 throw new SecurityException("Only SIGNAL_USR1 is allowed");
14036 }
14037
14038 synchronized (this) {
14039 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
14040 != PackageManager.PERMISSION_GRANTED) {
14041 throw new SecurityException("Requires permission "
14042 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
14043 }
14044
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014045 for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
14046 ProcessRecord r = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014047 if (r.thread != null && r.persistent) {
14048 Process.sendSignal(r.pid, sig);
14049 }
14050 }
14051 }
14052 }
14053
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014054 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014055 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014056
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014057 try {
14058 synchronized (this) {
14059 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
14060 // its own permission.
14061 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
14062 != PackageManager.PERMISSION_GRANTED) {
14063 throw new SecurityException("Requires permission "
14064 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014065 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014066
14067 if (start && fd == null) {
14068 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014069 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014070
14071 ProcessRecord proc = null;
14072 try {
14073 int pid = Integer.parseInt(process);
14074 synchronized (mPidsSelfLocked) {
14075 proc = mPidsSelfLocked.get(pid);
14076 }
14077 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014078 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014079
14080 if (proc == null) {
14081 HashMap<String, SparseArray<ProcessRecord>> all
14082 = mProcessNames.getMap();
14083 SparseArray<ProcessRecord> procs = all.get(process);
14084 if (procs != null && procs.size() > 0) {
14085 proc = procs.valueAt(0);
14086 }
14087 }
14088
14089 if (proc == null || proc.thread == null) {
14090 throw new IllegalArgumentException("Unknown process: " + process);
14091 }
14092
14093 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
14094 if (isSecure) {
14095 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
14096 throw new SecurityException("Process not debuggable: " + proc);
14097 }
14098 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014099
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014100 proc.thread.profilerControl(start, path, fd);
14101 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014102 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014103 }
14104 } catch (RemoteException e) {
14105 throw new IllegalStateException("Process disappeared");
14106 } finally {
14107 if (fd != null) {
14108 try {
14109 fd.close();
14110 } catch (IOException e) {
14111 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014112 }
14113 }
14114 }
14115
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014116 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
14117 public void monitor() {
14118 synchronized (this) { }
14119 }
14120}