blob: 266f2132557620ddce3f7239ac87df8baf71b80f [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;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070074import android.os.Debug;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080075import android.os.Environment;
76import android.os.FileUtils;
77import android.os.Handler;
78import android.os.IBinder;
79import android.os.IPermissionController;
80import android.os.Looper;
81import android.os.Message;
82import android.os.Parcel;
83import android.os.ParcelFileDescriptor;
84import android.os.PowerManager;
85import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070086import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087import android.os.RemoteException;
88import android.os.ServiceManager;
89import android.os.SystemClock;
90import android.os.SystemProperties;
91import android.provider.Checkin;
92import android.provider.Settings;
93import android.text.TextUtils;
94import android.util.Config;
95import android.util.EventLog;
96import android.util.Log;
97import android.util.PrintWriterPrinter;
98import android.util.SparseArray;
99import android.view.Gravity;
100import android.view.LayoutInflater;
101import android.view.View;
102import android.view.WindowManager;
103import android.view.WindowManagerPolicy;
104
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800105import java.io.File;
106import java.io.FileDescriptor;
107import java.io.FileInputStream;
108import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200109import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800110import java.io.PrintWriter;
111import java.lang.IllegalStateException;
112import java.lang.ref.WeakReference;
113import java.util.ArrayList;
114import java.util.HashMap;
115import java.util.HashSet;
116import java.util.Iterator;
117import java.util.List;
118import java.util.Locale;
119import java.util.Map;
120
121public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
122 static final String TAG = "ActivityManager";
123 static final boolean DEBUG = false;
124 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
125 static final boolean DEBUG_SWITCH = localLOGV || false;
126 static final boolean DEBUG_TASKS = localLOGV || false;
127 static final boolean DEBUG_PAUSE = localLOGV || false;
128 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
129 static final boolean DEBUG_TRANSITION = localLOGV || false;
130 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700131 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132 static final boolean DEBUG_SERVICE = localLOGV || false;
133 static final boolean DEBUG_VISBILITY = localLOGV || false;
134 static final boolean DEBUG_PROCESSES = localLOGV || false;
Dianne Hackborna1e989b2009-09-01 19:54:29 -0700135 static final boolean DEBUG_PROVIDER = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700137 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate436344a2009-09-30 16:17:37 -0700138 static final boolean DEBUG_BACKUP = localLOGV || false;
Dianne Hackborndc6b6352009-09-30 14:20:09 -0700139 static final boolean DEBUG_CONFIGURATION = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 static final boolean VALIDATE_TOKENS = false;
141 static final boolean SHOW_ACTIVITY_START_TIME = true;
142
143 // Control over CPU and battery monitoring.
144 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
145 static final boolean MONITOR_CPU_USAGE = true;
146 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
147 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
148 static final boolean MONITOR_THREAD_CPU_USAGE = false;
149
Dianne Hackborn1655be42009-05-08 14:29:01 -0700150 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700151 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700152
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 private static final String SYSTEM_SECURE = "ro.secure";
154
155 // This is the maximum number of application processes we would like
156 // to have running. Due to the asynchronous nature of things, we can
157 // temporarily go beyond this limit.
158 static final int MAX_PROCESSES = 2;
159
160 // Set to false to leave processes running indefinitely, relying on
161 // the kernel killing them as resources are required.
162 static final boolean ENFORCE_PROCESS_LIMIT = false;
163
164 // This is the maximum number of activities that we would like to have
165 // running at a given time.
166 static final int MAX_ACTIVITIES = 20;
167
168 // Maximum number of recent tasks that we can remember.
169 static final int MAX_RECENT_TASKS = 20;
170
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700171 // Amount of time after a call to stopAppSwitches() during which we will
172 // prevent further untrusted switches from happening.
173 static final long APP_SWITCH_DELAY_TIME = 5*1000;
174
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800175 // How long until we reset a task when the user returns to it. Currently
176 // 30 minutes.
177 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
178
179 // Set to true to disable the icon that is shown while a new activity
180 // is being started.
181 static final boolean SHOW_APP_STARTING_ICON = true;
182
183 // How long we wait until giving up on the last activity to pause. This
184 // is short because it directly impacts the responsiveness of starting the
185 // next activity.
186 static final int PAUSE_TIMEOUT = 500;
187
188 /**
189 * How long we can hold the launch wake lock before giving up.
190 */
191 static final int LAUNCH_TIMEOUT = 10*1000;
192
193 // How long we wait for a launched process to attach to the activity manager
194 // before we decide it's never going to come up for real.
195 static final int PROC_START_TIMEOUT = 10*1000;
196
197 // How long we wait until giving up on the last activity telling us it
198 // is idle.
199 static final int IDLE_TIMEOUT = 10*1000;
200
201 // How long to wait after going idle before forcing apps to GC.
202 static final int GC_TIMEOUT = 5*1000;
203
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700204 // The minimum amount of time between successive GC requests for a process.
205 static final int GC_MIN_INTERVAL = 60*1000;
206
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800207 // How long we wait until giving up on an activity telling us it has
208 // finished destroying itself.
209 static final int DESTROY_TIMEOUT = 10*1000;
210
211 // How long we allow a receiver to run before giving up on it.
212 static final int BROADCAST_TIMEOUT = 10*1000;
213
214 // How long we wait for a service to finish executing.
215 static final int SERVICE_TIMEOUT = 20*1000;
216
217 // How long a service needs to be running until restarting its process
218 // is no longer considered to be a relaunch of the service.
219 static final int SERVICE_RESTART_DURATION = 5*1000;
220
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700221 // How long a service needs to be running until it will start back at
222 // SERVICE_RESTART_DURATION after being killed.
223 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
224
225 // Multiplying factor to increase restart duration time by, for each time
226 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
227 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
228
229 // The minimum amount of time between restarting services that we allow.
230 // That is, when multiple services are restarting, we won't allow each
231 // to restart less than this amount of time from the last one.
232 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
233
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234 // Maximum amount of time for there to be no activity on a service before
235 // we consider it non-essential and allow its process to go on the
236 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700237 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238
239 // How long we wait until we timeout on key dispatching.
240 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
241
242 // The minimum time we allow between crashes, for us to consider this
243 // application to be bad and stop and its services and reject broadcasts.
244 static final int MIN_CRASH_INTERVAL = 60*1000;
245
246 // How long we wait until we timeout on key dispatching during instrumentation.
247 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
248
249 // OOM adjustments for processes in various states:
250
251 // This is a process without anything currently running in it. Definitely
252 // the first to go! Value set in system/rootdir/init.rc on startup.
253 // This value is initalized in the constructor, careful when refering to
254 // this static variable externally.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800255 static final int EMPTY_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256
257 // This is a process only hosting activities that are not visible,
258 // so it can be killed without any disruption. Value set in
259 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800260 static final int HIDDEN_APP_MAX_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 static int HIDDEN_APP_MIN_ADJ;
262
The Android Open Source Project4df24232009-03-05 14:34:35 -0800263 // This is a process holding the home application -- we want to try
264 // avoiding killing it, even if it would normally be in the background,
265 // because the user interacts with it so much.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800266 static final int HOME_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800267
Christopher Tate6fa95972009-06-05 18:43:55 -0700268 // This is a process currently hosting a backup operation. Killing it
269 // is not entirely fatal but is generally a bad idea.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800270 static final int BACKUP_APP_ADJ;
Christopher Tate6fa95972009-06-05 18:43:55 -0700271
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800272 // This is a process holding a secondary server -- killing it will not
273 // have much of an impact as far as the user is concerned. Value set in
274 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800275 static final int SECONDARY_SERVER_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276
277 // This is a process only hosting activities that are visible to the
278 // user, so we'd prefer they don't disappear. Value set in
279 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800280 static final int VISIBLE_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800281
282 // This is the process running the current foreground app. We'd really
283 // rather not kill it! Value set in system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800284 static final int FOREGROUND_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800285
286 // This is a process running a core server, such as telephony. Definitely
287 // don't want to kill it, but doing so is not completely fatal.
288 static final int CORE_SERVER_ADJ = -12;
289
290 // The system process runs at the default adjustment.
291 static final int SYSTEM_ADJ = -16;
292
293 // Memory pages are 4K.
294 static final int PAGE_SIZE = 4*1024;
295
Jacek Surazski82a73df2009-06-17 14:33:18 +0200296 // System property defining error report receiver for system apps
297 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
298
299 // System property defining default error report receiver
300 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
301
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800302 // Corresponding memory levels for above adjustments.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800303 static final int EMPTY_APP_MEM;
304 static final int HIDDEN_APP_MEM;
305 static final int HOME_APP_MEM;
306 static final int BACKUP_APP_MEM;
307 static final int SECONDARY_SERVER_MEM;
308 static final int VISIBLE_APP_MEM;
309 static final int FOREGROUND_APP_MEM;
310
311 // The minimum number of hidden apps we want to be able to keep around,
312 // without empty apps being able to push them out of memory.
313 static final int MIN_HIDDEN_APPS = 2;
314
315 // We put empty content processes after any hidden processes that have
316 // been idle for less than 30 seconds.
317 static final long CONTENT_APP_IDLE_OFFSET = 30*1000;
318
319 // We put empty content processes after any hidden processes that have
320 // been idle for less than 60 seconds.
321 static final long EMPTY_APP_IDLE_OFFSET = 60*1000;
322
323 static {
324 // These values are set in system/rootdir/init.rc on startup.
325 FOREGROUND_APP_ADJ =
326 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
327 VISIBLE_APP_ADJ =
328 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
329 SECONDARY_SERVER_ADJ =
330 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
331 BACKUP_APP_ADJ =
332 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
333 HOME_APP_ADJ =
334 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
335 HIDDEN_APP_MIN_ADJ =
336 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
337 EMPTY_APP_ADJ =
338 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
339 HIDDEN_APP_MAX_ADJ = EMPTY_APP_ADJ-1;
340 FOREGROUND_APP_MEM =
341 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
342 VISIBLE_APP_MEM =
343 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
344 SECONDARY_SERVER_MEM =
345 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
346 BACKUP_APP_MEM =
347 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
348 HOME_APP_MEM =
349 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
350 HIDDEN_APP_MEM =
351 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
352 EMPTY_APP_MEM =
353 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
354 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355
356 final int MY_PID;
357
358 static final String[] EMPTY_STRING_ARRAY = new String[0];
359
360 enum ActivityState {
361 INITIALIZING,
362 RESUMED,
363 PAUSING,
364 PAUSED,
365 STOPPING,
366 STOPPED,
367 FINISHING,
368 DESTROYING,
369 DESTROYED
370 }
371
372 /**
373 * The back history of all previous (and possibly still
374 * running) activities. It contains HistoryRecord objects.
375 */
376 final ArrayList mHistory = new ArrayList();
377
378 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700379 * Description of a request to start a new activity, which has been held
380 * due to app switches being disabled.
381 */
382 class PendingActivityLaunch {
383 HistoryRecord r;
384 HistoryRecord sourceRecord;
385 Uri[] grantedUriPermissions;
386 int grantedMode;
387 boolean onlyIfNeeded;
388 }
389
390 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
391 = new ArrayList<PendingActivityLaunch>();
392
393 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394 * List of all active broadcasts that are to be executed immediately
395 * (without waiting for another broadcast to finish). Currently this only
396 * contains broadcasts to registered receivers, to avoid spinning up
397 * a bunch of processes to execute IntentReceiver components.
398 */
399 final ArrayList<BroadcastRecord> mParallelBroadcasts
400 = new ArrayList<BroadcastRecord>();
401
402 /**
403 * List of all active broadcasts that are to be executed one at a time.
404 * The object at the top of the list is the currently activity broadcasts;
405 * those after it are waiting for the top to finish..
406 */
407 final ArrayList<BroadcastRecord> mOrderedBroadcasts
408 = new ArrayList<BroadcastRecord>();
409
410 /**
Dianne Hackborn12527f92009-11-11 17:39:50 -0800411 * Historical data of past broadcasts, for debugging.
412 */
413 static final int MAX_BROADCAST_HISTORY = 100;
414 final BroadcastRecord[] mBroadcastHistory
415 = new BroadcastRecord[MAX_BROADCAST_HISTORY];
416
417 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418 * Set when we current have a BROADCAST_INTENT_MSG in flight.
419 */
420 boolean mBroadcastsScheduled = false;
421
422 /**
423 * Set to indicate whether to issue an onUserLeaving callback when a
424 * newly launched activity is being brought in front of us.
425 */
426 boolean mUserLeaving = false;
427
428 /**
429 * When we are in the process of pausing an activity, before starting the
430 * next one, this variable holds the activity that is currently being paused.
431 */
432 HistoryRecord mPausingActivity = null;
433
434 /**
435 * Current activity that is resumed, or null if there is none.
436 */
437 HistoryRecord mResumedActivity = null;
438
439 /**
440 * Activity we have told the window manager to have key focus.
441 */
442 HistoryRecord mFocusedActivity = null;
443
444 /**
445 * This is the last activity that we put into the paused state. This is
446 * used to determine if we need to do an activity transition while sleeping,
447 * when we normally hold the top activity paused.
448 */
449 HistoryRecord mLastPausedActivity = null;
450
451 /**
452 * List of activities that are waiting for a new activity
453 * to become visible before completing whatever operation they are
454 * supposed to do.
455 */
456 final ArrayList mWaitingVisibleActivities = new ArrayList();
457
458 /**
459 * List of activities that are ready to be stopped, but waiting
460 * for the next activity to settle down before doing so. It contains
461 * HistoryRecord objects.
462 */
463 final ArrayList<HistoryRecord> mStoppingActivities
464 = new ArrayList<HistoryRecord>();
465
466 /**
Dianne Hackbornbfe319e2009-09-21 00:34:05 -0700467 * Animations that for the current transition have requested not to
468 * be considered for the transition animation.
469 */
470 final ArrayList<HistoryRecord> mNoAnimActivities
471 = new ArrayList<HistoryRecord>();
472
473 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800474 * List of intents that were used to start the most recent tasks.
475 */
476 final ArrayList<TaskRecord> mRecentTasks
477 = new ArrayList<TaskRecord>();
478
479 /**
480 * List of activities that are ready to be finished, but waiting
481 * for the previous activity to settle down before doing so. It contains
482 * HistoryRecord objects.
483 */
484 final ArrayList mFinishingActivities = new ArrayList();
485
486 /**
487 * All of the applications we currently have running organized by name.
488 * The keys are strings of the application package name (as
489 * returned by the package manager), and the keys are ApplicationRecord
490 * objects.
491 */
492 final ProcessMap<ProcessRecord> mProcessNames
493 = new ProcessMap<ProcessRecord>();
494
495 /**
496 * The last time that various processes have crashed.
497 */
498 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
499
500 /**
501 * Set of applications that we consider to be bad, and will reject
502 * incoming broadcasts from (which the user has no control over).
503 * Processes are added to this set when they have crashed twice within
504 * a minimum amount of time; they are removed from it when they are
505 * later restarted (hopefully due to some user action). The value is the
506 * time it was added to the list.
507 */
508 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
509
510 /**
511 * All of the processes we currently have running organized by pid.
512 * The keys are the pid running the application.
513 *
514 * <p>NOTE: This object is protected by its own lock, NOT the global
515 * activity manager lock!
516 */
517 final SparseArray<ProcessRecord> mPidsSelfLocked
518 = new SparseArray<ProcessRecord>();
519
520 /**
521 * All of the processes that have been forced to be foreground. The key
522 * is the pid of the caller who requested it (we hold a death
523 * link on it).
524 */
525 abstract class ForegroundToken implements IBinder.DeathRecipient {
526 int pid;
527 IBinder token;
528 }
529 final SparseArray<ForegroundToken> mForegroundProcesses
530 = new SparseArray<ForegroundToken>();
531
532 /**
533 * List of records for processes that someone had tried to start before the
534 * system was ready. We don't start them at that point, but ensure they
535 * are started by the time booting is complete.
536 */
537 final ArrayList<ProcessRecord> mProcessesOnHold
538 = new ArrayList<ProcessRecord>();
539
540 /**
541 * List of records for processes that we have started and are waiting
542 * for them to call back. This is really only needed when running in
543 * single processes mode, in which case we do not have a unique pid for
544 * each process.
545 */
546 final ArrayList<ProcessRecord> mStartingProcesses
547 = new ArrayList<ProcessRecord>();
548
549 /**
550 * List of persistent applications that are in the process
551 * of being started.
552 */
553 final ArrayList<ProcessRecord> mPersistentStartingProcesses
554 = new ArrayList<ProcessRecord>();
555
556 /**
557 * Processes that are being forcibly torn down.
558 */
559 final ArrayList<ProcessRecord> mRemovedProcesses
560 = new ArrayList<ProcessRecord>();
561
562 /**
563 * List of running applications, sorted by recent usage.
564 * The first entry in the list is the least recently used.
565 * It contains ApplicationRecord objects. This list does NOT include
566 * any persistent application records (since we never want to exit them).
567 */
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800568 final ArrayList<ProcessRecord> mLruProcesses
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800569 = new ArrayList<ProcessRecord>();
570
571 /**
572 * List of processes that should gc as soon as things are idle.
573 */
574 final ArrayList<ProcessRecord> mProcessesToGc
575 = new ArrayList<ProcessRecord>();
576
577 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800578 * This is the process holding what we currently consider to be
579 * the "home" activity.
580 */
581 private ProcessRecord mHomeProcess;
582
583 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800584 * List of running activities, sorted by recent usage.
585 * The first entry in the list is the least recently used.
586 * It contains HistoryRecord objects.
587 */
588 private final ArrayList mLRUActivities = new ArrayList();
589
590 /**
591 * Set of PendingResultRecord objects that are currently active.
592 */
593 final HashSet mPendingResultRecords = new HashSet();
594
595 /**
596 * Set of IntentSenderRecord objects that are currently active.
597 */
598 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
599 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
600
601 /**
602 * Intent broadcast that we have tried to start, but are
603 * waiting for its application's process to be created. We only
604 * need one (instead of a list) because we always process broadcasts
605 * one at a time, so no others can be started while waiting for this
606 * one.
607 */
608 BroadcastRecord mPendingBroadcast = null;
609
610 /**
611 * Keeps track of all IIntentReceivers that have been registered for
612 * broadcasts. Hash keys are the receiver IBinder, hash value is
613 * a ReceiverList.
614 */
615 final HashMap mRegisteredReceivers = new HashMap();
616
617 /**
618 * Resolver for broadcast intents to registered receivers.
619 * Holds BroadcastFilter (subclass of IntentFilter).
620 */
621 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
622 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
623 @Override
624 protected boolean allowFilterResult(
625 BroadcastFilter filter, List<BroadcastFilter> dest) {
626 IBinder target = filter.receiverList.receiver.asBinder();
627 for (int i=dest.size()-1; i>=0; i--) {
628 if (dest.get(i).receiverList.receiver.asBinder() == target) {
629 return false;
630 }
631 }
632 return true;
633 }
634 };
635
636 /**
637 * State of all active sticky broadcasts. Keys are the action of the
638 * sticky Intent, values are an ArrayList of all broadcasted intents with
639 * that action (which should usually be one).
640 */
641 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
642 new HashMap<String, ArrayList<Intent>>();
643
644 /**
645 * All currently running services.
646 */
647 final HashMap<ComponentName, ServiceRecord> mServices =
648 new HashMap<ComponentName, ServiceRecord>();
649
650 /**
651 * All currently running services indexed by the Intent used to start them.
652 */
653 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
654 new HashMap<Intent.FilterComparison, ServiceRecord>();
655
656 /**
657 * All currently bound service connections. Keys are the IBinder of
658 * the client's IServiceConnection.
659 */
660 final HashMap<IBinder, ConnectionRecord> mServiceConnections
661 = new HashMap<IBinder, ConnectionRecord>();
662
663 /**
664 * List of services that we have been asked to start,
665 * but haven't yet been able to. It is used to hold start requests
666 * while waiting for their corresponding application thread to get
667 * going.
668 */
669 final ArrayList<ServiceRecord> mPendingServices
670 = new ArrayList<ServiceRecord>();
671
672 /**
673 * List of services that are scheduled to restart following a crash.
674 */
675 final ArrayList<ServiceRecord> mRestartingServices
676 = new ArrayList<ServiceRecord>();
677
678 /**
679 * List of services that are in the process of being stopped.
680 */
681 final ArrayList<ServiceRecord> mStoppingServices
682 = new ArrayList<ServiceRecord>();
683
684 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700685 * Backup/restore process management
686 */
687 String mBackupAppName = null;
688 BackupRecord mBackupTarget = null;
689
690 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800691 * List of PendingThumbnailsRecord objects of clients who are still
692 * waiting to receive all of the thumbnails for a task.
693 */
694 final ArrayList mPendingThumbnails = new ArrayList();
695
696 /**
697 * List of HistoryRecord objects that have been finished and must
698 * still report back to a pending thumbnail receiver.
699 */
700 final ArrayList mCancelledThumbnails = new ArrayList();
701
702 /**
703 * All of the currently running global content providers. Keys are a
704 * string containing the provider name and values are a
705 * ContentProviderRecord object containing the data about it. Note
706 * that a single provider may be published under multiple names, so
707 * there may be multiple entries here for a single one in mProvidersByClass.
708 */
709 final HashMap mProvidersByName = new HashMap();
710
711 /**
712 * All of the currently running global content providers. Keys are a
713 * string containing the provider's implementation class and values are a
714 * ContentProviderRecord object containing the data about it.
715 */
716 final HashMap mProvidersByClass = new HashMap();
717
718 /**
719 * List of content providers who have clients waiting for them. The
720 * application is currently being launched and the provider will be
721 * removed from this list once it is published.
722 */
723 final ArrayList mLaunchingProviders = new ArrayList();
724
725 /**
726 * Global set of specific Uri permissions that have been granted.
727 */
728 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
729 = new SparseArray<HashMap<Uri, UriPermission>>();
730
731 /**
732 * Thread-local storage used to carry caller permissions over through
733 * indirect content-provider access.
734 * @see #ActivityManagerService.openContentUri()
735 */
736 private class Identity {
737 public int pid;
738 public int uid;
739
740 Identity(int _pid, int _uid) {
741 pid = _pid;
742 uid = _uid;
743 }
744 }
745 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
746
747 /**
748 * All information we have collected about the runtime performance of
749 * any user id that can impact battery performance.
750 */
751 final BatteryStatsService mBatteryStatsService;
752
753 /**
754 * information about component usage
755 */
756 final UsageStatsService mUsageStatsService;
757
758 /**
759 * Current configuration information. HistoryRecord objects are given
760 * a reference to this object to indicate which configuration they are
761 * currently running in, so this object must be kept immutable.
762 */
763 Configuration mConfiguration = new Configuration();
764
765 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700766 * Hardware-reported OpenGLES version.
767 */
768 final int GL_ES_VERSION;
769
770 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 * List of initialization arguments to pass to all processes when binding applications to them.
772 * For example, references to the commonly used services.
773 */
774 HashMap<String, IBinder> mAppBindArgs;
775
776 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700777 * Temporary to avoid allocations. Protected by main lock.
778 */
779 final StringBuilder mStringBuilder = new StringBuilder(256);
780
781 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800782 * Used to control how we initialize the service.
783 */
784 boolean mStartRunning = false;
785 ComponentName mTopComponent;
786 String mTopAction;
787 String mTopData;
788 boolean mSystemReady = false;
789 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700790 boolean mWaitingUpdate = false;
791 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792
793 Context mContext;
794
795 int mFactoryTest;
796
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700797 boolean mCheckedForSetup;
798
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700800 * The time at which we will allow normal application switches again,
801 * after a call to {@link #stopAppSwitches()}.
802 */
803 long mAppSwitchesAllowedTime;
804
805 /**
806 * This is set to true after the first switch after mAppSwitchesAllowedTime
807 * is set; any switches after that will clear the time.
808 */
809 boolean mDidAppSwitch;
810
811 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800812 * Set while we are wanting to sleep, to prevent any
813 * activities from being started/resumed.
814 */
815 boolean mSleeping = false;
816
817 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700818 * Set if we are shutting down the system, similar to sleeping.
819 */
820 boolean mShuttingDown = false;
821
822 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800823 * Set when the system is going to sleep, until we have
824 * successfully paused the current activity and released our wake lock.
825 * At that point the system is allowed to actually sleep.
826 */
827 PowerManager.WakeLock mGoingToSleep;
828
829 /**
830 * We don't want to allow the device to go to sleep while in the process
831 * of launching an activity. This is primarily to allow alarm intent
832 * receivers to launch an activity and get that to run before the device
833 * goes back to sleep.
834 */
835 PowerManager.WakeLock mLaunchingActivity;
836
837 /**
838 * Task identifier that activities are currently being started
839 * in. Incremented each time a new task is created.
840 * todo: Replace this with a TokenSpace class that generates non-repeating
841 * integers that won't wrap.
842 */
843 int mCurTask = 1;
844
845 /**
846 * Current sequence id for oom_adj computation traversal.
847 */
848 int mAdjSeq = 0;
849
850 /**
851 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
852 * is set, indicating the user wants processes started in such a way
853 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
854 * running in each process (thus no pre-initialized process, etc).
855 */
856 boolean mSimpleProcessManagement = false;
857
858 /**
859 * System monitoring: number of processes that died since the last
860 * N procs were started.
861 */
862 int[] mProcDeaths = new int[20];
863
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700864 /**
865 * This is set if we had to do a delayed dexopt of an app before launching
866 * it, to increasing the ANR timeouts in that case.
867 */
868 boolean mDidDexOpt;
869
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800870 String mDebugApp = null;
871 boolean mWaitForDebugger = false;
872 boolean mDebugTransient = false;
873 String mOrigDebugApp = null;
874 boolean mOrigWaitForDebugger = false;
875 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700876 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800877
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700878 final RemoteCallbackList<IActivityWatcher> mWatchers
879 = new RemoteCallbackList<IActivityWatcher>();
880
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800881 /**
882 * Callback of last caller to {@link #requestPss}.
883 */
884 Runnable mRequestPssCallback;
885
886 /**
887 * Remaining processes for which we are waiting results from the last
888 * call to {@link #requestPss}.
889 */
890 final ArrayList<ProcessRecord> mRequestPssList
891 = new ArrayList<ProcessRecord>();
892
893 /**
894 * Runtime statistics collection thread. This object's lock is used to
895 * protect all related state.
896 */
897 final Thread mProcessStatsThread;
898
899 /**
900 * Used to collect process stats when showing not responding dialog.
901 * Protected by mProcessStatsThread.
902 */
903 final ProcessStats mProcessStats = new ProcessStats(
904 MONITOR_THREAD_CPU_USAGE);
905 long mLastCpuTime = 0;
906 long mLastWriteTime = 0;
907
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700908 long mInitialStartTime = 0;
909
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800910 /**
911 * Set to true after the system has finished booting.
912 */
913 boolean mBooted = false;
914
915 int mProcessLimit = 0;
916
917 WindowManagerService mWindowManager;
918
919 static ActivityManagerService mSelf;
920 static ActivityThread mSystemThread;
921
922 private final class AppDeathRecipient implements IBinder.DeathRecipient {
923 final ProcessRecord mApp;
924 final int mPid;
925 final IApplicationThread mAppThread;
926
927 AppDeathRecipient(ProcessRecord app, int pid,
928 IApplicationThread thread) {
929 if (localLOGV) Log.v(
930 TAG, "New death recipient " + this
931 + " for thread " + thread.asBinder());
932 mApp = app;
933 mPid = pid;
934 mAppThread = thread;
935 }
936
937 public void binderDied() {
938 if (localLOGV) Log.v(
939 TAG, "Death received in " + this
940 + " for thread " + mAppThread.asBinder());
941 removeRequestedPss(mApp);
942 synchronized(ActivityManagerService.this) {
943 appDiedLocked(mApp, mPid, mAppThread);
944 }
945 }
946 }
947
948 static final int SHOW_ERROR_MSG = 1;
949 static final int SHOW_NOT_RESPONDING_MSG = 2;
950 static final int SHOW_FACTORY_ERROR_MSG = 3;
951 static final int UPDATE_CONFIGURATION_MSG = 4;
952 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
953 static final int WAIT_FOR_DEBUGGER_MSG = 6;
954 static final int BROADCAST_INTENT_MSG = 7;
955 static final int BROADCAST_TIMEOUT_MSG = 8;
956 static final int PAUSE_TIMEOUT_MSG = 9;
957 static final int IDLE_TIMEOUT_MSG = 10;
958 static final int IDLE_NOW_MSG = 11;
959 static final int SERVICE_TIMEOUT_MSG = 12;
960 static final int UPDATE_TIME_ZONE = 13;
961 static final int SHOW_UID_ERROR_MSG = 14;
962 static final int IM_FEELING_LUCKY_MSG = 15;
963 static final int LAUNCH_TIMEOUT_MSG = 16;
964 static final int DESTROY_TIMEOUT_MSG = 17;
965 static final int SERVICE_ERROR_MSG = 18;
966 static final int RESUME_TOP_ACTIVITY_MSG = 19;
967 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700968 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700969 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800970
971 AlertDialog mUidAlert;
972
973 final Handler mHandler = new Handler() {
974 //public Handler() {
975 // if (localLOGV) Log.v(TAG, "Handler started!");
976 //}
977
978 public void handleMessage(Message msg) {
979 switch (msg.what) {
980 case SHOW_ERROR_MSG: {
981 HashMap data = (HashMap) msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800982 synchronized (ActivityManagerService.this) {
983 ProcessRecord proc = (ProcessRecord)data.get("app");
984 if (proc != null && proc.crashDialog != null) {
985 Log.e(TAG, "App already has crash dialog: " + proc);
986 return;
987 }
988 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700989 if (!mSleeping && !mShuttingDown) {
Dan Egnorb7f03672009-12-09 16:22:32 -0800990 Dialog d = new AppErrorDialog(mContext, res, proc);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800991 d.show();
992 proc.crashDialog = d;
993 } else {
994 // The device is asleep, so just pretend that the user
995 // saw a crash dialog and hit "force quit".
996 res.set(0);
997 }
998 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700999
1000 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001001 } break;
1002 case SHOW_NOT_RESPONDING_MSG: {
1003 synchronized (ActivityManagerService.this) {
1004 HashMap data = (HashMap) msg.obj;
1005 ProcessRecord proc = (ProcessRecord)data.get("app");
1006 if (proc != null && proc.anrDialog != null) {
1007 Log.e(TAG, "App already has anr dialog: " + proc);
1008 return;
1009 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001010
1011 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
1012 null, null, 0, null, null, null,
1013 false, false, MY_PID, Process.SYSTEM_UID);
1014
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001015 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
1016 mContext, proc, (HistoryRecord)data.get("activity"));
1017 d.show();
1018 proc.anrDialog = d;
1019 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001020
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001021 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001022 } break;
1023 case SHOW_FACTORY_ERROR_MSG: {
1024 Dialog d = new FactoryErrorDialog(
1025 mContext, msg.getData().getCharSequence("msg"));
1026 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001027 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001028 } break;
1029 case UPDATE_CONFIGURATION_MSG: {
1030 final ContentResolver resolver = mContext.getContentResolver();
1031 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1032 } break;
1033 case GC_BACKGROUND_PROCESSES_MSG: {
1034 synchronized (ActivityManagerService.this) {
1035 performAppGcsIfAppropriateLocked();
1036 }
1037 } break;
1038 case WAIT_FOR_DEBUGGER_MSG: {
1039 synchronized (ActivityManagerService.this) {
1040 ProcessRecord app = (ProcessRecord)msg.obj;
1041 if (msg.arg1 != 0) {
1042 if (!app.waitedForDebugger) {
1043 Dialog d = new AppWaitingForDebuggerDialog(
1044 ActivityManagerService.this,
1045 mContext, app);
1046 app.waitDialog = d;
1047 app.waitedForDebugger = true;
1048 d.show();
1049 }
1050 } else {
1051 if (app.waitDialog != null) {
1052 app.waitDialog.dismiss();
1053 app.waitDialog = null;
1054 }
1055 }
1056 }
1057 } break;
1058 case BROADCAST_INTENT_MSG: {
1059 if (DEBUG_BROADCAST) Log.v(
1060 TAG, "Received BROADCAST_INTENT_MSG");
1061 processNextBroadcast(true);
1062 } break;
1063 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001064 if (mDidDexOpt) {
1065 mDidDexOpt = false;
1066 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1067 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1068 return;
1069 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001070 broadcastTimeout();
1071 } break;
1072 case PAUSE_TIMEOUT_MSG: {
1073 IBinder token = (IBinder)msg.obj;
1074 // We don't at this point know if the activity is fullscreen,
1075 // so we need to be conservative and assume it isn't.
1076 Log.w(TAG, "Activity pause timeout for " + token);
1077 activityPaused(token, null, true);
1078 } break;
1079 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001080 if (mDidDexOpt) {
1081 mDidDexOpt = false;
1082 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1083 nmsg.obj = msg.obj;
1084 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1085 return;
1086 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001087 // We don't at this point know if the activity is fullscreen,
1088 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001089 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001090 Log.w(TAG, "Activity idle timeout for " + token);
Dianne Hackborne88846e2009-09-30 21:34:25 -07001091 activityIdleInternal(token, true, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001092 } break;
1093 case DESTROY_TIMEOUT_MSG: {
1094 IBinder token = (IBinder)msg.obj;
1095 // We don't at this point know if the activity is fullscreen,
1096 // so we need to be conservative and assume it isn't.
1097 Log.w(TAG, "Activity destroy timeout for " + token);
1098 activityDestroyed(token);
1099 } break;
1100 case IDLE_NOW_MSG: {
1101 IBinder token = (IBinder)msg.obj;
Dianne Hackborne88846e2009-09-30 21:34:25 -07001102 activityIdle(token, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103 } break;
1104 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001105 if (mDidDexOpt) {
1106 mDidDexOpt = false;
1107 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1108 nmsg.obj = msg.obj;
1109 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1110 return;
1111 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001112 serviceTimeout((ProcessRecord)msg.obj);
1113 } break;
1114 case UPDATE_TIME_ZONE: {
1115 synchronized (ActivityManagerService.this) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001116 for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
1117 ProcessRecord r = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001118 if (r.thread != null) {
1119 try {
1120 r.thread.updateTimeZone();
1121 } catch (RemoteException ex) {
1122 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1123 }
1124 }
1125 }
1126 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001127 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 case SHOW_UID_ERROR_MSG: {
1129 // XXX This is a temporary dialog, no need to localize.
1130 AlertDialog d = new BaseErrorDialog(mContext);
1131 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1132 d.setCancelable(false);
1133 d.setTitle("System UIDs Inconsistent");
1134 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1135 d.setButton("I'm Feeling Lucky",
1136 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1137 mUidAlert = d;
1138 d.show();
1139 } break;
1140 case IM_FEELING_LUCKY_MSG: {
1141 if (mUidAlert != null) {
1142 mUidAlert.dismiss();
1143 mUidAlert = null;
1144 }
1145 } break;
1146 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001147 if (mDidDexOpt) {
1148 mDidDexOpt = false;
1149 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1150 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1151 return;
1152 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001153 synchronized (ActivityManagerService.this) {
1154 if (mLaunchingActivity.isHeld()) {
1155 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1156 mLaunchingActivity.release();
1157 }
1158 }
1159 } break;
1160 case SERVICE_ERROR_MSG: {
1161 ServiceRecord srv = (ServiceRecord)msg.obj;
1162 // This needs to be *un*synchronized to avoid deadlock.
1163 Checkin.logEvent(mContext.getContentResolver(),
1164 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1165 srv.name.toShortString());
1166 } break;
1167 case RESUME_TOP_ACTIVITY_MSG: {
1168 synchronized (ActivityManagerService.this) {
1169 resumeTopActivityLocked(null);
1170 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001171 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001172 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001173 if (mDidDexOpt) {
1174 mDidDexOpt = false;
1175 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1176 nmsg.obj = msg.obj;
1177 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1178 return;
1179 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001180 ProcessRecord app = (ProcessRecord)msg.obj;
1181 synchronized (ActivityManagerService.this) {
1182 processStartTimedOutLocked(app);
1183 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001184 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001185 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1186 synchronized (ActivityManagerService.this) {
1187 doPendingActivityLaunchesLocked(true);
1188 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001189 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001190 case KILL_APPLICATION_MSG: {
1191 synchronized (ActivityManagerService.this) {
1192 int uid = msg.arg1;
1193 boolean restart = (msg.arg2 == 1);
1194 String pkg = (String) msg.obj;
1195 uninstallPackageLocked(pkg, uid, restart);
1196 }
1197 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001198 }
1199 }
1200 };
1201
1202 public static void setSystemProcess() {
1203 try {
1204 ActivityManagerService m = mSelf;
1205
1206 ServiceManager.addService("activity", m);
1207 ServiceManager.addService("meminfo", new MemBinder(m));
1208 if (MONITOR_CPU_USAGE) {
1209 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1210 }
1211 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1212 ServiceManager.addService("activity.services", new ServicesBinder(m));
1213 ServiceManager.addService("activity.senders", new SendersBinder(m));
1214 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1215 ServiceManager.addService("permission", new PermissionController(m));
1216
1217 ApplicationInfo info =
1218 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001219 "android", STOCK_PM_FLAGS);
Mike Cleron432b7132009-09-24 15:28:29 -07001220 mSystemThread.installSystemApplicationInfo(info);
1221
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001222 synchronized (mSelf) {
1223 ProcessRecord app = mSelf.newProcessRecordLocked(
1224 mSystemThread.getApplicationThread(), info,
1225 info.processName);
1226 app.persistent = true;
1227 app.pid = Process.myPid();
1228 app.maxAdj = SYSTEM_ADJ;
1229 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1230 synchronized (mSelf.mPidsSelfLocked) {
1231 mSelf.mPidsSelfLocked.put(app.pid, app);
1232 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001233 mSelf.updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001234 }
1235 } catch (PackageManager.NameNotFoundException e) {
1236 throw new RuntimeException(
1237 "Unable to find android system package", e);
1238 }
1239 }
1240
1241 public void setWindowManager(WindowManagerService wm) {
1242 mWindowManager = wm;
1243 }
1244
1245 public static final Context main(int factoryTest) {
1246 AThread thr = new AThread();
1247 thr.start();
1248
1249 synchronized (thr) {
1250 while (thr.mService == null) {
1251 try {
1252 thr.wait();
1253 } catch (InterruptedException e) {
1254 }
1255 }
1256 }
1257
1258 ActivityManagerService m = thr.mService;
1259 mSelf = m;
1260 ActivityThread at = ActivityThread.systemMain();
1261 mSystemThread = at;
1262 Context context = at.getSystemContext();
1263 m.mContext = context;
1264 m.mFactoryTest = factoryTest;
1265 PowerManager pm =
1266 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1267 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1268 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1269 m.mLaunchingActivity.setReferenceCounted(false);
1270
1271 m.mBatteryStatsService.publish(context);
1272 m.mUsageStatsService.publish(context);
1273
1274 synchronized (thr) {
1275 thr.mReady = true;
1276 thr.notifyAll();
1277 }
1278
1279 m.startRunning(null, null, null, null);
1280
1281 return context;
1282 }
1283
1284 public static ActivityManagerService self() {
1285 return mSelf;
1286 }
1287
1288 static class AThread extends Thread {
1289 ActivityManagerService mService;
1290 boolean mReady = false;
1291
1292 public AThread() {
1293 super("ActivityManager");
1294 }
1295
1296 public void run() {
1297 Looper.prepare();
1298
1299 android.os.Process.setThreadPriority(
1300 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1301
1302 ActivityManagerService m = new ActivityManagerService();
1303
1304 synchronized (this) {
1305 mService = m;
1306 notifyAll();
1307 }
1308
1309 synchronized (this) {
1310 while (!mReady) {
1311 try {
1312 wait();
1313 } catch (InterruptedException e) {
1314 }
1315 }
1316 }
1317
1318 Looper.loop();
1319 }
1320 }
1321
1322 static class BroadcastsBinder extends Binder {
1323 ActivityManagerService mActivityManagerService;
1324 BroadcastsBinder(ActivityManagerService activityManagerService) {
1325 mActivityManagerService = activityManagerService;
1326 }
1327
1328 @Override
1329 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1330 mActivityManagerService.dumpBroadcasts(pw);
1331 }
1332 }
1333
1334 static class ServicesBinder extends Binder {
1335 ActivityManagerService mActivityManagerService;
1336 ServicesBinder(ActivityManagerService activityManagerService) {
1337 mActivityManagerService = activityManagerService;
1338 }
1339
1340 @Override
1341 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1342 mActivityManagerService.dumpServices(pw);
1343 }
1344 }
1345
1346 static class SendersBinder extends Binder {
1347 ActivityManagerService mActivityManagerService;
1348 SendersBinder(ActivityManagerService activityManagerService) {
1349 mActivityManagerService = activityManagerService;
1350 }
1351
1352 @Override
1353 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1354 mActivityManagerService.dumpSenders(pw);
1355 }
1356 }
1357
1358 static class ProvidersBinder extends Binder {
1359 ActivityManagerService mActivityManagerService;
1360 ProvidersBinder(ActivityManagerService activityManagerService) {
1361 mActivityManagerService = activityManagerService;
1362 }
1363
1364 @Override
1365 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1366 mActivityManagerService.dumpProviders(pw);
1367 }
1368 }
1369
1370 static class MemBinder extends Binder {
1371 ActivityManagerService mActivityManagerService;
1372 MemBinder(ActivityManagerService activityManagerService) {
1373 mActivityManagerService = activityManagerService;
1374 }
1375
1376 @Override
1377 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1378 ActivityManagerService service = mActivityManagerService;
1379 ArrayList<ProcessRecord> procs;
1380 synchronized (mActivityManagerService) {
1381 if (args != null && args.length > 0
1382 && args[0].charAt(0) != '-') {
1383 procs = new ArrayList<ProcessRecord>();
1384 int pid = -1;
1385 try {
1386 pid = Integer.parseInt(args[0]);
1387 } catch (NumberFormatException e) {
1388
1389 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001390 for (int i=service.mLruProcesses.size()-1; i>=0; i--) {
1391 ProcessRecord proc = service.mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001392 if (proc.pid == pid) {
1393 procs.add(proc);
1394 } else if (proc.processName.equals(args[0])) {
1395 procs.add(proc);
1396 }
1397 }
1398 if (procs.size() <= 0) {
1399 pw.println("No process found for: " + args[0]);
1400 return;
1401 }
1402 } else {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001403 procs = service.mLruProcesses;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001404 }
1405 }
1406 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1407 }
1408 }
1409
1410 static class CpuBinder extends Binder {
1411 ActivityManagerService mActivityManagerService;
1412 CpuBinder(ActivityManagerService activityManagerService) {
1413 mActivityManagerService = activityManagerService;
1414 }
1415
1416 @Override
1417 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1418 synchronized (mActivityManagerService.mProcessStatsThread) {
1419 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1420 }
1421 }
1422 }
1423
1424 private ActivityManagerService() {
1425 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1426 if (v != null && Integer.getInteger(v) != 0) {
1427 mSimpleProcessManagement = true;
1428 }
1429 v = System.getenv("ANDROID_DEBUG_APP");
1430 if (v != null) {
1431 mSimpleProcessManagement = true;
1432 }
1433
Dianne Hackborn2c6c5e62009-10-08 17:55:49 -07001434 Log.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
1435
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001436 MY_PID = Process.myPid();
1437
1438 File dataDir = Environment.getDataDirectory();
1439 File systemDir = new File(dataDir, "system");
1440 systemDir.mkdirs();
1441 mBatteryStatsService = new BatteryStatsService(new File(
1442 systemDir, "batterystats.bin").toString());
1443 mBatteryStatsService.getActiveStatistics().readLocked();
1444 mBatteryStatsService.getActiveStatistics().writeLocked();
1445
1446 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001447 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448
Jack Palevichb90d28c2009-07-22 15:35:24 -07001449 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1450 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1451
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001452 mConfiguration.makeDefault();
1453 mProcessStats.init();
1454
1455 // Add ourself to the Watchdog monitors.
1456 Watchdog.getInstance().addMonitor(this);
1457
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001458 mProcessStatsThread = new Thread("ProcessStats") {
1459 public void run() {
1460 while (true) {
1461 try {
1462 try {
1463 synchronized(this) {
1464 final long now = SystemClock.uptimeMillis();
1465 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1466 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1467 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1468 // + ", write delay=" + nextWriteDelay);
1469 if (nextWriteDelay < nextCpuDelay) {
1470 nextCpuDelay = nextWriteDelay;
1471 }
1472 if (nextCpuDelay > 0) {
1473 this.wait(nextCpuDelay);
1474 }
1475 }
1476 } catch (InterruptedException e) {
1477 }
1478
1479 updateCpuStatsNow();
1480 } catch (Exception e) {
1481 Log.e(TAG, "Unexpected exception collecting process stats", e);
1482 }
1483 }
1484 }
1485 };
1486 mProcessStatsThread.start();
1487 }
1488
1489 @Override
1490 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1491 throws RemoteException {
1492 try {
1493 return super.onTransact(code, data, reply, flags);
1494 } catch (RuntimeException e) {
1495 // The activity manager only throws security exceptions, so let's
1496 // log all others.
1497 if (!(e instanceof SecurityException)) {
1498 Log.e(TAG, "Activity Manager Crash", e);
1499 }
1500 throw e;
1501 }
1502 }
1503
1504 void updateCpuStats() {
1505 synchronized (mProcessStatsThread) {
1506 final long now = SystemClock.uptimeMillis();
1507 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1508 mProcessStatsThread.notify();
1509 }
1510 }
1511 }
1512
1513 void updateCpuStatsNow() {
1514 synchronized (mProcessStatsThread) {
1515 final long now = SystemClock.uptimeMillis();
1516 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001517
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001518 if (MONITOR_CPU_USAGE &&
1519 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1520 mLastCpuTime = now;
1521 haveNewCpuStats = true;
1522 mProcessStats.update();
1523 //Log.i(TAG, mProcessStats.printCurrentState());
1524 //Log.i(TAG, "Total CPU usage: "
1525 // + mProcessStats.getTotalCpuPercent() + "%");
1526
1527 // Log the cpu usage if the property is set.
1528 if ("true".equals(SystemProperties.get("events.cpu"))) {
1529 int user = mProcessStats.getLastUserTime();
1530 int system = mProcessStats.getLastSystemTime();
1531 int iowait = mProcessStats.getLastIoWaitTime();
1532 int irq = mProcessStats.getLastIrqTime();
1533 int softIrq = mProcessStats.getLastSoftIrqTime();
1534 int idle = mProcessStats.getLastIdleTime();
1535
1536 int total = user + system + iowait + irq + softIrq + idle;
1537 if (total == 0) total = 1;
1538
Doug Zongker2bec3d42009-12-04 12:52:44 -08001539 EventLog.writeEvent(EventLogTags.CPU,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001540 ((user+system+iowait+irq+softIrq) * 100) / total,
1541 (user * 100) / total,
1542 (system * 100) / total,
1543 (iowait * 100) / total,
1544 (irq * 100) / total,
1545 (softIrq * 100) / total);
1546 }
1547 }
1548
Amith Yamasanie43530a2009-08-21 13:11:37 -07001549 long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
Amith Yamasani819f9282009-06-24 23:18:15 -07001550 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001551 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001552 synchronized(mPidsSelfLocked) {
1553 if (haveNewCpuStats) {
1554 if (mBatteryStatsService.isOnBattery()) {
1555 final int N = mProcessStats.countWorkingStats();
1556 for (int i=0; i<N; i++) {
1557 ProcessStats.Stats st
1558 = mProcessStats.getWorkingStats(i);
1559 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1560 if (pr != null) {
1561 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1562 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001563 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001564 } else {
1565 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001566 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001567 if (ps != null) {
1568 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001569 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001570 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001571 }
1572 }
1573 }
1574 }
1575 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001576
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001577 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1578 mLastWriteTime = now;
1579 mBatteryStatsService.getActiveStatistics().writeLocked();
1580 }
1581 }
1582 }
1583 }
1584
1585 /**
1586 * Initialize the application bind args. These are passed to each
1587 * process when the bindApplication() IPC is sent to the process. They're
1588 * lazily setup to make sure the services are running when they're asked for.
1589 */
1590 private HashMap<String, IBinder> getCommonServicesLocked() {
1591 if (mAppBindArgs == null) {
1592 mAppBindArgs = new HashMap<String, IBinder>();
1593
1594 // Setup the application init args
1595 mAppBindArgs.put("package", ServiceManager.getService("package"));
1596 mAppBindArgs.put("window", ServiceManager.getService("window"));
1597 mAppBindArgs.put(Context.ALARM_SERVICE,
1598 ServiceManager.getService(Context.ALARM_SERVICE));
1599 }
1600 return mAppBindArgs;
1601 }
1602
1603 private final void setFocusedActivityLocked(HistoryRecord r) {
1604 if (mFocusedActivity != r) {
1605 mFocusedActivity = r;
1606 mWindowManager.setFocusedApp(r, true);
1607 }
1608 }
1609
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001610 private final void updateLruProcessLocked(ProcessRecord app,
1611 boolean oomAdj, boolean updateActivityTime) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001612 // put it on the LRU to keep track of when it should be exited.
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001613 int lrui = mLruProcesses.indexOf(app);
1614 if (lrui >= 0) mLruProcesses.remove(lrui);
1615
1616 int i = mLruProcesses.size()-1;
1617 int skipTop = 0;
1618
1619 // compute the new weight for this process.
1620 if (updateActivityTime) {
1621 app.lastActivityTime = SystemClock.uptimeMillis();
1622 }
1623 if (app.activities.size() > 0) {
1624 // If this process has activities, we more strongly want to keep
1625 // it around.
1626 app.lruWeight = app.lastActivityTime;
1627 } else if (app.pubProviders.size() > 0) {
1628 // If this process contains content providers, we want to keep
1629 // it a little more strongly.
1630 app.lruWeight = app.lastActivityTime - CONTENT_APP_IDLE_OFFSET;
1631 // Also don't let it kick out the first few "real" hidden processes.
1632 skipTop = MIN_HIDDEN_APPS;
1633 } else {
1634 // If this process doesn't have activities, we less strongly
1635 // want to keep it around, and generally want to avoid getting
1636 // in front of any very recently used activities.
1637 app.lruWeight = app.lastActivityTime - EMPTY_APP_IDLE_OFFSET;
1638 // Also don't let it kick out the first few "real" hidden processes.
1639 skipTop = MIN_HIDDEN_APPS;
1640 }
1641 while (i >= 0) {
1642 ProcessRecord p = mLruProcesses.get(i);
1643 // If this app shouldn't be in front of the first N background
1644 // apps, then skip over that many that are currently hidden.
1645 if (skipTop > 0 && p.setAdj >= HIDDEN_APP_MIN_ADJ) {
1646 skipTop--;
1647 }
1648 if (p.lruWeight <= app.lruWeight){
1649 mLruProcesses.add(i+1, app);
1650 break;
1651 }
1652 i--;
1653 }
1654 if (i < 0) {
1655 mLruProcesses.add(0, app);
1656 }
1657
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001658 //Log.i(TAG, "Putting proc to front: " + app.processName);
1659 if (oomAdj) {
1660 updateOomAdjLocked();
1661 }
1662 }
1663
1664 private final boolean updateLRUListLocked(HistoryRecord r) {
1665 final boolean hadit = mLRUActivities.remove(r);
1666 mLRUActivities.add(r);
1667 return hadit;
1668 }
1669
1670 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1671 int i = mHistory.size()-1;
1672 while (i >= 0) {
1673 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1674 if (!r.finishing && r != notTop) {
1675 return r;
1676 }
1677 i--;
1678 }
1679 return null;
1680 }
1681
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001682 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1683 int i = mHistory.size()-1;
1684 while (i >= 0) {
1685 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1686 if (!r.finishing && !r.delayedResume && r != notTop) {
1687 return r;
1688 }
1689 i--;
1690 }
1691 return null;
1692 }
1693
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001694 /**
1695 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001696 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001697 *
1698 * @param token If non-null, any history records matching this token will be skipped.
1699 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1700 *
1701 * @return Returns the HistoryRecord of the next activity on the stack.
1702 */
1703 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1704 int i = mHistory.size()-1;
1705 while (i >= 0) {
1706 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1707 // Note: the taskId check depends on real taskId fields being non-zero
1708 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1709 return r;
1710 }
1711 i--;
1712 }
1713 return null;
1714 }
1715
1716 private final ProcessRecord getProcessRecordLocked(
1717 String processName, int uid) {
1718 if (uid == Process.SYSTEM_UID) {
1719 // The system gets to run in any process. If there are multiple
1720 // processes with the same uid, just pick the first (this
1721 // should never happen).
1722 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1723 processName);
1724 return procs != null ? procs.valueAt(0) : null;
1725 }
1726 ProcessRecord proc = mProcessNames.get(processName, uid);
1727 return proc;
1728 }
1729
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001730 private void ensurePackageDexOpt(String packageName) {
1731 IPackageManager pm = ActivityThread.getPackageManager();
1732 try {
1733 if (pm.performDexOpt(packageName)) {
1734 mDidDexOpt = true;
1735 }
1736 } catch (RemoteException e) {
1737 }
1738 }
1739
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001740 private boolean isNextTransitionForward() {
1741 int transit = mWindowManager.getPendingAppTransition();
1742 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1743 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1744 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1745 }
1746
1747 private final boolean realStartActivityLocked(HistoryRecord r,
1748 ProcessRecord app, boolean andResume, boolean checkConfig)
1749 throws RemoteException {
1750
1751 r.startFreezingScreenLocked(app, 0);
1752 mWindowManager.setAppVisibility(r, true);
1753
1754 // Have the window manager re-evaluate the orientation of
1755 // the screen based on the new activity order. Note that
1756 // as a result of this, it can call back into the activity
1757 // manager with a new orientation. We don't care about that,
1758 // because the activity is not currently running so we are
1759 // just restarting it anyway.
1760 if (checkConfig) {
1761 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001762 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001763 r.mayFreezeScreenLocked(app) ? r : null);
1764 updateConfigurationLocked(config, r);
1765 }
1766
1767 r.app = app;
1768
1769 if (localLOGV) Log.v(TAG, "Launching: " + r);
1770
1771 int idx = app.activities.indexOf(r);
1772 if (idx < 0) {
1773 app.activities.add(r);
1774 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001775 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001776
1777 try {
1778 if (app.thread == null) {
1779 throw new RemoteException();
1780 }
1781 List<ResultInfo> results = null;
1782 List<Intent> newIntents = null;
1783 if (andResume) {
1784 results = r.results;
1785 newIntents = r.newIntents;
1786 }
1787 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1788 + " icicle=" + r.icicle
1789 + " with results=" + results + " newIntents=" + newIntents
1790 + " andResume=" + andResume);
1791 if (andResume) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08001792 EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001793 System.identityHashCode(r),
1794 r.task.taskId, r.shortComponentName);
1795 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001796 if (r.isHomeActivity) {
1797 mHomeProcess = app;
1798 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001799 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001800 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001801 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001802 r.info, r.icicle, results, newIntents, !andResume,
1803 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001804 } catch (RemoteException e) {
1805 if (r.launchFailed) {
1806 // This is the second time we failed -- finish activity
1807 // and give up.
1808 Log.e(TAG, "Second failure launching "
1809 + r.intent.getComponent().flattenToShortString()
1810 + ", giving up", e);
1811 appDiedLocked(app, app.pid, app.thread);
1812 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1813 "2nd-crash");
1814 return false;
1815 }
1816
1817 // This is the first time we failed -- restart process and
1818 // retry.
1819 app.activities.remove(r);
1820 throw e;
1821 }
1822
1823 r.launchFailed = false;
1824 if (updateLRUListLocked(r)) {
1825 Log.w(TAG, "Activity " + r
1826 + " being launched, but already in LRU list");
1827 }
1828
1829 if (andResume) {
1830 // As part of the process of launching, ActivityThread also performs
1831 // a resume.
1832 r.state = ActivityState.RESUMED;
1833 r.icicle = null;
1834 r.haveState = false;
1835 r.stopped = false;
1836 mResumedActivity = r;
1837 r.task.touchActiveTime();
1838 completeResumeLocked(r);
1839 pauseIfSleepingLocked();
1840 } else {
1841 // This activity is not starting in the resumed state... which
1842 // should look like we asked it to pause+stop (but remain visible),
1843 // and it has done so and reported back the current icicle and
1844 // other state.
1845 r.state = ActivityState.STOPPED;
1846 r.stopped = true;
1847 }
1848
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001849 // Launch the new version setup screen if needed. We do this -after-
1850 // launching the initial activity (that is, home), so that it can have
1851 // a chance to initialize itself while in the background, making the
1852 // switch back to it faster and look better.
1853 startSetupActivityLocked();
1854
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001855 return true;
1856 }
1857
1858 private final void startSpecificActivityLocked(HistoryRecord r,
1859 boolean andResume, boolean checkConfig) {
1860 // Is this activity's application already running?
1861 ProcessRecord app = getProcessRecordLocked(r.processName,
1862 r.info.applicationInfo.uid);
1863
1864 if (r.startTime == 0) {
1865 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001866 if (mInitialStartTime == 0) {
1867 mInitialStartTime = r.startTime;
1868 }
1869 } else if (mInitialStartTime == 0) {
1870 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001871 }
1872
1873 if (app != null && app.thread != null) {
1874 try {
1875 realStartActivityLocked(r, app, andResume, checkConfig);
1876 return;
1877 } catch (RemoteException e) {
1878 Log.w(TAG, "Exception when starting activity "
1879 + r.intent.getComponent().flattenToShortString(), e);
1880 }
1881
1882 // If a dead object exception was thrown -- fall through to
1883 // restart the application.
1884 }
1885
1886 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001887 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001888 }
1889
1890 private final ProcessRecord startProcessLocked(String processName,
1891 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001892 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001893 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1894 // We don't have to do anything more if:
1895 // (1) There is an existing application record; and
1896 // (2) The caller doesn't think it is dead, OR there is no thread
1897 // object attached to it so we know it couldn't have crashed; and
1898 // (3) There is a pid assigned to it, so it is either starting or
1899 // already running.
1900 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1901 + " app=" + app + " knownToBeDead=" + knownToBeDead
1902 + " thread=" + (app != null ? app.thread : null)
1903 + " pid=" + (app != null ? app.pid : -1));
1904 if (app != null &&
1905 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1906 return app;
1907 }
1908
1909 String hostingNameStr = hostingName != null
1910 ? hostingName.flattenToShortString() : null;
1911
1912 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1913 // If we are in the background, then check to see if this process
1914 // is bad. If so, we will just silently fail.
1915 if (mBadProcesses.get(info.processName, info.uid) != null) {
1916 return null;
1917 }
1918 } else {
1919 // When the user is explicitly starting a process, then clear its
1920 // crash count so that we won't make it bad until they see at
1921 // least one crash dialog again, and make the process good again
1922 // if it had been bad.
1923 mProcessCrashTimes.remove(info.processName, info.uid);
1924 if (mBadProcesses.get(info.processName, info.uid) != null) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08001925 EventLog.writeEvent(EventLogTags.AM_PROC_GOOD, info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001926 info.processName);
1927 mBadProcesses.remove(info.processName, info.uid);
1928 if (app != null) {
1929 app.bad = false;
1930 }
1931 }
1932 }
1933
1934 if (app == null) {
1935 app = newProcessRecordLocked(null, info, processName);
1936 mProcessNames.put(processName, info.uid, app);
1937 } else {
1938 // If this is a new package in the process, add the package to the list
1939 app.addPackage(info.packageName);
1940 }
1941
1942 // If the system is not ready yet, then hold off on starting this
1943 // process until it is.
1944 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001945 && !isAllowedWhileBooting(info)
1946 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001947 if (!mProcessesOnHold.contains(app)) {
1948 mProcessesOnHold.add(app);
1949 }
1950 return app;
1951 }
1952
1953 startProcessLocked(app, hostingType, hostingNameStr);
1954 return (app.pid != 0) ? app : null;
1955 }
1956
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001957 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1958 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1959 }
1960
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001961 private final void startProcessLocked(ProcessRecord app,
1962 String hostingType, String hostingNameStr) {
1963 if (app.pid > 0 && app.pid != MY_PID) {
1964 synchronized (mPidsSelfLocked) {
1965 mPidsSelfLocked.remove(app.pid);
1966 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1967 }
1968 app.pid = 0;
1969 }
1970
1971 mProcessesOnHold.remove(app);
1972
1973 updateCpuStats();
1974
1975 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1976 mProcDeaths[0] = 0;
1977
1978 try {
1979 int uid = app.info.uid;
1980 int[] gids = null;
1981 try {
1982 gids = mContext.getPackageManager().getPackageGids(
1983 app.info.packageName);
1984 } catch (PackageManager.NameNotFoundException e) {
1985 Log.w(TAG, "Unable to retrieve gids", e);
1986 }
1987 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1988 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1989 && mTopComponent != null
1990 && app.processName.equals(mTopComponent.getPackageName())) {
1991 uid = 0;
1992 }
1993 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1994 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1995 uid = 0;
1996 }
1997 }
1998 int debugFlags = 0;
1999 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
2000 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
2001 }
2002 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
2003 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
2004 }
2005 if ("1".equals(SystemProperties.get("debug.assert"))) {
2006 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
2007 }
2008 int pid = Process.start("android.app.ActivityThread",
2009 mSimpleProcessManagement ? app.processName : null, uid, uid,
2010 gids, debugFlags, null);
2011 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
2012 synchronized (bs) {
2013 if (bs.isOnBattery()) {
2014 app.batteryStats.incStartsLocked();
2015 }
2016 }
2017
Doug Zongker2bec3d42009-12-04 12:52:44 -08002018 EventLog.writeEvent(EventLogTags.AM_PROC_START, pid, uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002019 app.processName, hostingType,
2020 hostingNameStr != null ? hostingNameStr : "");
2021
2022 if (app.persistent) {
2023 Watchdog.getInstance().processStarted(app, app.processName, pid);
2024 }
2025
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07002026 StringBuilder buf = mStringBuilder;
2027 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002028 buf.append("Start proc ");
2029 buf.append(app.processName);
2030 buf.append(" for ");
2031 buf.append(hostingType);
2032 if (hostingNameStr != null) {
2033 buf.append(" ");
2034 buf.append(hostingNameStr);
2035 }
2036 buf.append(": pid=");
2037 buf.append(pid);
2038 buf.append(" uid=");
2039 buf.append(uid);
2040 buf.append(" gids={");
2041 if (gids != null) {
2042 for (int gi=0; gi<gids.length; gi++) {
2043 if (gi != 0) buf.append(", ");
2044 buf.append(gids[gi]);
2045
2046 }
2047 }
2048 buf.append("}");
2049 Log.i(TAG, buf.toString());
2050 if (pid == 0 || pid == MY_PID) {
2051 // Processes are being emulated with threads.
2052 app.pid = MY_PID;
2053 app.removed = false;
2054 mStartingProcesses.add(app);
2055 } else if (pid > 0) {
2056 app.pid = pid;
2057 app.removed = false;
2058 synchronized (mPidsSelfLocked) {
2059 this.mPidsSelfLocked.put(pid, app);
2060 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2061 msg.obj = app;
2062 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2063 }
2064 } else {
2065 app.pid = 0;
2066 RuntimeException e = new RuntimeException(
2067 "Failure starting process " + app.processName
2068 + ": returned pid=" + pid);
2069 Log.e(TAG, e.getMessage(), e);
2070 }
2071 } catch (RuntimeException e) {
2072 // XXX do better error recovery.
2073 app.pid = 0;
2074 Log.e(TAG, "Failure starting process " + app.processName, e);
2075 }
2076 }
2077
2078 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2079 if (mPausingActivity != null) {
2080 RuntimeException e = new RuntimeException();
2081 Log.e(TAG, "Trying to pause when pause is already pending for "
2082 + mPausingActivity, e);
2083 }
2084 HistoryRecord prev = mResumedActivity;
2085 if (prev == null) {
2086 RuntimeException e = new RuntimeException();
2087 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2088 resumeTopActivityLocked(null);
2089 return;
2090 }
2091 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2092 mResumedActivity = null;
2093 mPausingActivity = prev;
2094 mLastPausedActivity = prev;
2095 prev.state = ActivityState.PAUSING;
2096 prev.task.touchActiveTime();
2097
2098 updateCpuStats();
2099
2100 if (prev.app != null && prev.app.thread != null) {
2101 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2102 try {
Doug Zongker2bec3d42009-12-04 12:52:44 -08002103 EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002104 System.identityHashCode(prev),
2105 prev.shortComponentName);
2106 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2107 prev.configChangeFlags);
2108 updateUsageStats(prev, false);
2109 } catch (Exception e) {
2110 // Ignore exception, if process died other code will cleanup.
2111 Log.w(TAG, "Exception thrown during pause", e);
2112 mPausingActivity = null;
2113 mLastPausedActivity = null;
2114 }
2115 } else {
2116 mPausingActivity = null;
2117 mLastPausedActivity = null;
2118 }
2119
2120 // If we are not going to sleep, we want to ensure the device is
2121 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002122 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002123 mLaunchingActivity.acquire();
2124 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2125 // To be safe, don't allow the wake lock to be held for too long.
2126 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2127 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2128 }
2129 }
2130
2131
2132 if (mPausingActivity != null) {
2133 // Have the window manager pause its key dispatching until the new
2134 // activity has started. If we're pausing the activity just because
2135 // the screen is being turned off and the UI is sleeping, don't interrupt
2136 // key dispatch; the same activity will pick it up again on wakeup.
2137 if (!uiSleeping) {
2138 prev.pauseKeyDispatchingLocked();
2139 } else {
2140 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2141 }
2142
2143 // Schedule a pause timeout in case the app doesn't respond.
2144 // We don't give it much time because this directly impacts the
2145 // responsiveness seen by the user.
2146 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2147 msg.obj = prev;
2148 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2149 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2150 } else {
2151 // This activity failed to schedule the
2152 // pause, so just treat it as being paused now.
2153 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2154 resumeTopActivityLocked(null);
2155 }
2156 }
2157
2158 private final void completePauseLocked() {
2159 HistoryRecord prev = mPausingActivity;
2160 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2161
2162 if (prev != null) {
2163 if (prev.finishing) {
2164 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2165 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2166 } else if (prev.app != null) {
2167 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2168 if (prev.waitingVisible) {
2169 prev.waitingVisible = false;
2170 mWaitingVisibleActivities.remove(prev);
2171 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2172 TAG, "Complete pause, no longer waiting: " + prev);
2173 }
2174 if (prev.configDestroy) {
2175 // The previous is being paused because the configuration
2176 // is changing, which means it is actually stopping...
2177 // To juggle the fact that we are also starting a new
2178 // instance right now, we need to first completely stop
2179 // the current instance before starting the new one.
2180 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2181 destroyActivityLocked(prev, true);
2182 } else {
2183 mStoppingActivities.add(prev);
2184 if (mStoppingActivities.size() > 3) {
2185 // If we already have a few activities waiting to stop,
2186 // then give up on things going idle and start clearing
2187 // them out.
2188 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2189 Message msg = Message.obtain();
2190 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2191 mHandler.sendMessage(msg);
2192 }
2193 }
2194 } else {
2195 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2196 prev = null;
2197 }
2198 mPausingActivity = null;
2199 }
2200
Dianne Hackborn55280a92009-05-07 15:53:46 -07002201 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002202 resumeTopActivityLocked(prev);
2203 } else {
2204 if (mGoingToSleep.isHeld()) {
2205 mGoingToSleep.release();
2206 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002207 if (mShuttingDown) {
2208 notifyAll();
2209 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002210 }
2211
2212 if (prev != null) {
2213 prev.resumeKeyDispatchingLocked();
2214 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002215
2216 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2217 long diff = 0;
2218 synchronized (mProcessStatsThread) {
2219 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2220 }
2221 if (diff > 0) {
2222 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2223 synchronized (bsi) {
2224 BatteryStatsImpl.Uid.Proc ps =
2225 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2226 prev.info.packageName);
2227 if (ps != null) {
2228 ps.addForegroundTimeLocked(diff);
2229 }
2230 }
2231 }
2232 }
2233 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002234 }
2235
2236 /**
2237 * Once we know that we have asked an application to put an activity in
2238 * the resumed state (either by launching it or explicitly telling it),
2239 * this function updates the rest of our state to match that fact.
2240 */
2241 private final void completeResumeLocked(HistoryRecord next) {
2242 next.idle = false;
2243 next.results = null;
2244 next.newIntents = null;
2245
2246 // schedule an idle timeout in case the app doesn't do it for us.
2247 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2248 msg.obj = next;
2249 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2250
2251 if (false) {
2252 // The activity was never told to pause, so just keep
2253 // things going as-is. To maintain our own state,
2254 // we need to emulate it coming back and saying it is
2255 // idle.
2256 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2257 msg.obj = next;
2258 mHandler.sendMessage(msg);
2259 }
2260
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002261 reportResumedActivityLocked(next);
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002263 next.thumbnail = null;
2264 setFocusedActivityLocked(next);
2265 next.resumeKeyDispatchingLocked();
2266 ensureActivitiesVisibleLocked(null, 0);
2267 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002268 mNoAnimActivities.clear();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002269
2270 // Mark the point when the activity is resuming
2271 // TODO: To be more accurate, the mark should be before the onCreate,
2272 // not after the onResume. But for subsequent starts, onResume is fine.
2273 if (next.app != null) {
2274 synchronized (mProcessStatsThread) {
2275 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2276 }
2277 } else {
2278 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2279 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002280 }
2281
2282 /**
2283 * Make sure that all activities that need to be visible (that is, they
2284 * currently can be seen by the user) actually are.
2285 */
2286 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2287 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2288 if (DEBUG_VISBILITY) Log.v(
2289 TAG, "ensureActivitiesVisible behind " + top
2290 + " configChanges=0x" + Integer.toHexString(configChanges));
2291
2292 // If the top activity is not fullscreen, then we need to
2293 // make sure any activities under it are now visible.
2294 final int count = mHistory.size();
2295 int i = count-1;
2296 while (mHistory.get(i) != top) {
2297 i--;
2298 }
2299 HistoryRecord r;
2300 boolean behindFullscreen = false;
2301 for (; i>=0; i--) {
2302 r = (HistoryRecord)mHistory.get(i);
2303 if (DEBUG_VISBILITY) Log.v(
2304 TAG, "Make visible? " + r + " finishing=" + r.finishing
2305 + " state=" + r.state);
2306 if (r.finishing) {
2307 continue;
2308 }
2309
2310 final boolean doThisProcess = onlyThisProcess == null
2311 || onlyThisProcess.equals(r.processName);
2312
2313 // First: if this is not the current activity being started, make
2314 // sure it matches the current configuration.
2315 if (r != starting && doThisProcess) {
2316 ensureActivityConfigurationLocked(r, 0);
2317 }
2318
2319 if (r.app == null || r.app.thread == null) {
2320 if (onlyThisProcess == null
2321 || onlyThisProcess.equals(r.processName)) {
2322 // This activity needs to be visible, but isn't even
2323 // running... get it started, but don't resume it
2324 // at this point.
2325 if (DEBUG_VISBILITY) Log.v(
2326 TAG, "Start and freeze screen for " + r);
2327 if (r != starting) {
2328 r.startFreezingScreenLocked(r.app, configChanges);
2329 }
2330 if (!r.visible) {
2331 if (DEBUG_VISBILITY) Log.v(
2332 TAG, "Starting and making visible: " + r);
2333 mWindowManager.setAppVisibility(r, true);
2334 }
2335 if (r != starting) {
2336 startSpecificActivityLocked(r, false, false);
2337 }
2338 }
2339
2340 } else if (r.visible) {
2341 // If this activity is already visible, then there is nothing
2342 // else to do here.
2343 if (DEBUG_VISBILITY) Log.v(
2344 TAG, "Skipping: already visible at " + r);
2345 r.stopFreezingScreenLocked(false);
2346
2347 } else if (onlyThisProcess == null) {
2348 // This activity is not currently visible, but is running.
2349 // Tell it to become visible.
2350 r.visible = true;
2351 if (r.state != ActivityState.RESUMED && r != starting) {
2352 // If this activity is paused, tell it
2353 // to now show its window.
2354 if (DEBUG_VISBILITY) Log.v(
2355 TAG, "Making visible and scheduling visibility: " + r);
2356 try {
2357 mWindowManager.setAppVisibility(r, true);
2358 r.app.thread.scheduleWindowVisibility(r, true);
2359 r.stopFreezingScreenLocked(false);
2360 } catch (Exception e) {
2361 // Just skip on any failure; we'll make it
2362 // visible when it next restarts.
2363 Log.w(TAG, "Exception thrown making visibile: "
2364 + r.intent.getComponent(), e);
2365 }
2366 }
2367 }
2368
2369 // Aggregate current change flags.
2370 configChanges |= r.configChangeFlags;
2371
2372 if (r.fullscreen) {
2373 // At this point, nothing else needs to be shown
2374 if (DEBUG_VISBILITY) Log.v(
2375 TAG, "Stopping: fullscreen at " + r);
2376 behindFullscreen = true;
2377 i--;
2378 break;
2379 }
2380 }
2381
2382 // Now for any activities that aren't visible to the user, make
2383 // sure they no longer are keeping the screen frozen.
2384 while (i >= 0) {
2385 r = (HistoryRecord)mHistory.get(i);
2386 if (DEBUG_VISBILITY) Log.v(
2387 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2388 + " state=" + r.state
2389 + " behindFullscreen=" + behindFullscreen);
2390 if (!r.finishing) {
2391 if (behindFullscreen) {
2392 if (r.visible) {
2393 if (DEBUG_VISBILITY) Log.v(
2394 TAG, "Making invisible: " + r);
2395 r.visible = false;
2396 try {
2397 mWindowManager.setAppVisibility(r, false);
2398 if ((r.state == ActivityState.STOPPING
2399 || r.state == ActivityState.STOPPED)
2400 && r.app != null && r.app.thread != null) {
2401 if (DEBUG_VISBILITY) Log.v(
2402 TAG, "Scheduling invisibility: " + r);
2403 r.app.thread.scheduleWindowVisibility(r, false);
2404 }
2405 } catch (Exception e) {
2406 // Just skip on any failure; we'll make it
2407 // visible when it next restarts.
2408 Log.w(TAG, "Exception thrown making hidden: "
2409 + r.intent.getComponent(), e);
2410 }
2411 } else {
2412 if (DEBUG_VISBILITY) Log.v(
2413 TAG, "Already invisible: " + r);
2414 }
2415 } else if (r.fullscreen) {
2416 if (DEBUG_VISBILITY) Log.v(
2417 TAG, "Now behindFullscreen: " + r);
2418 behindFullscreen = true;
2419 }
2420 }
2421 i--;
2422 }
2423 }
2424
2425 /**
2426 * Version of ensureActivitiesVisible that can easily be called anywhere.
2427 */
2428 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2429 int configChanges) {
2430 HistoryRecord r = topRunningActivityLocked(null);
2431 if (r != null) {
2432 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2433 }
2434 }
2435
2436 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2437 if (resumed) {
2438 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2439 } else {
2440 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2441 }
2442 }
2443
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002444 private boolean startHomeActivityLocked() {
2445 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2446 && mTopAction == null) {
2447 // We are running in factory test mode, but unable to find
2448 // the factory test app, so just sit around displaying the
2449 // error message and don't try to start anything.
2450 return false;
2451 }
2452 Intent intent = new Intent(
2453 mTopAction,
2454 mTopData != null ? Uri.parse(mTopData) : null);
2455 intent.setComponent(mTopComponent);
2456 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2457 intent.addCategory(Intent.CATEGORY_HOME);
2458 }
2459 ActivityInfo aInfo =
2460 intent.resolveActivityInfo(mContext.getPackageManager(),
2461 STOCK_PM_FLAGS);
2462 if (aInfo != null) {
2463 intent.setComponent(new ComponentName(
2464 aInfo.applicationInfo.packageName, aInfo.name));
2465 // Don't do this if the home app is currently being
2466 // instrumented.
2467 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2468 aInfo.applicationInfo.uid);
2469 if (app == null || app.instrumentationClass == null) {
2470 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2471 startActivityLocked(null, intent, null, null, 0, aInfo,
2472 null, null, 0, 0, 0, false, false);
2473 }
2474 }
2475
2476
2477 return true;
2478 }
2479
2480 /**
2481 * Starts the "new version setup screen" if appropriate.
2482 */
2483 private void startSetupActivityLocked() {
2484 // Only do this once per boot.
2485 if (mCheckedForSetup) {
2486 return;
2487 }
2488
2489 // We will show this screen if the current one is a different
2490 // version than the last one shown, and we are not running in
2491 // low-level factory test mode.
2492 final ContentResolver resolver = mContext.getContentResolver();
2493 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2494 Settings.Secure.getInt(resolver,
2495 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2496 mCheckedForSetup = true;
2497
2498 // See if we should be showing the platform update setup UI.
2499 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2500 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2501 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2502
2503 // We don't allow third party apps to replace this.
2504 ResolveInfo ri = null;
2505 for (int i=0; ris != null && i<ris.size(); i++) {
2506 if ((ris.get(i).activityInfo.applicationInfo.flags
2507 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2508 ri = ris.get(i);
2509 break;
2510 }
2511 }
2512
2513 if (ri != null) {
2514 String vers = ri.activityInfo.metaData != null
2515 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2516 : null;
2517 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2518 vers = ri.activityInfo.applicationInfo.metaData.getString(
2519 Intent.METADATA_SETUP_VERSION);
2520 }
2521 String lastVers = Settings.Secure.getString(
2522 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2523 if (vers != null && !vers.equals(lastVers)) {
2524 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2525 intent.setComponent(new ComponentName(
2526 ri.activityInfo.packageName, ri.activityInfo.name));
2527 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2528 null, null, 0, 0, 0, false, false);
2529 }
2530 }
2531 }
2532 }
2533
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002534 private void reportResumedActivityLocked(HistoryRecord r) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002535 //Log.i(TAG, "**** REPORT RESUME: " + r);
2536
2537 final int identHash = System.identityHashCode(r);
2538 updateUsageStats(r, true);
2539
2540 int i = mWatchers.beginBroadcast();
2541 while (i > 0) {
2542 i--;
2543 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2544 if (w != null) {
2545 try {
2546 w.activityResuming(identHash);
2547 } catch (RemoteException e) {
2548 }
2549 }
2550 }
2551 mWatchers.finishBroadcast();
2552 }
2553
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002554 /**
2555 * Ensure that the top activity in the stack is resumed.
2556 *
2557 * @param prev The previously resumed activity, for when in the process
2558 * of pausing; can be null to call from elsewhere.
2559 *
2560 * @return Returns true if something is being resumed, or false if
2561 * nothing happened.
2562 */
2563 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2564 // Find the first activity that is not finishing.
2565 HistoryRecord next = topRunningActivityLocked(null);
2566
2567 // Remember how we'll process this pause/resume situation, and ensure
2568 // that the state is reset however we wind up proceeding.
2569 final boolean userLeaving = mUserLeaving;
2570 mUserLeaving = false;
2571
2572 if (next == null) {
2573 // There are no more activities! Let's just start up the
2574 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002575 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002576 }
2577
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002578 next.delayedResume = false;
2579
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002580 // If the top activity is the resumed one, nothing to do.
2581 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2582 // Make sure we have executed any pending transitions, since there
2583 // should be nothing left to do at this point.
2584 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002585 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002586 return false;
2587 }
2588
2589 // If we are sleeping, and there is no resumed activity, and the top
2590 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002591 if ((mSleeping || mShuttingDown)
2592 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002593 // Make sure we have executed any pending transitions, since there
2594 // should be nothing left to do at this point.
2595 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002596 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002597 return false;
2598 }
2599
2600 // The activity may be waiting for stop, but that is no longer
2601 // appropriate for it.
2602 mStoppingActivities.remove(next);
2603 mWaitingVisibleActivities.remove(next);
2604
2605 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2606
2607 // If we are currently pausing an activity, then don't do anything
2608 // until that is done.
2609 if (mPausingActivity != null) {
2610 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2611 return false;
2612 }
2613
2614 // We need to start pausing the current activity so the top one
2615 // can be resumed...
2616 if (mResumedActivity != null) {
2617 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2618 startPausingLocked(userLeaving, false);
2619 return true;
2620 }
2621
2622 if (prev != null && prev != next) {
2623 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2624 prev.waitingVisible = true;
2625 mWaitingVisibleActivities.add(prev);
2626 if (DEBUG_SWITCH) Log.v(
2627 TAG, "Resuming top, waiting visible to hide: " + prev);
2628 } else {
2629 // The next activity is already visible, so hide the previous
2630 // activity's windows right now so we can show the new one ASAP.
2631 // We only do this if the previous is finishing, which should mean
2632 // it is on top of the one being resumed so hiding it quickly
2633 // is good. Otherwise, we want to do the normal route of allowing
2634 // the resumed activity to be shown so we can decide if the
2635 // previous should actually be hidden depending on whether the
2636 // new one is found to be full-screen or not.
2637 if (prev.finishing) {
2638 mWindowManager.setAppVisibility(prev, false);
2639 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2640 + prev + ", waitingVisible="
2641 + (prev != null ? prev.waitingVisible : null)
2642 + ", nowVisible=" + next.nowVisible);
2643 } else {
2644 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2645 + prev + ", waitingVisible="
2646 + (prev != null ? prev.waitingVisible : null)
2647 + ", nowVisible=" + next.nowVisible);
2648 }
2649 }
2650 }
2651
2652 // We are starting up the next activity, so tell the window manager
2653 // that the previous one will be hidden soon. This way it can know
2654 // to ignore it when computing the desired screen orientation.
2655 if (prev != null) {
2656 if (prev.finishing) {
2657 if (DEBUG_TRANSITION) Log.v(TAG,
2658 "Prepare close transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002659 if (mNoAnimActivities.contains(prev)) {
2660 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2661 } else {
2662 mWindowManager.prepareAppTransition(prev.task == next.task
2663 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2664 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2665 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002666 mWindowManager.setAppWillBeHidden(prev);
2667 mWindowManager.setAppVisibility(prev, false);
2668 } else {
2669 if (DEBUG_TRANSITION) Log.v(TAG,
2670 "Prepare open transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002671 if (mNoAnimActivities.contains(next)) {
2672 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2673 } else {
2674 mWindowManager.prepareAppTransition(prev.task == next.task
2675 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2676 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2677 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002678 }
2679 if (false) {
2680 mWindowManager.setAppWillBeHidden(prev);
2681 mWindowManager.setAppVisibility(prev, false);
2682 }
2683 } else if (mHistory.size() > 1) {
2684 if (DEBUG_TRANSITION) Log.v(TAG,
2685 "Prepare open transition: no previous");
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002686 if (mNoAnimActivities.contains(next)) {
2687 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2688 } else {
2689 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2690 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002691 }
2692
2693 if (next.app != null && next.app.thread != null) {
2694 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2695
2696 // This activity is now becoming visible.
2697 mWindowManager.setAppVisibility(next, true);
2698
2699 HistoryRecord lastResumedActivity = mResumedActivity;
2700 ActivityState lastState = next.state;
2701
2702 updateCpuStats();
2703
2704 next.state = ActivityState.RESUMED;
2705 mResumedActivity = next;
2706 next.task.touchActiveTime();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08002707 updateLruProcessLocked(next.app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002708 updateLRUListLocked(next);
2709
2710 // Have the window manager re-evaluate the orientation of
2711 // the screen based on the new activity order.
Eric Fischerd4d04de2009-10-27 18:55:57 -07002712 boolean updated;
2713 synchronized (this) {
2714 Configuration config = mWindowManager.updateOrientationFromAppTokens(
2715 mConfiguration,
2716 next.mayFreezeScreenLocked(next.app) ? next : null);
2717 if (config != null) {
2718 /*
2719 * Explicitly restore the locale to the one from the
2720 * old configuration, since the one that comes back from
2721 * the window manager has the default (boot) locale.
2722 *
2723 * It looks like previously the locale picker only worked
2724 * by coincidence: usually it would do its setting of
2725 * the locale after the activity transition, so it didn't
2726 * matter that this lost it. With the synchronized
2727 * block now keeping them from happening at the same time,
2728 * this one always would happen second and undo what the
2729 * locale picker had just done.
2730 */
2731 config.locale = mConfiguration.locale;
2732 next.frozenBeforeDestroy = true;
2733 }
2734 updated = updateConfigurationLocked(config, next);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002735 }
Eric Fischerd4d04de2009-10-27 18:55:57 -07002736 if (!updated) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002737 // The configuration update wasn't able to keep the existing
2738 // instance of the activity, and instead started a new one.
2739 // We should be all done, but let's just make sure our activity
2740 // is still at the top and schedule another run if something
2741 // weird happened.
2742 HistoryRecord nextNext = topRunningActivityLocked(null);
2743 if (DEBUG_SWITCH) Log.i(TAG,
2744 "Activity config changed during resume: " + next
2745 + ", new next: " + nextNext);
2746 if (nextNext != next) {
2747 // Do over!
2748 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2749 }
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07002750 setFocusedActivityLocked(next);
2751 ensureActivitiesVisibleLocked(null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002752 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002753 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002754 return true;
2755 }
2756
2757 try {
2758 // Deliver all pending results.
2759 ArrayList a = next.results;
2760 if (a != null) {
2761 final int N = a.size();
2762 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002763 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002764 TAG, "Delivering results to " + next
2765 + ": " + a);
2766 next.app.thread.scheduleSendResult(next, a);
2767 }
2768 }
2769
2770 if (next.newIntents != null) {
2771 next.app.thread.scheduleNewIntent(next.newIntents, next);
2772 }
2773
Doug Zongker2bec3d42009-12-04 12:52:44 -08002774 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002775 System.identityHashCode(next),
2776 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002777
2778 next.app.thread.scheduleResumeActivity(next,
2779 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002780
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002781 pauseIfSleepingLocked();
2782
2783 } catch (Exception e) {
2784 // Whoops, need to restart this activity!
2785 next.state = lastState;
2786 mResumedActivity = lastResumedActivity;
2787 if (Config.LOGD) Log.d(TAG,
2788 "Restarting because process died: " + next);
2789 if (!next.hasBeenLaunched) {
2790 next.hasBeenLaunched = true;
2791 } else {
2792 if (SHOW_APP_STARTING_ICON) {
2793 mWindowManager.setAppStartingWindow(
2794 next, next.packageName, next.theme,
2795 next.nonLocalizedLabel,
2796 next.labelRes, next.icon, null, true);
2797 }
2798 }
2799 startSpecificActivityLocked(next, true, false);
2800 return true;
2801 }
2802
2803 // From this point on, if something goes wrong there is no way
2804 // to recover the activity.
2805 try {
2806 next.visible = true;
2807 completeResumeLocked(next);
2808 } catch (Exception e) {
2809 // If any exception gets thrown, toss away this
2810 // activity and try the next one.
2811 Log.w(TAG, "Exception thrown during resume of " + next, e);
2812 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2813 "resume-exception");
2814 return true;
2815 }
2816
2817 // Didn't need to use the icicle, and it is now out of date.
2818 next.icicle = null;
2819 next.haveState = false;
2820 next.stopped = false;
2821
2822 } else {
2823 // Whoops, need to restart this activity!
2824 if (!next.hasBeenLaunched) {
2825 next.hasBeenLaunched = true;
2826 } else {
2827 if (SHOW_APP_STARTING_ICON) {
2828 mWindowManager.setAppStartingWindow(
2829 next, next.packageName, next.theme,
2830 next.nonLocalizedLabel,
2831 next.labelRes, next.icon, null, true);
2832 }
2833 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2834 }
2835 startSpecificActivityLocked(next, true, true);
2836 }
2837
2838 return true;
2839 }
2840
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002841 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2842 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002843 final int NH = mHistory.size();
2844
2845 int addPos = -1;
2846
2847 if (!newTask) {
2848 // If starting in an existing task, find where that is...
2849 HistoryRecord next = null;
2850 boolean startIt = true;
2851 for (int i = NH-1; i >= 0; i--) {
2852 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2853 if (p.finishing) {
2854 continue;
2855 }
2856 if (p.task == r.task) {
2857 // Here it is! Now, if this is not yet visible to the
2858 // user, then just add it without starting; it will
2859 // get started when the user navigates back to it.
2860 addPos = i+1;
2861 if (!startIt) {
2862 mHistory.add(addPos, r);
2863 r.inHistory = true;
2864 r.task.numActivities++;
2865 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2866 r.info.screenOrientation, r.fullscreen);
2867 if (VALIDATE_TOKENS) {
2868 mWindowManager.validateAppTokens(mHistory);
2869 }
2870 return;
2871 }
2872 break;
2873 }
2874 if (p.fullscreen) {
2875 startIt = false;
2876 }
2877 next = p;
2878 }
2879 }
2880
2881 // Place a new activity at top of stack, so it is next to interact
2882 // with the user.
2883 if (addPos < 0) {
2884 addPos = mHistory.size();
2885 }
2886
2887 // If we are not placing the new activity frontmost, we do not want
2888 // to deliver the onUserLeaving callback to the actual frontmost
2889 // activity
2890 if (addPos < NH) {
2891 mUserLeaving = false;
2892 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2893 }
2894
2895 // Slot the activity into the history stack and proceed
2896 mHistory.add(addPos, r);
2897 r.inHistory = true;
2898 r.frontOfTask = newTask;
2899 r.task.numActivities++;
2900 if (NH > 0) {
2901 // We want to show the starting preview window if we are
2902 // switching to a new task, or the next activity's process is
2903 // not currently running.
2904 boolean showStartingIcon = newTask;
2905 ProcessRecord proc = r.app;
2906 if (proc == null) {
2907 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2908 }
2909 if (proc == null || proc.thread == null) {
2910 showStartingIcon = true;
2911 }
2912 if (DEBUG_TRANSITION) Log.v(TAG,
2913 "Prepare open transition: starting " + r);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002914 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
2915 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2916 mNoAnimActivities.add(r);
2917 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
2918 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
2919 mNoAnimActivities.remove(r);
2920 } else {
2921 mWindowManager.prepareAppTransition(newTask
2922 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2923 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2924 mNoAnimActivities.remove(r);
2925 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002926 mWindowManager.addAppToken(
2927 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2928 boolean doShow = true;
2929 if (newTask) {
2930 // Even though this activity is starting fresh, we still need
2931 // to reset it to make sure we apply affinities to move any
2932 // existing activities from other tasks in to it.
2933 // If the caller has requested that the target task be
2934 // reset, then do so.
2935 if ((r.intent.getFlags()
2936 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2937 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002938 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002939 }
2940 }
2941 if (SHOW_APP_STARTING_ICON && doShow) {
2942 // Figure out if we are transitioning from another activity that is
2943 // "has the same starting icon" as the next one. This allows the
2944 // window manager to keep the previous window it had previously
2945 // created, if it still had one.
2946 HistoryRecord prev = mResumedActivity;
2947 if (prev != null) {
2948 // We don't want to reuse the previous starting preview if:
2949 // (1) The current activity is in a different task.
2950 if (prev.task != r.task) prev = null;
2951 // (2) The current activity is already displayed.
2952 else if (prev.nowVisible) prev = null;
2953 }
2954 mWindowManager.setAppStartingWindow(
2955 r, r.packageName, r.theme, r.nonLocalizedLabel,
2956 r.labelRes, r.icon, prev, showStartingIcon);
2957 }
2958 } else {
2959 // If this is the first activity, don't do any fancy animations,
2960 // because there is nothing for it to animate on top of.
2961 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2962 r.info.screenOrientation, r.fullscreen);
2963 }
2964 if (VALIDATE_TOKENS) {
2965 mWindowManager.validateAppTokens(mHistory);
2966 }
2967
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002968 if (doResume) {
2969 resumeTopActivityLocked(null);
2970 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002971 }
2972
2973 /**
2974 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002975 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2976 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002977 * an instance of that activity in the stack and, if found, finish all
2978 * activities on top of it and return the instance.
2979 *
2980 * @param newR Description of the new activity being started.
2981 * @return Returns the old activity that should be continue to be used,
2982 * or null if none was found.
2983 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002984 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002985 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002986 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002987
2988 // First find the requested task.
2989 while (i > 0) {
2990 i--;
2991 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2992 if (r.task.taskId == taskId) {
2993 i++;
2994 break;
2995 }
2996 }
2997
2998 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002999 while (i > 0) {
3000 i--;
3001 HistoryRecord r = (HistoryRecord)mHistory.get(i);
3002 if (r.finishing) {
3003 continue;
3004 }
3005 if (r.task.taskId != taskId) {
3006 return null;
3007 }
3008 if (r.realActivity.equals(newR.realActivity)) {
3009 // Here it is! Now finish everything in front...
3010 HistoryRecord ret = r;
3011 if (doClear) {
3012 while (i < (mHistory.size()-1)) {
3013 i++;
3014 r = (HistoryRecord)mHistory.get(i);
3015 if (r.finishing) {
3016 continue;
3017 }
3018 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
3019 null, "clear")) {
3020 i--;
3021 }
3022 }
3023 }
3024
3025 // Finally, if this is a normal launch mode (that is, not
3026 // expecting onNewIntent()), then we will finish the current
3027 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003028 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
3029 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003030 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003031 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003032 if (index >= 0) {
3033 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
3034 null, "clear");
3035 }
3036 return null;
3037 }
3038 }
3039
3040 return ret;
3041 }
3042 }
3043
3044 return null;
3045 }
3046
3047 /**
3048 * Find the activity in the history stack within the given task. Returns
3049 * the index within the history at which it's found, or < 0 if not found.
3050 */
3051 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
3052 int i = mHistory.size();
3053 while (i > 0) {
3054 i--;
3055 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
3056 if (candidate.task.taskId != task) {
3057 break;
3058 }
3059 if (candidate.realActivity.equals(r.realActivity)) {
3060 return i;
3061 }
3062 }
3063
3064 return -1;
3065 }
3066
3067 /**
3068 * Reorder the history stack so that the activity at the given index is
3069 * brought to the front.
3070 */
3071 private final HistoryRecord moveActivityToFrontLocked(int where) {
3072 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3073 int top = mHistory.size();
3074 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3075 mHistory.add(top, newTop);
3076 oldTop.frontOfTask = false;
3077 newTop.frontOfTask = true;
3078 return newTop;
3079 }
3080
3081 /**
3082 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3083 * method will be called at the proper time.
3084 */
3085 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3086 boolean sent = false;
3087 if (r.state == ActivityState.RESUMED
3088 && r.app != null && r.app.thread != null) {
3089 try {
3090 ArrayList<Intent> ar = new ArrayList<Intent>();
3091 ar.add(new Intent(intent));
3092 r.app.thread.scheduleNewIntent(ar, r);
3093 sent = true;
3094 } catch (Exception e) {
3095 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3096 }
3097 }
3098 if (!sent) {
3099 r.addNewIntentLocked(new Intent(intent));
3100 }
3101 }
3102
3103 private final void logStartActivity(int tag, HistoryRecord r,
3104 TaskRecord task) {
3105 EventLog.writeEvent(tag,
3106 System.identityHashCode(r), task.taskId,
3107 r.shortComponentName, r.intent.getAction(),
3108 r.intent.getType(), r.intent.getDataString(),
3109 r.intent.getFlags());
3110 }
3111
3112 private final int startActivityLocked(IApplicationThread caller,
3113 Intent intent, String resolvedType,
3114 Uri[] grantedUriPermissions,
3115 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3116 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003117 int callingPid, int callingUid, boolean onlyIfNeeded,
3118 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003119 Log.i(TAG, "Starting activity: " + intent);
3120
3121 HistoryRecord sourceRecord = null;
3122 HistoryRecord resultRecord = null;
3123 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003124 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003125 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003126 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3127 if (index >= 0) {
3128 sourceRecord = (HistoryRecord)mHistory.get(index);
3129 if (requestCode >= 0 && !sourceRecord.finishing) {
3130 resultRecord = sourceRecord;
3131 }
3132 }
3133 }
3134
3135 int launchFlags = intent.getFlags();
3136
3137 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3138 && sourceRecord != null) {
3139 // Transfer the result target from the source activity to the new
3140 // one being started, including any failures.
3141 if (requestCode >= 0) {
3142 return START_FORWARD_AND_REQUEST_CONFLICT;
3143 }
3144 resultRecord = sourceRecord.resultTo;
3145 resultWho = sourceRecord.resultWho;
3146 requestCode = sourceRecord.requestCode;
3147 sourceRecord.resultTo = null;
3148 if (resultRecord != null) {
3149 resultRecord.removeResultsLocked(
3150 sourceRecord, resultWho, requestCode);
3151 }
3152 }
3153
3154 int err = START_SUCCESS;
3155
3156 if (intent.getComponent() == null) {
3157 // We couldn't find a class that can handle the given Intent.
3158 // That's the end of that!
3159 err = START_INTENT_NOT_RESOLVED;
3160 }
3161
3162 if (err == START_SUCCESS && aInfo == null) {
3163 // We couldn't find the specific class specified in the Intent.
3164 // Also the end of the line.
3165 err = START_CLASS_NOT_FOUND;
3166 }
3167
3168 ProcessRecord callerApp = null;
3169 if (err == START_SUCCESS && caller != null) {
3170 callerApp = getRecordForAppLocked(caller);
3171 if (callerApp != null) {
3172 callingPid = callerApp.pid;
3173 callingUid = callerApp.info.uid;
3174 } else {
3175 Log.w(TAG, "Unable to find app for caller " + caller
3176 + " (pid=" + callingPid + ") when starting: "
3177 + intent.toString());
3178 err = START_PERMISSION_DENIED;
3179 }
3180 }
3181
3182 if (err != START_SUCCESS) {
3183 if (resultRecord != null) {
3184 sendActivityResultLocked(-1,
3185 resultRecord, resultWho, requestCode,
3186 Activity.RESULT_CANCELED, null);
3187 }
3188 return err;
3189 }
3190
3191 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3192 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3193 if (perm != PackageManager.PERMISSION_GRANTED) {
3194 if (resultRecord != null) {
3195 sendActivityResultLocked(-1,
3196 resultRecord, resultWho, requestCode,
3197 Activity.RESULT_CANCELED, null);
3198 }
3199 String msg = "Permission Denial: starting " + intent.toString()
3200 + " from " + callerApp + " (pid=" + callingPid
3201 + ", uid=" + callingUid + ")"
3202 + " requires " + aInfo.permission;
3203 Log.w(TAG, msg);
3204 throw new SecurityException(msg);
3205 }
3206
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003207 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003208 boolean abort = false;
3209 try {
3210 // The Intent we give to the watcher has the extra data
3211 // stripped off, since it can contain private information.
3212 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003213 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003214 aInfo.applicationInfo.packageName);
3215 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003216 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003217 }
3218
3219 if (abort) {
3220 if (resultRecord != null) {
3221 sendActivityResultLocked(-1,
3222 resultRecord, resultWho, requestCode,
3223 Activity.RESULT_CANCELED, null);
3224 }
3225 // We pretend to the caller that it was really started, but
3226 // they will just get a cancel result.
3227 return START_SUCCESS;
3228 }
3229 }
3230
3231 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3232 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003233 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003234
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003235 if (mResumedActivity == null
3236 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3237 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3238 PendingActivityLaunch pal = new PendingActivityLaunch();
3239 pal.r = r;
3240 pal.sourceRecord = sourceRecord;
3241 pal.grantedUriPermissions = grantedUriPermissions;
3242 pal.grantedMode = grantedMode;
3243 pal.onlyIfNeeded = onlyIfNeeded;
3244 mPendingActivityLaunches.add(pal);
3245 return START_SWITCHES_CANCELED;
3246 }
3247 }
3248
3249 if (mDidAppSwitch) {
3250 // This is the second allowed switch since we stopped switches,
3251 // so now just generally allow switches. Use case: user presses
3252 // home (switches disabled, switch to home, mDidAppSwitch now true);
3253 // user taps a home icon (coming from home so allowed, we hit here
3254 // and now allow anyone to switch again).
3255 mAppSwitchesAllowedTime = 0;
3256 } else {
3257 mDidAppSwitch = true;
3258 }
3259
3260 doPendingActivityLaunchesLocked(false);
3261
3262 return startActivityUncheckedLocked(r, sourceRecord,
3263 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3264 }
3265
3266 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3267 final int N = mPendingActivityLaunches.size();
3268 if (N <= 0) {
3269 return;
3270 }
3271 for (int i=0; i<N; i++) {
3272 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3273 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3274 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3275 doResume && i == (N-1));
3276 }
3277 mPendingActivityLaunches.clear();
3278 }
3279
3280 private final int startActivityUncheckedLocked(HistoryRecord r,
3281 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3282 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3283 final Intent intent = r.intent;
3284 final int callingUid = r.launchedFromUid;
3285
3286 int launchFlags = intent.getFlags();
3287
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003288 // We'll invoke onUserLeaving before onPause only if the launching
3289 // activity did not explicitly state that this is an automated launch.
3290 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3291 if (DEBUG_USER_LEAVING) Log.v(TAG,
3292 "startActivity() => mUserLeaving=" + mUserLeaving);
3293
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003294 // If the caller has asked not to resume at this point, we make note
3295 // of this in the record so that we can skip it when trying to find
3296 // the top running activity.
3297 if (!doResume) {
3298 r.delayedResume = true;
3299 }
3300
3301 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3302 != 0 ? r : null;
3303
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003304 // If the onlyIfNeeded flag is set, then we can do this if the activity
3305 // being launched is the same as the one making the call... or, as
3306 // a special case, if we do not know the caller then we count the
3307 // current top activity as the caller.
3308 if (onlyIfNeeded) {
3309 HistoryRecord checkedCaller = sourceRecord;
3310 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003311 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003312 }
3313 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3314 // Caller is not the same as launcher, so always needed.
3315 onlyIfNeeded = false;
3316 }
3317 }
3318
3319 if (grantedUriPermissions != null && callingUid > 0) {
3320 for (int i=0; i<grantedUriPermissions.length; i++) {
3321 grantUriPermissionLocked(callingUid, r.packageName,
3322 grantedUriPermissions[i], grantedMode, r);
3323 }
3324 }
3325
3326 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3327 intent, r);
3328
3329 if (sourceRecord == null) {
3330 // This activity is not being started from another... in this
3331 // case we -always- start a new task.
3332 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3333 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3334 + intent);
3335 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3336 }
3337 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3338 // The original activity who is starting us is running as a single
3339 // instance... this new activity it is starting must go on its
3340 // own task.
3341 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3342 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3343 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3344 // The activity being started is a single instance... it always
3345 // gets launched into its own task.
3346 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3347 }
3348
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003349 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003350 // For whatever reason this activity is being launched into a new
3351 // task... yet the caller has requested a result back. Well, that
3352 // is pretty messed up, so instead immediately send back a cancel
3353 // and let the new task continue launched as normal without a
3354 // dependency on its originator.
3355 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3356 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003357 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003358 Activity.RESULT_CANCELED, null);
3359 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003360 }
3361
3362 boolean addingToTask = false;
3363 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3364 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3365 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3366 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3367 // If bring to front is requested, and no result is requested, and
3368 // we can find a task that was started with this same
3369 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003370 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003371 // See if there is a task to bring to the front. If this is
3372 // a SINGLE_INSTANCE activity, there can be one and only one
3373 // instance of it in the history, and it is always in its own
3374 // unique task, so we do a special search.
3375 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3376 ? findTaskLocked(intent, r.info)
3377 : findActivityLocked(intent, r.info);
3378 if (taskTop != null) {
3379 if (taskTop.task.intent == null) {
3380 // This task was started because of movement of
3381 // the activity based on affinity... now that we
3382 // are actually launching it, we can assign the
3383 // base intent.
3384 taskTop.task.setIntent(intent, r.info);
3385 }
3386 // If the target task is not in the front, then we need
3387 // to bring it to the front... except... well, with
3388 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3389 // to have the same behavior as if a new instance was
3390 // being started, which means not bringing it to the front
3391 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003392 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003393 if (curTop.task != taskTop.task) {
3394 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3395 boolean callerAtFront = sourceRecord == null
3396 || curTop.task == sourceRecord.task;
3397 if (callerAtFront) {
3398 // We really do want to push this one into the
3399 // user's face, right now.
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07003400 moveTaskToFrontLocked(taskTop.task, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003401 }
3402 }
3403 // If the caller has requested that the target task be
3404 // reset, then do so.
3405 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3406 taskTop = resetTaskIfNeededLocked(taskTop, r);
3407 }
3408 if (onlyIfNeeded) {
3409 // We don't need to start a new activity, and
3410 // the client said not to do anything if that
3411 // is the case, so this is it! And for paranoia, make
3412 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003413 if (doResume) {
3414 resumeTopActivityLocked(null);
3415 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003416 return START_RETURN_INTENT_TO_CALLER;
3417 }
3418 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3419 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3420 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3421 // In this situation we want to remove all activities
3422 // from the task up to the one being started. In most
3423 // cases this means we are resetting the task to its
3424 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003425 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003426 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003427 if (top != null) {
3428 if (top.frontOfTask) {
3429 // Activity aliases may mean we use different
3430 // intents for the top activity, so make sure
3431 // the task now has the identity of the new
3432 // intent.
3433 top.task.setIntent(r.intent, r.info);
3434 }
Doug Zongker2bec3d42009-12-04 12:52:44 -08003435 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003436 deliverNewIntentLocked(top, r.intent);
3437 } else {
3438 // A special case: we need to
3439 // start the activity because it is not currently
3440 // running, and the caller has asked to clear the
3441 // current task to have this activity at the top.
3442 addingToTask = true;
3443 // Now pretend like this activity is being started
3444 // by the top of its task, so it is put in the
3445 // right place.
3446 sourceRecord = taskTop;
3447 }
3448 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3449 // In this case the top activity on the task is the
3450 // same as the one being launched, so we take that
3451 // as a request to bring the task to the foreground.
3452 // If the top activity in the task is the root
3453 // activity, deliver this new intent to it if it
3454 // desires.
3455 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3456 && taskTop.realActivity.equals(r.realActivity)) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003457 logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003458 if (taskTop.frontOfTask) {
3459 taskTop.task.setIntent(r.intent, r.info);
3460 }
3461 deliverNewIntentLocked(taskTop, r.intent);
3462 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3463 // In this case we are launching the root activity
3464 // of the task, but with a different intent. We
3465 // should start a new instance on top.
3466 addingToTask = true;
3467 sourceRecord = taskTop;
3468 }
3469 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3470 // In this case an activity is being launched in to an
3471 // existing task, without resetting that task. This
3472 // is typically the situation of launching an activity
3473 // from a notification or shortcut. We want to place
3474 // the new activity on top of the current task.
3475 addingToTask = true;
3476 sourceRecord = taskTop;
3477 } else if (!taskTop.task.rootWasReset) {
3478 // In this case we are launching in to an existing task
3479 // that has not yet been started from its front door.
3480 // The current task has been brought to the front.
3481 // Ideally, we'd probably like to place this new task
3482 // at the bottom of its stack, but that's a little hard
3483 // to do with the current organization of the code so
3484 // for now we'll just drop it.
3485 taskTop.task.setIntent(r.intent, r.info);
3486 }
3487 if (!addingToTask) {
3488 // We didn't do anything... but it was needed (a.k.a., client
3489 // don't use that intent!) And for paranoia, make
3490 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003491 if (doResume) {
3492 resumeTopActivityLocked(null);
3493 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003494 return START_TASK_TO_FRONT;
3495 }
3496 }
3497 }
3498 }
3499
3500 //String uri = r.intent.toURI();
3501 //Intent intent2 = new Intent(uri);
3502 //Log.i(TAG, "Given intent: " + r.intent);
3503 //Log.i(TAG, "URI is: " + uri);
3504 //Log.i(TAG, "To intent: " + intent2);
3505
3506 if (r.packageName != null) {
3507 // If the activity being launched is the same as the one currently
3508 // at the top, then we need to check if it should only be launched
3509 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003510 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3511 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003512 if (top.realActivity.equals(r.realActivity)) {
3513 if (top.app != null && top.app.thread != null) {
3514 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3515 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3516 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003517 logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003518 // For paranoia, make sure we have correctly
3519 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003520 if (doResume) {
3521 resumeTopActivityLocked(null);
3522 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003523 if (onlyIfNeeded) {
3524 // We don't need to start a new activity, and
3525 // the client said not to do anything if that
3526 // is the case, so this is it!
3527 return START_RETURN_INTENT_TO_CALLER;
3528 }
3529 deliverNewIntentLocked(top, r.intent);
3530 return START_DELIVERED_TO_TOP;
3531 }
3532 }
3533 }
3534 }
3535
3536 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003537 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003538 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003539 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003540 Activity.RESULT_CANCELED, null);
3541 }
3542 return START_CLASS_NOT_FOUND;
3543 }
3544
3545 boolean newTask = false;
3546
3547 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003548 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003549 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3550 // todo: should do better management of integers.
3551 mCurTask++;
3552 if (mCurTask <= 0) {
3553 mCurTask = 1;
3554 }
3555 r.task = new TaskRecord(mCurTask, r.info, intent,
3556 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3557 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3558 + " in new task " + r.task);
3559 newTask = true;
3560 addRecentTask(r.task);
3561
3562 } else if (sourceRecord != null) {
3563 if (!addingToTask &&
3564 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3565 // In this case, we are adding the activity to an existing
3566 // task, but the caller has asked to clear that task if the
3567 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003568 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003569 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003570 if (top != null) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003571 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003572 deliverNewIntentLocked(top, r.intent);
3573 // For paranoia, make sure we have correctly
3574 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003575 if (doResume) {
3576 resumeTopActivityLocked(null);
3577 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003578 return START_DELIVERED_TO_TOP;
3579 }
3580 } else if (!addingToTask &&
3581 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3582 // In this case, we are launching an activity in our own task
3583 // that may already be running somewhere in the history, and
3584 // we want to shuffle it to the front of the stack if so.
3585 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3586 if (where >= 0) {
3587 HistoryRecord top = moveActivityToFrontLocked(where);
Doug Zongker2bec3d42009-12-04 12:52:44 -08003588 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003589 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003590 if (doResume) {
3591 resumeTopActivityLocked(null);
3592 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003593 return START_DELIVERED_TO_TOP;
3594 }
3595 }
3596 // An existing activity is starting this new activity, so we want
3597 // to keep the new one in the same task as the one that is starting
3598 // it.
3599 r.task = sourceRecord.task;
3600 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3601 + " in existing task " + r.task);
3602
3603 } else {
3604 // This not being started from an existing activity, and not part
3605 // of a new task... just put it in the top task, though these days
3606 // this case should never happen.
3607 final int N = mHistory.size();
3608 HistoryRecord prev =
3609 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3610 r.task = prev != null
3611 ? prev.task
3612 : new TaskRecord(mCurTask, r.info, intent,
3613 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3614 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3615 + " in new guessed " + r.task);
3616 }
3617 if (newTask) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003618 EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003619 }
Doug Zongker2bec3d42009-12-04 12:52:44 -08003620 logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003621 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003622 return START_SUCCESS;
3623 }
3624
3625 public final int startActivity(IApplicationThread caller,
3626 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3627 int grantedMode, IBinder resultTo,
3628 String resultWho, int requestCode, boolean onlyIfNeeded,
3629 boolean debug) {
3630 // Refuse possible leaked file descriptors
3631 if (intent != null && intent.hasFileDescriptors()) {
3632 throw new IllegalArgumentException("File descriptors passed in Intent");
3633 }
3634
The Android Open Source Project4df24232009-03-05 14:34:35 -08003635 final boolean componentSpecified = intent.getComponent() != null;
3636
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003637 // Don't modify the client's object!
3638 intent = new Intent(intent);
3639
3640 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003641 ActivityInfo aInfo;
3642 try {
3643 ResolveInfo rInfo =
3644 ActivityThread.getPackageManager().resolveIntent(
3645 intent, resolvedType,
3646 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003647 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003648 aInfo = rInfo != null ? rInfo.activityInfo : null;
3649 } catch (RemoteException e) {
3650 aInfo = null;
3651 }
3652
3653 if (aInfo != null) {
3654 // Store the found target back into the intent, because now that
3655 // we have it we never want to do this again. For example, if the
3656 // user navigates back to this point in the history, we should
3657 // always restart the exact same activity.
3658 intent.setComponent(new ComponentName(
3659 aInfo.applicationInfo.packageName, aInfo.name));
3660
3661 // Don't debug things in the system process
3662 if (debug) {
3663 if (!aInfo.processName.equals("system")) {
3664 setDebugApp(aInfo.processName, true, false);
3665 }
3666 }
3667 }
3668
3669 synchronized(this) {
3670 final long origId = Binder.clearCallingIdentity();
3671 int res = startActivityLocked(caller, intent, resolvedType,
3672 grantedUriPermissions, grantedMode, aInfo,
3673 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003674 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003675 Binder.restoreCallingIdentity(origId);
3676 return res;
3677 }
3678 }
3679
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003680 public int startActivityIntentSender(IApplicationThread caller,
3681 IntentSender intent, Intent fillInIntent, String resolvedType,
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003682 IBinder resultTo, String resultWho, int requestCode,
3683 int flagsMask, int flagsValues) {
3684 // Refuse possible leaked file descriptors
3685 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3686 throw new IllegalArgumentException("File descriptors passed in Intent");
3687 }
3688
3689 IIntentSender sender = intent.getTarget();
3690 if (!(sender instanceof PendingIntentRecord)) {
3691 throw new IllegalArgumentException("Bad PendingIntent object");
3692 }
3693
3694 PendingIntentRecord pir = (PendingIntentRecord)sender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003695
3696 synchronized (this) {
3697 // If this is coming from the currently resumed activity, it is
3698 // effectively saying that app switches are allowed at this point.
3699 if (mResumedActivity != null
3700 && mResumedActivity.info.applicationInfo.uid ==
3701 Binder.getCallingUid()) {
3702 mAppSwitchesAllowedTime = 0;
3703 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003704 }
3705
3706 return pir.sendInner(0, fillInIntent, resolvedType,
3707 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3708 }
3709
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003710 public boolean startNextMatchingActivity(IBinder callingActivity,
3711 Intent intent) {
3712 // Refuse possible leaked file descriptors
3713 if (intent != null && intent.hasFileDescriptors() == true) {
3714 throw new IllegalArgumentException("File descriptors passed in Intent");
3715 }
3716
3717 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003718 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003719 if (index < 0) {
3720 return false;
3721 }
3722 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3723 if (r.app == null || r.app.thread == null) {
3724 // The caller is not running... d'oh!
3725 return false;
3726 }
3727 intent = new Intent(intent);
3728 // The caller is not allowed to change the data.
3729 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3730 // And we are resetting to find the next component...
3731 intent.setComponent(null);
3732
3733 ActivityInfo aInfo = null;
3734 try {
3735 List<ResolveInfo> resolves =
3736 ActivityThread.getPackageManager().queryIntentActivities(
3737 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003738 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003739
3740 // Look for the original activity in the list...
3741 final int N = resolves != null ? resolves.size() : 0;
3742 for (int i=0; i<N; i++) {
3743 ResolveInfo rInfo = resolves.get(i);
3744 if (rInfo.activityInfo.packageName.equals(r.packageName)
3745 && rInfo.activityInfo.name.equals(r.info.name)) {
3746 // We found the current one... the next matching is
3747 // after it.
3748 i++;
3749 if (i<N) {
3750 aInfo = resolves.get(i).activityInfo;
3751 }
3752 break;
3753 }
3754 }
3755 } catch (RemoteException e) {
3756 }
3757
3758 if (aInfo == null) {
3759 // Nobody who is next!
3760 return false;
3761 }
3762
3763 intent.setComponent(new ComponentName(
3764 aInfo.applicationInfo.packageName, aInfo.name));
3765 intent.setFlags(intent.getFlags()&~(
3766 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3767 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3768 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3769 Intent.FLAG_ACTIVITY_NEW_TASK));
3770
3771 // Okay now we need to start the new activity, replacing the
3772 // currently running activity. This is a little tricky because
3773 // we want to start the new one as if the current one is finished,
3774 // but not finish the current one first so that there is no flicker.
3775 // And thus...
3776 final boolean wasFinishing = r.finishing;
3777 r.finishing = true;
3778
3779 // Propagate reply information over to the new activity.
3780 final HistoryRecord resultTo = r.resultTo;
3781 final String resultWho = r.resultWho;
3782 final int requestCode = r.requestCode;
3783 r.resultTo = null;
3784 if (resultTo != null) {
3785 resultTo.removeResultsLocked(r, resultWho, requestCode);
3786 }
3787
3788 final long origId = Binder.clearCallingIdentity();
3789 // XXX we are not dealing with propagating grantedUriPermissions...
3790 // those are not yet exposed to user code, so there is no need.
3791 int res = startActivityLocked(r.app.thread, intent,
3792 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003793 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003794 Binder.restoreCallingIdentity(origId);
3795
3796 r.finishing = wasFinishing;
3797 if (res != START_SUCCESS) {
3798 return false;
3799 }
3800 return true;
3801 }
3802 }
3803
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003804 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003805 Intent intent, String resolvedType, IBinder resultTo,
3806 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003807
3808 // This is so super not safe, that only the system (or okay root)
3809 // can do it.
3810 final int callingUid = Binder.getCallingUid();
3811 if (callingUid != 0 && callingUid != Process.myUid()) {
3812 throw new SecurityException(
3813 "startActivityInPackage only available to the system");
3814 }
3815
The Android Open Source Project4df24232009-03-05 14:34:35 -08003816 final boolean componentSpecified = intent.getComponent() != null;
3817
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003818 // Don't modify the client's object!
3819 intent = new Intent(intent);
3820
3821 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003822 ActivityInfo aInfo;
3823 try {
3824 ResolveInfo rInfo =
3825 ActivityThread.getPackageManager().resolveIntent(
3826 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003827 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003828 aInfo = rInfo != null ? rInfo.activityInfo : null;
3829 } catch (RemoteException e) {
3830 aInfo = null;
3831 }
3832
3833 if (aInfo != null) {
3834 // Store the found target back into the intent, because now that
3835 // we have it we never want to do this again. For example, if the
3836 // user navigates back to this point in the history, we should
3837 // always restart the exact same activity.
3838 intent.setComponent(new ComponentName(
3839 aInfo.applicationInfo.packageName, aInfo.name));
3840 }
3841
3842 synchronized(this) {
3843 return startActivityLocked(null, intent, resolvedType,
3844 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003845 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003846 }
3847 }
3848
3849 private final void addRecentTask(TaskRecord task) {
3850 // Remove any existing entries that are the same kind of task.
3851 int N = mRecentTasks.size();
3852 for (int i=0; i<N; i++) {
3853 TaskRecord tr = mRecentTasks.get(i);
3854 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3855 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3856 mRecentTasks.remove(i);
3857 i--;
3858 N--;
3859 if (task.intent == null) {
3860 // If the new recent task we are adding is not fully
3861 // specified, then replace it with the existing recent task.
3862 task = tr;
3863 }
3864 }
3865 }
3866 if (N >= MAX_RECENT_TASKS) {
3867 mRecentTasks.remove(N-1);
3868 }
3869 mRecentTasks.add(0, task);
3870 }
3871
3872 public void setRequestedOrientation(IBinder token,
3873 int requestedOrientation) {
3874 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003875 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003876 if (index < 0) {
3877 return;
3878 }
3879 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3880 final long origId = Binder.clearCallingIdentity();
3881 mWindowManager.setAppOrientation(r, requestedOrientation);
3882 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003883 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003884 r.mayFreezeScreenLocked(r.app) ? r : null);
3885 if (config != null) {
3886 r.frozenBeforeDestroy = true;
3887 if (!updateConfigurationLocked(config, r)) {
3888 resumeTopActivityLocked(null);
3889 }
3890 }
3891 Binder.restoreCallingIdentity(origId);
3892 }
3893 }
3894
3895 public int getRequestedOrientation(IBinder token) {
3896 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003897 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003898 if (index < 0) {
3899 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3900 }
3901 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3902 return mWindowManager.getAppOrientation(r);
3903 }
3904 }
3905
3906 private final void stopActivityLocked(HistoryRecord r) {
3907 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3908 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3909 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3910 if (!r.finishing) {
3911 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3912 "no-history");
3913 }
3914 } else if (r.app != null && r.app.thread != null) {
3915 if (mFocusedActivity == r) {
3916 setFocusedActivityLocked(topRunningActivityLocked(null));
3917 }
3918 r.resumeKeyDispatchingLocked();
3919 try {
3920 r.stopped = false;
3921 r.state = ActivityState.STOPPING;
3922 if (DEBUG_VISBILITY) Log.v(
3923 TAG, "Stopping visible=" + r.visible + " for " + r);
3924 if (!r.visible) {
3925 mWindowManager.setAppVisibility(r, false);
3926 }
3927 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3928 } catch (Exception e) {
3929 // Maybe just ignore exceptions here... if the process
3930 // has crashed, our death notification will clean things
3931 // up.
3932 Log.w(TAG, "Exception thrown during pause", e);
3933 // Just in case, assume it to be stopped.
3934 r.stopped = true;
3935 r.state = ActivityState.STOPPED;
3936 if (r.configDestroy) {
3937 destroyActivityLocked(r, true);
3938 }
3939 }
3940 }
3941 }
3942
3943 /**
3944 * @return Returns true if the activity is being finished, false if for
3945 * some reason it is being left as-is.
3946 */
3947 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3948 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003949 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003950 TAG, "Finishing activity: token=" + token
3951 + ", result=" + resultCode + ", data=" + resultData);
3952
Dianne Hackborn75b03852009-06-12 15:43:26 -07003953 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003954 if (index < 0) {
3955 return false;
3956 }
3957 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3958
3959 // Is this the last activity left?
3960 boolean lastActivity = true;
3961 for (int i=mHistory.size()-1; i>=0; i--) {
3962 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3963 if (!p.finishing && p != r) {
3964 lastActivity = false;
3965 break;
3966 }
3967 }
3968
3969 // If this is the last activity, but it is the home activity, then
3970 // just don't finish it.
3971 if (lastActivity) {
3972 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3973 return false;
3974 }
3975 }
3976
3977 finishActivityLocked(r, index, resultCode, resultData, reason);
3978 return true;
3979 }
3980
3981 /**
3982 * @return Returns true if this activity has been removed from the history
3983 * list, or false if it is still in the list and will be removed later.
3984 */
3985 private final boolean finishActivityLocked(HistoryRecord r, int index,
3986 int resultCode, Intent resultData, String reason) {
3987 if (r.finishing) {
3988 Log.w(TAG, "Duplicate finish request for " + r);
3989 return false;
3990 }
3991
3992 r.finishing = true;
Doug Zongker2bec3d42009-12-04 12:52:44 -08003993 EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003994 System.identityHashCode(r),
3995 r.task.taskId, r.shortComponentName, reason);
3996 r.task.numActivities--;
3997 if (r.frontOfTask && index < (mHistory.size()-1)) {
3998 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3999 if (next.task == r.task) {
4000 next.frontOfTask = true;
4001 }
4002 }
4003
4004 r.pauseKeyDispatchingLocked();
4005 if (mFocusedActivity == r) {
4006 setFocusedActivityLocked(topRunningActivityLocked(null));
4007 }
4008
4009 // send the result
4010 HistoryRecord resultTo = r.resultTo;
4011 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07004012 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
4013 + " who=" + r.resultWho + " req=" + r.requestCode
4014 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004015 if (r.info.applicationInfo.uid > 0) {
4016 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
4017 r.packageName, resultData, r);
4018 }
4019 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
4020 resultData);
4021 r.resultTo = null;
4022 }
Chris Tate8a7dc172009-03-24 20:11:42 -07004023 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004024
4025 // Make sure this HistoryRecord is not holding on to other resources,
4026 // because clients have remote IPC references to this object so we
4027 // can't assume that will go away and want to avoid circular IPC refs.
4028 r.results = null;
4029 r.pendingResults = null;
4030 r.newIntents = null;
4031 r.icicle = null;
4032
4033 if (mPendingThumbnails.size() > 0) {
4034 // There are clients waiting to receive thumbnails so, in case
4035 // this is an activity that someone is waiting for, add it
4036 // to the pending list so we can correctly update the clients.
4037 mCancelledThumbnails.add(r);
4038 }
4039
4040 if (mResumedActivity == r) {
4041 boolean endTask = index <= 0
4042 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
4043 if (DEBUG_TRANSITION) Log.v(TAG,
4044 "Prepare close transition: finishing " + r);
4045 mWindowManager.prepareAppTransition(endTask
4046 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
4047 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
4048
4049 // Tell window manager to prepare for this one to be removed.
4050 mWindowManager.setAppVisibility(r, false);
4051
4052 if (mPausingActivity == null) {
4053 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
4054 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
4055 startPausingLocked(false, false);
4056 }
4057
4058 } else if (r.state != ActivityState.PAUSING) {
4059 // If the activity is PAUSING, we will complete the finish once
4060 // it is done pausing; else we can just directly finish it here.
4061 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
4062 return finishCurrentActivityLocked(r, index,
4063 FINISH_AFTER_PAUSE) == null;
4064 } else {
4065 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
4066 }
4067
4068 return false;
4069 }
4070
4071 private static final int FINISH_IMMEDIATELY = 0;
4072 private static final int FINISH_AFTER_PAUSE = 1;
4073 private static final int FINISH_AFTER_VISIBLE = 2;
4074
4075 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4076 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004077 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004078 if (index < 0) {
4079 return null;
4080 }
4081
4082 return finishCurrentActivityLocked(r, index, mode);
4083 }
4084
4085 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4086 int index, int mode) {
4087 // First things first: if this activity is currently visible,
4088 // and the resumed activity is not yet visible, then hold off on
4089 // finishing until the resumed one becomes visible.
4090 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4091 if (!mStoppingActivities.contains(r)) {
4092 mStoppingActivities.add(r);
4093 if (mStoppingActivities.size() > 3) {
4094 // If we already have a few activities waiting to stop,
4095 // then give up on things going idle and start clearing
4096 // them out.
4097 Message msg = Message.obtain();
4098 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4099 mHandler.sendMessage(msg);
4100 }
4101 }
4102 r.state = ActivityState.STOPPING;
4103 updateOomAdjLocked();
4104 return r;
4105 }
4106
4107 // make sure the record is cleaned out of other places.
4108 mStoppingActivities.remove(r);
4109 mWaitingVisibleActivities.remove(r);
4110 if (mResumedActivity == r) {
4111 mResumedActivity = null;
4112 }
4113 final ActivityState prevState = r.state;
4114 r.state = ActivityState.FINISHING;
4115
4116 if (mode == FINISH_IMMEDIATELY
4117 || prevState == ActivityState.STOPPED
4118 || prevState == ActivityState.INITIALIZING) {
4119 // If this activity is already stopped, we can just finish
4120 // it right now.
4121 return destroyActivityLocked(r, true) ? null : r;
4122 } else {
4123 // Need to go through the full pause cycle to get this
4124 // activity into the stopped state and then finish it.
4125 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4126 mFinishingActivities.add(r);
4127 resumeTopActivityLocked(null);
4128 }
4129 return r;
4130 }
4131
4132 /**
4133 * This is the internal entry point for handling Activity.finish().
4134 *
4135 * @param token The Binder token referencing the Activity we want to finish.
4136 * @param resultCode Result code, if any, from this Activity.
4137 * @param resultData Result data (Intent), if any, from this Activity.
4138 *
Alexey Tarasov83bad3d2009-08-12 15:05:43 +11004139 * @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 -08004140 */
4141 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4142 // Refuse possible leaked file descriptors
4143 if (resultData != null && resultData.hasFileDescriptors() == true) {
4144 throw new IllegalArgumentException("File descriptors passed in Intent");
4145 }
4146
4147 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004148 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004149 // Find the first activity that is not finishing.
4150 HistoryRecord next = topRunningActivityLocked(token, 0);
4151 if (next != null) {
4152 // ask watcher if this is allowed
4153 boolean resumeOK = true;
4154 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004155 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004156 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004157 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004158 }
4159
4160 if (!resumeOK) {
4161 return false;
4162 }
4163 }
4164 }
4165 final long origId = Binder.clearCallingIdentity();
4166 boolean res = requestFinishActivityLocked(token, resultCode,
4167 resultData, "app-request");
4168 Binder.restoreCallingIdentity(origId);
4169 return res;
4170 }
4171 }
4172
4173 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4174 String resultWho, int requestCode, int resultCode, Intent data) {
4175
4176 if (callingUid > 0) {
4177 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4178 data, r);
4179 }
4180
The Android Open Source Project10592532009-03-18 17:39:46 -07004181 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4182 + " : who=" + resultWho + " req=" + requestCode
4183 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004184 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4185 try {
4186 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4187 list.add(new ResultInfo(resultWho, requestCode,
4188 resultCode, data));
4189 r.app.thread.scheduleSendResult(r, list);
4190 return;
4191 } catch (Exception e) {
4192 Log.w(TAG, "Exception thrown sending result to " + r, e);
4193 }
4194 }
4195
4196 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4197 }
4198
4199 public final void finishSubActivity(IBinder token, String resultWho,
4200 int requestCode) {
4201 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004202 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004203 if (index < 0) {
4204 return;
4205 }
4206 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4207
4208 final long origId = Binder.clearCallingIdentity();
4209
4210 int i;
4211 for (i=mHistory.size()-1; i>=0; i--) {
4212 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4213 if (r.resultTo == self && r.requestCode == requestCode) {
4214 if ((r.resultWho == null && resultWho == null) ||
4215 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4216 finishActivityLocked(r, i,
4217 Activity.RESULT_CANCELED, null, "request-sub");
4218 }
4219 }
4220 }
4221
4222 Binder.restoreCallingIdentity(origId);
4223 }
4224 }
4225
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07004226 public void overridePendingTransition(IBinder token, String packageName,
4227 int enterAnim, int exitAnim) {
4228 synchronized(this) {
4229 int index = indexOfTokenLocked(token);
4230 if (index < 0) {
4231 return;
4232 }
4233 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4234
4235 final long origId = Binder.clearCallingIdentity();
4236
4237 if (self.state == ActivityState.RESUMED
4238 || self.state == ActivityState.PAUSING) {
4239 mWindowManager.overridePendingAppTransition(packageName,
4240 enterAnim, exitAnim);
4241 }
4242
4243 Binder.restoreCallingIdentity(origId);
4244 }
4245 }
4246
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004247 /**
4248 * Perform clean-up of service connections in an activity record.
4249 */
4250 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4251 // Throw away any services that have been bound by this activity.
4252 if (r.connections != null) {
4253 Iterator<ConnectionRecord> it = r.connections.iterator();
4254 while (it.hasNext()) {
4255 ConnectionRecord c = it.next();
4256 removeConnectionLocked(c, null, r);
4257 }
4258 r.connections = null;
4259 }
4260 }
4261
4262 /**
4263 * Perform the common clean-up of an activity record. This is called both
4264 * as part of destroyActivityLocked() (when destroying the client-side
4265 * representation) and cleaning things up as a result of its hosting
4266 * processing going away, in which case there is no remaining client-side
4267 * state to destroy so only the cleanup here is needed.
4268 */
4269 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4270 if (mResumedActivity == r) {
4271 mResumedActivity = null;
4272 }
4273 if (mFocusedActivity == r) {
4274 mFocusedActivity = null;
4275 }
4276
4277 r.configDestroy = false;
4278 r.frozenBeforeDestroy = false;
4279
4280 // Make sure this record is no longer in the pending finishes list.
4281 // This could happen, for example, if we are trimming activities
4282 // down to the max limit while they are still waiting to finish.
4283 mFinishingActivities.remove(r);
4284 mWaitingVisibleActivities.remove(r);
4285
4286 // Remove any pending results.
4287 if (r.finishing && r.pendingResults != null) {
4288 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4289 PendingIntentRecord rec = apr.get();
4290 if (rec != null) {
4291 cancelIntentSenderLocked(rec, false);
4292 }
4293 }
4294 r.pendingResults = null;
4295 }
4296
4297 if (cleanServices) {
4298 cleanUpActivityServicesLocked(r);
4299 }
4300
4301 if (mPendingThumbnails.size() > 0) {
4302 // There are clients waiting to receive thumbnails so, in case
4303 // this is an activity that someone is waiting for, add it
4304 // to the pending list so we can correctly update the clients.
4305 mCancelledThumbnails.add(r);
4306 }
4307
4308 // Get rid of any pending idle timeouts.
4309 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4310 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4311 }
4312
4313 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4314 if (r.state != ActivityState.DESTROYED) {
4315 mHistory.remove(r);
4316 r.inHistory = false;
4317 r.state = ActivityState.DESTROYED;
4318 mWindowManager.removeAppToken(r);
4319 if (VALIDATE_TOKENS) {
4320 mWindowManager.validateAppTokens(mHistory);
4321 }
4322 cleanUpActivityServicesLocked(r);
4323 removeActivityUriPermissionsLocked(r);
4324 }
4325 }
4326
4327 /**
4328 * Destroy the current CLIENT SIDE instance of an activity. This may be
4329 * called both when actually finishing an activity, or when performing
4330 * a configuration switch where we destroy the current client-side object
4331 * but then create a new client-side object for this same HistoryRecord.
4332 */
4333 private final boolean destroyActivityLocked(HistoryRecord r,
4334 boolean removeFromApp) {
4335 if (DEBUG_SWITCH) Log.v(
4336 TAG, "Removing activity: token=" + r
4337 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
Doug Zongker2bec3d42009-12-04 12:52:44 -08004338 EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004339 System.identityHashCode(r),
4340 r.task.taskId, r.shortComponentName);
4341
4342 boolean removedFromHistory = false;
4343
4344 cleanUpActivityLocked(r, false);
4345
4346 if (r.app != null) {
4347 if (removeFromApp) {
4348 int idx = r.app.activities.indexOf(r);
4349 if (idx >= 0) {
4350 r.app.activities.remove(idx);
4351 }
4352 if (r.persistent) {
4353 decPersistentCountLocked(r.app);
4354 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004355 if (r.app.activities.size() == 0) {
4356 // No longer have activities, so update location in
4357 // LRU list.
4358 updateLruProcessLocked(r.app, true, false);
4359 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004360 }
4361
4362 boolean skipDestroy = false;
4363
4364 try {
4365 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4366 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4367 r.configChangeFlags);
4368 } catch (Exception e) {
4369 // We can just ignore exceptions here... if the process
4370 // has crashed, our death notification will clean things
4371 // up.
4372 //Log.w(TAG, "Exception thrown during finish", e);
4373 if (r.finishing) {
4374 removeActivityFromHistoryLocked(r);
4375 removedFromHistory = true;
4376 skipDestroy = true;
4377 }
4378 }
4379
4380 r.app = null;
4381 r.nowVisible = false;
4382
4383 if (r.finishing && !skipDestroy) {
4384 r.state = ActivityState.DESTROYING;
4385 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4386 msg.obj = r;
4387 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4388 } else {
4389 r.state = ActivityState.DESTROYED;
4390 }
4391 } else {
4392 // remove this record from the history.
4393 if (r.finishing) {
4394 removeActivityFromHistoryLocked(r);
4395 removedFromHistory = true;
4396 } else {
4397 r.state = ActivityState.DESTROYED;
4398 }
4399 }
4400
4401 r.configChangeFlags = 0;
4402
4403 if (!mLRUActivities.remove(r)) {
4404 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4405 }
4406
4407 return removedFromHistory;
4408 }
4409
4410 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4411 ProcessRecord app)
4412 {
4413 int i = list.size();
4414 if (localLOGV) Log.v(
4415 TAG, "Removing app " + app + " from list " + list
4416 + " with " + i + " entries");
4417 while (i > 0) {
4418 i--;
4419 HistoryRecord r = (HistoryRecord)list.get(i);
4420 if (localLOGV) Log.v(
4421 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4422 if (r.app == app) {
4423 if (localLOGV) Log.v(TAG, "Removing this entry!");
4424 list.remove(i);
4425 }
4426 }
4427 }
4428
4429 /**
4430 * Main function for removing an existing process from the activity manager
4431 * as a result of that process going away. Clears out all connections
4432 * to the process.
4433 */
4434 private final void handleAppDiedLocked(ProcessRecord app,
4435 boolean restarting) {
4436 cleanUpApplicationRecordLocked(app, restarting, -1);
4437 if (!restarting) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004438 mLruProcesses.remove(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004439 }
4440
4441 // Just in case...
4442 if (mPausingActivity != null && mPausingActivity.app == app) {
4443 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4444 mPausingActivity = null;
4445 }
4446 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4447 mLastPausedActivity = null;
4448 }
4449
4450 // Remove this application's activities from active lists.
4451 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4452 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4453 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4454 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4455
4456 boolean atTop = true;
4457 boolean hasVisibleActivities = false;
4458
4459 // Clean out the history list.
4460 int i = mHistory.size();
4461 if (localLOGV) Log.v(
4462 TAG, "Removing app " + app + " from history with " + i + " entries");
4463 while (i > 0) {
4464 i--;
4465 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4466 if (localLOGV) Log.v(
4467 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4468 if (r.app == app) {
4469 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4470 if (localLOGV) Log.v(
4471 TAG, "Removing this entry! frozen=" + r.haveState
4472 + " finishing=" + r.finishing);
4473 mHistory.remove(i);
4474
4475 r.inHistory = false;
4476 mWindowManager.removeAppToken(r);
4477 if (VALIDATE_TOKENS) {
4478 mWindowManager.validateAppTokens(mHistory);
4479 }
4480 removeActivityUriPermissionsLocked(r);
4481
4482 } else {
4483 // We have the current state for this activity, so
4484 // it can be restarted later when needed.
4485 if (localLOGV) Log.v(
4486 TAG, "Keeping entry, setting app to null");
4487 if (r.visible) {
4488 hasVisibleActivities = true;
4489 }
4490 r.app = null;
4491 r.nowVisible = false;
4492 if (!r.haveState) {
4493 r.icicle = null;
4494 }
4495 }
4496
4497 cleanUpActivityLocked(r, true);
4498 r.state = ActivityState.STOPPED;
4499 }
4500 atTop = false;
4501 }
4502
4503 app.activities.clear();
4504
4505 if (app.instrumentationClass != null) {
4506 Log.w(TAG, "Crash of app " + app.processName
4507 + " running instrumentation " + app.instrumentationClass);
4508 Bundle info = new Bundle();
4509 info.putString("shortMsg", "Process crashed.");
4510 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4511 }
4512
4513 if (!restarting) {
4514 if (!resumeTopActivityLocked(null)) {
4515 // If there was nothing to resume, and we are not already
4516 // restarting this process, but there is a visible activity that
4517 // is hosted by the process... then make sure all visible
4518 // activities are running, taking care of restarting this
4519 // process.
4520 if (hasVisibleActivities) {
4521 ensureActivitiesVisibleLocked(null, 0);
4522 }
4523 }
4524 }
4525 }
4526
4527 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4528 IBinder threadBinder = thread.asBinder();
4529
4530 // Find the application record.
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004531 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4532 ProcessRecord rec = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004533 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4534 return i;
4535 }
4536 }
4537 return -1;
4538 }
4539
4540 private final ProcessRecord getRecordForAppLocked(
4541 IApplicationThread thread) {
4542 if (thread == null) {
4543 return null;
4544 }
4545
4546 int appIndex = getLRURecordIndexForAppLocked(thread);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004547 return appIndex >= 0 ? mLruProcesses.get(appIndex) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004548 }
4549
4550 private final void appDiedLocked(ProcessRecord app, int pid,
4551 IApplicationThread thread) {
4552
4553 mProcDeaths[0]++;
4554
4555 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4556 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4557 + ") has died.");
Doug Zongker2bec3d42009-12-04 12:52:44 -08004558 EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004559 if (localLOGV) Log.v(
4560 TAG, "Dying app: " + app + ", pid: " + pid
4561 + ", thread: " + thread.asBinder());
4562 boolean doLowMem = app.instrumentationClass == null;
4563 handleAppDiedLocked(app, false);
4564
4565 if (doLowMem) {
4566 // If there are no longer any background processes running,
4567 // and the app that died was not running instrumentation,
4568 // then tell everyone we are now low on memory.
4569 boolean haveBg = false;
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004570 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4571 ProcessRecord rec = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004572 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4573 haveBg = true;
4574 break;
4575 }
4576 }
4577
4578 if (!haveBg) {
4579 Log.i(TAG, "Low Memory: No more background processes.");
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004580 EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mLruProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004581 long now = SystemClock.uptimeMillis();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004582 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4583 ProcessRecord rec = mLruProcesses.get(i);
Dianne Hackborn36124872009-10-08 16:22:03 -07004584 if (rec != app && rec.thread != null &&
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004585 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4586 // The low memory report is overriding any current
4587 // state for a GC request. Make sure to do
4588 // visible/foreground processes first.
4589 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4590 rec.lastRequestedGc = 0;
4591 } else {
4592 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004593 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004594 rec.reportLowMemory = true;
4595 rec.lastLowMemory = now;
4596 mProcessesToGc.remove(rec);
4597 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004598 }
4599 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004600 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004601 }
4602 }
4603 } else if (Config.LOGD) {
4604 Log.d(TAG, "Received spurious death notification for thread "
4605 + thread.asBinder());
4606 }
4607 }
4608
4609 final String readFile(String filename) {
4610 try {
4611 FileInputStream fs = new FileInputStream(filename);
4612 byte[] inp = new byte[8192];
4613 int size = fs.read(inp);
4614 fs.close();
4615 return new String(inp, 0, 0, size);
4616 } catch (java.io.IOException e) {
4617 }
4618 return "";
4619 }
4620
4621 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004622 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004623 if (app.notResponding || app.crashing) {
4624 return;
4625 }
4626
4627 // Log the ANR to the event log.
Doug Zongker2bec3d42009-12-04 12:52:44 -08004628 EventLog.writeEvent(EventLogTags.ANR, app.pid, app.processName, annotation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004629
4630 // If we are on a secure build and the application is not interesting to the user (it is
4631 // not visible or in the background), just kill it instead of displaying a dialog.
4632 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4633 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4634 Process.killProcess(app.pid);
4635 return;
4636 }
4637
4638 // DeviceMonitor.start();
4639
4640 String processInfo = null;
4641 if (MONITOR_CPU_USAGE) {
4642 updateCpuStatsNow();
4643 synchronized (mProcessStatsThread) {
4644 processInfo = mProcessStats.printCurrentState();
4645 }
4646 }
4647
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004648 StringBuilder info = mStringBuilder;
4649 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004650 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004651 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004652 if (reportedActivity != null && reportedActivity.app != null) {
4653 info.append(" (last in ");
4654 info.append(reportedActivity.app.processName);
4655 info.append(")");
4656 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004657 if (annotation != null) {
4658 info.append("\nAnnotation: ");
4659 info.append(annotation);
4660 }
4661 if (MONITOR_CPU_USAGE) {
4662 info.append("\nCPU usage:\n");
4663 info.append(processInfo);
4664 }
4665 Log.i(TAG, info.toString());
4666
4667 // The application is not responding. Dump as many thread traces as we can.
4668 boolean fileDump = prepareTraceFile(true);
4669 if (!fileDump) {
4670 // Dumping traces to the log, just dump the process that isn't responding so
4671 // we don't overflow the log
4672 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4673 } else {
4674 // Dumping traces to a file so dump all active processes we know about
4675 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004676 // First, these are the most important processes.
4677 final int[] imppids = new int[3];
4678 int i=0;
4679 imppids[0] = app.pid;
4680 i++;
4681 if (reportedActivity != null && reportedActivity.app != null
4682 && reportedActivity.app.thread != null
4683 && reportedActivity.app.pid != app.pid) {
4684 imppids[i] = reportedActivity.app.pid;
4685 i++;
4686 }
4687 imppids[i] = Process.myPid();
4688 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4689 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4690 synchronized (this) {
4691 try {
4692 wait(200);
4693 } catch (InterruptedException e) {
4694 }
4695 }
4696 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004697 for (i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
4698 ProcessRecord r = mLruProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004699 boolean done = false;
4700 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4701 if (imppids[j] == r.pid) {
4702 done = true;
4703 break;
4704 }
4705 }
4706 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004707 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004708 synchronized (this) {
4709 try {
4710 wait(200);
4711 } catch (InterruptedException e) {
4712 }
4713 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004714 }
4715 }
4716 }
4717 }
4718
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004719 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004720 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004721 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004722 app.pid, info.toString());
4723 if (res != 0) {
4724 if (res < 0) {
4725 // wait until the SIGQUIT has had a chance to process before killing the
4726 // process.
4727 try {
4728 wait(2000);
4729 } catch (InterruptedException e) {
4730 }
4731
4732 Process.killProcess(app.pid);
4733 return;
4734 }
4735 }
4736 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004737 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004738 }
4739 }
4740
4741 makeAppNotRespondingLocked(app,
4742 activity != null ? activity.shortComponentName : null,
4743 annotation != null ? "ANR " + annotation : "ANR",
Dan Egnorb7f03672009-12-09 16:22:32 -08004744 info.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004745 Message msg = Message.obtain();
4746 HashMap map = new HashMap();
4747 msg.what = SHOW_NOT_RESPONDING_MSG;
4748 msg.obj = map;
4749 map.put("app", app);
4750 if (activity != null) {
4751 map.put("activity", activity);
4752 }
4753
4754 mHandler.sendMessage(msg);
4755 return;
4756 }
4757
4758 /**
4759 * If a stack trace file has been configured, prepare the filesystem
4760 * by creating the directory if it doesn't exist and optionally
4761 * removing the old trace file.
4762 *
4763 * @param removeExisting If set, the existing trace file will be removed.
4764 * @return Returns true if the trace file preparations succeeded
4765 */
4766 public static boolean prepareTraceFile(boolean removeExisting) {
4767 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4768 boolean fileReady = false;
4769 if (!TextUtils.isEmpty(tracesPath)) {
4770 File f = new File(tracesPath);
4771 if (!f.exists()) {
4772 // Ensure the enclosing directory exists
4773 File dir = f.getParentFile();
4774 if (!dir.exists()) {
4775 fileReady = dir.mkdirs();
4776 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004777 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004778 } else if (dir.isDirectory()) {
4779 fileReady = true;
4780 }
4781 } else if (removeExisting) {
4782 // Remove the previous traces file, so we don't fill the disk.
4783 // The VM will recreate it
4784 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4785 fileReady = f.delete();
4786 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004787
4788 if (removeExisting) {
4789 try {
4790 f.createNewFile();
4791 FileUtils.setPermissions(f.getAbsolutePath(),
4792 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4793 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4794 fileReady = true;
4795 } catch (IOException e) {
4796 Log.w(TAG, "Unable to make ANR traces file", e);
4797 }
4798 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004799 }
4800
4801 return fileReady;
4802 }
4803
4804
4805 private final void decPersistentCountLocked(ProcessRecord app)
4806 {
4807 app.persistentActivities--;
4808 if (app.persistentActivities > 0) {
4809 // Still more of 'em...
4810 return;
4811 }
4812 if (app.persistent) {
4813 // Ah, but the application itself is persistent. Whatever!
4814 return;
4815 }
4816
4817 // App is no longer persistent... make sure it and the ones
4818 // following it in the LRU list have the correc oom_adj.
4819 updateOomAdjLocked();
4820 }
4821
4822 public void setPersistent(IBinder token, boolean isPersistent) {
4823 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4824 != PackageManager.PERMISSION_GRANTED) {
4825 String msg = "Permission Denial: setPersistent() from pid="
4826 + Binder.getCallingPid()
4827 + ", uid=" + Binder.getCallingUid()
4828 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4829 Log.w(TAG, msg);
4830 throw new SecurityException(msg);
4831 }
4832
4833 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004834 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004835 if (index < 0) {
4836 return;
4837 }
4838 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4839 ProcessRecord app = r.app;
4840
4841 if (localLOGV) Log.v(
4842 TAG, "Setting persistence " + isPersistent + ": " + r);
4843
4844 if (isPersistent) {
4845 if (r.persistent) {
4846 // Okay okay, I heard you already!
4847 if (localLOGV) Log.v(TAG, "Already persistent!");
4848 return;
4849 }
4850 r.persistent = true;
4851 app.persistentActivities++;
4852 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4853 if (app.persistentActivities > 1) {
4854 // We aren't the first...
4855 if (localLOGV) Log.v(TAG, "Not the first!");
4856 return;
4857 }
4858 if (app.persistent) {
4859 // This would be redundant.
4860 if (localLOGV) Log.v(TAG, "App is persistent!");
4861 return;
4862 }
4863
4864 // App is now persistent... make sure it and the ones
4865 // following it now have the correct oom_adj.
4866 final long origId = Binder.clearCallingIdentity();
4867 updateOomAdjLocked();
4868 Binder.restoreCallingIdentity(origId);
4869
4870 } else {
4871 if (!r.persistent) {
4872 // Okay okay, I heard you already!
4873 return;
4874 }
4875 r.persistent = false;
4876 final long origId = Binder.clearCallingIdentity();
4877 decPersistentCountLocked(app);
4878 Binder.restoreCallingIdentity(origId);
4879
4880 }
4881 }
4882 }
4883
4884 public boolean clearApplicationUserData(final String packageName,
4885 final IPackageDataObserver observer) {
4886 int uid = Binder.getCallingUid();
4887 int pid = Binder.getCallingPid();
4888 long callingId = Binder.clearCallingIdentity();
4889 try {
4890 IPackageManager pm = ActivityThread.getPackageManager();
4891 int pkgUid = -1;
4892 synchronized(this) {
4893 try {
4894 pkgUid = pm.getPackageUid(packageName);
4895 } catch (RemoteException e) {
4896 }
4897 if (pkgUid == -1) {
4898 Log.w(TAG, "Invalid packageName:" + packageName);
4899 return false;
4900 }
4901 if (uid == pkgUid || checkComponentPermission(
4902 android.Manifest.permission.CLEAR_APP_USER_DATA,
4903 pid, uid, -1)
4904 == PackageManager.PERMISSION_GRANTED) {
4905 restartPackageLocked(packageName, pkgUid);
4906 } else {
4907 throw new SecurityException(pid+" does not have permission:"+
4908 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4909 "for process:"+packageName);
4910 }
4911 }
4912
4913 try {
4914 //clear application user data
4915 pm.clearApplicationUserData(packageName, observer);
4916 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4917 Uri.fromParts("package", packageName, null));
4918 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4919 broadcastIntentLocked(null, null, intent,
4920 null, null, 0, null, null, null,
4921 false, false, MY_PID, Process.SYSTEM_UID);
4922 } catch (RemoteException e) {
4923 }
4924 } finally {
4925 Binder.restoreCallingIdentity(callingId);
4926 }
4927 return true;
4928 }
4929
4930 public void restartPackage(final String packageName) {
4931 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4932 != PackageManager.PERMISSION_GRANTED) {
4933 String msg = "Permission Denial: restartPackage() from pid="
4934 + Binder.getCallingPid()
4935 + ", uid=" + Binder.getCallingUid()
4936 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4937 Log.w(TAG, msg);
4938 throw new SecurityException(msg);
4939 }
4940
4941 long callingId = Binder.clearCallingIdentity();
4942 try {
4943 IPackageManager pm = ActivityThread.getPackageManager();
4944 int pkgUid = -1;
4945 synchronized(this) {
4946 try {
4947 pkgUid = pm.getPackageUid(packageName);
4948 } catch (RemoteException e) {
4949 }
4950 if (pkgUid == -1) {
4951 Log.w(TAG, "Invalid packageName: " + packageName);
4952 return;
4953 }
4954 restartPackageLocked(packageName, pkgUid);
4955 }
4956 } finally {
4957 Binder.restoreCallingIdentity(callingId);
4958 }
4959 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004960
4961 /*
4962 * The pkg name and uid have to be specified.
4963 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4964 */
4965 public void killApplicationWithUid(String pkg, int uid) {
4966 if (pkg == null) {
4967 return;
4968 }
4969 // Make sure the uid is valid.
4970 if (uid < 0) {
4971 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4972 return;
4973 }
4974 int callerUid = Binder.getCallingUid();
4975 // Only the system server can kill an application
4976 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004977 // Post an aysnc message to kill the application
4978 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4979 msg.arg1 = uid;
4980 msg.arg2 = 0;
4981 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004982 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004983 } else {
4984 throw new SecurityException(callerUid + " cannot kill pkg: " +
4985 pkg);
4986 }
4987 }
4988
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004989 public void closeSystemDialogs(String reason) {
4990 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4991 if (reason != null) {
4992 intent.putExtra("reason", reason);
4993 }
4994
4995 final int uid = Binder.getCallingUid();
4996 final long origId = Binder.clearCallingIdentity();
4997 synchronized (this) {
4998 int i = mWatchers.beginBroadcast();
4999 while (i > 0) {
5000 i--;
5001 IActivityWatcher w = mWatchers.getBroadcastItem(i);
5002 if (w != null) {
5003 try {
5004 w.closingSystemDialogs(reason);
5005 } catch (RemoteException e) {
5006 }
5007 }
5008 }
5009 mWatchers.finishBroadcast();
5010
Dianne Hackbornffa42482009-09-23 22:20:11 -07005011 mWindowManager.closeSystemDialogs(reason);
5012
5013 for (i=mHistory.size()-1; i>=0; i--) {
5014 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5015 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
5016 finishActivityLocked(r, i,
5017 Activity.RESULT_CANCELED, null, "close-sys");
5018 }
5019 }
5020
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07005021 broadcastIntentLocked(null, null, intent, null,
5022 null, 0, null, null, null, false, false, -1, uid);
5023 }
5024 Binder.restoreCallingIdentity(origId);
5025 }
5026
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005027 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005028 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005029 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
5030 for (int i=pids.length-1; i>=0; i--) {
5031 infos[i] = new Debug.MemoryInfo();
5032 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005033 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005034 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005035 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07005036
5037 public void killApplicationProcess(String processName, int uid) {
5038 if (processName == null) {
5039 return;
5040 }
5041
5042 int callerUid = Binder.getCallingUid();
5043 // Only the system server can kill an application
5044 if (callerUid == Process.SYSTEM_UID) {
5045 synchronized (this) {
5046 ProcessRecord app = getProcessRecordLocked(processName, uid);
5047 if (app != null) {
5048 try {
5049 app.thread.scheduleSuicide();
5050 } catch (RemoteException e) {
5051 // If the other end already died, then our work here is done.
5052 }
5053 } else {
5054 Log.w(TAG, "Process/uid not found attempting kill of "
5055 + processName + " / " + uid);
5056 }
5057 }
5058 } else {
5059 throw new SecurityException(callerUid + " cannot kill app process: " +
5060 processName);
5061 }
5062 }
5063
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005064 private void restartPackageLocked(final String packageName, int uid) {
5065 uninstallPackageLocked(packageName, uid, false);
5066 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
5067 Uri.fromParts("package", packageName, null));
5068 intent.putExtra(Intent.EXTRA_UID, uid);
5069 broadcastIntentLocked(null, null, intent,
5070 null, null, 0, null, null, null,
5071 false, false, MY_PID, Process.SYSTEM_UID);
5072 }
5073
5074 private final void uninstallPackageLocked(String name, int uid,
5075 boolean callerWillRestart) {
5076 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
5077
5078 int i, N;
5079
5080 final String procNamePrefix = name + ":";
5081 if (uid < 0) {
5082 try {
5083 uid = ActivityThread.getPackageManager().getPackageUid(name);
5084 } catch (RemoteException e) {
5085 }
5086 }
5087
5088 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
5089 while (badApps.hasNext()) {
5090 SparseArray<Long> ba = badApps.next();
5091 if (ba.get(uid) != null) {
5092 badApps.remove();
5093 }
5094 }
5095
5096 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
5097
5098 // Remove all processes this package may have touched: all with the
5099 // same UID (except for the system or root user), and all whose name
5100 // matches the package name.
5101 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5102 final int NA = apps.size();
5103 for (int ia=0; ia<NA; ia++) {
5104 ProcessRecord app = apps.valueAt(ia);
5105 if (app.removed) {
5106 procs.add(app);
5107 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5108 || app.processName.equals(name)
5109 || app.processName.startsWith(procNamePrefix)) {
5110 app.removed = true;
5111 procs.add(app);
5112 }
5113 }
5114 }
5115
5116 N = procs.size();
5117 for (i=0; i<N; i++) {
5118 removeProcessLocked(procs.get(i), callerWillRestart);
5119 }
5120
5121 for (i=mHistory.size()-1; i>=0; i--) {
5122 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5123 if (r.packageName.equals(name)) {
5124 if (Config.LOGD) Log.d(
5125 TAG, " Force finishing activity "
5126 + r.intent.getComponent().flattenToShortString());
5127 if (r.app != null) {
5128 r.app.removed = true;
5129 }
5130 r.app = null;
5131 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5132 }
5133 }
5134
5135 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5136 for (ServiceRecord service : mServices.values()) {
5137 if (service.packageName.equals(name)) {
5138 if (service.app != null) {
5139 service.app.removed = true;
5140 }
5141 service.app = null;
5142 services.add(service);
5143 }
5144 }
5145
5146 N = services.size();
5147 for (i=0; i<N; i++) {
5148 bringDownServiceLocked(services.get(i), true);
5149 }
5150
5151 resumeTopActivityLocked(null);
5152 }
5153
5154 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5155 final String name = app.processName;
5156 final int uid = app.info.uid;
5157 if (Config.LOGD) Log.d(
5158 TAG, "Force removing process " + app + " (" + name
5159 + "/" + uid + ")");
5160
5161 mProcessNames.remove(name, uid);
5162 boolean needRestart = false;
5163 if (app.pid > 0 && app.pid != MY_PID) {
5164 int pid = app.pid;
5165 synchronized (mPidsSelfLocked) {
5166 mPidsSelfLocked.remove(pid);
5167 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5168 }
5169 handleAppDiedLocked(app, true);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08005170 mLruProcesses.remove(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005171 Process.killProcess(pid);
5172
5173 if (app.persistent) {
5174 if (!callerWillRestart) {
5175 addAppLocked(app.info);
5176 } else {
5177 needRestart = true;
5178 }
5179 }
5180 } else {
5181 mRemovedProcesses.add(app);
5182 }
5183
5184 return needRestart;
5185 }
5186
5187 private final void processStartTimedOutLocked(ProcessRecord app) {
5188 final int pid = app.pid;
5189 boolean gone = false;
5190 synchronized (mPidsSelfLocked) {
5191 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5192 if (knownApp != null && knownApp.thread == null) {
5193 mPidsSelfLocked.remove(pid);
5194 gone = true;
5195 }
5196 }
5197
5198 if (gone) {
5199 Log.w(TAG, "Process " + app + " failed to attach");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005200 EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, pid, app.info.uid,
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005201 app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005202 mProcessNames.remove(app.processName, app.info.uid);
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005203 // Take care of any launching providers waiting for this process.
5204 checkAppInLaunchingProvidersLocked(app, true);
5205 // Take care of any services that are waiting for the process.
5206 for (int i=0; i<mPendingServices.size(); i++) {
5207 ServiceRecord sr = mPendingServices.get(i);
5208 if (app.info.uid == sr.appInfo.uid
5209 && app.processName.equals(sr.processName)) {
5210 Log.w(TAG, "Forcing bringing down service: " + sr);
5211 mPendingServices.remove(i);
5212 i--;
5213 bringDownServiceLocked(sr, true);
5214 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005215 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005216 Process.killProcess(pid);
Christopher Tate181fafa2009-05-14 11:12:14 -07005217 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5218 Log.w(TAG, "Unattached app died before backup, skipping");
5219 try {
5220 IBackupManager bm = IBackupManager.Stub.asInterface(
5221 ServiceManager.getService(Context.BACKUP_SERVICE));
5222 bm.agentDisconnected(app.info.packageName);
5223 } catch (RemoteException e) {
5224 // Can't happen; the backup manager is local
5225 }
5226 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005227 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5228 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5229 mPendingBroadcast = null;
5230 scheduleBroadcastsLocked();
5231 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005232 } else {
5233 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5234 }
5235 }
5236
5237 private final boolean attachApplicationLocked(IApplicationThread thread,
5238 int pid) {
5239
5240 // Find the application record that is being attached... either via
5241 // the pid if we are running in multiple processes, or just pull the
5242 // next app record if we are emulating process with anonymous threads.
5243 ProcessRecord app;
5244 if (pid != MY_PID && pid >= 0) {
5245 synchronized (mPidsSelfLocked) {
5246 app = mPidsSelfLocked.get(pid);
5247 }
5248 } else if (mStartingProcesses.size() > 0) {
5249 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005250 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005251 } else {
5252 app = null;
5253 }
5254
5255 if (app == null) {
5256 Log.w(TAG, "No pending application record for pid " + pid
5257 + " (IApplicationThread " + thread + "); dropping process");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005258 EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005259 if (pid > 0 && pid != MY_PID) {
5260 Process.killProcess(pid);
5261 } else {
5262 try {
5263 thread.scheduleExit();
5264 } catch (Exception e) {
5265 // Ignore exceptions.
5266 }
5267 }
5268 return false;
5269 }
5270
5271 // If this application record is still attached to a previous
5272 // process, clean it up now.
5273 if (app.thread != null) {
5274 handleAppDiedLocked(app, true);
5275 }
5276
5277 // Tell the process all about itself.
5278
5279 if (localLOGV) Log.v(
5280 TAG, "Binding process pid " + pid + " to record " + app);
5281
5282 String processName = app.processName;
5283 try {
5284 thread.asBinder().linkToDeath(new AppDeathRecipient(
5285 app, pid, thread), 0);
5286 } catch (RemoteException e) {
5287 app.resetPackageList();
5288 startProcessLocked(app, "link fail", processName);
5289 return false;
5290 }
5291
Doug Zongker2bec3d42009-12-04 12:52:44 -08005292 EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005293
5294 app.thread = thread;
5295 app.curAdj = app.setAdj = -100;
Dianne Hackborn09c916b2009-12-08 14:50:51 -08005296 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
5297 app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005298 app.forcingToForeground = null;
5299 app.foregroundServices = false;
5300 app.debugging = false;
5301
5302 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5303
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005304 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5305 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005306
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005307 if (!normalMode) {
5308 Log.i(TAG, "Launching preboot mode app: " + app);
5309 }
5310
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005311 if (localLOGV) Log.v(
5312 TAG, "New app record " + app
5313 + " thread=" + thread.asBinder() + " pid=" + pid);
5314 try {
5315 int testMode = IApplicationThread.DEBUG_OFF;
5316 if (mDebugApp != null && mDebugApp.equals(processName)) {
5317 testMode = mWaitForDebugger
5318 ? IApplicationThread.DEBUG_WAIT
5319 : IApplicationThread.DEBUG_ON;
5320 app.debugging = true;
5321 if (mDebugTransient) {
5322 mDebugApp = mOrigDebugApp;
5323 mWaitForDebugger = mOrigWaitForDebugger;
5324 }
5325 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005326
Christopher Tate181fafa2009-05-14 11:12:14 -07005327 // If the app is being launched for restore or full backup, set it up specially
5328 boolean isRestrictedBackupMode = false;
5329 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5330 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5331 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5332 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005333
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005334 ensurePackageDexOpt(app.instrumentationInfo != null
5335 ? app.instrumentationInfo.packageName
5336 : app.info.packageName);
5337 if (app.instrumentationClass != null) {
5338 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005339 }
Dianne Hackborndc6b6352009-09-30 14:20:09 -07005340 if (DEBUG_CONFIGURATION) Log.v(TAG, "Binding proc "
5341 + processName + " with config " + mConfiguration);
Dianne Hackborn1655be42009-05-08 14:29:01 -07005342 thread.bindApplication(processName, app.instrumentationInfo != null
5343 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005344 app.instrumentationClass, app.instrumentationProfileFile,
5345 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005346 isRestrictedBackupMode || !normalMode,
5347 mConfiguration, getCommonServicesLocked());
Dianne Hackborndd71fc82009-12-16 19:24:32 -08005348 updateLruProcessLocked(app, false, true);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005349 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005350 } catch (Exception e) {
5351 // todo: Yikes! What should we do? For now we will try to
5352 // start another process, but that could easily get us in
5353 // an infinite loop of restarting processes...
5354 Log.w(TAG, "Exception thrown during bind!", e);
5355
5356 app.resetPackageList();
5357 startProcessLocked(app, "bind fail", processName);
5358 return false;
5359 }
5360
5361 // Remove this record from the list of starting applications.
5362 mPersistentStartingProcesses.remove(app);
5363 mProcessesOnHold.remove(app);
5364
5365 boolean badApp = false;
5366 boolean didSomething = false;
5367
5368 // See if the top visible activity is waiting to run in this process...
5369 HistoryRecord hr = topRunningActivityLocked(null);
5370 if (hr != null) {
5371 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5372 && processName.equals(hr.processName)) {
5373 try {
5374 if (realStartActivityLocked(hr, app, true, true)) {
5375 didSomething = true;
5376 }
5377 } catch (Exception e) {
5378 Log.w(TAG, "Exception in new application when starting activity "
5379 + hr.intent.getComponent().flattenToShortString(), e);
5380 badApp = true;
5381 }
5382 } else {
5383 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5384 }
5385 }
5386
5387 // Find any services that should be running in this process...
5388 if (!badApp && mPendingServices.size() > 0) {
5389 ServiceRecord sr = null;
5390 try {
5391 for (int i=0; i<mPendingServices.size(); i++) {
5392 sr = mPendingServices.get(i);
5393 if (app.info.uid != sr.appInfo.uid
5394 || !processName.equals(sr.processName)) {
5395 continue;
5396 }
5397
5398 mPendingServices.remove(i);
5399 i--;
5400 realStartServiceLocked(sr, app);
5401 didSomething = true;
5402 }
5403 } catch (Exception e) {
5404 Log.w(TAG, "Exception in new application when starting service "
5405 + sr.shortName, e);
5406 badApp = true;
5407 }
5408 }
5409
5410 // Check if the next broadcast receiver is in this process...
5411 BroadcastRecord br = mPendingBroadcast;
5412 if (!badApp && br != null && br.curApp == app) {
5413 try {
5414 mPendingBroadcast = null;
5415 processCurBroadcastLocked(br, app);
5416 didSomething = true;
5417 } catch (Exception e) {
5418 Log.w(TAG, "Exception in new application when starting receiver "
5419 + br.curComponent.flattenToShortString(), e);
5420 badApp = true;
5421 logBroadcastReceiverDiscard(br);
5422 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5423 br.resultExtras, br.resultAbort, true);
5424 scheduleBroadcastsLocked();
5425 }
5426 }
5427
Christopher Tate181fafa2009-05-14 11:12:14 -07005428 // Check whether the next backup agent is in this process...
5429 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5430 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005431 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005432 try {
5433 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5434 } catch (Exception e) {
5435 Log.w(TAG, "Exception scheduling backup agent creation: ");
5436 e.printStackTrace();
5437 }
5438 }
5439
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005440 if (badApp) {
5441 // todo: Also need to kill application to deal with all
5442 // kinds of exceptions.
5443 handleAppDiedLocked(app, false);
5444 return false;
5445 }
5446
5447 if (!didSomething) {
5448 updateOomAdjLocked();
5449 }
5450
5451 return true;
5452 }
5453
5454 public final void attachApplication(IApplicationThread thread) {
5455 synchronized (this) {
5456 int callingPid = Binder.getCallingPid();
5457 final long origId = Binder.clearCallingIdentity();
5458 attachApplicationLocked(thread, callingPid);
5459 Binder.restoreCallingIdentity(origId);
5460 }
5461 }
5462
Dianne Hackborne88846e2009-09-30 21:34:25 -07005463 public final void activityIdle(IBinder token, Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005464 final long origId = Binder.clearCallingIdentity();
Dianne Hackborne88846e2009-09-30 21:34:25 -07005465 activityIdleInternal(token, false, config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005466 Binder.restoreCallingIdentity(origId);
5467 }
5468
5469 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5470 boolean remove) {
5471 int N = mStoppingActivities.size();
5472 if (N <= 0) return null;
5473
5474 ArrayList<HistoryRecord> stops = null;
5475
5476 final boolean nowVisible = mResumedActivity != null
5477 && mResumedActivity.nowVisible
5478 && !mResumedActivity.waitingVisible;
5479 for (int i=0; i<N; i++) {
5480 HistoryRecord s = mStoppingActivities.get(i);
5481 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5482 + nowVisible + " waitingVisible=" + s.waitingVisible
5483 + " finishing=" + s.finishing);
5484 if (s.waitingVisible && nowVisible) {
5485 mWaitingVisibleActivities.remove(s);
5486 s.waitingVisible = false;
5487 if (s.finishing) {
5488 // If this activity is finishing, it is sitting on top of
5489 // everyone else but we now know it is no longer needed...
5490 // so get rid of it. Otherwise, we need to go through the
5491 // normal flow and hide it once we determine that it is
5492 // hidden by the activities in front of it.
5493 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5494 mWindowManager.setAppVisibility(s, false);
5495 }
5496 }
5497 if (!s.waitingVisible && remove) {
5498 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5499 if (stops == null) {
5500 stops = new ArrayList<HistoryRecord>();
5501 }
5502 stops.add(s);
5503 mStoppingActivities.remove(i);
5504 N--;
5505 i--;
5506 }
5507 }
5508
5509 return stops;
5510 }
5511
5512 void enableScreenAfterBoot() {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005513 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005514 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005515 mWindowManager.enableScreenAfterBoot();
5516 }
5517
Dianne Hackborne88846e2009-09-30 21:34:25 -07005518 final void activityIdleInternal(IBinder token, boolean fromTimeout,
5519 Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005520 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5521
5522 ArrayList<HistoryRecord> stops = null;
5523 ArrayList<HistoryRecord> finishes = null;
5524 ArrayList<HistoryRecord> thumbnails = null;
5525 int NS = 0;
5526 int NF = 0;
5527 int NT = 0;
5528 IApplicationThread sendThumbnail = null;
5529 boolean booting = false;
5530 boolean enableScreen = false;
5531
5532 synchronized (this) {
5533 if (token != null) {
5534 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5535 }
5536
5537 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005538 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005539 if (index >= 0) {
5540 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5541
Dianne Hackborne88846e2009-09-30 21:34:25 -07005542 // This is a hack to semi-deal with a race condition
5543 // in the client where it can be constructed with a
5544 // newer configuration from when we asked it to launch.
5545 // We'll update with whatever configuration it now says
5546 // it used to launch.
5547 if (config != null) {
5548 r.configuration = config;
5549 }
5550
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005551 // No longer need to keep the device awake.
5552 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5553 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5554 mLaunchingActivity.release();
5555 }
5556
5557 // We are now idle. If someone is waiting for a thumbnail from
5558 // us, we can now deliver.
5559 r.idle = true;
5560 scheduleAppGcsLocked();
5561 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5562 sendThumbnail = r.app.thread;
5563 r.thumbnailNeeded = false;
5564 }
5565
5566 // If this activity is fullscreen, set up to hide those under it.
5567
5568 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5569 ensureActivitiesVisibleLocked(null, 0);
5570
5571 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5572 if (!mBooted && !fromTimeout) {
5573 mBooted = true;
5574 enableScreen = true;
5575 }
5576 }
5577
5578 // Atomically retrieve all of the other things to do.
5579 stops = processStoppingActivitiesLocked(true);
5580 NS = stops != null ? stops.size() : 0;
5581 if ((NF=mFinishingActivities.size()) > 0) {
5582 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5583 mFinishingActivities.clear();
5584 }
5585 if ((NT=mCancelledThumbnails.size()) > 0) {
5586 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5587 mCancelledThumbnails.clear();
5588 }
5589
5590 booting = mBooting;
5591 mBooting = false;
5592 }
5593
5594 int i;
5595
5596 // Send thumbnail if requested.
5597 if (sendThumbnail != null) {
5598 try {
5599 sendThumbnail.requestThumbnail(token);
5600 } catch (Exception e) {
5601 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5602 sendPendingThumbnail(null, token, null, null, true);
5603 }
5604 }
5605
5606 // Stop any activities that are scheduled to do so but have been
5607 // waiting for the next one to start.
5608 for (i=0; i<NS; i++) {
5609 HistoryRecord r = (HistoryRecord)stops.get(i);
5610 synchronized (this) {
5611 if (r.finishing) {
5612 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5613 } else {
5614 stopActivityLocked(r);
5615 }
5616 }
5617 }
5618
5619 // Finish any activities that are scheduled to do so but have been
5620 // waiting for the next one to start.
5621 for (i=0; i<NF; i++) {
5622 HistoryRecord r = (HistoryRecord)finishes.get(i);
5623 synchronized (this) {
5624 destroyActivityLocked(r, true);
5625 }
5626 }
5627
5628 // Report back to any thumbnail receivers.
5629 for (i=0; i<NT; i++) {
5630 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5631 sendPendingThumbnail(r, null, null, null, true);
5632 }
5633
5634 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005635 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005636 }
5637
5638 trimApplications();
5639 //dump();
5640 //mWindowManager.dump();
5641
5642 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005643 enableScreenAfterBoot();
5644 }
5645 }
5646
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005647 final void finishBooting() {
5648 // Ensure that any processes we had put on hold are now started
5649 // up.
5650 final int NP = mProcessesOnHold.size();
5651 if (NP > 0) {
5652 ArrayList<ProcessRecord> procs =
5653 new ArrayList<ProcessRecord>(mProcessesOnHold);
5654 for (int ip=0; ip<NP; ip++) {
5655 this.startProcessLocked(procs.get(ip), "on-hold", null);
5656 }
5657 }
5658 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5659 // Tell anyone interested that we are done booting!
5660 synchronized (this) {
5661 broadcastIntentLocked(null, null,
5662 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5663 null, null, 0, null, null,
5664 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5665 false, false, MY_PID, Process.SYSTEM_UID);
5666 }
5667 }
5668 }
5669
5670 final void ensureBootCompleted() {
5671 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005672 boolean enableScreen;
5673 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005674 booting = mBooting;
5675 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005676 enableScreen = !mBooted;
5677 mBooted = true;
5678 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005679
5680 if (booting) {
5681 finishBooting();
5682 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005683
5684 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005685 enableScreenAfterBoot();
5686 }
5687 }
5688
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005689 public final void activityPaused(IBinder token, Bundle icicle) {
5690 // Refuse possible leaked file descriptors
5691 if (icicle != null && icicle.hasFileDescriptors()) {
5692 throw new IllegalArgumentException("File descriptors passed in Bundle");
5693 }
5694
5695 final long origId = Binder.clearCallingIdentity();
5696 activityPaused(token, icicle, false);
5697 Binder.restoreCallingIdentity(origId);
5698 }
5699
5700 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5701 if (DEBUG_PAUSE) Log.v(
5702 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5703 + ", timeout=" + timeout);
5704
5705 HistoryRecord r = null;
5706
5707 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005708 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005709 if (index >= 0) {
5710 r = (HistoryRecord)mHistory.get(index);
5711 if (!timeout) {
5712 r.icicle = icicle;
5713 r.haveState = true;
5714 }
5715 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5716 if (mPausingActivity == r) {
5717 r.state = ActivityState.PAUSED;
5718 completePauseLocked();
5719 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005720 EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005721 System.identityHashCode(r), r.shortComponentName,
5722 mPausingActivity != null
5723 ? mPausingActivity.shortComponentName : "(none)");
5724 }
5725 }
5726 }
5727 }
5728
5729 public final void activityStopped(IBinder token, Bitmap thumbnail,
5730 CharSequence description) {
5731 if (localLOGV) Log.v(
5732 TAG, "Activity stopped: token=" + token);
5733
5734 HistoryRecord r = null;
5735
5736 final long origId = Binder.clearCallingIdentity();
5737
5738 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005739 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005740 if (index >= 0) {
5741 r = (HistoryRecord)mHistory.get(index);
5742 r.thumbnail = thumbnail;
5743 r.description = description;
5744 r.stopped = true;
5745 r.state = ActivityState.STOPPED;
5746 if (!r.finishing) {
5747 if (r.configDestroy) {
5748 destroyActivityLocked(r, true);
5749 resumeTopActivityLocked(null);
5750 }
5751 }
5752 }
5753 }
5754
5755 if (r != null) {
5756 sendPendingThumbnail(r, null, null, null, false);
5757 }
5758
5759 trimApplications();
5760
5761 Binder.restoreCallingIdentity(origId);
5762 }
5763
5764 public final void activityDestroyed(IBinder token) {
5765 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5766 synchronized (this) {
5767 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5768
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 if (r.state == ActivityState.DESTROYING) {
5773 final long origId = Binder.clearCallingIdentity();
5774 removeActivityFromHistoryLocked(r);
5775 Binder.restoreCallingIdentity(origId);
5776 }
5777 }
5778 }
5779 }
5780
5781 public String getCallingPackage(IBinder token) {
5782 synchronized (this) {
5783 HistoryRecord r = getCallingRecordLocked(token);
Dianne Hackborn9bbcb912009-10-20 15:42:38 -07005784 return r != null && r.app != null ? r.info.packageName : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005785 }
5786 }
5787
5788 public ComponentName getCallingActivity(IBinder token) {
5789 synchronized (this) {
5790 HistoryRecord r = getCallingRecordLocked(token);
5791 return r != null ? r.intent.getComponent() : null;
5792 }
5793 }
5794
5795 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005796 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005797 if (index >= 0) {
5798 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5799 if (r != null) {
5800 return r.resultTo;
5801 }
5802 }
5803 return null;
5804 }
5805
5806 public ComponentName getActivityClassForToken(IBinder token) {
5807 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005808 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005809 if (index >= 0) {
5810 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5811 return r.intent.getComponent();
5812 }
5813 return null;
5814 }
5815 }
5816
5817 public String getPackageForToken(IBinder token) {
5818 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005819 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005820 if (index >= 0) {
5821 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5822 return r.packageName;
5823 }
5824 return null;
5825 }
5826 }
5827
5828 public IIntentSender getIntentSender(int type,
5829 String packageName, IBinder token, String resultWho,
5830 int requestCode, Intent intent, String resolvedType, int flags) {
5831 // Refuse possible leaked file descriptors
5832 if (intent != null && intent.hasFileDescriptors() == true) {
5833 throw new IllegalArgumentException("File descriptors passed in Intent");
5834 }
5835
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005836 if (type == INTENT_SENDER_BROADCAST) {
5837 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5838 throw new IllegalArgumentException(
5839 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5840 }
5841 }
5842
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005843 synchronized(this) {
5844 int callingUid = Binder.getCallingUid();
5845 try {
5846 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5847 Process.supportsProcesses()) {
5848 int uid = ActivityThread.getPackageManager()
5849 .getPackageUid(packageName);
5850 if (uid != Binder.getCallingUid()) {
5851 String msg = "Permission Denial: getIntentSender() from pid="
5852 + Binder.getCallingPid()
5853 + ", uid=" + Binder.getCallingUid()
5854 + ", (need uid=" + uid + ")"
5855 + " is not allowed to send as package " + packageName;
5856 Log.w(TAG, msg);
5857 throw new SecurityException(msg);
5858 }
5859 }
5860 } catch (RemoteException e) {
5861 throw new SecurityException(e);
5862 }
5863 HistoryRecord activity = null;
5864 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005865 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005866 if (index < 0) {
5867 return null;
5868 }
5869 activity = (HistoryRecord)mHistory.get(index);
5870 if (activity.finishing) {
5871 return null;
5872 }
5873 }
5874
5875 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5876 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5877 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5878 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5879 |PendingIntent.FLAG_UPDATE_CURRENT);
5880
5881 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5882 type, packageName, activity, resultWho,
5883 requestCode, intent, resolvedType, flags);
5884 WeakReference<PendingIntentRecord> ref;
5885 ref = mIntentSenderRecords.get(key);
5886 PendingIntentRecord rec = ref != null ? ref.get() : null;
5887 if (rec != null) {
5888 if (!cancelCurrent) {
5889 if (updateCurrent) {
5890 rec.key.requestIntent.replaceExtras(intent);
5891 }
5892 return rec;
5893 }
5894 rec.canceled = true;
5895 mIntentSenderRecords.remove(key);
5896 }
5897 if (noCreate) {
5898 return rec;
5899 }
5900 rec = new PendingIntentRecord(this, key, callingUid);
5901 mIntentSenderRecords.put(key, rec.ref);
5902 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5903 if (activity.pendingResults == null) {
5904 activity.pendingResults
5905 = new HashSet<WeakReference<PendingIntentRecord>>();
5906 }
5907 activity.pendingResults.add(rec.ref);
5908 }
5909 return rec;
5910 }
5911 }
5912
5913 public void cancelIntentSender(IIntentSender sender) {
5914 if (!(sender instanceof PendingIntentRecord)) {
5915 return;
5916 }
5917 synchronized(this) {
5918 PendingIntentRecord rec = (PendingIntentRecord)sender;
5919 try {
5920 int uid = ActivityThread.getPackageManager()
5921 .getPackageUid(rec.key.packageName);
5922 if (uid != Binder.getCallingUid()) {
5923 String msg = "Permission Denial: cancelIntentSender() from pid="
5924 + Binder.getCallingPid()
5925 + ", uid=" + Binder.getCallingUid()
5926 + " is not allowed to cancel packges "
5927 + rec.key.packageName;
5928 Log.w(TAG, msg);
5929 throw new SecurityException(msg);
5930 }
5931 } catch (RemoteException e) {
5932 throw new SecurityException(e);
5933 }
5934 cancelIntentSenderLocked(rec, true);
5935 }
5936 }
5937
5938 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5939 rec.canceled = true;
5940 mIntentSenderRecords.remove(rec.key);
5941 if (cleanActivity && rec.key.activity != null) {
5942 rec.key.activity.pendingResults.remove(rec.ref);
5943 }
5944 }
5945
5946 public String getPackageForIntentSender(IIntentSender pendingResult) {
5947 if (!(pendingResult instanceof PendingIntentRecord)) {
5948 return null;
5949 }
5950 synchronized(this) {
5951 try {
5952 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5953 return res.key.packageName;
5954 } catch (ClassCastException e) {
5955 }
5956 }
5957 return null;
5958 }
5959
5960 public void setProcessLimit(int max) {
5961 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5962 "setProcessLimit()");
5963 mProcessLimit = max;
5964 }
5965
5966 public int getProcessLimit() {
5967 return mProcessLimit;
5968 }
5969
5970 void foregroundTokenDied(ForegroundToken token) {
5971 synchronized (ActivityManagerService.this) {
5972 synchronized (mPidsSelfLocked) {
5973 ForegroundToken cur
5974 = mForegroundProcesses.get(token.pid);
5975 if (cur != token) {
5976 return;
5977 }
5978 mForegroundProcesses.remove(token.pid);
5979 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5980 if (pr == null) {
5981 return;
5982 }
5983 pr.forcingToForeground = null;
5984 pr.foregroundServices = false;
5985 }
5986 updateOomAdjLocked();
5987 }
5988 }
5989
5990 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5991 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5992 "setProcessForeground()");
5993 synchronized(this) {
5994 boolean changed = false;
5995
5996 synchronized (mPidsSelfLocked) {
5997 ProcessRecord pr = mPidsSelfLocked.get(pid);
5998 if (pr == null) {
5999 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
6000 return;
6001 }
6002 ForegroundToken oldToken = mForegroundProcesses.get(pid);
6003 if (oldToken != null) {
6004 oldToken.token.unlinkToDeath(oldToken, 0);
6005 mForegroundProcesses.remove(pid);
6006 pr.forcingToForeground = null;
6007 changed = true;
6008 }
6009 if (isForeground && token != null) {
6010 ForegroundToken newToken = new ForegroundToken() {
6011 public void binderDied() {
6012 foregroundTokenDied(this);
6013 }
6014 };
6015 newToken.pid = pid;
6016 newToken.token = token;
6017 try {
6018 token.linkToDeath(newToken, 0);
6019 mForegroundProcesses.put(pid, newToken);
6020 pr.forcingToForeground = token;
6021 changed = true;
6022 } catch (RemoteException e) {
6023 // If the process died while doing this, we will later
6024 // do the cleanup with the process death link.
6025 }
6026 }
6027 }
6028
6029 if (changed) {
6030 updateOomAdjLocked();
6031 }
6032 }
6033 }
6034
6035 // =========================================================
6036 // PERMISSIONS
6037 // =========================================================
6038
6039 static class PermissionController extends IPermissionController.Stub {
6040 ActivityManagerService mActivityManagerService;
6041 PermissionController(ActivityManagerService activityManagerService) {
6042 mActivityManagerService = activityManagerService;
6043 }
6044
6045 public boolean checkPermission(String permission, int pid, int uid) {
6046 return mActivityManagerService.checkPermission(permission, pid,
6047 uid) == PackageManager.PERMISSION_GRANTED;
6048 }
6049 }
6050
6051 /**
6052 * This can be called with or without the global lock held.
6053 */
6054 int checkComponentPermission(String permission, int pid, int uid,
6055 int reqUid) {
6056 // We might be performing an operation on behalf of an indirect binder
6057 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
6058 // client identity accordingly before proceeding.
6059 Identity tlsIdentity = sCallerIdentity.get();
6060 if (tlsIdentity != null) {
6061 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
6062 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
6063 uid = tlsIdentity.uid;
6064 pid = tlsIdentity.pid;
6065 }
6066
6067 // Root, system server and our own process get to do everything.
6068 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
6069 !Process.supportsProcesses()) {
6070 return PackageManager.PERMISSION_GRANTED;
6071 }
6072 // If the target requires a specific UID, always fail for others.
6073 if (reqUid >= 0 && uid != reqUid) {
root0369a7c2009-03-23 15:20:47 +01006074 Log.w(TAG, "Permission denied: checkComponentPermission() reqUid=" + reqUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006075 return PackageManager.PERMISSION_DENIED;
6076 }
6077 if (permission == null) {
6078 return PackageManager.PERMISSION_GRANTED;
6079 }
6080 try {
6081 return ActivityThread.getPackageManager()
6082 .checkUidPermission(permission, uid);
6083 } catch (RemoteException e) {
6084 // Should never happen, but if it does... deny!
6085 Log.e(TAG, "PackageManager is dead?!?", e);
6086 }
6087 return PackageManager.PERMISSION_DENIED;
6088 }
6089
6090 /**
6091 * As the only public entry point for permissions checking, this method
6092 * can enforce the semantic that requesting a check on a null global
6093 * permission is automatically denied. (Internally a null permission
6094 * string is used when calling {@link #checkComponentPermission} in cases
6095 * when only uid-based security is needed.)
6096 *
6097 * This can be called with or without the global lock held.
6098 */
6099 public int checkPermission(String permission, int pid, int uid) {
6100 if (permission == null) {
6101 return PackageManager.PERMISSION_DENIED;
6102 }
6103 return checkComponentPermission(permission, pid, uid, -1);
6104 }
6105
6106 /**
6107 * Binder IPC calls go through the public entry point.
6108 * This can be called with or without the global lock held.
6109 */
6110 int checkCallingPermission(String permission) {
6111 return checkPermission(permission,
6112 Binder.getCallingPid(),
6113 Binder.getCallingUid());
6114 }
6115
6116 /**
6117 * This can be called with or without the global lock held.
6118 */
6119 void enforceCallingPermission(String permission, String func) {
6120 if (checkCallingPermission(permission)
6121 == PackageManager.PERMISSION_GRANTED) {
6122 return;
6123 }
6124
6125 String msg = "Permission Denial: " + func + " from pid="
6126 + Binder.getCallingPid()
6127 + ", uid=" + Binder.getCallingUid()
6128 + " requires " + permission;
6129 Log.w(TAG, msg);
6130 throw new SecurityException(msg);
6131 }
6132
6133 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6134 ProviderInfo pi, int uid, int modeFlags) {
6135 try {
6136 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6137 if ((pi.readPermission != null) &&
6138 (pm.checkUidPermission(pi.readPermission, uid)
6139 != PackageManager.PERMISSION_GRANTED)) {
6140 return false;
6141 }
6142 }
6143 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6144 if ((pi.writePermission != null) &&
6145 (pm.checkUidPermission(pi.writePermission, uid)
6146 != PackageManager.PERMISSION_GRANTED)) {
6147 return false;
6148 }
6149 }
6150 return true;
6151 } catch (RemoteException e) {
6152 return false;
6153 }
6154 }
6155
6156 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6157 int modeFlags) {
6158 // Root gets to do everything.
6159 if (uid == 0 || !Process.supportsProcesses()) {
6160 return true;
6161 }
6162 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6163 if (perms == null) return false;
6164 UriPermission perm = perms.get(uri);
6165 if (perm == null) return false;
6166 return (modeFlags&perm.modeFlags) == modeFlags;
6167 }
6168
6169 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6170 // Another redirected-binder-call permissions check as in
6171 // {@link checkComponentPermission}.
6172 Identity tlsIdentity = sCallerIdentity.get();
6173 if (tlsIdentity != null) {
6174 uid = tlsIdentity.uid;
6175 pid = tlsIdentity.pid;
6176 }
6177
6178 // Our own process gets to do everything.
6179 if (pid == MY_PID) {
6180 return PackageManager.PERMISSION_GRANTED;
6181 }
6182 synchronized(this) {
6183 return checkUriPermissionLocked(uri, uid, modeFlags)
6184 ? PackageManager.PERMISSION_GRANTED
6185 : PackageManager.PERMISSION_DENIED;
6186 }
6187 }
6188
6189 private void grantUriPermissionLocked(int callingUid,
6190 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6191 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6192 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6193 if (modeFlags == 0) {
6194 return;
6195 }
6196
6197 final IPackageManager pm = ActivityThread.getPackageManager();
6198
6199 // If this is not a content: uri, we can't do anything with it.
6200 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6201 return;
6202 }
6203
6204 String name = uri.getAuthority();
6205 ProviderInfo pi = null;
6206 ContentProviderRecord cpr
6207 = (ContentProviderRecord)mProvidersByName.get(name);
6208 if (cpr != null) {
6209 pi = cpr.info;
6210 } else {
6211 try {
6212 pi = pm.resolveContentProvider(name,
6213 PackageManager.GET_URI_PERMISSION_PATTERNS);
6214 } catch (RemoteException ex) {
6215 }
6216 }
6217 if (pi == null) {
6218 Log.w(TAG, "No content provider found for: " + name);
6219 return;
6220 }
6221
6222 int targetUid;
6223 try {
6224 targetUid = pm.getPackageUid(targetPkg);
6225 if (targetUid < 0) {
6226 return;
6227 }
6228 } catch (RemoteException ex) {
6229 return;
6230 }
6231
6232 // First... does the target actually need this permission?
6233 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6234 // No need to grant the target this permission.
6235 return;
6236 }
6237
6238 // Second... maybe someone else has already granted the
6239 // permission?
6240 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6241 // No need to grant the target this permission.
6242 return;
6243 }
6244
6245 // Third... is the provider allowing granting of URI permissions?
6246 if (!pi.grantUriPermissions) {
6247 throw new SecurityException("Provider " + pi.packageName
6248 + "/" + pi.name
6249 + " does not allow granting of Uri permissions (uri "
6250 + uri + ")");
6251 }
6252 if (pi.uriPermissionPatterns != null) {
6253 final int N = pi.uriPermissionPatterns.length;
6254 boolean allowed = false;
6255 for (int i=0; i<N; i++) {
6256 if (pi.uriPermissionPatterns[i] != null
6257 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6258 allowed = true;
6259 break;
6260 }
6261 }
6262 if (!allowed) {
6263 throw new SecurityException("Provider " + pi.packageName
6264 + "/" + pi.name
6265 + " does not allow granting of permission to path of Uri "
6266 + uri);
6267 }
6268 }
6269
6270 // Fourth... does the caller itself have permission to access
6271 // this uri?
6272 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6273 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6274 throw new SecurityException("Uid " + callingUid
6275 + " does not have permission to uri " + uri);
6276 }
6277 }
6278
6279 // Okay! So here we are: the caller has the assumed permission
6280 // to the uri, and the target doesn't. Let's now give this to
6281 // the target.
6282
6283 HashMap<Uri, UriPermission> targetUris
6284 = mGrantedUriPermissions.get(targetUid);
6285 if (targetUris == null) {
6286 targetUris = new HashMap<Uri, UriPermission>();
6287 mGrantedUriPermissions.put(targetUid, targetUris);
6288 }
6289
6290 UriPermission perm = targetUris.get(uri);
6291 if (perm == null) {
6292 perm = new UriPermission(targetUid, uri);
6293 targetUris.put(uri, perm);
6294
6295 }
6296 perm.modeFlags |= modeFlags;
6297 if (activity == null) {
6298 perm.globalModeFlags |= modeFlags;
6299 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6300 perm.readActivities.add(activity);
6301 if (activity.readUriPermissions == null) {
6302 activity.readUriPermissions = new HashSet<UriPermission>();
6303 }
6304 activity.readUriPermissions.add(perm);
6305 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6306 perm.writeActivities.add(activity);
6307 if (activity.writeUriPermissions == null) {
6308 activity.writeUriPermissions = new HashSet<UriPermission>();
6309 }
6310 activity.writeUriPermissions.add(perm);
6311 }
6312 }
6313
6314 private void grantUriPermissionFromIntentLocked(int callingUid,
6315 String targetPkg, Intent intent, HistoryRecord activity) {
6316 if (intent == null) {
6317 return;
6318 }
6319 Uri data = intent.getData();
6320 if (data == null) {
6321 return;
6322 }
6323 grantUriPermissionLocked(callingUid, targetPkg, data,
6324 intent.getFlags(), activity);
6325 }
6326
6327 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6328 Uri uri, int modeFlags) {
6329 synchronized(this) {
6330 final ProcessRecord r = getRecordForAppLocked(caller);
6331 if (r == null) {
6332 throw new SecurityException("Unable to find app for caller "
6333 + caller
6334 + " when granting permission to uri " + uri);
6335 }
6336 if (targetPkg == null) {
6337 Log.w(TAG, "grantUriPermission: null target");
6338 return;
6339 }
6340 if (uri == null) {
6341 Log.w(TAG, "grantUriPermission: null uri");
6342 return;
6343 }
6344
6345 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6346 null);
6347 }
6348 }
6349
6350 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6351 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6352 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6353 HashMap<Uri, UriPermission> perms
6354 = mGrantedUriPermissions.get(perm.uid);
6355 if (perms != null) {
6356 perms.remove(perm.uri);
6357 if (perms.size() == 0) {
6358 mGrantedUriPermissions.remove(perm.uid);
6359 }
6360 }
6361 }
6362 }
6363
6364 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6365 if (activity.readUriPermissions != null) {
6366 for (UriPermission perm : activity.readUriPermissions) {
6367 perm.readActivities.remove(activity);
6368 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6369 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6370 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6371 removeUriPermissionIfNeededLocked(perm);
6372 }
6373 }
6374 }
6375 if (activity.writeUriPermissions != null) {
6376 for (UriPermission perm : activity.writeUriPermissions) {
6377 perm.writeActivities.remove(activity);
6378 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6379 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6380 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6381 removeUriPermissionIfNeededLocked(perm);
6382 }
6383 }
6384 }
6385 }
6386
6387 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6388 int modeFlags) {
6389 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6390 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6391 if (modeFlags == 0) {
6392 return;
6393 }
6394
6395 final IPackageManager pm = ActivityThread.getPackageManager();
6396
6397 final String authority = uri.getAuthority();
6398 ProviderInfo pi = null;
6399 ContentProviderRecord cpr
6400 = (ContentProviderRecord)mProvidersByName.get(authority);
6401 if (cpr != null) {
6402 pi = cpr.info;
6403 } else {
6404 try {
6405 pi = pm.resolveContentProvider(authority,
6406 PackageManager.GET_URI_PERMISSION_PATTERNS);
6407 } catch (RemoteException ex) {
6408 }
6409 }
6410 if (pi == null) {
6411 Log.w(TAG, "No content provider found for: " + authority);
6412 return;
6413 }
6414
6415 // Does the caller have this permission on the URI?
6416 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6417 // Right now, if you are not the original owner of the permission,
6418 // you are not allowed to revoke it.
6419 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6420 throw new SecurityException("Uid " + callingUid
6421 + " does not have permission to uri " + uri);
6422 //}
6423 }
6424
6425 // Go through all of the permissions and remove any that match.
6426 final List<String> SEGMENTS = uri.getPathSegments();
6427 if (SEGMENTS != null) {
6428 final int NS = SEGMENTS.size();
6429 int N = mGrantedUriPermissions.size();
6430 for (int i=0; i<N; i++) {
6431 HashMap<Uri, UriPermission> perms
6432 = mGrantedUriPermissions.valueAt(i);
6433 Iterator<UriPermission> it = perms.values().iterator();
6434 toploop:
6435 while (it.hasNext()) {
6436 UriPermission perm = it.next();
6437 Uri targetUri = perm.uri;
6438 if (!authority.equals(targetUri.getAuthority())) {
6439 continue;
6440 }
6441 List<String> targetSegments = targetUri.getPathSegments();
6442 if (targetSegments == null) {
6443 continue;
6444 }
6445 if (targetSegments.size() < NS) {
6446 continue;
6447 }
6448 for (int j=0; j<NS; j++) {
6449 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6450 continue toploop;
6451 }
6452 }
6453 perm.clearModes(modeFlags);
6454 if (perm.modeFlags == 0) {
6455 it.remove();
6456 }
6457 }
6458 if (perms.size() == 0) {
6459 mGrantedUriPermissions.remove(
6460 mGrantedUriPermissions.keyAt(i));
6461 N--;
6462 i--;
6463 }
6464 }
6465 }
6466 }
6467
6468 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6469 int modeFlags) {
6470 synchronized(this) {
6471 final ProcessRecord r = getRecordForAppLocked(caller);
6472 if (r == null) {
6473 throw new SecurityException("Unable to find app for caller "
6474 + caller
6475 + " when revoking permission to uri " + uri);
6476 }
6477 if (uri == null) {
6478 Log.w(TAG, "revokeUriPermission: null uri");
6479 return;
6480 }
6481
6482 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6483 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6484 if (modeFlags == 0) {
6485 return;
6486 }
6487
6488 final IPackageManager pm = ActivityThread.getPackageManager();
6489
6490 final String authority = uri.getAuthority();
6491 ProviderInfo pi = null;
6492 ContentProviderRecord cpr
6493 = (ContentProviderRecord)mProvidersByName.get(authority);
6494 if (cpr != null) {
6495 pi = cpr.info;
6496 } else {
6497 try {
6498 pi = pm.resolveContentProvider(authority,
6499 PackageManager.GET_URI_PERMISSION_PATTERNS);
6500 } catch (RemoteException ex) {
6501 }
6502 }
6503 if (pi == null) {
6504 Log.w(TAG, "No content provider found for: " + authority);
6505 return;
6506 }
6507
6508 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6509 }
6510 }
6511
6512 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6513 synchronized (this) {
6514 ProcessRecord app =
6515 who != null ? getRecordForAppLocked(who) : null;
6516 if (app == null) return;
6517
6518 Message msg = Message.obtain();
6519 msg.what = WAIT_FOR_DEBUGGER_MSG;
6520 msg.obj = app;
6521 msg.arg1 = waiting ? 1 : 0;
6522 mHandler.sendMessage(msg);
6523 }
6524 }
6525
6526 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6527 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006528 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006529 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006530 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006531 }
6532
6533 // =========================================================
6534 // TASK MANAGEMENT
6535 // =========================================================
6536
6537 public List getTasks(int maxNum, int flags,
6538 IThumbnailReceiver receiver) {
6539 ArrayList list = new ArrayList();
6540
6541 PendingThumbnailsRecord pending = null;
6542 IApplicationThread topThumbnail = null;
6543 HistoryRecord topRecord = null;
6544
6545 synchronized(this) {
6546 if (localLOGV) Log.v(
6547 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6548 + ", receiver=" + receiver);
6549
6550 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6551 != PackageManager.PERMISSION_GRANTED) {
6552 if (receiver != null) {
6553 // If the caller wants to wait for pending thumbnails,
6554 // it ain't gonna get them.
6555 try {
6556 receiver.finished();
6557 } catch (RemoteException ex) {
6558 }
6559 }
6560 String msg = "Permission Denial: getTasks() from pid="
6561 + Binder.getCallingPid()
6562 + ", uid=" + Binder.getCallingUid()
6563 + " requires " + android.Manifest.permission.GET_TASKS;
6564 Log.w(TAG, msg);
6565 throw new SecurityException(msg);
6566 }
6567
6568 int pos = mHistory.size()-1;
6569 HistoryRecord next =
6570 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6571 HistoryRecord top = null;
6572 CharSequence topDescription = null;
6573 TaskRecord curTask = null;
6574 int numActivities = 0;
6575 int numRunning = 0;
6576 while (pos >= 0 && maxNum > 0) {
6577 final HistoryRecord r = next;
6578 pos--;
6579 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6580
6581 // Initialize state for next task if needed.
6582 if (top == null ||
6583 (top.state == ActivityState.INITIALIZING
6584 && top.task == r.task)) {
6585 top = r;
6586 topDescription = r.description;
6587 curTask = r.task;
6588 numActivities = numRunning = 0;
6589 }
6590
6591 // Add 'r' into the current task.
6592 numActivities++;
6593 if (r.app != null && r.app.thread != null) {
6594 numRunning++;
6595 }
6596 if (topDescription == null) {
6597 topDescription = r.description;
6598 }
6599
6600 if (localLOGV) Log.v(
6601 TAG, r.intent.getComponent().flattenToShortString()
6602 + ": task=" + r.task);
6603
6604 // If the next one is a different task, generate a new
6605 // TaskInfo entry for what we have.
6606 if (next == null || next.task != curTask) {
6607 ActivityManager.RunningTaskInfo ci
6608 = new ActivityManager.RunningTaskInfo();
6609 ci.id = curTask.taskId;
6610 ci.baseActivity = r.intent.getComponent();
6611 ci.topActivity = top.intent.getComponent();
6612 ci.thumbnail = top.thumbnail;
6613 ci.description = topDescription;
6614 ci.numActivities = numActivities;
6615 ci.numRunning = numRunning;
6616 //System.out.println(
6617 // "#" + maxNum + ": " + " descr=" + ci.description);
6618 if (ci.thumbnail == null && receiver != null) {
6619 if (localLOGV) Log.v(
6620 TAG, "State=" + top.state + "Idle=" + top.idle
6621 + " app=" + top.app
6622 + " thr=" + (top.app != null ? top.app.thread : null));
6623 if (top.state == ActivityState.RESUMED
6624 || top.state == ActivityState.PAUSING) {
6625 if (top.idle && top.app != null
6626 && top.app.thread != null) {
6627 topRecord = top;
6628 topThumbnail = top.app.thread;
6629 } else {
6630 top.thumbnailNeeded = true;
6631 }
6632 }
6633 if (pending == null) {
6634 pending = new PendingThumbnailsRecord(receiver);
6635 }
6636 pending.pendingRecords.add(top);
6637 }
6638 list.add(ci);
6639 maxNum--;
6640 top = null;
6641 }
6642 }
6643
6644 if (pending != null) {
6645 mPendingThumbnails.add(pending);
6646 }
6647 }
6648
6649 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6650
6651 if (topThumbnail != null) {
6652 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6653 try {
6654 topThumbnail.requestThumbnail(topRecord);
6655 } catch (Exception e) {
6656 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6657 sendPendingThumbnail(null, topRecord, null, null, true);
6658 }
6659 }
6660
6661 if (pending == null && receiver != null) {
6662 // In this case all thumbnails were available and the client
6663 // is being asked to be told when the remaining ones come in...
6664 // which is unusually, since the top-most currently running
6665 // activity should never have a canned thumbnail! Oh well.
6666 try {
6667 receiver.finished();
6668 } catch (RemoteException ex) {
6669 }
6670 }
6671
6672 return list;
6673 }
6674
6675 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6676 int flags) {
6677 synchronized (this) {
6678 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6679 "getRecentTasks()");
6680
6681 final int N = mRecentTasks.size();
6682 ArrayList<ActivityManager.RecentTaskInfo> res
6683 = new ArrayList<ActivityManager.RecentTaskInfo>(
6684 maxNum < N ? maxNum : N);
6685 for (int i=0; i<N && maxNum > 0; i++) {
6686 TaskRecord tr = mRecentTasks.get(i);
6687 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6688 || (tr.intent == null)
6689 || ((tr.intent.getFlags()
6690 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6691 ActivityManager.RecentTaskInfo rti
6692 = new ActivityManager.RecentTaskInfo();
6693 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6694 rti.baseIntent = new Intent(
6695 tr.intent != null ? tr.intent : tr.affinityIntent);
6696 rti.origActivity = tr.origActivity;
6697 res.add(rti);
6698 maxNum--;
6699 }
6700 }
6701 return res;
6702 }
6703 }
6704
6705 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6706 int j;
6707 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6708 TaskRecord jt = startTask;
6709
6710 // First look backwards
6711 for (j=startIndex-1; j>=0; j--) {
6712 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6713 if (r.task != jt) {
6714 jt = r.task;
6715 if (affinity.equals(jt.affinity)) {
6716 return j;
6717 }
6718 }
6719 }
6720
6721 // Now look forwards
6722 final int N = mHistory.size();
6723 jt = startTask;
6724 for (j=startIndex+1; j<N; j++) {
6725 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6726 if (r.task != jt) {
6727 if (affinity.equals(jt.affinity)) {
6728 return j;
6729 }
6730 jt = r.task;
6731 }
6732 }
6733
6734 // Might it be at the top?
6735 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6736 return N-1;
6737 }
6738
6739 return -1;
6740 }
6741
6742 /**
6743 * Perform a reset of the given task, if needed as part of launching it.
6744 * Returns the new HistoryRecord at the top of the task.
6745 */
6746 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6747 HistoryRecord newActivity) {
6748 boolean forceReset = (newActivity.info.flags
6749 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6750 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6751 if ((newActivity.info.flags
6752 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6753 forceReset = true;
6754 }
6755 }
6756
6757 final TaskRecord task = taskTop.task;
6758
6759 // We are going to move through the history list so that we can look
6760 // at each activity 'target' with 'below' either the interesting
6761 // activity immediately below it in the stack or null.
6762 HistoryRecord target = null;
6763 int targetI = 0;
6764 int taskTopI = -1;
6765 int replyChainEnd = -1;
6766 int lastReparentPos = -1;
6767 for (int i=mHistory.size()-1; i>=-1; i--) {
6768 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6769
6770 if (below != null && below.finishing) {
6771 continue;
6772 }
6773 if (target == null) {
6774 target = below;
6775 targetI = i;
6776 // If we were in the middle of a reply chain before this
6777 // task, it doesn't appear like the root of the chain wants
6778 // anything interesting, so drop it.
6779 replyChainEnd = -1;
6780 continue;
6781 }
6782
6783 final int flags = target.info.flags;
6784
6785 final boolean finishOnTaskLaunch =
6786 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6787 final boolean allowTaskReparenting =
6788 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6789
6790 if (target.task == task) {
6791 // We are inside of the task being reset... we'll either
6792 // finish this activity, push it out for another task,
6793 // or leave it as-is. We only do this
6794 // for activities that are not the root of the task (since
6795 // if we finish the root, we may no longer have the task!).
6796 if (taskTopI < 0) {
6797 taskTopI = targetI;
6798 }
6799 if (below != null && below.task == task) {
6800 final boolean clearWhenTaskReset =
6801 (target.intent.getFlags()
6802 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006803 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006804 // If this activity is sending a reply to a previous
6805 // activity, we can't do anything with it now until
6806 // we reach the start of the reply chain.
6807 // XXX note that we are assuming the result is always
6808 // to the previous activity, which is almost always
6809 // the case but we really shouldn't count on.
6810 if (replyChainEnd < 0) {
6811 replyChainEnd = targetI;
6812 }
Ed Heyl73798232009-03-24 21:32:21 -07006813 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006814 && target.taskAffinity != null
6815 && !target.taskAffinity.equals(task.affinity)) {
6816 // If this activity has an affinity for another
6817 // task, then we need to move it out of here. We will
6818 // move it as far out of the way as possible, to the
6819 // bottom of the activity stack. This also keeps it
6820 // correctly ordered with any activities we previously
6821 // moved.
6822 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6823 if (target.taskAffinity != null
6824 && target.taskAffinity.equals(p.task.affinity)) {
6825 // If the activity currently at the bottom has the
6826 // same task affinity as the one we are moving,
6827 // then merge it into the same task.
6828 target.task = p.task;
6829 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6830 + " out to bottom task " + p.task);
6831 } else {
6832 mCurTask++;
6833 if (mCurTask <= 0) {
6834 mCurTask = 1;
6835 }
6836 target.task = new TaskRecord(mCurTask, target.info, null,
6837 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6838 target.task.affinityIntent = target.intent;
6839 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6840 + " out to new task " + target.task);
6841 }
6842 mWindowManager.setAppGroupId(target, task.taskId);
6843 if (replyChainEnd < 0) {
6844 replyChainEnd = targetI;
6845 }
6846 int dstPos = 0;
6847 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6848 p = (HistoryRecord)mHistory.get(srcPos);
6849 if (p.finishing) {
6850 continue;
6851 }
6852 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6853 + " out to target's task " + target.task);
6854 task.numActivities--;
6855 p.task = target.task;
6856 target.task.numActivities++;
6857 mHistory.remove(srcPos);
6858 mHistory.add(dstPos, p);
6859 mWindowManager.moveAppToken(dstPos, p);
6860 mWindowManager.setAppGroupId(p, p.task.taskId);
6861 dstPos++;
6862 if (VALIDATE_TOKENS) {
6863 mWindowManager.validateAppTokens(mHistory);
6864 }
6865 i++;
6866 }
6867 if (taskTop == p) {
6868 taskTop = below;
6869 }
6870 if (taskTopI == replyChainEnd) {
6871 taskTopI = -1;
6872 }
6873 replyChainEnd = -1;
6874 addRecentTask(target.task);
6875 } else if (forceReset || finishOnTaskLaunch
6876 || clearWhenTaskReset) {
6877 // If the activity should just be removed -- either
6878 // because it asks for it, or the task should be
6879 // cleared -- then finish it and anything that is
6880 // part of its reply chain.
6881 if (clearWhenTaskReset) {
6882 // In this case, we want to finish this activity
6883 // and everything above it, so be sneaky and pretend
6884 // like these are all in the reply chain.
6885 replyChainEnd = targetI+1;
6886 while (replyChainEnd < mHistory.size() &&
6887 ((HistoryRecord)mHistory.get(
6888 replyChainEnd)).task == task) {
6889 replyChainEnd++;
6890 }
6891 replyChainEnd--;
6892 } else if (replyChainEnd < 0) {
6893 replyChainEnd = targetI;
6894 }
6895 HistoryRecord p = null;
6896 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6897 p = (HistoryRecord)mHistory.get(srcPos);
6898 if (p.finishing) {
6899 continue;
6900 }
6901 if (finishActivityLocked(p, srcPos,
6902 Activity.RESULT_CANCELED, null, "reset")) {
6903 replyChainEnd--;
6904 srcPos--;
6905 }
6906 }
6907 if (taskTop == p) {
6908 taskTop = below;
6909 }
6910 if (taskTopI == replyChainEnd) {
6911 taskTopI = -1;
6912 }
6913 replyChainEnd = -1;
6914 } else {
6915 // If we were in the middle of a chain, well the
6916 // activity that started it all doesn't want anything
6917 // special, so leave it all as-is.
6918 replyChainEnd = -1;
6919 }
6920 } else {
6921 // Reached the bottom of the task -- any reply chain
6922 // should be left as-is.
6923 replyChainEnd = -1;
6924 }
6925
6926 } else if (target.resultTo != null) {
6927 // If this activity is sending a reply to a previous
6928 // activity, we can't do anything with it now until
6929 // we reach the start of the reply chain.
6930 // XXX note that we are assuming the result is always
6931 // to the previous activity, which is almost always
6932 // the case but we really shouldn't count on.
6933 if (replyChainEnd < 0) {
6934 replyChainEnd = targetI;
6935 }
6936
6937 } else if (taskTopI >= 0 && allowTaskReparenting
6938 && task.affinity != null
6939 && task.affinity.equals(target.taskAffinity)) {
6940 // We are inside of another task... if this activity has
6941 // an affinity for our task, then either remove it if we are
6942 // clearing or move it over to our task. Note that
6943 // we currently punt on the case where we are resetting a
6944 // task that is not at the top but who has activities above
6945 // with an affinity to it... this is really not a normal
6946 // case, and we will need to later pull that task to the front
6947 // and usually at that point we will do the reset and pick
6948 // up those remaining activities. (This only happens if
6949 // someone starts an activity in a new task from an activity
6950 // in a task that is not currently on top.)
6951 if (forceReset || finishOnTaskLaunch) {
6952 if (replyChainEnd < 0) {
6953 replyChainEnd = targetI;
6954 }
6955 HistoryRecord p = null;
6956 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6957 p = (HistoryRecord)mHistory.get(srcPos);
6958 if (p.finishing) {
6959 continue;
6960 }
6961 if (finishActivityLocked(p, srcPos,
6962 Activity.RESULT_CANCELED, null, "reset")) {
6963 taskTopI--;
6964 lastReparentPos--;
6965 replyChainEnd--;
6966 srcPos--;
6967 }
6968 }
6969 replyChainEnd = -1;
6970 } else {
6971 if (replyChainEnd < 0) {
6972 replyChainEnd = targetI;
6973 }
6974 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6975 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6976 if (p.finishing) {
6977 continue;
6978 }
6979 if (lastReparentPos < 0) {
6980 lastReparentPos = taskTopI;
6981 taskTop = p;
6982 } else {
6983 lastReparentPos--;
6984 }
6985 mHistory.remove(srcPos);
6986 p.task.numActivities--;
6987 p.task = task;
6988 mHistory.add(lastReparentPos, p);
6989 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6990 + " in to resetting task " + task);
6991 task.numActivities++;
6992 mWindowManager.moveAppToken(lastReparentPos, p);
6993 mWindowManager.setAppGroupId(p, p.task.taskId);
6994 if (VALIDATE_TOKENS) {
6995 mWindowManager.validateAppTokens(mHistory);
6996 }
6997 }
6998 replyChainEnd = -1;
6999
7000 // Now we've moved it in to place... but what if this is
7001 // a singleTop activity and we have put it on top of another
7002 // instance of the same activity? Then we drop the instance
7003 // below so it remains singleTop.
7004 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
7005 for (int j=lastReparentPos-1; j>=0; j--) {
7006 HistoryRecord p = (HistoryRecord)mHistory.get(j);
7007 if (p.finishing) {
7008 continue;
7009 }
7010 if (p.intent.getComponent().equals(target.intent.getComponent())) {
7011 if (finishActivityLocked(p, j,
7012 Activity.RESULT_CANCELED, null, "replace")) {
7013 taskTopI--;
7014 lastReparentPos--;
7015 }
7016 }
7017 }
7018 }
7019 }
7020 }
7021
7022 target = below;
7023 targetI = i;
7024 }
7025
7026 return taskTop;
7027 }
7028
7029 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007030 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007031 */
7032 public void moveTaskToFront(int task) {
7033 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7034 "moveTaskToFront()");
7035
7036 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007037 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7038 Binder.getCallingUid(), "Task to front")) {
7039 return;
7040 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007041 final long origId = Binder.clearCallingIdentity();
7042 try {
7043 int N = mRecentTasks.size();
7044 for (int i=0; i<N; i++) {
7045 TaskRecord tr = mRecentTasks.get(i);
7046 if (tr.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007047 moveTaskToFrontLocked(tr, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007048 return;
7049 }
7050 }
7051 for (int i=mHistory.size()-1; i>=0; i--) {
7052 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
7053 if (hr.task.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007054 moveTaskToFrontLocked(hr.task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007055 return;
7056 }
7057 }
7058 } finally {
7059 Binder.restoreCallingIdentity(origId);
7060 }
7061 }
7062 }
7063
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007064 private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007065 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
7066
7067 final int task = tr.taskId;
7068 int top = mHistory.size()-1;
7069
7070 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
7071 // nothing to do!
7072 return;
7073 }
7074
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007075 ArrayList moved = new ArrayList();
7076
7077 // Applying the affinities may have removed entries from the history,
7078 // so get the size again.
7079 top = mHistory.size()-1;
7080 int pos = top;
7081
7082 // Shift all activities with this task up to the top
7083 // of the stack, keeping them in the same internal order.
7084 while (pos >= 0) {
7085 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7086 if (localLOGV) Log.v(
7087 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7088 boolean first = true;
7089 if (r.task.taskId == task) {
7090 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
7091 mHistory.remove(pos);
7092 mHistory.add(top, r);
7093 moved.add(0, r);
7094 top--;
7095 if (first) {
7096 addRecentTask(r.task);
7097 first = false;
7098 }
7099 }
7100 pos--;
7101 }
7102
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007103 if (DEBUG_TRANSITION) Log.v(TAG,
7104 "Prepare to front transition: task=" + tr);
7105 if (reason != null &&
7106 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7107 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7108 HistoryRecord r = topRunningActivityLocked(null);
7109 if (r != null) {
7110 mNoAnimActivities.add(r);
7111 }
7112 } else {
7113 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7114 }
7115
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007116 mWindowManager.moveAppTokensToTop(moved);
7117 if (VALIDATE_TOKENS) {
7118 mWindowManager.validateAppTokens(mHistory);
7119 }
7120
7121 finishTaskMove(task);
Doug Zongker2bec3d42009-12-04 12:52:44 -08007122 EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007123 }
7124
7125 private final void finishTaskMove(int task) {
7126 resumeTopActivityLocked(null);
7127 }
7128
7129 public void moveTaskToBack(int task) {
7130 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7131 "moveTaskToBack()");
7132
7133 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007134 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7135 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7136 Binder.getCallingUid(), "Task to back")) {
7137 return;
7138 }
7139 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007140 final long origId = Binder.clearCallingIdentity();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007141 moveTaskToBackLocked(task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007142 Binder.restoreCallingIdentity(origId);
7143 }
7144 }
7145
7146 /**
7147 * Moves an activity, and all of the other activities within the same task, to the bottom
7148 * of the history stack. The activity's order within the task is unchanged.
7149 *
7150 * @param token A reference to the activity we wish to move
7151 * @param nonRoot If false then this only works if the activity is the root
7152 * of a task; if true it will work for any activity in a task.
7153 * @return Returns true if the move completed, false if not.
7154 */
7155 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7156 synchronized(this) {
7157 final long origId = Binder.clearCallingIdentity();
7158 int taskId = getTaskForActivityLocked(token, !nonRoot);
7159 if (taskId >= 0) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007160 return moveTaskToBackLocked(taskId, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007161 }
7162 Binder.restoreCallingIdentity(origId);
7163 }
7164 return false;
7165 }
7166
7167 /**
7168 * Worker method for rearranging history stack. Implements the function of moving all
7169 * activities for a specific task (gathering them if disjoint) into a single group at the
7170 * bottom of the stack.
7171 *
7172 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7173 * to premeptively cancel the move.
7174 *
7175 * @param task The taskId to collect and move to the bottom.
7176 * @return Returns true if the move completed, false if not.
7177 */
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007178 private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007179 Log.i(TAG, "moveTaskToBack: " + task);
7180
7181 // If we have a watcher, preflight the move before committing to it. First check
7182 // for *other* available tasks, but if none are available, then try again allowing the
7183 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007184 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007185 HistoryRecord next = topRunningActivityLocked(null, task);
7186 if (next == null) {
7187 next = topRunningActivityLocked(null, 0);
7188 }
7189 if (next != null) {
7190 // ask watcher if this is allowed
7191 boolean moveOK = true;
7192 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007193 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007194 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007195 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007196 }
7197 if (!moveOK) {
7198 return false;
7199 }
7200 }
7201 }
7202
7203 ArrayList moved = new ArrayList();
7204
7205 if (DEBUG_TRANSITION) Log.v(TAG,
7206 "Prepare to back transition: task=" + task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007207
7208 final int N = mHistory.size();
7209 int bottom = 0;
7210 int pos = 0;
7211
7212 // Shift all activities with this task down to the bottom
7213 // of the stack, keeping them in the same internal order.
7214 while (pos < N) {
7215 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7216 if (localLOGV) Log.v(
7217 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7218 if (r.task.taskId == task) {
7219 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7220 mHistory.remove(pos);
7221 mHistory.add(bottom, r);
7222 moved.add(r);
7223 bottom++;
7224 }
7225 pos++;
7226 }
7227
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007228 if (reason != null &&
7229 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7230 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7231 HistoryRecord r = topRunningActivityLocked(null);
7232 if (r != null) {
7233 mNoAnimActivities.add(r);
7234 }
7235 } else {
Suchi Amalapurapuc9568e32009-11-05 18:51:16 -08007236 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007237 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007238 mWindowManager.moveAppTokensToBottom(moved);
7239 if (VALIDATE_TOKENS) {
7240 mWindowManager.validateAppTokens(mHistory);
7241 }
7242
7243 finishTaskMove(task);
7244 return true;
7245 }
7246
7247 public void moveTaskBackwards(int task) {
7248 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7249 "moveTaskBackwards()");
7250
7251 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007252 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7253 Binder.getCallingUid(), "Task backwards")) {
7254 return;
7255 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007256 final long origId = Binder.clearCallingIdentity();
7257 moveTaskBackwardsLocked(task);
7258 Binder.restoreCallingIdentity(origId);
7259 }
7260 }
7261
7262 private final void moveTaskBackwardsLocked(int task) {
7263 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7264 }
7265
7266 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7267 synchronized(this) {
7268 return getTaskForActivityLocked(token, onlyRoot);
7269 }
7270 }
7271
7272 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7273 final int N = mHistory.size();
7274 TaskRecord lastTask = null;
7275 for (int i=0; i<N; i++) {
7276 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7277 if (r == token) {
7278 if (!onlyRoot || lastTask != r.task) {
7279 return r.task.taskId;
7280 }
7281 return -1;
7282 }
7283 lastTask = r.task;
7284 }
7285
7286 return -1;
7287 }
7288
7289 /**
7290 * Returns the top activity in any existing task matching the given
7291 * Intent. Returns null if no such task is found.
7292 */
7293 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7294 ComponentName cls = intent.getComponent();
7295 if (info.targetActivity != null) {
7296 cls = new ComponentName(info.packageName, info.targetActivity);
7297 }
7298
7299 TaskRecord cp = null;
7300
7301 final int N = mHistory.size();
7302 for (int i=(N-1); i>=0; i--) {
7303 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7304 if (!r.finishing && r.task != cp
7305 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7306 cp = r.task;
7307 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7308 // + "/aff=" + r.task.affinity + " to new cls="
7309 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7310 if (r.task.affinity != null) {
7311 if (r.task.affinity.equals(info.taskAffinity)) {
7312 //Log.i(TAG, "Found matching affinity!");
7313 return r;
7314 }
7315 } else if (r.task.intent != null
7316 && r.task.intent.getComponent().equals(cls)) {
7317 //Log.i(TAG, "Found matching class!");
7318 //dump();
7319 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7320 return r;
7321 } else if (r.task.affinityIntent != null
7322 && r.task.affinityIntent.getComponent().equals(cls)) {
7323 //Log.i(TAG, "Found matching class!");
7324 //dump();
7325 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7326 return r;
7327 }
7328 }
7329 }
7330
7331 return null;
7332 }
7333
7334 /**
7335 * Returns the first activity (starting from the top of the stack) that
7336 * is the same as the given activity. Returns null if no such activity
7337 * is found.
7338 */
7339 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7340 ComponentName cls = intent.getComponent();
7341 if (info.targetActivity != null) {
7342 cls = new ComponentName(info.packageName, info.targetActivity);
7343 }
7344
7345 final int N = mHistory.size();
7346 for (int i=(N-1); i>=0; i--) {
7347 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7348 if (!r.finishing) {
7349 if (r.intent.getComponent().equals(cls)) {
7350 //Log.i(TAG, "Found matching class!");
7351 //dump();
7352 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7353 return r;
7354 }
7355 }
7356 }
7357
7358 return null;
7359 }
7360
7361 public void finishOtherInstances(IBinder token, ComponentName className) {
7362 synchronized(this) {
7363 final long origId = Binder.clearCallingIdentity();
7364
7365 int N = mHistory.size();
7366 TaskRecord lastTask = null;
7367 for (int i=0; i<N; i++) {
7368 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7369 if (r.realActivity.equals(className)
7370 && r != token && lastTask != r.task) {
7371 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7372 null, "others")) {
7373 i--;
7374 N--;
7375 }
7376 }
7377 lastTask = r.task;
7378 }
7379
7380 Binder.restoreCallingIdentity(origId);
7381 }
7382 }
7383
7384 // =========================================================
7385 // THUMBNAILS
7386 // =========================================================
7387
7388 public void reportThumbnail(IBinder token,
7389 Bitmap thumbnail, CharSequence description) {
7390 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7391 final long origId = Binder.clearCallingIdentity();
7392 sendPendingThumbnail(null, token, thumbnail, description, true);
7393 Binder.restoreCallingIdentity(origId);
7394 }
7395
7396 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7397 Bitmap thumbnail, CharSequence description, boolean always) {
7398 TaskRecord task = null;
7399 ArrayList receivers = null;
7400
7401 //System.out.println("Send pending thumbnail: " + r);
7402
7403 synchronized(this) {
7404 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007405 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007406 if (index < 0) {
7407 return;
7408 }
7409 r = (HistoryRecord)mHistory.get(index);
7410 }
7411 if (thumbnail == null) {
7412 thumbnail = r.thumbnail;
7413 description = r.description;
7414 }
7415 if (thumbnail == null && !always) {
7416 // If there is no thumbnail, and this entry is not actually
7417 // going away, then abort for now and pick up the next
7418 // thumbnail we get.
7419 return;
7420 }
7421 task = r.task;
7422
7423 int N = mPendingThumbnails.size();
7424 int i=0;
7425 while (i<N) {
7426 PendingThumbnailsRecord pr =
7427 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7428 //System.out.println("Looking in " + pr.pendingRecords);
7429 if (pr.pendingRecords.remove(r)) {
7430 if (receivers == null) {
7431 receivers = new ArrayList();
7432 }
7433 receivers.add(pr);
7434 if (pr.pendingRecords.size() == 0) {
7435 pr.finished = true;
7436 mPendingThumbnails.remove(i);
7437 N--;
7438 continue;
7439 }
7440 }
7441 i++;
7442 }
7443 }
7444
7445 if (receivers != null) {
7446 final int N = receivers.size();
7447 for (int i=0; i<N; i++) {
7448 try {
7449 PendingThumbnailsRecord pr =
7450 (PendingThumbnailsRecord)receivers.get(i);
7451 pr.receiver.newThumbnail(
7452 task != null ? task.taskId : -1, thumbnail, description);
7453 if (pr.finished) {
7454 pr.receiver.finished();
7455 }
7456 } catch (Exception e) {
7457 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7458 }
7459 }
7460 }
7461 }
7462
7463 // =========================================================
7464 // CONTENT PROVIDERS
7465 // =========================================================
7466
7467 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7468 List providers = null;
7469 try {
7470 providers = ActivityThread.getPackageManager().
7471 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007472 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007473 } catch (RemoteException ex) {
7474 }
7475 if (providers != null) {
7476 final int N = providers.size();
7477 for (int i=0; i<N; i++) {
7478 ProviderInfo cpi =
7479 (ProviderInfo)providers.get(i);
7480 ContentProviderRecord cpr =
7481 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7482 if (cpr == null) {
7483 cpr = new ContentProviderRecord(cpi, app.info);
7484 mProvidersByClass.put(cpi.name, cpr);
7485 }
7486 app.pubProviders.put(cpi.name, cpr);
7487 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007488 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007489 }
7490 }
7491 return providers;
7492 }
7493
7494 private final String checkContentProviderPermissionLocked(
7495 ProviderInfo cpi, ProcessRecord r, int mode) {
7496 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7497 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7498 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7499 cpi.exported ? -1 : cpi.applicationInfo.uid)
7500 == PackageManager.PERMISSION_GRANTED
7501 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7502 return null;
7503 }
7504 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7505 cpi.exported ? -1 : cpi.applicationInfo.uid)
7506 == PackageManager.PERMISSION_GRANTED) {
7507 return null;
7508 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007509
7510 PathPermission[] pps = cpi.pathPermissions;
7511 if (pps != null) {
7512 int i = pps.length;
7513 while (i > 0) {
7514 i--;
7515 PathPermission pp = pps[i];
7516 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7517 cpi.exported ? -1 : cpi.applicationInfo.uid)
7518 == PackageManager.PERMISSION_GRANTED
7519 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7520 return null;
7521 }
7522 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7523 cpi.exported ? -1 : cpi.applicationInfo.uid)
7524 == PackageManager.PERMISSION_GRANTED) {
7525 return null;
7526 }
7527 }
7528 }
7529
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007530 String msg = "Permission Denial: opening provider " + cpi.name
7531 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7532 + ", uid=" + callingUid + ") requires "
7533 + cpi.readPermission + " or " + cpi.writePermission;
7534 Log.w(TAG, msg);
7535 return msg;
7536 }
7537
7538 private final ContentProviderHolder getContentProviderImpl(
7539 IApplicationThread caller, String name) {
7540 ContentProviderRecord cpr;
7541 ProviderInfo cpi = null;
7542
7543 synchronized(this) {
7544 ProcessRecord r = null;
7545 if (caller != null) {
7546 r = getRecordForAppLocked(caller);
7547 if (r == null) {
7548 throw new SecurityException(
7549 "Unable to find app for caller " + caller
7550 + " (pid=" + Binder.getCallingPid()
7551 + ") when getting content provider " + name);
7552 }
7553 }
7554
7555 // First check if this content provider has been published...
7556 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7557 if (cpr != null) {
7558 cpi = cpr.info;
7559 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7560 return new ContentProviderHolder(cpi,
7561 cpi.readPermission != null
7562 ? cpi.readPermission : cpi.writePermission);
7563 }
7564
7565 if (r != null && cpr.canRunHere(r)) {
7566 // This provider has been published or is in the process
7567 // of being published... but it is also allowed to run
7568 // in the caller's process, so don't make a connection
7569 // and just let the caller instantiate its own instance.
7570 if (cpr.provider != null) {
7571 // don't give caller the provider object, it needs
7572 // to make its own.
7573 cpr = new ContentProviderRecord(cpr);
7574 }
7575 return cpr;
7576 }
7577
7578 final long origId = Binder.clearCallingIdentity();
7579
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007580 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007581 // return it right away.
7582 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007583 if (DEBUG_PROVIDER) Log.v(TAG,
7584 "Adding provider requested by "
7585 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007586 + cpr.info.processName);
7587 Integer cnt = r.conProviders.get(cpr);
7588 if (cnt == null) {
7589 r.conProviders.put(cpr, new Integer(1));
7590 } else {
7591 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7592 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007593 cpr.clients.add(r);
7594 } else {
7595 cpr.externals++;
7596 }
7597
7598 if (cpr.app != null) {
7599 updateOomAdjLocked(cpr.app);
7600 }
7601
7602 Binder.restoreCallingIdentity(origId);
7603
7604 } else {
7605 try {
7606 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007607 resolveContentProvider(name,
7608 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007609 } catch (RemoteException ex) {
7610 }
7611 if (cpi == null) {
7612 return null;
7613 }
7614
7615 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7616 return new ContentProviderHolder(cpi,
7617 cpi.readPermission != null
7618 ? cpi.readPermission : cpi.writePermission);
7619 }
7620
7621 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7622 final boolean firstClass = cpr == null;
7623 if (firstClass) {
7624 try {
7625 ApplicationInfo ai =
7626 ActivityThread.getPackageManager().
7627 getApplicationInfo(
7628 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007629 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007630 if (ai == null) {
7631 Log.w(TAG, "No package info for content provider "
7632 + cpi.name);
7633 return null;
7634 }
7635 cpr = new ContentProviderRecord(cpi, ai);
7636 } catch (RemoteException ex) {
7637 // pm is in same process, this will never happen.
7638 }
7639 }
7640
7641 if (r != null && cpr.canRunHere(r)) {
7642 // If this is a multiprocess provider, then just return its
7643 // info and allow the caller to instantiate it. Only do
7644 // this if the provider is the same user as the caller's
7645 // process, or can run as root (so can be in any process).
7646 return cpr;
7647 }
7648
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007649 if (DEBUG_PROVIDER) {
7650 RuntimeException e = new RuntimeException("here");
7651 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7652 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007653 }
7654
7655 // This is single process, and our app is now connecting to it.
7656 // See if we are already in the process of launching this
7657 // provider.
7658 final int N = mLaunchingProviders.size();
7659 int i;
7660 for (i=0; i<N; i++) {
7661 if (mLaunchingProviders.get(i) == cpr) {
7662 break;
7663 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007664 }
7665
7666 // If the provider is not already being launched, then get it
7667 // started.
7668 if (i >= N) {
7669 final long origId = Binder.clearCallingIdentity();
7670 ProcessRecord proc = startProcessLocked(cpi.processName,
7671 cpr.appInfo, false, 0, "content provider",
7672 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007673 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007674 if (proc == null) {
7675 Log.w(TAG, "Unable to launch app "
7676 + cpi.applicationInfo.packageName + "/"
7677 + cpi.applicationInfo.uid + " for provider "
7678 + name + ": process is bad");
7679 return null;
7680 }
7681 cpr.launchingApp = proc;
7682 mLaunchingProviders.add(cpr);
7683 Binder.restoreCallingIdentity(origId);
7684 }
7685
7686 // Make sure the provider is published (the same provider class
7687 // may be published under multiple names).
7688 if (firstClass) {
7689 mProvidersByClass.put(cpi.name, cpr);
7690 }
7691 mProvidersByName.put(name, cpr);
7692
7693 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007694 if (DEBUG_PROVIDER) Log.v(TAG,
7695 "Adding provider requested by "
7696 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007697 + cpr.info.processName);
7698 Integer cnt = r.conProviders.get(cpr);
7699 if (cnt == null) {
7700 r.conProviders.put(cpr, new Integer(1));
7701 } else {
7702 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7703 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007704 cpr.clients.add(r);
7705 } else {
7706 cpr.externals++;
7707 }
7708 }
7709 }
7710
7711 // Wait for the provider to be published...
7712 synchronized (cpr) {
7713 while (cpr.provider == null) {
7714 if (cpr.launchingApp == null) {
7715 Log.w(TAG, "Unable to launch app "
7716 + cpi.applicationInfo.packageName + "/"
7717 + cpi.applicationInfo.uid + " for provider "
7718 + name + ": launching app became null");
Doug Zongker2bec3d42009-12-04 12:52:44 -08007719 EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007720 cpi.applicationInfo.packageName,
7721 cpi.applicationInfo.uid, name);
7722 return null;
7723 }
7724 try {
7725 cpr.wait();
7726 } catch (InterruptedException ex) {
7727 }
7728 }
7729 }
7730 return cpr;
7731 }
7732
7733 public final ContentProviderHolder getContentProvider(
7734 IApplicationThread caller, String name) {
7735 if (caller == null) {
7736 String msg = "null IApplicationThread when getting content provider "
7737 + name;
7738 Log.w(TAG, msg);
7739 throw new SecurityException(msg);
7740 }
7741
7742 return getContentProviderImpl(caller, name);
7743 }
7744
7745 private ContentProviderHolder getContentProviderExternal(String name) {
7746 return getContentProviderImpl(null, name);
7747 }
7748
7749 /**
7750 * Drop a content provider from a ProcessRecord's bookkeeping
7751 * @param cpr
7752 */
7753 public void removeContentProvider(IApplicationThread caller, String name) {
7754 synchronized (this) {
7755 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7756 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007757 // remove from mProvidersByClass
7758 if (DEBUG_PROVIDER) Log.v(TAG, name +
7759 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007760 return;
7761 }
7762 final ProcessRecord r = getRecordForAppLocked(caller);
7763 if (r == null) {
7764 throw new SecurityException(
7765 "Unable to find app for caller " + caller +
7766 " when removing content provider " + name);
7767 }
7768 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007769 ContentProviderRecord localCpr = (ContentProviderRecord)
7770 mProvidersByClass.get(cpr.info.name);
7771 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7772 + r.info.processName + " from process "
7773 + localCpr.appInfo.processName);
7774 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007775 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007776 Log.w(TAG, "removeContentProvider called on local provider: "
7777 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007778 return;
7779 } else {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007780 Integer cnt = r.conProviders.get(localCpr);
7781 if (cnt == null || cnt.intValue() <= 1) {
7782 localCpr.clients.remove(r);
7783 r.conProviders.remove(localCpr);
7784 } else {
7785 r.conProviders.put(localCpr, new Integer(cnt.intValue()-1));
7786 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007787 }
7788 updateOomAdjLocked();
7789 }
7790 }
7791
7792 private void removeContentProviderExternal(String name) {
7793 synchronized (this) {
7794 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7795 if(cpr == null) {
7796 //remove from mProvidersByClass
7797 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7798 return;
7799 }
7800
7801 //update content provider record entry info
7802 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7803 localCpr.externals--;
7804 if (localCpr.externals < 0) {
7805 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7806 }
7807 updateOomAdjLocked();
7808 }
7809 }
7810
7811 public final void publishContentProviders(IApplicationThread caller,
7812 List<ContentProviderHolder> providers) {
7813 if (providers == null) {
7814 return;
7815 }
7816
7817 synchronized(this) {
7818 final ProcessRecord r = getRecordForAppLocked(caller);
7819 if (r == null) {
7820 throw new SecurityException(
7821 "Unable to find app for caller " + caller
7822 + " (pid=" + Binder.getCallingPid()
7823 + ") when publishing content providers");
7824 }
7825
7826 final long origId = Binder.clearCallingIdentity();
7827
7828 final int N = providers.size();
7829 for (int i=0; i<N; i++) {
7830 ContentProviderHolder src = providers.get(i);
7831 if (src == null || src.info == null || src.provider == null) {
7832 continue;
7833 }
7834 ContentProviderRecord dst =
7835 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7836 if (dst != null) {
7837 mProvidersByClass.put(dst.info.name, dst);
7838 String names[] = dst.info.authority.split(";");
7839 for (int j = 0; j < names.length; j++) {
7840 mProvidersByName.put(names[j], dst);
7841 }
7842
7843 int NL = mLaunchingProviders.size();
7844 int j;
7845 for (j=0; j<NL; j++) {
7846 if (mLaunchingProviders.get(j) == dst) {
7847 mLaunchingProviders.remove(j);
7848 j--;
7849 NL--;
7850 }
7851 }
7852 synchronized (dst) {
7853 dst.provider = src.provider;
7854 dst.app = r;
7855 dst.notifyAll();
7856 }
7857 updateOomAdjLocked(r);
7858 }
7859 }
7860
7861 Binder.restoreCallingIdentity(origId);
7862 }
7863 }
7864
7865 public static final void installSystemProviders() {
7866 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7867 List providers = mSelf.generateApplicationProvidersLocked(app);
7868 mSystemThread.installSystemProviders(providers);
7869 }
7870
7871 // =========================================================
7872 // GLOBAL MANAGEMENT
7873 // =========================================================
7874
7875 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7876 ApplicationInfo info, String customProcess) {
7877 String proc = customProcess != null ? customProcess : info.processName;
7878 BatteryStatsImpl.Uid.Proc ps = null;
7879 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7880 synchronized (stats) {
7881 ps = stats.getProcessStatsLocked(info.uid, proc);
7882 }
7883 return new ProcessRecord(ps, thread, info, proc);
7884 }
7885
7886 final ProcessRecord addAppLocked(ApplicationInfo info) {
7887 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7888
7889 if (app == null) {
7890 app = newProcessRecordLocked(null, info, null);
7891 mProcessNames.put(info.processName, info.uid, app);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08007892 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007893 }
7894
7895 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7896 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7897 app.persistent = true;
7898 app.maxAdj = CORE_SERVER_ADJ;
7899 }
7900 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7901 mPersistentStartingProcesses.add(app);
7902 startProcessLocked(app, "added application", app.processName);
7903 }
7904
7905 return app;
7906 }
7907
7908 public void unhandledBack() {
7909 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7910 "unhandledBack()");
7911
7912 synchronized(this) {
7913 int count = mHistory.size();
7914 if (Config.LOGD) Log.d(
7915 TAG, "Performing unhandledBack(): stack size = " + count);
7916 if (count > 1) {
7917 final long origId = Binder.clearCallingIdentity();
7918 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7919 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7920 Binder.restoreCallingIdentity(origId);
7921 }
7922 }
7923 }
7924
7925 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7926 String name = uri.getAuthority();
7927 ContentProviderHolder cph = getContentProviderExternal(name);
7928 ParcelFileDescriptor pfd = null;
7929 if (cph != null) {
7930 // We record the binder invoker's uid in thread-local storage before
7931 // going to the content provider to open the file. Later, in the code
7932 // that handles all permissions checks, we look for this uid and use
7933 // that rather than the Activity Manager's own uid. The effect is that
7934 // we do the check against the caller's permissions even though it looks
7935 // to the content provider like the Activity Manager itself is making
7936 // the request.
7937 sCallerIdentity.set(new Identity(
7938 Binder.getCallingPid(), Binder.getCallingUid()));
7939 try {
7940 pfd = cph.provider.openFile(uri, "r");
7941 } catch (FileNotFoundException e) {
7942 // do nothing; pfd will be returned null
7943 } finally {
7944 // Ensure that whatever happens, we clean up the identity state
7945 sCallerIdentity.remove();
7946 }
7947
7948 // We've got the fd now, so we're done with the provider.
7949 removeContentProviderExternal(name);
7950 } else {
7951 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7952 }
7953 return pfd;
7954 }
7955
7956 public void goingToSleep() {
7957 synchronized(this) {
7958 mSleeping = true;
7959 mWindowManager.setEventDispatching(false);
7960
7961 if (mResumedActivity != null) {
7962 pauseIfSleepingLocked();
7963 } else {
7964 Log.w(TAG, "goingToSleep with no resumed activity!");
7965 }
7966 }
7967 }
7968
Dianne Hackborn55280a92009-05-07 15:53:46 -07007969 public boolean shutdown(int timeout) {
7970 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7971 != PackageManager.PERMISSION_GRANTED) {
7972 throw new SecurityException("Requires permission "
7973 + android.Manifest.permission.SHUTDOWN);
7974 }
7975
7976 boolean timedout = false;
7977
7978 synchronized(this) {
7979 mShuttingDown = true;
7980 mWindowManager.setEventDispatching(false);
7981
7982 if (mResumedActivity != null) {
7983 pauseIfSleepingLocked();
7984 final long endTime = System.currentTimeMillis() + timeout;
7985 while (mResumedActivity != null || mPausingActivity != null) {
7986 long delay = endTime - System.currentTimeMillis();
7987 if (delay <= 0) {
7988 Log.w(TAG, "Activity manager shutdown timed out");
7989 timedout = true;
7990 break;
7991 }
7992 try {
7993 this.wait();
7994 } catch (InterruptedException e) {
7995 }
7996 }
7997 }
7998 }
7999
8000 mUsageStatsService.shutdown();
8001 mBatteryStatsService.shutdown();
8002
8003 return timedout;
8004 }
8005
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008006 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07008007 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008008 if (!mGoingToSleep.isHeld()) {
8009 mGoingToSleep.acquire();
8010 if (mLaunchingActivity.isHeld()) {
8011 mLaunchingActivity.release();
8012 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
8013 }
8014 }
8015
8016 // If we are not currently pausing an activity, get the current
8017 // one to pause. If we are pausing one, we will just let that stuff
8018 // run and release the wake lock when all done.
8019 if (mPausingActivity == null) {
8020 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
8021 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
8022 startPausingLocked(false, true);
8023 }
8024 }
8025 }
8026
8027 public void wakingUp() {
8028 synchronized(this) {
8029 if (mGoingToSleep.isHeld()) {
8030 mGoingToSleep.release();
8031 }
8032 mWindowManager.setEventDispatching(true);
8033 mSleeping = false;
8034 resumeTopActivityLocked(null);
8035 }
8036 }
8037
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07008038 public void stopAppSwitches() {
8039 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8040 != PackageManager.PERMISSION_GRANTED) {
8041 throw new SecurityException("Requires permission "
8042 + android.Manifest.permission.STOP_APP_SWITCHES);
8043 }
8044
8045 synchronized(this) {
8046 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
8047 + APP_SWITCH_DELAY_TIME;
8048 mDidAppSwitch = false;
8049 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8050 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8051 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
8052 }
8053 }
8054
8055 public void resumeAppSwitches() {
8056 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8057 != PackageManager.PERMISSION_GRANTED) {
8058 throw new SecurityException("Requires permission "
8059 + android.Manifest.permission.STOP_APP_SWITCHES);
8060 }
8061
8062 synchronized(this) {
8063 // Note that we don't execute any pending app switches... we will
8064 // let those wait until either the timeout, or the next start
8065 // activity request.
8066 mAppSwitchesAllowedTime = 0;
8067 }
8068 }
8069
8070 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
8071 String name) {
8072 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
8073 return true;
8074 }
8075
8076 final int perm = checkComponentPermission(
8077 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
8078 callingUid, -1);
8079 if (perm == PackageManager.PERMISSION_GRANTED) {
8080 return true;
8081 }
8082
8083 Log.w(TAG, name + " request from " + callingUid + " stopped");
8084 return false;
8085 }
8086
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008087 public void setDebugApp(String packageName, boolean waitForDebugger,
8088 boolean persistent) {
8089 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
8090 "setDebugApp()");
8091
8092 // Note that this is not really thread safe if there are multiple
8093 // callers into it at the same time, but that's not a situation we
8094 // care about.
8095 if (persistent) {
8096 final ContentResolver resolver = mContext.getContentResolver();
8097 Settings.System.putString(
8098 resolver, Settings.System.DEBUG_APP,
8099 packageName);
8100 Settings.System.putInt(
8101 resolver, Settings.System.WAIT_FOR_DEBUGGER,
8102 waitForDebugger ? 1 : 0);
8103 }
8104
8105 synchronized (this) {
8106 if (!persistent) {
8107 mOrigDebugApp = mDebugApp;
8108 mOrigWaitForDebugger = mWaitForDebugger;
8109 }
8110 mDebugApp = packageName;
8111 mWaitForDebugger = waitForDebugger;
8112 mDebugTransient = !persistent;
8113 if (packageName != null) {
8114 final long origId = Binder.clearCallingIdentity();
8115 uninstallPackageLocked(packageName, -1, false);
8116 Binder.restoreCallingIdentity(origId);
8117 }
8118 }
8119 }
8120
8121 public void setAlwaysFinish(boolean enabled) {
8122 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
8123 "setAlwaysFinish()");
8124
8125 Settings.System.putInt(
8126 mContext.getContentResolver(),
8127 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
8128
8129 synchronized (this) {
8130 mAlwaysFinishActivities = enabled;
8131 }
8132 }
8133
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008134 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008135 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008136 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008137 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008138 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008139 }
8140 }
8141
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008142 public void registerActivityWatcher(IActivityWatcher watcher) {
8143 mWatchers.register(watcher);
8144 }
8145
8146 public void unregisterActivityWatcher(IActivityWatcher watcher) {
8147 mWatchers.unregister(watcher);
8148 }
8149
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008150 public final void enterSafeMode() {
8151 synchronized(this) {
8152 // It only makes sense to do this before the system is ready
8153 // and started launching other packages.
8154 if (!mSystemReady) {
8155 try {
8156 ActivityThread.getPackageManager().enterSafeMode();
8157 } catch (RemoteException e) {
8158 }
8159
8160 View v = LayoutInflater.from(mContext).inflate(
8161 com.android.internal.R.layout.safe_mode, null);
8162 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8163 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8164 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8165 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8166 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8167 lp.format = v.getBackground().getOpacity();
8168 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8169 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8170 ((WindowManager)mContext.getSystemService(
8171 Context.WINDOW_SERVICE)).addView(v, lp);
8172 }
8173 }
8174 }
8175
8176 public void noteWakeupAlarm(IIntentSender sender) {
8177 if (!(sender instanceof PendingIntentRecord)) {
8178 return;
8179 }
8180 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8181 synchronized (stats) {
8182 if (mBatteryStatsService.isOnBattery()) {
8183 mBatteryStatsService.enforceCallingPermission();
8184 PendingIntentRecord rec = (PendingIntentRecord)sender;
8185 int MY_UID = Binder.getCallingUid();
8186 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8187 BatteryStatsImpl.Uid.Pkg pkg =
8188 stats.getPackageStatsLocked(uid, rec.key.packageName);
8189 pkg.incWakeupsLocked();
8190 }
8191 }
8192 }
8193
8194 public boolean killPidsForMemory(int[] pids) {
8195 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8196 throw new SecurityException("killPidsForMemory only available to the system");
8197 }
8198
8199 // XXX Note: don't acquire main activity lock here, because the window
8200 // manager calls in with its locks held.
8201
8202 boolean killed = false;
8203 synchronized (mPidsSelfLocked) {
8204 int[] types = new int[pids.length];
8205 int worstType = 0;
8206 for (int i=0; i<pids.length; i++) {
8207 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8208 if (proc != null) {
8209 int type = proc.setAdj;
8210 types[i] = type;
8211 if (type > worstType) {
8212 worstType = type;
8213 }
8214 }
8215 }
8216
8217 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8218 // then constrain it so we will kill all hidden procs.
8219 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8220 worstType = HIDDEN_APP_MIN_ADJ;
8221 }
8222 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8223 for (int i=0; i<pids.length; i++) {
8224 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8225 if (proc == null) {
8226 continue;
8227 }
8228 int adj = proc.setAdj;
8229 if (adj >= worstType) {
8230 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8231 + adj + ")");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008232 EventLog.writeEvent(EventLogTags.AM_KILL_FOR_MEMORY, proc.pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008233 proc.processName, adj);
8234 killed = true;
8235 Process.killProcess(pids[i]);
8236 }
8237 }
8238 }
8239 return killed;
8240 }
8241
8242 public void reportPss(IApplicationThread caller, int pss) {
8243 Watchdog.PssRequestor req;
8244 String name;
8245 ProcessRecord callerApp;
8246 synchronized (this) {
8247 if (caller == null) {
8248 return;
8249 }
8250 callerApp = getRecordForAppLocked(caller);
8251 if (callerApp == null) {
8252 return;
8253 }
8254 callerApp.lastPss = pss;
8255 req = callerApp;
8256 name = callerApp.processName;
8257 }
8258 Watchdog.getInstance().reportPss(req, name, pss);
8259 if (!callerApp.persistent) {
8260 removeRequestedPss(callerApp);
8261 }
8262 }
8263
8264 public void requestPss(Runnable completeCallback) {
8265 ArrayList<ProcessRecord> procs;
8266 synchronized (this) {
8267 mRequestPssCallback = completeCallback;
8268 mRequestPssList.clear();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008269 for (int i=mLruProcesses.size()-1; i>=0; i--) {
8270 ProcessRecord proc = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008271 if (!proc.persistent) {
8272 mRequestPssList.add(proc);
8273 }
8274 }
8275 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8276 }
8277
8278 int oldPri = Process.getThreadPriority(Process.myTid());
8279 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8280 for (int i=procs.size()-1; i>=0; i--) {
8281 ProcessRecord proc = procs.get(i);
8282 proc.lastPss = 0;
8283 proc.requestPss();
8284 }
8285 Process.setThreadPriority(oldPri);
8286 }
8287
8288 void removeRequestedPss(ProcessRecord proc) {
8289 Runnable callback = null;
8290 synchronized (this) {
8291 if (mRequestPssList.remove(proc)) {
8292 if (mRequestPssList.size() == 0) {
8293 callback = mRequestPssCallback;
8294 mRequestPssCallback = null;
8295 }
8296 }
8297 }
8298
8299 if (callback != null) {
8300 callback.run();
8301 }
8302 }
8303
8304 public void collectPss(Watchdog.PssStats stats) {
8305 stats.mEmptyPss = 0;
8306 stats.mEmptyCount = 0;
8307 stats.mBackgroundPss = 0;
8308 stats.mBackgroundCount = 0;
8309 stats.mServicePss = 0;
8310 stats.mServiceCount = 0;
8311 stats.mVisiblePss = 0;
8312 stats.mVisibleCount = 0;
8313 stats.mForegroundPss = 0;
8314 stats.mForegroundCount = 0;
8315 stats.mNoPssCount = 0;
8316 synchronized (this) {
8317 int i;
8318 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8319 ? mProcDeaths.length : stats.mProcDeaths.length;
8320 int aggr = 0;
8321 for (i=0; i<NPD; i++) {
8322 aggr += mProcDeaths[i];
8323 stats.mProcDeaths[i] = aggr;
8324 }
8325 while (i<stats.mProcDeaths.length) {
8326 stats.mProcDeaths[i] = 0;
8327 i++;
8328 }
8329
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008330 for (i=mLruProcesses.size()-1; i>=0; i--) {
8331 ProcessRecord proc = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008332 if (proc.persistent) {
8333 continue;
8334 }
8335 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8336 if (proc.lastPss == 0) {
8337 stats.mNoPssCount++;
8338 continue;
8339 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008340 if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8341 if (proc.empty) {
8342 stats.mEmptyPss += proc.lastPss;
8343 stats.mEmptyCount++;
8344 } else {
8345 stats.mBackgroundPss += proc.lastPss;
8346 stats.mBackgroundCount++;
8347 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008348 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8349 stats.mVisiblePss += proc.lastPss;
8350 stats.mVisibleCount++;
8351 } else {
8352 stats.mForegroundPss += proc.lastPss;
8353 stats.mForegroundCount++;
8354 }
8355 }
8356 }
8357 }
8358
8359 public final void startRunning(String pkg, String cls, String action,
8360 String data) {
8361 synchronized(this) {
8362 if (mStartRunning) {
8363 return;
8364 }
8365 mStartRunning = true;
8366 mTopComponent = pkg != null && cls != null
8367 ? new ComponentName(pkg, cls) : null;
8368 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8369 mTopData = data;
8370 if (!mSystemReady) {
8371 return;
8372 }
8373 }
8374
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008375 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008376 }
8377
8378 private void retrieveSettings() {
8379 final ContentResolver resolver = mContext.getContentResolver();
8380 String debugApp = Settings.System.getString(
8381 resolver, Settings.System.DEBUG_APP);
8382 boolean waitForDebugger = Settings.System.getInt(
8383 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8384 boolean alwaysFinishActivities = Settings.System.getInt(
8385 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8386
8387 Configuration configuration = new Configuration();
8388 Settings.System.getConfiguration(resolver, configuration);
8389
8390 synchronized (this) {
8391 mDebugApp = mOrigDebugApp = debugApp;
8392 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8393 mAlwaysFinishActivities = alwaysFinishActivities;
8394 // This happens before any activities are started, so we can
8395 // change mConfiguration in-place.
8396 mConfiguration.updateFrom(configuration);
Dianne Hackborndc6b6352009-09-30 14:20:09 -07008397 if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008398 }
8399 }
8400
8401 public boolean testIsSystemReady() {
8402 // no need to synchronize(this) just to read & return the value
8403 return mSystemReady;
8404 }
8405
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008406 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008407 // In the simulator, startRunning will never have been called, which
8408 // normally sets a few crucial variables. Do it here instead.
8409 if (!Process.supportsProcesses()) {
8410 mStartRunning = true;
8411 mTopAction = Intent.ACTION_MAIN;
8412 }
8413
8414 synchronized(this) {
8415 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008416 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008417 return;
8418 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008419
8420 // Check to see if there are any update receivers to run.
8421 if (!mDidUpdate) {
8422 if (mWaitingUpdate) {
8423 return;
8424 }
8425 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8426 List<ResolveInfo> ris = null;
8427 try {
8428 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8429 intent, null, 0);
8430 } catch (RemoteException e) {
8431 }
8432 if (ris != null) {
8433 for (int i=ris.size()-1; i>=0; i--) {
8434 if ((ris.get(i).activityInfo.applicationInfo.flags
8435 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8436 ris.remove(i);
8437 }
8438 }
8439 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8440 for (int i=0; i<ris.size(); i++) {
8441 ActivityInfo ai = ris.get(i).activityInfo;
8442 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8443 IIntentReceiver finisher = null;
8444 if (i == 0) {
8445 finisher = new IIntentReceiver.Stub() {
8446 public void performReceive(Intent intent, int resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -07008447 String data, Bundle extras, boolean ordered,
8448 boolean sticky)
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008449 throws RemoteException {
8450 synchronized (ActivityManagerService.this) {
8451 mDidUpdate = true;
8452 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008453 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008454 }
8455 };
8456 }
8457 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8458 broadcastIntentLocked(null, null, intent, null, finisher,
8459 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
8460 if (i == 0) {
8461 mWaitingUpdate = true;
8462 }
8463 }
8464 }
8465 if (mWaitingUpdate) {
8466 return;
8467 }
8468 mDidUpdate = true;
8469 }
8470
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008471 mSystemReady = true;
8472 if (!mStartRunning) {
8473 return;
8474 }
8475 }
8476
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008477 ArrayList<ProcessRecord> procsToKill = null;
8478 synchronized(mPidsSelfLocked) {
8479 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8480 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8481 if (!isAllowedWhileBooting(proc.info)){
8482 if (procsToKill == null) {
8483 procsToKill = new ArrayList<ProcessRecord>();
8484 }
8485 procsToKill.add(proc);
8486 }
8487 }
8488 }
8489
8490 if (procsToKill != null) {
8491 synchronized(this) {
8492 for (int i=procsToKill.size()-1; i>=0; i--) {
8493 ProcessRecord proc = procsToKill.get(i);
8494 Log.i(TAG, "Removing system update proc: " + proc);
8495 removeProcessLocked(proc, true);
8496 }
8497 }
8498 }
8499
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008500 Log.i(TAG, "System now ready");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008501 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008502 SystemClock.uptimeMillis());
8503
8504 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008505 // Make sure we have no pre-ready processes sitting around.
8506
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008507 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8508 ResolveInfo ri = mContext.getPackageManager()
8509 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008510 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008511 CharSequence errorMsg = null;
8512 if (ri != null) {
8513 ActivityInfo ai = ri.activityInfo;
8514 ApplicationInfo app = ai.applicationInfo;
8515 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8516 mTopAction = Intent.ACTION_FACTORY_TEST;
8517 mTopData = null;
8518 mTopComponent = new ComponentName(app.packageName,
8519 ai.name);
8520 } else {
8521 errorMsg = mContext.getResources().getText(
8522 com.android.internal.R.string.factorytest_not_system);
8523 }
8524 } else {
8525 errorMsg = mContext.getResources().getText(
8526 com.android.internal.R.string.factorytest_no_action);
8527 }
8528 if (errorMsg != null) {
8529 mTopAction = null;
8530 mTopData = null;
8531 mTopComponent = null;
8532 Message msg = Message.obtain();
8533 msg.what = SHOW_FACTORY_ERROR_MSG;
8534 msg.getData().putCharSequence("msg", errorMsg);
8535 mHandler.sendMessage(msg);
8536 }
8537 }
8538 }
8539
8540 retrieveSettings();
8541
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008542 if (goingCallback != null) goingCallback.run();
8543
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008544 synchronized (this) {
8545 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8546 try {
8547 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008548 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008549 if (apps != null) {
8550 int N = apps.size();
8551 int i;
8552 for (i=0; i<N; i++) {
8553 ApplicationInfo info
8554 = (ApplicationInfo)apps.get(i);
8555 if (info != null &&
8556 !info.packageName.equals("android")) {
8557 addAppLocked(info);
8558 }
8559 }
8560 }
8561 } catch (RemoteException ex) {
8562 // pm is in same process, this will never happen.
8563 }
8564 }
8565
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008566 // Start up initial activity.
8567 mBooting = true;
8568
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008569 try {
8570 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8571 Message msg = Message.obtain();
8572 msg.what = SHOW_UID_ERROR_MSG;
8573 mHandler.sendMessage(msg);
8574 }
8575 } catch (RemoteException e) {
8576 }
8577
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008578 resumeTopActivityLocked(null);
8579 }
8580 }
8581
Dan Egnorb7f03672009-12-09 16:22:32 -08008582 private boolean makeAppCrashingLocked(ProcessRecord app,
8583 String tag, String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008584 app.crashing = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008585 app.crashingReport = generateProcessError(app,
8586 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg,
8587 stackTrace);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008588 startAppProblemLocked(app);
8589 app.stopFreezingAllLocked();
8590 return handleAppCrashLocked(app);
8591 }
8592
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008593 private ComponentName getErrorReportReceiver(ProcessRecord app) {
Jacek Surazskia2339432009-09-18 15:01:26 +02008594 // check if error reporting is enabled in Gservices
8595 int enabled = Settings.Gservices.getInt(mContext.getContentResolver(),
8596 Settings.Gservices.SEND_ACTION_APP_ERROR, 0);
8597 if (enabled == 0) {
8598 return null;
8599 }
8600
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008601 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008602
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008603 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008604 // look for receiver in the installer package
8605 String candidate = pm.getInstallerPackageName(app.info.packageName);
8606 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8607 if (result != null) {
8608 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008609 }
8610
Jacek Surazski82a73df2009-06-17 14:33:18 +02008611 // if the error app is on the system image, look for system apps
8612 // error receiver
8613 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8614 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8615 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8616 if (result != null) {
8617 return result;
8618 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008619 }
8620
Jacek Surazski82a73df2009-06-17 14:33:18 +02008621 // if there is a default receiver, try that
8622 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8623 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008624 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008625 // should not happen
8626 Log.e(TAG, "error talking to PackageManager", e);
8627 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008628 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008629 }
8630
8631 /**
8632 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8633 *
8634 * @param pm PackageManager isntance
8635 * @param errorPackage package which caused the error
8636 * @param receiverPackage candidate package to receive the error
8637 * @return activity component within receiverPackage which handles
8638 * ACTION_APP_ERROR, or null if not found
8639 */
8640 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8641 String receiverPackage) throws RemoteException {
8642 if (receiverPackage == null || receiverPackage.length() == 0) {
8643 return null;
8644 }
8645
8646 // break the loop if it's the error report receiver package that crashed
8647 if (receiverPackage.equals(errorPackage)) {
8648 return null;
8649 }
8650
8651 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8652 intent.setPackage(receiverPackage);
8653 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8654 if (info == null || info.activityInfo == null) {
8655 return null;
8656 }
8657 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008658 }
8659
Dan Egnorb7f03672009-12-09 16:22:32 -08008660 private void makeAppNotRespondingLocked(ProcessRecord app,
8661 String tag, String shortMsg, String longMsg) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008662 app.notResponding = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008663 app.notRespondingReport = generateProcessError(app,
8664 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008665 startAppProblemLocked(app);
8666 app.stopFreezingAllLocked();
8667 }
8668
8669 /**
8670 * Generate a process error record, suitable for attachment to a ProcessRecord.
8671 *
8672 * @param app The ProcessRecord in which the error occurred.
8673 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8674 * ActivityManager.AppErrorStateInfo
8675 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8676 * @param shortMsg Short message describing the crash.
8677 * @param longMsg Long message describing the crash.
Dan Egnorb7f03672009-12-09 16:22:32 -08008678 * @param stackTrace Full crash stack trace, may be null.
8679 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008680 * @return Returns a fully-formed AppErrorStateInfo record.
8681 */
8682 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
Dan Egnorb7f03672009-12-09 16:22:32 -08008683 int condition, String tag, String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008684 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
Dan Egnorb7f03672009-12-09 16:22:32 -08008685
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008686 report.condition = condition;
8687 report.processName = app.processName;
8688 report.pid = app.pid;
8689 report.uid = app.info.uid;
8690 report.tag = tag;
8691 report.shortMsg = shortMsg;
8692 report.longMsg = longMsg;
Dan Egnorb7f03672009-12-09 16:22:32 -08008693 report.stackTrace = stackTrace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008694
8695 return report;
8696 }
8697
8698 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8699 boolean crashed) {
8700 synchronized (this) {
8701 app.crashing = false;
8702 app.crashingReport = null;
8703 app.notResponding = false;
8704 app.notRespondingReport = null;
8705 if (app.anrDialog == fromDialog) {
8706 app.anrDialog = null;
8707 }
8708 if (app.waitDialog == fromDialog) {
8709 app.waitDialog = null;
8710 }
8711 if (app.pid > 0 && app.pid != MY_PID) {
8712 if (crashed) {
8713 handleAppCrashLocked(app);
8714 }
8715 Log.i(ActivityManagerService.TAG, "Killing process "
8716 + app.processName
8717 + " (pid=" + app.pid + ") at user's request");
8718 Process.killProcess(app.pid);
8719 }
8720
8721 }
8722 }
8723
Dan Egnorb7f03672009-12-09 16:22:32 -08008724 private boolean handleAppCrashLocked(ProcessRecord app) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008725 long now = SystemClock.uptimeMillis();
8726
8727 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8728 app.info.uid);
8729 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8730 // This process loses!
8731 Log.w(TAG, "Process " + app.info.processName
8732 + " has crashed too many times: killing!");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008733 EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008734 app.info.processName, app.info.uid);
8735 killServicesLocked(app, false);
8736 for (int i=mHistory.size()-1; i>=0; i--) {
8737 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8738 if (r.app == app) {
8739 if (Config.LOGD) Log.d(
8740 TAG, " Force finishing activity "
8741 + r.intent.getComponent().flattenToShortString());
8742 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8743 }
8744 }
8745 if (!app.persistent) {
8746 // We don't want to start this process again until the user
8747 // explicitly does so... but for persistent process, we really
8748 // need to keep it running. If a persistent process is actually
8749 // repeatedly crashing, then badness for everyone.
Doug Zongker2bec3d42009-12-04 12:52:44 -08008750 EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008751 app.info.processName);
8752 mBadProcesses.put(app.info.processName, app.info.uid, now);
8753 app.bad = true;
8754 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8755 app.removed = true;
8756 removeProcessLocked(app, false);
8757 return false;
8758 }
8759 }
8760
8761 // Bump up the crash count of any services currently running in the proc.
8762 if (app.services.size() != 0) {
8763 // Any services running in the application need to be placed
8764 // back in the pending list.
8765 Iterator it = app.services.iterator();
8766 while (it.hasNext()) {
8767 ServiceRecord sr = (ServiceRecord)it.next();
8768 sr.crashCount++;
8769 }
8770 }
8771
8772 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8773 return true;
8774 }
8775
8776 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008777 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008778 skipCurrentReceiverLocked(app);
8779 }
8780
8781 void skipCurrentReceiverLocked(ProcessRecord app) {
8782 boolean reschedule = false;
8783 BroadcastRecord r = app.curReceiver;
8784 if (r != null) {
8785 // The current broadcast is waiting for this app's receiver
8786 // to be finished. Looks like that's not going to happen, so
8787 // let the broadcast continue.
8788 logBroadcastReceiverDiscard(r);
8789 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8790 r.resultExtras, r.resultAbort, true);
8791 reschedule = true;
8792 }
8793 r = mPendingBroadcast;
8794 if (r != null && r.curApp == app) {
8795 if (DEBUG_BROADCAST) Log.v(TAG,
8796 "skip & discard pending app " + r);
8797 logBroadcastReceiverDiscard(r);
8798 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8799 r.resultExtras, r.resultAbort, true);
8800 reschedule = true;
8801 }
8802 if (reschedule) {
8803 scheduleBroadcastsLocked();
8804 }
8805 }
8806
Dan Egnorb7f03672009-12-09 16:22:32 -08008807 public void handleApplicationError(IBinder app, String tag,
8808 ApplicationErrorReport.CrashInfo crashInfo) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008809 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008810 ProcessRecord r = null;
Dan Egnorb7f03672009-12-09 16:22:32 -08008811 long timeMillis = System.currentTimeMillis();
8812 String shortMsg = crashInfo.exceptionClassName;
8813 String longMsg = crashInfo.exceptionMessage;
8814 String stackTrace = crashInfo.stackTrace;
8815 if (shortMsg != null && longMsg != null) {
8816 longMsg = shortMsg + ": " + longMsg;
8817 } else if (shortMsg != null) {
8818 longMsg = shortMsg;
8819 }
8820
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008821 synchronized (this) {
8822 if (app != null) {
8823 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8824 final int NA = apps.size();
8825 for (int ia=0; ia<NA; ia++) {
8826 ProcessRecord p = apps.valueAt(ia);
8827 if (p.thread != null && p.thread.asBinder() == app) {
8828 r = p;
8829 break;
8830 }
8831 }
8832 }
8833 }
8834
8835 if (r != null) {
8836 // The application has crashed. Send the SIGQUIT to the process so
8837 // that it can dump its state.
8838 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8839 //Log.i(TAG, "Current system threads:");
8840 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8841 }
8842
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008843 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008844 try {
8845 String name = r != null ? r.processName : null;
8846 int pid = r != null ? r.pid : Binder.getCallingPid();
Dan Egnorb7f03672009-12-09 16:22:32 -08008847 if (!mController.appCrashed(name, pid, tag,
8848 shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008849 Log.w(TAG, "Force-killing crashed app " + name
8850 + " at watcher's request");
8851 Process.killProcess(pid);
Dan Egnorb7f03672009-12-09 16:22:32 -08008852 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008853 }
8854 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008855 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008856 }
8857 }
8858
8859 final long origId = Binder.clearCallingIdentity();
8860
8861 // If this process is running instrumentation, finish it.
8862 if (r != null && r.instrumentationClass != null) {
8863 Log.w(TAG, "Error in app " + r.processName
8864 + " running instrumentation " + r.instrumentationClass + ":");
8865 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8866 if (longMsg != null) Log.w(TAG, " " + longMsg);
8867 Bundle info = new Bundle();
8868 info.putString("shortMsg", shortMsg);
8869 info.putString("longMsg", longMsg);
8870 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8871 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08008872 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008873 }
8874
8875 if (r != null) {
Dan Egnorb7f03672009-12-09 16:22:32 -08008876 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, stackTrace)) {
8877 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008878 }
8879 } else {
8880 Log.w(TAG, "Some application object " + app + " tag " + tag
8881 + " has crashed, but I don't know who it is.");
8882 Log.w(TAG, "ShortMsg:" + shortMsg);
8883 Log.w(TAG, "LongMsg:" + longMsg);
8884 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08008885 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008886 }
8887
8888 Message msg = Message.obtain();
8889 msg.what = SHOW_ERROR_MSG;
8890 HashMap data = new HashMap();
8891 data.put("result", result);
8892 data.put("app", r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008893 msg.obj = data;
8894 mHandler.sendMessage(msg);
8895
8896 Binder.restoreCallingIdentity(origId);
8897 }
8898
8899 int res = result.get();
8900
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008901 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008902 synchronized (this) {
8903 if (r != null) {
8904 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8905 SystemClock.uptimeMillis());
8906 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008907 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
Dan Egnorb7f03672009-12-09 16:22:32 -08008908 appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008909 }
8910 }
8911
8912 if (appErrorIntent != null) {
8913 try {
8914 mContext.startActivity(appErrorIntent);
8915 } catch (ActivityNotFoundException e) {
8916 Log.w(TAG, "bug report receiver dissappeared", e);
8917 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008918 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008919 }
Dan Egnorb7f03672009-12-09 16:22:32 -08008920
8921 Intent createAppErrorIntentLocked(ProcessRecord r,
8922 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
8923 ApplicationErrorReport report = createAppErrorReportLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008924 if (report == null) {
8925 return null;
8926 }
8927 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8928 result.setComponent(r.errorReportReceiver);
8929 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8930 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8931 return result;
8932 }
8933
Dan Egnorb7f03672009-12-09 16:22:32 -08008934 private ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r,
8935 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008936 if (r.errorReportReceiver == null) {
8937 return null;
8938 }
8939
8940 if (!r.crashing && !r.notResponding) {
8941 return null;
8942 }
8943
Dan Egnorb7f03672009-12-09 16:22:32 -08008944 ApplicationErrorReport report = new ApplicationErrorReport();
8945 report.packageName = r.info.packageName;
8946 report.installerPackageName = r.errorReportReceiver.getPackageName();
8947 report.processName = r.processName;
8948 report.time = timeMillis;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008949
Dan Egnorb7f03672009-12-09 16:22:32 -08008950 if (r.crashing) {
8951 report.type = ApplicationErrorReport.TYPE_CRASH;
8952 report.crashInfo = crashInfo;
8953 } else if (r.notResponding) {
8954 report.type = ApplicationErrorReport.TYPE_ANR;
8955 report.anrInfo = new ApplicationErrorReport.AnrInfo();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008956
Dan Egnorb7f03672009-12-09 16:22:32 -08008957 report.anrInfo.activity = r.notRespondingReport.tag;
8958 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8959 report.anrInfo.info = r.notRespondingReport.longMsg;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008960 }
8961
Dan Egnorb7f03672009-12-09 16:22:32 -08008962 return report;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008963 }
8964
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008965 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8966 // assume our apps are happy - lazy create the list
8967 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8968
8969 synchronized (this) {
8970
8971 // iterate across all processes
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008972 for (int i=mLruProcesses.size()-1; i>=0; i--) {
8973 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008974 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8975 // This one's in trouble, so we'll generate a report for it
8976 // crashes are higher priority (in case there's a crash *and* an anr)
8977 ActivityManager.ProcessErrorStateInfo report = null;
8978 if (app.crashing) {
8979 report = app.crashingReport;
8980 } else if (app.notResponding) {
8981 report = app.notRespondingReport;
8982 }
8983
8984 if (report != null) {
8985 if (errList == null) {
8986 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8987 }
8988 errList.add(report);
8989 } else {
8990 Log.w(TAG, "Missing app error report, app = " + app.processName +
8991 " crashing = " + app.crashing +
8992 " notResponding = " + app.notResponding);
8993 }
8994 }
8995 }
8996 }
8997
8998 return errList;
8999 }
9000
9001 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
9002 // Lazy instantiation of list
9003 List<ActivityManager.RunningAppProcessInfo> runList = null;
9004 synchronized (this) {
9005 // Iterate across all processes
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009006 for (int i=mLruProcesses.size()-1; i>=0; i--) {
9007 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009008 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
9009 // Generate process state info for running application
9010 ActivityManager.RunningAppProcessInfo currApp =
9011 new ActivityManager.RunningAppProcessInfo(app.processName,
9012 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07009013 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009014 int adj = app.curAdj;
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009015 if (adj >= EMPTY_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009016 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
9017 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
9018 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08009019 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
9020 } else if (adj >= HOME_APP_ADJ) {
9021 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
9022 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009023 } else if (adj >= SECONDARY_SERVER_ADJ) {
9024 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
9025 } else if (adj >= VISIBLE_APP_ADJ) {
9026 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
9027 } else {
9028 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
9029 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009030 currApp.importanceReasonCode = app.adjTypeCode;
9031 if (app.adjSource instanceof ProcessRecord) {
9032 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
9033 } else if (app.adjSource instanceof HistoryRecord) {
9034 HistoryRecord r = (HistoryRecord)app.adjSource;
9035 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
9036 }
9037 if (app.adjTarget instanceof ComponentName) {
9038 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
9039 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009040 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
9041 // + " lru=" + currApp.lru);
9042 if (runList == null) {
9043 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
9044 }
9045 runList.add(currApp);
9046 }
9047 }
9048 }
9049 return runList;
9050 }
9051
9052 @Override
9053 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
9054 synchronized (this) {
9055 if (checkCallingPermission(android.Manifest.permission.DUMP)
9056 != PackageManager.PERMISSION_GRANTED) {
9057 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9058 + Binder.getCallingPid()
9059 + ", uid=" + Binder.getCallingUid()
9060 + " without permission "
9061 + android.Manifest.permission.DUMP);
9062 return;
9063 }
9064 if (args.length != 0 && "service".equals(args[0])) {
9065 dumpService(fd, pw, args);
9066 return;
9067 }
9068 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009069 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009070 pw.println(" ");
9071 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009072 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009073 if (mWaitingVisibleActivities.size() > 0) {
9074 pw.println(" ");
9075 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009076 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009077 }
9078 if (mStoppingActivities.size() > 0) {
9079 pw.println(" ");
9080 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009081 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009082 }
9083 if (mFinishingActivities.size() > 0) {
9084 pw.println(" ");
9085 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009086 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009087 }
9088
9089 pw.println(" ");
9090 pw.println(" mPausingActivity: " + mPausingActivity);
9091 pw.println(" mResumedActivity: " + mResumedActivity);
9092 pw.println(" mFocusedActivity: " + mFocusedActivity);
9093 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
9094
9095 if (mRecentTasks.size() > 0) {
9096 pw.println(" ");
9097 pw.println("Recent tasks in Current Activity Manager State:");
9098
9099 final int N = mRecentTasks.size();
9100 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009101 TaskRecord tr = mRecentTasks.get(i);
9102 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
9103 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009104 mRecentTasks.get(i).dump(pw, " ");
9105 }
9106 }
9107
9108 pw.println(" ");
9109 pw.println(" mCurTask: " + mCurTask);
9110
9111 pw.println(" ");
9112 pw.println("Processes in Current Activity Manager State:");
9113
9114 boolean needSep = false;
9115 int numPers = 0;
9116
9117 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
9118 final int NA = procs.size();
9119 for (int ia=0; ia<NA; ia++) {
9120 if (!needSep) {
9121 pw.println(" All known processes:");
9122 needSep = true;
9123 }
9124 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009125 pw.print(r.persistent ? " *PERS*" : " *APP*");
9126 pw.print(" UID "); pw.print(procs.keyAt(ia));
9127 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009128 r.dump(pw, " ");
9129 if (r.persistent) {
9130 numPers++;
9131 }
9132 }
9133 }
9134
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009135 if (mLruProcesses.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009136 if (needSep) pw.println(" ");
9137 needSep = true;
9138 pw.println(" Running processes (most recent first):");
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009139 dumpProcessList(pw, this, mLruProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009140 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009141 needSep = true;
9142 }
9143
9144 synchronized (mPidsSelfLocked) {
9145 if (mPidsSelfLocked.size() > 0) {
9146 if (needSep) pw.println(" ");
9147 needSep = true;
9148 pw.println(" PID mappings:");
9149 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009150 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9151 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009152 }
9153 }
9154 }
9155
9156 if (mForegroundProcesses.size() > 0) {
9157 if (needSep) pw.println(" ");
9158 needSep = true;
9159 pw.println(" Foreground Processes:");
9160 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009161 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9162 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009163 }
9164 }
9165
9166 if (mPersistentStartingProcesses.size() > 0) {
9167 if (needSep) pw.println(" ");
9168 needSep = true;
9169 pw.println(" Persisent processes that are starting:");
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009170 dumpProcessList(pw, this, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009171 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009172 }
9173
9174 if (mStartingProcesses.size() > 0) {
9175 if (needSep) pw.println(" ");
9176 needSep = true;
9177 pw.println(" Processes that are starting:");
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009178 dumpProcessList(pw, this, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009179 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009180 }
9181
9182 if (mRemovedProcesses.size() > 0) {
9183 if (needSep) pw.println(" ");
9184 needSep = true;
9185 pw.println(" Processes that are being removed:");
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009186 dumpProcessList(pw, this, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009187 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009188 }
9189
9190 if (mProcessesOnHold.size() > 0) {
9191 if (needSep) pw.println(" ");
9192 needSep = true;
9193 pw.println(" Processes that are on old until the system is ready:");
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009194 dumpProcessList(pw, this, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009195 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009196 }
9197
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009198 if (mProcessesToGc.size() > 0) {
9199 if (needSep) pw.println(" ");
9200 needSep = true;
9201 pw.println(" Processes that are waiting to GC:");
9202 long now = SystemClock.uptimeMillis();
9203 for (int i=0; i<mProcessesToGc.size(); i++) {
9204 ProcessRecord proc = mProcessesToGc.get(i);
9205 pw.print(" Process "); pw.println(proc);
9206 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9207 pw.print(", last gced=");
9208 pw.print(now-proc.lastRequestedGc);
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -07009209 pw.print(" ms ago, last lowMem=");
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009210 pw.print(now-proc.lastLowMemory);
9211 pw.println(" ms ago");
9212
9213 }
9214 }
9215
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009216 if (mProcessCrashTimes.getMap().size() > 0) {
9217 if (needSep) pw.println(" ");
9218 needSep = true;
9219 pw.println(" Time since processes crashed:");
9220 long now = SystemClock.uptimeMillis();
9221 for (Map.Entry<String, SparseArray<Long>> procs
9222 : mProcessCrashTimes.getMap().entrySet()) {
9223 SparseArray<Long> uids = procs.getValue();
9224 final int N = uids.size();
9225 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009226 pw.print(" Process "); pw.print(procs.getKey());
9227 pw.print(" uid "); pw.print(uids.keyAt(i));
9228 pw.print(": last crashed ");
9229 pw.print((now-uids.valueAt(i)));
9230 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009231 }
9232 }
9233 }
9234
9235 if (mBadProcesses.getMap().size() > 0) {
9236 if (needSep) pw.println(" ");
9237 needSep = true;
9238 pw.println(" Bad processes:");
9239 for (Map.Entry<String, SparseArray<Long>> procs
9240 : mBadProcesses.getMap().entrySet()) {
9241 SparseArray<Long> uids = procs.getValue();
9242 final int N = uids.size();
9243 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009244 pw.print(" Bad process "); pw.print(procs.getKey());
9245 pw.print(" uid "); pw.print(uids.keyAt(i));
9246 pw.print(": crashed at time ");
9247 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009248 }
9249 }
9250 }
9251
9252 pw.println(" ");
9253 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08009254 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009255 pw.println(" mConfiguration: " + mConfiguration);
9256 pw.println(" mStartRunning=" + mStartRunning
9257 + " mSystemReady=" + mSystemReady
9258 + " mBooting=" + mBooting
9259 + " mBooted=" + mBooted
9260 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07009261 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009262 pw.println(" mGoingToSleep=" + mGoingToSleep);
9263 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
9264 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9265 + " mDebugTransient=" + mDebugTransient
9266 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9267 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07009268 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009269 }
9270 }
9271
9272 /**
9273 * There are three ways to call this:
9274 * - no service specified: dump all the services
9275 * - a flattened component name that matched an existing service was specified as the
9276 * first arg: dump that one service
9277 * - the first arg isn't the flattened component name of an existing service:
9278 * dump all services whose component contains the first arg as a substring
9279 */
9280 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
9281 String[] newArgs;
9282 String componentNameString;
9283 ServiceRecord r;
9284 if (args.length == 1) {
9285 componentNameString = null;
9286 newArgs = EMPTY_STRING_ARRAY;
9287 r = null;
9288 } else {
9289 componentNameString = args[1];
9290 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9291 r = componentName != null ? mServices.get(componentName) : null;
9292 newArgs = new String[args.length - 2];
9293 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
9294 }
9295
9296 if (r != null) {
9297 dumpService(fd, pw, r, newArgs);
9298 } else {
9299 for (ServiceRecord r1 : mServices.values()) {
9300 if (componentNameString == null
9301 || r1.name.flattenToString().contains(componentNameString)) {
9302 dumpService(fd, pw, r1, newArgs);
9303 }
9304 }
9305 }
9306 }
9307
9308 /**
9309 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9310 * there is a thread associated with the service.
9311 */
9312 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9313 pw.println(" Service " + r.name.flattenToString());
9314 if (r.app != null && r.app.thread != null) {
9315 try {
9316 // flush anything that is already in the PrintWriter since the thread is going
9317 // to write to the file descriptor directly
9318 pw.flush();
9319 r.app.thread.dumpService(fd, r, args);
9320 pw.print("\n");
9321 } catch (RemoteException e) {
9322 pw.println("got a RemoteException while dumping the service");
9323 }
9324 }
9325 }
9326
9327 void dumpBroadcasts(PrintWriter pw) {
9328 synchronized (this) {
9329 if (checkCallingPermission(android.Manifest.permission.DUMP)
9330 != PackageManager.PERMISSION_GRANTED) {
9331 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9332 + Binder.getCallingPid()
9333 + ", uid=" + Binder.getCallingUid()
9334 + " without permission "
9335 + android.Manifest.permission.DUMP);
9336 return;
9337 }
9338 pw.println("Broadcasts in Current Activity Manager State:");
9339
9340 if (mRegisteredReceivers.size() > 0) {
9341 pw.println(" ");
9342 pw.println(" Registered Receivers:");
9343 Iterator it = mRegisteredReceivers.values().iterator();
9344 while (it.hasNext()) {
9345 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009346 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009347 r.dump(pw, " ");
9348 }
9349 }
9350
9351 pw.println(" ");
9352 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009353 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009354
9355 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9356 || mPendingBroadcast != null) {
9357 if (mParallelBroadcasts.size() > 0) {
9358 pw.println(" ");
9359 pw.println(" Active broadcasts:");
9360 }
9361 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9362 pw.println(" Broadcast #" + i + ":");
9363 mParallelBroadcasts.get(i).dump(pw, " ");
9364 }
9365 if (mOrderedBroadcasts.size() > 0) {
9366 pw.println(" ");
9367 pw.println(" Active serialized broadcasts:");
9368 }
9369 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9370 pw.println(" Serialized Broadcast #" + i + ":");
9371 mOrderedBroadcasts.get(i).dump(pw, " ");
9372 }
9373 pw.println(" ");
9374 pw.println(" Pending broadcast:");
9375 if (mPendingBroadcast != null) {
9376 mPendingBroadcast.dump(pw, " ");
9377 } else {
9378 pw.println(" (null)");
9379 }
9380 }
9381
9382 pw.println(" ");
Dianne Hackborn12527f92009-11-11 17:39:50 -08009383 pw.println(" Historical broadcasts:");
9384 for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
9385 BroadcastRecord r = mBroadcastHistory[i];
9386 if (r == null) {
9387 break;
9388 }
9389 pw.println(" Historical Broadcast #" + i + ":");
9390 r.dump(pw, " ");
9391 }
9392
9393 pw.println(" ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009394 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9395 if (mStickyBroadcasts != null) {
9396 pw.println(" ");
9397 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009398 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009399 for (Map.Entry<String, ArrayList<Intent>> ent
9400 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009401 pw.print(" * Sticky action "); pw.print(ent.getKey());
9402 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009403 ArrayList<Intent> intents = ent.getValue();
9404 final int N = intents.size();
9405 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009406 sb.setLength(0);
9407 sb.append(" Intent: ");
9408 intents.get(i).toShortString(sb, true, false);
9409 pw.println(sb.toString());
9410 Bundle bundle = intents.get(i).getExtras();
9411 if (bundle != null) {
9412 pw.print(" ");
9413 pw.println(bundle.toString());
9414 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009415 }
9416 }
9417 }
9418
9419 pw.println(" ");
9420 pw.println(" mHandler:");
9421 mHandler.dump(new PrintWriterPrinter(pw), " ");
9422 }
9423 }
9424
9425 void dumpServices(PrintWriter pw) {
9426 synchronized (this) {
9427 if (checkCallingPermission(android.Manifest.permission.DUMP)
9428 != PackageManager.PERMISSION_GRANTED) {
9429 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9430 + Binder.getCallingPid()
9431 + ", uid=" + Binder.getCallingUid()
9432 + " without permission "
9433 + android.Manifest.permission.DUMP);
9434 return;
9435 }
9436 pw.println("Services in Current Activity Manager State:");
9437
9438 boolean needSep = false;
9439
9440 if (mServices.size() > 0) {
9441 pw.println(" Active services:");
9442 Iterator<ServiceRecord> it = mServices.values().iterator();
9443 while (it.hasNext()) {
9444 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009445 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009446 r.dump(pw, " ");
9447 }
9448 needSep = true;
9449 }
9450
9451 if (mPendingServices.size() > 0) {
9452 if (needSep) pw.println(" ");
9453 pw.println(" Pending services:");
9454 for (int i=0; i<mPendingServices.size(); i++) {
9455 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009456 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009457 r.dump(pw, " ");
9458 }
9459 needSep = true;
9460 }
9461
9462 if (mRestartingServices.size() > 0) {
9463 if (needSep) pw.println(" ");
9464 pw.println(" Restarting services:");
9465 for (int i=0; i<mRestartingServices.size(); i++) {
9466 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009467 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009468 r.dump(pw, " ");
9469 }
9470 needSep = true;
9471 }
9472
9473 if (mStoppingServices.size() > 0) {
9474 if (needSep) pw.println(" ");
9475 pw.println(" Stopping services:");
9476 for (int i=0; i<mStoppingServices.size(); i++) {
9477 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009478 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009479 r.dump(pw, " ");
9480 }
9481 needSep = true;
9482 }
9483
9484 if (mServiceConnections.size() > 0) {
9485 if (needSep) pw.println(" ");
9486 pw.println(" Connection bindings to services:");
9487 Iterator<ConnectionRecord> it
9488 = mServiceConnections.values().iterator();
9489 while (it.hasNext()) {
9490 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009491 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009492 r.dump(pw, " ");
9493 }
9494 }
9495 }
9496 }
9497
9498 void dumpProviders(PrintWriter pw) {
9499 synchronized (this) {
9500 if (checkCallingPermission(android.Manifest.permission.DUMP)
9501 != PackageManager.PERMISSION_GRANTED) {
9502 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9503 + Binder.getCallingPid()
9504 + ", uid=" + Binder.getCallingUid()
9505 + " without permission "
9506 + android.Manifest.permission.DUMP);
9507 return;
9508 }
9509
9510 pw.println("Content Providers in Current Activity Manager State:");
9511
9512 boolean needSep = false;
9513
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009514 if (mProvidersByClass.size() > 0) {
9515 if (needSep) pw.println(" ");
9516 pw.println(" Published content providers (by class):");
9517 Iterator it = mProvidersByClass.entrySet().iterator();
9518 while (it.hasNext()) {
9519 Map.Entry e = (Map.Entry)it.next();
9520 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009521 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009522 r.dump(pw, " ");
9523 }
9524 needSep = true;
9525 }
9526
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009527 if (mProvidersByName.size() > 0) {
9528 pw.println(" ");
9529 pw.println(" Authority to provider mappings:");
9530 Iterator it = mProvidersByName.entrySet().iterator();
9531 while (it.hasNext()) {
9532 Map.Entry e = (Map.Entry)it.next();
9533 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9534 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9535 pw.println(r);
9536 }
9537 needSep = true;
9538 }
9539
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009540 if (mLaunchingProviders.size() > 0) {
9541 if (needSep) pw.println(" ");
9542 pw.println(" Launching content providers:");
9543 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009544 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9545 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009546 }
9547 needSep = true;
9548 }
9549
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009550 if (mGrantedUriPermissions.size() > 0) {
9551 pw.println();
9552 pw.println("Granted Uri Permissions:");
9553 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9554 int uid = mGrantedUriPermissions.keyAt(i);
9555 HashMap<Uri, UriPermission> perms
9556 = mGrantedUriPermissions.valueAt(i);
9557 pw.print(" * UID "); pw.print(uid);
9558 pw.println(" holds:");
9559 for (UriPermission perm : perms.values()) {
9560 pw.print(" "); pw.println(perm);
9561 perm.dump(pw, " ");
9562 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009563 }
9564 }
9565 }
9566 }
9567
9568 void dumpSenders(PrintWriter pw) {
9569 synchronized (this) {
9570 if (checkCallingPermission(android.Manifest.permission.DUMP)
9571 != PackageManager.PERMISSION_GRANTED) {
9572 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9573 + Binder.getCallingPid()
9574 + ", uid=" + Binder.getCallingUid()
9575 + " without permission "
9576 + android.Manifest.permission.DUMP);
9577 return;
9578 }
9579
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009580 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009581
9582 if (this.mIntentSenderRecords.size() > 0) {
9583 Iterator<WeakReference<PendingIntentRecord>> it
9584 = mIntentSenderRecords.values().iterator();
9585 while (it.hasNext()) {
9586 WeakReference<PendingIntentRecord> ref = it.next();
9587 PendingIntentRecord rec = ref != null ? ref.get(): null;
9588 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009589 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009590 rec.dump(pw, " ");
9591 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009592 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009593 }
9594 }
9595 }
9596 }
9597 }
9598
9599 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009600 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009601 TaskRecord lastTask = null;
9602 for (int i=list.size()-1; i>=0; i--) {
9603 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009604 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009605 if (lastTask != r.task) {
9606 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009607 pw.print(prefix);
9608 pw.print(full ? "* " : " ");
9609 pw.println(lastTask);
9610 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009611 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009612 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009613 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009614 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9615 pw.print(" #"); pw.print(i); pw.print(": ");
9616 pw.println(r);
9617 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009618 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009619 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009620 }
9621 }
9622
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009623 private static String buildOomTag(String prefix, String space, int val, int base) {
9624 if (val == base) {
9625 if (space == null) return prefix;
9626 return prefix + " ";
9627 }
9628 return prefix + "+" + Integer.toString(val-base);
9629 }
9630
9631 private static final int dumpProcessList(PrintWriter pw,
9632 ActivityManagerService service, List list,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009633 String prefix, String normalLabel, String persistentLabel,
9634 boolean inclOomAdj) {
9635 int numPers = 0;
9636 for (int i=list.size()-1; i>=0; i--) {
9637 ProcessRecord r = (ProcessRecord)list.get(i);
9638 if (false) {
9639 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9640 + " #" + i + ":");
9641 r.dump(pw, prefix + " ");
9642 } else if (inclOomAdj) {
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009643 String oomAdj;
9644 if (r.setAdj >= EMPTY_APP_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009645 oomAdj = buildOomTag("empty", null, r.setAdj, EMPTY_APP_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009646 } else if (r.setAdj >= HIDDEN_APP_MIN_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009647 oomAdj = buildOomTag("bak", " ", r.setAdj, HIDDEN_APP_MIN_ADJ);
9648 } else if (r.setAdj >= HOME_APP_ADJ) {
9649 oomAdj = buildOomTag("home ", null, r.setAdj, HOME_APP_ADJ);
9650 } else if (r.setAdj >= SECONDARY_SERVER_ADJ) {
9651 oomAdj = buildOomTag("svc", " ", r.setAdj, SECONDARY_SERVER_ADJ);
9652 } else if (r.setAdj >= BACKUP_APP_ADJ) {
9653 oomAdj = buildOomTag("bckup", null, r.setAdj, BACKUP_APP_ADJ);
9654 } else if (r.setAdj >= VISIBLE_APP_ADJ) {
9655 oomAdj = buildOomTag("vis ", null, r.setAdj, VISIBLE_APP_ADJ);
9656 } else if (r.setAdj >= FOREGROUND_APP_ADJ) {
9657 oomAdj = buildOomTag("fore ", null, r.setAdj, FOREGROUND_APP_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009658 } else if (r.setAdj >= CORE_SERVER_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009659 oomAdj = buildOomTag("core ", null, r.setAdj, CORE_SERVER_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009660 } else if (r.setAdj >= SYSTEM_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009661 oomAdj = buildOomTag("sys ", null, r.setAdj, SYSTEM_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009662 } else {
9663 oomAdj = Integer.toString(r.setAdj);
9664 }
9665 String schedGroup;
9666 switch (r.setSchedGroup) {
9667 case Process.THREAD_GROUP_BG_NONINTERACTIVE:
9668 schedGroup = "B";
9669 break;
9670 case Process.THREAD_GROUP_DEFAULT:
9671 schedGroup = "F";
9672 break;
9673 default:
9674 schedGroup = Integer.toString(r.setSchedGroup);
9675 break;
9676 }
9677 pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009678 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009679 i, oomAdj, schedGroup, r.toShortString(), r.adjType));
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009680 if (r.adjSource != null || r.adjTarget != null) {
9681 pw.println(prefix + " " + r.adjTarget
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009682 + "<=" + r.adjSource);
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009683 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009684 } else {
9685 pw.println(String.format("%s%s #%2d: %s",
9686 prefix, (r.persistent ? persistentLabel : normalLabel),
9687 i, r.toString()));
9688 }
9689 if (r.persistent) {
9690 numPers++;
9691 }
9692 }
9693 return numPers;
9694 }
9695
9696 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9697 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009698 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009699 long uptime = SystemClock.uptimeMillis();
9700 long realtime = SystemClock.elapsedRealtime();
9701
9702 if (isCheckinRequest) {
9703 // short checkin version
9704 pw.println(uptime + "," + realtime);
9705 pw.flush();
9706 } else {
9707 pw.println("Applications Memory Usage (kB):");
9708 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9709 }
9710 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9711 ProcessRecord r = (ProcessRecord)list.get(i);
9712 if (r.thread != null) {
9713 if (!isCheckinRequest) {
9714 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9715 pw.flush();
9716 }
9717 try {
9718 r.thread.asBinder().dump(fd, args);
9719 } catch (RemoteException e) {
9720 if (!isCheckinRequest) {
9721 pw.println("Got RemoteException!");
9722 pw.flush();
9723 }
9724 }
9725 }
9726 }
9727 }
9728
9729 /**
9730 * Searches array of arguments for the specified string
9731 * @param args array of argument strings
9732 * @param value value to search for
9733 * @return true if the value is contained in the array
9734 */
9735 private static boolean scanArgs(String[] args, String value) {
9736 if (args != null) {
9737 for (String arg : args) {
9738 if (value.equals(arg)) {
9739 return true;
9740 }
9741 }
9742 }
9743 return false;
9744 }
9745
Dianne Hackborn75b03852009-06-12 15:43:26 -07009746 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009747 int count = mHistory.size();
9748
9749 // convert the token to an entry in the history.
9750 HistoryRecord r = null;
9751 int index = -1;
9752 for (int i=count-1; i>=0; i--) {
9753 Object o = mHistory.get(i);
9754 if (o == token) {
9755 r = (HistoryRecord)o;
9756 index = i;
9757 break;
9758 }
9759 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009760
9761 return index;
9762 }
9763
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009764 private final void killServicesLocked(ProcessRecord app,
9765 boolean allowRestart) {
9766 // Report disconnected services.
9767 if (false) {
9768 // XXX we are letting the client link to the service for
9769 // death notifications.
9770 if (app.services.size() > 0) {
9771 Iterator it = app.services.iterator();
9772 while (it.hasNext()) {
9773 ServiceRecord r = (ServiceRecord)it.next();
9774 if (r.connections.size() > 0) {
9775 Iterator<ConnectionRecord> jt
9776 = r.connections.values().iterator();
9777 while (jt.hasNext()) {
9778 ConnectionRecord c = jt.next();
9779 if (c.binding.client != app) {
9780 try {
9781 //c.conn.connected(r.className, null);
9782 } catch (Exception e) {
9783 // todo: this should be asynchronous!
9784 Log.w(TAG, "Exception thrown disconnected servce "
9785 + r.shortName
9786 + " from app " + app.processName, e);
9787 }
9788 }
9789 }
9790 }
9791 }
9792 }
9793 }
9794
9795 // Clean up any connections this application has to other services.
9796 if (app.connections.size() > 0) {
9797 Iterator<ConnectionRecord> it = app.connections.iterator();
9798 while (it.hasNext()) {
9799 ConnectionRecord r = it.next();
9800 removeConnectionLocked(r, app, null);
9801 }
9802 }
9803 app.connections.clear();
9804
9805 if (app.services.size() != 0) {
9806 // Any services running in the application need to be placed
9807 // back in the pending list.
9808 Iterator it = app.services.iterator();
9809 while (it.hasNext()) {
9810 ServiceRecord sr = (ServiceRecord)it.next();
9811 synchronized (sr.stats.getBatteryStats()) {
9812 sr.stats.stopLaunchedLocked();
9813 }
9814 sr.app = null;
9815 sr.executeNesting = 0;
9816 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009817
9818 boolean hasClients = sr.bindings.size() > 0;
9819 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009820 Iterator<IntentBindRecord> bindings
9821 = sr.bindings.values().iterator();
9822 while (bindings.hasNext()) {
9823 IntentBindRecord b = bindings.next();
9824 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9825 + ": shouldUnbind=" + b.hasBound);
9826 b.binder = null;
9827 b.requested = b.received = b.hasBound = false;
9828 }
9829 }
9830
9831 if (sr.crashCount >= 2) {
9832 Log.w(TAG, "Service crashed " + sr.crashCount
9833 + " times, stopping: " + sr);
Doug Zongker2bec3d42009-12-04 12:52:44 -08009834 EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009835 sr.crashCount, sr.shortName, app.pid);
9836 bringDownServiceLocked(sr, true);
9837 } else if (!allowRestart) {
9838 bringDownServiceLocked(sr, true);
9839 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009840 boolean canceled = scheduleServiceRestartLocked(sr, true);
9841
9842 // Should the service remain running? Note that in the
9843 // extreme case of so many attempts to deliver a command
9844 // that it failed, that we also will stop it here.
9845 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
9846 if (sr.pendingStarts.size() == 0) {
9847 sr.startRequested = false;
9848 if (!hasClients) {
9849 // Whoops, no reason to restart!
9850 bringDownServiceLocked(sr, true);
9851 }
9852 }
9853 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009854 }
9855 }
9856
9857 if (!allowRestart) {
9858 app.services.clear();
9859 }
9860 }
9861
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009862 // Make sure we have no more records on the stopping list.
9863 int i = mStoppingServices.size();
9864 while (i > 0) {
9865 i--;
9866 ServiceRecord sr = mStoppingServices.get(i);
9867 if (sr.app == app) {
9868 mStoppingServices.remove(i);
9869 }
9870 }
9871
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009872 app.executingServices.clear();
9873 }
9874
9875 private final void removeDyingProviderLocked(ProcessRecord proc,
9876 ContentProviderRecord cpr) {
9877 synchronized (cpr) {
9878 cpr.launchingApp = null;
9879 cpr.notifyAll();
9880 }
9881
9882 mProvidersByClass.remove(cpr.info.name);
9883 String names[] = cpr.info.authority.split(";");
9884 for (int j = 0; j < names.length; j++) {
9885 mProvidersByName.remove(names[j]);
9886 }
9887
9888 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9889 while (cit.hasNext()) {
9890 ProcessRecord capp = cit.next();
9891 if (!capp.persistent && capp.thread != null
9892 && capp.pid != 0
9893 && capp.pid != MY_PID) {
9894 Log.i(TAG, "Killing app " + capp.processName
9895 + " (pid " + capp.pid
9896 + ") because provider " + cpr.info.name
9897 + " is in dying process " + proc.processName);
9898 Process.killProcess(capp.pid);
9899 }
9900 }
9901
9902 mLaunchingProviders.remove(cpr);
9903 }
9904
9905 /**
9906 * Main code for cleaning up a process when it has gone away. This is
9907 * called both as a result of the process dying, or directly when stopping
9908 * a process when running in single process mode.
9909 */
9910 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9911 boolean restarting, int index) {
9912 if (index >= 0) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009913 mLruProcesses.remove(index);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009914 }
9915
Dianne Hackborn36124872009-10-08 16:22:03 -07009916 mProcessesToGc.remove(app);
9917
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009918 // Dismiss any open dialogs.
9919 if (app.crashDialog != null) {
9920 app.crashDialog.dismiss();
9921 app.crashDialog = null;
9922 }
9923 if (app.anrDialog != null) {
9924 app.anrDialog.dismiss();
9925 app.anrDialog = null;
9926 }
9927 if (app.waitDialog != null) {
9928 app.waitDialog.dismiss();
9929 app.waitDialog = null;
9930 }
9931
9932 app.crashing = false;
9933 app.notResponding = false;
9934
9935 app.resetPackageList();
9936 app.thread = null;
9937 app.forcingToForeground = null;
9938 app.foregroundServices = false;
9939
9940 killServicesLocked(app, true);
9941
9942 boolean restart = false;
9943
9944 int NL = mLaunchingProviders.size();
9945
9946 // Remove published content providers.
9947 if (!app.pubProviders.isEmpty()) {
9948 Iterator it = app.pubProviders.values().iterator();
9949 while (it.hasNext()) {
9950 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9951 cpr.provider = null;
9952 cpr.app = null;
9953
9954 // See if someone is waiting for this provider... in which
9955 // case we don't remove it, but just let it restart.
9956 int i = 0;
9957 if (!app.bad) {
9958 for (; i<NL; i++) {
9959 if (mLaunchingProviders.get(i) == cpr) {
9960 restart = true;
9961 break;
9962 }
9963 }
9964 } else {
9965 i = NL;
9966 }
9967
9968 if (i >= NL) {
9969 removeDyingProviderLocked(app, cpr);
9970 NL = mLaunchingProviders.size();
9971 }
9972 }
9973 app.pubProviders.clear();
9974 }
9975
Dianne Hackbornf670ef72009-11-16 13:59:16 -08009976 // Take care of any launching providers waiting for this process.
9977 if (checkAppInLaunchingProvidersLocked(app, false)) {
9978 restart = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009979 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08009980
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009981 // Unregister from connected content providers.
9982 if (!app.conProviders.isEmpty()) {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07009983 Iterator it = app.conProviders.keySet().iterator();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009984 while (it.hasNext()) {
9985 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9986 cpr.clients.remove(app);
9987 }
9988 app.conProviders.clear();
9989 }
9990
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009991 // At this point there may be remaining entries in mLaunchingProviders
9992 // where we were the only one waiting, so they are no longer of use.
9993 // Look for these and clean up if found.
9994 // XXX Commented out for now. Trying to figure out a way to reproduce
9995 // the actual situation to identify what is actually going on.
9996 if (false) {
9997 for (int i=0; i<NL; i++) {
9998 ContentProviderRecord cpr = (ContentProviderRecord)
9999 mLaunchingProviders.get(i);
10000 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
10001 synchronized (cpr) {
10002 cpr.launchingApp = null;
10003 cpr.notifyAll();
10004 }
10005 }
10006 }
10007 }
10008
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010009 skipCurrentReceiverLocked(app);
10010
10011 // Unregister any receivers.
10012 if (app.receivers.size() > 0) {
10013 Iterator<ReceiverList> it = app.receivers.iterator();
10014 while (it.hasNext()) {
10015 removeReceiverLocked(it.next());
10016 }
10017 app.receivers.clear();
10018 }
10019
Christopher Tate181fafa2009-05-14 11:12:14 -070010020 // If the app is undergoing backup, tell the backup manager about it
10021 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
10022 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
10023 try {
10024 IBackupManager bm = IBackupManager.Stub.asInterface(
10025 ServiceManager.getService(Context.BACKUP_SERVICE));
10026 bm.agentDisconnected(app.info.packageName);
10027 } catch (RemoteException e) {
10028 // can't happen; backup manager is local
10029 }
10030 }
10031
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010032 // If the caller is restarting this app, then leave it in its
10033 // current lists and let the caller take care of it.
10034 if (restarting) {
10035 return;
10036 }
10037
10038 if (!app.persistent) {
10039 if (DEBUG_PROCESSES) Log.v(TAG,
10040 "Removing non-persistent process during cleanup: " + app);
10041 mProcessNames.remove(app.processName, app.info.uid);
10042 } else if (!app.removed) {
10043 // This app is persistent, so we need to keep its record around.
10044 // If it is not already on the pending app list, add it there
10045 // and start a new process for it.
10046 app.thread = null;
10047 app.forcingToForeground = null;
10048 app.foregroundServices = false;
10049 if (mPersistentStartingProcesses.indexOf(app) < 0) {
10050 mPersistentStartingProcesses.add(app);
10051 restart = true;
10052 }
10053 }
10054 mProcessesOnHold.remove(app);
10055
The Android Open Source Project4df24232009-03-05 14:34:35 -080010056 if (app == mHomeProcess) {
10057 mHomeProcess = null;
10058 }
10059
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010060 if (restart) {
10061 // We have components that still need to be running in the
10062 // process, so re-launch it.
10063 mProcessNames.put(app.processName, app.info.uid, app);
10064 startProcessLocked(app, "restart", app.processName);
10065 } else if (app.pid > 0 && app.pid != MY_PID) {
10066 // Goodbye!
10067 synchronized (mPidsSelfLocked) {
10068 mPidsSelfLocked.remove(app.pid);
10069 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
10070 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -070010071 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010072 }
10073 }
10074
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010075 boolean checkAppInLaunchingProvidersLocked(ProcessRecord app, boolean alwaysBad) {
10076 // Look through the content providers we are waiting to have launched,
10077 // and if any run in this process then either schedule a restart of
10078 // the process or kill the client waiting for it if this process has
10079 // gone bad.
10080 int NL = mLaunchingProviders.size();
10081 boolean restart = false;
10082 for (int i=0; i<NL; i++) {
10083 ContentProviderRecord cpr = (ContentProviderRecord)
10084 mLaunchingProviders.get(i);
10085 if (cpr.launchingApp == app) {
10086 if (!alwaysBad && !app.bad) {
10087 restart = true;
10088 } else {
10089 removeDyingProviderLocked(app, cpr);
10090 NL = mLaunchingProviders.size();
10091 }
10092 }
10093 }
10094 return restart;
10095 }
10096
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010097 // =========================================================
10098 // SERVICES
10099 // =========================================================
10100
10101 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
10102 ActivityManager.RunningServiceInfo info =
10103 new ActivityManager.RunningServiceInfo();
10104 info.service = r.name;
10105 if (r.app != null) {
10106 info.pid = r.app.pid;
10107 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010108 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010109 info.process = r.processName;
10110 info.foreground = r.isForeground;
10111 info.activeSince = r.createTime;
10112 info.started = r.startRequested;
10113 info.clientCount = r.connections.size();
10114 info.crashCount = r.crashCount;
10115 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010116 if (r.isForeground) {
10117 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
10118 }
10119 if (r.startRequested) {
10120 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
10121 }
10122 if (r.app != null && r.app.pid == Process.myPid()) {
10123 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
10124 }
10125 if (r.app != null && r.app.persistent) {
10126 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
10127 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010128 for (ConnectionRecord conn : r.connections.values()) {
10129 if (conn.clientLabel != 0) {
10130 info.clientPackage = conn.binding.client.info.packageName;
10131 info.clientLabel = conn.clientLabel;
10132 break;
10133 }
10134 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010135 return info;
10136 }
10137
10138 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
10139 int flags) {
10140 synchronized (this) {
10141 ArrayList<ActivityManager.RunningServiceInfo> res
10142 = new ArrayList<ActivityManager.RunningServiceInfo>();
10143
10144 if (mServices.size() > 0) {
10145 Iterator<ServiceRecord> it = mServices.values().iterator();
10146 while (it.hasNext() && res.size() < maxNum) {
10147 res.add(makeRunningServiceInfoLocked(it.next()));
10148 }
10149 }
10150
10151 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
10152 ServiceRecord r = mRestartingServices.get(i);
10153 ActivityManager.RunningServiceInfo info =
10154 makeRunningServiceInfoLocked(r);
10155 info.restarting = r.nextRestartTime;
10156 res.add(info);
10157 }
10158
10159 return res;
10160 }
10161 }
10162
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010163 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
10164 synchronized (this) {
10165 ServiceRecord r = mServices.get(name);
10166 if (r != null) {
10167 for (ConnectionRecord conn : r.connections.values()) {
10168 if (conn.clientIntent != null) {
10169 return conn.clientIntent;
10170 }
10171 }
10172 }
10173 }
10174 return null;
10175 }
10176
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010177 private final ServiceRecord findServiceLocked(ComponentName name,
10178 IBinder token) {
10179 ServiceRecord r = mServices.get(name);
10180 return r == token ? r : null;
10181 }
10182
10183 private final class ServiceLookupResult {
10184 final ServiceRecord record;
10185 final String permission;
10186
10187 ServiceLookupResult(ServiceRecord _record, String _permission) {
10188 record = _record;
10189 permission = _permission;
10190 }
10191 };
10192
10193 private ServiceLookupResult findServiceLocked(Intent service,
10194 String resolvedType) {
10195 ServiceRecord r = null;
10196 if (service.getComponent() != null) {
10197 r = mServices.get(service.getComponent());
10198 }
10199 if (r == null) {
10200 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10201 r = mServicesByIntent.get(filter);
10202 }
10203
10204 if (r == null) {
10205 try {
10206 ResolveInfo rInfo =
10207 ActivityThread.getPackageManager().resolveService(
10208 service, resolvedType, 0);
10209 ServiceInfo sInfo =
10210 rInfo != null ? rInfo.serviceInfo : null;
10211 if (sInfo == null) {
10212 return null;
10213 }
10214
10215 ComponentName name = new ComponentName(
10216 sInfo.applicationInfo.packageName, sInfo.name);
10217 r = mServices.get(name);
10218 } catch (RemoteException ex) {
10219 // pm is in same process, this will never happen.
10220 }
10221 }
10222 if (r != null) {
10223 int callingPid = Binder.getCallingPid();
10224 int callingUid = Binder.getCallingUid();
10225 if (checkComponentPermission(r.permission,
10226 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10227 != PackageManager.PERMISSION_GRANTED) {
10228 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10229 + " from pid=" + callingPid
10230 + ", uid=" + callingUid
10231 + " requires " + r.permission);
10232 return new ServiceLookupResult(null, r.permission);
10233 }
10234 return new ServiceLookupResult(r, null);
10235 }
10236 return null;
10237 }
10238
10239 private class ServiceRestarter implements Runnable {
10240 private ServiceRecord mService;
10241
10242 void setService(ServiceRecord service) {
10243 mService = service;
10244 }
10245
10246 public void run() {
10247 synchronized(ActivityManagerService.this) {
10248 performServiceRestartLocked(mService);
10249 }
10250 }
10251 }
10252
10253 private ServiceLookupResult retrieveServiceLocked(Intent service,
10254 String resolvedType, int callingPid, int callingUid) {
10255 ServiceRecord r = null;
10256 if (service.getComponent() != null) {
10257 r = mServices.get(service.getComponent());
10258 }
10259 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10260 r = mServicesByIntent.get(filter);
10261 if (r == null) {
10262 try {
10263 ResolveInfo rInfo =
10264 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010265 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010266 ServiceInfo sInfo =
10267 rInfo != null ? rInfo.serviceInfo : null;
10268 if (sInfo == null) {
10269 Log.w(TAG, "Unable to start service " + service +
10270 ": not found");
10271 return null;
10272 }
10273
10274 ComponentName name = new ComponentName(
10275 sInfo.applicationInfo.packageName, sInfo.name);
10276 r = mServices.get(name);
10277 if (r == null) {
10278 filter = new Intent.FilterComparison(service.cloneFilter());
10279 ServiceRestarter res = new ServiceRestarter();
10280 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10281 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10282 synchronized (stats) {
10283 ss = stats.getServiceStatsLocked(
10284 sInfo.applicationInfo.uid, sInfo.packageName,
10285 sInfo.name);
10286 }
10287 r = new ServiceRecord(ss, name, filter, sInfo, res);
10288 res.setService(r);
10289 mServices.put(name, r);
10290 mServicesByIntent.put(filter, r);
10291
10292 // Make sure this component isn't in the pending list.
10293 int N = mPendingServices.size();
10294 for (int i=0; i<N; i++) {
10295 ServiceRecord pr = mPendingServices.get(i);
10296 if (pr.name.equals(name)) {
10297 mPendingServices.remove(i);
10298 i--;
10299 N--;
10300 }
10301 }
10302 }
10303 } catch (RemoteException ex) {
10304 // pm is in same process, this will never happen.
10305 }
10306 }
10307 if (r != null) {
10308 if (checkComponentPermission(r.permission,
10309 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10310 != PackageManager.PERMISSION_GRANTED) {
10311 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10312 + " from pid=" + Binder.getCallingPid()
10313 + ", uid=" + Binder.getCallingUid()
10314 + " requires " + r.permission);
10315 return new ServiceLookupResult(null, r.permission);
10316 }
10317 return new ServiceLookupResult(r, null);
10318 }
10319 return null;
10320 }
10321
10322 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10323 long now = SystemClock.uptimeMillis();
10324 if (r.executeNesting == 0 && r.app != null) {
10325 if (r.app.executingServices.size() == 0) {
10326 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10327 msg.obj = r.app;
10328 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10329 }
10330 r.app.executingServices.add(r);
10331 }
10332 r.executeNesting++;
10333 r.executingStart = now;
10334 }
10335
10336 private final void sendServiceArgsLocked(ServiceRecord r,
10337 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010338 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010339 if (N == 0) {
10340 return;
10341 }
10342
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010343 int i = 0;
10344 while (i < N) {
10345 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010346 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010347 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010348 + r.name + " " + r.intent + " args=" + si.intent);
Dianne Hackbornfed534e2009-09-23 00:42:12 -070010349 if (si.intent == null && N > 1) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010350 // If somehow we got a dummy start at the front, then
10351 // just drop it here.
10352 i++;
10353 continue;
10354 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010355 bumpServiceExecutingLocked(r);
10356 if (!oomAdjusted) {
10357 oomAdjusted = true;
10358 updateOomAdjLocked(r.app);
10359 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010360 int flags = 0;
10361 if (si.deliveryCount > 0) {
10362 flags |= Service.START_FLAG_RETRY;
10363 }
10364 if (si.doneExecutingCount > 0) {
10365 flags |= Service.START_FLAG_REDELIVERY;
10366 }
10367 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10368 si.deliveredTime = SystemClock.uptimeMillis();
10369 r.deliveredStarts.add(si);
10370 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010371 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010372 } catch (RemoteException e) {
10373 // Remote process gone... we'll let the normal cleanup take
10374 // care of this.
10375 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010376 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010377 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010378 break;
10379 }
10380 }
10381 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010382 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010383 } else {
10384 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010385 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010386 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010387 }
10388 }
10389 }
10390
10391 private final boolean requestServiceBindingLocked(ServiceRecord r,
10392 IntentBindRecord i, boolean rebind) {
10393 if (r.app == null || r.app.thread == null) {
10394 // If service is not currently running, can't yet bind.
10395 return false;
10396 }
10397 if ((!i.requested || rebind) && i.apps.size() > 0) {
10398 try {
10399 bumpServiceExecutingLocked(r);
10400 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10401 + ": shouldUnbind=" + i.hasBound);
10402 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10403 if (!rebind) {
10404 i.requested = true;
10405 }
10406 i.hasBound = true;
10407 i.doRebind = false;
10408 } catch (RemoteException e) {
10409 return false;
10410 }
10411 }
10412 return true;
10413 }
10414
10415 private final void requestServiceBindingsLocked(ServiceRecord r) {
10416 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10417 while (bindings.hasNext()) {
10418 IntentBindRecord i = bindings.next();
10419 if (!requestServiceBindingLocked(r, i, false)) {
10420 break;
10421 }
10422 }
10423 }
10424
10425 private final void realStartServiceLocked(ServiceRecord r,
10426 ProcessRecord app) throws RemoteException {
10427 if (app.thread == null) {
10428 throw new RemoteException();
10429 }
10430
10431 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010432 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010433
10434 app.services.add(r);
10435 bumpServiceExecutingLocked(r);
Dianne Hackborndd71fc82009-12-16 19:24:32 -080010436 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010437
10438 boolean created = false;
10439 try {
10440 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10441 + r.name + " " + r.intent);
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010442 mStringBuilder.setLength(0);
10443 r.intent.getIntent().toShortString(mStringBuilder, false, true);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010444 EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010445 System.identityHashCode(r), r.shortName,
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010446 mStringBuilder.toString(), r.app.pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010447 synchronized (r.stats.getBatteryStats()) {
10448 r.stats.startLaunchedLocked();
10449 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010450 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010451 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010452 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010453 created = true;
10454 } finally {
10455 if (!created) {
10456 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010457 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010458 }
10459 }
10460
10461 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010462
10463 // If the service is in the started state, and there are no
10464 // pending arguments, then fake up one so its onStartCommand() will
10465 // be called.
10466 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10467 r.lastStartId++;
10468 if (r.lastStartId < 1) {
10469 r.lastStartId = 1;
10470 }
10471 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10472 }
10473
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010474 sendServiceArgsLocked(r, true);
10475 }
10476
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010477 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10478 boolean allowCancel) {
10479 boolean canceled = false;
10480
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010481 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010482 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010483 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010484
10485 // Any delivered but not yet finished starts should be put back
10486 // on the pending list.
10487 final int N = r.deliveredStarts.size();
10488 if (N > 0) {
10489 for (int i=N-1; i>=0; i--) {
10490 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10491 if (si.intent == null) {
10492 // We'll generate this again if needed.
10493 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10494 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10495 r.pendingStarts.add(0, si);
10496 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10497 dur *= 2;
10498 if (minDuration < dur) minDuration = dur;
10499 if (resetTime < dur) resetTime = dur;
10500 } else {
10501 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10502 + r.name);
10503 canceled = true;
10504 }
10505 }
10506 r.deliveredStarts.clear();
10507 }
10508
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010509 r.totalRestartCount++;
10510 if (r.restartDelay == 0) {
10511 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010512 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010513 } else {
10514 // If it has been a "reasonably long time" since the service
10515 // was started, then reset our restart duration back to
10516 // the beginning, so we don't infinitely increase the duration
10517 // on a service that just occasionally gets killed (which is
10518 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010519 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010520 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010521 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010522 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010523 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010524 if (r.restartDelay < minDuration) {
10525 r.restartDelay = minDuration;
10526 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010527 }
10528 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010529
10530 r.nextRestartTime = now + r.restartDelay;
10531
10532 // Make sure that we don't end up restarting a bunch of services
10533 // all at the same time.
10534 boolean repeat;
10535 do {
10536 repeat = false;
10537 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10538 ServiceRecord r2 = mRestartingServices.get(i);
10539 if (r2 != r && r.nextRestartTime
10540 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10541 && r.nextRestartTime
10542 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10543 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10544 r.restartDelay = r.nextRestartTime - now;
10545 repeat = true;
10546 break;
10547 }
10548 }
10549 } while (repeat);
10550
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010551 if (!mRestartingServices.contains(r)) {
10552 mRestartingServices.add(r);
10553 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010554
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010555 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010556
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010557 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010558 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010559 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10560 Log.w(TAG, "Scheduling restart of crashed service "
10561 + r.shortName + " in " + r.restartDelay + "ms");
Doug Zongker2bec3d42009-12-04 12:52:44 -080010562 EventLog.writeEvent(EventLogTags.AM_SCHEDULE_SERVICE_RESTART,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010563 r.shortName, r.restartDelay);
10564
10565 Message msg = Message.obtain();
10566 msg.what = SERVICE_ERROR_MSG;
10567 msg.obj = r;
10568 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010569
10570 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010571 }
10572
10573 final void performServiceRestartLocked(ServiceRecord r) {
10574 if (!mRestartingServices.contains(r)) {
10575 return;
10576 }
10577 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10578 }
10579
10580 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10581 if (r.restartDelay == 0) {
10582 return false;
10583 }
10584 r.resetRestartCounter();
10585 mRestartingServices.remove(r);
10586 mHandler.removeCallbacks(r.restarter);
10587 return true;
10588 }
10589
10590 private final boolean bringUpServiceLocked(ServiceRecord r,
10591 int intentFlags, boolean whileRestarting) {
10592 //Log.i(TAG, "Bring up service:");
10593 //r.dump(" ");
10594
Dianne Hackborn36124872009-10-08 16:22:03 -070010595 if (r.app != null && r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010596 sendServiceArgsLocked(r, false);
10597 return true;
10598 }
10599
10600 if (!whileRestarting && r.restartDelay > 0) {
10601 // If waiting for a restart, then do nothing.
10602 return true;
10603 }
10604
10605 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10606 + " " + r.intent);
10607
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010608 // We are now bringing the service up, so no longer in the
10609 // restarting state.
10610 mRestartingServices.remove(r);
10611
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010612 final String appName = r.processName;
10613 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10614 if (app != null && app.thread != null) {
10615 try {
10616 realStartServiceLocked(r, app);
10617 return true;
10618 } catch (RemoteException e) {
10619 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10620 }
10621
10622 // If a dead object exception was thrown -- fall through to
10623 // restart the application.
10624 }
10625
Dianne Hackborn36124872009-10-08 16:22:03 -070010626 // Not running -- get it started, and enqueue this service record
10627 // to be executed when the app comes up.
10628 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
10629 "service", r.name, false) == null) {
10630 Log.w(TAG, "Unable to launch app "
10631 + r.appInfo.packageName + "/"
10632 + r.appInfo.uid + " for service "
10633 + r.intent.getIntent() + ": process is bad");
10634 bringDownServiceLocked(r, true);
10635 return false;
10636 }
10637
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010638 if (!mPendingServices.contains(r)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010639 mPendingServices.add(r);
10640 }
Dianne Hackborn36124872009-10-08 16:22:03 -070010641
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010642 return true;
10643 }
10644
10645 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10646 //Log.i(TAG, "Bring down service:");
10647 //r.dump(" ");
10648
10649 // Does it still need to run?
10650 if (!force && r.startRequested) {
10651 return;
10652 }
10653 if (r.connections.size() > 0) {
10654 if (!force) {
10655 // XXX should probably keep a count of the number of auto-create
10656 // connections directly in the service.
10657 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10658 while (it.hasNext()) {
10659 ConnectionRecord cr = it.next();
10660 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10661 return;
10662 }
10663 }
10664 }
10665
10666 // Report to all of the connections that the service is no longer
10667 // available.
10668 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10669 while (it.hasNext()) {
10670 ConnectionRecord c = it.next();
10671 try {
10672 // todo: shouldn't be a synchronous call!
10673 c.conn.connected(r.name, null);
10674 } catch (Exception e) {
10675 Log.w(TAG, "Failure disconnecting service " + r.name +
10676 " to connection " + c.conn.asBinder() +
10677 " (in " + c.binding.client.processName + ")", e);
10678 }
10679 }
10680 }
10681
10682 // Tell the service that it has been unbound.
10683 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10684 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10685 while (it.hasNext()) {
10686 IntentBindRecord ibr = it.next();
10687 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10688 + ": hasBound=" + ibr.hasBound);
10689 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10690 try {
10691 bumpServiceExecutingLocked(r);
10692 updateOomAdjLocked(r.app);
10693 ibr.hasBound = false;
10694 r.app.thread.scheduleUnbindService(r,
10695 ibr.intent.getIntent());
10696 } catch (Exception e) {
10697 Log.w(TAG, "Exception when unbinding service "
10698 + r.shortName, e);
10699 serviceDoneExecutingLocked(r, true);
10700 }
10701 }
10702 }
10703 }
10704
10705 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10706 + " " + r.intent);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010707 EventLog.writeEvent(EventLogTags.AM_DESTROY_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010708 System.identityHashCode(r), r.shortName,
10709 (r.app != null) ? r.app.pid : -1);
10710
10711 mServices.remove(r.name);
10712 mServicesByIntent.remove(r.intent);
10713 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10714 r.totalRestartCount = 0;
10715 unscheduleServiceRestartLocked(r);
10716
10717 // Also make sure it is not on the pending list.
10718 int N = mPendingServices.size();
10719 for (int i=0; i<N; i++) {
10720 if (mPendingServices.get(i) == r) {
10721 mPendingServices.remove(i);
10722 if (DEBUG_SERVICE) Log.v(
10723 TAG, "Removed pending service: " + r.shortName);
10724 i--;
10725 N--;
10726 }
10727 }
10728
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010729 r.cancelNotification();
10730 r.isForeground = false;
10731 r.foregroundId = 0;
10732 r.foregroundNoti = null;
10733
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010734 // Clear start entries.
10735 r.deliveredStarts.clear();
10736 r.pendingStarts.clear();
10737
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010738 if (r.app != null) {
10739 synchronized (r.stats.getBatteryStats()) {
10740 r.stats.stopLaunchedLocked();
10741 }
10742 r.app.services.remove(r);
10743 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010744 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010745 if (DEBUG_SERVICE) Log.v(TAG,
10746 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010747 bumpServiceExecutingLocked(r);
10748 mStoppingServices.add(r);
10749 updateOomAdjLocked(r.app);
10750 r.app.thread.scheduleStopService(r);
10751 } catch (Exception e) {
10752 Log.w(TAG, "Exception when stopping service "
10753 + r.shortName, e);
10754 serviceDoneExecutingLocked(r, true);
10755 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010756 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010757 } else {
10758 if (DEBUG_SERVICE) Log.v(
10759 TAG, "Removed service that has no process: " + r.shortName);
10760 }
10761 } else {
10762 if (DEBUG_SERVICE) Log.v(
10763 TAG, "Removed service that is not running: " + r.shortName);
10764 }
10765 }
10766
10767 ComponentName startServiceLocked(IApplicationThread caller,
10768 Intent service, String resolvedType,
10769 int callingPid, int callingUid) {
10770 synchronized(this) {
10771 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10772 + " type=" + resolvedType + " args=" + service.getExtras());
10773
10774 if (caller != null) {
10775 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10776 if (callerApp == null) {
10777 throw new SecurityException(
10778 "Unable to find app for caller " + caller
10779 + " (pid=" + Binder.getCallingPid()
10780 + ") when starting service " + service);
10781 }
10782 }
10783
10784 ServiceLookupResult res =
10785 retrieveServiceLocked(service, resolvedType,
10786 callingPid, callingUid);
10787 if (res == null) {
10788 return null;
10789 }
10790 if (res.record == null) {
10791 return new ComponentName("!", res.permission != null
10792 ? res.permission : "private to package");
10793 }
10794 ServiceRecord r = res.record;
10795 if (unscheduleServiceRestartLocked(r)) {
10796 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10797 + r.shortName);
10798 }
10799 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010800 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010801 r.lastStartId++;
10802 if (r.lastStartId < 1) {
10803 r.lastStartId = 1;
10804 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010805 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010806 r.lastActivity = SystemClock.uptimeMillis();
10807 synchronized (r.stats.getBatteryStats()) {
10808 r.stats.startRunningLocked();
10809 }
10810 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10811 return new ComponentName("!", "Service process is bad");
10812 }
10813 return r.name;
10814 }
10815 }
10816
10817 public ComponentName startService(IApplicationThread caller, Intent service,
10818 String resolvedType) {
10819 // Refuse possible leaked file descriptors
10820 if (service != null && service.hasFileDescriptors() == true) {
10821 throw new IllegalArgumentException("File descriptors passed in Intent");
10822 }
10823
10824 synchronized(this) {
10825 final int callingPid = Binder.getCallingPid();
10826 final int callingUid = Binder.getCallingUid();
10827 final long origId = Binder.clearCallingIdentity();
10828 ComponentName res = startServiceLocked(caller, service,
10829 resolvedType, callingPid, callingUid);
10830 Binder.restoreCallingIdentity(origId);
10831 return res;
10832 }
10833 }
10834
10835 ComponentName startServiceInPackage(int uid,
10836 Intent service, String resolvedType) {
10837 synchronized(this) {
10838 final long origId = Binder.clearCallingIdentity();
10839 ComponentName res = startServiceLocked(null, service,
10840 resolvedType, -1, uid);
10841 Binder.restoreCallingIdentity(origId);
10842 return res;
10843 }
10844 }
10845
10846 public int stopService(IApplicationThread caller, Intent service,
10847 String resolvedType) {
10848 // Refuse possible leaked file descriptors
10849 if (service != null && service.hasFileDescriptors() == true) {
10850 throw new IllegalArgumentException("File descriptors passed in Intent");
10851 }
10852
10853 synchronized(this) {
10854 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10855 + " type=" + resolvedType);
10856
10857 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10858 if (caller != null && callerApp == null) {
10859 throw new SecurityException(
10860 "Unable to find app for caller " + caller
10861 + " (pid=" + Binder.getCallingPid()
10862 + ") when stopping service " + service);
10863 }
10864
10865 // If this service is active, make sure it is stopped.
10866 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10867 if (r != null) {
10868 if (r.record != null) {
10869 synchronized (r.record.stats.getBatteryStats()) {
10870 r.record.stats.stopRunningLocked();
10871 }
10872 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010873 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010874 final long origId = Binder.clearCallingIdentity();
10875 bringDownServiceLocked(r.record, false);
10876 Binder.restoreCallingIdentity(origId);
10877 return 1;
10878 }
10879 return -1;
10880 }
10881 }
10882
10883 return 0;
10884 }
10885
10886 public IBinder peekService(Intent service, String resolvedType) {
10887 // Refuse possible leaked file descriptors
10888 if (service != null && service.hasFileDescriptors() == true) {
10889 throw new IllegalArgumentException("File descriptors passed in Intent");
10890 }
10891
10892 IBinder ret = null;
10893
10894 synchronized(this) {
10895 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10896
10897 if (r != null) {
10898 // r.record is null if findServiceLocked() failed the caller permission check
10899 if (r.record == null) {
10900 throw new SecurityException(
10901 "Permission Denial: Accessing service " + r.record.name
10902 + " from pid=" + Binder.getCallingPid()
10903 + ", uid=" + Binder.getCallingUid()
10904 + " requires " + r.permission);
10905 }
10906 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10907 if (ib != null) {
10908 ret = ib.binder;
10909 }
10910 }
10911 }
10912
10913 return ret;
10914 }
10915
10916 public boolean stopServiceToken(ComponentName className, IBinder token,
10917 int startId) {
10918 synchronized(this) {
10919 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10920 + " " + token + " startId=" + startId);
10921 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010922 if (r != null) {
10923 if (startId >= 0) {
10924 // Asked to only stop if done with all work. Note that
10925 // to avoid leaks, we will take this as dropping all
10926 // start items up to and including this one.
10927 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
10928 if (si != null) {
10929 while (r.deliveredStarts.size() > 0) {
10930 if (r.deliveredStarts.remove(0) == si) {
10931 break;
10932 }
10933 }
10934 }
10935
10936 if (r.lastStartId != startId) {
10937 return false;
10938 }
10939
10940 if (r.deliveredStarts.size() > 0) {
10941 Log.w(TAG, "stopServiceToken startId " + startId
10942 + " is last, but have " + r.deliveredStarts.size()
10943 + " remaining args");
10944 }
10945 }
10946
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010947 synchronized (r.stats.getBatteryStats()) {
10948 r.stats.stopRunningLocked();
10949 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010950 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010951 }
10952 final long origId = Binder.clearCallingIdentity();
10953 bringDownServiceLocked(r, false);
10954 Binder.restoreCallingIdentity(origId);
10955 return true;
10956 }
10957 }
10958 return false;
10959 }
10960
10961 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010962 int id, Notification notification, boolean removeNotification) {
10963 final long origId = Binder.clearCallingIdentity();
10964 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010965 synchronized(this) {
10966 ServiceRecord r = findServiceLocked(className, token);
10967 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010968 if (id != 0) {
10969 if (notification == null) {
10970 throw new IllegalArgumentException("null notification");
10971 }
10972 if (r.foregroundId != id) {
10973 r.cancelNotification();
10974 r.foregroundId = id;
10975 }
10976 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
10977 r.foregroundNoti = notification;
10978 r.isForeground = true;
10979 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010980 if (r.app != null) {
10981 updateServiceForegroundLocked(r.app, true);
10982 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010983 } else {
10984 if (r.isForeground) {
10985 r.isForeground = false;
10986 if (r.app != null) {
10987 updateServiceForegroundLocked(r.app, true);
10988 }
10989 }
10990 if (removeNotification) {
10991 r.cancelNotification();
10992 r.foregroundId = 0;
10993 r.foregroundNoti = null;
10994 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010995 }
10996 }
10997 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010998 } finally {
10999 Binder.restoreCallingIdentity(origId);
11000 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011001 }
11002
11003 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
11004 boolean anyForeground = false;
11005 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
11006 if (sr.isForeground) {
11007 anyForeground = true;
11008 break;
11009 }
11010 }
11011 if (anyForeground != proc.foregroundServices) {
11012 proc.foregroundServices = anyForeground;
11013 if (oomAdj) {
11014 updateOomAdjLocked();
11015 }
11016 }
11017 }
11018
11019 public int bindService(IApplicationThread caller, IBinder token,
11020 Intent service, String resolvedType,
11021 IServiceConnection connection, int flags) {
11022 // Refuse possible leaked file descriptors
11023 if (service != null && service.hasFileDescriptors() == true) {
11024 throw new IllegalArgumentException("File descriptors passed in Intent");
11025 }
11026
11027 synchronized(this) {
11028 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
11029 + " type=" + resolvedType + " conn=" + connection.asBinder()
11030 + " flags=0x" + Integer.toHexString(flags));
11031 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11032 if (callerApp == null) {
11033 throw new SecurityException(
11034 "Unable to find app for caller " + caller
11035 + " (pid=" + Binder.getCallingPid()
11036 + ") when binding service " + service);
11037 }
11038
11039 HistoryRecord activity = null;
11040 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070011041 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011042 if (aindex < 0) {
11043 Log.w(TAG, "Binding with unknown activity: " + token);
11044 return 0;
11045 }
11046 activity = (HistoryRecord)mHistory.get(aindex);
11047 }
11048
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011049 int clientLabel = 0;
11050 PendingIntent clientIntent = null;
11051
11052 if (callerApp.info.uid == Process.SYSTEM_UID) {
11053 // Hacky kind of thing -- allow system stuff to tell us
11054 // what they are, so we can report this elsewhere for
11055 // others to know why certain services are running.
11056 try {
11057 clientIntent = (PendingIntent)service.getParcelableExtra(
11058 Intent.EXTRA_CLIENT_INTENT);
11059 } catch (RuntimeException e) {
11060 }
11061 if (clientIntent != null) {
11062 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
11063 if (clientLabel != 0) {
11064 // There are no useful extras in the intent, trash them.
11065 // System code calling with this stuff just needs to know
11066 // this will happen.
11067 service = service.cloneFilter();
11068 }
11069 }
11070 }
11071
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011072 ServiceLookupResult res =
11073 retrieveServiceLocked(service, resolvedType,
11074 Binder.getCallingPid(), Binder.getCallingUid());
11075 if (res == null) {
11076 return 0;
11077 }
11078 if (res.record == null) {
11079 return -1;
11080 }
11081 ServiceRecord s = res.record;
11082
11083 final long origId = Binder.clearCallingIdentity();
11084
11085 if (unscheduleServiceRestartLocked(s)) {
11086 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
11087 + s.shortName);
11088 }
11089
11090 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
11091 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011092 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011093
11094 IBinder binder = connection.asBinder();
11095 s.connections.put(binder, c);
11096 b.connections.add(c);
11097 if (activity != null) {
11098 if (activity.connections == null) {
11099 activity.connections = new HashSet<ConnectionRecord>();
11100 }
11101 activity.connections.add(c);
11102 }
11103 b.client.connections.add(c);
11104 mServiceConnections.put(binder, c);
11105
11106 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
11107 s.lastActivity = SystemClock.uptimeMillis();
11108 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
11109 return 0;
11110 }
11111 }
11112
11113 if (s.app != null) {
11114 // This could have made the service more important.
11115 updateOomAdjLocked(s.app);
11116 }
11117
11118 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
11119 + ": received=" + b.intent.received
11120 + " apps=" + b.intent.apps.size()
11121 + " doRebind=" + b.intent.doRebind);
11122
11123 if (s.app != null && b.intent.received) {
11124 // Service is already running, so we can immediately
11125 // publish the connection.
11126 try {
11127 c.conn.connected(s.name, b.intent.binder);
11128 } catch (Exception e) {
11129 Log.w(TAG, "Failure sending service " + s.shortName
11130 + " to connection " + c.conn.asBinder()
11131 + " (in " + c.binding.client.processName + ")", e);
11132 }
11133
11134 // If this is the first app connected back to this binding,
11135 // and the service had previously asked to be told when
11136 // rebound, then do so.
11137 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
11138 requestServiceBindingLocked(s, b.intent, true);
11139 }
11140 } else if (!b.intent.requested) {
11141 requestServiceBindingLocked(s, b.intent, false);
11142 }
11143
11144 Binder.restoreCallingIdentity(origId);
11145 }
11146
11147 return 1;
11148 }
11149
11150 private void removeConnectionLocked(
11151 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
11152 IBinder binder = c.conn.asBinder();
11153 AppBindRecord b = c.binding;
11154 ServiceRecord s = b.service;
11155 s.connections.remove(binder);
11156 b.connections.remove(c);
11157 if (c.activity != null && c.activity != skipAct) {
11158 if (c.activity.connections != null) {
11159 c.activity.connections.remove(c);
11160 }
11161 }
11162 if (b.client != skipApp) {
11163 b.client.connections.remove(c);
11164 }
11165 mServiceConnections.remove(binder);
11166
11167 if (b.connections.size() == 0) {
11168 b.intent.apps.remove(b.client);
11169 }
11170
11171 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
11172 + ": shouldUnbind=" + b.intent.hasBound);
11173 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
11174 && b.intent.hasBound) {
11175 try {
11176 bumpServiceExecutingLocked(s);
11177 updateOomAdjLocked(s.app);
11178 b.intent.hasBound = false;
11179 // Assume the client doesn't want to know about a rebind;
11180 // we will deal with that later if it asks for one.
11181 b.intent.doRebind = false;
11182 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
11183 } catch (Exception e) {
11184 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
11185 serviceDoneExecutingLocked(s, true);
11186 }
11187 }
11188
11189 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
11190 bringDownServiceLocked(s, false);
11191 }
11192 }
11193
11194 public boolean unbindService(IServiceConnection connection) {
11195 synchronized (this) {
11196 IBinder binder = connection.asBinder();
11197 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11198 ConnectionRecord r = mServiceConnections.get(binder);
11199 if (r == null) {
11200 Log.w(TAG, "Unbind failed: could not find connection for "
11201 + connection.asBinder());
11202 return false;
11203 }
11204
11205 final long origId = Binder.clearCallingIdentity();
11206
11207 removeConnectionLocked(r, null, null);
11208
11209 if (r.binding.service.app != null) {
11210 // This could have made the service less important.
11211 updateOomAdjLocked(r.binding.service.app);
11212 }
11213
11214 Binder.restoreCallingIdentity(origId);
11215 }
11216
11217 return true;
11218 }
11219
11220 public void publishService(IBinder token, Intent intent, IBinder service) {
11221 // Refuse possible leaked file descriptors
11222 if (intent != null && intent.hasFileDescriptors() == true) {
11223 throw new IllegalArgumentException("File descriptors passed in Intent");
11224 }
11225
11226 synchronized(this) {
11227 if (!(token instanceof ServiceRecord)) {
11228 throw new IllegalArgumentException("Invalid service token");
11229 }
11230 ServiceRecord r = (ServiceRecord)token;
11231
11232 final long origId = Binder.clearCallingIdentity();
11233
11234 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11235 + " " + intent + ": " + service);
11236 if (r != null) {
11237 Intent.FilterComparison filter
11238 = new Intent.FilterComparison(intent);
11239 IntentBindRecord b = r.bindings.get(filter);
11240 if (b != null && !b.received) {
11241 b.binder = service;
11242 b.requested = true;
11243 b.received = true;
11244 if (r.connections.size() > 0) {
11245 Iterator<ConnectionRecord> it
11246 = r.connections.values().iterator();
11247 while (it.hasNext()) {
11248 ConnectionRecord c = it.next();
11249 if (!filter.equals(c.binding.intent.intent)) {
11250 if (DEBUG_SERVICE) Log.v(
11251 TAG, "Not publishing to: " + c);
11252 if (DEBUG_SERVICE) Log.v(
11253 TAG, "Bound intent: " + c.binding.intent.intent);
11254 if (DEBUG_SERVICE) Log.v(
11255 TAG, "Published intent: " + intent);
11256 continue;
11257 }
11258 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11259 try {
11260 c.conn.connected(r.name, service);
11261 } catch (Exception e) {
11262 Log.w(TAG, "Failure sending service " + r.name +
11263 " to connection " + c.conn.asBinder() +
11264 " (in " + c.binding.client.processName + ")", e);
11265 }
11266 }
11267 }
11268 }
11269
11270 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11271
11272 Binder.restoreCallingIdentity(origId);
11273 }
11274 }
11275 }
11276
11277 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11278 // Refuse possible leaked file descriptors
11279 if (intent != null && intent.hasFileDescriptors() == true) {
11280 throw new IllegalArgumentException("File descriptors passed in Intent");
11281 }
11282
11283 synchronized(this) {
11284 if (!(token instanceof ServiceRecord)) {
11285 throw new IllegalArgumentException("Invalid service token");
11286 }
11287 ServiceRecord r = (ServiceRecord)token;
11288
11289 final long origId = Binder.clearCallingIdentity();
11290
11291 if (r != null) {
11292 Intent.FilterComparison filter
11293 = new Intent.FilterComparison(intent);
11294 IntentBindRecord b = r.bindings.get(filter);
11295 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11296 + " at " + b + ": apps="
11297 + (b != null ? b.apps.size() : 0));
11298 if (b != null) {
11299 if (b.apps.size() > 0) {
11300 // Applications have already bound since the last
11301 // unbind, so just rebind right here.
11302 requestServiceBindingLocked(r, b, true);
11303 } else {
11304 // Note to tell the service the next time there is
11305 // a new client.
11306 b.doRebind = true;
11307 }
11308 }
11309
11310 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11311
11312 Binder.restoreCallingIdentity(origId);
11313 }
11314 }
11315 }
11316
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011317 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011318 synchronized(this) {
11319 if (!(token instanceof ServiceRecord)) {
11320 throw new IllegalArgumentException("Invalid service token");
11321 }
11322 ServiceRecord r = (ServiceRecord)token;
11323 boolean inStopping = mStoppingServices.contains(token);
11324 if (r != null) {
11325 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11326 + ": nesting=" + r.executeNesting
11327 + ", inStopping=" + inStopping);
11328 if (r != token) {
11329 Log.w(TAG, "Done executing service " + r.name
11330 + " with incorrect token: given " + token
11331 + ", expected " + r);
11332 return;
11333 }
11334
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011335 if (type == 1) {
11336 // This is a call from a service start... take care of
11337 // book-keeping.
11338 r.callStart = true;
11339 switch (res) {
11340 case Service.START_STICKY_COMPATIBILITY:
11341 case Service.START_STICKY: {
11342 // We are done with the associated start arguments.
11343 r.findDeliveredStart(startId, true);
11344 // Don't stop if killed.
11345 r.stopIfKilled = false;
11346 break;
11347 }
11348 case Service.START_NOT_STICKY: {
11349 // We are done with the associated start arguments.
11350 r.findDeliveredStart(startId, true);
11351 if (r.lastStartId == startId) {
11352 // There is no more work, and this service
11353 // doesn't want to hang around if killed.
11354 r.stopIfKilled = true;
11355 }
11356 break;
11357 }
11358 case Service.START_REDELIVER_INTENT: {
11359 // We'll keep this item until they explicitly
11360 // call stop for it, but keep track of the fact
11361 // that it was delivered.
11362 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11363 if (si != null) {
11364 si.deliveryCount = 0;
11365 si.doneExecutingCount++;
11366 // Don't stop if killed.
11367 r.stopIfKilled = true;
11368 }
11369 break;
11370 }
11371 default:
11372 throw new IllegalArgumentException(
11373 "Unknown service start result: " + res);
11374 }
11375 if (res == Service.START_STICKY_COMPATIBILITY) {
11376 r.callStart = false;
11377 }
11378 }
11379
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011380 final long origId = Binder.clearCallingIdentity();
11381 serviceDoneExecutingLocked(r, inStopping);
11382 Binder.restoreCallingIdentity(origId);
11383 } else {
11384 Log.w(TAG, "Done executing unknown service " + r.name
11385 + " with token " + token);
11386 }
11387 }
11388 }
11389
11390 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11391 r.executeNesting--;
11392 if (r.executeNesting <= 0 && r.app != null) {
11393 r.app.executingServices.remove(r);
11394 if (r.app.executingServices.size() == 0) {
11395 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11396 }
11397 if (inStopping) {
11398 mStoppingServices.remove(r);
11399 }
11400 updateOomAdjLocked(r.app);
11401 }
11402 }
11403
11404 void serviceTimeout(ProcessRecord proc) {
11405 synchronized(this) {
11406 if (proc.executingServices.size() == 0 || proc.thread == null) {
11407 return;
11408 }
11409 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11410 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11411 ServiceRecord timeout = null;
11412 long nextTime = 0;
11413 while (it.hasNext()) {
11414 ServiceRecord sr = it.next();
11415 if (sr.executingStart < maxTime) {
11416 timeout = sr;
11417 break;
11418 }
11419 if (sr.executingStart > nextTime) {
11420 nextTime = sr.executingStart;
11421 }
11422 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -080011423 if (timeout != null && mLruProcesses.contains(proc)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011424 Log.w(TAG, "Timeout executing service: " + timeout);
Dan Egnorb7f03672009-12-09 16:22:32 -080011425 appNotRespondingLocked(proc, null, null, "Executing service " + timeout.name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011426 } else {
11427 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11428 msg.obj = proc;
11429 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11430 }
11431 }
11432 }
11433
11434 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011435 // BACKUP AND RESTORE
11436 // =========================================================
11437
11438 // Cause the target app to be launched if necessary and its backup agent
11439 // instantiated. The backup agent will invoke backupAgentCreated() on the
11440 // activity manager to announce its creation.
11441 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11442 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11443 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11444
11445 synchronized(this) {
11446 // !!! TODO: currently no check here that we're already bound
11447 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11448 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11449 synchronized (stats) {
11450 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11451 }
11452
11453 BackupRecord r = new BackupRecord(ss, app, backupMode);
11454 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11455 // startProcessLocked() returns existing proc's record if it's already running
11456 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011457 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011458 if (proc == null) {
11459 Log.e(TAG, "Unable to start backup agent process " + r);
11460 return false;
11461 }
11462
11463 r.app = proc;
11464 mBackupTarget = r;
11465 mBackupAppName = app.packageName;
11466
Christopher Tate6fa95972009-06-05 18:43:55 -070011467 // Try not to kill the process during backup
11468 updateOomAdjLocked(proc);
11469
Christopher Tate181fafa2009-05-14 11:12:14 -070011470 // If the process is already attached, schedule the creation of the backup agent now.
11471 // If it is not yet live, this will be done when it attaches to the framework.
11472 if (proc.thread != null) {
11473 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11474 try {
11475 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11476 } catch (RemoteException e) {
Christopher Tate436344a2009-09-30 16:17:37 -070011477 // Will time out on the backup manager side
Christopher Tate181fafa2009-05-14 11:12:14 -070011478 }
11479 } else {
11480 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11481 }
11482 // Invariants: at this point, the target app process exists and the application
11483 // is either already running or in the process of coming up. mBackupTarget and
11484 // mBackupAppName describe the app, so that when it binds back to the AM we
11485 // know that it's scheduled for a backup-agent operation.
11486 }
11487
11488 return true;
11489 }
11490
11491 // A backup agent has just come up
11492 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11493 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11494 + " = " + agent);
11495
11496 synchronized(this) {
11497 if (!agentPackageName.equals(mBackupAppName)) {
11498 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11499 return;
11500 }
11501
Christopher Tate043dadc2009-06-02 16:11:00 -070011502 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011503 try {
11504 IBackupManager bm = IBackupManager.Stub.asInterface(
11505 ServiceManager.getService(Context.BACKUP_SERVICE));
11506 bm.agentConnected(agentPackageName, agent);
11507 } catch (RemoteException e) {
11508 // can't happen; the backup manager service is local
11509 } catch (Exception e) {
11510 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11511 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011512 } finally {
11513 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011514 }
11515 }
11516 }
11517
11518 // done with this agent
11519 public void unbindBackupAgent(ApplicationInfo appInfo) {
11520 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011521 if (appInfo == null) {
11522 Log.w(TAG, "unbind backup agent for null app");
11523 return;
11524 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011525
11526 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011527 if (mBackupAppName == null) {
11528 Log.w(TAG, "Unbinding backup agent with no active backup");
11529 return;
11530 }
11531
Christopher Tate181fafa2009-05-14 11:12:14 -070011532 if (!mBackupAppName.equals(appInfo.packageName)) {
11533 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11534 return;
11535 }
11536
Christopher Tate6fa95972009-06-05 18:43:55 -070011537 ProcessRecord proc = mBackupTarget.app;
11538 mBackupTarget = null;
11539 mBackupAppName = null;
11540
11541 // Not backing this app up any more; reset its OOM adjustment
11542 updateOomAdjLocked(proc);
11543
Christopher Tatec7b31e32009-06-10 15:49:30 -070011544 // If the app crashed during backup, 'thread' will be null here
11545 if (proc.thread != null) {
11546 try {
11547 proc.thread.scheduleDestroyBackupAgent(appInfo);
11548 } catch (Exception e) {
11549 Log.e(TAG, "Exception when unbinding backup agent:");
11550 e.printStackTrace();
11551 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011552 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011553 }
11554 }
11555 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011556 // BROADCASTS
11557 // =========================================================
11558
11559 private final List getStickies(String action, IntentFilter filter,
11560 List cur) {
11561 final ContentResolver resolver = mContext.getContentResolver();
11562 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11563 if (list == null) {
11564 return cur;
11565 }
11566 int N = list.size();
11567 for (int i=0; i<N; i++) {
11568 Intent intent = list.get(i);
11569 if (filter.match(resolver, intent, true, TAG) >= 0) {
11570 if (cur == null) {
11571 cur = new ArrayList<Intent>();
11572 }
11573 cur.add(intent);
11574 }
11575 }
11576 return cur;
11577 }
11578
11579 private final void scheduleBroadcastsLocked() {
11580 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11581 + mBroadcastsScheduled);
11582
11583 if (mBroadcastsScheduled) {
11584 return;
11585 }
11586 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11587 mBroadcastsScheduled = true;
11588 }
11589
11590 public Intent registerReceiver(IApplicationThread caller,
11591 IIntentReceiver receiver, IntentFilter filter, String permission) {
11592 synchronized(this) {
11593 ProcessRecord callerApp = null;
11594 if (caller != null) {
11595 callerApp = getRecordForAppLocked(caller);
11596 if (callerApp == null) {
11597 throw new SecurityException(
11598 "Unable to find app for caller " + caller
11599 + " (pid=" + Binder.getCallingPid()
11600 + ") when registering receiver " + receiver);
11601 }
11602 }
11603
11604 List allSticky = null;
11605
11606 // Look for any matching sticky broadcasts...
11607 Iterator actions = filter.actionsIterator();
11608 if (actions != null) {
11609 while (actions.hasNext()) {
11610 String action = (String)actions.next();
11611 allSticky = getStickies(action, filter, allSticky);
11612 }
11613 } else {
11614 allSticky = getStickies(null, filter, allSticky);
11615 }
11616
11617 // The first sticky in the list is returned directly back to
11618 // the client.
11619 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11620
11621 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11622 + ": " + sticky);
11623
11624 if (receiver == null) {
11625 return sticky;
11626 }
11627
11628 ReceiverList rl
11629 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11630 if (rl == null) {
11631 rl = new ReceiverList(this, callerApp,
11632 Binder.getCallingPid(),
11633 Binder.getCallingUid(), receiver);
11634 if (rl.app != null) {
11635 rl.app.receivers.add(rl);
11636 } else {
11637 try {
11638 receiver.asBinder().linkToDeath(rl, 0);
11639 } catch (RemoteException e) {
11640 return sticky;
11641 }
11642 rl.linkedToDeath = true;
11643 }
11644 mRegisteredReceivers.put(receiver.asBinder(), rl);
11645 }
11646 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11647 rl.add(bf);
11648 if (!bf.debugCheck()) {
11649 Log.w(TAG, "==> For Dynamic broadast");
11650 }
11651 mReceiverResolver.addFilter(bf);
11652
11653 // Enqueue broadcasts for all existing stickies that match
11654 // this filter.
11655 if (allSticky != null) {
11656 ArrayList receivers = new ArrayList();
11657 receivers.add(bf);
11658
11659 int N = allSticky.size();
11660 for (int i=0; i<N; i++) {
11661 Intent intent = (Intent)allSticky.get(i);
11662 BroadcastRecord r = new BroadcastRecord(intent, null,
11663 null, -1, -1, null, receivers, null, 0, null, null,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011664 false, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011665 if (mParallelBroadcasts.size() == 0) {
11666 scheduleBroadcastsLocked();
11667 }
11668 mParallelBroadcasts.add(r);
11669 }
11670 }
11671
11672 return sticky;
11673 }
11674 }
11675
11676 public void unregisterReceiver(IIntentReceiver receiver) {
11677 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11678
11679 boolean doNext = false;
11680
11681 synchronized(this) {
11682 ReceiverList rl
11683 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11684 if (rl != null) {
11685 if (rl.curBroadcast != null) {
11686 BroadcastRecord r = rl.curBroadcast;
11687 doNext = finishReceiverLocked(
11688 receiver.asBinder(), r.resultCode, r.resultData,
11689 r.resultExtras, r.resultAbort, true);
11690 }
11691
11692 if (rl.app != null) {
11693 rl.app.receivers.remove(rl);
11694 }
11695 removeReceiverLocked(rl);
11696 if (rl.linkedToDeath) {
11697 rl.linkedToDeath = false;
11698 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11699 }
11700 }
11701 }
11702
11703 if (!doNext) {
11704 return;
11705 }
11706
11707 final long origId = Binder.clearCallingIdentity();
11708 processNextBroadcast(false);
11709 trimApplications();
11710 Binder.restoreCallingIdentity(origId);
11711 }
11712
11713 void removeReceiverLocked(ReceiverList rl) {
11714 mRegisteredReceivers.remove(rl.receiver.asBinder());
11715 int N = rl.size();
11716 for (int i=0; i<N; i++) {
11717 mReceiverResolver.removeFilter(rl.get(i));
11718 }
11719 }
11720
11721 private final int broadcastIntentLocked(ProcessRecord callerApp,
11722 String callerPackage, Intent intent, String resolvedType,
11723 IIntentReceiver resultTo, int resultCode, String resultData,
11724 Bundle map, String requiredPermission,
11725 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11726 intent = new Intent(intent);
11727
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011728 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011729 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11730 + " ordered=" + ordered);
11731 if ((resultTo != null) && !ordered) {
11732 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11733 }
11734
11735 // Handle special intents: if this broadcast is from the package
11736 // manager about a package being removed, we need to remove all of
11737 // its activities from the history stack.
11738 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11739 intent.getAction());
11740 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11741 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11742 || uidRemoved) {
11743 if (checkComponentPermission(
11744 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11745 callingPid, callingUid, -1)
11746 == PackageManager.PERMISSION_GRANTED) {
11747 if (uidRemoved) {
11748 final Bundle intentExtras = intent.getExtras();
11749 final int uid = intentExtras != null
11750 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11751 if (uid >= 0) {
11752 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11753 synchronized (bs) {
11754 bs.removeUidStatsLocked(uid);
11755 }
11756 }
11757 } else {
11758 Uri data = intent.getData();
11759 String ssp;
11760 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11761 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11762 uninstallPackageLocked(ssp,
11763 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011764 AttributeCache ac = AttributeCache.instance();
11765 if (ac != null) {
11766 ac.removePackage(ssp);
11767 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011768 }
11769 }
11770 }
11771 } else {
11772 String msg = "Permission Denial: " + intent.getAction()
11773 + " broadcast from " + callerPackage + " (pid=" + callingPid
11774 + ", uid=" + callingUid + ")"
11775 + " requires "
11776 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11777 Log.w(TAG, msg);
11778 throw new SecurityException(msg);
11779 }
11780 }
11781
11782 /*
11783 * If this is the time zone changed action, queue up a message that will reset the timezone
11784 * of all currently running processes. This message will get queued up before the broadcast
11785 * happens.
11786 */
11787 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11788 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11789 }
11790
Dianne Hackborn854060af2009-07-09 18:14:31 -070011791 /*
11792 * Prevent non-system code (defined here to be non-persistent
11793 * processes) from sending protected broadcasts.
11794 */
11795 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11796 || callingUid == Process.SHELL_UID || callingUid == 0) {
11797 // Always okay.
11798 } else if (callerApp == null || !callerApp.persistent) {
11799 try {
11800 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11801 intent.getAction())) {
11802 String msg = "Permission Denial: not allowed to send broadcast "
11803 + intent.getAction() + " from pid="
11804 + callingPid + ", uid=" + callingUid;
11805 Log.w(TAG, msg);
11806 throw new SecurityException(msg);
11807 }
11808 } catch (RemoteException e) {
11809 Log.w(TAG, "Remote exception", e);
11810 return BROADCAST_SUCCESS;
11811 }
11812 }
11813
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011814 // Add to the sticky list if requested.
11815 if (sticky) {
11816 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11817 callingPid, callingUid)
11818 != PackageManager.PERMISSION_GRANTED) {
11819 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11820 + callingPid + ", uid=" + callingUid
11821 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11822 Log.w(TAG, msg);
11823 throw new SecurityException(msg);
11824 }
11825 if (requiredPermission != null) {
11826 Log.w(TAG, "Can't broadcast sticky intent " + intent
11827 + " and enforce permission " + requiredPermission);
11828 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11829 }
11830 if (intent.getComponent() != null) {
11831 throw new SecurityException(
11832 "Sticky broadcasts can't target a specific component");
11833 }
11834 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11835 if (list == null) {
11836 list = new ArrayList<Intent>();
11837 mStickyBroadcasts.put(intent.getAction(), list);
11838 }
11839 int N = list.size();
11840 int i;
11841 for (i=0; i<N; i++) {
11842 if (intent.filterEquals(list.get(i))) {
11843 // This sticky already exists, replace it.
11844 list.set(i, new Intent(intent));
11845 break;
11846 }
11847 }
11848 if (i >= N) {
11849 list.add(new Intent(intent));
11850 }
11851 }
11852
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011853 // Figure out who all will receive this broadcast.
11854 List receivers = null;
11855 List<BroadcastFilter> registeredReceivers = null;
11856 try {
11857 if (intent.getComponent() != null) {
11858 // Broadcast is going to one specific receiver class...
11859 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011860 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011861 if (ai != null) {
11862 receivers = new ArrayList();
11863 ResolveInfo ri = new ResolveInfo();
11864 ri.activityInfo = ai;
11865 receivers.add(ri);
11866 }
11867 } else {
11868 // Need to resolve the intent to interested receivers...
11869 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11870 == 0) {
11871 receivers =
11872 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011873 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011874 }
Mihai Preda074edef2009-05-18 17:13:31 +020011875 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011876 }
11877 } catch (RemoteException ex) {
11878 // pm is in same process, this will never happen.
11879 }
11880
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080011881 final boolean replacePending =
11882 (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
11883
11884 if (DEBUG_BROADCAST) Log.v(TAG, "Enqueing broadcast: " + intent.getAction()
11885 + " replacePending=" + replacePending);
11886
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011887 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11888 if (!ordered && NR > 0) {
11889 // If we are not serializing this broadcast, then send the
11890 // registered receivers separately so they don't wait for the
11891 // components to be launched.
11892 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11893 callerPackage, callingPid, callingUid, requiredPermission,
11894 registeredReceivers, resultTo, resultCode, resultData, map,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011895 ordered, sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011896 if (DEBUG_BROADCAST) Log.v(
11897 TAG, "Enqueueing parallel broadcast " + r
11898 + ": prev had " + mParallelBroadcasts.size());
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080011899 boolean replaced = false;
11900 if (replacePending) {
11901 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
11902 if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
11903 if (DEBUG_BROADCAST) Log.v(TAG,
11904 "***** DROPPING PARALLEL: " + intent);
11905 mParallelBroadcasts.set(i, r);
11906 replaced = true;
11907 break;
11908 }
11909 }
11910 }
11911 if (!replaced) {
11912 mParallelBroadcasts.add(r);
11913 scheduleBroadcastsLocked();
11914 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011915 registeredReceivers = null;
11916 NR = 0;
11917 }
11918
11919 // Merge into one list.
11920 int ir = 0;
11921 if (receivers != null) {
11922 // A special case for PACKAGE_ADDED: do not allow the package
11923 // being added to see this broadcast. This prevents them from
11924 // using this as a back door to get run as soon as they are
11925 // installed. Maybe in the future we want to have a special install
11926 // broadcast or such for apps, but we'd like to deliberately make
11927 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011928 boolean skip = false;
11929 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011930 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011931 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11932 skip = true;
11933 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11934 skip = true;
11935 }
11936 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011937 ? intent.getData().getSchemeSpecificPart()
11938 : null;
11939 if (skipPackage != null && receivers != null) {
11940 int NT = receivers.size();
11941 for (int it=0; it<NT; it++) {
11942 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11943 if (curt.activityInfo.packageName.equals(skipPackage)) {
11944 receivers.remove(it);
11945 it--;
11946 NT--;
11947 }
11948 }
11949 }
11950
11951 int NT = receivers != null ? receivers.size() : 0;
11952 int it = 0;
11953 ResolveInfo curt = null;
11954 BroadcastFilter curr = null;
11955 while (it < NT && ir < NR) {
11956 if (curt == null) {
11957 curt = (ResolveInfo)receivers.get(it);
11958 }
11959 if (curr == null) {
11960 curr = registeredReceivers.get(ir);
11961 }
11962 if (curr.getPriority() >= curt.priority) {
11963 // Insert this broadcast record into the final list.
11964 receivers.add(it, curr);
11965 ir++;
11966 curr = null;
11967 it++;
11968 NT++;
11969 } else {
11970 // Skip to the next ResolveInfo in the final list.
11971 it++;
11972 curt = null;
11973 }
11974 }
11975 }
11976 while (ir < NR) {
11977 if (receivers == null) {
11978 receivers = new ArrayList();
11979 }
11980 receivers.add(registeredReceivers.get(ir));
11981 ir++;
11982 }
11983
11984 if ((receivers != null && receivers.size() > 0)
11985 || resultTo != null) {
11986 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11987 callerPackage, callingPid, callingUid, requiredPermission,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011988 receivers, resultTo, resultCode, resultData, map, ordered,
11989 sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011990 if (DEBUG_BROADCAST) Log.v(
11991 TAG, "Enqueueing ordered broadcast " + r
11992 + ": prev had " + mOrderedBroadcasts.size());
11993 if (DEBUG_BROADCAST) {
11994 int seq = r.intent.getIntExtra("seq", -1);
11995 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11996 }
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080011997 boolean replaced = false;
11998 if (replacePending) {
11999 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
12000 if (intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
12001 if (DEBUG_BROADCAST) Log.v(TAG,
12002 "***** DROPPING ORDERED: " + intent);
12003 mOrderedBroadcasts.set(i, r);
12004 replaced = true;
12005 break;
12006 }
12007 }
12008 }
12009 if (!replaced) {
12010 mOrderedBroadcasts.add(r);
12011 scheduleBroadcastsLocked();
12012 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012013 }
12014
12015 return BROADCAST_SUCCESS;
12016 }
12017
12018 public final int broadcastIntent(IApplicationThread caller,
12019 Intent intent, String resolvedType, IIntentReceiver resultTo,
12020 int resultCode, String resultData, Bundle map,
12021 String requiredPermission, boolean serialized, boolean sticky) {
12022 // Refuse possible leaked file descriptors
12023 if (intent != null && intent.hasFileDescriptors() == true) {
12024 throw new IllegalArgumentException("File descriptors passed in Intent");
12025 }
12026
12027 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012028 int flags = intent.getFlags();
12029
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012030 if (!mSystemReady) {
12031 // if the caller really truly claims to know what they're doing, go
12032 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012033 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
12034 intent = new Intent(intent);
12035 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
12036 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
12037 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
12038 + " before boot completion");
12039 throw new IllegalStateException("Cannot broadcast before boot completed");
12040 }
12041 }
12042
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012043 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
12044 throw new IllegalArgumentException(
12045 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
12046 }
12047
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012048 final ProcessRecord callerApp = getRecordForAppLocked(caller);
12049 final int callingPid = Binder.getCallingPid();
12050 final int callingUid = Binder.getCallingUid();
12051 final long origId = Binder.clearCallingIdentity();
12052 int res = broadcastIntentLocked(callerApp,
12053 callerApp != null ? callerApp.info.packageName : null,
12054 intent, resolvedType, resultTo,
12055 resultCode, resultData, map, requiredPermission, serialized,
12056 sticky, callingPid, callingUid);
12057 Binder.restoreCallingIdentity(origId);
12058 return res;
12059 }
12060 }
12061
12062 int broadcastIntentInPackage(String packageName, int uid,
12063 Intent intent, String resolvedType, IIntentReceiver resultTo,
12064 int resultCode, String resultData, Bundle map,
12065 String requiredPermission, boolean serialized, boolean sticky) {
12066 synchronized(this) {
12067 final long origId = Binder.clearCallingIdentity();
12068 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
12069 resultTo, resultCode, resultData, map, requiredPermission,
12070 serialized, sticky, -1, uid);
12071 Binder.restoreCallingIdentity(origId);
12072 return res;
12073 }
12074 }
12075
12076 public final void unbroadcastIntent(IApplicationThread caller,
12077 Intent intent) {
12078 // Refuse possible leaked file descriptors
12079 if (intent != null && intent.hasFileDescriptors() == true) {
12080 throw new IllegalArgumentException("File descriptors passed in Intent");
12081 }
12082
12083 synchronized(this) {
12084 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
12085 != PackageManager.PERMISSION_GRANTED) {
12086 String msg = "Permission Denial: unbroadcastIntent() from pid="
12087 + Binder.getCallingPid()
12088 + ", uid=" + Binder.getCallingUid()
12089 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
12090 Log.w(TAG, msg);
12091 throw new SecurityException(msg);
12092 }
12093 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12094 if (list != null) {
12095 int N = list.size();
12096 int i;
12097 for (i=0; i<N; i++) {
12098 if (intent.filterEquals(list.get(i))) {
12099 list.remove(i);
12100 break;
12101 }
12102 }
12103 }
12104 }
12105 }
12106
12107 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
12108 String resultData, Bundle resultExtras, boolean resultAbort,
12109 boolean explicit) {
12110 if (mOrderedBroadcasts.size() == 0) {
12111 if (explicit) {
12112 Log.w(TAG, "finishReceiver called but no pending broadcasts");
12113 }
12114 return false;
12115 }
12116 BroadcastRecord r = mOrderedBroadcasts.get(0);
12117 if (r.receiver == null) {
12118 if (explicit) {
12119 Log.w(TAG, "finishReceiver called but none active");
12120 }
12121 return false;
12122 }
12123 if (r.receiver != receiver) {
12124 Log.w(TAG, "finishReceiver called but active receiver is different");
12125 return false;
12126 }
12127 int state = r.state;
12128 r.state = r.IDLE;
12129 if (state == r.IDLE) {
12130 if (explicit) {
12131 Log.w(TAG, "finishReceiver called but state is IDLE");
12132 }
12133 }
12134 r.receiver = null;
12135 r.intent.setComponent(null);
12136 if (r.curApp != null) {
12137 r.curApp.curReceiver = null;
12138 }
12139 if (r.curFilter != null) {
12140 r.curFilter.receiverList.curBroadcast = null;
12141 }
12142 r.curFilter = null;
12143 r.curApp = null;
12144 r.curComponent = null;
12145 r.curReceiver = null;
12146 mPendingBroadcast = null;
12147
12148 r.resultCode = resultCode;
12149 r.resultData = resultData;
12150 r.resultExtras = resultExtras;
12151 r.resultAbort = resultAbort;
12152
12153 // We will process the next receiver right now if this is finishing
12154 // an app receiver (which is always asynchronous) or after we have
12155 // come back from calling a receiver.
12156 return state == BroadcastRecord.APP_RECEIVE
12157 || state == BroadcastRecord.CALL_DONE_RECEIVE;
12158 }
12159
12160 public void finishReceiver(IBinder who, int resultCode, String resultData,
12161 Bundle resultExtras, boolean resultAbort) {
12162 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
12163
12164 // Refuse possible leaked file descriptors
12165 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
12166 throw new IllegalArgumentException("File descriptors passed in Bundle");
12167 }
12168
12169 boolean doNext;
12170
12171 final long origId = Binder.clearCallingIdentity();
12172
12173 synchronized(this) {
12174 doNext = finishReceiverLocked(
12175 who, resultCode, resultData, resultExtras, resultAbort, true);
12176 }
12177
12178 if (doNext) {
12179 processNextBroadcast(false);
12180 }
12181 trimApplications();
12182
12183 Binder.restoreCallingIdentity(origId);
12184 }
12185
12186 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
12187 if (r.nextReceiver > 0) {
12188 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12189 if (curReceiver instanceof BroadcastFilter) {
12190 BroadcastFilter bf = (BroadcastFilter) curReceiver;
Doug Zongker2bec3d42009-12-04 12:52:44 -080012191 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012192 System.identityHashCode(r),
12193 r.intent.getAction(),
12194 r.nextReceiver - 1,
12195 System.identityHashCode(bf));
12196 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -080012197 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012198 System.identityHashCode(r),
12199 r.intent.getAction(),
12200 r.nextReceiver - 1,
12201 ((ResolveInfo)curReceiver).toString());
12202 }
12203 } else {
12204 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
12205 + r);
Doug Zongker2bec3d42009-12-04 12:52:44 -080012206 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012207 System.identityHashCode(r),
12208 r.intent.getAction(),
12209 r.nextReceiver,
12210 "NONE");
12211 }
12212 }
12213
12214 private final void broadcastTimeout() {
12215 synchronized (this) {
12216 if (mOrderedBroadcasts.size() == 0) {
12217 return;
12218 }
12219 long now = SystemClock.uptimeMillis();
12220 BroadcastRecord r = mOrderedBroadcasts.get(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012221 if ((r.receiverTime+BROADCAST_TIMEOUT) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012222 if (DEBUG_BROADCAST) Log.v(TAG,
12223 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012224 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012225 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012226 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012227 return;
12228 }
12229
12230 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012231 r.receiverTime = now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012232 r.anrCount++;
12233
12234 // Current receiver has passed its expiration date.
12235 if (r.nextReceiver <= 0) {
12236 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12237 return;
12238 }
12239
12240 ProcessRecord app = null;
12241
12242 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12243 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12244 logBroadcastReceiverDiscard(r);
12245 if (curReceiver instanceof BroadcastFilter) {
12246 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12247 if (bf.receiverList.pid != 0
12248 && bf.receiverList.pid != MY_PID) {
12249 synchronized (this.mPidsSelfLocked) {
12250 app = this.mPidsSelfLocked.get(
12251 bf.receiverList.pid);
12252 }
12253 }
12254 } else {
12255 app = r.curApp;
12256 }
12257
12258 if (app != null) {
Dan Egnorb7f03672009-12-09 16:22:32 -080012259 appNotRespondingLocked(app, null, null, "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012260 }
12261
12262 if (mPendingBroadcast == r) {
12263 mPendingBroadcast = null;
12264 }
12265
12266 // Move on to the next receiver.
12267 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12268 r.resultExtras, r.resultAbort, true);
12269 scheduleBroadcastsLocked();
12270 }
12271 }
12272
12273 private final void processCurBroadcastLocked(BroadcastRecord r,
12274 ProcessRecord app) throws RemoteException {
12275 if (app.thread == null) {
12276 throw new RemoteException();
12277 }
12278 r.receiver = app.thread.asBinder();
12279 r.curApp = app;
12280 app.curReceiver = r;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080012281 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012282
12283 // Tell the application to launch this receiver.
12284 r.intent.setComponent(r.curComponent);
12285
12286 boolean started = false;
12287 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012288 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012289 "Delivering to component " + r.curComponent
12290 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012291 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012292 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12293 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12294 started = true;
12295 } finally {
12296 if (!started) {
12297 r.receiver = null;
12298 r.curApp = null;
12299 app.curReceiver = null;
12300 }
12301 }
12302
12303 }
12304
12305 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012306 Intent intent, int resultCode, String data, Bundle extras,
12307 boolean ordered, boolean sticky) throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012308 if (app != null && app.thread != null) {
12309 // If we have an app thread, do the call through that so it is
12310 // correctly ordered with other one-way calls.
12311 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012312 data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012313 } else {
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012314 receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012315 }
12316 }
12317
12318 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12319 BroadcastFilter filter, boolean ordered) {
12320 boolean skip = false;
12321 if (filter.requiredPermission != null) {
12322 int perm = checkComponentPermission(filter.requiredPermission,
12323 r.callingPid, r.callingUid, -1);
12324 if (perm != PackageManager.PERMISSION_GRANTED) {
12325 Log.w(TAG, "Permission Denial: broadcasting "
12326 + r.intent.toString()
12327 + " from " + r.callerPackage + " (pid="
12328 + r.callingPid + ", uid=" + r.callingUid + ")"
12329 + " requires " + filter.requiredPermission
12330 + " due to registered receiver " + filter);
12331 skip = true;
12332 }
12333 }
12334 if (r.requiredPermission != null) {
12335 int perm = checkComponentPermission(r.requiredPermission,
12336 filter.receiverList.pid, filter.receiverList.uid, -1);
12337 if (perm != PackageManager.PERMISSION_GRANTED) {
12338 Log.w(TAG, "Permission Denial: receiving "
12339 + r.intent.toString()
12340 + " to " + filter.receiverList.app
12341 + " (pid=" + filter.receiverList.pid
12342 + ", uid=" + filter.receiverList.uid + ")"
12343 + " requires " + r.requiredPermission
12344 + " due to sender " + r.callerPackage
12345 + " (uid " + r.callingUid + ")");
12346 skip = true;
12347 }
12348 }
12349
12350 if (!skip) {
12351 // If this is not being sent as an ordered broadcast, then we
12352 // don't want to touch the fields that keep track of the current
12353 // state of ordered broadcasts.
12354 if (ordered) {
12355 r.receiver = filter.receiverList.receiver.asBinder();
12356 r.curFilter = filter;
12357 filter.receiverList.curBroadcast = r;
12358 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012359 if (filter.receiverList.app != null) {
12360 // Bump hosting application to no longer be in background
12361 // scheduling class. Note that we can't do that if there
12362 // isn't an app... but we can only be in that case for
12363 // things that directly call the IActivityManager API, which
12364 // are already core system stuff so don't matter for this.
12365 r.curApp = filter.receiverList.app;
12366 filter.receiverList.app.curReceiver = r;
12367 updateOomAdjLocked();
12368 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012369 }
12370 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012371 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012372 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012373 Log.i(TAG, "Delivering to " + filter.receiverList.app
12374 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012375 }
12376 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12377 new Intent(r.intent), r.resultCode,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012378 r.resultData, r.resultExtras, r.ordered, r.initialSticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012379 if (ordered) {
12380 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12381 }
12382 } catch (RemoteException e) {
12383 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12384 if (ordered) {
12385 r.receiver = null;
12386 r.curFilter = null;
12387 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012388 if (filter.receiverList.app != null) {
12389 filter.receiverList.app.curReceiver = null;
12390 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012391 }
12392 }
12393 }
12394 }
12395
Dianne Hackborn12527f92009-11-11 17:39:50 -080012396 private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
12397 if (r.callingUid < 0) {
12398 // This was from a registerReceiver() call; ignore it.
12399 return;
12400 }
12401 System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
12402 MAX_BROADCAST_HISTORY-1);
12403 r.finishTime = SystemClock.uptimeMillis();
12404 mBroadcastHistory[0] = r;
12405 }
12406
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012407 private final void processNextBroadcast(boolean fromMsg) {
12408 synchronized(this) {
12409 BroadcastRecord r;
12410
12411 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12412 + mParallelBroadcasts.size() + " broadcasts, "
12413 + mOrderedBroadcasts.size() + " serialized broadcasts");
12414
12415 updateCpuStats();
12416
12417 if (fromMsg) {
12418 mBroadcastsScheduled = false;
12419 }
12420
12421 // First, deliver any non-serialized broadcasts right away.
12422 while (mParallelBroadcasts.size() > 0) {
12423 r = mParallelBroadcasts.remove(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012424 r.dispatchTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012425 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012426 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12427 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012428 for (int i=0; i<N; i++) {
12429 Object target = r.receivers.get(i);
12430 if (DEBUG_BROADCAST) Log.v(TAG,
12431 "Delivering non-serialized to registered "
12432 + target + ": " + r);
12433 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12434 }
Dianne Hackborn12527f92009-11-11 17:39:50 -080012435 addBroadcastToHistoryLocked(r);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012436 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12437 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012438 }
12439
12440 // Now take care of the next serialized one...
12441
12442 // If we are waiting for a process to come up to handle the next
12443 // broadcast, then do nothing at this point. Just in case, we
12444 // check that the process we're waiting for still exists.
12445 if (mPendingBroadcast != null) {
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -070012446 if (DEBUG_BROADCAST_LIGHT) {
12447 Log.v(TAG, "processNextBroadcast: waiting for "
12448 + mPendingBroadcast.curApp);
12449 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012450
12451 boolean isDead;
12452 synchronized (mPidsSelfLocked) {
12453 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12454 }
12455 if (!isDead) {
12456 // It's still alive, so keep waiting
12457 return;
12458 } else {
12459 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12460 + " died before responding to broadcast");
12461 mPendingBroadcast = null;
12462 }
12463 }
12464
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012465 boolean looped = false;
12466
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012467 do {
12468 if (mOrderedBroadcasts.size() == 0) {
12469 // No more broadcasts pending, so all done!
12470 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012471 if (looped) {
12472 // If we had finished the last ordered broadcast, then
12473 // make sure all processes have correct oom and sched
12474 // adjustments.
12475 updateOomAdjLocked();
12476 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012477 return;
12478 }
12479 r = mOrderedBroadcasts.get(0);
12480 boolean forceReceive = false;
12481
12482 // Ensure that even if something goes awry with the timeout
12483 // detection, we catch "hung" broadcasts here, discard them,
12484 // and continue to make progress.
12485 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12486 long now = SystemClock.uptimeMillis();
12487 if (r.dispatchTime > 0) {
12488 if ((numReceivers > 0) &&
12489 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12490 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12491 + " now=" + now
12492 + " dispatchTime=" + r.dispatchTime
Dianne Hackborn12527f92009-11-11 17:39:50 -080012493 + " startTime=" + r.receiverTime
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012494 + " intent=" + r.intent
12495 + " numReceivers=" + numReceivers
12496 + " nextReceiver=" + r.nextReceiver
12497 + " state=" + r.state);
12498 broadcastTimeout(); // forcibly finish this broadcast
12499 forceReceive = true;
12500 r.state = BroadcastRecord.IDLE;
12501 }
12502 }
12503
12504 if (r.state != BroadcastRecord.IDLE) {
12505 if (DEBUG_BROADCAST) Log.d(TAG,
12506 "processNextBroadcast() called when not idle (state="
12507 + r.state + ")");
12508 return;
12509 }
12510
12511 if (r.receivers == null || r.nextReceiver >= numReceivers
12512 || r.resultAbort || forceReceive) {
12513 // No more receivers for this broadcast! Send the final
12514 // result if requested...
12515 if (r.resultTo != null) {
12516 try {
12517 if (DEBUG_BROADCAST) {
12518 int seq = r.intent.getIntExtra("seq", -1);
12519 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12520 + " seq=" + seq + " app=" + r.callerApp);
12521 }
12522 performReceive(r.callerApp, r.resultTo,
12523 new Intent(r.intent), r.resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012524 r.resultData, r.resultExtras, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012525 } catch (RemoteException e) {
12526 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12527 }
12528 }
12529
12530 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12531 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12532
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012533 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12534 + r);
12535
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012536 // ... and on to the next...
Dianne Hackborn12527f92009-11-11 17:39:50 -080012537 addBroadcastToHistoryLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012538 mOrderedBroadcasts.remove(0);
12539 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012540 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012541 continue;
12542 }
12543 } while (r == null);
12544
12545 // Get the next receiver...
12546 int recIdx = r.nextReceiver++;
12547
12548 // Keep track of when this receiver started, and make sure there
12549 // is a timeout message pending to kill it if need be.
Dianne Hackborn12527f92009-11-11 17:39:50 -080012550 r.receiverTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012551 if (recIdx == 0) {
Dianne Hackborn12527f92009-11-11 17:39:50 -080012552 r.dispatchTime = r.receiverTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012553
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012554 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12555 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012556 if (DEBUG_BROADCAST) Log.v(TAG,
12557 "Submitting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012558 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012559 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012560 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012561 }
12562
12563 Object nextReceiver = r.receivers.get(recIdx);
12564 if (nextReceiver instanceof BroadcastFilter) {
12565 // Simple case: this is a registered receiver who gets
12566 // a direct call.
12567 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12568 if (DEBUG_BROADCAST) Log.v(TAG,
12569 "Delivering serialized to registered "
12570 + filter + ": " + r);
12571 deliverToRegisteredReceiver(r, filter, r.ordered);
12572 if (r.receiver == null || !r.ordered) {
12573 // The receiver has already finished, so schedule to
12574 // process the next one.
12575 r.state = BroadcastRecord.IDLE;
12576 scheduleBroadcastsLocked();
12577 }
12578 return;
12579 }
12580
12581 // Hard case: need to instantiate the receiver, possibly
12582 // starting its application process to host it.
12583
12584 ResolveInfo info =
12585 (ResolveInfo)nextReceiver;
12586
12587 boolean skip = false;
12588 int perm = checkComponentPermission(info.activityInfo.permission,
12589 r.callingPid, r.callingUid,
12590 info.activityInfo.exported
12591 ? -1 : info.activityInfo.applicationInfo.uid);
12592 if (perm != PackageManager.PERMISSION_GRANTED) {
12593 Log.w(TAG, "Permission Denial: broadcasting "
12594 + r.intent.toString()
12595 + " from " + r.callerPackage + " (pid=" + r.callingPid
12596 + ", uid=" + r.callingUid + ")"
12597 + " requires " + info.activityInfo.permission
12598 + " due to receiver " + info.activityInfo.packageName
12599 + "/" + info.activityInfo.name);
12600 skip = true;
12601 }
12602 if (r.callingUid != Process.SYSTEM_UID &&
12603 r.requiredPermission != null) {
12604 try {
12605 perm = ActivityThread.getPackageManager().
12606 checkPermission(r.requiredPermission,
12607 info.activityInfo.applicationInfo.packageName);
12608 } catch (RemoteException e) {
12609 perm = PackageManager.PERMISSION_DENIED;
12610 }
12611 if (perm != PackageManager.PERMISSION_GRANTED) {
12612 Log.w(TAG, "Permission Denial: receiving "
12613 + r.intent + " to "
12614 + info.activityInfo.applicationInfo.packageName
12615 + " requires " + r.requiredPermission
12616 + " due to sender " + r.callerPackage
12617 + " (uid " + r.callingUid + ")");
12618 skip = true;
12619 }
12620 }
12621 if (r.curApp != null && r.curApp.crashing) {
12622 // If the target process is crashing, just skip it.
12623 skip = true;
12624 }
12625
12626 if (skip) {
12627 r.receiver = null;
12628 r.curFilter = null;
12629 r.state = BroadcastRecord.IDLE;
12630 scheduleBroadcastsLocked();
12631 return;
12632 }
12633
12634 r.state = BroadcastRecord.APP_RECEIVE;
12635 String targetProcess = info.activityInfo.processName;
12636 r.curComponent = new ComponentName(
12637 info.activityInfo.applicationInfo.packageName,
12638 info.activityInfo.name);
12639 r.curReceiver = info.activityInfo;
12640
12641 // Is this receiver's application already running?
12642 ProcessRecord app = getProcessRecordLocked(targetProcess,
12643 info.activityInfo.applicationInfo.uid);
12644 if (app != null && app.thread != null) {
12645 try {
12646 processCurBroadcastLocked(r, app);
12647 return;
12648 } catch (RemoteException e) {
12649 Log.w(TAG, "Exception when sending broadcast to "
12650 + r.curComponent, e);
12651 }
12652
12653 // If a dead object exception was thrown -- fall through to
12654 // restart the application.
12655 }
12656
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012657 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012658 if ((r.curApp=startProcessLocked(targetProcess,
12659 info.activityInfo.applicationInfo, true,
12660 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012661 "broadcast", r.curComponent,
12662 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12663 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012664 // Ah, this recipient is unavailable. Finish it if necessary,
12665 // and mark the broadcast record as ready for the next.
12666 Log.w(TAG, "Unable to launch app "
12667 + info.activityInfo.applicationInfo.packageName + "/"
12668 + info.activityInfo.applicationInfo.uid + " for broadcast "
12669 + r.intent + ": process is bad");
12670 logBroadcastReceiverDiscard(r);
12671 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12672 r.resultExtras, r.resultAbort, true);
12673 scheduleBroadcastsLocked();
12674 r.state = BroadcastRecord.IDLE;
12675 return;
12676 }
12677
12678 mPendingBroadcast = r;
12679 }
12680 }
12681
12682 // =========================================================
12683 // INSTRUMENTATION
12684 // =========================================================
12685
12686 public boolean startInstrumentation(ComponentName className,
12687 String profileFile, int flags, Bundle arguments,
12688 IInstrumentationWatcher watcher) {
12689 // Refuse possible leaked file descriptors
12690 if (arguments != null && arguments.hasFileDescriptors()) {
12691 throw new IllegalArgumentException("File descriptors passed in Bundle");
12692 }
12693
12694 synchronized(this) {
12695 InstrumentationInfo ii = null;
12696 ApplicationInfo ai = null;
12697 try {
12698 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012699 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012700 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012701 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012702 } catch (PackageManager.NameNotFoundException e) {
12703 }
12704 if (ii == null) {
12705 reportStartInstrumentationFailure(watcher, className,
12706 "Unable to find instrumentation info for: " + className);
12707 return false;
12708 }
12709 if (ai == null) {
12710 reportStartInstrumentationFailure(watcher, className,
12711 "Unable to find instrumentation target package: " + ii.targetPackage);
12712 return false;
12713 }
12714
12715 int match = mContext.getPackageManager().checkSignatures(
12716 ii.targetPackage, ii.packageName);
12717 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12718 String msg = "Permission Denial: starting instrumentation "
12719 + className + " from pid="
12720 + Binder.getCallingPid()
12721 + ", uid=" + Binder.getCallingPid()
12722 + " not allowed because package " + ii.packageName
12723 + " does not have a signature matching the target "
12724 + ii.targetPackage;
12725 reportStartInstrumentationFailure(watcher, className, msg);
12726 throw new SecurityException(msg);
12727 }
12728
12729 final long origId = Binder.clearCallingIdentity();
12730 uninstallPackageLocked(ii.targetPackage, -1, true);
12731 ProcessRecord app = addAppLocked(ai);
12732 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012733 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012734 app.instrumentationProfileFile = profileFile;
12735 app.instrumentationArguments = arguments;
12736 app.instrumentationWatcher = watcher;
12737 app.instrumentationResultClass = className;
12738 Binder.restoreCallingIdentity(origId);
12739 }
12740
12741 return true;
12742 }
12743
12744 /**
12745 * Report errors that occur while attempting to start Instrumentation. Always writes the
12746 * error to the logs, but if somebody is watching, send the report there too. This enables
12747 * the "am" command to report errors with more information.
12748 *
12749 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12750 * @param cn The component name of the instrumentation.
12751 * @param report The error report.
12752 */
12753 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12754 ComponentName cn, String report) {
12755 Log.w(TAG, report);
12756 try {
12757 if (watcher != null) {
12758 Bundle results = new Bundle();
12759 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12760 results.putString("Error", report);
12761 watcher.instrumentationStatus(cn, -1, results);
12762 }
12763 } catch (RemoteException e) {
12764 Log.w(TAG, e);
12765 }
12766 }
12767
12768 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12769 if (app.instrumentationWatcher != null) {
12770 try {
12771 // NOTE: IInstrumentationWatcher *must* be oneway here
12772 app.instrumentationWatcher.instrumentationFinished(
12773 app.instrumentationClass,
12774 resultCode,
12775 results);
12776 } catch (RemoteException e) {
12777 }
12778 }
12779 app.instrumentationWatcher = null;
12780 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012781 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012782 app.instrumentationProfileFile = null;
12783 app.instrumentationArguments = null;
12784
12785 uninstallPackageLocked(app.processName, -1, false);
12786 }
12787
12788 public void finishInstrumentation(IApplicationThread target,
12789 int resultCode, Bundle results) {
12790 // Refuse possible leaked file descriptors
12791 if (results != null && results.hasFileDescriptors()) {
12792 throw new IllegalArgumentException("File descriptors passed in Intent");
12793 }
12794
12795 synchronized(this) {
12796 ProcessRecord app = getRecordForAppLocked(target);
12797 if (app == null) {
12798 Log.w(TAG, "finishInstrumentation: no app for " + target);
12799 return;
12800 }
12801 final long origId = Binder.clearCallingIdentity();
12802 finishInstrumentationLocked(app, resultCode, results);
12803 Binder.restoreCallingIdentity(origId);
12804 }
12805 }
12806
12807 // =========================================================
12808 // CONFIGURATION
12809 // =========================================================
12810
12811 public ConfigurationInfo getDeviceConfigurationInfo() {
12812 ConfigurationInfo config = new ConfigurationInfo();
12813 synchronized (this) {
12814 config.reqTouchScreen = mConfiguration.touchscreen;
12815 config.reqKeyboardType = mConfiguration.keyboard;
12816 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012817 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12818 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012819 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12820 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012821 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12822 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012823 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12824 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012825 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012826 }
12827 return config;
12828 }
12829
12830 public Configuration getConfiguration() {
12831 Configuration ci;
12832 synchronized(this) {
12833 ci = new Configuration(mConfiguration);
12834 }
12835 return ci;
12836 }
12837
12838 public void updateConfiguration(Configuration values) {
12839 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12840 "updateConfiguration()");
12841
12842 synchronized(this) {
12843 if (values == null && mWindowManager != null) {
12844 // sentinel: fetch the current configuration from the window manager
12845 values = mWindowManager.computeNewConfiguration();
12846 }
12847
12848 final long origId = Binder.clearCallingIdentity();
12849 updateConfigurationLocked(values, null);
12850 Binder.restoreCallingIdentity(origId);
12851 }
12852 }
12853
12854 /**
12855 * Do either or both things: (1) change the current configuration, and (2)
12856 * make sure the given activity is running with the (now) current
12857 * configuration. Returns true if the activity has been left running, or
12858 * false if <var>starting</var> is being destroyed to match the new
12859 * configuration.
12860 */
12861 public boolean updateConfigurationLocked(Configuration values,
12862 HistoryRecord starting) {
12863 int changes = 0;
12864
12865 boolean kept = true;
12866
12867 if (values != null) {
12868 Configuration newConfig = new Configuration(mConfiguration);
12869 changes = newConfig.updateFrom(values);
12870 if (changes != 0) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012871 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012872 Log.i(TAG, "Updating configuration to: " + values);
12873 }
12874
Doug Zongker2bec3d42009-12-04 12:52:44 -080012875 EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012876
12877 if (values.locale != null) {
12878 saveLocaleLocked(values.locale,
12879 !values.locale.equals(mConfiguration.locale),
12880 values.userSetLocale);
12881 }
12882
12883 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070012884 Log.i(TAG, "Config changed: " + newConfig);
Dianne Hackborn826d17c2009-11-12 12:55:51 -080012885
12886 AttributeCache ac = AttributeCache.instance();
12887 if (ac != null) {
12888 ac.updateConfiguration(mConfiguration);
12889 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012890
12891 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12892 msg.obj = new Configuration(mConfiguration);
12893 mHandler.sendMessage(msg);
12894
Dianne Hackborndd71fc82009-12-16 19:24:32 -080012895 for (int i=mLruProcesses.size()-1; i>=0; i--) {
12896 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012897 try {
12898 if (app.thread != null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012899 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending to proc "
12900 + app.processName + " new config " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012901 app.thread.scheduleConfigurationChanged(mConfiguration);
12902 }
12903 } catch (Exception e) {
12904 }
12905 }
12906 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012907 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
12908 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012909 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12910 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackborn362d5b92009-11-11 18:04:39 -080012911 if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
12912 broadcastIntentLocked(null, null,
12913 new Intent(Intent.ACTION_LOCALE_CHANGED),
12914 null, null, 0, null, null,
12915 null, false, false, MY_PID, Process.SYSTEM_UID);
12916 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012917 }
12918 }
12919
12920 if (changes != 0 && starting == null) {
12921 // If the configuration changed, and the caller is not already
12922 // in the process of starting an activity, then find the top
12923 // activity to check if its configuration needs to change.
12924 starting = topRunningActivityLocked(null);
12925 }
12926
12927 if (starting != null) {
12928 kept = ensureActivityConfigurationLocked(starting, changes);
12929 if (kept) {
12930 // If this didn't result in the starting activity being
12931 // destroyed, then we need to make sure at this point that all
12932 // other activities are made visible.
12933 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12934 + ", ensuring others are correct.");
12935 ensureActivitiesVisibleLocked(starting, changes);
12936 }
12937 }
12938
12939 return kept;
12940 }
12941
12942 private final boolean relaunchActivityLocked(HistoryRecord r,
12943 int changes, boolean andResume) {
12944 List<ResultInfo> results = null;
12945 List<Intent> newIntents = null;
12946 if (andResume) {
12947 results = r.results;
12948 newIntents = r.newIntents;
12949 }
12950 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12951 + " with results=" + results + " newIntents=" + newIntents
12952 + " andResume=" + andResume);
Doug Zongker2bec3d42009-12-04 12:52:44 -080012953 EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
12954 : EventLogTags.AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012955 r.task.taskId, r.shortComponentName);
12956
12957 r.startFreezingScreenLocked(r.app, 0);
12958
12959 try {
12960 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12961 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
Dianne Hackborn871ecdc2009-12-11 15:24:33 -080012962 changes, !andResume, mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012963 // Note: don't need to call pauseIfSleepingLocked() here, because
12964 // the caller will only pass in 'andResume' if this activity is
12965 // currently resumed, which implies we aren't sleeping.
12966 } catch (RemoteException e) {
12967 return false;
12968 }
12969
12970 if (andResume) {
12971 r.results = null;
12972 r.newIntents = null;
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -070012973 reportResumedActivityLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012974 }
12975
12976 return true;
12977 }
12978
12979 /**
12980 * Make sure the given activity matches the current configuration. Returns
12981 * false if the activity had to be destroyed. Returns true if the
12982 * configuration is the same, or the activity will remain running as-is
12983 * for whatever reason. Ensures the HistoryRecord is updated with the
12984 * correct configuration and all other bookkeeping is handled.
12985 */
12986 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12987 int globalChanges) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012988 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12989 "Ensuring correct configuration: " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012990
12991 // Short circuit: if the two configurations are the exact same
12992 // object (the common case), then there is nothing to do.
12993 Configuration newConfig = mConfiguration;
12994 if (r.configuration == newConfig) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012995 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12996 "Configuration unchanged in " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012997 return true;
12998 }
12999
13000 // We don't worry about activities that are finishing.
13001 if (r.finishing) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013002 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013003 "Configuration doesn't matter in finishing " + r);
13004 r.stopFreezingScreenLocked(false);
13005 return true;
13006 }
13007
13008 // Okay we now are going to make this activity have the new config.
13009 // But then we need to figure out how it needs to deal with that.
13010 Configuration oldConfig = r.configuration;
13011 r.configuration = newConfig;
13012
13013 // If the activity isn't currently running, just leave the new
13014 // configuration and it will pick that up next time it starts.
13015 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013016 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013017 "Configuration doesn't matter not running " + r);
13018 r.stopFreezingScreenLocked(false);
13019 return true;
13020 }
13021
13022 // If the activity isn't persistent, there is a chance we will
13023 // need to restart it.
13024 if (!r.persistent) {
13025
13026 // Figure out what has changed between the two configurations.
13027 int changes = oldConfig.diff(newConfig);
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013028 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
13029 Log.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013030 + Integer.toHexString(changes) + ", handles=0x"
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013031 + Integer.toHexString(r.info.configChanges)
13032 + ", newConfig=" + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013033 }
13034 if ((changes&(~r.info.configChanges)) != 0) {
13035 // Aha, the activity isn't handling the change, so DIE DIE DIE.
13036 r.configChangeFlags |= changes;
13037 r.startFreezingScreenLocked(r.app, globalChanges);
13038 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013039 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13040 "Switch is destroying non-running " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013041 destroyActivityLocked(r, true);
13042 } else if (r.state == ActivityState.PAUSING) {
13043 // A little annoying: we are waiting for this activity to
13044 // finish pausing. Let's not do anything now, but just
13045 // flag that it needs to be restarted when done pausing.
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013046 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13047 "Switch is skipping already pausing " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013048 r.configDestroy = true;
13049 return true;
13050 } else if (r.state == ActivityState.RESUMED) {
13051 // Try to optimize this case: the configuration is changing
13052 // and we need to restart the top, resumed activity.
13053 // Instead of doing the normal handshaking, just say
13054 // "restart!".
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013055 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13056 "Switch is restarting resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013057 relaunchActivityLocked(r, r.configChangeFlags, true);
13058 r.configChangeFlags = 0;
13059 } else {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013060 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13061 "Switch is restarting non-resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013062 relaunchActivityLocked(r, r.configChangeFlags, false);
13063 r.configChangeFlags = 0;
13064 }
13065
13066 // All done... tell the caller we weren't able to keep this
13067 // activity around.
13068 return false;
13069 }
13070 }
13071
13072 // Default case: the activity can handle this new configuration, so
13073 // hand it over. Note that we don't need to give it the new
13074 // configuration, since we always send configuration changes to all
13075 // process when they happen so it can just use whatever configuration
13076 // it last got.
13077 if (r.app != null && r.app.thread != null) {
13078 try {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013079 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending new config to " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013080 r.app.thread.scheduleActivityConfigurationChanged(r);
13081 } catch (RemoteException e) {
13082 // If process died, whatever.
13083 }
13084 }
13085 r.stopFreezingScreenLocked(false);
13086
13087 return true;
13088 }
13089
13090 /**
13091 * Save the locale. You must be inside a synchronized (this) block.
13092 */
13093 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
13094 if(isDiff) {
13095 SystemProperties.set("user.language", l.getLanguage());
13096 SystemProperties.set("user.region", l.getCountry());
13097 }
13098
13099 if(isPersist) {
13100 SystemProperties.set("persist.sys.language", l.getLanguage());
13101 SystemProperties.set("persist.sys.country", l.getCountry());
13102 SystemProperties.set("persist.sys.localevar", l.getVariant());
13103 }
13104 }
13105
13106 // =========================================================
13107 // LIFETIME MANAGEMENT
13108 // =========================================================
13109
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013110 private final int computeOomAdjLocked(ProcessRecord app, int hiddenAdj,
13111 ProcessRecord TOP_APP, boolean recursed) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013112 if (mAdjSeq == app.adjSeq) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013113 // This adjustment has already been computed. If we are calling
13114 // from the top, we may have already computed our adjustment with
13115 // an earlier hidden adjustment that isn't really for us... if
13116 // so, use the new hidden adjustment.
13117 if (!recursed && app.hidden) {
13118 app.curAdj = hiddenAdj;
13119 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013120 return app.curAdj;
13121 }
13122
13123 if (app.thread == null) {
13124 app.adjSeq = mAdjSeq;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013125 app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013126 return (app.curAdj=EMPTY_APP_ADJ);
13127 }
13128
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013129 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
13130 // The max adjustment doesn't allow this app to be anything
13131 // below foreground, so it is not worth doing work for it.
13132 app.adjType = "fixed";
13133 app.adjSeq = mAdjSeq;
13134 app.curRawAdj = app.maxAdj;
13135 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
13136 return (app.curAdj=app.maxAdj);
13137 }
13138
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013139 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013140 app.adjSource = null;
13141 app.adjTarget = null;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013142 app.empty = false;
13143 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013144
The Android Open Source Project4df24232009-03-05 14:34:35 -080013145 // Determine the importance of the process, starting with most
13146 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013147 int adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013148 int schedGroup;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013149 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013150 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013151 // The last app on the list is the foreground app.
13152 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013153 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013154 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013155 } else if (app.instrumentationClass != null) {
13156 // Don't want to kill running instrumentation.
13157 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013158 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013159 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013160 } else if (app.persistentActivities > 0) {
13161 // Special persistent activities... shouldn't be used these days.
13162 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013163 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013164 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013165 } else if (app.curReceiver != null ||
13166 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
13167 // An app that is currently receiving a broadcast also
13168 // counts as being in the foreground.
13169 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013170 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013171 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013172 } else if (app.executingServices.size() > 0) {
13173 // An app that is currently executing a service callback also
13174 // counts as being in the foreground.
13175 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013176 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013177 app.adjType = "exec-service";
13178 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013179 // The user is aware of this app, so make it visible.
13180 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013181 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013182 app.adjType = "foreground-service";
13183 } else if (app.forcingToForeground != null) {
13184 // The user is aware of this app, so make it visible.
13185 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013186 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013187 app.adjType = "force-foreground";
13188 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080013189 } else if (app == mHomeProcess) {
13190 // This process is hosting what we currently consider to be the
13191 // home app, so we don't want to let it go into the background.
13192 adj = HOME_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013193 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013194 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013195 } else if ((N=app.activities.size()) != 0) {
13196 // This app is in the background with paused activities.
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013197 app.hidden = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013198 adj = hiddenAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013199 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013200 app.adjType = "bg-activities";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013201 N = app.activities.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013202 for (int j=0; j<N; j++) {
13203 if (((HistoryRecord)app.activities.get(j)).visible) {
13204 // This app has a visible activity!
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013205 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013206 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013207 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013208 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013209 break;
13210 }
13211 }
13212 } else {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013213 // A very not-needed process. If this is lower in the lru list,
13214 // we will push it in to the empty bucket.
13215 app.hidden = true;
13216 app.empty = true;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013217 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013218 adj = hiddenAdj;
13219 app.adjType = "bg-empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013220 }
13221
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013222 //Log.i(TAG, "OOM " + app + ": initial adj=" + adj);
13223
The Android Open Source Project4df24232009-03-05 14:34:35 -080013224 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013225 // there are applications dependent on our services or providers, but
13226 // this gives us a baseline and makes sure we don't get into an
13227 // infinite recursion.
13228 app.adjSeq = mAdjSeq;
13229 app.curRawAdj = adj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013230
Christopher Tate6fa95972009-06-05 18:43:55 -070013231 if (mBackupTarget != null && app == mBackupTarget.app) {
13232 // If possible we want to avoid killing apps while they're being backed up
13233 if (adj > BACKUP_APP_ADJ) {
13234 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
13235 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013236 app.adjType = "backup";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013237 app.hidden = false;
Christopher Tate6fa95972009-06-05 18:43:55 -070013238 }
13239 }
13240
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013241 if (app.services.size() != 0 && (adj > FOREGROUND_APP_ADJ
13242 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013243 final long now = SystemClock.uptimeMillis();
13244 // This process is more important if the top activity is
13245 // bound to the service.
13246 Iterator jt = app.services.iterator();
13247 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13248 ServiceRecord s = (ServiceRecord)jt.next();
13249 if (s.startRequested) {
13250 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
13251 // This service has seen some activity within
13252 // recent memory, so we will keep its process ahead
13253 // of the background processes.
13254 if (adj > SECONDARY_SERVER_ADJ) {
13255 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013256 app.adjType = "started-services";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013257 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013258 }
13259 }
13260 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013261 if (s.connections.size() > 0 && (adj > FOREGROUND_APP_ADJ
13262 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013263 Iterator<ConnectionRecord> kt
13264 = s.connections.values().iterator();
13265 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13266 // XXX should compute this based on the max of
13267 // all connected clients.
13268 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013269 if (cr.binding.client == app) {
13270 // Binding to ourself is not interesting.
13271 continue;
13272 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013273 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
13274 ProcessRecord client = cr.binding.client;
13275 int myHiddenAdj = hiddenAdj;
13276 if (myHiddenAdj > client.hiddenAdj) {
13277 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
13278 myHiddenAdj = client.hiddenAdj;
13279 } else {
13280 myHiddenAdj = VISIBLE_APP_ADJ;
13281 }
13282 }
13283 int clientAdj = computeOomAdjLocked(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013284 client, myHiddenAdj, TOP_APP, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013285 if (adj > clientAdj) {
13286 adj = clientAdj > VISIBLE_APP_ADJ
13287 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013288 if (!client.hidden) {
13289 app.hidden = false;
13290 }
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013291 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013292 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13293 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013294 app.adjSource = cr.binding.client;
13295 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013296 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013297 if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
13298 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13299 schedGroup = Process.THREAD_GROUP_DEFAULT;
13300 }
13301 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013302 }
13303 HistoryRecord a = cr.activity;
13304 //if (a != null) {
13305 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13306 //}
13307 if (a != null && adj > FOREGROUND_APP_ADJ &&
13308 (a.state == ActivityState.RESUMED
13309 || a.state == ActivityState.PAUSING)) {
13310 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013311 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013312 app.hidden = false;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013313 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013314 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13315 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013316 app.adjSource = a;
13317 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013318 }
13319 }
13320 }
13321 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013322
13323 // Finally, f this process has active services running in it, we
13324 // would like to avoid killing it unless it would prevent the current
13325 // application from running. By default we put the process in
13326 // with the rest of the background processes; as we scan through
13327 // its services we may bump it up from there.
13328 if (adj > hiddenAdj) {
13329 adj = hiddenAdj;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013330 app.hidden = false;
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013331 app.adjType = "bg-services";
13332 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013333 }
13334
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013335 if (app.pubProviders.size() != 0 && (adj > FOREGROUND_APP_ADJ
13336 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013337 Iterator jt = app.pubProviders.values().iterator();
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013338 while (jt.hasNext() && (adj > FOREGROUND_APP_ADJ
13339 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013340 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13341 if (cpr.clients.size() != 0) {
13342 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13343 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13344 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013345 if (client == app) {
13346 // Being our own client is not interesting.
13347 continue;
13348 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013349 int myHiddenAdj = hiddenAdj;
13350 if (myHiddenAdj > client.hiddenAdj) {
13351 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13352 myHiddenAdj = client.hiddenAdj;
13353 } else {
13354 myHiddenAdj = FOREGROUND_APP_ADJ;
13355 }
13356 }
13357 int clientAdj = computeOomAdjLocked(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013358 client, myHiddenAdj, TOP_APP, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013359 if (adj > clientAdj) {
13360 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013361 ? clientAdj : FOREGROUND_APP_ADJ;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013362 if (!client.hidden) {
13363 app.hidden = false;
13364 }
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013365 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013366 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13367 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013368 app.adjSource = client;
13369 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013370 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013371 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13372 schedGroup = Process.THREAD_GROUP_DEFAULT;
13373 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013374 }
13375 }
13376 // If the provider has external (non-framework) process
13377 // dependencies, ensure that its adjustment is at least
13378 // FOREGROUND_APP_ADJ.
13379 if (cpr.externals != 0) {
13380 if (adj > FOREGROUND_APP_ADJ) {
13381 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013382 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013383 app.hidden = false;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013384 app.adjType = "provider";
13385 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013386 }
13387 }
13388 }
13389 }
13390
13391 app.curRawAdj = adj;
13392
13393 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13394 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13395 if (adj > app.maxAdj) {
13396 adj = app.maxAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013397 if (app.maxAdj <= VISIBLE_APP_ADJ) {
13398 schedGroup = Process.THREAD_GROUP_DEFAULT;
13399 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013400 }
13401
13402 app.curAdj = adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013403 app.curSchedGroup = schedGroup;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013404
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013405 return adj;
13406 }
13407
13408 /**
13409 * Ask a given process to GC right now.
13410 */
13411 final void performAppGcLocked(ProcessRecord app) {
13412 try {
13413 app.lastRequestedGc = SystemClock.uptimeMillis();
13414 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013415 if (app.reportLowMemory) {
13416 app.reportLowMemory = false;
13417 app.thread.scheduleLowMemory();
13418 } else {
13419 app.thread.processInBackground();
13420 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013421 }
13422 } catch (Exception e) {
13423 // whatever.
13424 }
13425 }
13426
13427 /**
13428 * Returns true if things are idle enough to perform GCs.
13429 */
13430 private final boolean canGcNow() {
13431 return mParallelBroadcasts.size() == 0
13432 && mOrderedBroadcasts.size() == 0
13433 && (mSleeping || (mResumedActivity != null &&
13434 mResumedActivity.idle));
13435 }
13436
13437 /**
13438 * Perform GCs on all processes that are waiting for it, but only
13439 * if things are idle.
13440 */
13441 final void performAppGcsLocked() {
13442 final int N = mProcessesToGc.size();
13443 if (N <= 0) {
13444 return;
13445 }
13446 if (canGcNow()) {
13447 while (mProcessesToGc.size() > 0) {
13448 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013449 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13450 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13451 <= SystemClock.uptimeMillis()) {
13452 // To avoid spamming the system, we will GC processes one
13453 // at a time, waiting a few seconds between each.
13454 performAppGcLocked(proc);
13455 scheduleAppGcsLocked();
13456 return;
13457 } else {
13458 // It hasn't been long enough since we last GCed this
13459 // process... put it in the list to wait for its time.
13460 addProcessToGcListLocked(proc);
13461 break;
13462 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013463 }
13464 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013465
13466 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013467 }
13468 }
13469
13470 /**
13471 * If all looks good, perform GCs on all processes waiting for them.
13472 */
13473 final void performAppGcsIfAppropriateLocked() {
13474 if (canGcNow()) {
13475 performAppGcsLocked();
13476 return;
13477 }
13478 // Still not idle, wait some more.
13479 scheduleAppGcsLocked();
13480 }
13481
13482 /**
13483 * Schedule the execution of all pending app GCs.
13484 */
13485 final void scheduleAppGcsLocked() {
13486 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013487
13488 if (mProcessesToGc.size() > 0) {
13489 // Schedule a GC for the time to the next process.
13490 ProcessRecord proc = mProcessesToGc.get(0);
13491 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13492
13493 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13494 long now = SystemClock.uptimeMillis();
13495 if (when < (now+GC_TIMEOUT)) {
13496 when = now + GC_TIMEOUT;
13497 }
13498 mHandler.sendMessageAtTime(msg, when);
13499 }
13500 }
13501
13502 /**
13503 * Add a process to the array of processes waiting to be GCed. Keeps the
13504 * list in sorted order by the last GC time. The process can't already be
13505 * on the list.
13506 */
13507 final void addProcessToGcListLocked(ProcessRecord proc) {
13508 boolean added = false;
13509 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13510 if (mProcessesToGc.get(i).lastRequestedGc <
13511 proc.lastRequestedGc) {
13512 added = true;
13513 mProcessesToGc.add(i+1, proc);
13514 break;
13515 }
13516 }
13517 if (!added) {
13518 mProcessesToGc.add(0, proc);
13519 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013520 }
13521
13522 /**
13523 * Set up to ask a process to GC itself. This will either do it
13524 * immediately, or put it on the list of processes to gc the next
13525 * time things are idle.
13526 */
13527 final void scheduleAppGcLocked(ProcessRecord app) {
13528 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013529 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013530 return;
13531 }
13532 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013533 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013534 scheduleAppGcsLocked();
13535 }
13536 }
13537
13538 private final boolean updateOomAdjLocked(
13539 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13540 app.hiddenAdj = hiddenAdj;
13541
13542 if (app.thread == null) {
13543 return true;
13544 }
13545
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013546 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013547
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013548 if ((app.pid != 0 && app.pid != MY_PID) || Process.supportsProcesses()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013549 if (app.curRawAdj != app.setRawAdj) {
13550 if (app.curRawAdj > FOREGROUND_APP_ADJ
13551 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13552 // If this app is transitioning from foreground to
13553 // non-foreground, have it do a gc.
13554 scheduleAppGcLocked(app);
13555 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13556 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13557 // Likewise do a gc when an app is moving in to the
13558 // background (such as a service stopping).
13559 scheduleAppGcLocked(app);
13560 }
13561 app.setRawAdj = app.curRawAdj;
13562 }
13563 if (adj != app.setAdj) {
13564 if (Process.setOomAdj(app.pid, adj)) {
13565 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13566 TAG, "Set app " + app.processName +
13567 " oom adj to " + adj);
13568 app.setAdj = adj;
13569 } else {
13570 return false;
13571 }
13572 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013573 if (app.setSchedGroup != app.curSchedGroup) {
13574 app.setSchedGroup = app.curSchedGroup;
13575 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13576 "Setting process group of " + app.processName
13577 + " to " + app.curSchedGroup);
13578 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013579 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013580 try {
13581 Process.setProcessGroup(app.pid, app.curSchedGroup);
13582 } catch (Exception e) {
13583 Log.w(TAG, "Failed setting process group of " + app.pid
13584 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013585 e.printStackTrace();
13586 } finally {
13587 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013588 }
13589 }
13590 if (false) {
13591 if (app.thread != null) {
13592 try {
13593 app.thread.setSchedulingGroup(app.curSchedGroup);
13594 } catch (RemoteException e) {
13595 }
13596 }
13597 }
13598 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013599 }
13600
13601 return true;
13602 }
13603
13604 private final HistoryRecord resumedAppLocked() {
13605 HistoryRecord resumedActivity = mResumedActivity;
13606 if (resumedActivity == null || resumedActivity.app == null) {
13607 resumedActivity = mPausingActivity;
13608 if (resumedActivity == null || resumedActivity.app == null) {
13609 resumedActivity = topRunningActivityLocked(null);
13610 }
13611 }
13612 return resumedActivity;
13613 }
13614
13615 private final boolean updateOomAdjLocked(ProcessRecord app) {
13616 final HistoryRecord TOP_ACT = resumedAppLocked();
13617 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13618 int curAdj = app.curAdj;
13619 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13620 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13621
13622 mAdjSeq++;
13623
13624 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13625 if (res) {
13626 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13627 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13628 if (nowHidden != wasHidden) {
13629 // Changed to/from hidden state, so apps after it in the LRU
13630 // list may also be changed.
13631 updateOomAdjLocked();
13632 }
13633 }
13634 return res;
13635 }
13636
13637 private final boolean updateOomAdjLocked() {
13638 boolean didOomAdj = true;
13639 final HistoryRecord TOP_ACT = resumedAppLocked();
13640 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13641
13642 if (false) {
13643 RuntimeException e = new RuntimeException();
13644 e.fillInStackTrace();
13645 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13646 }
13647
13648 mAdjSeq++;
13649
13650 // First try updating the OOM adjustment for each of the
13651 // application processes based on their current state.
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013652 int i = mLruProcesses.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013653 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13654 while (i > 0) {
13655 i--;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013656 ProcessRecord app = mLruProcesses.get(i);
13657 //Log.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013658 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013659 if (curHiddenAdj < EMPTY_APP_ADJ
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013660 && app.curAdj == curHiddenAdj) {
13661 curHiddenAdj++;
13662 }
13663 } else {
13664 didOomAdj = false;
13665 }
13666 }
13667
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013668 // If we return false, we will fall back on killing processes to
13669 // have a fixed limit. Do this if a limit has been requested; else
13670 // only return false if one of the adjustments failed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013671 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13672 }
13673
13674 private final void trimApplications() {
13675 synchronized (this) {
13676 int i;
13677
13678 // First remove any unused application processes whose package
13679 // has been removed.
13680 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13681 final ProcessRecord app = mRemovedProcesses.get(i);
13682 if (app.activities.size() == 0
13683 && app.curReceiver == null && app.services.size() == 0) {
13684 Log.i(
13685 TAG, "Exiting empty application process "
13686 + app.processName + " ("
13687 + (app.thread != null ? app.thread.asBinder() : null)
13688 + ")\n");
13689 if (app.pid > 0 && app.pid != MY_PID) {
13690 Process.killProcess(app.pid);
13691 } else {
13692 try {
13693 app.thread.scheduleExit();
13694 } catch (Exception e) {
13695 // Ignore exceptions.
13696 }
13697 }
13698 cleanUpApplicationRecordLocked(app, false, -1);
13699 mRemovedProcesses.remove(i);
13700
13701 if (app.persistent) {
13702 if (app.persistent) {
13703 addAppLocked(app.info);
13704 }
13705 }
13706 }
13707 }
13708
13709 // Now try updating the OOM adjustment for each of the
13710 // application processes based on their current state.
13711 // If the setOomAdj() API is not supported, then go with our
13712 // back-up plan...
13713 if (!updateOomAdjLocked()) {
13714
13715 // Count how many processes are running services.
13716 int numServiceProcs = 0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013717 for (i=mLruProcesses.size()-1; i>=0; i--) {
13718 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013719
13720 if (app.persistent || app.services.size() != 0
13721 || app.curReceiver != null
13722 || app.persistentActivities > 0) {
13723 // Don't count processes holding services against our
13724 // maximum process count.
13725 if (localLOGV) Log.v(
13726 TAG, "Not trimming app " + app + " with services: "
13727 + app.services);
13728 numServiceProcs++;
13729 }
13730 }
13731
13732 int curMaxProcs = mProcessLimit;
13733 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13734 if (mAlwaysFinishActivities) {
13735 curMaxProcs = 1;
13736 }
13737 curMaxProcs += numServiceProcs;
13738
13739 // Quit as many processes as we can to get down to the desired
13740 // process count. First remove any processes that no longer
13741 // have activites running in them.
13742 for ( i=0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013743 i<mLruProcesses.size()
13744 && mLruProcesses.size() > curMaxProcs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013745 i++) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013746 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013747 // Quit an application only if it is not currently
13748 // running any activities.
13749 if (!app.persistent && app.activities.size() == 0
13750 && app.curReceiver == null && app.services.size() == 0) {
13751 Log.i(
13752 TAG, "Exiting empty application process "
13753 + app.processName + " ("
13754 + (app.thread != null ? app.thread.asBinder() : null)
13755 + ")\n");
13756 if (app.pid > 0 && app.pid != MY_PID) {
13757 Process.killProcess(app.pid);
13758 } else {
13759 try {
13760 app.thread.scheduleExit();
13761 } catch (Exception e) {
13762 // Ignore exceptions.
13763 }
13764 }
13765 // todo: For now we assume the application is not buggy
13766 // or evil, and will quit as a result of our request.
13767 // Eventually we need to drive this off of the death
13768 // notification, and kill the process if it takes too long.
13769 cleanUpApplicationRecordLocked(app, false, i);
13770 i--;
13771 }
13772 }
13773
13774 // If we still have too many processes, now from the least
13775 // recently used process we start finishing activities.
13776 if (Config.LOGV) Log.v(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013777 TAG, "*** NOW HAVE " + mLruProcesses.size() +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013778 " of " + curMaxProcs + " processes");
13779 for ( i=0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013780 i<mLruProcesses.size()
13781 && mLruProcesses.size() > curMaxProcs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013782 i++) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013783 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013784 // Quit the application only if we have a state saved for
13785 // all of its activities.
13786 boolean canQuit = !app.persistent && app.curReceiver == null
13787 && app.services.size() == 0
13788 && app.persistentActivities == 0;
13789 int NUMA = app.activities.size();
13790 int j;
13791 if (Config.LOGV) Log.v(
13792 TAG, "Looking to quit " + app.processName);
13793 for (j=0; j<NUMA && canQuit; j++) {
13794 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13795 if (Config.LOGV) Log.v(
13796 TAG, " " + r.intent.getComponent().flattenToShortString()
13797 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13798 canQuit = (r.haveState || !r.stateNotNeeded)
13799 && !r.visible && r.stopped;
13800 }
13801 if (canQuit) {
13802 // Finish all of the activities, and then the app itself.
13803 for (j=0; j<NUMA; j++) {
13804 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13805 if (!r.finishing) {
13806 destroyActivityLocked(r, false);
13807 }
13808 r.resultTo = null;
13809 }
13810 Log.i(TAG, "Exiting application process "
13811 + app.processName + " ("
13812 + (app.thread != null ? app.thread.asBinder() : null)
13813 + ")\n");
13814 if (app.pid > 0 && app.pid != MY_PID) {
13815 Process.killProcess(app.pid);
13816 } else {
13817 try {
13818 app.thread.scheduleExit();
13819 } catch (Exception e) {
13820 // Ignore exceptions.
13821 }
13822 }
13823 // todo: For now we assume the application is not buggy
13824 // or evil, and will quit as a result of our request.
13825 // Eventually we need to drive this off of the death
13826 // notification, and kill the process if it takes too long.
13827 cleanUpApplicationRecordLocked(app, false, i);
13828 i--;
13829 //dump();
13830 }
13831 }
13832
13833 }
13834
13835 int curMaxActivities = MAX_ACTIVITIES;
13836 if (mAlwaysFinishActivities) {
13837 curMaxActivities = 1;
13838 }
13839
13840 // Finally, if there are too many activities now running, try to
13841 // finish as many as we can to get back down to the limit.
13842 for ( i=0;
13843 i<mLRUActivities.size()
13844 && mLRUActivities.size() > curMaxActivities;
13845 i++) {
13846 final HistoryRecord r
13847 = (HistoryRecord)mLRUActivities.get(i);
13848
13849 // We can finish this one if we have its icicle saved and
13850 // it is not persistent.
13851 if ((r.haveState || !r.stateNotNeeded) && !r.visible
13852 && r.stopped && !r.persistent && !r.finishing) {
13853 final int origSize = mLRUActivities.size();
13854 destroyActivityLocked(r, true);
13855
13856 // This will remove it from the LRU list, so keep
13857 // our index at the same value. Note that this check to
13858 // see if the size changes is just paranoia -- if
13859 // something unexpected happens, we don't want to end up
13860 // in an infinite loop.
13861 if (origSize > mLRUActivities.size()) {
13862 i--;
13863 }
13864 }
13865 }
13866 }
13867 }
13868
13869 /** This method sends the specified signal to each of the persistent apps */
13870 public void signalPersistentProcesses(int sig) throws RemoteException {
13871 if (sig != Process.SIGNAL_USR1) {
13872 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13873 }
13874
13875 synchronized (this) {
13876 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13877 != PackageManager.PERMISSION_GRANTED) {
13878 throw new SecurityException("Requires permission "
13879 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13880 }
13881
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013882 for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
13883 ProcessRecord r = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013884 if (r.thread != null && r.persistent) {
13885 Process.sendSignal(r.pid, sig);
13886 }
13887 }
13888 }
13889 }
13890
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013891 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013892 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013893
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013894 try {
13895 synchronized (this) {
13896 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13897 // its own permission.
13898 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13899 != PackageManager.PERMISSION_GRANTED) {
13900 throw new SecurityException("Requires permission "
13901 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013902 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013903
13904 if (start && fd == null) {
13905 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013906 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013907
13908 ProcessRecord proc = null;
13909 try {
13910 int pid = Integer.parseInt(process);
13911 synchronized (mPidsSelfLocked) {
13912 proc = mPidsSelfLocked.get(pid);
13913 }
13914 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013915 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013916
13917 if (proc == null) {
13918 HashMap<String, SparseArray<ProcessRecord>> all
13919 = mProcessNames.getMap();
13920 SparseArray<ProcessRecord> procs = all.get(process);
13921 if (procs != null && procs.size() > 0) {
13922 proc = procs.valueAt(0);
13923 }
13924 }
13925
13926 if (proc == null || proc.thread == null) {
13927 throw new IllegalArgumentException("Unknown process: " + process);
13928 }
13929
13930 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
13931 if (isSecure) {
13932 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
13933 throw new SecurityException("Process not debuggable: " + proc);
13934 }
13935 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013936
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013937 proc.thread.profilerControl(start, path, fd);
13938 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013939 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013940 }
13941 } catch (RemoteException e) {
13942 throw new IllegalStateException("Process disappeared");
13943 } finally {
13944 if (fd != null) {
13945 try {
13946 fd.close();
13947 } catch (IOException e) {
13948 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013949 }
13950 }
13951 }
13952
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013953 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13954 public void monitor() {
13955 synchronized (this) { }
13956 }
13957}