blob: a404ec5c7f5426b3a05e6d23153d3b74dae99572 [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;
Dianne Hackborn8f7f35e2010-02-25 18:48:12 -080038import android.app.IActivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.app.IActivityWatcher;
40import android.app.IApplicationThread;
41import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.app.IServiceConnection;
43import android.app.IThumbnailReceiver;
44import android.app.Instrumentation;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070045import android.app.Notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.app.PendingIntent;
47import android.app.ResultInfo;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070048import android.app.Service;
Christopher Tate181fafa2009-05-14 11:12:14 -070049import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020050import android.content.ActivityNotFoundException;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080051import android.content.BroadcastReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052import android.content.ComponentName;
53import android.content.ContentResolver;
54import android.content.Context;
55import android.content.Intent;
56import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070057import android.content.IIntentReceiver;
58import android.content.IIntentSender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -070059import android.content.IntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060import android.content.pm.ActivityInfo;
61import android.content.pm.ApplicationInfo;
62import android.content.pm.ConfigurationInfo;
63import android.content.pm.IPackageDataObserver;
64import android.content.pm.IPackageManager;
65import android.content.pm.InstrumentationInfo;
Dan Egnor66c40e72010-01-26 16:23:11 -080066import android.content.pm.PackageInfo;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070068import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069import android.content.pm.ProviderInfo;
70import android.content.pm.ResolveInfo;
71import android.content.pm.ServiceInfo;
72import android.content.res.Configuration;
73import android.graphics.Bitmap;
74import android.net.Uri;
75import android.os.Binder;
Dan Egnor60d87622009-12-16 16:32:58 -080076import android.os.Build;
Dan Egnor42471dd2010-01-07 17:25:22 -080077import android.os.Bundle;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070078import android.os.Debug;
Dan Egnor60d87622009-12-16 16:32:58 -080079import android.os.DropBoxManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080import android.os.Environment;
Dan Egnor42471dd2010-01-07 17:25:22 -080081import android.os.FileObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082import android.os.FileUtils;
83import android.os.Handler;
84import android.os.IBinder;
85import android.os.IPermissionController;
86import android.os.Looper;
87import android.os.Message;
88import android.os.Parcel;
89import android.os.ParcelFileDescriptor;
90import android.os.PowerManager;
91import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070092import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093import android.os.RemoteException;
94import android.os.ServiceManager;
95import android.os.SystemClock;
96import android.os.SystemProperties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097import android.provider.Settings;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098import android.util.Config;
99import android.util.EventLog;
100import android.util.Log;
101import android.util.PrintWriterPrinter;
102import android.util.SparseArray;
103import android.view.Gravity;
104import android.view.LayoutInflater;
105import android.view.View;
106import android.view.WindowManager;
107import android.view.WindowManagerPolicy;
108
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109import java.io.File;
110import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200112import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113import java.io.PrintWriter;
114import java.lang.IllegalStateException;
115import java.lang.ref.WeakReference;
116import java.util.ArrayList;
117import java.util.HashMap;
118import java.util.HashSet;
119import java.util.Iterator;
120import java.util.List;
121import java.util.Locale;
122import java.util.Map;
123
124public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
125 static final String TAG = "ActivityManager";
126 static final boolean DEBUG = false;
127 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
128 static final boolean DEBUG_SWITCH = localLOGV || false;
129 static final boolean DEBUG_TASKS = localLOGV || false;
130 static final boolean DEBUG_PAUSE = localLOGV || false;
131 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
132 static final boolean DEBUG_TRANSITION = localLOGV || false;
133 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700134 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 static final boolean DEBUG_SERVICE = localLOGV || false;
136 static final boolean DEBUG_VISBILITY = localLOGV || false;
137 static final boolean DEBUG_PROCESSES = localLOGV || false;
Dianne Hackborna1e989b2009-09-01 19:54:29 -0700138 static final boolean DEBUG_PROVIDER = localLOGV || false;
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -0800139 static final boolean DEBUG_URI_PERMISSION = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700141 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate436344a2009-09-30 16:17:37 -0700142 static final boolean DEBUG_BACKUP = localLOGV || false;
Dianne Hackborndc6b6352009-09-30 14:20:09 -0700143 static final boolean DEBUG_CONFIGURATION = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 static final boolean VALIDATE_TOKENS = false;
145 static final boolean SHOW_ACTIVITY_START_TIME = true;
146
147 // Control over CPU and battery monitoring.
148 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
149 static final boolean MONITOR_CPU_USAGE = true;
150 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
151 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
152 static final boolean MONITOR_THREAD_CPU_USAGE = false;
153
Dianne Hackborn1655be42009-05-08 14:29:01 -0700154 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700155 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700156
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 private static final String SYSTEM_SECURE = "ro.secure";
158
159 // This is the maximum number of application processes we would like
160 // to have running. Due to the asynchronous nature of things, we can
161 // temporarily go beyond this limit.
162 static final int MAX_PROCESSES = 2;
163
164 // Set to false to leave processes running indefinitely, relying on
165 // the kernel killing them as resources are required.
166 static final boolean ENFORCE_PROCESS_LIMIT = false;
167
168 // This is the maximum number of activities that we would like to have
169 // running at a given time.
170 static final int MAX_ACTIVITIES = 20;
171
172 // Maximum number of recent tasks that we can remember.
173 static final int MAX_RECENT_TASKS = 20;
174
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700175 // Amount of time after a call to stopAppSwitches() during which we will
176 // prevent further untrusted switches from happening.
177 static final long APP_SWITCH_DELAY_TIME = 5*1000;
178
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179 // How long until we reset a task when the user returns to it. Currently
180 // 30 minutes.
181 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
182
183 // Set to true to disable the icon that is shown while a new activity
184 // is being started.
185 static final boolean SHOW_APP_STARTING_ICON = true;
186
187 // How long we wait until giving up on the last activity to pause. This
188 // is short because it directly impacts the responsiveness of starting the
189 // next activity.
190 static final int PAUSE_TIMEOUT = 500;
191
192 /**
193 * How long we can hold the launch wake lock before giving up.
194 */
195 static final int LAUNCH_TIMEOUT = 10*1000;
196
197 // How long we wait for a launched process to attach to the activity manager
198 // before we decide it's never going to come up for real.
199 static final int PROC_START_TIMEOUT = 10*1000;
200
201 // How long we wait until giving up on the last activity telling us it
202 // is idle.
203 static final int IDLE_TIMEOUT = 10*1000;
204
205 // How long to wait after going idle before forcing apps to GC.
206 static final int GC_TIMEOUT = 5*1000;
207
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700208 // The minimum amount of time between successive GC requests for a process.
209 static final int GC_MIN_INTERVAL = 60*1000;
210
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800211 // How long we wait until giving up on an activity telling us it has
212 // finished destroying itself.
213 static final int DESTROY_TIMEOUT = 10*1000;
214
215 // How long we allow a receiver to run before giving up on it.
216 static final int BROADCAST_TIMEOUT = 10*1000;
217
218 // How long we wait for a service to finish executing.
219 static final int SERVICE_TIMEOUT = 20*1000;
220
221 // How long a service needs to be running until restarting its process
222 // is no longer considered to be a relaunch of the service.
223 static final int SERVICE_RESTART_DURATION = 5*1000;
224
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700225 // How long a service needs to be running until it will start back at
226 // SERVICE_RESTART_DURATION after being killed.
227 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
228
229 // Multiplying factor to increase restart duration time by, for each time
230 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
231 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
232
233 // The minimum amount of time between restarting services that we allow.
234 // That is, when multiple services are restarting, we won't allow each
235 // to restart less than this amount of time from the last one.
236 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
237
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800238 // Maximum amount of time for there to be no activity on a service before
239 // we consider it non-essential and allow its process to go on the
240 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700241 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242
243 // How long we wait until we timeout on key dispatching.
244 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
245
246 // The minimum time we allow between crashes, for us to consider this
247 // application to be bad and stop and its services and reject broadcasts.
248 static final int MIN_CRASH_INTERVAL = 60*1000;
249
250 // How long we wait until we timeout on key dispatching during instrumentation.
251 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
252
253 // OOM adjustments for processes in various states:
254
255 // This is a process without anything currently running in it. Definitely
256 // the first to go! Value set in system/rootdir/init.rc on startup.
257 // This value is initalized in the constructor, careful when refering to
258 // this static variable externally.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800259 static final int EMPTY_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800260
261 // This is a process only hosting activities that are not visible,
262 // so it can be killed without any disruption. Value set in
263 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800264 static final int HIDDEN_APP_MAX_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265 static int HIDDEN_APP_MIN_ADJ;
266
The Android Open Source Project4df24232009-03-05 14:34:35 -0800267 // This is a process holding the home application -- we want to try
268 // avoiding killing it, even if it would normally be in the background,
269 // because the user interacts with it so much.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800270 static final int HOME_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800271
Christopher Tate6fa95972009-06-05 18:43:55 -0700272 // This is a process currently hosting a backup operation. Killing it
273 // is not entirely fatal but is generally a bad idea.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800274 static final int BACKUP_APP_ADJ;
Christopher Tate6fa95972009-06-05 18:43:55 -0700275
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800276 // This is a process holding a secondary server -- killing it will not
277 // have much of an impact as far as the user is concerned. Value set in
278 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800279 static final int SECONDARY_SERVER_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800280
281 // This is a process only hosting activities that are visible to the
282 // user, so we'd prefer they don't disappear. Value set in
283 // system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800284 static final int VISIBLE_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800285
286 // This is the process running the current foreground app. We'd really
287 // rather not kill it! Value set in system/rootdir/init.rc on startup.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800288 static final int FOREGROUND_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800289
290 // This is a process running a core server, such as telephony. Definitely
291 // don't want to kill it, but doing so is not completely fatal.
292 static final int CORE_SERVER_ADJ = -12;
293
294 // The system process runs at the default adjustment.
295 static final int SYSTEM_ADJ = -16;
296
297 // Memory pages are 4K.
298 static final int PAGE_SIZE = 4*1024;
299
300 // Corresponding memory levels for above adjustments.
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800301 static final int EMPTY_APP_MEM;
302 static final int HIDDEN_APP_MEM;
303 static final int HOME_APP_MEM;
304 static final int BACKUP_APP_MEM;
305 static final int SECONDARY_SERVER_MEM;
306 static final int VISIBLE_APP_MEM;
307 static final int FOREGROUND_APP_MEM;
308
309 // The minimum number of hidden apps we want to be able to keep around,
310 // without empty apps being able to push them out of memory.
311 static final int MIN_HIDDEN_APPS = 2;
312
313 // We put empty content processes after any hidden processes that have
314 // been idle for less than 30 seconds.
315 static final long CONTENT_APP_IDLE_OFFSET = 30*1000;
316
317 // We put empty content processes after any hidden processes that have
318 // been idle for less than 60 seconds.
319 static final long EMPTY_APP_IDLE_OFFSET = 60*1000;
320
321 static {
322 // These values are set in system/rootdir/init.rc on startup.
323 FOREGROUND_APP_ADJ =
324 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
325 VISIBLE_APP_ADJ =
326 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
327 SECONDARY_SERVER_ADJ =
328 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
329 BACKUP_APP_ADJ =
330 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
331 HOME_APP_ADJ =
332 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
333 HIDDEN_APP_MIN_ADJ =
334 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
335 EMPTY_APP_ADJ =
336 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
337 HIDDEN_APP_MAX_ADJ = EMPTY_APP_ADJ-1;
338 FOREGROUND_APP_MEM =
339 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
340 VISIBLE_APP_MEM =
341 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
342 SECONDARY_SERVER_MEM =
343 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
344 BACKUP_APP_MEM =
345 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
346 HOME_APP_MEM =
347 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
348 HIDDEN_APP_MEM =
349 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
350 EMPTY_APP_MEM =
351 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
352 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800353
Dan Egnor42471dd2010-01-07 17:25:22 -0800354 static final int MY_PID = Process.myPid();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800355
356 static final String[] EMPTY_STRING_ARRAY = new String[0];
357
358 enum ActivityState {
359 INITIALIZING,
360 RESUMED,
361 PAUSING,
362 PAUSED,
363 STOPPING,
364 STOPPED,
365 FINISHING,
366 DESTROYING,
367 DESTROYED
368 }
369
370 /**
371 * The back history of all previous (and possibly still
372 * running) activities. It contains HistoryRecord objects.
373 */
374 final ArrayList mHistory = new ArrayList();
375
376 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700377 * Description of a request to start a new activity, which has been held
378 * due to app switches being disabled.
379 */
380 class PendingActivityLaunch {
381 HistoryRecord r;
382 HistoryRecord sourceRecord;
383 Uri[] grantedUriPermissions;
384 int grantedMode;
385 boolean onlyIfNeeded;
386 }
387
388 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
389 = new ArrayList<PendingActivityLaunch>();
390
391 /**
Dianne Hackborn8f7f35e2010-02-25 18:48:12 -0800392 * List of people waiting to find out about the next launched activity.
393 */
394 final ArrayList<IActivityManager.WaitResult> mWaitingActivityLaunched
395 = new ArrayList<IActivityManager.WaitResult>();
396
397 /**
398 * List of people waiting to find out about the next visible activity.
399 */
400 final ArrayList<IActivityManager.WaitResult> mWaitingActivityVisible
401 = new ArrayList<IActivityManager.WaitResult>();
402
403 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800404 * List of all active broadcasts that are to be executed immediately
405 * (without waiting for another broadcast to finish). Currently this only
406 * contains broadcasts to registered receivers, to avoid spinning up
407 * a bunch of processes to execute IntentReceiver components.
408 */
409 final ArrayList<BroadcastRecord> mParallelBroadcasts
410 = new ArrayList<BroadcastRecord>();
411
412 /**
413 * List of all active broadcasts that are to be executed one at a time.
414 * The object at the top of the list is the currently activity broadcasts;
415 * those after it are waiting for the top to finish..
416 */
417 final ArrayList<BroadcastRecord> mOrderedBroadcasts
418 = new ArrayList<BroadcastRecord>();
419
420 /**
Dianne Hackborn12527f92009-11-11 17:39:50 -0800421 * Historical data of past broadcasts, for debugging.
422 */
423 static final int MAX_BROADCAST_HISTORY = 100;
424 final BroadcastRecord[] mBroadcastHistory
425 = new BroadcastRecord[MAX_BROADCAST_HISTORY];
426
427 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 * Set when we current have a BROADCAST_INTENT_MSG in flight.
429 */
430 boolean mBroadcastsScheduled = false;
431
432 /**
433 * Set to indicate whether to issue an onUserLeaving callback when a
434 * newly launched activity is being brought in front of us.
435 */
436 boolean mUserLeaving = false;
437
438 /**
439 * When we are in the process of pausing an activity, before starting the
440 * next one, this variable holds the activity that is currently being paused.
441 */
442 HistoryRecord mPausingActivity = null;
443
444 /**
445 * Current activity that is resumed, or null if there is none.
446 */
447 HistoryRecord mResumedActivity = null;
448
449 /**
450 * Activity we have told the window manager to have key focus.
451 */
452 HistoryRecord mFocusedActivity = null;
453
454 /**
455 * This is the last activity that we put into the paused state. This is
456 * used to determine if we need to do an activity transition while sleeping,
457 * when we normally hold the top activity paused.
458 */
459 HistoryRecord mLastPausedActivity = null;
460
461 /**
462 * List of activities that are waiting for a new activity
463 * to become visible before completing whatever operation they are
464 * supposed to do.
465 */
466 final ArrayList mWaitingVisibleActivities = new ArrayList();
467
468 /**
469 * List of activities that are ready to be stopped, but waiting
470 * for the next activity to settle down before doing so. It contains
471 * HistoryRecord objects.
472 */
473 final ArrayList<HistoryRecord> mStoppingActivities
474 = new ArrayList<HistoryRecord>();
475
476 /**
Dianne Hackbornbfe319e2009-09-21 00:34:05 -0700477 * Animations that for the current transition have requested not to
478 * be considered for the transition animation.
479 */
480 final ArrayList<HistoryRecord> mNoAnimActivities
481 = new ArrayList<HistoryRecord>();
482
483 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800484 * List of intents that were used to start the most recent tasks.
485 */
486 final ArrayList<TaskRecord> mRecentTasks
487 = new ArrayList<TaskRecord>();
488
489 /**
490 * List of activities that are ready to be finished, but waiting
491 * for the previous activity to settle down before doing so. It contains
492 * HistoryRecord objects.
493 */
494 final ArrayList mFinishingActivities = new ArrayList();
495
496 /**
497 * All of the applications we currently have running organized by name.
498 * The keys are strings of the application package name (as
499 * returned by the package manager), and the keys are ApplicationRecord
500 * objects.
501 */
502 final ProcessMap<ProcessRecord> mProcessNames
503 = new ProcessMap<ProcessRecord>();
504
505 /**
506 * The last time that various processes have crashed.
507 */
508 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
509
510 /**
511 * Set of applications that we consider to be bad, and will reject
512 * incoming broadcasts from (which the user has no control over).
513 * Processes are added to this set when they have crashed twice within
514 * a minimum amount of time; they are removed from it when they are
515 * later restarted (hopefully due to some user action). The value is the
516 * time it was added to the list.
517 */
518 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
519
520 /**
521 * All of the processes we currently have running organized by pid.
522 * The keys are the pid running the application.
523 *
524 * <p>NOTE: This object is protected by its own lock, NOT the global
525 * activity manager lock!
526 */
527 final SparseArray<ProcessRecord> mPidsSelfLocked
528 = new SparseArray<ProcessRecord>();
529
530 /**
531 * All of the processes that have been forced to be foreground. The key
532 * is the pid of the caller who requested it (we hold a death
533 * link on it).
534 */
535 abstract class ForegroundToken implements IBinder.DeathRecipient {
536 int pid;
537 IBinder token;
538 }
539 final SparseArray<ForegroundToken> mForegroundProcesses
540 = new SparseArray<ForegroundToken>();
541
542 /**
543 * List of records for processes that someone had tried to start before the
544 * system was ready. We don't start them at that point, but ensure they
545 * are started by the time booting is complete.
546 */
547 final ArrayList<ProcessRecord> mProcessesOnHold
548 = new ArrayList<ProcessRecord>();
549
550 /**
551 * List of records for processes that we have started and are waiting
552 * for them to call back. This is really only needed when running in
553 * single processes mode, in which case we do not have a unique pid for
554 * each process.
555 */
556 final ArrayList<ProcessRecord> mStartingProcesses
557 = new ArrayList<ProcessRecord>();
558
559 /**
560 * List of persistent applications that are in the process
561 * of being started.
562 */
563 final ArrayList<ProcessRecord> mPersistentStartingProcesses
564 = new ArrayList<ProcessRecord>();
565
566 /**
567 * Processes that are being forcibly torn down.
568 */
569 final ArrayList<ProcessRecord> mRemovedProcesses
570 = new ArrayList<ProcessRecord>();
571
572 /**
573 * List of running applications, sorted by recent usage.
574 * The first entry in the list is the least recently used.
575 * It contains ApplicationRecord objects. This list does NOT include
576 * any persistent application records (since we never want to exit them).
577 */
Dianne Hackborndd71fc82009-12-16 19:24:32 -0800578 final ArrayList<ProcessRecord> mLruProcesses
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800579 = new ArrayList<ProcessRecord>();
580
581 /**
582 * List of processes that should gc as soon as things are idle.
583 */
584 final ArrayList<ProcessRecord> mProcessesToGc
585 = new ArrayList<ProcessRecord>();
586
587 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800588 * This is the process holding what we currently consider to be
589 * the "home" activity.
590 */
591 private ProcessRecord mHomeProcess;
592
593 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800594 * List of running activities, sorted by recent usage.
595 * The first entry in the list is the least recently used.
596 * It contains HistoryRecord objects.
597 */
598 private final ArrayList mLRUActivities = new ArrayList();
599
600 /**
601 * Set of PendingResultRecord objects that are currently active.
602 */
603 final HashSet mPendingResultRecords = new HashSet();
604
605 /**
606 * Set of IntentSenderRecord objects that are currently active.
607 */
608 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
609 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
610
611 /**
612 * Intent broadcast that we have tried to start, but are
613 * waiting for its application's process to be created. We only
614 * need one (instead of a list) because we always process broadcasts
615 * one at a time, so no others can be started while waiting for this
616 * one.
617 */
618 BroadcastRecord mPendingBroadcast = null;
619
620 /**
621 * Keeps track of all IIntentReceivers that have been registered for
622 * broadcasts. Hash keys are the receiver IBinder, hash value is
623 * a ReceiverList.
624 */
625 final HashMap mRegisteredReceivers = new HashMap();
626
627 /**
628 * Resolver for broadcast intents to registered receivers.
629 * Holds BroadcastFilter (subclass of IntentFilter).
630 */
631 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
632 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
633 @Override
634 protected boolean allowFilterResult(
635 BroadcastFilter filter, List<BroadcastFilter> dest) {
636 IBinder target = filter.receiverList.receiver.asBinder();
637 for (int i=dest.size()-1; i>=0; i--) {
638 if (dest.get(i).receiverList.receiver.asBinder() == target) {
639 return false;
640 }
641 }
642 return true;
643 }
644 };
645
646 /**
647 * State of all active sticky broadcasts. Keys are the action of the
648 * sticky Intent, values are an ArrayList of all broadcasted intents with
649 * that action (which should usually be one).
650 */
651 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
652 new HashMap<String, ArrayList<Intent>>();
653
654 /**
655 * All currently running services.
656 */
657 final HashMap<ComponentName, ServiceRecord> mServices =
658 new HashMap<ComponentName, ServiceRecord>();
659
660 /**
661 * All currently running services indexed by the Intent used to start them.
662 */
663 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
664 new HashMap<Intent.FilterComparison, ServiceRecord>();
665
666 /**
667 * All currently bound service connections. Keys are the IBinder of
668 * the client's IServiceConnection.
669 */
670 final HashMap<IBinder, ConnectionRecord> mServiceConnections
671 = new HashMap<IBinder, ConnectionRecord>();
672
673 /**
674 * List of services that we have been asked to start,
675 * but haven't yet been able to. It is used to hold start requests
676 * while waiting for their corresponding application thread to get
677 * going.
678 */
679 final ArrayList<ServiceRecord> mPendingServices
680 = new ArrayList<ServiceRecord>();
681
682 /**
683 * List of services that are scheduled to restart following a crash.
684 */
685 final ArrayList<ServiceRecord> mRestartingServices
686 = new ArrayList<ServiceRecord>();
687
688 /**
689 * List of services that are in the process of being stopped.
690 */
691 final ArrayList<ServiceRecord> mStoppingServices
692 = new ArrayList<ServiceRecord>();
693
694 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700695 * Backup/restore process management
696 */
697 String mBackupAppName = null;
698 BackupRecord mBackupTarget = null;
699
700 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800701 * List of PendingThumbnailsRecord objects of clients who are still
702 * waiting to receive all of the thumbnails for a task.
703 */
704 final ArrayList mPendingThumbnails = new ArrayList();
705
706 /**
707 * List of HistoryRecord objects that have been finished and must
708 * still report back to a pending thumbnail receiver.
709 */
710 final ArrayList mCancelledThumbnails = new ArrayList();
711
712 /**
713 * All of the currently running global content providers. Keys are a
714 * string containing the provider name and values are a
715 * ContentProviderRecord object containing the data about it. Note
716 * that a single provider may be published under multiple names, so
717 * there may be multiple entries here for a single one in mProvidersByClass.
718 */
719 final HashMap mProvidersByName = new HashMap();
720
721 /**
722 * All of the currently running global content providers. Keys are a
723 * string containing the provider's implementation class and values are a
724 * ContentProviderRecord object containing the data about it.
725 */
726 final HashMap mProvidersByClass = new HashMap();
727
728 /**
729 * List of content providers who have clients waiting for them. The
730 * application is currently being launched and the provider will be
731 * removed from this list once it is published.
732 */
733 final ArrayList mLaunchingProviders = new ArrayList();
734
735 /**
736 * Global set of specific Uri permissions that have been granted.
737 */
738 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
739 = new SparseArray<HashMap<Uri, UriPermission>>();
740
741 /**
742 * Thread-local storage used to carry caller permissions over through
743 * indirect content-provider access.
744 * @see #ActivityManagerService.openContentUri()
745 */
746 private class Identity {
747 public int pid;
748 public int uid;
749
750 Identity(int _pid, int _uid) {
751 pid = _pid;
752 uid = _uid;
753 }
754 }
755 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
756
757 /**
758 * All information we have collected about the runtime performance of
759 * any user id that can impact battery performance.
760 */
761 final BatteryStatsService mBatteryStatsService;
762
763 /**
764 * information about component usage
765 */
766 final UsageStatsService mUsageStatsService;
767
768 /**
769 * Current configuration information. HistoryRecord objects are given
770 * a reference to this object to indicate which configuration they are
771 * currently running in, so this object must be kept immutable.
772 */
773 Configuration mConfiguration = new Configuration();
774
775 /**
Dianne Hackborne36d6e22010-02-17 19:46:25 -0800776 * Current sequencing integer of the configuration, for skipping old
777 * configurations.
778 */
779 int mConfigurationSeq = 0;
780
781 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700782 * Hardware-reported OpenGLES version.
783 */
784 final int GL_ES_VERSION;
785
786 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800787 * List of initialization arguments to pass to all processes when binding applications to them.
788 * For example, references to the commonly used services.
789 */
790 HashMap<String, IBinder> mAppBindArgs;
791
792 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700793 * Temporary to avoid allocations. Protected by main lock.
794 */
795 final StringBuilder mStringBuilder = new StringBuilder(256);
796
797 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800798 * Used to control how we initialize the service.
799 */
800 boolean mStartRunning = false;
801 ComponentName mTopComponent;
802 String mTopAction;
803 String mTopData;
804 boolean mSystemReady = false;
805 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700806 boolean mWaitingUpdate = false;
807 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800808
809 Context mContext;
810
811 int mFactoryTest;
812
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700813 boolean mCheckedForSetup;
814
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700816 * The time at which we will allow normal application switches again,
817 * after a call to {@link #stopAppSwitches()}.
818 */
819 long mAppSwitchesAllowedTime;
820
821 /**
822 * This is set to true after the first switch after mAppSwitchesAllowedTime
823 * is set; any switches after that will clear the time.
824 */
825 boolean mDidAppSwitch;
826
827 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800828 * Set while we are wanting to sleep, to prevent any
829 * activities from being started/resumed.
830 */
831 boolean mSleeping = false;
832
833 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700834 * Set if we are shutting down the system, similar to sleeping.
835 */
836 boolean mShuttingDown = false;
837
838 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800839 * Set when the system is going to sleep, until we have
840 * successfully paused the current activity and released our wake lock.
841 * At that point the system is allowed to actually sleep.
842 */
843 PowerManager.WakeLock mGoingToSleep;
844
845 /**
846 * We don't want to allow the device to go to sleep while in the process
847 * of launching an activity. This is primarily to allow alarm intent
848 * receivers to launch an activity and get that to run before the device
849 * goes back to sleep.
850 */
851 PowerManager.WakeLock mLaunchingActivity;
852
853 /**
854 * Task identifier that activities are currently being started
855 * in. Incremented each time a new task is created.
856 * todo: Replace this with a TokenSpace class that generates non-repeating
857 * integers that won't wrap.
858 */
859 int mCurTask = 1;
860
861 /**
862 * Current sequence id for oom_adj computation traversal.
863 */
864 int mAdjSeq = 0;
865
866 /**
867 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
868 * is set, indicating the user wants processes started in such a way
869 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
870 * running in each process (thus no pre-initialized process, etc).
871 */
872 boolean mSimpleProcessManagement = false;
873
874 /**
875 * System monitoring: number of processes that died since the last
876 * N procs were started.
877 */
878 int[] mProcDeaths = new int[20];
879
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700880 /**
881 * This is set if we had to do a delayed dexopt of an app before launching
882 * it, to increasing the ANR timeouts in that case.
883 */
884 boolean mDidDexOpt;
885
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800886 String mDebugApp = null;
887 boolean mWaitForDebugger = false;
888 boolean mDebugTransient = false;
889 String mOrigDebugApp = null;
890 boolean mOrigWaitForDebugger = false;
891 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700892 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800893
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700894 final RemoteCallbackList<IActivityWatcher> mWatchers
895 = new RemoteCallbackList<IActivityWatcher>();
896
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897 /**
898 * Callback of last caller to {@link #requestPss}.
899 */
900 Runnable mRequestPssCallback;
901
902 /**
903 * Remaining processes for which we are waiting results from the last
904 * call to {@link #requestPss}.
905 */
906 final ArrayList<ProcessRecord> mRequestPssList
907 = new ArrayList<ProcessRecord>();
908
909 /**
910 * Runtime statistics collection thread. This object's lock is used to
911 * protect all related state.
912 */
913 final Thread mProcessStatsThread;
914
915 /**
916 * Used to collect process stats when showing not responding dialog.
917 * Protected by mProcessStatsThread.
918 */
919 final ProcessStats mProcessStats = new ProcessStats(
920 MONITOR_THREAD_CPU_USAGE);
921 long mLastCpuTime = 0;
922 long mLastWriteTime = 0;
923
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700924 long mInitialStartTime = 0;
925
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800926 /**
927 * Set to true after the system has finished booting.
928 */
929 boolean mBooted = false;
930
931 int mProcessLimit = 0;
932
933 WindowManagerService mWindowManager;
934
935 static ActivityManagerService mSelf;
936 static ActivityThread mSystemThread;
937
938 private final class AppDeathRecipient implements IBinder.DeathRecipient {
939 final ProcessRecord mApp;
940 final int mPid;
941 final IApplicationThread mAppThread;
942
943 AppDeathRecipient(ProcessRecord app, int pid,
944 IApplicationThread thread) {
945 if (localLOGV) Log.v(
946 TAG, "New death recipient " + this
947 + " for thread " + thread.asBinder());
948 mApp = app;
949 mPid = pid;
950 mAppThread = thread;
951 }
952
953 public void binderDied() {
954 if (localLOGV) Log.v(
955 TAG, "Death received in " + this
956 + " for thread " + mAppThread.asBinder());
957 removeRequestedPss(mApp);
958 synchronized(ActivityManagerService.this) {
959 appDiedLocked(mApp, mPid, mAppThread);
960 }
961 }
962 }
963
964 static final int SHOW_ERROR_MSG = 1;
965 static final int SHOW_NOT_RESPONDING_MSG = 2;
966 static final int SHOW_FACTORY_ERROR_MSG = 3;
967 static final int UPDATE_CONFIGURATION_MSG = 4;
968 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
969 static final int WAIT_FOR_DEBUGGER_MSG = 6;
970 static final int BROADCAST_INTENT_MSG = 7;
971 static final int BROADCAST_TIMEOUT_MSG = 8;
972 static final int PAUSE_TIMEOUT_MSG = 9;
973 static final int IDLE_TIMEOUT_MSG = 10;
974 static final int IDLE_NOW_MSG = 11;
975 static final int SERVICE_TIMEOUT_MSG = 12;
976 static final int UPDATE_TIME_ZONE = 13;
977 static final int SHOW_UID_ERROR_MSG = 14;
978 static final int IM_FEELING_LUCKY_MSG = 15;
979 static final int LAUNCH_TIMEOUT_MSG = 16;
980 static final int DESTROY_TIMEOUT_MSG = 17;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800981 static final int RESUME_TOP_ACTIVITY_MSG = 19;
982 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700983 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700984 static final int KILL_APPLICATION_MSG = 22;
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -0800985 static final int FINALIZE_PENDING_INTENT_MSG = 23;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800986
987 AlertDialog mUidAlert;
988
989 final Handler mHandler = new Handler() {
990 //public Handler() {
991 // if (localLOGV) Log.v(TAG, "Handler started!");
992 //}
993
994 public void handleMessage(Message msg) {
995 switch (msg.what) {
996 case SHOW_ERROR_MSG: {
997 HashMap data = (HashMap) msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800998 synchronized (ActivityManagerService.this) {
999 ProcessRecord proc = (ProcessRecord)data.get("app");
1000 if (proc != null && proc.crashDialog != null) {
1001 Log.e(TAG, "App already has crash dialog: " + proc);
1002 return;
1003 }
1004 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -07001005 if (!mSleeping && !mShuttingDown) {
Dan Egnorb7f03672009-12-09 16:22:32 -08001006 Dialog d = new AppErrorDialog(mContext, res, proc);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001007 d.show();
1008 proc.crashDialog = d;
1009 } else {
1010 // The device is asleep, so just pretend that the user
1011 // saw a crash dialog and hit "force quit".
1012 res.set(0);
1013 }
1014 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001015
1016 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001017 } break;
1018 case SHOW_NOT_RESPONDING_MSG: {
1019 synchronized (ActivityManagerService.this) {
1020 HashMap data = (HashMap) msg.obj;
1021 ProcessRecord proc = (ProcessRecord)data.get("app");
1022 if (proc != null && proc.anrDialog != null) {
1023 Log.e(TAG, "App already has anr dialog: " + proc);
1024 return;
1025 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001026
1027 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
1028 null, null, 0, null, null, null,
1029 false, false, MY_PID, Process.SYSTEM_UID);
1030
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
1032 mContext, proc, (HistoryRecord)data.get("activity"));
1033 d.show();
1034 proc.anrDialog = d;
1035 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001036
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001037 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001038 } break;
1039 case SHOW_FACTORY_ERROR_MSG: {
1040 Dialog d = new FactoryErrorDialog(
1041 mContext, msg.getData().getCharSequence("msg"));
1042 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001043 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001044 } break;
1045 case UPDATE_CONFIGURATION_MSG: {
1046 final ContentResolver resolver = mContext.getContentResolver();
1047 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1048 } break;
1049 case GC_BACKGROUND_PROCESSES_MSG: {
1050 synchronized (ActivityManagerService.this) {
1051 performAppGcsIfAppropriateLocked();
1052 }
1053 } break;
1054 case WAIT_FOR_DEBUGGER_MSG: {
1055 synchronized (ActivityManagerService.this) {
1056 ProcessRecord app = (ProcessRecord)msg.obj;
1057 if (msg.arg1 != 0) {
1058 if (!app.waitedForDebugger) {
1059 Dialog d = new AppWaitingForDebuggerDialog(
1060 ActivityManagerService.this,
1061 mContext, app);
1062 app.waitDialog = d;
1063 app.waitedForDebugger = true;
1064 d.show();
1065 }
1066 } else {
1067 if (app.waitDialog != null) {
1068 app.waitDialog.dismiss();
1069 app.waitDialog = null;
1070 }
1071 }
1072 }
1073 } break;
1074 case BROADCAST_INTENT_MSG: {
1075 if (DEBUG_BROADCAST) Log.v(
1076 TAG, "Received BROADCAST_INTENT_MSG");
1077 processNextBroadcast(true);
1078 } break;
1079 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001080 if (mDidDexOpt) {
1081 mDidDexOpt = false;
1082 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1083 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1084 return;
1085 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001086 broadcastTimeout();
1087 } break;
1088 case PAUSE_TIMEOUT_MSG: {
1089 IBinder token = (IBinder)msg.obj;
1090 // We don't at this point know if the activity is fullscreen,
1091 // so we need to be conservative and assume it isn't.
1092 Log.w(TAG, "Activity pause timeout for " + token);
1093 activityPaused(token, null, true);
1094 } break;
1095 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001096 if (mDidDexOpt) {
1097 mDidDexOpt = false;
1098 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1099 nmsg.obj = msg.obj;
1100 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1101 return;
1102 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001103 // We don't at this point know if the activity is fullscreen,
1104 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001105 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001106 Log.w(TAG, "Activity idle timeout for " + token);
Dianne Hackborne88846e2009-09-30 21:34:25 -07001107 activityIdleInternal(token, true, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001108 } break;
1109 case DESTROY_TIMEOUT_MSG: {
1110 IBinder token = (IBinder)msg.obj;
1111 // We don't at this point know if the activity is fullscreen,
1112 // so we need to be conservative and assume it isn't.
1113 Log.w(TAG, "Activity destroy timeout for " + token);
1114 activityDestroyed(token);
1115 } break;
1116 case IDLE_NOW_MSG: {
1117 IBinder token = (IBinder)msg.obj;
Dianne Hackborne88846e2009-09-30 21:34:25 -07001118 activityIdle(token, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001119 } break;
1120 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001121 if (mDidDexOpt) {
1122 mDidDexOpt = false;
1123 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1124 nmsg.obj = msg.obj;
1125 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1126 return;
1127 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 serviceTimeout((ProcessRecord)msg.obj);
1129 } break;
1130 case UPDATE_TIME_ZONE: {
1131 synchronized (ActivityManagerService.this) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001132 for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
1133 ProcessRecord r = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001134 if (r.thread != null) {
1135 try {
1136 r.thread.updateTimeZone();
1137 } catch (RemoteException ex) {
1138 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1139 }
1140 }
1141 }
1142 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001143 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001144 case SHOW_UID_ERROR_MSG: {
1145 // XXX This is a temporary dialog, no need to localize.
1146 AlertDialog d = new BaseErrorDialog(mContext);
1147 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1148 d.setCancelable(false);
1149 d.setTitle("System UIDs Inconsistent");
1150 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1151 d.setButton("I'm Feeling Lucky",
1152 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1153 mUidAlert = d;
1154 d.show();
1155 } break;
1156 case IM_FEELING_LUCKY_MSG: {
1157 if (mUidAlert != null) {
1158 mUidAlert.dismiss();
1159 mUidAlert = null;
1160 }
1161 } break;
1162 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001163 if (mDidDexOpt) {
1164 mDidDexOpt = false;
1165 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1166 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1167 return;
1168 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001169 synchronized (ActivityManagerService.this) {
1170 if (mLaunchingActivity.isHeld()) {
1171 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1172 mLaunchingActivity.release();
1173 }
1174 }
1175 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 case RESUME_TOP_ACTIVITY_MSG: {
1177 synchronized (ActivityManagerService.this) {
1178 resumeTopActivityLocked(null);
1179 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001180 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001181 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001182 if (mDidDexOpt) {
1183 mDidDexOpt = false;
1184 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1185 nmsg.obj = msg.obj;
1186 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1187 return;
1188 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001189 ProcessRecord app = (ProcessRecord)msg.obj;
1190 synchronized (ActivityManagerService.this) {
1191 processStartTimedOutLocked(app);
1192 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001193 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001194 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1195 synchronized (ActivityManagerService.this) {
1196 doPendingActivityLaunchesLocked(true);
1197 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001198 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001199 case KILL_APPLICATION_MSG: {
1200 synchronized (ActivityManagerService.this) {
1201 int uid = msg.arg1;
1202 boolean restart = (msg.arg2 == 1);
1203 String pkg = (String) msg.obj;
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001204 forceStopPackageLocked(pkg, uid, restart, false, true);
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001205 }
1206 } break;
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08001207 case FINALIZE_PENDING_INTENT_MSG: {
1208 ((PendingIntentRecord)msg.obj).completeFinalize();
1209 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001210 }
1211 }
1212 };
1213
1214 public static void setSystemProcess() {
1215 try {
1216 ActivityManagerService m = mSelf;
1217
1218 ServiceManager.addService("activity", m);
1219 ServiceManager.addService("meminfo", new MemBinder(m));
1220 if (MONITOR_CPU_USAGE) {
1221 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1222 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001223 ServiceManager.addService("permission", new PermissionController(m));
1224
1225 ApplicationInfo info =
1226 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001227 "android", STOCK_PM_FLAGS);
Mike Cleron432b7132009-09-24 15:28:29 -07001228 mSystemThread.installSystemApplicationInfo(info);
1229
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001230 synchronized (mSelf) {
1231 ProcessRecord app = mSelf.newProcessRecordLocked(
1232 mSystemThread.getApplicationThread(), info,
1233 info.processName);
1234 app.persistent = true;
Dan Egnor42471dd2010-01-07 17:25:22 -08001235 app.pid = MY_PID;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001236 app.maxAdj = SYSTEM_ADJ;
1237 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1238 synchronized (mSelf.mPidsSelfLocked) {
1239 mSelf.mPidsSelfLocked.put(app.pid, app);
1240 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001241 mSelf.updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001242 }
1243 } catch (PackageManager.NameNotFoundException e) {
1244 throw new RuntimeException(
1245 "Unable to find android system package", e);
1246 }
1247 }
1248
1249 public void setWindowManager(WindowManagerService wm) {
1250 mWindowManager = wm;
1251 }
1252
1253 public static final Context main(int factoryTest) {
1254 AThread thr = new AThread();
1255 thr.start();
1256
1257 synchronized (thr) {
1258 while (thr.mService == null) {
1259 try {
1260 thr.wait();
1261 } catch (InterruptedException e) {
1262 }
1263 }
1264 }
1265
1266 ActivityManagerService m = thr.mService;
1267 mSelf = m;
1268 ActivityThread at = ActivityThread.systemMain();
1269 mSystemThread = at;
1270 Context context = at.getSystemContext();
1271 m.mContext = context;
1272 m.mFactoryTest = factoryTest;
1273 PowerManager pm =
1274 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1275 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1276 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1277 m.mLaunchingActivity.setReferenceCounted(false);
1278
1279 m.mBatteryStatsService.publish(context);
1280 m.mUsageStatsService.publish(context);
1281
1282 synchronized (thr) {
1283 thr.mReady = true;
1284 thr.notifyAll();
1285 }
1286
1287 m.startRunning(null, null, null, null);
1288
1289 return context;
1290 }
1291
1292 public static ActivityManagerService self() {
1293 return mSelf;
1294 }
1295
1296 static class AThread extends Thread {
1297 ActivityManagerService mService;
1298 boolean mReady = false;
1299
1300 public AThread() {
1301 super("ActivityManager");
1302 }
1303
1304 public void run() {
1305 Looper.prepare();
1306
1307 android.os.Process.setThreadPriority(
1308 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1309
1310 ActivityManagerService m = new ActivityManagerService();
1311
1312 synchronized (this) {
1313 mService = m;
1314 notifyAll();
1315 }
1316
1317 synchronized (this) {
1318 while (!mReady) {
1319 try {
1320 wait();
1321 } catch (InterruptedException e) {
1322 }
1323 }
1324 }
1325
1326 Looper.loop();
1327 }
1328 }
1329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001330 static class MemBinder extends Binder {
1331 ActivityManagerService mActivityManagerService;
1332 MemBinder(ActivityManagerService activityManagerService) {
1333 mActivityManagerService = activityManagerService;
1334 }
1335
1336 @Override
1337 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1338 ActivityManagerService service = mActivityManagerService;
1339 ArrayList<ProcessRecord> procs;
1340 synchronized (mActivityManagerService) {
1341 if (args != null && args.length > 0
1342 && args[0].charAt(0) != '-') {
1343 procs = new ArrayList<ProcessRecord>();
1344 int pid = -1;
1345 try {
1346 pid = Integer.parseInt(args[0]);
1347 } catch (NumberFormatException e) {
1348
1349 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001350 for (int i=service.mLruProcesses.size()-1; i>=0; i--) {
1351 ProcessRecord proc = service.mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001352 if (proc.pid == pid) {
1353 procs.add(proc);
1354 } else if (proc.processName.equals(args[0])) {
1355 procs.add(proc);
1356 }
1357 }
1358 if (procs.size() <= 0) {
1359 pw.println("No process found for: " + args[0]);
1360 return;
1361 }
1362 } else {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001363 procs = service.mLruProcesses;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001364 }
1365 }
1366 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1367 }
1368 }
1369
1370 static class CpuBinder extends Binder {
1371 ActivityManagerService mActivityManagerService;
1372 CpuBinder(ActivityManagerService activityManagerService) {
1373 mActivityManagerService = activityManagerService;
1374 }
1375
1376 @Override
1377 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1378 synchronized (mActivityManagerService.mProcessStatsThread) {
1379 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1380 }
1381 }
1382 }
1383
1384 private ActivityManagerService() {
1385 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1386 if (v != null && Integer.getInteger(v) != 0) {
1387 mSimpleProcessManagement = true;
1388 }
1389 v = System.getenv("ANDROID_DEBUG_APP");
1390 if (v != null) {
1391 mSimpleProcessManagement = true;
1392 }
1393
Dianne Hackborn2c6c5e62009-10-08 17:55:49 -07001394 Log.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
1395
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001396 File dataDir = Environment.getDataDirectory();
1397 File systemDir = new File(dataDir, "system");
1398 systemDir.mkdirs();
1399 mBatteryStatsService = new BatteryStatsService(new File(
1400 systemDir, "batterystats.bin").toString());
1401 mBatteryStatsService.getActiveStatistics().readLocked();
1402 mBatteryStatsService.getActiveStatistics().writeLocked();
1403
1404 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001405 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001406
Jack Palevichb90d28c2009-07-22 15:35:24 -07001407 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1408 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1409
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08001410 mConfiguration.setToDefaults();
1411 mConfiguration.locale = Locale.getDefault();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001412 mProcessStats.init();
1413
1414 // Add ourself to the Watchdog monitors.
1415 Watchdog.getInstance().addMonitor(this);
1416
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001417 mProcessStatsThread = new Thread("ProcessStats") {
1418 public void run() {
1419 while (true) {
1420 try {
1421 try {
1422 synchronized(this) {
1423 final long now = SystemClock.uptimeMillis();
1424 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1425 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1426 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1427 // + ", write delay=" + nextWriteDelay);
1428 if (nextWriteDelay < nextCpuDelay) {
1429 nextCpuDelay = nextWriteDelay;
1430 }
1431 if (nextCpuDelay > 0) {
1432 this.wait(nextCpuDelay);
1433 }
1434 }
1435 } catch (InterruptedException e) {
1436 }
1437
1438 updateCpuStatsNow();
1439 } catch (Exception e) {
1440 Log.e(TAG, "Unexpected exception collecting process stats", e);
1441 }
1442 }
1443 }
1444 };
1445 mProcessStatsThread.start();
1446 }
1447
1448 @Override
1449 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1450 throws RemoteException {
1451 try {
1452 return super.onTransact(code, data, reply, flags);
1453 } catch (RuntimeException e) {
1454 // The activity manager only throws security exceptions, so let's
1455 // log all others.
1456 if (!(e instanceof SecurityException)) {
1457 Log.e(TAG, "Activity Manager Crash", e);
1458 }
1459 throw e;
1460 }
1461 }
1462
1463 void updateCpuStats() {
1464 synchronized (mProcessStatsThread) {
1465 final long now = SystemClock.uptimeMillis();
1466 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1467 mProcessStatsThread.notify();
1468 }
1469 }
1470 }
1471
1472 void updateCpuStatsNow() {
1473 synchronized (mProcessStatsThread) {
1474 final long now = SystemClock.uptimeMillis();
1475 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001476
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001477 if (MONITOR_CPU_USAGE &&
1478 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1479 mLastCpuTime = now;
1480 haveNewCpuStats = true;
1481 mProcessStats.update();
1482 //Log.i(TAG, mProcessStats.printCurrentState());
1483 //Log.i(TAG, "Total CPU usage: "
1484 // + mProcessStats.getTotalCpuPercent() + "%");
1485
1486 // Log the cpu usage if the property is set.
1487 if ("true".equals(SystemProperties.get("events.cpu"))) {
1488 int user = mProcessStats.getLastUserTime();
1489 int system = mProcessStats.getLastSystemTime();
1490 int iowait = mProcessStats.getLastIoWaitTime();
1491 int irq = mProcessStats.getLastIrqTime();
1492 int softIrq = mProcessStats.getLastSoftIrqTime();
1493 int idle = mProcessStats.getLastIdleTime();
1494
1495 int total = user + system + iowait + irq + softIrq + idle;
1496 if (total == 0) total = 1;
1497
Doug Zongker2bec3d42009-12-04 12:52:44 -08001498 EventLog.writeEvent(EventLogTags.CPU,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001499 ((user+system+iowait+irq+softIrq) * 100) / total,
1500 (user * 100) / total,
1501 (system * 100) / total,
1502 (iowait * 100) / total,
1503 (irq * 100) / total,
1504 (softIrq * 100) / total);
1505 }
1506 }
1507
Amith Yamasanie43530a2009-08-21 13:11:37 -07001508 long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
Amith Yamasani819f9282009-06-24 23:18:15 -07001509 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001510 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001511 synchronized(mPidsSelfLocked) {
1512 if (haveNewCpuStats) {
1513 if (mBatteryStatsService.isOnBattery()) {
1514 final int N = mProcessStats.countWorkingStats();
1515 for (int i=0; i<N; i++) {
1516 ProcessStats.Stats st
1517 = mProcessStats.getWorkingStats(i);
1518 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1519 if (pr != null) {
1520 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1521 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001522 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001523 } else {
1524 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001525 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001526 if (ps != null) {
1527 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001528 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001529 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001530 }
1531 }
1532 }
1533 }
1534 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001535
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001536 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1537 mLastWriteTime = now;
1538 mBatteryStatsService.getActiveStatistics().writeLocked();
1539 }
1540 }
1541 }
1542 }
1543
1544 /**
1545 * Initialize the application bind args. These are passed to each
1546 * process when the bindApplication() IPC is sent to the process. They're
1547 * lazily setup to make sure the services are running when they're asked for.
1548 */
1549 private HashMap<String, IBinder> getCommonServicesLocked() {
1550 if (mAppBindArgs == null) {
1551 mAppBindArgs = new HashMap<String, IBinder>();
1552
1553 // Setup the application init args
1554 mAppBindArgs.put("package", ServiceManager.getService("package"));
1555 mAppBindArgs.put("window", ServiceManager.getService("window"));
1556 mAppBindArgs.put(Context.ALARM_SERVICE,
1557 ServiceManager.getService(Context.ALARM_SERVICE));
1558 }
1559 return mAppBindArgs;
1560 }
1561
1562 private final void setFocusedActivityLocked(HistoryRecord r) {
1563 if (mFocusedActivity != r) {
1564 mFocusedActivity = r;
1565 mWindowManager.setFocusedApp(r, true);
1566 }
1567 }
1568
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001569 private final void updateLruProcessLocked(ProcessRecord app,
1570 boolean oomAdj, boolean updateActivityTime) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001571 // put it on the LRU to keep track of when it should be exited.
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001572 int lrui = mLruProcesses.indexOf(app);
1573 if (lrui >= 0) mLruProcesses.remove(lrui);
1574
1575 int i = mLruProcesses.size()-1;
1576 int skipTop = 0;
1577
1578 // compute the new weight for this process.
1579 if (updateActivityTime) {
1580 app.lastActivityTime = SystemClock.uptimeMillis();
1581 }
1582 if (app.activities.size() > 0) {
1583 // If this process has activities, we more strongly want to keep
1584 // it around.
1585 app.lruWeight = app.lastActivityTime;
1586 } else if (app.pubProviders.size() > 0) {
1587 // If this process contains content providers, we want to keep
1588 // it a little more strongly.
1589 app.lruWeight = app.lastActivityTime - CONTENT_APP_IDLE_OFFSET;
1590 // Also don't let it kick out the first few "real" hidden processes.
1591 skipTop = MIN_HIDDEN_APPS;
1592 } else {
1593 // If this process doesn't have activities, we less strongly
1594 // want to keep it around, and generally want to avoid getting
1595 // in front of any very recently used activities.
1596 app.lruWeight = app.lastActivityTime - EMPTY_APP_IDLE_OFFSET;
1597 // Also don't let it kick out the first few "real" hidden processes.
1598 skipTop = MIN_HIDDEN_APPS;
1599 }
1600 while (i >= 0) {
1601 ProcessRecord p = mLruProcesses.get(i);
1602 // If this app shouldn't be in front of the first N background
1603 // apps, then skip over that many that are currently hidden.
1604 if (skipTop > 0 && p.setAdj >= HIDDEN_APP_MIN_ADJ) {
1605 skipTop--;
1606 }
1607 if (p.lruWeight <= app.lruWeight){
1608 mLruProcesses.add(i+1, app);
1609 break;
1610 }
1611 i--;
1612 }
1613 if (i < 0) {
1614 mLruProcesses.add(0, app);
1615 }
1616
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001617 //Log.i(TAG, "Putting proc to front: " + app.processName);
1618 if (oomAdj) {
1619 updateOomAdjLocked();
1620 }
1621 }
1622
1623 private final boolean updateLRUListLocked(HistoryRecord r) {
1624 final boolean hadit = mLRUActivities.remove(r);
1625 mLRUActivities.add(r);
1626 return hadit;
1627 }
1628
1629 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1630 int i = mHistory.size()-1;
1631 while (i >= 0) {
1632 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1633 if (!r.finishing && r != notTop) {
1634 return r;
1635 }
1636 i--;
1637 }
1638 return null;
1639 }
1640
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001641 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1642 int i = mHistory.size()-1;
1643 while (i >= 0) {
1644 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1645 if (!r.finishing && !r.delayedResume && r != notTop) {
1646 return r;
1647 }
1648 i--;
1649 }
1650 return null;
1651 }
1652
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001653 /**
1654 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001655 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001656 *
1657 * @param token If non-null, any history records matching this token will be skipped.
1658 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1659 *
1660 * @return Returns the HistoryRecord of the next activity on the stack.
1661 */
1662 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1663 int i = mHistory.size()-1;
1664 while (i >= 0) {
1665 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1666 // Note: the taskId check depends on real taskId fields being non-zero
1667 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1668 return r;
1669 }
1670 i--;
1671 }
1672 return null;
1673 }
1674
1675 private final ProcessRecord getProcessRecordLocked(
1676 String processName, int uid) {
1677 if (uid == Process.SYSTEM_UID) {
1678 // The system gets to run in any process. If there are multiple
1679 // processes with the same uid, just pick the first (this
1680 // should never happen).
1681 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1682 processName);
1683 return procs != null ? procs.valueAt(0) : null;
1684 }
1685 ProcessRecord proc = mProcessNames.get(processName, uid);
1686 return proc;
1687 }
1688
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001689 private void ensurePackageDexOpt(String packageName) {
1690 IPackageManager pm = ActivityThread.getPackageManager();
1691 try {
1692 if (pm.performDexOpt(packageName)) {
1693 mDidDexOpt = true;
1694 }
1695 } catch (RemoteException e) {
1696 }
1697 }
1698
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001699 private boolean isNextTransitionForward() {
1700 int transit = mWindowManager.getPendingAppTransition();
1701 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1702 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1703 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1704 }
1705
1706 private final boolean realStartActivityLocked(HistoryRecord r,
1707 ProcessRecord app, boolean andResume, boolean checkConfig)
1708 throws RemoteException {
1709
1710 r.startFreezingScreenLocked(app, 0);
1711 mWindowManager.setAppVisibility(r, true);
1712
1713 // Have the window manager re-evaluate the orientation of
1714 // the screen based on the new activity order. Note that
1715 // as a result of this, it can call back into the activity
1716 // manager with a new orientation. We don't care about that,
1717 // because the activity is not currently running so we are
1718 // just restarting it anyway.
1719 if (checkConfig) {
1720 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001721 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001722 r.mayFreezeScreenLocked(app) ? r : null);
1723 updateConfigurationLocked(config, r);
1724 }
1725
1726 r.app = app;
1727
1728 if (localLOGV) Log.v(TAG, "Launching: " + r);
1729
1730 int idx = app.activities.indexOf(r);
1731 if (idx < 0) {
1732 app.activities.add(r);
1733 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08001734 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001735
1736 try {
1737 if (app.thread == null) {
1738 throw new RemoteException();
1739 }
1740 List<ResultInfo> results = null;
1741 List<Intent> newIntents = null;
1742 if (andResume) {
1743 results = r.results;
1744 newIntents = r.newIntents;
1745 }
1746 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1747 + " icicle=" + r.icicle
1748 + " with results=" + results + " newIntents=" + newIntents
1749 + " andResume=" + andResume);
1750 if (andResume) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08001751 EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001752 System.identityHashCode(r),
1753 r.task.taskId, r.shortComponentName);
1754 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001755 if (r.isHomeActivity) {
1756 mHomeProcess = app;
1757 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001758 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001759 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001760 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001761 r.info, r.icicle, results, newIntents, !andResume,
1762 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001763 } catch (RemoteException e) {
1764 if (r.launchFailed) {
1765 // This is the second time we failed -- finish activity
1766 // and give up.
1767 Log.e(TAG, "Second failure launching "
1768 + r.intent.getComponent().flattenToShortString()
1769 + ", giving up", e);
1770 appDiedLocked(app, app.pid, app.thread);
1771 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1772 "2nd-crash");
1773 return false;
1774 }
1775
1776 // This is the first time we failed -- restart process and
1777 // retry.
1778 app.activities.remove(r);
1779 throw e;
1780 }
1781
1782 r.launchFailed = false;
1783 if (updateLRUListLocked(r)) {
1784 Log.w(TAG, "Activity " + r
1785 + " being launched, but already in LRU list");
1786 }
1787
1788 if (andResume) {
1789 // As part of the process of launching, ActivityThread also performs
1790 // a resume.
1791 r.state = ActivityState.RESUMED;
1792 r.icicle = null;
1793 r.haveState = false;
1794 r.stopped = false;
1795 mResumedActivity = r;
1796 r.task.touchActiveTime();
1797 completeResumeLocked(r);
1798 pauseIfSleepingLocked();
1799 } else {
1800 // This activity is not starting in the resumed state... which
1801 // should look like we asked it to pause+stop (but remain visible),
1802 // and it has done so and reported back the current icicle and
1803 // other state.
1804 r.state = ActivityState.STOPPED;
1805 r.stopped = true;
1806 }
1807
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001808 // Launch the new version setup screen if needed. We do this -after-
1809 // launching the initial activity (that is, home), so that it can have
1810 // a chance to initialize itself while in the background, making the
1811 // switch back to it faster and look better.
1812 startSetupActivityLocked();
1813
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001814 return true;
1815 }
1816
1817 private final void startSpecificActivityLocked(HistoryRecord r,
1818 boolean andResume, boolean checkConfig) {
1819 // Is this activity's application already running?
1820 ProcessRecord app = getProcessRecordLocked(r.processName,
1821 r.info.applicationInfo.uid);
1822
1823 if (r.startTime == 0) {
1824 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001825 if (mInitialStartTime == 0) {
1826 mInitialStartTime = r.startTime;
1827 }
1828 } else if (mInitialStartTime == 0) {
1829 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001830 }
1831
1832 if (app != null && app.thread != null) {
1833 try {
1834 realStartActivityLocked(r, app, andResume, checkConfig);
1835 return;
1836 } catch (RemoteException e) {
1837 Log.w(TAG, "Exception when starting activity "
1838 + r.intent.getComponent().flattenToShortString(), e);
1839 }
1840
1841 // If a dead object exception was thrown -- fall through to
1842 // restart the application.
1843 }
1844
1845 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001846 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001847 }
1848
1849 private final ProcessRecord startProcessLocked(String processName,
1850 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001851 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001852 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1853 // We don't have to do anything more if:
1854 // (1) There is an existing application record; and
1855 // (2) The caller doesn't think it is dead, OR there is no thread
1856 // object attached to it so we know it couldn't have crashed; and
1857 // (3) There is a pid assigned to it, so it is either starting or
1858 // already running.
1859 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1860 + " app=" + app + " knownToBeDead=" + knownToBeDead
1861 + " thread=" + (app != null ? app.thread : null)
1862 + " pid=" + (app != null ? app.pid : -1));
1863 if (app != null &&
1864 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1865 return app;
1866 }
1867
1868 String hostingNameStr = hostingName != null
1869 ? hostingName.flattenToShortString() : null;
1870
1871 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1872 // If we are in the background, then check to see if this process
1873 // is bad. If so, we will just silently fail.
1874 if (mBadProcesses.get(info.processName, info.uid) != null) {
1875 return null;
1876 }
1877 } else {
1878 // When the user is explicitly starting a process, then clear its
1879 // crash count so that we won't make it bad until they see at
1880 // least one crash dialog again, and make the process good again
1881 // if it had been bad.
1882 mProcessCrashTimes.remove(info.processName, info.uid);
1883 if (mBadProcesses.get(info.processName, info.uid) != null) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08001884 EventLog.writeEvent(EventLogTags.AM_PROC_GOOD, info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001885 info.processName);
1886 mBadProcesses.remove(info.processName, info.uid);
1887 if (app != null) {
1888 app.bad = false;
1889 }
1890 }
1891 }
1892
1893 if (app == null) {
1894 app = newProcessRecordLocked(null, info, processName);
1895 mProcessNames.put(processName, info.uid, app);
1896 } else {
1897 // If this is a new package in the process, add the package to the list
1898 app.addPackage(info.packageName);
1899 }
1900
1901 // If the system is not ready yet, then hold off on starting this
1902 // process until it is.
1903 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001904 && !isAllowedWhileBooting(info)
1905 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001906 if (!mProcessesOnHold.contains(app)) {
1907 mProcessesOnHold.add(app);
1908 }
1909 return app;
1910 }
1911
1912 startProcessLocked(app, hostingType, hostingNameStr);
1913 return (app.pid != 0) ? app : null;
1914 }
1915
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001916 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1917 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1918 }
1919
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001920 private final void startProcessLocked(ProcessRecord app,
1921 String hostingType, String hostingNameStr) {
1922 if (app.pid > 0 && app.pid != MY_PID) {
1923 synchronized (mPidsSelfLocked) {
1924 mPidsSelfLocked.remove(app.pid);
1925 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1926 }
1927 app.pid = 0;
1928 }
1929
1930 mProcessesOnHold.remove(app);
1931
1932 updateCpuStats();
1933
1934 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1935 mProcDeaths[0] = 0;
1936
1937 try {
1938 int uid = app.info.uid;
1939 int[] gids = null;
1940 try {
1941 gids = mContext.getPackageManager().getPackageGids(
1942 app.info.packageName);
1943 } catch (PackageManager.NameNotFoundException e) {
1944 Log.w(TAG, "Unable to retrieve gids", e);
1945 }
1946 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1947 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1948 && mTopComponent != null
1949 && app.processName.equals(mTopComponent.getPackageName())) {
1950 uid = 0;
1951 }
1952 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1953 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1954 uid = 0;
1955 }
1956 }
1957 int debugFlags = 0;
1958 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1959 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1960 }
Ben Cheng6c0afff2010-02-14 16:18:56 -08001961 // Run the app in safe mode if its manifest requests so or the
1962 // system is booted in safe mode.
1963 if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 ||
1964 Zygote.systemInSafeMode == true) {
Ben Cheng23085b72010-02-08 16:06:32 -08001965 debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
1966 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001967 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1968 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1969 }
1970 if ("1".equals(SystemProperties.get("debug.assert"))) {
1971 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1972 }
1973 int pid = Process.start("android.app.ActivityThread",
1974 mSimpleProcessManagement ? app.processName : null, uid, uid,
1975 gids, debugFlags, null);
1976 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1977 synchronized (bs) {
1978 if (bs.isOnBattery()) {
1979 app.batteryStats.incStartsLocked();
1980 }
1981 }
1982
Doug Zongker2bec3d42009-12-04 12:52:44 -08001983 EventLog.writeEvent(EventLogTags.AM_PROC_START, pid, uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001984 app.processName, hostingType,
1985 hostingNameStr != null ? hostingNameStr : "");
1986
1987 if (app.persistent) {
1988 Watchdog.getInstance().processStarted(app, app.processName, pid);
1989 }
1990
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001991 StringBuilder buf = mStringBuilder;
1992 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001993 buf.append("Start proc ");
1994 buf.append(app.processName);
1995 buf.append(" for ");
1996 buf.append(hostingType);
1997 if (hostingNameStr != null) {
1998 buf.append(" ");
1999 buf.append(hostingNameStr);
2000 }
2001 buf.append(": pid=");
2002 buf.append(pid);
2003 buf.append(" uid=");
2004 buf.append(uid);
2005 buf.append(" gids={");
2006 if (gids != null) {
2007 for (int gi=0; gi<gids.length; gi++) {
2008 if (gi != 0) buf.append(", ");
2009 buf.append(gids[gi]);
2010
2011 }
2012 }
2013 buf.append("}");
2014 Log.i(TAG, buf.toString());
2015 if (pid == 0 || pid == MY_PID) {
2016 // Processes are being emulated with threads.
2017 app.pid = MY_PID;
2018 app.removed = false;
2019 mStartingProcesses.add(app);
2020 } else if (pid > 0) {
2021 app.pid = pid;
2022 app.removed = false;
2023 synchronized (mPidsSelfLocked) {
2024 this.mPidsSelfLocked.put(pid, app);
2025 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2026 msg.obj = app;
2027 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2028 }
2029 } else {
2030 app.pid = 0;
2031 RuntimeException e = new RuntimeException(
2032 "Failure starting process " + app.processName
2033 + ": returned pid=" + pid);
2034 Log.e(TAG, e.getMessage(), e);
2035 }
2036 } catch (RuntimeException e) {
2037 // XXX do better error recovery.
2038 app.pid = 0;
2039 Log.e(TAG, "Failure starting process " + app.processName, e);
2040 }
2041 }
2042
2043 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2044 if (mPausingActivity != null) {
2045 RuntimeException e = new RuntimeException();
2046 Log.e(TAG, "Trying to pause when pause is already pending for "
2047 + mPausingActivity, e);
2048 }
2049 HistoryRecord prev = mResumedActivity;
2050 if (prev == null) {
2051 RuntimeException e = new RuntimeException();
2052 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2053 resumeTopActivityLocked(null);
2054 return;
2055 }
2056 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2057 mResumedActivity = null;
2058 mPausingActivity = prev;
2059 mLastPausedActivity = prev;
2060 prev.state = ActivityState.PAUSING;
2061 prev.task.touchActiveTime();
2062
2063 updateCpuStats();
2064
2065 if (prev.app != null && prev.app.thread != null) {
2066 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2067 try {
Doug Zongker2bec3d42009-12-04 12:52:44 -08002068 EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002069 System.identityHashCode(prev),
2070 prev.shortComponentName);
2071 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2072 prev.configChangeFlags);
2073 updateUsageStats(prev, false);
2074 } catch (Exception e) {
2075 // Ignore exception, if process died other code will cleanup.
2076 Log.w(TAG, "Exception thrown during pause", e);
2077 mPausingActivity = null;
2078 mLastPausedActivity = null;
2079 }
2080 } else {
2081 mPausingActivity = null;
2082 mLastPausedActivity = null;
2083 }
2084
2085 // If we are not going to sleep, we want to ensure the device is
2086 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002087 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002088 mLaunchingActivity.acquire();
2089 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2090 // To be safe, don't allow the wake lock to be held for too long.
2091 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2092 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2093 }
2094 }
2095
2096
2097 if (mPausingActivity != null) {
2098 // Have the window manager pause its key dispatching until the new
2099 // activity has started. If we're pausing the activity just because
2100 // the screen is being turned off and the UI is sleeping, don't interrupt
2101 // key dispatch; the same activity will pick it up again on wakeup.
2102 if (!uiSleeping) {
2103 prev.pauseKeyDispatchingLocked();
2104 } else {
2105 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2106 }
2107
2108 // Schedule a pause timeout in case the app doesn't respond.
2109 // We don't give it much time because this directly impacts the
2110 // responsiveness seen by the user.
2111 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2112 msg.obj = prev;
2113 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2114 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2115 } else {
2116 // This activity failed to schedule the
2117 // pause, so just treat it as being paused now.
2118 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2119 resumeTopActivityLocked(null);
2120 }
2121 }
2122
2123 private final void completePauseLocked() {
2124 HistoryRecord prev = mPausingActivity;
2125 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2126
2127 if (prev != null) {
2128 if (prev.finishing) {
2129 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2130 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2131 } else if (prev.app != null) {
2132 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2133 if (prev.waitingVisible) {
2134 prev.waitingVisible = false;
2135 mWaitingVisibleActivities.remove(prev);
2136 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2137 TAG, "Complete pause, no longer waiting: " + prev);
2138 }
2139 if (prev.configDestroy) {
2140 // The previous is being paused because the configuration
2141 // is changing, which means it is actually stopping...
2142 // To juggle the fact that we are also starting a new
2143 // instance right now, we need to first completely stop
2144 // the current instance before starting the new one.
2145 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2146 destroyActivityLocked(prev, true);
2147 } else {
2148 mStoppingActivities.add(prev);
2149 if (mStoppingActivities.size() > 3) {
2150 // If we already have a few activities waiting to stop,
2151 // then give up on things going idle and start clearing
2152 // them out.
2153 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2154 Message msg = Message.obtain();
2155 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2156 mHandler.sendMessage(msg);
2157 }
2158 }
2159 } else {
2160 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2161 prev = null;
2162 }
2163 mPausingActivity = null;
2164 }
2165
Dianne Hackborn55280a92009-05-07 15:53:46 -07002166 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002167 resumeTopActivityLocked(prev);
2168 } else {
2169 if (mGoingToSleep.isHeld()) {
2170 mGoingToSleep.release();
2171 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002172 if (mShuttingDown) {
2173 notifyAll();
2174 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002175 }
2176
2177 if (prev != null) {
2178 prev.resumeKeyDispatchingLocked();
2179 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002180
2181 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2182 long diff = 0;
2183 synchronized (mProcessStatsThread) {
2184 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2185 }
2186 if (diff > 0) {
2187 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2188 synchronized (bsi) {
2189 BatteryStatsImpl.Uid.Proc ps =
2190 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2191 prev.info.packageName);
2192 if (ps != null) {
2193 ps.addForegroundTimeLocked(diff);
2194 }
2195 }
2196 }
2197 }
2198 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002199 }
2200
2201 /**
2202 * Once we know that we have asked an application to put an activity in
2203 * the resumed state (either by launching it or explicitly telling it),
2204 * this function updates the rest of our state to match that fact.
2205 */
2206 private final void completeResumeLocked(HistoryRecord next) {
2207 next.idle = false;
2208 next.results = null;
2209 next.newIntents = null;
2210
2211 // schedule an idle timeout in case the app doesn't do it for us.
2212 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2213 msg.obj = next;
2214 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2215
2216 if (false) {
2217 // The activity was never told to pause, so just keep
2218 // things going as-is. To maintain our own state,
2219 // we need to emulate it coming back and saying it is
2220 // idle.
2221 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2222 msg.obj = next;
2223 mHandler.sendMessage(msg);
2224 }
2225
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002226 reportResumedActivityLocked(next);
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002227
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002228 next.thumbnail = null;
2229 setFocusedActivityLocked(next);
2230 next.resumeKeyDispatchingLocked();
2231 ensureActivitiesVisibleLocked(null, 0);
2232 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002233 mNoAnimActivities.clear();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002234
2235 // Mark the point when the activity is resuming
2236 // TODO: To be more accurate, the mark should be before the onCreate,
2237 // not after the onResume. But for subsequent starts, onResume is fine.
2238 if (next.app != null) {
2239 synchronized (mProcessStatsThread) {
2240 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2241 }
2242 } else {
2243 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2244 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002245 }
2246
2247 /**
2248 * Make sure that all activities that need to be visible (that is, they
2249 * currently can be seen by the user) actually are.
2250 */
2251 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2252 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2253 if (DEBUG_VISBILITY) Log.v(
2254 TAG, "ensureActivitiesVisible behind " + top
2255 + " configChanges=0x" + Integer.toHexString(configChanges));
2256
2257 // If the top activity is not fullscreen, then we need to
2258 // make sure any activities under it are now visible.
2259 final int count = mHistory.size();
2260 int i = count-1;
2261 while (mHistory.get(i) != top) {
2262 i--;
2263 }
2264 HistoryRecord r;
2265 boolean behindFullscreen = false;
2266 for (; i>=0; i--) {
2267 r = (HistoryRecord)mHistory.get(i);
2268 if (DEBUG_VISBILITY) Log.v(
2269 TAG, "Make visible? " + r + " finishing=" + r.finishing
2270 + " state=" + r.state);
2271 if (r.finishing) {
2272 continue;
2273 }
2274
2275 final boolean doThisProcess = onlyThisProcess == null
2276 || onlyThisProcess.equals(r.processName);
2277
2278 // First: if this is not the current activity being started, make
2279 // sure it matches the current configuration.
2280 if (r != starting && doThisProcess) {
2281 ensureActivityConfigurationLocked(r, 0);
2282 }
2283
2284 if (r.app == null || r.app.thread == null) {
2285 if (onlyThisProcess == null
2286 || onlyThisProcess.equals(r.processName)) {
2287 // This activity needs to be visible, but isn't even
2288 // running... get it started, but don't resume it
2289 // at this point.
2290 if (DEBUG_VISBILITY) Log.v(
2291 TAG, "Start and freeze screen for " + r);
2292 if (r != starting) {
2293 r.startFreezingScreenLocked(r.app, configChanges);
2294 }
2295 if (!r.visible) {
2296 if (DEBUG_VISBILITY) Log.v(
2297 TAG, "Starting and making visible: " + r);
2298 mWindowManager.setAppVisibility(r, true);
2299 }
2300 if (r != starting) {
2301 startSpecificActivityLocked(r, false, false);
2302 }
2303 }
2304
2305 } else if (r.visible) {
2306 // If this activity is already visible, then there is nothing
2307 // else to do here.
2308 if (DEBUG_VISBILITY) Log.v(
2309 TAG, "Skipping: already visible at " + r);
2310 r.stopFreezingScreenLocked(false);
2311
2312 } else if (onlyThisProcess == null) {
2313 // This activity is not currently visible, but is running.
2314 // Tell it to become visible.
2315 r.visible = true;
2316 if (r.state != ActivityState.RESUMED && r != starting) {
2317 // If this activity is paused, tell it
2318 // to now show its window.
2319 if (DEBUG_VISBILITY) Log.v(
2320 TAG, "Making visible and scheduling visibility: " + r);
2321 try {
2322 mWindowManager.setAppVisibility(r, true);
2323 r.app.thread.scheduleWindowVisibility(r, true);
2324 r.stopFreezingScreenLocked(false);
2325 } catch (Exception e) {
2326 // Just skip on any failure; we'll make it
2327 // visible when it next restarts.
2328 Log.w(TAG, "Exception thrown making visibile: "
2329 + r.intent.getComponent(), e);
2330 }
2331 }
2332 }
2333
2334 // Aggregate current change flags.
2335 configChanges |= r.configChangeFlags;
2336
2337 if (r.fullscreen) {
2338 // At this point, nothing else needs to be shown
2339 if (DEBUG_VISBILITY) Log.v(
2340 TAG, "Stopping: fullscreen at " + r);
2341 behindFullscreen = true;
2342 i--;
2343 break;
2344 }
2345 }
2346
2347 // Now for any activities that aren't visible to the user, make
2348 // sure they no longer are keeping the screen frozen.
2349 while (i >= 0) {
2350 r = (HistoryRecord)mHistory.get(i);
2351 if (DEBUG_VISBILITY) Log.v(
2352 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2353 + " state=" + r.state
2354 + " behindFullscreen=" + behindFullscreen);
2355 if (!r.finishing) {
2356 if (behindFullscreen) {
2357 if (r.visible) {
2358 if (DEBUG_VISBILITY) Log.v(
2359 TAG, "Making invisible: " + r);
2360 r.visible = false;
2361 try {
2362 mWindowManager.setAppVisibility(r, false);
2363 if ((r.state == ActivityState.STOPPING
2364 || r.state == ActivityState.STOPPED)
2365 && r.app != null && r.app.thread != null) {
2366 if (DEBUG_VISBILITY) Log.v(
2367 TAG, "Scheduling invisibility: " + r);
2368 r.app.thread.scheduleWindowVisibility(r, false);
2369 }
2370 } catch (Exception e) {
2371 // Just skip on any failure; we'll make it
2372 // visible when it next restarts.
2373 Log.w(TAG, "Exception thrown making hidden: "
2374 + r.intent.getComponent(), e);
2375 }
2376 } else {
2377 if (DEBUG_VISBILITY) Log.v(
2378 TAG, "Already invisible: " + r);
2379 }
2380 } else if (r.fullscreen) {
2381 if (DEBUG_VISBILITY) Log.v(
2382 TAG, "Now behindFullscreen: " + r);
2383 behindFullscreen = true;
2384 }
2385 }
2386 i--;
2387 }
2388 }
2389
2390 /**
2391 * Version of ensureActivitiesVisible that can easily be called anywhere.
2392 */
2393 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2394 int configChanges) {
2395 HistoryRecord r = topRunningActivityLocked(null);
2396 if (r != null) {
2397 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2398 }
2399 }
2400
2401 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2402 if (resumed) {
2403 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2404 } else {
2405 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2406 }
2407 }
2408
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002409 private boolean startHomeActivityLocked() {
2410 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2411 && mTopAction == null) {
2412 // We are running in factory test mode, but unable to find
2413 // the factory test app, so just sit around displaying the
2414 // error message and don't try to start anything.
2415 return false;
2416 }
2417 Intent intent = new Intent(
2418 mTopAction,
2419 mTopData != null ? Uri.parse(mTopData) : null);
2420 intent.setComponent(mTopComponent);
2421 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2422 intent.addCategory(Intent.CATEGORY_HOME);
2423 }
2424 ActivityInfo aInfo =
2425 intent.resolveActivityInfo(mContext.getPackageManager(),
2426 STOCK_PM_FLAGS);
2427 if (aInfo != null) {
2428 intent.setComponent(new ComponentName(
2429 aInfo.applicationInfo.packageName, aInfo.name));
2430 // Don't do this if the home app is currently being
2431 // instrumented.
2432 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2433 aInfo.applicationInfo.uid);
2434 if (app == null || app.instrumentationClass == null) {
2435 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2436 startActivityLocked(null, intent, null, null, 0, aInfo,
2437 null, null, 0, 0, 0, false, false);
2438 }
2439 }
2440
2441
2442 return true;
2443 }
2444
2445 /**
2446 * Starts the "new version setup screen" if appropriate.
2447 */
2448 private void startSetupActivityLocked() {
2449 // Only do this once per boot.
2450 if (mCheckedForSetup) {
2451 return;
2452 }
2453
2454 // We will show this screen if the current one is a different
2455 // version than the last one shown, and we are not running in
2456 // low-level factory test mode.
2457 final ContentResolver resolver = mContext.getContentResolver();
2458 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2459 Settings.Secure.getInt(resolver,
2460 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2461 mCheckedForSetup = true;
2462
2463 // See if we should be showing the platform update setup UI.
2464 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2465 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2466 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2467
2468 // We don't allow third party apps to replace this.
2469 ResolveInfo ri = null;
2470 for (int i=0; ris != null && i<ris.size(); i++) {
2471 if ((ris.get(i).activityInfo.applicationInfo.flags
2472 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2473 ri = ris.get(i);
2474 break;
2475 }
2476 }
2477
2478 if (ri != null) {
2479 String vers = ri.activityInfo.metaData != null
2480 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2481 : null;
2482 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2483 vers = ri.activityInfo.applicationInfo.metaData.getString(
2484 Intent.METADATA_SETUP_VERSION);
2485 }
2486 String lastVers = Settings.Secure.getString(
2487 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2488 if (vers != null && !vers.equals(lastVers)) {
2489 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2490 intent.setComponent(new ComponentName(
2491 ri.activityInfo.packageName, ri.activityInfo.name));
2492 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2493 null, null, 0, 0, 0, false, false);
2494 }
2495 }
2496 }
2497 }
2498
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002499 private void reportResumedActivityLocked(HistoryRecord r) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002500 //Log.i(TAG, "**** REPORT RESUME: " + r);
2501
2502 final int identHash = System.identityHashCode(r);
2503 updateUsageStats(r, true);
2504
2505 int i = mWatchers.beginBroadcast();
2506 while (i > 0) {
2507 i--;
2508 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2509 if (w != null) {
2510 try {
2511 w.activityResuming(identHash);
2512 } catch (RemoteException e) {
2513 }
2514 }
2515 }
2516 mWatchers.finishBroadcast();
2517 }
2518
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002519 /**
2520 * Ensure that the top activity in the stack is resumed.
2521 *
2522 * @param prev The previously resumed activity, for when in the process
2523 * of pausing; can be null to call from elsewhere.
2524 *
2525 * @return Returns true if something is being resumed, or false if
2526 * nothing happened.
2527 */
2528 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2529 // Find the first activity that is not finishing.
2530 HistoryRecord next = topRunningActivityLocked(null);
2531
2532 // Remember how we'll process this pause/resume situation, and ensure
2533 // that the state is reset however we wind up proceeding.
2534 final boolean userLeaving = mUserLeaving;
2535 mUserLeaving = false;
2536
2537 if (next == null) {
2538 // There are no more activities! Let's just start up the
2539 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002540 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002541 }
2542
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002543 next.delayedResume = false;
2544
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002545 // If the top activity is the resumed one, nothing to do.
2546 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2547 // Make sure we have executed any pending transitions, since there
2548 // should be nothing left to do at this point.
2549 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002550 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002551 return false;
2552 }
2553
2554 // If we are sleeping, and there is no resumed activity, and the top
2555 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002556 if ((mSleeping || mShuttingDown)
2557 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002558 // Make sure we have executed any pending transitions, since there
2559 // should be nothing left to do at this point.
2560 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002561 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002562 return false;
2563 }
2564
2565 // The activity may be waiting for stop, but that is no longer
2566 // appropriate for it.
2567 mStoppingActivities.remove(next);
2568 mWaitingVisibleActivities.remove(next);
2569
2570 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2571
2572 // If we are currently pausing an activity, then don't do anything
2573 // until that is done.
2574 if (mPausingActivity != null) {
2575 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2576 return false;
2577 }
2578
2579 // We need to start pausing the current activity so the top one
2580 // can be resumed...
2581 if (mResumedActivity != null) {
2582 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2583 startPausingLocked(userLeaving, false);
2584 return true;
2585 }
2586
2587 if (prev != null && prev != next) {
2588 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2589 prev.waitingVisible = true;
2590 mWaitingVisibleActivities.add(prev);
2591 if (DEBUG_SWITCH) Log.v(
2592 TAG, "Resuming top, waiting visible to hide: " + prev);
2593 } else {
2594 // The next activity is already visible, so hide the previous
2595 // activity's windows right now so we can show the new one ASAP.
2596 // We only do this if the previous is finishing, which should mean
2597 // it is on top of the one being resumed so hiding it quickly
2598 // is good. Otherwise, we want to do the normal route of allowing
2599 // the resumed activity to be shown so we can decide if the
2600 // previous should actually be hidden depending on whether the
2601 // new one is found to be full-screen or not.
2602 if (prev.finishing) {
2603 mWindowManager.setAppVisibility(prev, false);
2604 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2605 + prev + ", waitingVisible="
2606 + (prev != null ? prev.waitingVisible : null)
2607 + ", nowVisible=" + next.nowVisible);
2608 } else {
2609 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2610 + prev + ", waitingVisible="
2611 + (prev != null ? prev.waitingVisible : null)
2612 + ", nowVisible=" + next.nowVisible);
2613 }
2614 }
2615 }
2616
2617 // We are starting up the next activity, so tell the window manager
2618 // that the previous one will be hidden soon. This way it can know
2619 // to ignore it when computing the desired screen orientation.
2620 if (prev != null) {
2621 if (prev.finishing) {
2622 if (DEBUG_TRANSITION) Log.v(TAG,
2623 "Prepare close transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002624 if (mNoAnimActivities.contains(prev)) {
2625 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2626 } else {
2627 mWindowManager.prepareAppTransition(prev.task == next.task
2628 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2629 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2630 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002631 mWindowManager.setAppWillBeHidden(prev);
2632 mWindowManager.setAppVisibility(prev, false);
2633 } else {
2634 if (DEBUG_TRANSITION) Log.v(TAG,
2635 "Prepare open transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002636 if (mNoAnimActivities.contains(next)) {
2637 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2638 } else {
2639 mWindowManager.prepareAppTransition(prev.task == next.task
2640 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2641 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2642 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002643 }
2644 if (false) {
2645 mWindowManager.setAppWillBeHidden(prev);
2646 mWindowManager.setAppVisibility(prev, false);
2647 }
2648 } else if (mHistory.size() > 1) {
2649 if (DEBUG_TRANSITION) Log.v(TAG,
2650 "Prepare open transition: no previous");
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002651 if (mNoAnimActivities.contains(next)) {
2652 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2653 } else {
2654 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2655 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002656 }
2657
2658 if (next.app != null && next.app.thread != null) {
2659 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2660
2661 // This activity is now becoming visible.
2662 mWindowManager.setAppVisibility(next, true);
2663
2664 HistoryRecord lastResumedActivity = mResumedActivity;
2665 ActivityState lastState = next.state;
2666
2667 updateCpuStats();
2668
2669 next.state = ActivityState.RESUMED;
2670 mResumedActivity = next;
2671 next.task.touchActiveTime();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08002672 updateLruProcessLocked(next.app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002673 updateLRUListLocked(next);
2674
2675 // Have the window manager re-evaluate the orientation of
2676 // the screen based on the new activity order.
Eric Fischerd4d04de2009-10-27 18:55:57 -07002677 boolean updated;
2678 synchronized (this) {
2679 Configuration config = mWindowManager.updateOrientationFromAppTokens(
2680 mConfiguration,
2681 next.mayFreezeScreenLocked(next.app) ? next : null);
2682 if (config != null) {
Eric Fischerd4d04de2009-10-27 18:55:57 -07002683 next.frozenBeforeDestroy = true;
2684 }
2685 updated = updateConfigurationLocked(config, next);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002686 }
Eric Fischerd4d04de2009-10-27 18:55:57 -07002687 if (!updated) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002688 // The configuration update wasn't able to keep the existing
2689 // instance of the activity, and instead started a new one.
2690 // We should be all done, but let's just make sure our activity
2691 // is still at the top and schedule another run if something
2692 // weird happened.
2693 HistoryRecord nextNext = topRunningActivityLocked(null);
2694 if (DEBUG_SWITCH) Log.i(TAG,
2695 "Activity config changed during resume: " + next
2696 + ", new next: " + nextNext);
2697 if (nextNext != next) {
2698 // Do over!
2699 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2700 }
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07002701 setFocusedActivityLocked(next);
2702 ensureActivitiesVisibleLocked(null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002703 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002704 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002705 return true;
2706 }
2707
2708 try {
2709 // Deliver all pending results.
2710 ArrayList a = next.results;
2711 if (a != null) {
2712 final int N = a.size();
2713 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002714 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002715 TAG, "Delivering results to " + next
2716 + ": " + a);
2717 next.app.thread.scheduleSendResult(next, a);
2718 }
2719 }
2720
2721 if (next.newIntents != null) {
2722 next.app.thread.scheduleNewIntent(next.newIntents, next);
2723 }
2724
Doug Zongker2bec3d42009-12-04 12:52:44 -08002725 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002726 System.identityHashCode(next),
2727 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002728
2729 next.app.thread.scheduleResumeActivity(next,
2730 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002731
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002732 pauseIfSleepingLocked();
2733
2734 } catch (Exception e) {
2735 // Whoops, need to restart this activity!
2736 next.state = lastState;
2737 mResumedActivity = lastResumedActivity;
Dianne Hackborn03abb812010-01-04 18:43:19 -08002738 Log.i(TAG, "Restarting because process died: " + next);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002739 if (!next.hasBeenLaunched) {
2740 next.hasBeenLaunched = true;
2741 } else {
2742 if (SHOW_APP_STARTING_ICON) {
2743 mWindowManager.setAppStartingWindow(
2744 next, next.packageName, next.theme,
2745 next.nonLocalizedLabel,
2746 next.labelRes, next.icon, null, true);
2747 }
2748 }
2749 startSpecificActivityLocked(next, true, false);
2750 return true;
2751 }
2752
2753 // From this point on, if something goes wrong there is no way
2754 // to recover the activity.
2755 try {
2756 next.visible = true;
2757 completeResumeLocked(next);
2758 } catch (Exception e) {
2759 // If any exception gets thrown, toss away this
2760 // activity and try the next one.
2761 Log.w(TAG, "Exception thrown during resume of " + next, e);
2762 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2763 "resume-exception");
2764 return true;
2765 }
2766
2767 // Didn't need to use the icicle, and it is now out of date.
2768 next.icicle = null;
2769 next.haveState = false;
2770 next.stopped = false;
2771
2772 } else {
2773 // Whoops, need to restart this activity!
2774 if (!next.hasBeenLaunched) {
2775 next.hasBeenLaunched = true;
2776 } else {
2777 if (SHOW_APP_STARTING_ICON) {
2778 mWindowManager.setAppStartingWindow(
2779 next, next.packageName, next.theme,
2780 next.nonLocalizedLabel,
2781 next.labelRes, next.icon, null, true);
2782 }
2783 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2784 }
2785 startSpecificActivityLocked(next, true, true);
2786 }
2787
2788 return true;
2789 }
2790
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002791 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2792 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002793 final int NH = mHistory.size();
2794
2795 int addPos = -1;
2796
2797 if (!newTask) {
2798 // If starting in an existing task, find where that is...
2799 HistoryRecord next = null;
2800 boolean startIt = true;
2801 for (int i = NH-1; i >= 0; i--) {
2802 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2803 if (p.finishing) {
2804 continue;
2805 }
2806 if (p.task == r.task) {
2807 // Here it is! Now, if this is not yet visible to the
2808 // user, then just add it without starting; it will
2809 // get started when the user navigates back to it.
2810 addPos = i+1;
2811 if (!startIt) {
2812 mHistory.add(addPos, r);
2813 r.inHistory = true;
2814 r.task.numActivities++;
2815 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2816 r.info.screenOrientation, r.fullscreen);
2817 if (VALIDATE_TOKENS) {
2818 mWindowManager.validateAppTokens(mHistory);
2819 }
2820 return;
2821 }
2822 break;
2823 }
2824 if (p.fullscreen) {
2825 startIt = false;
2826 }
2827 next = p;
2828 }
2829 }
2830
2831 // Place a new activity at top of stack, so it is next to interact
2832 // with the user.
2833 if (addPos < 0) {
2834 addPos = mHistory.size();
2835 }
2836
2837 // If we are not placing the new activity frontmost, we do not want
2838 // to deliver the onUserLeaving callback to the actual frontmost
2839 // activity
2840 if (addPos < NH) {
2841 mUserLeaving = false;
2842 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2843 }
2844
2845 // Slot the activity into the history stack and proceed
2846 mHistory.add(addPos, r);
2847 r.inHistory = true;
2848 r.frontOfTask = newTask;
2849 r.task.numActivities++;
2850 if (NH > 0) {
2851 // We want to show the starting preview window if we are
2852 // switching to a new task, or the next activity's process is
2853 // not currently running.
2854 boolean showStartingIcon = newTask;
2855 ProcessRecord proc = r.app;
2856 if (proc == null) {
2857 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2858 }
2859 if (proc == null || proc.thread == null) {
2860 showStartingIcon = true;
2861 }
2862 if (DEBUG_TRANSITION) Log.v(TAG,
2863 "Prepare open transition: starting " + r);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002864 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
2865 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2866 mNoAnimActivities.add(r);
2867 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
2868 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
2869 mNoAnimActivities.remove(r);
2870 } else {
2871 mWindowManager.prepareAppTransition(newTask
2872 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2873 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2874 mNoAnimActivities.remove(r);
2875 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002876 mWindowManager.addAppToken(
2877 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2878 boolean doShow = true;
2879 if (newTask) {
2880 // Even though this activity is starting fresh, we still need
2881 // to reset it to make sure we apply affinities to move any
2882 // existing activities from other tasks in to it.
2883 // If the caller has requested that the target task be
2884 // reset, then do so.
2885 if ((r.intent.getFlags()
2886 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2887 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002888 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002889 }
2890 }
2891 if (SHOW_APP_STARTING_ICON && doShow) {
2892 // Figure out if we are transitioning from another activity that is
2893 // "has the same starting icon" as the next one. This allows the
2894 // window manager to keep the previous window it had previously
2895 // created, if it still had one.
2896 HistoryRecord prev = mResumedActivity;
2897 if (prev != null) {
2898 // We don't want to reuse the previous starting preview if:
2899 // (1) The current activity is in a different task.
2900 if (prev.task != r.task) prev = null;
2901 // (2) The current activity is already displayed.
2902 else if (prev.nowVisible) prev = null;
2903 }
2904 mWindowManager.setAppStartingWindow(
2905 r, r.packageName, r.theme, r.nonLocalizedLabel,
2906 r.labelRes, r.icon, prev, showStartingIcon);
2907 }
2908 } else {
2909 // If this is the first activity, don't do any fancy animations,
2910 // because there is nothing for it to animate on top of.
2911 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2912 r.info.screenOrientation, r.fullscreen);
2913 }
2914 if (VALIDATE_TOKENS) {
2915 mWindowManager.validateAppTokens(mHistory);
2916 }
2917
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002918 if (doResume) {
2919 resumeTopActivityLocked(null);
2920 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002921 }
2922
2923 /**
2924 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002925 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2926 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002927 * an instance of that activity in the stack and, if found, finish all
2928 * activities on top of it and return the instance.
2929 *
2930 * @param newR Description of the new activity being started.
2931 * @return Returns the old activity that should be continue to be used,
2932 * or null if none was found.
2933 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002934 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002935 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002936 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002937
2938 // First find the requested task.
2939 while (i > 0) {
2940 i--;
2941 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2942 if (r.task.taskId == taskId) {
2943 i++;
2944 break;
2945 }
2946 }
2947
2948 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002949 while (i > 0) {
2950 i--;
2951 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2952 if (r.finishing) {
2953 continue;
2954 }
2955 if (r.task.taskId != taskId) {
2956 return null;
2957 }
2958 if (r.realActivity.equals(newR.realActivity)) {
2959 // Here it is! Now finish everything in front...
2960 HistoryRecord ret = r;
2961 if (doClear) {
2962 while (i < (mHistory.size()-1)) {
2963 i++;
2964 r = (HistoryRecord)mHistory.get(i);
2965 if (r.finishing) {
2966 continue;
2967 }
2968 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2969 null, "clear")) {
2970 i--;
2971 }
2972 }
2973 }
2974
2975 // Finally, if this is a normal launch mode (that is, not
2976 // expecting onNewIntent()), then we will finish the current
2977 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002978 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
2979 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002980 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002981 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002982 if (index >= 0) {
2983 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2984 null, "clear");
2985 }
2986 return null;
2987 }
2988 }
2989
2990 return ret;
2991 }
2992 }
2993
2994 return null;
2995 }
2996
2997 /**
2998 * Find the activity in the history stack within the given task. Returns
2999 * the index within the history at which it's found, or < 0 if not found.
3000 */
3001 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
3002 int i = mHistory.size();
3003 while (i > 0) {
3004 i--;
3005 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
3006 if (candidate.task.taskId != task) {
3007 break;
3008 }
3009 if (candidate.realActivity.equals(r.realActivity)) {
3010 return i;
3011 }
3012 }
3013
3014 return -1;
3015 }
3016
3017 /**
3018 * Reorder the history stack so that the activity at the given index is
3019 * brought to the front.
3020 */
3021 private final HistoryRecord moveActivityToFrontLocked(int where) {
3022 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3023 int top = mHistory.size();
3024 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3025 mHistory.add(top, newTop);
3026 oldTop.frontOfTask = false;
3027 newTop.frontOfTask = true;
3028 return newTop;
3029 }
3030
3031 /**
3032 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3033 * method will be called at the proper time.
3034 */
3035 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3036 boolean sent = false;
3037 if (r.state == ActivityState.RESUMED
3038 && r.app != null && r.app.thread != null) {
3039 try {
3040 ArrayList<Intent> ar = new ArrayList<Intent>();
3041 ar.add(new Intent(intent));
3042 r.app.thread.scheduleNewIntent(ar, r);
3043 sent = true;
3044 } catch (Exception e) {
3045 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3046 }
3047 }
3048 if (!sent) {
3049 r.addNewIntentLocked(new Intent(intent));
3050 }
3051 }
3052
3053 private final void logStartActivity(int tag, HistoryRecord r,
3054 TaskRecord task) {
3055 EventLog.writeEvent(tag,
3056 System.identityHashCode(r), task.taskId,
3057 r.shortComponentName, r.intent.getAction(),
3058 r.intent.getType(), r.intent.getDataString(),
3059 r.intent.getFlags());
3060 }
3061
3062 private final int startActivityLocked(IApplicationThread caller,
3063 Intent intent, String resolvedType,
3064 Uri[] grantedUriPermissions,
3065 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3066 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003067 int callingPid, int callingUid, boolean onlyIfNeeded,
3068 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003069 Log.i(TAG, "Starting activity: " + intent);
3070
3071 HistoryRecord sourceRecord = null;
3072 HistoryRecord resultRecord = null;
3073 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003074 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003075 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003076 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3077 if (index >= 0) {
3078 sourceRecord = (HistoryRecord)mHistory.get(index);
3079 if (requestCode >= 0 && !sourceRecord.finishing) {
3080 resultRecord = sourceRecord;
3081 }
3082 }
3083 }
3084
3085 int launchFlags = intent.getFlags();
3086
3087 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3088 && sourceRecord != null) {
3089 // Transfer the result target from the source activity to the new
3090 // one being started, including any failures.
3091 if (requestCode >= 0) {
3092 return START_FORWARD_AND_REQUEST_CONFLICT;
3093 }
3094 resultRecord = sourceRecord.resultTo;
3095 resultWho = sourceRecord.resultWho;
3096 requestCode = sourceRecord.requestCode;
3097 sourceRecord.resultTo = null;
3098 if (resultRecord != null) {
3099 resultRecord.removeResultsLocked(
3100 sourceRecord, resultWho, requestCode);
3101 }
3102 }
3103
3104 int err = START_SUCCESS;
3105
3106 if (intent.getComponent() == null) {
3107 // We couldn't find a class that can handle the given Intent.
3108 // That's the end of that!
3109 err = START_INTENT_NOT_RESOLVED;
3110 }
3111
3112 if (err == START_SUCCESS && aInfo == null) {
3113 // We couldn't find the specific class specified in the Intent.
3114 // Also the end of the line.
3115 err = START_CLASS_NOT_FOUND;
3116 }
3117
3118 ProcessRecord callerApp = null;
3119 if (err == START_SUCCESS && caller != null) {
3120 callerApp = getRecordForAppLocked(caller);
3121 if (callerApp != null) {
3122 callingPid = callerApp.pid;
3123 callingUid = callerApp.info.uid;
3124 } else {
3125 Log.w(TAG, "Unable to find app for caller " + caller
3126 + " (pid=" + callingPid + ") when starting: "
3127 + intent.toString());
3128 err = START_PERMISSION_DENIED;
3129 }
3130 }
3131
3132 if (err != START_SUCCESS) {
3133 if (resultRecord != null) {
3134 sendActivityResultLocked(-1,
3135 resultRecord, resultWho, requestCode,
3136 Activity.RESULT_CANCELED, null);
3137 }
3138 return err;
3139 }
3140
3141 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3142 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3143 if (perm != PackageManager.PERMISSION_GRANTED) {
3144 if (resultRecord != null) {
3145 sendActivityResultLocked(-1,
3146 resultRecord, resultWho, requestCode,
3147 Activity.RESULT_CANCELED, null);
3148 }
3149 String msg = "Permission Denial: starting " + intent.toString()
3150 + " from " + callerApp + " (pid=" + callingPid
3151 + ", uid=" + callingUid + ")"
3152 + " requires " + aInfo.permission;
3153 Log.w(TAG, msg);
3154 throw new SecurityException(msg);
3155 }
3156
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003157 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003158 boolean abort = false;
3159 try {
3160 // The Intent we give to the watcher has the extra data
3161 // stripped off, since it can contain private information.
3162 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003163 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003164 aInfo.applicationInfo.packageName);
3165 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003166 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003167 }
3168
3169 if (abort) {
3170 if (resultRecord != null) {
3171 sendActivityResultLocked(-1,
3172 resultRecord, resultWho, requestCode,
3173 Activity.RESULT_CANCELED, null);
3174 }
3175 // We pretend to the caller that it was really started, but
3176 // they will just get a cancel result.
3177 return START_SUCCESS;
3178 }
3179 }
3180
3181 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3182 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003183 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003184
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003185 if (mResumedActivity == null
3186 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3187 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3188 PendingActivityLaunch pal = new PendingActivityLaunch();
3189 pal.r = r;
3190 pal.sourceRecord = sourceRecord;
3191 pal.grantedUriPermissions = grantedUriPermissions;
3192 pal.grantedMode = grantedMode;
3193 pal.onlyIfNeeded = onlyIfNeeded;
3194 mPendingActivityLaunches.add(pal);
3195 return START_SWITCHES_CANCELED;
3196 }
3197 }
3198
3199 if (mDidAppSwitch) {
3200 // This is the second allowed switch since we stopped switches,
3201 // so now just generally allow switches. Use case: user presses
3202 // home (switches disabled, switch to home, mDidAppSwitch now true);
3203 // user taps a home icon (coming from home so allowed, we hit here
3204 // and now allow anyone to switch again).
3205 mAppSwitchesAllowedTime = 0;
3206 } else {
3207 mDidAppSwitch = true;
3208 }
3209
3210 doPendingActivityLaunchesLocked(false);
3211
3212 return startActivityUncheckedLocked(r, sourceRecord,
3213 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3214 }
3215
3216 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3217 final int N = mPendingActivityLaunches.size();
3218 if (N <= 0) {
3219 return;
3220 }
3221 for (int i=0; i<N; i++) {
3222 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3223 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3224 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3225 doResume && i == (N-1));
3226 }
3227 mPendingActivityLaunches.clear();
3228 }
3229
3230 private final int startActivityUncheckedLocked(HistoryRecord r,
3231 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3232 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3233 final Intent intent = r.intent;
3234 final int callingUid = r.launchedFromUid;
3235
3236 int launchFlags = intent.getFlags();
3237
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003238 // We'll invoke onUserLeaving before onPause only if the launching
3239 // activity did not explicitly state that this is an automated launch.
3240 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3241 if (DEBUG_USER_LEAVING) Log.v(TAG,
3242 "startActivity() => mUserLeaving=" + mUserLeaving);
3243
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003244 // If the caller has asked not to resume at this point, we make note
3245 // of this in the record so that we can skip it when trying to find
3246 // the top running activity.
3247 if (!doResume) {
3248 r.delayedResume = true;
3249 }
3250
3251 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3252 != 0 ? r : null;
3253
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003254 // If the onlyIfNeeded flag is set, then we can do this if the activity
3255 // being launched is the same as the one making the call... or, as
3256 // a special case, if we do not know the caller then we count the
3257 // current top activity as the caller.
3258 if (onlyIfNeeded) {
3259 HistoryRecord checkedCaller = sourceRecord;
3260 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003261 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003262 }
3263 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3264 // Caller is not the same as launcher, so always needed.
3265 onlyIfNeeded = false;
3266 }
3267 }
3268
3269 if (grantedUriPermissions != null && callingUid > 0) {
3270 for (int i=0; i<grantedUriPermissions.length; i++) {
3271 grantUriPermissionLocked(callingUid, r.packageName,
3272 grantedUriPermissions[i], grantedMode, r);
3273 }
3274 }
3275
3276 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3277 intent, r);
3278
3279 if (sourceRecord == null) {
3280 // This activity is not being started from another... in this
3281 // case we -always- start a new task.
3282 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3283 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3284 + intent);
3285 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3286 }
3287 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3288 // The original activity who is starting us is running as a single
3289 // instance... this new activity it is starting must go on its
3290 // own task.
3291 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3292 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3293 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3294 // The activity being started is a single instance... it always
3295 // gets launched into its own task.
3296 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3297 }
3298
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003299 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003300 // For whatever reason this activity is being launched into a new
3301 // task... yet the caller has requested a result back. Well, that
3302 // is pretty messed up, so instead immediately send back a cancel
3303 // and let the new task continue launched as normal without a
3304 // dependency on its originator.
3305 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3306 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003307 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003308 Activity.RESULT_CANCELED, null);
3309 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003310 }
3311
3312 boolean addingToTask = false;
3313 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3314 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3315 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3316 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3317 // If bring to front is requested, and no result is requested, and
3318 // we can find a task that was started with this same
3319 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003320 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003321 // See if there is a task to bring to the front. If this is
3322 // a SINGLE_INSTANCE activity, there can be one and only one
3323 // instance of it in the history, and it is always in its own
3324 // unique task, so we do a special search.
3325 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3326 ? findTaskLocked(intent, r.info)
3327 : findActivityLocked(intent, r.info);
3328 if (taskTop != null) {
3329 if (taskTop.task.intent == null) {
3330 // This task was started because of movement of
3331 // the activity based on affinity... now that we
3332 // are actually launching it, we can assign the
3333 // base intent.
3334 taskTop.task.setIntent(intent, r.info);
3335 }
3336 // If the target task is not in the front, then we need
3337 // to bring it to the front... except... well, with
3338 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3339 // to have the same behavior as if a new instance was
3340 // being started, which means not bringing it to the front
3341 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003342 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003343 if (curTop.task != taskTop.task) {
3344 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3345 boolean callerAtFront = sourceRecord == null
3346 || curTop.task == sourceRecord.task;
3347 if (callerAtFront) {
3348 // We really do want to push this one into the
3349 // user's face, right now.
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07003350 moveTaskToFrontLocked(taskTop.task, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003351 }
3352 }
3353 // If the caller has requested that the target task be
3354 // reset, then do so.
3355 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3356 taskTop = resetTaskIfNeededLocked(taskTop, r);
3357 }
3358 if (onlyIfNeeded) {
3359 // We don't need to start a new activity, and
3360 // the client said not to do anything if that
3361 // is the case, so this is it! And for paranoia, make
3362 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003363 if (doResume) {
3364 resumeTopActivityLocked(null);
3365 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003366 return START_RETURN_INTENT_TO_CALLER;
3367 }
3368 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3369 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3370 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3371 // In this situation we want to remove all activities
3372 // from the task up to the one being started. In most
3373 // cases this means we are resetting the task to its
3374 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003375 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003376 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003377 if (top != null) {
3378 if (top.frontOfTask) {
3379 // Activity aliases may mean we use different
3380 // intents for the top activity, so make sure
3381 // the task now has the identity of the new
3382 // intent.
3383 top.task.setIntent(r.intent, r.info);
3384 }
Doug Zongker2bec3d42009-12-04 12:52:44 -08003385 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003386 deliverNewIntentLocked(top, r.intent);
3387 } else {
3388 // A special case: we need to
3389 // start the activity because it is not currently
3390 // running, and the caller has asked to clear the
3391 // current task to have this activity at the top.
3392 addingToTask = true;
3393 // Now pretend like this activity is being started
3394 // by the top of its task, so it is put in the
3395 // right place.
3396 sourceRecord = taskTop;
3397 }
3398 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3399 // In this case the top activity on the task is the
3400 // same as the one being launched, so we take that
3401 // as a request to bring the task to the foreground.
3402 // If the top activity in the task is the root
3403 // activity, deliver this new intent to it if it
3404 // desires.
3405 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3406 && taskTop.realActivity.equals(r.realActivity)) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003407 logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003408 if (taskTop.frontOfTask) {
3409 taskTop.task.setIntent(r.intent, r.info);
3410 }
3411 deliverNewIntentLocked(taskTop, r.intent);
3412 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3413 // In this case we are launching the root activity
3414 // of the task, but with a different intent. We
3415 // should start a new instance on top.
3416 addingToTask = true;
3417 sourceRecord = taskTop;
3418 }
3419 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3420 // In this case an activity is being launched in to an
3421 // existing task, without resetting that task. This
3422 // is typically the situation of launching an activity
3423 // from a notification or shortcut. We want to place
3424 // the new activity on top of the current task.
3425 addingToTask = true;
3426 sourceRecord = taskTop;
3427 } else if (!taskTop.task.rootWasReset) {
3428 // In this case we are launching in to an existing task
3429 // that has not yet been started from its front door.
3430 // The current task has been brought to the front.
3431 // Ideally, we'd probably like to place this new task
3432 // at the bottom of its stack, but that's a little hard
3433 // to do with the current organization of the code so
3434 // for now we'll just drop it.
3435 taskTop.task.setIntent(r.intent, r.info);
3436 }
3437 if (!addingToTask) {
3438 // We didn't do anything... but it was needed (a.k.a., client
3439 // don't use that intent!) And for paranoia, make
3440 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003441 if (doResume) {
3442 resumeTopActivityLocked(null);
3443 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003444 return START_TASK_TO_FRONT;
3445 }
3446 }
3447 }
3448 }
3449
3450 //String uri = r.intent.toURI();
3451 //Intent intent2 = new Intent(uri);
3452 //Log.i(TAG, "Given intent: " + r.intent);
3453 //Log.i(TAG, "URI is: " + uri);
3454 //Log.i(TAG, "To intent: " + intent2);
3455
3456 if (r.packageName != null) {
3457 // If the activity being launched is the same as the one currently
3458 // at the top, then we need to check if it should only be launched
3459 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003460 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3461 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003462 if (top.realActivity.equals(r.realActivity)) {
3463 if (top.app != null && top.app.thread != null) {
3464 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3465 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3466 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003467 logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003468 // For paranoia, make sure we have correctly
3469 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003470 if (doResume) {
3471 resumeTopActivityLocked(null);
3472 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003473 if (onlyIfNeeded) {
3474 // We don't need to start a new activity, and
3475 // the client said not to do anything if that
3476 // is the case, so this is it!
3477 return START_RETURN_INTENT_TO_CALLER;
3478 }
3479 deliverNewIntentLocked(top, r.intent);
3480 return START_DELIVERED_TO_TOP;
3481 }
3482 }
3483 }
3484 }
3485
3486 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003487 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003488 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003489 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003490 Activity.RESULT_CANCELED, null);
3491 }
3492 return START_CLASS_NOT_FOUND;
3493 }
3494
3495 boolean newTask = false;
3496
3497 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003498 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003499 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3500 // todo: should do better management of integers.
3501 mCurTask++;
3502 if (mCurTask <= 0) {
3503 mCurTask = 1;
3504 }
3505 r.task = new TaskRecord(mCurTask, r.info, intent,
3506 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3507 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3508 + " in new task " + r.task);
3509 newTask = true;
3510 addRecentTask(r.task);
3511
3512 } else if (sourceRecord != null) {
3513 if (!addingToTask &&
3514 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3515 // In this case, we are adding the activity to an existing
3516 // task, but the caller has asked to clear that task if the
3517 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003518 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003519 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003520 if (top != null) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003521 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003522 deliverNewIntentLocked(top, r.intent);
3523 // For paranoia, make sure we have correctly
3524 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003525 if (doResume) {
3526 resumeTopActivityLocked(null);
3527 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003528 return START_DELIVERED_TO_TOP;
3529 }
3530 } else if (!addingToTask &&
3531 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3532 // In this case, we are launching an activity in our own task
3533 // that may already be running somewhere in the history, and
3534 // we want to shuffle it to the front of the stack if so.
3535 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3536 if (where >= 0) {
3537 HistoryRecord top = moveActivityToFrontLocked(where);
Doug Zongker2bec3d42009-12-04 12:52:44 -08003538 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003539 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003540 if (doResume) {
3541 resumeTopActivityLocked(null);
3542 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003543 return START_DELIVERED_TO_TOP;
3544 }
3545 }
3546 // An existing activity is starting this new activity, so we want
3547 // to keep the new one in the same task as the one that is starting
3548 // it.
3549 r.task = sourceRecord.task;
3550 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3551 + " in existing task " + r.task);
3552
3553 } else {
3554 // This not being started from an existing activity, and not part
3555 // of a new task... just put it in the top task, though these days
3556 // this case should never happen.
3557 final int N = mHistory.size();
3558 HistoryRecord prev =
3559 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3560 r.task = prev != null
3561 ? prev.task
3562 : new TaskRecord(mCurTask, r.info, intent,
3563 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3564 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3565 + " in new guessed " + r.task);
3566 }
3567 if (newTask) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003568 EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003569 }
Doug Zongker2bec3d42009-12-04 12:52:44 -08003570 logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003571 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003572 return START_SUCCESS;
3573 }
3574
Dianne Hackborn8f7f35e2010-02-25 18:48:12 -08003575 void reportActivityLaunchedLocked(boolean timeout, HistoryRecord r,
3576 long thisTime, long totalTime) {
3577 for (int i=mWaitingActivityLaunched.size()-1; i>=0; i--) {
3578 WaitResult w = mWaitingActivityLaunched.get(i);
3579 w.timeout = timeout;
3580 if (r != null) {
3581 w.who = new ComponentName(r.info.packageName, r.info.name);
3582 }
3583 w.thisTime = thisTime;
3584 w.totalTime = totalTime;
3585 }
3586 notify();
3587 }
3588
3589 void reportActivityVisibleLocked(HistoryRecord r) {
3590 for (int i=mWaitingActivityVisible.size()-1; i>=0; i--) {
3591 WaitResult w = mWaitingActivityVisible.get(i);
3592 w.timeout = false;
3593 if (r != null) {
3594 w.who = new ComponentName(r.info.packageName, r.info.name);
3595 }
3596 w.totalTime = SystemClock.uptimeMillis() - w.thisTime;
3597 w.thisTime = w.totalTime;
3598 }
3599 notify();
3600 }
3601
3602 private final int startActivityMayWait(IApplicationThread caller,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003603 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3604 int grantedMode, IBinder resultTo,
3605 String resultWho, int requestCode, boolean onlyIfNeeded,
Dianne Hackborn8f7f35e2010-02-25 18:48:12 -08003606 boolean debug, WaitResult outResult) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003607 // Refuse possible leaked file descriptors
3608 if (intent != null && intent.hasFileDescriptors()) {
3609 throw new IllegalArgumentException("File descriptors passed in Intent");
3610 }
3611
The Android Open Source Project4df24232009-03-05 14:34:35 -08003612 final boolean componentSpecified = intent.getComponent() != null;
3613
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003614 // Don't modify the client's object!
3615 intent = new Intent(intent);
3616
3617 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003618 ActivityInfo aInfo;
3619 try {
3620 ResolveInfo rInfo =
3621 ActivityThread.getPackageManager().resolveIntent(
3622 intent, resolvedType,
3623 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003624 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003625 aInfo = rInfo != null ? rInfo.activityInfo : null;
3626 } catch (RemoteException e) {
3627 aInfo = null;
3628 }
3629
3630 if (aInfo != null) {
3631 // Store the found target back into the intent, because now that
3632 // we have it we never want to do this again. For example, if the
3633 // user navigates back to this point in the history, we should
3634 // always restart the exact same activity.
3635 intent.setComponent(new ComponentName(
3636 aInfo.applicationInfo.packageName, aInfo.name));
3637
3638 // Don't debug things in the system process
3639 if (debug) {
3640 if (!aInfo.processName.equals("system")) {
3641 setDebugApp(aInfo.processName, true, false);
3642 }
3643 }
3644 }
3645
Dianne Hackborn8f7f35e2010-02-25 18:48:12 -08003646 synchronized (this) {
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08003647 int callingPid;
3648 int callingUid;
3649 if (caller == null) {
3650 callingPid = Binder.getCallingPid();
3651 callingUid = Binder.getCallingUid();
3652 } else {
3653 callingPid = callingUid = -1;
3654 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003655 final long origId = Binder.clearCallingIdentity();
3656 int res = startActivityLocked(caller, intent, resolvedType,
3657 grantedUriPermissions, grantedMode, aInfo,
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08003658 resultTo, resultWho, requestCode, callingPid, callingUid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003659 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003660 Binder.restoreCallingIdentity(origId);
Dianne Hackborn8f7f35e2010-02-25 18:48:12 -08003661
3662 if (outResult != null) {
3663 outResult.result = res;
3664 if (res == IActivityManager.START_SUCCESS) {
3665 mWaitingActivityLaunched.add(outResult);
3666 do {
3667 try {
3668 wait();
3669 } catch (InterruptedException e) {
3670 }
3671 } while (!outResult.timeout && outResult.who == null);
3672 } else if (res == IActivityManager.START_TASK_TO_FRONT) {
3673 HistoryRecord r = this.topRunningActivityLocked(null);
3674 if (r.nowVisible) {
3675 outResult.timeout = false;
3676 outResult.who = new ComponentName(r.info.packageName, r.info.name);
3677 outResult.totalTime = 0;
3678 outResult.thisTime = 0;
3679 } else {
3680 outResult.thisTime = SystemClock.uptimeMillis();
3681 mWaitingActivityVisible.add(outResult);
3682 do {
3683 try {
3684 wait();
3685 } catch (InterruptedException e) {
3686 }
3687 } while (!outResult.timeout && outResult.who == null);
3688 }
3689 }
3690 }
3691
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003692 return res;
3693 }
3694 }
3695
Dianne Hackborn8f7f35e2010-02-25 18:48:12 -08003696 public final int startActivity(IApplicationThread caller,
3697 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3698 int grantedMode, IBinder resultTo,
3699 String resultWho, int requestCode, boolean onlyIfNeeded,
3700 boolean debug) {
3701 return startActivityMayWait(caller, intent, resolvedType, grantedUriPermissions,
3702 grantedMode, resultTo, resultWho, requestCode, onlyIfNeeded, debug, null);
3703 }
3704
3705 public final WaitResult startActivityAndWait(IApplicationThread caller,
3706 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3707 int grantedMode, IBinder resultTo,
3708 String resultWho, int requestCode, boolean onlyIfNeeded,
3709 boolean debug) {
3710 WaitResult res = new WaitResult();
3711 startActivityMayWait(caller, intent, resolvedType, grantedUriPermissions,
3712 grantedMode, resultTo, resultWho, requestCode, onlyIfNeeded, debug, res);
3713 return res;
3714 }
3715
3716 public int startActivityIntentSender(IApplicationThread caller,
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003717 IntentSender intent, Intent fillInIntent, String resolvedType,
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003718 IBinder resultTo, String resultWho, int requestCode,
3719 int flagsMask, int flagsValues) {
3720 // Refuse possible leaked file descriptors
3721 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3722 throw new IllegalArgumentException("File descriptors passed in Intent");
3723 }
3724
3725 IIntentSender sender = intent.getTarget();
3726 if (!(sender instanceof PendingIntentRecord)) {
3727 throw new IllegalArgumentException("Bad PendingIntent object");
3728 }
3729
3730 PendingIntentRecord pir = (PendingIntentRecord)sender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003731
3732 synchronized (this) {
3733 // If this is coming from the currently resumed activity, it is
3734 // effectively saying that app switches are allowed at this point.
3735 if (mResumedActivity != null
3736 && mResumedActivity.info.applicationInfo.uid ==
3737 Binder.getCallingUid()) {
3738 mAppSwitchesAllowedTime = 0;
3739 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003740 }
3741
3742 return pir.sendInner(0, fillInIntent, resolvedType,
3743 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3744 }
3745
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003746 public boolean startNextMatchingActivity(IBinder callingActivity,
3747 Intent intent) {
3748 // Refuse possible leaked file descriptors
3749 if (intent != null && intent.hasFileDescriptors() == true) {
3750 throw new IllegalArgumentException("File descriptors passed in Intent");
3751 }
3752
3753 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003754 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003755 if (index < 0) {
3756 return false;
3757 }
3758 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3759 if (r.app == null || r.app.thread == null) {
3760 // The caller is not running... d'oh!
3761 return false;
3762 }
3763 intent = new Intent(intent);
3764 // The caller is not allowed to change the data.
3765 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3766 // And we are resetting to find the next component...
3767 intent.setComponent(null);
3768
3769 ActivityInfo aInfo = null;
3770 try {
3771 List<ResolveInfo> resolves =
3772 ActivityThread.getPackageManager().queryIntentActivities(
3773 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003774 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003775
3776 // Look for the original activity in the list...
3777 final int N = resolves != null ? resolves.size() : 0;
3778 for (int i=0; i<N; i++) {
3779 ResolveInfo rInfo = resolves.get(i);
3780 if (rInfo.activityInfo.packageName.equals(r.packageName)
3781 && rInfo.activityInfo.name.equals(r.info.name)) {
3782 // We found the current one... the next matching is
3783 // after it.
3784 i++;
3785 if (i<N) {
3786 aInfo = resolves.get(i).activityInfo;
3787 }
3788 break;
3789 }
3790 }
3791 } catch (RemoteException e) {
3792 }
3793
3794 if (aInfo == null) {
3795 // Nobody who is next!
3796 return false;
3797 }
3798
3799 intent.setComponent(new ComponentName(
3800 aInfo.applicationInfo.packageName, aInfo.name));
3801 intent.setFlags(intent.getFlags()&~(
3802 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3803 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3804 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3805 Intent.FLAG_ACTIVITY_NEW_TASK));
3806
3807 // Okay now we need to start the new activity, replacing the
3808 // currently running activity. This is a little tricky because
3809 // we want to start the new one as if the current one is finished,
3810 // but not finish the current one first so that there is no flicker.
3811 // And thus...
3812 final boolean wasFinishing = r.finishing;
3813 r.finishing = true;
3814
3815 // Propagate reply information over to the new activity.
3816 final HistoryRecord resultTo = r.resultTo;
3817 final String resultWho = r.resultWho;
3818 final int requestCode = r.requestCode;
3819 r.resultTo = null;
3820 if (resultTo != null) {
3821 resultTo.removeResultsLocked(r, resultWho, requestCode);
3822 }
3823
3824 final long origId = Binder.clearCallingIdentity();
3825 // XXX we are not dealing with propagating grantedUriPermissions...
3826 // those are not yet exposed to user code, so there is no need.
3827 int res = startActivityLocked(r.app.thread, intent,
3828 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003829 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003830 Binder.restoreCallingIdentity(origId);
3831
3832 r.finishing = wasFinishing;
3833 if (res != START_SUCCESS) {
3834 return false;
3835 }
3836 return true;
3837 }
3838 }
3839
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003840 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003841 Intent intent, String resolvedType, IBinder resultTo,
3842 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003843
3844 // This is so super not safe, that only the system (or okay root)
3845 // can do it.
3846 final int callingUid = Binder.getCallingUid();
3847 if (callingUid != 0 && callingUid != Process.myUid()) {
3848 throw new SecurityException(
3849 "startActivityInPackage only available to the system");
3850 }
3851
The Android Open Source Project4df24232009-03-05 14:34:35 -08003852 final boolean componentSpecified = intent.getComponent() != null;
3853
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003854 // Don't modify the client's object!
3855 intent = new Intent(intent);
3856
3857 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003858 ActivityInfo aInfo;
3859 try {
3860 ResolveInfo rInfo =
3861 ActivityThread.getPackageManager().resolveIntent(
3862 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003863 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003864 aInfo = rInfo != null ? rInfo.activityInfo : null;
3865 } catch (RemoteException e) {
3866 aInfo = null;
3867 }
3868
3869 if (aInfo != null) {
3870 // Store the found target back into the intent, because now that
3871 // we have it we never want to do this again. For example, if the
3872 // user navigates back to this point in the history, we should
3873 // always restart the exact same activity.
3874 intent.setComponent(new ComponentName(
3875 aInfo.applicationInfo.packageName, aInfo.name));
3876 }
3877
3878 synchronized(this) {
3879 return startActivityLocked(null, intent, resolvedType,
3880 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003881 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003882 }
3883 }
3884
3885 private final void addRecentTask(TaskRecord task) {
3886 // Remove any existing entries that are the same kind of task.
3887 int N = mRecentTasks.size();
3888 for (int i=0; i<N; i++) {
3889 TaskRecord tr = mRecentTasks.get(i);
3890 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3891 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3892 mRecentTasks.remove(i);
3893 i--;
3894 N--;
3895 if (task.intent == null) {
3896 // If the new recent task we are adding is not fully
3897 // specified, then replace it with the existing recent task.
3898 task = tr;
3899 }
3900 }
3901 }
3902 if (N >= MAX_RECENT_TASKS) {
3903 mRecentTasks.remove(N-1);
3904 }
3905 mRecentTasks.add(0, task);
3906 }
3907
3908 public void setRequestedOrientation(IBinder token,
3909 int requestedOrientation) {
3910 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003911 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003912 if (index < 0) {
3913 return;
3914 }
3915 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3916 final long origId = Binder.clearCallingIdentity();
3917 mWindowManager.setAppOrientation(r, requestedOrientation);
3918 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003919 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003920 r.mayFreezeScreenLocked(r.app) ? r : null);
3921 if (config != null) {
3922 r.frozenBeforeDestroy = true;
3923 if (!updateConfigurationLocked(config, r)) {
3924 resumeTopActivityLocked(null);
3925 }
3926 }
3927 Binder.restoreCallingIdentity(origId);
3928 }
3929 }
3930
3931 public int getRequestedOrientation(IBinder token) {
3932 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003933 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003934 if (index < 0) {
3935 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3936 }
3937 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3938 return mWindowManager.getAppOrientation(r);
3939 }
3940 }
3941
3942 private final void stopActivityLocked(HistoryRecord r) {
3943 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3944 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3945 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3946 if (!r.finishing) {
3947 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3948 "no-history");
3949 }
3950 } else if (r.app != null && r.app.thread != null) {
3951 if (mFocusedActivity == r) {
3952 setFocusedActivityLocked(topRunningActivityLocked(null));
3953 }
3954 r.resumeKeyDispatchingLocked();
3955 try {
3956 r.stopped = false;
3957 r.state = ActivityState.STOPPING;
3958 if (DEBUG_VISBILITY) Log.v(
3959 TAG, "Stopping visible=" + r.visible + " for " + r);
3960 if (!r.visible) {
3961 mWindowManager.setAppVisibility(r, false);
3962 }
3963 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3964 } catch (Exception e) {
3965 // Maybe just ignore exceptions here... if the process
3966 // has crashed, our death notification will clean things
3967 // up.
3968 Log.w(TAG, "Exception thrown during pause", e);
3969 // Just in case, assume it to be stopped.
3970 r.stopped = true;
3971 r.state = ActivityState.STOPPED;
3972 if (r.configDestroy) {
3973 destroyActivityLocked(r, true);
3974 }
3975 }
3976 }
3977 }
3978
3979 /**
3980 * @return Returns true if the activity is being finished, false if for
3981 * some reason it is being left as-is.
3982 */
3983 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3984 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003985 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003986 TAG, "Finishing activity: token=" + token
3987 + ", result=" + resultCode + ", data=" + resultData);
3988
Dianne Hackborn75b03852009-06-12 15:43:26 -07003989 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003990 if (index < 0) {
3991 return false;
3992 }
3993 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3994
3995 // Is this the last activity left?
3996 boolean lastActivity = true;
3997 for (int i=mHistory.size()-1; i>=0; i--) {
3998 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3999 if (!p.finishing && p != r) {
4000 lastActivity = false;
4001 break;
4002 }
4003 }
4004
4005 // If this is the last activity, but it is the home activity, then
4006 // just don't finish it.
4007 if (lastActivity) {
4008 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
4009 return false;
4010 }
4011 }
4012
4013 finishActivityLocked(r, index, resultCode, resultData, reason);
4014 return true;
4015 }
4016
4017 /**
4018 * @return Returns true if this activity has been removed from the history
4019 * list, or false if it is still in the list and will be removed later.
4020 */
4021 private final boolean finishActivityLocked(HistoryRecord r, int index,
4022 int resultCode, Intent resultData, String reason) {
4023 if (r.finishing) {
4024 Log.w(TAG, "Duplicate finish request for " + r);
4025 return false;
4026 }
4027
4028 r.finishing = true;
Doug Zongker2bec3d42009-12-04 12:52:44 -08004029 EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004030 System.identityHashCode(r),
4031 r.task.taskId, r.shortComponentName, reason);
4032 r.task.numActivities--;
4033 if (r.frontOfTask && index < (mHistory.size()-1)) {
4034 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
4035 if (next.task == r.task) {
4036 next.frontOfTask = true;
4037 }
4038 }
4039
4040 r.pauseKeyDispatchingLocked();
4041 if (mFocusedActivity == r) {
4042 setFocusedActivityLocked(topRunningActivityLocked(null));
4043 }
4044
4045 // send the result
4046 HistoryRecord resultTo = r.resultTo;
4047 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07004048 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
4049 + " who=" + r.resultWho + " req=" + r.requestCode
4050 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004051 if (r.info.applicationInfo.uid > 0) {
4052 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
4053 r.packageName, resultData, r);
4054 }
4055 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
4056 resultData);
4057 r.resultTo = null;
4058 }
Chris Tate8a7dc172009-03-24 20:11:42 -07004059 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004060
4061 // Make sure this HistoryRecord is not holding on to other resources,
4062 // because clients have remote IPC references to this object so we
4063 // can't assume that will go away and want to avoid circular IPC refs.
4064 r.results = null;
4065 r.pendingResults = null;
4066 r.newIntents = null;
4067 r.icicle = null;
4068
4069 if (mPendingThumbnails.size() > 0) {
4070 // There are clients waiting to receive thumbnails so, in case
4071 // this is an activity that someone is waiting for, add it
4072 // to the pending list so we can correctly update the clients.
4073 mCancelledThumbnails.add(r);
4074 }
4075
4076 if (mResumedActivity == r) {
4077 boolean endTask = index <= 0
4078 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
4079 if (DEBUG_TRANSITION) Log.v(TAG,
4080 "Prepare close transition: finishing " + r);
4081 mWindowManager.prepareAppTransition(endTask
4082 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
4083 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
4084
4085 // Tell window manager to prepare for this one to be removed.
4086 mWindowManager.setAppVisibility(r, false);
4087
4088 if (mPausingActivity == null) {
4089 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
4090 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
4091 startPausingLocked(false, false);
4092 }
4093
4094 } else if (r.state != ActivityState.PAUSING) {
4095 // If the activity is PAUSING, we will complete the finish once
4096 // it is done pausing; else we can just directly finish it here.
4097 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
4098 return finishCurrentActivityLocked(r, index,
4099 FINISH_AFTER_PAUSE) == null;
4100 } else {
4101 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
4102 }
4103
4104 return false;
4105 }
4106
4107 private static final int FINISH_IMMEDIATELY = 0;
4108 private static final int FINISH_AFTER_PAUSE = 1;
4109 private static final int FINISH_AFTER_VISIBLE = 2;
4110
4111 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4112 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004113 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004114 if (index < 0) {
4115 return null;
4116 }
4117
4118 return finishCurrentActivityLocked(r, index, mode);
4119 }
4120
4121 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4122 int index, int mode) {
4123 // First things first: if this activity is currently visible,
4124 // and the resumed activity is not yet visible, then hold off on
4125 // finishing until the resumed one becomes visible.
4126 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4127 if (!mStoppingActivities.contains(r)) {
4128 mStoppingActivities.add(r);
4129 if (mStoppingActivities.size() > 3) {
4130 // If we already have a few activities waiting to stop,
4131 // then give up on things going idle and start clearing
4132 // them out.
4133 Message msg = Message.obtain();
4134 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4135 mHandler.sendMessage(msg);
4136 }
4137 }
4138 r.state = ActivityState.STOPPING;
4139 updateOomAdjLocked();
4140 return r;
4141 }
4142
4143 // make sure the record is cleaned out of other places.
4144 mStoppingActivities.remove(r);
4145 mWaitingVisibleActivities.remove(r);
4146 if (mResumedActivity == r) {
4147 mResumedActivity = null;
4148 }
4149 final ActivityState prevState = r.state;
4150 r.state = ActivityState.FINISHING;
4151
4152 if (mode == FINISH_IMMEDIATELY
4153 || prevState == ActivityState.STOPPED
4154 || prevState == ActivityState.INITIALIZING) {
4155 // If this activity is already stopped, we can just finish
4156 // it right now.
4157 return destroyActivityLocked(r, true) ? null : r;
4158 } else {
4159 // Need to go through the full pause cycle to get this
4160 // activity into the stopped state and then finish it.
4161 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4162 mFinishingActivities.add(r);
4163 resumeTopActivityLocked(null);
4164 }
4165 return r;
4166 }
4167
4168 /**
4169 * This is the internal entry point for handling Activity.finish().
4170 *
4171 * @param token The Binder token referencing the Activity we want to finish.
4172 * @param resultCode Result code, if any, from this Activity.
4173 * @param resultData Result data (Intent), if any, from this Activity.
4174 *
Alexey Tarasov83bad3d2009-08-12 15:05:43 +11004175 * @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 -08004176 */
4177 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4178 // Refuse possible leaked file descriptors
4179 if (resultData != null && resultData.hasFileDescriptors() == true) {
4180 throw new IllegalArgumentException("File descriptors passed in Intent");
4181 }
4182
4183 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004184 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004185 // Find the first activity that is not finishing.
4186 HistoryRecord next = topRunningActivityLocked(token, 0);
4187 if (next != null) {
4188 // ask watcher if this is allowed
4189 boolean resumeOK = true;
4190 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004191 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004192 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004193 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004194 }
4195
4196 if (!resumeOK) {
4197 return false;
4198 }
4199 }
4200 }
4201 final long origId = Binder.clearCallingIdentity();
4202 boolean res = requestFinishActivityLocked(token, resultCode,
4203 resultData, "app-request");
4204 Binder.restoreCallingIdentity(origId);
4205 return res;
4206 }
4207 }
4208
4209 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4210 String resultWho, int requestCode, int resultCode, Intent data) {
4211
4212 if (callingUid > 0) {
4213 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4214 data, r);
4215 }
4216
The Android Open Source Project10592532009-03-18 17:39:46 -07004217 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4218 + " : who=" + resultWho + " req=" + requestCode
4219 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004220 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4221 try {
4222 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4223 list.add(new ResultInfo(resultWho, requestCode,
4224 resultCode, data));
4225 r.app.thread.scheduleSendResult(r, list);
4226 return;
4227 } catch (Exception e) {
4228 Log.w(TAG, "Exception thrown sending result to " + r, e);
4229 }
4230 }
4231
4232 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4233 }
4234
4235 public final void finishSubActivity(IBinder token, String resultWho,
4236 int requestCode) {
4237 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004238 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004239 if (index < 0) {
4240 return;
4241 }
4242 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4243
4244 final long origId = Binder.clearCallingIdentity();
4245
4246 int i;
4247 for (i=mHistory.size()-1; i>=0; i--) {
4248 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4249 if (r.resultTo == self && r.requestCode == requestCode) {
4250 if ((r.resultWho == null && resultWho == null) ||
4251 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4252 finishActivityLocked(r, i,
4253 Activity.RESULT_CANCELED, null, "request-sub");
4254 }
4255 }
4256 }
4257
4258 Binder.restoreCallingIdentity(origId);
4259 }
4260 }
4261
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07004262 public void overridePendingTransition(IBinder token, String packageName,
4263 int enterAnim, int exitAnim) {
4264 synchronized(this) {
4265 int index = indexOfTokenLocked(token);
4266 if (index < 0) {
4267 return;
4268 }
4269 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4270
4271 final long origId = Binder.clearCallingIdentity();
4272
4273 if (self.state == ActivityState.RESUMED
4274 || self.state == ActivityState.PAUSING) {
4275 mWindowManager.overridePendingAppTransition(packageName,
4276 enterAnim, exitAnim);
4277 }
4278
4279 Binder.restoreCallingIdentity(origId);
4280 }
4281 }
4282
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004283 /**
4284 * Perform clean-up of service connections in an activity record.
4285 */
4286 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4287 // Throw away any services that have been bound by this activity.
4288 if (r.connections != null) {
4289 Iterator<ConnectionRecord> it = r.connections.iterator();
4290 while (it.hasNext()) {
4291 ConnectionRecord c = it.next();
4292 removeConnectionLocked(c, null, r);
4293 }
4294 r.connections = null;
4295 }
4296 }
4297
4298 /**
4299 * Perform the common clean-up of an activity record. This is called both
4300 * as part of destroyActivityLocked() (when destroying the client-side
4301 * representation) and cleaning things up as a result of its hosting
4302 * processing going away, in which case there is no remaining client-side
4303 * state to destroy so only the cleanup here is needed.
4304 */
4305 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4306 if (mResumedActivity == r) {
4307 mResumedActivity = null;
4308 }
4309 if (mFocusedActivity == r) {
4310 mFocusedActivity = null;
4311 }
4312
4313 r.configDestroy = false;
4314 r.frozenBeforeDestroy = false;
4315
4316 // Make sure this record is no longer in the pending finishes list.
4317 // This could happen, for example, if we are trimming activities
4318 // down to the max limit while they are still waiting to finish.
4319 mFinishingActivities.remove(r);
4320 mWaitingVisibleActivities.remove(r);
4321
4322 // Remove any pending results.
4323 if (r.finishing && r.pendingResults != null) {
4324 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4325 PendingIntentRecord rec = apr.get();
4326 if (rec != null) {
4327 cancelIntentSenderLocked(rec, false);
4328 }
4329 }
4330 r.pendingResults = null;
4331 }
4332
4333 if (cleanServices) {
4334 cleanUpActivityServicesLocked(r);
4335 }
4336
4337 if (mPendingThumbnails.size() > 0) {
4338 // There are clients waiting to receive thumbnails so, in case
4339 // this is an activity that someone is waiting for, add it
4340 // to the pending list so we can correctly update the clients.
4341 mCancelledThumbnails.add(r);
4342 }
4343
4344 // Get rid of any pending idle timeouts.
4345 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4346 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4347 }
4348
4349 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4350 if (r.state != ActivityState.DESTROYED) {
4351 mHistory.remove(r);
4352 r.inHistory = false;
4353 r.state = ActivityState.DESTROYED;
4354 mWindowManager.removeAppToken(r);
4355 if (VALIDATE_TOKENS) {
4356 mWindowManager.validateAppTokens(mHistory);
4357 }
4358 cleanUpActivityServicesLocked(r);
4359 removeActivityUriPermissionsLocked(r);
4360 }
4361 }
4362
4363 /**
4364 * Destroy the current CLIENT SIDE instance of an activity. This may be
4365 * called both when actually finishing an activity, or when performing
4366 * a configuration switch where we destroy the current client-side object
4367 * but then create a new client-side object for this same HistoryRecord.
4368 */
4369 private final boolean destroyActivityLocked(HistoryRecord r,
4370 boolean removeFromApp) {
4371 if (DEBUG_SWITCH) Log.v(
4372 TAG, "Removing activity: token=" + r
4373 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
Doug Zongker2bec3d42009-12-04 12:52:44 -08004374 EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004375 System.identityHashCode(r),
4376 r.task.taskId, r.shortComponentName);
4377
4378 boolean removedFromHistory = false;
4379
4380 cleanUpActivityLocked(r, false);
4381
Dianne Hackborn03abb812010-01-04 18:43:19 -08004382 final boolean hadApp = r.app != null;
4383
4384 if (hadApp) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004385 if (removeFromApp) {
4386 int idx = r.app.activities.indexOf(r);
4387 if (idx >= 0) {
4388 r.app.activities.remove(idx);
4389 }
4390 if (r.persistent) {
4391 decPersistentCountLocked(r.app);
4392 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004393 if (r.app.activities.size() == 0) {
4394 // No longer have activities, so update location in
4395 // LRU list.
4396 updateLruProcessLocked(r.app, true, false);
4397 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004398 }
4399
4400 boolean skipDestroy = false;
4401
4402 try {
4403 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4404 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4405 r.configChangeFlags);
4406 } catch (Exception e) {
4407 // We can just ignore exceptions here... if the process
4408 // has crashed, our death notification will clean things
4409 // up.
4410 //Log.w(TAG, "Exception thrown during finish", e);
4411 if (r.finishing) {
4412 removeActivityFromHistoryLocked(r);
4413 removedFromHistory = true;
4414 skipDestroy = true;
4415 }
4416 }
4417
4418 r.app = null;
4419 r.nowVisible = false;
4420
4421 if (r.finishing && !skipDestroy) {
4422 r.state = ActivityState.DESTROYING;
4423 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4424 msg.obj = r;
4425 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4426 } else {
4427 r.state = ActivityState.DESTROYED;
4428 }
4429 } else {
4430 // remove this record from the history.
4431 if (r.finishing) {
4432 removeActivityFromHistoryLocked(r);
4433 removedFromHistory = true;
4434 } else {
4435 r.state = ActivityState.DESTROYED;
4436 }
4437 }
4438
4439 r.configChangeFlags = 0;
4440
Dianne Hackborn03abb812010-01-04 18:43:19 -08004441 if (!mLRUActivities.remove(r) && hadApp) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004442 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4443 }
4444
4445 return removedFromHistory;
4446 }
4447
Dianne Hackborn03abb812010-01-04 18:43:19 -08004448 private static void removeHistoryRecordsForAppLocked(ArrayList list, ProcessRecord app) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004449 int i = list.size();
4450 if (localLOGV) Log.v(
4451 TAG, "Removing app " + app + " from list " + list
4452 + " with " + i + " entries");
4453 while (i > 0) {
4454 i--;
4455 HistoryRecord r = (HistoryRecord)list.get(i);
4456 if (localLOGV) Log.v(
4457 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4458 if (r.app == app) {
4459 if (localLOGV) Log.v(TAG, "Removing this entry!");
4460 list.remove(i);
4461 }
4462 }
4463 }
4464
4465 /**
4466 * Main function for removing an existing process from the activity manager
4467 * as a result of that process going away. Clears out all connections
4468 * to the process.
4469 */
4470 private final void handleAppDiedLocked(ProcessRecord app,
4471 boolean restarting) {
4472 cleanUpApplicationRecordLocked(app, restarting, -1);
4473 if (!restarting) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004474 mLruProcesses.remove(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004475 }
4476
4477 // Just in case...
4478 if (mPausingActivity != null && mPausingActivity.app == app) {
4479 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4480 mPausingActivity = null;
4481 }
4482 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4483 mLastPausedActivity = null;
4484 }
4485
4486 // Remove this application's activities from active lists.
4487 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4488 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4489 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4490 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4491
4492 boolean atTop = true;
4493 boolean hasVisibleActivities = false;
4494
4495 // Clean out the history list.
4496 int i = mHistory.size();
4497 if (localLOGV) Log.v(
4498 TAG, "Removing app " + app + " from history with " + i + " entries");
4499 while (i > 0) {
4500 i--;
4501 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4502 if (localLOGV) Log.v(
4503 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4504 if (r.app == app) {
4505 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4506 if (localLOGV) Log.v(
4507 TAG, "Removing this entry! frozen=" + r.haveState
4508 + " finishing=" + r.finishing);
4509 mHistory.remove(i);
4510
4511 r.inHistory = false;
4512 mWindowManager.removeAppToken(r);
4513 if (VALIDATE_TOKENS) {
4514 mWindowManager.validateAppTokens(mHistory);
4515 }
4516 removeActivityUriPermissionsLocked(r);
4517
4518 } else {
4519 // We have the current state for this activity, so
4520 // it can be restarted later when needed.
4521 if (localLOGV) Log.v(
4522 TAG, "Keeping entry, setting app to null");
4523 if (r.visible) {
4524 hasVisibleActivities = true;
4525 }
4526 r.app = null;
4527 r.nowVisible = false;
4528 if (!r.haveState) {
4529 r.icicle = null;
4530 }
4531 }
4532
4533 cleanUpActivityLocked(r, true);
4534 r.state = ActivityState.STOPPED;
4535 }
4536 atTop = false;
4537 }
4538
4539 app.activities.clear();
4540
4541 if (app.instrumentationClass != null) {
4542 Log.w(TAG, "Crash of app " + app.processName
4543 + " running instrumentation " + app.instrumentationClass);
4544 Bundle info = new Bundle();
4545 info.putString("shortMsg", "Process crashed.");
4546 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4547 }
4548
4549 if (!restarting) {
4550 if (!resumeTopActivityLocked(null)) {
4551 // If there was nothing to resume, and we are not already
4552 // restarting this process, but there is a visible activity that
4553 // is hosted by the process... then make sure all visible
4554 // activities are running, taking care of restarting this
4555 // process.
4556 if (hasVisibleActivities) {
4557 ensureActivitiesVisibleLocked(null, 0);
4558 }
4559 }
4560 }
4561 }
4562
4563 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4564 IBinder threadBinder = thread.asBinder();
4565
4566 // Find the application record.
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004567 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4568 ProcessRecord rec = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004569 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4570 return i;
4571 }
4572 }
4573 return -1;
4574 }
4575
4576 private final ProcessRecord getRecordForAppLocked(
4577 IApplicationThread thread) {
4578 if (thread == null) {
4579 return null;
4580 }
4581
4582 int appIndex = getLRURecordIndexForAppLocked(thread);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004583 return appIndex >= 0 ? mLruProcesses.get(appIndex) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004584 }
4585
4586 private final void appDiedLocked(ProcessRecord app, int pid,
4587 IApplicationThread thread) {
4588
4589 mProcDeaths[0]++;
4590
4591 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4592 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4593 + ") has died.");
Doug Zongker2bec3d42009-12-04 12:52:44 -08004594 EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004595 if (localLOGV) Log.v(
4596 TAG, "Dying app: " + app + ", pid: " + pid
4597 + ", thread: " + thread.asBinder());
4598 boolean doLowMem = app.instrumentationClass == null;
4599 handleAppDiedLocked(app, false);
4600
4601 if (doLowMem) {
4602 // If there are no longer any background processes running,
4603 // and the app that died was not running instrumentation,
4604 // then tell everyone we are now low on memory.
4605 boolean haveBg = false;
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004606 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4607 ProcessRecord rec = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004608 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4609 haveBg = true;
4610 break;
4611 }
4612 }
4613
4614 if (!haveBg) {
4615 Log.i(TAG, "Low Memory: No more background processes.");
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004616 EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mLruProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004617 long now = SystemClock.uptimeMillis();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08004618 for (int i=mLruProcesses.size()-1; i>=0; i--) {
4619 ProcessRecord rec = mLruProcesses.get(i);
Dianne Hackborn36124872009-10-08 16:22:03 -07004620 if (rec != app && rec.thread != null &&
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004621 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4622 // The low memory report is overriding any current
4623 // state for a GC request. Make sure to do
4624 // visible/foreground processes first.
4625 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4626 rec.lastRequestedGc = 0;
4627 } else {
4628 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004629 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004630 rec.reportLowMemory = true;
4631 rec.lastLowMemory = now;
4632 mProcessesToGc.remove(rec);
4633 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004634 }
4635 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004636 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004637 }
4638 }
Dianne Hackborn03abb812010-01-04 18:43:19 -08004639 } else if (DEBUG_PROCESSES) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004640 Log.d(TAG, "Received spurious death notification for thread "
4641 + thread.asBinder());
4642 }
4643 }
4644
Dan Egnor42471dd2010-01-07 17:25:22 -08004645 /**
4646 * If a stack trace dump file is configured, dump process stack traces.
4647 * @param pids of dalvik VM processes to dump stack traces for
4648 * @return file containing stack traces, or null if no dump file is configured
4649 */
4650 private static File dumpStackTraces(ArrayList<Integer> pids) {
4651 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4652 if (tracesPath == null || tracesPath.length() == 0) {
4653 return null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004654 }
Dan Egnor42471dd2010-01-07 17:25:22 -08004655
4656 File tracesFile = new File(tracesPath);
4657 try {
4658 File tracesDir = tracesFile.getParentFile();
4659 if (!tracesDir.exists()) tracesFile.mkdirs();
4660 FileUtils.setPermissions(tracesDir.getPath(), 0775, -1, -1); // drwxrwxr-x
4661
4662 if (tracesFile.exists()) tracesFile.delete();
4663 tracesFile.createNewFile();
4664 FileUtils.setPermissions(tracesFile.getPath(), 0666, -1, -1); // -rw-rw-rw-
4665 } catch (IOException e) {
4666 Log.w(TAG, "Unable to prepare ANR traces file: " + tracesPath, e);
4667 return null;
4668 }
4669
4670 // Use a FileObserver to detect when traces finish writing.
4671 // The order of traces is considered important to maintain for legibility.
4672 FileObserver observer = new FileObserver(tracesPath, FileObserver.CLOSE_WRITE) {
4673 public synchronized void onEvent(int event, String path) { notify(); }
4674 };
4675
4676 try {
4677 observer.startWatching();
4678 int num = pids.size();
4679 for (int i = 0; i < num; i++) {
4680 synchronized (observer) {
4681 Process.sendSignal(pids.get(i), Process.SIGNAL_QUIT);
4682 observer.wait(200); // Wait for write-close, give up after 200msec
4683 }
4684 }
4685 } catch (InterruptedException e) {
4686 Log.wtf(TAG, e);
4687 } finally {
4688 observer.stopWatching();
4689 }
4690
4691 return tracesFile;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004692 }
4693
Dan Egnor42471dd2010-01-07 17:25:22 -08004694 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
4695 HistoryRecord parent, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004696 if (app.notResponding || app.crashing) {
4697 return;
4698 }
Dan Egnor42471dd2010-01-07 17:25:22 -08004699
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004700 // Log the ANR to the event log.
Dan Egnor2780e732010-01-22 14:47:35 -08004701 EventLog.writeEvent(EventLogTags.AM_ANR, app.pid, app.processName, app.info.flags,
4702 annotation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004703
Dan Egnor42471dd2010-01-07 17:25:22 -08004704 // Dump thread traces as quickly as we can, starting with "interesting" processes.
4705 ArrayList<Integer> pids = new ArrayList<Integer>(20);
4706 pids.add(app.pid);
4707
4708 int parentPid = app.pid;
4709 if (parent != null && parent.app != null && parent.app.pid > 0) parentPid = parent.app.pid;
4710 if (parentPid != app.pid) pids.add(parentPid);
4711
4712 if (MY_PID != app.pid && MY_PID != parentPid) pids.add(MY_PID);
4713
4714 for (int i = mLruProcesses.size() - 1; i >= 0; i--) {
4715 ProcessRecord r = mLruProcesses.get(i);
4716 if (r != null && r.thread != null) {
4717 int pid = r.pid;
4718 if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) pids.add(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004719 }
4720 }
4721
Dan Egnor42471dd2010-01-07 17:25:22 -08004722 File tracesFile = dumpStackTraces(pids);
4723
4724 // Log the ANR to the main log.
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004725 StringBuilder info = mStringBuilder;
4726 info.setLength(0);
Dan Egnor42471dd2010-01-07 17:25:22 -08004727 info.append("ANR in ").append(app.processName);
4728 if (activity != null && activity.shortComponentName != null) {
4729 info.append(" (").append(activity.shortComponentName).append(")");
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004730 }
Eric Rowe6f4f6192010-02-17 18:29:04 -08004731 info.append("\n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004732 if (annotation != null) {
Eric Rowe6f4f6192010-02-17 18:29:04 -08004733 info.append("Reason: ").append(annotation).append("\n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004734 }
Dan Egnor42471dd2010-01-07 17:25:22 -08004735 if (parent != null && parent != activity) {
Eric Rowe6f4f6192010-02-17 18:29:04 -08004736 info.append("Parent: ").append(parent.shortComponentName).append("\n");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004737 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004738
Dan Egnor42471dd2010-01-07 17:25:22 -08004739 String cpuInfo = null;
4740 if (MONITOR_CPU_USAGE) {
4741 updateCpuStatsNow();
4742 synchronized (mProcessStatsThread) { cpuInfo = mProcessStats.printCurrentState(); }
4743 info.append(cpuInfo);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004744 }
4745
Dan Egnor42471dd2010-01-07 17:25:22 -08004746 Log.e(TAG, info.toString());
4747 if (tracesFile == null) {
4748 // There is no trace file, so dump (only) the alleged culprit's threads to the log
4749 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4750 }
4751
4752 addErrorToDropBox("anr", app, activity, parent, annotation, cpuInfo, tracesFile, null);
4753
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004754 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004755 try {
Dan Egnor42471dd2010-01-07 17:25:22 -08004756 // 0 == show dialog, 1 = keep waiting, -1 = kill process immediately
4757 int res = mController.appNotResponding(app.processName, app.pid, info.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004758 if (res != 0) {
Dan Egnor42471dd2010-01-07 17:25:22 -08004759 if (res < 0 && app.pid != MY_PID) Process.killProcess(app.pid);
4760 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004761 }
4762 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004763 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004764 }
4765 }
4766
Dan Egnor42471dd2010-01-07 17:25:22 -08004767 // Unless configured otherwise, swallow ANRs in background processes & kill the process.
4768 boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
4769 Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
4770 if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
4771 Process.killProcess(app.pid);
4772 return;
4773 }
4774
4775 // Set the app's notResponding state, and look up the errorReportReceiver
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004776 makeAppNotRespondingLocked(app,
4777 activity != null ? activity.shortComponentName : null,
4778 annotation != null ? "ANR " + annotation : "ANR",
Dan Egnorb7f03672009-12-09 16:22:32 -08004779 info.toString());
Dan Egnor42471dd2010-01-07 17:25:22 -08004780
4781 // Bring up the infamous App Not Responding dialog
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004782 Message msg = Message.obtain();
4783 HashMap map = new HashMap();
4784 msg.what = SHOW_NOT_RESPONDING_MSG;
4785 msg.obj = map;
4786 map.put("app", app);
4787 if (activity != null) {
4788 map.put("activity", activity);
4789 }
4790
4791 mHandler.sendMessage(msg);
4792 return;
4793 }
4794
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004795 private final void decPersistentCountLocked(ProcessRecord app)
4796 {
4797 app.persistentActivities--;
4798 if (app.persistentActivities > 0) {
4799 // Still more of 'em...
4800 return;
4801 }
4802 if (app.persistent) {
4803 // Ah, but the application itself is persistent. Whatever!
4804 return;
4805 }
4806
4807 // App is no longer persistent... make sure it and the ones
4808 // following it in the LRU list have the correc oom_adj.
4809 updateOomAdjLocked();
4810 }
4811
4812 public void setPersistent(IBinder token, boolean isPersistent) {
4813 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4814 != PackageManager.PERMISSION_GRANTED) {
4815 String msg = "Permission Denial: setPersistent() from pid="
4816 + Binder.getCallingPid()
4817 + ", uid=" + Binder.getCallingUid()
4818 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4819 Log.w(TAG, msg);
4820 throw new SecurityException(msg);
4821 }
4822
4823 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004824 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004825 if (index < 0) {
4826 return;
4827 }
4828 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4829 ProcessRecord app = r.app;
4830
4831 if (localLOGV) Log.v(
4832 TAG, "Setting persistence " + isPersistent + ": " + r);
4833
4834 if (isPersistent) {
4835 if (r.persistent) {
4836 // Okay okay, I heard you already!
4837 if (localLOGV) Log.v(TAG, "Already persistent!");
4838 return;
4839 }
4840 r.persistent = true;
4841 app.persistentActivities++;
4842 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4843 if (app.persistentActivities > 1) {
4844 // We aren't the first...
4845 if (localLOGV) Log.v(TAG, "Not the first!");
4846 return;
4847 }
4848 if (app.persistent) {
4849 // This would be redundant.
4850 if (localLOGV) Log.v(TAG, "App is persistent!");
4851 return;
4852 }
4853
4854 // App is now persistent... make sure it and the ones
4855 // following it now have the correct oom_adj.
4856 final long origId = Binder.clearCallingIdentity();
4857 updateOomAdjLocked();
4858 Binder.restoreCallingIdentity(origId);
4859
4860 } else {
4861 if (!r.persistent) {
4862 // Okay okay, I heard you already!
4863 return;
4864 }
4865 r.persistent = false;
4866 final long origId = Binder.clearCallingIdentity();
4867 decPersistentCountLocked(app);
4868 Binder.restoreCallingIdentity(origId);
4869
4870 }
4871 }
4872 }
4873
4874 public boolean clearApplicationUserData(final String packageName,
4875 final IPackageDataObserver observer) {
4876 int uid = Binder.getCallingUid();
4877 int pid = Binder.getCallingPid();
4878 long callingId = Binder.clearCallingIdentity();
4879 try {
4880 IPackageManager pm = ActivityThread.getPackageManager();
4881 int pkgUid = -1;
4882 synchronized(this) {
4883 try {
4884 pkgUid = pm.getPackageUid(packageName);
4885 } catch (RemoteException e) {
4886 }
4887 if (pkgUid == -1) {
4888 Log.w(TAG, "Invalid packageName:" + packageName);
4889 return false;
4890 }
4891 if (uid == pkgUid || checkComponentPermission(
4892 android.Manifest.permission.CLEAR_APP_USER_DATA,
4893 pid, uid, -1)
4894 == PackageManager.PERMISSION_GRANTED) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08004895 forceStopPackageLocked(packageName, pkgUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004896 } else {
4897 throw new SecurityException(pid+" does not have permission:"+
4898 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4899 "for process:"+packageName);
4900 }
4901 }
4902
4903 try {
4904 //clear application user data
4905 pm.clearApplicationUserData(packageName, observer);
4906 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4907 Uri.fromParts("package", packageName, null));
4908 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4909 broadcastIntentLocked(null, null, intent,
4910 null, null, 0, null, null, null,
4911 false, false, MY_PID, Process.SYSTEM_UID);
4912 } catch (RemoteException e) {
4913 }
4914 } finally {
4915 Binder.restoreCallingIdentity(callingId);
4916 }
4917 return true;
4918 }
4919
Dianne Hackborn03abb812010-01-04 18:43:19 -08004920 public void killBackgroundProcesses(final String packageName) {
4921 if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
4922 != PackageManager.PERMISSION_GRANTED &&
4923 checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4924 != PackageManager.PERMISSION_GRANTED) {
4925 String msg = "Permission Denial: killBackgroundProcesses() from pid="
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004926 + Binder.getCallingPid()
4927 + ", uid=" + Binder.getCallingUid()
Dianne Hackborn03abb812010-01-04 18:43:19 -08004928 + " requires " + android.Manifest.permission.KILL_BACKGROUND_PROCESSES;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004929 Log.w(TAG, msg);
4930 throw new SecurityException(msg);
4931 }
4932
4933 long callingId = Binder.clearCallingIdentity();
4934 try {
4935 IPackageManager pm = ActivityThread.getPackageManager();
4936 int pkgUid = -1;
4937 synchronized(this) {
4938 try {
4939 pkgUid = pm.getPackageUid(packageName);
4940 } catch (RemoteException e) {
4941 }
4942 if (pkgUid == -1) {
4943 Log.w(TAG, "Invalid packageName: " + packageName);
4944 return;
4945 }
Dianne Hackborn03abb812010-01-04 18:43:19 -08004946 killPackageProcessesLocked(packageName, pkgUid,
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08004947 SECONDARY_SERVER_ADJ, false, true);
Dianne Hackborn03abb812010-01-04 18:43:19 -08004948 }
4949 } finally {
4950 Binder.restoreCallingIdentity(callingId);
4951 }
4952 }
4953
4954 public void forceStopPackage(final String packageName) {
4955 if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
4956 != PackageManager.PERMISSION_GRANTED) {
4957 String msg = "Permission Denial: forceStopPackage() from pid="
4958 + Binder.getCallingPid()
4959 + ", uid=" + Binder.getCallingUid()
4960 + " requires " + android.Manifest.permission.FORCE_STOP_PACKAGES;
4961 Log.w(TAG, msg);
4962 throw new SecurityException(msg);
4963 }
4964
4965 long callingId = Binder.clearCallingIdentity();
4966 try {
4967 IPackageManager pm = ActivityThread.getPackageManager();
4968 int pkgUid = -1;
4969 synchronized(this) {
4970 try {
4971 pkgUid = pm.getPackageUid(packageName);
4972 } catch (RemoteException e) {
4973 }
4974 if (pkgUid == -1) {
4975 Log.w(TAG, "Invalid packageName: " + packageName);
4976 return;
4977 }
4978 forceStopPackageLocked(packageName, pkgUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004979 }
4980 } finally {
4981 Binder.restoreCallingIdentity(callingId);
4982 }
4983 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004984
4985 /*
4986 * The pkg name and uid have to be specified.
4987 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4988 */
4989 public void killApplicationWithUid(String pkg, int uid) {
4990 if (pkg == null) {
4991 return;
4992 }
4993 // Make sure the uid is valid.
4994 if (uid < 0) {
4995 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4996 return;
4997 }
4998 int callerUid = Binder.getCallingUid();
4999 // Only the system server can kill an application
5000 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07005001 // Post an aysnc message to kill the application
5002 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
5003 msg.arg1 = uid;
5004 msg.arg2 = 0;
5005 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07005006 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07005007 } else {
5008 throw new SecurityException(callerUid + " cannot kill pkg: " +
5009 pkg);
5010 }
5011 }
5012
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07005013 public void closeSystemDialogs(String reason) {
5014 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
5015 if (reason != null) {
5016 intent.putExtra("reason", reason);
5017 }
5018
5019 final int uid = Binder.getCallingUid();
5020 final long origId = Binder.clearCallingIdentity();
5021 synchronized (this) {
5022 int i = mWatchers.beginBroadcast();
5023 while (i > 0) {
5024 i--;
5025 IActivityWatcher w = mWatchers.getBroadcastItem(i);
5026 if (w != null) {
5027 try {
5028 w.closingSystemDialogs(reason);
5029 } catch (RemoteException e) {
5030 }
5031 }
5032 }
5033 mWatchers.finishBroadcast();
5034
Dianne Hackbornffa42482009-09-23 22:20:11 -07005035 mWindowManager.closeSystemDialogs(reason);
5036
5037 for (i=mHistory.size()-1; i>=0; i--) {
5038 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5039 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
5040 finishActivityLocked(r, i,
5041 Activity.RESULT_CANCELED, null, "close-sys");
5042 }
5043 }
5044
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07005045 broadcastIntentLocked(null, null, intent, null,
5046 null, 0, null, null, null, false, false, -1, uid);
5047 }
5048 Binder.restoreCallingIdentity(origId);
5049 }
5050
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005051 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005052 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005053 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
5054 for (int i=pids.length-1; i>=0; i--) {
5055 infos[i] = new Debug.MemoryInfo();
5056 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005057 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07005058 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07005059 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07005060
5061 public void killApplicationProcess(String processName, int uid) {
5062 if (processName == null) {
5063 return;
5064 }
5065
5066 int callerUid = Binder.getCallingUid();
5067 // Only the system server can kill an application
5068 if (callerUid == Process.SYSTEM_UID) {
5069 synchronized (this) {
5070 ProcessRecord app = getProcessRecordLocked(processName, uid);
5071 if (app != null) {
5072 try {
5073 app.thread.scheduleSuicide();
5074 } catch (RemoteException e) {
5075 // If the other end already died, then our work here is done.
5076 }
5077 } else {
5078 Log.w(TAG, "Process/uid not found attempting kill of "
5079 + processName + " / " + uid);
5080 }
5081 }
5082 } else {
5083 throw new SecurityException(callerUid + " cannot kill app process: " +
5084 processName);
5085 }
5086 }
5087
Dianne Hackborn03abb812010-01-04 18:43:19 -08005088 private void forceStopPackageLocked(final String packageName, int uid) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005089 forceStopPackageLocked(packageName, uid, false, false, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005090 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
5091 Uri.fromParts("package", packageName, null));
5092 intent.putExtra(Intent.EXTRA_UID, uid);
5093 broadcastIntentLocked(null, null, intent,
5094 null, null, 0, null, null, null,
5095 false, false, MY_PID, Process.SYSTEM_UID);
5096 }
5097
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005098 private final boolean killPackageProcessesLocked(String packageName, int uid,
5099 int minOomAdj, boolean callerWillRestart, boolean doit) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08005100 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005101
Dianne Hackborn03abb812010-01-04 18:43:19 -08005102 // Remove all processes this package may have touched: all with the
5103 // same UID (except for the system or root user), and all whose name
5104 // matches the package name.
5105 final String procNamePrefix = packageName + ":";
5106 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5107 final int NA = apps.size();
5108 for (int ia=0; ia<NA; ia++) {
5109 ProcessRecord app = apps.valueAt(ia);
5110 if (app.removed) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005111 if (doit) {
5112 procs.add(app);
5113 }
Dianne Hackborn03abb812010-01-04 18:43:19 -08005114 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5115 || app.processName.equals(packageName)
5116 || app.processName.startsWith(procNamePrefix)) {
5117 if (app.setAdj >= minOomAdj) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005118 if (!doit) {
5119 return true;
5120 }
Dianne Hackborn03abb812010-01-04 18:43:19 -08005121 app.removed = true;
5122 procs.add(app);
5123 }
5124 }
5125 }
5126 }
5127
5128 int N = procs.size();
5129 for (int i=0; i<N; i++) {
5130 removeProcessLocked(procs.get(i), callerWillRestart);
5131 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005132 return N > 0;
Dianne Hackborn03abb812010-01-04 18:43:19 -08005133 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08005134
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005135 private final boolean forceStopPackageLocked(String name, int uid,
5136 boolean callerWillRestart, boolean purgeCache, boolean doit) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005137 int i, N;
5138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005139 if (uid < 0) {
5140 try {
5141 uid = ActivityThread.getPackageManager().getPackageUid(name);
5142 } catch (RemoteException e) {
5143 }
5144 }
5145
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005146 if (doit) {
5147 Log.i(TAG, "Force stopping package " + name + " uid=" + uid);
Dianne Hackborn03abb812010-01-04 18:43:19 -08005148
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005149 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
5150 while (badApps.hasNext()) {
5151 SparseArray<Long> ba = badApps.next();
5152 if (ba.get(uid) != null) {
5153 badApps.remove();
5154 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005155 }
5156 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005157
5158 boolean didSomething = killPackageProcessesLocked(name, uid, -100,
5159 callerWillRestart, doit);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005160
5161 for (i=mHistory.size()-1; i>=0; i--) {
5162 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5163 if (r.packageName.equals(name)) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005164 if (!doit) {
5165 return true;
5166 }
5167 didSomething = true;
Dianne Hackborn03abb812010-01-04 18:43:19 -08005168 Log.i(TAG, " Force finishing activity " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005169 if (r.app != null) {
5170 r.app.removed = true;
5171 }
5172 r.app = null;
5173 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5174 }
5175 }
5176
5177 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5178 for (ServiceRecord service : mServices.values()) {
5179 if (service.packageName.equals(name)) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005180 if (!doit) {
5181 return true;
5182 }
5183 didSomething = true;
Dianne Hackborn03abb812010-01-04 18:43:19 -08005184 Log.i(TAG, " Force stopping service " + service);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005185 if (service.app != null) {
5186 service.app.removed = true;
5187 }
5188 service.app = null;
5189 services.add(service);
5190 }
5191 }
5192
5193 N = services.size();
5194 for (i=0; i<N; i++) {
5195 bringDownServiceLocked(services.get(i), true);
5196 }
5197
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005198 if (doit) {
5199 if (purgeCache) {
5200 AttributeCache ac = AttributeCache.instance();
5201 if (ac != null) {
5202 ac.removePackage(name);
5203 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08005204 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005205 resumeTopActivityLocked(null);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -08005206 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005207
5208 return didSomething;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005209 }
5210
5211 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5212 final String name = app.processName;
5213 final int uid = app.info.uid;
Dianne Hackborn03abb812010-01-04 18:43:19 -08005214 if (DEBUG_PROCESSES) Log.d(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005215 TAG, "Force removing process " + app + " (" + name
5216 + "/" + uid + ")");
5217
5218 mProcessNames.remove(name, uid);
5219 boolean needRestart = false;
5220 if (app.pid > 0 && app.pid != MY_PID) {
5221 int pid = app.pid;
5222 synchronized (mPidsSelfLocked) {
5223 mPidsSelfLocked.remove(pid);
5224 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5225 }
5226 handleAppDiedLocked(app, true);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08005227 mLruProcesses.remove(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005228 Process.killProcess(pid);
5229
5230 if (app.persistent) {
5231 if (!callerWillRestart) {
5232 addAppLocked(app.info);
5233 } else {
5234 needRestart = true;
5235 }
5236 }
5237 } else {
5238 mRemovedProcesses.add(app);
5239 }
5240
5241 return needRestart;
5242 }
5243
5244 private final void processStartTimedOutLocked(ProcessRecord app) {
5245 final int pid = app.pid;
5246 boolean gone = false;
5247 synchronized (mPidsSelfLocked) {
5248 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5249 if (knownApp != null && knownApp.thread == null) {
5250 mPidsSelfLocked.remove(pid);
5251 gone = true;
5252 }
5253 }
5254
5255 if (gone) {
5256 Log.w(TAG, "Process " + app + " failed to attach");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005257 EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, pid, app.info.uid,
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005258 app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005259 mProcessNames.remove(app.processName, app.info.uid);
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005260 // Take care of any launching providers waiting for this process.
5261 checkAppInLaunchingProvidersLocked(app, true);
5262 // Take care of any services that are waiting for the process.
5263 for (int i=0; i<mPendingServices.size(); i++) {
5264 ServiceRecord sr = mPendingServices.get(i);
5265 if (app.info.uid == sr.appInfo.uid
5266 && app.processName.equals(sr.processName)) {
5267 Log.w(TAG, "Forcing bringing down service: " + sr);
5268 mPendingServices.remove(i);
5269 i--;
5270 bringDownServiceLocked(sr, true);
5271 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005272 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005273 Process.killProcess(pid);
Christopher Tate181fafa2009-05-14 11:12:14 -07005274 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5275 Log.w(TAG, "Unattached app died before backup, skipping");
5276 try {
5277 IBackupManager bm = IBackupManager.Stub.asInterface(
5278 ServiceManager.getService(Context.BACKUP_SERVICE));
5279 bm.agentDisconnected(app.info.packageName);
5280 } catch (RemoteException e) {
5281 // Can't happen; the backup manager is local
5282 }
5283 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005284 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5285 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5286 mPendingBroadcast = null;
5287 scheduleBroadcastsLocked();
5288 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005289 } else {
5290 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5291 }
5292 }
5293
5294 private final boolean attachApplicationLocked(IApplicationThread thread,
5295 int pid) {
5296
5297 // Find the application record that is being attached... either via
5298 // the pid if we are running in multiple processes, or just pull the
5299 // next app record if we are emulating process with anonymous threads.
5300 ProcessRecord app;
5301 if (pid != MY_PID && pid >= 0) {
5302 synchronized (mPidsSelfLocked) {
5303 app = mPidsSelfLocked.get(pid);
5304 }
5305 } else if (mStartingProcesses.size() > 0) {
5306 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005307 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005308 } else {
5309 app = null;
5310 }
5311
5312 if (app == null) {
5313 Log.w(TAG, "No pending application record for pid " + pid
5314 + " (IApplicationThread " + thread + "); dropping process");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005315 EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005316 if (pid > 0 && pid != MY_PID) {
5317 Process.killProcess(pid);
5318 } else {
5319 try {
5320 thread.scheduleExit();
5321 } catch (Exception e) {
5322 // Ignore exceptions.
5323 }
5324 }
5325 return false;
5326 }
5327
5328 // If this application record is still attached to a previous
5329 // process, clean it up now.
5330 if (app.thread != null) {
5331 handleAppDiedLocked(app, true);
5332 }
5333
5334 // Tell the process all about itself.
5335
5336 if (localLOGV) Log.v(
5337 TAG, "Binding process pid " + pid + " to record " + app);
5338
5339 String processName = app.processName;
5340 try {
5341 thread.asBinder().linkToDeath(new AppDeathRecipient(
5342 app, pid, thread), 0);
5343 } catch (RemoteException e) {
5344 app.resetPackageList();
5345 startProcessLocked(app, "link fail", processName);
5346 return false;
5347 }
5348
Doug Zongker2bec3d42009-12-04 12:52:44 -08005349 EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005350
5351 app.thread = thread;
5352 app.curAdj = app.setAdj = -100;
Dianne Hackborn09c916b2009-12-08 14:50:51 -08005353 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
5354 app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005355 app.forcingToForeground = null;
5356 app.foregroundServices = false;
5357 app.debugging = false;
5358
5359 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5360
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005361 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5362 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005363
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005364 if (!normalMode) {
5365 Log.i(TAG, "Launching preboot mode app: " + app);
5366 }
5367
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005368 if (localLOGV) Log.v(
5369 TAG, "New app record " + app
5370 + " thread=" + thread.asBinder() + " pid=" + pid);
5371 try {
5372 int testMode = IApplicationThread.DEBUG_OFF;
5373 if (mDebugApp != null && mDebugApp.equals(processName)) {
5374 testMode = mWaitForDebugger
5375 ? IApplicationThread.DEBUG_WAIT
5376 : IApplicationThread.DEBUG_ON;
5377 app.debugging = true;
5378 if (mDebugTransient) {
5379 mDebugApp = mOrigDebugApp;
5380 mWaitForDebugger = mOrigWaitForDebugger;
5381 }
5382 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005383
Christopher Tate181fafa2009-05-14 11:12:14 -07005384 // If the app is being launched for restore or full backup, set it up specially
5385 boolean isRestrictedBackupMode = false;
5386 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5387 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5388 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5389 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005390
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005391 ensurePackageDexOpt(app.instrumentationInfo != null
5392 ? app.instrumentationInfo.packageName
5393 : app.info.packageName);
5394 if (app.instrumentationClass != null) {
5395 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005396 }
Dianne Hackborndc6b6352009-09-30 14:20:09 -07005397 if (DEBUG_CONFIGURATION) Log.v(TAG, "Binding proc "
5398 + processName + " with config " + mConfiguration);
Dianne Hackborn1655be42009-05-08 14:29:01 -07005399 thread.bindApplication(processName, app.instrumentationInfo != null
5400 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005401 app.instrumentationClass, app.instrumentationProfileFile,
5402 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005403 isRestrictedBackupMode || !normalMode,
5404 mConfiguration, getCommonServicesLocked());
Dianne Hackborndd71fc82009-12-16 19:24:32 -08005405 updateLruProcessLocked(app, false, true);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005406 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005407 } catch (Exception e) {
5408 // todo: Yikes! What should we do? For now we will try to
5409 // start another process, but that could easily get us in
5410 // an infinite loop of restarting processes...
5411 Log.w(TAG, "Exception thrown during bind!", e);
5412
5413 app.resetPackageList();
5414 startProcessLocked(app, "bind fail", processName);
5415 return false;
5416 }
5417
5418 // Remove this record from the list of starting applications.
5419 mPersistentStartingProcesses.remove(app);
5420 mProcessesOnHold.remove(app);
5421
5422 boolean badApp = false;
5423 boolean didSomething = false;
5424
5425 // See if the top visible activity is waiting to run in this process...
5426 HistoryRecord hr = topRunningActivityLocked(null);
5427 if (hr != null) {
5428 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5429 && processName.equals(hr.processName)) {
5430 try {
5431 if (realStartActivityLocked(hr, app, true, true)) {
5432 didSomething = true;
5433 }
5434 } catch (Exception e) {
5435 Log.w(TAG, "Exception in new application when starting activity "
5436 + hr.intent.getComponent().flattenToShortString(), e);
5437 badApp = true;
5438 }
5439 } else {
5440 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5441 }
5442 }
5443
5444 // Find any services that should be running in this process...
5445 if (!badApp && mPendingServices.size() > 0) {
5446 ServiceRecord sr = null;
5447 try {
5448 for (int i=0; i<mPendingServices.size(); i++) {
5449 sr = mPendingServices.get(i);
5450 if (app.info.uid != sr.appInfo.uid
5451 || !processName.equals(sr.processName)) {
5452 continue;
5453 }
5454
5455 mPendingServices.remove(i);
5456 i--;
5457 realStartServiceLocked(sr, app);
5458 didSomething = true;
5459 }
5460 } catch (Exception e) {
5461 Log.w(TAG, "Exception in new application when starting service "
5462 + sr.shortName, e);
5463 badApp = true;
5464 }
5465 }
5466
5467 // Check if the next broadcast receiver is in this process...
5468 BroadcastRecord br = mPendingBroadcast;
5469 if (!badApp && br != null && br.curApp == app) {
5470 try {
5471 mPendingBroadcast = null;
5472 processCurBroadcastLocked(br, app);
5473 didSomething = true;
5474 } catch (Exception e) {
5475 Log.w(TAG, "Exception in new application when starting receiver "
5476 + br.curComponent.flattenToShortString(), e);
5477 badApp = true;
5478 logBroadcastReceiverDiscard(br);
5479 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5480 br.resultExtras, br.resultAbort, true);
5481 scheduleBroadcastsLocked();
5482 }
5483 }
5484
Christopher Tate181fafa2009-05-14 11:12:14 -07005485 // Check whether the next backup agent is in this process...
5486 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5487 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005488 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005489 try {
5490 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5491 } catch (Exception e) {
5492 Log.w(TAG, "Exception scheduling backup agent creation: ");
5493 e.printStackTrace();
5494 }
5495 }
5496
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005497 if (badApp) {
5498 // todo: Also need to kill application to deal with all
5499 // kinds of exceptions.
5500 handleAppDiedLocked(app, false);
5501 return false;
5502 }
5503
5504 if (!didSomething) {
5505 updateOomAdjLocked();
5506 }
5507
5508 return true;
5509 }
5510
5511 public final void attachApplication(IApplicationThread thread) {
5512 synchronized (this) {
5513 int callingPid = Binder.getCallingPid();
5514 final long origId = Binder.clearCallingIdentity();
5515 attachApplicationLocked(thread, callingPid);
5516 Binder.restoreCallingIdentity(origId);
5517 }
5518 }
5519
Dianne Hackborne88846e2009-09-30 21:34:25 -07005520 public final void activityIdle(IBinder token, Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005521 final long origId = Binder.clearCallingIdentity();
Dianne Hackborne88846e2009-09-30 21:34:25 -07005522 activityIdleInternal(token, false, config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005523 Binder.restoreCallingIdentity(origId);
5524 }
5525
5526 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5527 boolean remove) {
5528 int N = mStoppingActivities.size();
5529 if (N <= 0) return null;
5530
5531 ArrayList<HistoryRecord> stops = null;
5532
5533 final boolean nowVisible = mResumedActivity != null
5534 && mResumedActivity.nowVisible
5535 && !mResumedActivity.waitingVisible;
5536 for (int i=0; i<N; i++) {
5537 HistoryRecord s = mStoppingActivities.get(i);
5538 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5539 + nowVisible + " waitingVisible=" + s.waitingVisible
5540 + " finishing=" + s.finishing);
5541 if (s.waitingVisible && nowVisible) {
5542 mWaitingVisibleActivities.remove(s);
5543 s.waitingVisible = false;
5544 if (s.finishing) {
5545 // If this activity is finishing, it is sitting on top of
5546 // everyone else but we now know it is no longer needed...
5547 // so get rid of it. Otherwise, we need to go through the
5548 // normal flow and hide it once we determine that it is
5549 // hidden by the activities in front of it.
5550 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5551 mWindowManager.setAppVisibility(s, false);
5552 }
5553 }
5554 if (!s.waitingVisible && remove) {
5555 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5556 if (stops == null) {
5557 stops = new ArrayList<HistoryRecord>();
5558 }
5559 stops.add(s);
5560 mStoppingActivities.remove(i);
5561 N--;
5562 i--;
5563 }
5564 }
5565
5566 return stops;
5567 }
5568
5569 void enableScreenAfterBoot() {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005570 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005571 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005572 mWindowManager.enableScreenAfterBoot();
5573 }
5574
Dianne Hackborne88846e2009-09-30 21:34:25 -07005575 final void activityIdleInternal(IBinder token, boolean fromTimeout,
5576 Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005577 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5578
5579 ArrayList<HistoryRecord> stops = null;
5580 ArrayList<HistoryRecord> finishes = null;
5581 ArrayList<HistoryRecord> thumbnails = null;
5582 int NS = 0;
5583 int NF = 0;
5584 int NT = 0;
5585 IApplicationThread sendThumbnail = null;
5586 boolean booting = false;
5587 boolean enableScreen = false;
5588
5589 synchronized (this) {
5590 if (token != null) {
5591 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5592 }
5593
5594 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005595 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005596 if (index >= 0) {
5597 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5598
Dianne Hackborn8f7f35e2010-02-25 18:48:12 -08005599 if (fromTimeout) {
5600 reportActivityLaunchedLocked(fromTimeout, r, -1, -1);
5601 }
5602
Dianne Hackborne88846e2009-09-30 21:34:25 -07005603 // This is a hack to semi-deal with a race condition
5604 // in the client where it can be constructed with a
5605 // newer configuration from when we asked it to launch.
5606 // We'll update with whatever configuration it now says
5607 // it used to launch.
5608 if (config != null) {
5609 r.configuration = config;
5610 }
5611
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005612 // No longer need to keep the device awake.
5613 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5614 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5615 mLaunchingActivity.release();
5616 }
5617
5618 // We are now idle. If someone is waiting for a thumbnail from
5619 // us, we can now deliver.
5620 r.idle = true;
5621 scheduleAppGcsLocked();
5622 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5623 sendThumbnail = r.app.thread;
5624 r.thumbnailNeeded = false;
5625 }
5626
5627 // If this activity is fullscreen, set up to hide those under it.
5628
5629 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5630 ensureActivitiesVisibleLocked(null, 0);
5631
5632 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5633 if (!mBooted && !fromTimeout) {
5634 mBooted = true;
5635 enableScreen = true;
5636 }
Dianne Hackborn8f7f35e2010-02-25 18:48:12 -08005637
5638 } else if (fromTimeout) {
5639 reportActivityLaunchedLocked(fromTimeout, null, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005640 }
5641
5642 // Atomically retrieve all of the other things to do.
5643 stops = processStoppingActivitiesLocked(true);
5644 NS = stops != null ? stops.size() : 0;
5645 if ((NF=mFinishingActivities.size()) > 0) {
5646 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5647 mFinishingActivities.clear();
5648 }
5649 if ((NT=mCancelledThumbnails.size()) > 0) {
5650 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5651 mCancelledThumbnails.clear();
5652 }
5653
5654 booting = mBooting;
5655 mBooting = false;
5656 }
5657
5658 int i;
5659
5660 // Send thumbnail if requested.
5661 if (sendThumbnail != null) {
5662 try {
5663 sendThumbnail.requestThumbnail(token);
5664 } catch (Exception e) {
5665 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5666 sendPendingThumbnail(null, token, null, null, true);
5667 }
5668 }
5669
5670 // Stop any activities that are scheduled to do so but have been
5671 // waiting for the next one to start.
5672 for (i=0; i<NS; i++) {
5673 HistoryRecord r = (HistoryRecord)stops.get(i);
5674 synchronized (this) {
5675 if (r.finishing) {
5676 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5677 } else {
5678 stopActivityLocked(r);
5679 }
5680 }
5681 }
5682
5683 // Finish any activities that are scheduled to do so but have been
5684 // waiting for the next one to start.
5685 for (i=0; i<NF; i++) {
5686 HistoryRecord r = (HistoryRecord)finishes.get(i);
5687 synchronized (this) {
5688 destroyActivityLocked(r, true);
5689 }
5690 }
5691
5692 // Report back to any thumbnail receivers.
5693 for (i=0; i<NT; i++) {
5694 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5695 sendPendingThumbnail(r, null, null, null, true);
5696 }
5697
5698 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005699 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005700 }
5701
5702 trimApplications();
5703 //dump();
5704 //mWindowManager.dump();
5705
5706 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005707 enableScreenAfterBoot();
5708 }
5709 }
5710
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005711 final void finishBooting() {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005712 IntentFilter pkgFilter = new IntentFilter();
5713 pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
5714 pkgFilter.addDataScheme("package");
5715 mContext.registerReceiver(new BroadcastReceiver() {
5716 @Override
5717 public void onReceive(Context context, Intent intent) {
5718 String[] pkgs = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
5719 if (pkgs != null) {
5720 for (String pkg : pkgs) {
5721 if (forceStopPackageLocked(pkg, -1, false, false, false)) {
5722 setResultCode(Activity.RESULT_OK);
5723 return;
5724 }
5725 }
5726 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005727 }
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08005728 }, pkgFilter);
5729
5730 synchronized (this) {
5731 // Ensure that any processes we had put on hold are now started
5732 // up.
5733 final int NP = mProcessesOnHold.size();
5734 if (NP > 0) {
5735 ArrayList<ProcessRecord> procs =
5736 new ArrayList<ProcessRecord>(mProcessesOnHold);
5737 for (int ip=0; ip<NP; ip++) {
5738 this.startProcessLocked(procs.get(ip), "on-hold", null);
5739 }
5740 }
5741
5742 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5743 // Tell anyone interested that we are done booting!
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005744 broadcastIntentLocked(null, null,
5745 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5746 null, null, 0, null, null,
5747 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5748 false, false, MY_PID, Process.SYSTEM_UID);
5749 }
5750 }
5751 }
5752
5753 final void ensureBootCompleted() {
5754 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005755 boolean enableScreen;
5756 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005757 booting = mBooting;
5758 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005759 enableScreen = !mBooted;
5760 mBooted = true;
5761 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005762
5763 if (booting) {
5764 finishBooting();
5765 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005766
5767 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005768 enableScreenAfterBoot();
5769 }
5770 }
5771
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005772 public final void activityPaused(IBinder token, Bundle icicle) {
5773 // Refuse possible leaked file descriptors
5774 if (icicle != null && icicle.hasFileDescriptors()) {
5775 throw new IllegalArgumentException("File descriptors passed in Bundle");
5776 }
5777
5778 final long origId = Binder.clearCallingIdentity();
5779 activityPaused(token, icicle, false);
5780 Binder.restoreCallingIdentity(origId);
5781 }
5782
5783 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5784 if (DEBUG_PAUSE) Log.v(
5785 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5786 + ", timeout=" + timeout);
5787
5788 HistoryRecord r = null;
5789
5790 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005791 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005792 if (index >= 0) {
5793 r = (HistoryRecord)mHistory.get(index);
5794 if (!timeout) {
5795 r.icicle = icicle;
5796 r.haveState = true;
5797 }
5798 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5799 if (mPausingActivity == r) {
5800 r.state = ActivityState.PAUSED;
5801 completePauseLocked();
5802 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005803 EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005804 System.identityHashCode(r), r.shortComponentName,
5805 mPausingActivity != null
5806 ? mPausingActivity.shortComponentName : "(none)");
5807 }
5808 }
5809 }
5810 }
5811
5812 public final void activityStopped(IBinder token, Bitmap thumbnail,
5813 CharSequence description) {
5814 if (localLOGV) Log.v(
5815 TAG, "Activity stopped: token=" + token);
5816
5817 HistoryRecord r = null;
5818
5819 final long origId = Binder.clearCallingIdentity();
5820
5821 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005822 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005823 if (index >= 0) {
5824 r = (HistoryRecord)mHistory.get(index);
5825 r.thumbnail = thumbnail;
5826 r.description = description;
5827 r.stopped = true;
5828 r.state = ActivityState.STOPPED;
5829 if (!r.finishing) {
5830 if (r.configDestroy) {
5831 destroyActivityLocked(r, true);
5832 resumeTopActivityLocked(null);
5833 }
5834 }
5835 }
5836 }
5837
5838 if (r != null) {
5839 sendPendingThumbnail(r, null, null, null, false);
5840 }
5841
5842 trimApplications();
5843
5844 Binder.restoreCallingIdentity(origId);
5845 }
5846
5847 public final void activityDestroyed(IBinder token) {
5848 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5849 synchronized (this) {
5850 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5851
Dianne Hackborn75b03852009-06-12 15:43:26 -07005852 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005853 if (index >= 0) {
5854 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5855 if (r.state == ActivityState.DESTROYING) {
5856 final long origId = Binder.clearCallingIdentity();
5857 removeActivityFromHistoryLocked(r);
5858 Binder.restoreCallingIdentity(origId);
5859 }
5860 }
5861 }
5862 }
5863
5864 public String getCallingPackage(IBinder token) {
5865 synchronized (this) {
5866 HistoryRecord r = getCallingRecordLocked(token);
Dianne Hackborn9bbcb912009-10-20 15:42:38 -07005867 return r != null && r.app != null ? r.info.packageName : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005868 }
5869 }
5870
5871 public ComponentName getCallingActivity(IBinder token) {
5872 synchronized (this) {
5873 HistoryRecord r = getCallingRecordLocked(token);
5874 return r != null ? r.intent.getComponent() : null;
5875 }
5876 }
5877
5878 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005879 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005880 if (index >= 0) {
5881 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5882 if (r != null) {
5883 return r.resultTo;
5884 }
5885 }
5886 return null;
5887 }
5888
5889 public ComponentName getActivityClassForToken(IBinder token) {
5890 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005891 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005892 if (index >= 0) {
5893 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5894 return r.intent.getComponent();
5895 }
5896 return null;
5897 }
5898 }
5899
5900 public String getPackageForToken(IBinder token) {
5901 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005902 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005903 if (index >= 0) {
5904 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5905 return r.packageName;
5906 }
5907 return null;
5908 }
5909 }
5910
5911 public IIntentSender getIntentSender(int type,
5912 String packageName, IBinder token, String resultWho,
5913 int requestCode, Intent intent, String resolvedType, int flags) {
5914 // Refuse possible leaked file descriptors
5915 if (intent != null && intent.hasFileDescriptors() == true) {
5916 throw new IllegalArgumentException("File descriptors passed in Intent");
5917 }
5918
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005919 if (type == INTENT_SENDER_BROADCAST) {
5920 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5921 throw new IllegalArgumentException(
5922 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5923 }
5924 }
5925
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005926 synchronized(this) {
5927 int callingUid = Binder.getCallingUid();
5928 try {
5929 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5930 Process.supportsProcesses()) {
5931 int uid = ActivityThread.getPackageManager()
5932 .getPackageUid(packageName);
5933 if (uid != Binder.getCallingUid()) {
5934 String msg = "Permission Denial: getIntentSender() from pid="
5935 + Binder.getCallingPid()
5936 + ", uid=" + Binder.getCallingUid()
5937 + ", (need uid=" + uid + ")"
5938 + " is not allowed to send as package " + packageName;
5939 Log.w(TAG, msg);
5940 throw new SecurityException(msg);
5941 }
5942 }
5943 } catch (RemoteException e) {
5944 throw new SecurityException(e);
5945 }
5946 HistoryRecord activity = null;
5947 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005948 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005949 if (index < 0) {
5950 return null;
5951 }
5952 activity = (HistoryRecord)mHistory.get(index);
5953 if (activity.finishing) {
5954 return null;
5955 }
5956 }
5957
5958 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5959 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5960 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5961 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5962 |PendingIntent.FLAG_UPDATE_CURRENT);
5963
5964 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5965 type, packageName, activity, resultWho,
5966 requestCode, intent, resolvedType, flags);
5967 WeakReference<PendingIntentRecord> ref;
5968 ref = mIntentSenderRecords.get(key);
5969 PendingIntentRecord rec = ref != null ? ref.get() : null;
5970 if (rec != null) {
5971 if (!cancelCurrent) {
5972 if (updateCurrent) {
5973 rec.key.requestIntent.replaceExtras(intent);
5974 }
5975 return rec;
5976 }
5977 rec.canceled = true;
5978 mIntentSenderRecords.remove(key);
5979 }
5980 if (noCreate) {
5981 return rec;
5982 }
5983 rec = new PendingIntentRecord(this, key, callingUid);
5984 mIntentSenderRecords.put(key, rec.ref);
5985 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5986 if (activity.pendingResults == null) {
5987 activity.pendingResults
5988 = new HashSet<WeakReference<PendingIntentRecord>>();
5989 }
5990 activity.pendingResults.add(rec.ref);
5991 }
5992 return rec;
5993 }
5994 }
5995
5996 public void cancelIntentSender(IIntentSender sender) {
5997 if (!(sender instanceof PendingIntentRecord)) {
5998 return;
5999 }
6000 synchronized(this) {
6001 PendingIntentRecord rec = (PendingIntentRecord)sender;
6002 try {
6003 int uid = ActivityThread.getPackageManager()
6004 .getPackageUid(rec.key.packageName);
6005 if (uid != Binder.getCallingUid()) {
6006 String msg = "Permission Denial: cancelIntentSender() from pid="
6007 + Binder.getCallingPid()
6008 + ", uid=" + Binder.getCallingUid()
6009 + " is not allowed to cancel packges "
6010 + rec.key.packageName;
6011 Log.w(TAG, msg);
6012 throw new SecurityException(msg);
6013 }
6014 } catch (RemoteException e) {
6015 throw new SecurityException(e);
6016 }
6017 cancelIntentSenderLocked(rec, true);
6018 }
6019 }
6020
6021 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
6022 rec.canceled = true;
6023 mIntentSenderRecords.remove(rec.key);
6024 if (cleanActivity && rec.key.activity != null) {
6025 rec.key.activity.pendingResults.remove(rec.ref);
6026 }
6027 }
6028
6029 public String getPackageForIntentSender(IIntentSender pendingResult) {
6030 if (!(pendingResult instanceof PendingIntentRecord)) {
6031 return null;
6032 }
6033 synchronized(this) {
6034 try {
6035 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
6036 return res.key.packageName;
6037 } catch (ClassCastException e) {
6038 }
6039 }
6040 return null;
6041 }
6042
6043 public void setProcessLimit(int max) {
6044 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
6045 "setProcessLimit()");
6046 mProcessLimit = max;
6047 }
6048
6049 public int getProcessLimit() {
6050 return mProcessLimit;
6051 }
6052
6053 void foregroundTokenDied(ForegroundToken token) {
6054 synchronized (ActivityManagerService.this) {
6055 synchronized (mPidsSelfLocked) {
6056 ForegroundToken cur
6057 = mForegroundProcesses.get(token.pid);
6058 if (cur != token) {
6059 return;
6060 }
6061 mForegroundProcesses.remove(token.pid);
6062 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
6063 if (pr == null) {
6064 return;
6065 }
6066 pr.forcingToForeground = null;
6067 pr.foregroundServices = false;
6068 }
6069 updateOomAdjLocked();
6070 }
6071 }
6072
6073 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
6074 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
6075 "setProcessForeground()");
6076 synchronized(this) {
6077 boolean changed = false;
6078
6079 synchronized (mPidsSelfLocked) {
6080 ProcessRecord pr = mPidsSelfLocked.get(pid);
6081 if (pr == null) {
6082 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
6083 return;
6084 }
6085 ForegroundToken oldToken = mForegroundProcesses.get(pid);
6086 if (oldToken != null) {
6087 oldToken.token.unlinkToDeath(oldToken, 0);
6088 mForegroundProcesses.remove(pid);
6089 pr.forcingToForeground = null;
6090 changed = true;
6091 }
6092 if (isForeground && token != null) {
6093 ForegroundToken newToken = new ForegroundToken() {
6094 public void binderDied() {
6095 foregroundTokenDied(this);
6096 }
6097 };
6098 newToken.pid = pid;
6099 newToken.token = token;
6100 try {
6101 token.linkToDeath(newToken, 0);
6102 mForegroundProcesses.put(pid, newToken);
6103 pr.forcingToForeground = token;
6104 changed = true;
6105 } catch (RemoteException e) {
6106 // If the process died while doing this, we will later
6107 // do the cleanup with the process death link.
6108 }
6109 }
6110 }
6111
6112 if (changed) {
6113 updateOomAdjLocked();
6114 }
6115 }
6116 }
6117
6118 // =========================================================
6119 // PERMISSIONS
6120 // =========================================================
6121
6122 static class PermissionController extends IPermissionController.Stub {
6123 ActivityManagerService mActivityManagerService;
6124 PermissionController(ActivityManagerService activityManagerService) {
6125 mActivityManagerService = activityManagerService;
6126 }
6127
6128 public boolean checkPermission(String permission, int pid, int uid) {
6129 return mActivityManagerService.checkPermission(permission, pid,
6130 uid) == PackageManager.PERMISSION_GRANTED;
6131 }
6132 }
6133
6134 /**
6135 * This can be called with or without the global lock held.
6136 */
6137 int checkComponentPermission(String permission, int pid, int uid,
6138 int reqUid) {
6139 // We might be performing an operation on behalf of an indirect binder
6140 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
6141 // client identity accordingly before proceeding.
6142 Identity tlsIdentity = sCallerIdentity.get();
6143 if (tlsIdentity != null) {
6144 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
6145 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
6146 uid = tlsIdentity.uid;
6147 pid = tlsIdentity.pid;
6148 }
6149
6150 // Root, system server and our own process get to do everything.
6151 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
6152 !Process.supportsProcesses()) {
6153 return PackageManager.PERMISSION_GRANTED;
6154 }
6155 // If the target requires a specific UID, always fail for others.
6156 if (reqUid >= 0 && uid != reqUid) {
root0369a7c2009-03-23 15:20:47 +01006157 Log.w(TAG, "Permission denied: checkComponentPermission() reqUid=" + reqUid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006158 return PackageManager.PERMISSION_DENIED;
6159 }
6160 if (permission == null) {
6161 return PackageManager.PERMISSION_GRANTED;
6162 }
6163 try {
6164 return ActivityThread.getPackageManager()
6165 .checkUidPermission(permission, uid);
6166 } catch (RemoteException e) {
6167 // Should never happen, but if it does... deny!
6168 Log.e(TAG, "PackageManager is dead?!?", e);
6169 }
6170 return PackageManager.PERMISSION_DENIED;
6171 }
6172
6173 /**
6174 * As the only public entry point for permissions checking, this method
6175 * can enforce the semantic that requesting a check on a null global
6176 * permission is automatically denied. (Internally a null permission
6177 * string is used when calling {@link #checkComponentPermission} in cases
6178 * when only uid-based security is needed.)
6179 *
6180 * This can be called with or without the global lock held.
6181 */
6182 public int checkPermission(String permission, int pid, int uid) {
6183 if (permission == null) {
6184 return PackageManager.PERMISSION_DENIED;
6185 }
6186 return checkComponentPermission(permission, pid, uid, -1);
6187 }
6188
6189 /**
6190 * Binder IPC calls go through the public entry point.
6191 * This can be called with or without the global lock held.
6192 */
6193 int checkCallingPermission(String permission) {
6194 return checkPermission(permission,
6195 Binder.getCallingPid(),
6196 Binder.getCallingUid());
6197 }
6198
6199 /**
6200 * This can be called with or without the global lock held.
6201 */
6202 void enforceCallingPermission(String permission, String func) {
6203 if (checkCallingPermission(permission)
6204 == PackageManager.PERMISSION_GRANTED) {
6205 return;
6206 }
6207
6208 String msg = "Permission Denial: " + func + " from pid="
6209 + Binder.getCallingPid()
6210 + ", uid=" + Binder.getCallingUid()
6211 + " requires " + permission;
6212 Log.w(TAG, msg);
6213 throw new SecurityException(msg);
6214 }
6215
6216 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6217 ProviderInfo pi, int uid, int modeFlags) {
6218 try {
6219 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6220 if ((pi.readPermission != null) &&
6221 (pm.checkUidPermission(pi.readPermission, uid)
6222 != PackageManager.PERMISSION_GRANTED)) {
6223 return false;
6224 }
6225 }
6226 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6227 if ((pi.writePermission != null) &&
6228 (pm.checkUidPermission(pi.writePermission, uid)
6229 != PackageManager.PERMISSION_GRANTED)) {
6230 return false;
6231 }
6232 }
6233 return true;
6234 } catch (RemoteException e) {
6235 return false;
6236 }
6237 }
6238
6239 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6240 int modeFlags) {
6241 // Root gets to do everything.
6242 if (uid == 0 || !Process.supportsProcesses()) {
6243 return true;
6244 }
6245 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6246 if (perms == null) return false;
6247 UriPermission perm = perms.get(uri);
6248 if (perm == null) return false;
6249 return (modeFlags&perm.modeFlags) == modeFlags;
6250 }
6251
6252 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6253 // Another redirected-binder-call permissions check as in
6254 // {@link checkComponentPermission}.
6255 Identity tlsIdentity = sCallerIdentity.get();
6256 if (tlsIdentity != null) {
6257 uid = tlsIdentity.uid;
6258 pid = tlsIdentity.pid;
6259 }
6260
6261 // Our own process gets to do everything.
6262 if (pid == MY_PID) {
6263 return PackageManager.PERMISSION_GRANTED;
6264 }
6265 synchronized(this) {
6266 return checkUriPermissionLocked(uri, uid, modeFlags)
6267 ? PackageManager.PERMISSION_GRANTED
6268 : PackageManager.PERMISSION_DENIED;
6269 }
6270 }
6271
6272 private void grantUriPermissionLocked(int callingUid,
6273 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6274 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6275 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6276 if (modeFlags == 0) {
6277 return;
6278 }
6279
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08006280 if (DEBUG_URI_PERMISSION) Log.v(TAG,
6281 "Requested grant " + targetPkg + " permission to " + uri);
6282
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006283 final IPackageManager pm = ActivityThread.getPackageManager();
6284
6285 // If this is not a content: uri, we can't do anything with it.
6286 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08006287 if (DEBUG_URI_PERMISSION) Log.v(TAG,
6288 "Can't grant URI permission for non-content URI: " + uri);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006289 return;
6290 }
6291
6292 String name = uri.getAuthority();
6293 ProviderInfo pi = null;
6294 ContentProviderRecord cpr
6295 = (ContentProviderRecord)mProvidersByName.get(name);
6296 if (cpr != null) {
6297 pi = cpr.info;
6298 } else {
6299 try {
6300 pi = pm.resolveContentProvider(name,
6301 PackageManager.GET_URI_PERMISSION_PATTERNS);
6302 } catch (RemoteException ex) {
6303 }
6304 }
6305 if (pi == null) {
6306 Log.w(TAG, "No content provider found for: " + name);
6307 return;
6308 }
6309
6310 int targetUid;
6311 try {
6312 targetUid = pm.getPackageUid(targetPkg);
6313 if (targetUid < 0) {
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08006314 if (DEBUG_URI_PERMISSION) Log.v(TAG,
6315 "Can't grant URI permission no uid for: " + targetPkg);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006316 return;
6317 }
6318 } catch (RemoteException ex) {
6319 return;
6320 }
6321
6322 // First... does the target actually need this permission?
6323 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6324 // No need to grant the target this permission.
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08006325 if (DEBUG_URI_PERMISSION) Log.v(TAG,
6326 "Target " + targetPkg + " already has full permission to " + uri);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006327 return;
6328 }
6329
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08006330 // Second... is the provider allowing granting of URI permissions?
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006331 if (!pi.grantUriPermissions) {
6332 throw new SecurityException("Provider " + pi.packageName
6333 + "/" + pi.name
6334 + " does not allow granting of Uri permissions (uri "
6335 + uri + ")");
6336 }
6337 if (pi.uriPermissionPatterns != null) {
6338 final int N = pi.uriPermissionPatterns.length;
6339 boolean allowed = false;
6340 for (int i=0; i<N; i++) {
6341 if (pi.uriPermissionPatterns[i] != null
6342 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6343 allowed = true;
6344 break;
6345 }
6346 }
6347 if (!allowed) {
6348 throw new SecurityException("Provider " + pi.packageName
6349 + "/" + pi.name
6350 + " does not allow granting of permission to path of Uri "
6351 + uri);
6352 }
6353 }
6354
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08006355 // Third... does the caller itself have permission to access
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006356 // this uri?
6357 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6358 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6359 throw new SecurityException("Uid " + callingUid
6360 + " does not have permission to uri " + uri);
6361 }
6362 }
6363
6364 // Okay! So here we are: the caller has the assumed permission
6365 // to the uri, and the target doesn't. Let's now give this to
6366 // the target.
6367
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08006368 if (DEBUG_URI_PERMISSION) Log.v(TAG,
6369 "Granting " + targetPkg + " permission to " + uri);
6370
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006371 HashMap<Uri, UriPermission> targetUris
6372 = mGrantedUriPermissions.get(targetUid);
6373 if (targetUris == null) {
6374 targetUris = new HashMap<Uri, UriPermission>();
6375 mGrantedUriPermissions.put(targetUid, targetUris);
6376 }
6377
6378 UriPermission perm = targetUris.get(uri);
6379 if (perm == null) {
6380 perm = new UriPermission(targetUid, uri);
6381 targetUris.put(uri, perm);
6382
6383 }
6384 perm.modeFlags |= modeFlags;
6385 if (activity == null) {
6386 perm.globalModeFlags |= modeFlags;
6387 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6388 perm.readActivities.add(activity);
6389 if (activity.readUriPermissions == null) {
6390 activity.readUriPermissions = new HashSet<UriPermission>();
6391 }
6392 activity.readUriPermissions.add(perm);
6393 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6394 perm.writeActivities.add(activity);
6395 if (activity.writeUriPermissions == null) {
6396 activity.writeUriPermissions = new HashSet<UriPermission>();
6397 }
6398 activity.writeUriPermissions.add(perm);
6399 }
6400 }
6401
6402 private void grantUriPermissionFromIntentLocked(int callingUid,
6403 String targetPkg, Intent intent, HistoryRecord activity) {
6404 if (intent == null) {
6405 return;
6406 }
6407 Uri data = intent.getData();
6408 if (data == null) {
6409 return;
6410 }
6411 grantUriPermissionLocked(callingUid, targetPkg, data,
6412 intent.getFlags(), activity);
6413 }
6414
6415 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6416 Uri uri, int modeFlags) {
6417 synchronized(this) {
6418 final ProcessRecord r = getRecordForAppLocked(caller);
6419 if (r == null) {
6420 throw new SecurityException("Unable to find app for caller "
6421 + caller
6422 + " when granting permission to uri " + uri);
6423 }
6424 if (targetPkg == null) {
6425 Log.w(TAG, "grantUriPermission: null target");
6426 return;
6427 }
6428 if (uri == null) {
6429 Log.w(TAG, "grantUriPermission: null uri");
6430 return;
6431 }
6432
6433 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6434 null);
6435 }
6436 }
6437
6438 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6439 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6440 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6441 HashMap<Uri, UriPermission> perms
6442 = mGrantedUriPermissions.get(perm.uid);
6443 if (perms != null) {
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08006444 if (DEBUG_URI_PERMISSION) Log.v(TAG,
6445 "Removing " + perm.uid + " permission to " + perm.uri);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006446 perms.remove(perm.uri);
6447 if (perms.size() == 0) {
6448 mGrantedUriPermissions.remove(perm.uid);
6449 }
6450 }
6451 }
6452 }
6453
6454 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6455 if (activity.readUriPermissions != null) {
6456 for (UriPermission perm : activity.readUriPermissions) {
6457 perm.readActivities.remove(activity);
6458 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6459 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6460 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6461 removeUriPermissionIfNeededLocked(perm);
6462 }
6463 }
6464 }
6465 if (activity.writeUriPermissions != null) {
6466 for (UriPermission perm : activity.writeUriPermissions) {
6467 perm.writeActivities.remove(activity);
6468 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6469 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6470 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6471 removeUriPermissionIfNeededLocked(perm);
6472 }
6473 }
6474 }
6475 }
6476
6477 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6478 int modeFlags) {
6479 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6480 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6481 if (modeFlags == 0) {
6482 return;
6483 }
6484
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08006485 if (DEBUG_URI_PERMISSION) Log.v(TAG,
6486 "Revoking all granted permissions to " + uri);
6487
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006488 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 // Does the caller have this permission on the URI?
6509 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6510 // Right now, if you are not the original owner of the permission,
6511 // you are not allowed to revoke it.
6512 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6513 throw new SecurityException("Uid " + callingUid
6514 + " does not have permission to uri " + uri);
6515 //}
6516 }
6517
6518 // Go through all of the permissions and remove any that match.
6519 final List<String> SEGMENTS = uri.getPathSegments();
6520 if (SEGMENTS != null) {
6521 final int NS = SEGMENTS.size();
6522 int N = mGrantedUriPermissions.size();
6523 for (int i=0; i<N; i++) {
6524 HashMap<Uri, UriPermission> perms
6525 = mGrantedUriPermissions.valueAt(i);
6526 Iterator<UriPermission> it = perms.values().iterator();
6527 toploop:
6528 while (it.hasNext()) {
6529 UriPermission perm = it.next();
6530 Uri targetUri = perm.uri;
6531 if (!authority.equals(targetUri.getAuthority())) {
6532 continue;
6533 }
6534 List<String> targetSegments = targetUri.getPathSegments();
6535 if (targetSegments == null) {
6536 continue;
6537 }
6538 if (targetSegments.size() < NS) {
6539 continue;
6540 }
6541 for (int j=0; j<NS; j++) {
6542 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6543 continue toploop;
6544 }
6545 }
Dianne Hackborn9e0f5d92010-02-22 15:05:42 -08006546 if (DEBUG_URI_PERMISSION) Log.v(TAG,
6547 "Revoking " + perm.uid + " permission to " + perm.uri);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006548 perm.clearModes(modeFlags);
6549 if (perm.modeFlags == 0) {
6550 it.remove();
6551 }
6552 }
6553 if (perms.size() == 0) {
6554 mGrantedUriPermissions.remove(
6555 mGrantedUriPermissions.keyAt(i));
6556 N--;
6557 i--;
6558 }
6559 }
6560 }
6561 }
6562
6563 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6564 int modeFlags) {
6565 synchronized(this) {
6566 final ProcessRecord r = getRecordForAppLocked(caller);
6567 if (r == null) {
6568 throw new SecurityException("Unable to find app for caller "
6569 + caller
6570 + " when revoking permission to uri " + uri);
6571 }
6572 if (uri == null) {
6573 Log.w(TAG, "revokeUriPermission: null uri");
6574 return;
6575 }
6576
6577 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6578 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6579 if (modeFlags == 0) {
6580 return;
6581 }
6582
6583 final IPackageManager pm = ActivityThread.getPackageManager();
6584
6585 final String authority = uri.getAuthority();
6586 ProviderInfo pi = null;
6587 ContentProviderRecord cpr
6588 = (ContentProviderRecord)mProvidersByName.get(authority);
6589 if (cpr != null) {
6590 pi = cpr.info;
6591 } else {
6592 try {
6593 pi = pm.resolveContentProvider(authority,
6594 PackageManager.GET_URI_PERMISSION_PATTERNS);
6595 } catch (RemoteException ex) {
6596 }
6597 }
6598 if (pi == null) {
6599 Log.w(TAG, "No content provider found for: " + authority);
6600 return;
6601 }
6602
6603 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6604 }
6605 }
6606
6607 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6608 synchronized (this) {
6609 ProcessRecord app =
6610 who != null ? getRecordForAppLocked(who) : null;
6611 if (app == null) return;
6612
6613 Message msg = Message.obtain();
6614 msg.what = WAIT_FOR_DEBUGGER_MSG;
6615 msg.obj = app;
6616 msg.arg1 = waiting ? 1 : 0;
6617 mHandler.sendMessage(msg);
6618 }
6619 }
6620
6621 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6622 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006623 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006624 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006625 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006626 }
6627
6628 // =========================================================
6629 // TASK MANAGEMENT
6630 // =========================================================
6631
6632 public List getTasks(int maxNum, int flags,
6633 IThumbnailReceiver receiver) {
6634 ArrayList list = new ArrayList();
6635
6636 PendingThumbnailsRecord pending = null;
6637 IApplicationThread topThumbnail = null;
6638 HistoryRecord topRecord = null;
6639
6640 synchronized(this) {
6641 if (localLOGV) Log.v(
6642 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6643 + ", receiver=" + receiver);
6644
6645 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6646 != PackageManager.PERMISSION_GRANTED) {
6647 if (receiver != null) {
6648 // If the caller wants to wait for pending thumbnails,
6649 // it ain't gonna get them.
6650 try {
6651 receiver.finished();
6652 } catch (RemoteException ex) {
6653 }
6654 }
6655 String msg = "Permission Denial: getTasks() from pid="
6656 + Binder.getCallingPid()
6657 + ", uid=" + Binder.getCallingUid()
6658 + " requires " + android.Manifest.permission.GET_TASKS;
6659 Log.w(TAG, msg);
6660 throw new SecurityException(msg);
6661 }
6662
6663 int pos = mHistory.size()-1;
6664 HistoryRecord next =
6665 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6666 HistoryRecord top = null;
6667 CharSequence topDescription = null;
6668 TaskRecord curTask = null;
6669 int numActivities = 0;
6670 int numRunning = 0;
6671 while (pos >= 0 && maxNum > 0) {
6672 final HistoryRecord r = next;
6673 pos--;
6674 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6675
6676 // Initialize state for next task if needed.
6677 if (top == null ||
6678 (top.state == ActivityState.INITIALIZING
6679 && top.task == r.task)) {
6680 top = r;
6681 topDescription = r.description;
6682 curTask = r.task;
6683 numActivities = numRunning = 0;
6684 }
6685
6686 // Add 'r' into the current task.
6687 numActivities++;
6688 if (r.app != null && r.app.thread != null) {
6689 numRunning++;
6690 }
6691 if (topDescription == null) {
6692 topDescription = r.description;
6693 }
6694
6695 if (localLOGV) Log.v(
6696 TAG, r.intent.getComponent().flattenToShortString()
6697 + ": task=" + r.task);
6698
6699 // If the next one is a different task, generate a new
6700 // TaskInfo entry for what we have.
6701 if (next == null || next.task != curTask) {
6702 ActivityManager.RunningTaskInfo ci
6703 = new ActivityManager.RunningTaskInfo();
6704 ci.id = curTask.taskId;
6705 ci.baseActivity = r.intent.getComponent();
6706 ci.topActivity = top.intent.getComponent();
6707 ci.thumbnail = top.thumbnail;
6708 ci.description = topDescription;
6709 ci.numActivities = numActivities;
6710 ci.numRunning = numRunning;
6711 //System.out.println(
6712 // "#" + maxNum + ": " + " descr=" + ci.description);
6713 if (ci.thumbnail == null && receiver != null) {
6714 if (localLOGV) Log.v(
6715 TAG, "State=" + top.state + "Idle=" + top.idle
6716 + " app=" + top.app
6717 + " thr=" + (top.app != null ? top.app.thread : null));
6718 if (top.state == ActivityState.RESUMED
6719 || top.state == ActivityState.PAUSING) {
6720 if (top.idle && top.app != null
6721 && top.app.thread != null) {
6722 topRecord = top;
6723 topThumbnail = top.app.thread;
6724 } else {
6725 top.thumbnailNeeded = true;
6726 }
6727 }
6728 if (pending == null) {
6729 pending = new PendingThumbnailsRecord(receiver);
6730 }
6731 pending.pendingRecords.add(top);
6732 }
6733 list.add(ci);
6734 maxNum--;
6735 top = null;
6736 }
6737 }
6738
6739 if (pending != null) {
6740 mPendingThumbnails.add(pending);
6741 }
6742 }
6743
6744 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6745
6746 if (topThumbnail != null) {
6747 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6748 try {
6749 topThumbnail.requestThumbnail(topRecord);
6750 } catch (Exception e) {
6751 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6752 sendPendingThumbnail(null, topRecord, null, null, true);
6753 }
6754 }
6755
6756 if (pending == null && receiver != null) {
6757 // In this case all thumbnails were available and the client
6758 // is being asked to be told when the remaining ones come in...
6759 // which is unusually, since the top-most currently running
6760 // activity should never have a canned thumbnail! Oh well.
6761 try {
6762 receiver.finished();
6763 } catch (RemoteException ex) {
6764 }
6765 }
6766
6767 return list;
6768 }
6769
6770 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6771 int flags) {
6772 synchronized (this) {
6773 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6774 "getRecentTasks()");
6775
6776 final int N = mRecentTasks.size();
6777 ArrayList<ActivityManager.RecentTaskInfo> res
6778 = new ArrayList<ActivityManager.RecentTaskInfo>(
6779 maxNum < N ? maxNum : N);
6780 for (int i=0; i<N && maxNum > 0; i++) {
6781 TaskRecord tr = mRecentTasks.get(i);
6782 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6783 || (tr.intent == null)
6784 || ((tr.intent.getFlags()
6785 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6786 ActivityManager.RecentTaskInfo rti
6787 = new ActivityManager.RecentTaskInfo();
6788 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6789 rti.baseIntent = new Intent(
6790 tr.intent != null ? tr.intent : tr.affinityIntent);
6791 rti.origActivity = tr.origActivity;
6792 res.add(rti);
6793 maxNum--;
6794 }
6795 }
6796 return res;
6797 }
6798 }
6799
6800 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6801 int j;
6802 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6803 TaskRecord jt = startTask;
6804
6805 // First look backwards
6806 for (j=startIndex-1; j>=0; j--) {
6807 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6808 if (r.task != jt) {
6809 jt = r.task;
6810 if (affinity.equals(jt.affinity)) {
6811 return j;
6812 }
6813 }
6814 }
6815
6816 // Now look forwards
6817 final int N = mHistory.size();
6818 jt = startTask;
6819 for (j=startIndex+1; j<N; j++) {
6820 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6821 if (r.task != jt) {
6822 if (affinity.equals(jt.affinity)) {
6823 return j;
6824 }
6825 jt = r.task;
6826 }
6827 }
6828
6829 // Might it be at the top?
6830 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6831 return N-1;
6832 }
6833
6834 return -1;
6835 }
6836
6837 /**
6838 * Perform a reset of the given task, if needed as part of launching it.
6839 * Returns the new HistoryRecord at the top of the task.
6840 */
6841 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6842 HistoryRecord newActivity) {
6843 boolean forceReset = (newActivity.info.flags
6844 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6845 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6846 if ((newActivity.info.flags
6847 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6848 forceReset = true;
6849 }
6850 }
6851
6852 final TaskRecord task = taskTop.task;
6853
6854 // We are going to move through the history list so that we can look
6855 // at each activity 'target' with 'below' either the interesting
6856 // activity immediately below it in the stack or null.
6857 HistoryRecord target = null;
6858 int targetI = 0;
6859 int taskTopI = -1;
6860 int replyChainEnd = -1;
6861 int lastReparentPos = -1;
6862 for (int i=mHistory.size()-1; i>=-1; i--) {
6863 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6864
6865 if (below != null && below.finishing) {
6866 continue;
6867 }
6868 if (target == null) {
6869 target = below;
6870 targetI = i;
6871 // If we were in the middle of a reply chain before this
6872 // task, it doesn't appear like the root of the chain wants
6873 // anything interesting, so drop it.
6874 replyChainEnd = -1;
6875 continue;
6876 }
6877
6878 final int flags = target.info.flags;
6879
6880 final boolean finishOnTaskLaunch =
6881 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6882 final boolean allowTaskReparenting =
6883 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6884
6885 if (target.task == task) {
6886 // We are inside of the task being reset... we'll either
6887 // finish this activity, push it out for another task,
6888 // or leave it as-is. We only do this
6889 // for activities that are not the root of the task (since
6890 // if we finish the root, we may no longer have the task!).
6891 if (taskTopI < 0) {
6892 taskTopI = targetI;
6893 }
6894 if (below != null && below.task == task) {
6895 final boolean clearWhenTaskReset =
6896 (target.intent.getFlags()
6897 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006898 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006899 // If this activity is sending a reply to a previous
6900 // activity, we can't do anything with it now until
6901 // we reach the start of the reply chain.
6902 // XXX note that we are assuming the result is always
6903 // to the previous activity, which is almost always
6904 // the case but we really shouldn't count on.
6905 if (replyChainEnd < 0) {
6906 replyChainEnd = targetI;
6907 }
Ed Heyl73798232009-03-24 21:32:21 -07006908 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006909 && target.taskAffinity != null
6910 && !target.taskAffinity.equals(task.affinity)) {
6911 // If this activity has an affinity for another
6912 // task, then we need to move it out of here. We will
6913 // move it as far out of the way as possible, to the
6914 // bottom of the activity stack. This also keeps it
6915 // correctly ordered with any activities we previously
6916 // moved.
6917 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6918 if (target.taskAffinity != null
6919 && target.taskAffinity.equals(p.task.affinity)) {
6920 // If the activity currently at the bottom has the
6921 // same task affinity as the one we are moving,
6922 // then merge it into the same task.
6923 target.task = p.task;
6924 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6925 + " out to bottom task " + p.task);
6926 } else {
6927 mCurTask++;
6928 if (mCurTask <= 0) {
6929 mCurTask = 1;
6930 }
6931 target.task = new TaskRecord(mCurTask, target.info, null,
6932 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6933 target.task.affinityIntent = target.intent;
6934 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6935 + " out to new task " + target.task);
6936 }
6937 mWindowManager.setAppGroupId(target, task.taskId);
6938 if (replyChainEnd < 0) {
6939 replyChainEnd = targetI;
6940 }
6941 int dstPos = 0;
6942 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6943 p = (HistoryRecord)mHistory.get(srcPos);
6944 if (p.finishing) {
6945 continue;
6946 }
6947 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6948 + " out to target's task " + target.task);
6949 task.numActivities--;
6950 p.task = target.task;
6951 target.task.numActivities++;
6952 mHistory.remove(srcPos);
6953 mHistory.add(dstPos, p);
6954 mWindowManager.moveAppToken(dstPos, p);
6955 mWindowManager.setAppGroupId(p, p.task.taskId);
6956 dstPos++;
6957 if (VALIDATE_TOKENS) {
6958 mWindowManager.validateAppTokens(mHistory);
6959 }
6960 i++;
6961 }
6962 if (taskTop == p) {
6963 taskTop = below;
6964 }
6965 if (taskTopI == replyChainEnd) {
6966 taskTopI = -1;
6967 }
6968 replyChainEnd = -1;
6969 addRecentTask(target.task);
6970 } else if (forceReset || finishOnTaskLaunch
6971 || clearWhenTaskReset) {
6972 // If the activity should just be removed -- either
6973 // because it asks for it, or the task should be
6974 // cleared -- then finish it and anything that is
6975 // part of its reply chain.
6976 if (clearWhenTaskReset) {
6977 // In this case, we want to finish this activity
6978 // and everything above it, so be sneaky and pretend
6979 // like these are all in the reply chain.
6980 replyChainEnd = targetI+1;
6981 while (replyChainEnd < mHistory.size() &&
6982 ((HistoryRecord)mHistory.get(
6983 replyChainEnd)).task == task) {
6984 replyChainEnd++;
6985 }
6986 replyChainEnd--;
6987 } else if (replyChainEnd < 0) {
6988 replyChainEnd = targetI;
6989 }
6990 HistoryRecord p = null;
6991 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6992 p = (HistoryRecord)mHistory.get(srcPos);
6993 if (p.finishing) {
6994 continue;
6995 }
6996 if (finishActivityLocked(p, srcPos,
6997 Activity.RESULT_CANCELED, null, "reset")) {
6998 replyChainEnd--;
6999 srcPos--;
7000 }
7001 }
7002 if (taskTop == p) {
7003 taskTop = below;
7004 }
7005 if (taskTopI == replyChainEnd) {
7006 taskTopI = -1;
7007 }
7008 replyChainEnd = -1;
7009 } else {
7010 // If we were in the middle of a chain, well the
7011 // activity that started it all doesn't want anything
7012 // special, so leave it all as-is.
7013 replyChainEnd = -1;
7014 }
7015 } else {
7016 // Reached the bottom of the task -- any reply chain
7017 // should be left as-is.
7018 replyChainEnd = -1;
7019 }
7020
7021 } else if (target.resultTo != null) {
7022 // If this activity is sending a reply to a previous
7023 // activity, we can't do anything with it now until
7024 // we reach the start of the reply chain.
7025 // XXX note that we are assuming the result is always
7026 // to the previous activity, which is almost always
7027 // the case but we really shouldn't count on.
7028 if (replyChainEnd < 0) {
7029 replyChainEnd = targetI;
7030 }
7031
7032 } else if (taskTopI >= 0 && allowTaskReparenting
7033 && task.affinity != null
7034 && task.affinity.equals(target.taskAffinity)) {
7035 // We are inside of another task... if this activity has
7036 // an affinity for our task, then either remove it if we are
7037 // clearing or move it over to our task. Note that
7038 // we currently punt on the case where we are resetting a
7039 // task that is not at the top but who has activities above
7040 // with an affinity to it... this is really not a normal
7041 // case, and we will need to later pull that task to the front
7042 // and usually at that point we will do the reset and pick
7043 // up those remaining activities. (This only happens if
7044 // someone starts an activity in a new task from an activity
7045 // in a task that is not currently on top.)
7046 if (forceReset || finishOnTaskLaunch) {
7047 if (replyChainEnd < 0) {
7048 replyChainEnd = targetI;
7049 }
7050 HistoryRecord p = null;
7051 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
7052 p = (HistoryRecord)mHistory.get(srcPos);
7053 if (p.finishing) {
7054 continue;
7055 }
7056 if (finishActivityLocked(p, srcPos,
7057 Activity.RESULT_CANCELED, null, "reset")) {
7058 taskTopI--;
7059 lastReparentPos--;
7060 replyChainEnd--;
7061 srcPos--;
7062 }
7063 }
7064 replyChainEnd = -1;
7065 } else {
7066 if (replyChainEnd < 0) {
7067 replyChainEnd = targetI;
7068 }
7069 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
7070 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
7071 if (p.finishing) {
7072 continue;
7073 }
7074 if (lastReparentPos < 0) {
7075 lastReparentPos = taskTopI;
7076 taskTop = p;
7077 } else {
7078 lastReparentPos--;
7079 }
7080 mHistory.remove(srcPos);
7081 p.task.numActivities--;
7082 p.task = task;
7083 mHistory.add(lastReparentPos, p);
7084 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
7085 + " in to resetting task " + task);
7086 task.numActivities++;
7087 mWindowManager.moveAppToken(lastReparentPos, p);
7088 mWindowManager.setAppGroupId(p, p.task.taskId);
7089 if (VALIDATE_TOKENS) {
7090 mWindowManager.validateAppTokens(mHistory);
7091 }
7092 }
7093 replyChainEnd = -1;
7094
7095 // Now we've moved it in to place... but what if this is
7096 // a singleTop activity and we have put it on top of another
7097 // instance of the same activity? Then we drop the instance
7098 // below so it remains singleTop.
7099 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
7100 for (int j=lastReparentPos-1; j>=0; j--) {
7101 HistoryRecord p = (HistoryRecord)mHistory.get(j);
7102 if (p.finishing) {
7103 continue;
7104 }
7105 if (p.intent.getComponent().equals(target.intent.getComponent())) {
7106 if (finishActivityLocked(p, j,
7107 Activity.RESULT_CANCELED, null, "replace")) {
7108 taskTopI--;
7109 lastReparentPos--;
7110 }
7111 }
7112 }
7113 }
7114 }
7115 }
7116
7117 target = below;
7118 targetI = i;
7119 }
7120
7121 return taskTop;
7122 }
7123
7124 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007125 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007126 */
7127 public void moveTaskToFront(int task) {
7128 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7129 "moveTaskToFront()");
7130
7131 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007132 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7133 Binder.getCallingUid(), "Task to front")) {
7134 return;
7135 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007136 final long origId = Binder.clearCallingIdentity();
7137 try {
7138 int N = mRecentTasks.size();
7139 for (int i=0; i<N; i++) {
7140 TaskRecord tr = mRecentTasks.get(i);
7141 if (tr.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007142 moveTaskToFrontLocked(tr, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007143 return;
7144 }
7145 }
7146 for (int i=mHistory.size()-1; i>=0; i--) {
7147 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
7148 if (hr.task.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007149 moveTaskToFrontLocked(hr.task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007150 return;
7151 }
7152 }
7153 } finally {
7154 Binder.restoreCallingIdentity(origId);
7155 }
7156 }
7157 }
7158
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007159 private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007160 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
7161
7162 final int task = tr.taskId;
7163 int top = mHistory.size()-1;
7164
7165 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
7166 // nothing to do!
7167 return;
7168 }
7169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007170 ArrayList moved = new ArrayList();
7171
7172 // Applying the affinities may have removed entries from the history,
7173 // so get the size again.
7174 top = mHistory.size()-1;
7175 int pos = top;
7176
7177 // Shift all activities with this task up to the top
7178 // of the stack, keeping them in the same internal order.
7179 while (pos >= 0) {
7180 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7181 if (localLOGV) Log.v(
7182 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7183 boolean first = true;
7184 if (r.task.taskId == task) {
7185 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
7186 mHistory.remove(pos);
7187 mHistory.add(top, r);
7188 moved.add(0, r);
7189 top--;
7190 if (first) {
7191 addRecentTask(r.task);
7192 first = false;
7193 }
7194 }
7195 pos--;
7196 }
7197
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007198 if (DEBUG_TRANSITION) Log.v(TAG,
7199 "Prepare to front transition: task=" + tr);
7200 if (reason != null &&
7201 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7202 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7203 HistoryRecord r = topRunningActivityLocked(null);
7204 if (r != null) {
7205 mNoAnimActivities.add(r);
7206 }
7207 } else {
7208 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7209 }
7210
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007211 mWindowManager.moveAppTokensToTop(moved);
7212 if (VALIDATE_TOKENS) {
7213 mWindowManager.validateAppTokens(mHistory);
7214 }
7215
7216 finishTaskMove(task);
Doug Zongker2bec3d42009-12-04 12:52:44 -08007217 EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007218 }
7219
7220 private final void finishTaskMove(int task) {
7221 resumeTopActivityLocked(null);
7222 }
7223
7224 public void moveTaskToBack(int task) {
7225 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7226 "moveTaskToBack()");
7227
7228 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007229 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7230 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7231 Binder.getCallingUid(), "Task to back")) {
7232 return;
7233 }
7234 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007235 final long origId = Binder.clearCallingIdentity();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007236 moveTaskToBackLocked(task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007237 Binder.restoreCallingIdentity(origId);
7238 }
7239 }
7240
7241 /**
7242 * Moves an activity, and all of the other activities within the same task, to the bottom
7243 * of the history stack. The activity's order within the task is unchanged.
7244 *
7245 * @param token A reference to the activity we wish to move
7246 * @param nonRoot If false then this only works if the activity is the root
7247 * of a task; if true it will work for any activity in a task.
7248 * @return Returns true if the move completed, false if not.
7249 */
7250 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7251 synchronized(this) {
7252 final long origId = Binder.clearCallingIdentity();
7253 int taskId = getTaskForActivityLocked(token, !nonRoot);
7254 if (taskId >= 0) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007255 return moveTaskToBackLocked(taskId, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007256 }
7257 Binder.restoreCallingIdentity(origId);
7258 }
7259 return false;
7260 }
7261
7262 /**
7263 * Worker method for rearranging history stack. Implements the function of moving all
7264 * activities for a specific task (gathering them if disjoint) into a single group at the
7265 * bottom of the stack.
7266 *
7267 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7268 * to premeptively cancel the move.
7269 *
7270 * @param task The taskId to collect and move to the bottom.
7271 * @return Returns true if the move completed, false if not.
7272 */
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007273 private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007274 Log.i(TAG, "moveTaskToBack: " + task);
7275
7276 // If we have a watcher, preflight the move before committing to it. First check
7277 // for *other* available tasks, but if none are available, then try again allowing the
7278 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007279 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007280 HistoryRecord next = topRunningActivityLocked(null, task);
7281 if (next == null) {
7282 next = topRunningActivityLocked(null, 0);
7283 }
7284 if (next != null) {
7285 // ask watcher if this is allowed
7286 boolean moveOK = true;
7287 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007288 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007289 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007290 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007291 }
7292 if (!moveOK) {
7293 return false;
7294 }
7295 }
7296 }
7297
7298 ArrayList moved = new ArrayList();
7299
7300 if (DEBUG_TRANSITION) Log.v(TAG,
7301 "Prepare to back transition: task=" + task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007302
7303 final int N = mHistory.size();
7304 int bottom = 0;
7305 int pos = 0;
7306
7307 // Shift all activities with this task down to the bottom
7308 // of the stack, keeping them in the same internal order.
7309 while (pos < N) {
7310 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7311 if (localLOGV) Log.v(
7312 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7313 if (r.task.taskId == task) {
7314 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7315 mHistory.remove(pos);
7316 mHistory.add(bottom, r);
7317 moved.add(r);
7318 bottom++;
7319 }
7320 pos++;
7321 }
7322
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007323 if (reason != null &&
7324 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7325 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7326 HistoryRecord r = topRunningActivityLocked(null);
7327 if (r != null) {
7328 mNoAnimActivities.add(r);
7329 }
7330 } else {
Suchi Amalapurapuc9568e32009-11-05 18:51:16 -08007331 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007332 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007333 mWindowManager.moveAppTokensToBottom(moved);
7334 if (VALIDATE_TOKENS) {
7335 mWindowManager.validateAppTokens(mHistory);
7336 }
7337
7338 finishTaskMove(task);
7339 return true;
7340 }
7341
7342 public void moveTaskBackwards(int task) {
7343 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7344 "moveTaskBackwards()");
7345
7346 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007347 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7348 Binder.getCallingUid(), "Task backwards")) {
7349 return;
7350 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007351 final long origId = Binder.clearCallingIdentity();
7352 moveTaskBackwardsLocked(task);
7353 Binder.restoreCallingIdentity(origId);
7354 }
7355 }
7356
7357 private final void moveTaskBackwardsLocked(int task) {
7358 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7359 }
7360
7361 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7362 synchronized(this) {
7363 return getTaskForActivityLocked(token, onlyRoot);
7364 }
7365 }
7366
7367 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7368 final int N = mHistory.size();
7369 TaskRecord lastTask = null;
7370 for (int i=0; i<N; i++) {
7371 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7372 if (r == token) {
7373 if (!onlyRoot || lastTask != r.task) {
7374 return r.task.taskId;
7375 }
7376 return -1;
7377 }
7378 lastTask = r.task;
7379 }
7380
7381 return -1;
7382 }
7383
7384 /**
7385 * Returns the top activity in any existing task matching the given
7386 * Intent. Returns null if no such task is found.
7387 */
7388 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7389 ComponentName cls = intent.getComponent();
7390 if (info.targetActivity != null) {
7391 cls = new ComponentName(info.packageName, info.targetActivity);
7392 }
7393
7394 TaskRecord cp = null;
7395
7396 final int N = mHistory.size();
7397 for (int i=(N-1); i>=0; i--) {
7398 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7399 if (!r.finishing && r.task != cp
7400 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7401 cp = r.task;
7402 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7403 // + "/aff=" + r.task.affinity + " to new cls="
7404 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7405 if (r.task.affinity != null) {
7406 if (r.task.affinity.equals(info.taskAffinity)) {
7407 //Log.i(TAG, "Found matching affinity!");
7408 return r;
7409 }
7410 } else if (r.task.intent != null
7411 && r.task.intent.getComponent().equals(cls)) {
7412 //Log.i(TAG, "Found matching class!");
7413 //dump();
7414 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7415 return r;
7416 } else if (r.task.affinityIntent != null
7417 && r.task.affinityIntent.getComponent().equals(cls)) {
7418 //Log.i(TAG, "Found matching class!");
7419 //dump();
7420 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7421 return r;
7422 }
7423 }
7424 }
7425
7426 return null;
7427 }
7428
7429 /**
7430 * Returns the first activity (starting from the top of the stack) that
7431 * is the same as the given activity. Returns null if no such activity
7432 * is found.
7433 */
7434 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7435 ComponentName cls = intent.getComponent();
7436 if (info.targetActivity != null) {
7437 cls = new ComponentName(info.packageName, info.targetActivity);
7438 }
7439
7440 final int N = mHistory.size();
7441 for (int i=(N-1); i>=0; i--) {
7442 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7443 if (!r.finishing) {
7444 if (r.intent.getComponent().equals(cls)) {
7445 //Log.i(TAG, "Found matching class!");
7446 //dump();
7447 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7448 return r;
7449 }
7450 }
7451 }
7452
7453 return null;
7454 }
7455
7456 public void finishOtherInstances(IBinder token, ComponentName className) {
7457 synchronized(this) {
7458 final long origId = Binder.clearCallingIdentity();
7459
7460 int N = mHistory.size();
7461 TaskRecord lastTask = null;
7462 for (int i=0; i<N; i++) {
7463 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7464 if (r.realActivity.equals(className)
7465 && r != token && lastTask != r.task) {
7466 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7467 null, "others")) {
7468 i--;
7469 N--;
7470 }
7471 }
7472 lastTask = r.task;
7473 }
7474
7475 Binder.restoreCallingIdentity(origId);
7476 }
7477 }
7478
7479 // =========================================================
7480 // THUMBNAILS
7481 // =========================================================
7482
7483 public void reportThumbnail(IBinder token,
7484 Bitmap thumbnail, CharSequence description) {
7485 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7486 final long origId = Binder.clearCallingIdentity();
7487 sendPendingThumbnail(null, token, thumbnail, description, true);
7488 Binder.restoreCallingIdentity(origId);
7489 }
7490
7491 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7492 Bitmap thumbnail, CharSequence description, boolean always) {
7493 TaskRecord task = null;
7494 ArrayList receivers = null;
7495
7496 //System.out.println("Send pending thumbnail: " + r);
7497
7498 synchronized(this) {
7499 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007500 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007501 if (index < 0) {
7502 return;
7503 }
7504 r = (HistoryRecord)mHistory.get(index);
7505 }
7506 if (thumbnail == null) {
7507 thumbnail = r.thumbnail;
7508 description = r.description;
7509 }
7510 if (thumbnail == null && !always) {
7511 // If there is no thumbnail, and this entry is not actually
7512 // going away, then abort for now and pick up the next
7513 // thumbnail we get.
7514 return;
7515 }
7516 task = r.task;
7517
7518 int N = mPendingThumbnails.size();
7519 int i=0;
7520 while (i<N) {
7521 PendingThumbnailsRecord pr =
7522 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7523 //System.out.println("Looking in " + pr.pendingRecords);
7524 if (pr.pendingRecords.remove(r)) {
7525 if (receivers == null) {
7526 receivers = new ArrayList();
7527 }
7528 receivers.add(pr);
7529 if (pr.pendingRecords.size() == 0) {
7530 pr.finished = true;
7531 mPendingThumbnails.remove(i);
7532 N--;
7533 continue;
7534 }
7535 }
7536 i++;
7537 }
7538 }
7539
7540 if (receivers != null) {
7541 final int N = receivers.size();
7542 for (int i=0; i<N; i++) {
7543 try {
7544 PendingThumbnailsRecord pr =
7545 (PendingThumbnailsRecord)receivers.get(i);
7546 pr.receiver.newThumbnail(
7547 task != null ? task.taskId : -1, thumbnail, description);
7548 if (pr.finished) {
7549 pr.receiver.finished();
7550 }
7551 } catch (Exception e) {
7552 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7553 }
7554 }
7555 }
7556 }
7557
7558 // =========================================================
7559 // CONTENT PROVIDERS
7560 // =========================================================
7561
7562 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7563 List providers = null;
7564 try {
7565 providers = ActivityThread.getPackageManager().
7566 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007567 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007568 } catch (RemoteException ex) {
7569 }
7570 if (providers != null) {
7571 final int N = providers.size();
7572 for (int i=0; i<N; i++) {
7573 ProviderInfo cpi =
7574 (ProviderInfo)providers.get(i);
7575 ContentProviderRecord cpr =
7576 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7577 if (cpr == null) {
7578 cpr = new ContentProviderRecord(cpi, app.info);
7579 mProvidersByClass.put(cpi.name, cpr);
7580 }
7581 app.pubProviders.put(cpi.name, cpr);
7582 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007583 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007584 }
7585 }
7586 return providers;
7587 }
7588
7589 private final String checkContentProviderPermissionLocked(
7590 ProviderInfo cpi, ProcessRecord r, int mode) {
7591 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7592 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7593 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7594 cpi.exported ? -1 : cpi.applicationInfo.uid)
7595 == PackageManager.PERMISSION_GRANTED
7596 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7597 return null;
7598 }
7599 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7600 cpi.exported ? -1 : cpi.applicationInfo.uid)
7601 == PackageManager.PERMISSION_GRANTED) {
7602 return null;
7603 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007604
7605 PathPermission[] pps = cpi.pathPermissions;
7606 if (pps != null) {
7607 int i = pps.length;
7608 while (i > 0) {
7609 i--;
7610 PathPermission pp = pps[i];
7611 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7612 cpi.exported ? -1 : cpi.applicationInfo.uid)
7613 == PackageManager.PERMISSION_GRANTED
7614 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7615 return null;
7616 }
7617 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7618 cpi.exported ? -1 : cpi.applicationInfo.uid)
7619 == PackageManager.PERMISSION_GRANTED) {
7620 return null;
7621 }
7622 }
7623 }
7624
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007625 String msg = "Permission Denial: opening provider " + cpi.name
7626 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7627 + ", uid=" + callingUid + ") requires "
7628 + cpi.readPermission + " or " + cpi.writePermission;
7629 Log.w(TAG, msg);
7630 return msg;
7631 }
7632
7633 private final ContentProviderHolder getContentProviderImpl(
7634 IApplicationThread caller, String name) {
7635 ContentProviderRecord cpr;
7636 ProviderInfo cpi = null;
7637
7638 synchronized(this) {
7639 ProcessRecord r = null;
7640 if (caller != null) {
7641 r = getRecordForAppLocked(caller);
7642 if (r == null) {
7643 throw new SecurityException(
7644 "Unable to find app for caller " + caller
7645 + " (pid=" + Binder.getCallingPid()
7646 + ") when getting content provider " + name);
7647 }
7648 }
7649
7650 // First check if this content provider has been published...
7651 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7652 if (cpr != null) {
7653 cpi = cpr.info;
7654 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7655 return new ContentProviderHolder(cpi,
7656 cpi.readPermission != null
7657 ? cpi.readPermission : cpi.writePermission);
7658 }
7659
7660 if (r != null && cpr.canRunHere(r)) {
7661 // This provider has been published or is in the process
7662 // of being published... but it is also allowed to run
7663 // in the caller's process, so don't make a connection
7664 // and just let the caller instantiate its own instance.
7665 if (cpr.provider != null) {
7666 // don't give caller the provider object, it needs
7667 // to make its own.
7668 cpr = new ContentProviderRecord(cpr);
7669 }
7670 return cpr;
7671 }
7672
7673 final long origId = Binder.clearCallingIdentity();
7674
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007675 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007676 // return it right away.
7677 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007678 if (DEBUG_PROVIDER) Log.v(TAG,
7679 "Adding provider requested by "
7680 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007681 + cpr.info.processName);
7682 Integer cnt = r.conProviders.get(cpr);
7683 if (cnt == null) {
7684 r.conProviders.put(cpr, new Integer(1));
7685 } else {
7686 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7687 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007688 cpr.clients.add(r);
7689 } else {
7690 cpr.externals++;
7691 }
7692
7693 if (cpr.app != null) {
7694 updateOomAdjLocked(cpr.app);
7695 }
7696
7697 Binder.restoreCallingIdentity(origId);
7698
7699 } else {
7700 try {
7701 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007702 resolveContentProvider(name,
7703 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007704 } catch (RemoteException ex) {
7705 }
7706 if (cpi == null) {
7707 return null;
7708 }
7709
7710 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7711 return new ContentProviderHolder(cpi,
7712 cpi.readPermission != null
7713 ? cpi.readPermission : cpi.writePermission);
7714 }
7715
Dianne Hackbornc3b91fd2010-02-23 17:25:30 -08007716 if (!mSystemReady && !mDidUpdate && !mWaitingUpdate
7717 && !cpi.processName.equals("system")) {
7718 // If this content provider does not run in the system
7719 // process, and the system is not yet ready to run other
7720 // processes, then fail fast instead of hanging.
7721 throw new IllegalArgumentException(
7722 "Attempt to launch content provider before system ready");
7723 }
7724
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007725 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7726 final boolean firstClass = cpr == null;
7727 if (firstClass) {
7728 try {
7729 ApplicationInfo ai =
7730 ActivityThread.getPackageManager().
7731 getApplicationInfo(
7732 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007733 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007734 if (ai == null) {
7735 Log.w(TAG, "No package info for content provider "
7736 + cpi.name);
7737 return null;
7738 }
7739 cpr = new ContentProviderRecord(cpi, ai);
7740 } catch (RemoteException ex) {
7741 // pm is in same process, this will never happen.
7742 }
7743 }
7744
7745 if (r != null && cpr.canRunHere(r)) {
7746 // If this is a multiprocess provider, then just return its
7747 // info and allow the caller to instantiate it. Only do
7748 // this if the provider is the same user as the caller's
7749 // process, or can run as root (so can be in any process).
7750 return cpr;
7751 }
7752
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007753 if (DEBUG_PROVIDER) {
7754 RuntimeException e = new RuntimeException("here");
7755 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7756 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007757 }
7758
7759 // This is single process, and our app is now connecting to it.
7760 // See if we are already in the process of launching this
7761 // provider.
7762 final int N = mLaunchingProviders.size();
7763 int i;
7764 for (i=0; i<N; i++) {
7765 if (mLaunchingProviders.get(i) == cpr) {
7766 break;
7767 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007768 }
7769
7770 // If the provider is not already being launched, then get it
7771 // started.
7772 if (i >= N) {
7773 final long origId = Binder.clearCallingIdentity();
7774 ProcessRecord proc = startProcessLocked(cpi.processName,
7775 cpr.appInfo, false, 0, "content provider",
7776 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007777 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007778 if (proc == null) {
7779 Log.w(TAG, "Unable to launch app "
7780 + cpi.applicationInfo.packageName + "/"
7781 + cpi.applicationInfo.uid + " for provider "
7782 + name + ": process is bad");
7783 return null;
7784 }
7785 cpr.launchingApp = proc;
7786 mLaunchingProviders.add(cpr);
7787 Binder.restoreCallingIdentity(origId);
7788 }
7789
7790 // Make sure the provider is published (the same provider class
7791 // may be published under multiple names).
7792 if (firstClass) {
7793 mProvidersByClass.put(cpi.name, cpr);
7794 }
7795 mProvidersByName.put(name, cpr);
7796
7797 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007798 if (DEBUG_PROVIDER) Log.v(TAG,
7799 "Adding provider requested by "
7800 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007801 + cpr.info.processName);
7802 Integer cnt = r.conProviders.get(cpr);
7803 if (cnt == null) {
7804 r.conProviders.put(cpr, new Integer(1));
7805 } else {
7806 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7807 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007808 cpr.clients.add(r);
7809 } else {
7810 cpr.externals++;
7811 }
7812 }
7813 }
7814
7815 // Wait for the provider to be published...
7816 synchronized (cpr) {
7817 while (cpr.provider == null) {
7818 if (cpr.launchingApp == null) {
7819 Log.w(TAG, "Unable to launch app "
7820 + cpi.applicationInfo.packageName + "/"
7821 + cpi.applicationInfo.uid + " for provider "
7822 + name + ": launching app became null");
Doug Zongker2bec3d42009-12-04 12:52:44 -08007823 EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007824 cpi.applicationInfo.packageName,
7825 cpi.applicationInfo.uid, name);
7826 return null;
7827 }
7828 try {
7829 cpr.wait();
7830 } catch (InterruptedException ex) {
7831 }
7832 }
7833 }
7834 return cpr;
7835 }
7836
7837 public final ContentProviderHolder getContentProvider(
7838 IApplicationThread caller, String name) {
7839 if (caller == null) {
7840 String msg = "null IApplicationThread when getting content provider "
7841 + name;
7842 Log.w(TAG, msg);
7843 throw new SecurityException(msg);
7844 }
7845
7846 return getContentProviderImpl(caller, name);
7847 }
7848
7849 private ContentProviderHolder getContentProviderExternal(String name) {
7850 return getContentProviderImpl(null, name);
7851 }
7852
7853 /**
7854 * Drop a content provider from a ProcessRecord's bookkeeping
7855 * @param cpr
7856 */
7857 public void removeContentProvider(IApplicationThread caller, String name) {
7858 synchronized (this) {
7859 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7860 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007861 // remove from mProvidersByClass
7862 if (DEBUG_PROVIDER) Log.v(TAG, name +
7863 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007864 return;
7865 }
7866 final ProcessRecord r = getRecordForAppLocked(caller);
7867 if (r == null) {
7868 throw new SecurityException(
7869 "Unable to find app for caller " + caller +
7870 " when removing content provider " + name);
7871 }
7872 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007873 ContentProviderRecord localCpr = (ContentProviderRecord)
7874 mProvidersByClass.get(cpr.info.name);
7875 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7876 + r.info.processName + " from process "
7877 + localCpr.appInfo.processName);
7878 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007879 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007880 Log.w(TAG, "removeContentProvider called on local provider: "
7881 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007882 return;
7883 } else {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007884 Integer cnt = r.conProviders.get(localCpr);
7885 if (cnt == null || cnt.intValue() <= 1) {
7886 localCpr.clients.remove(r);
7887 r.conProviders.remove(localCpr);
7888 } else {
7889 r.conProviders.put(localCpr, new Integer(cnt.intValue()-1));
7890 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007891 }
7892 updateOomAdjLocked();
7893 }
7894 }
7895
7896 private void removeContentProviderExternal(String name) {
7897 synchronized (this) {
7898 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7899 if(cpr == null) {
7900 //remove from mProvidersByClass
7901 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7902 return;
7903 }
7904
7905 //update content provider record entry info
7906 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7907 localCpr.externals--;
7908 if (localCpr.externals < 0) {
7909 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7910 }
7911 updateOomAdjLocked();
7912 }
7913 }
7914
7915 public final void publishContentProviders(IApplicationThread caller,
7916 List<ContentProviderHolder> providers) {
7917 if (providers == null) {
7918 return;
7919 }
7920
7921 synchronized(this) {
7922 final ProcessRecord r = getRecordForAppLocked(caller);
7923 if (r == null) {
7924 throw new SecurityException(
7925 "Unable to find app for caller " + caller
7926 + " (pid=" + Binder.getCallingPid()
7927 + ") when publishing content providers");
7928 }
7929
7930 final long origId = Binder.clearCallingIdentity();
7931
7932 final int N = providers.size();
7933 for (int i=0; i<N; i++) {
7934 ContentProviderHolder src = providers.get(i);
7935 if (src == null || src.info == null || src.provider == null) {
7936 continue;
7937 }
7938 ContentProviderRecord dst =
7939 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7940 if (dst != null) {
7941 mProvidersByClass.put(dst.info.name, dst);
7942 String names[] = dst.info.authority.split(";");
7943 for (int j = 0; j < names.length; j++) {
7944 mProvidersByName.put(names[j], dst);
7945 }
7946
7947 int NL = mLaunchingProviders.size();
7948 int j;
7949 for (j=0; j<NL; j++) {
7950 if (mLaunchingProviders.get(j) == dst) {
7951 mLaunchingProviders.remove(j);
7952 j--;
7953 NL--;
7954 }
7955 }
7956 synchronized (dst) {
7957 dst.provider = src.provider;
7958 dst.app = r;
7959 dst.notifyAll();
7960 }
7961 updateOomAdjLocked(r);
7962 }
7963 }
7964
7965 Binder.restoreCallingIdentity(origId);
7966 }
7967 }
7968
7969 public static final void installSystemProviders() {
7970 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7971 List providers = mSelf.generateApplicationProvidersLocked(app);
Dianne Hackbornc3b91fd2010-02-23 17:25:30 -08007972 if (providers != null) {
7973 for (int i=providers.size()-1; i>=0; i--) {
7974 ProviderInfo pi = (ProviderInfo)providers.get(i);
7975 if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
7976 Log.w(TAG, "Not installing system proc provider " + pi.name
7977 + ": not system .apk");
7978 providers.remove(i);
7979 }
7980 }
7981 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007982 mSystemThread.installSystemProviders(providers);
7983 }
7984
7985 // =========================================================
7986 // GLOBAL MANAGEMENT
7987 // =========================================================
7988
7989 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7990 ApplicationInfo info, String customProcess) {
7991 String proc = customProcess != null ? customProcess : info.processName;
7992 BatteryStatsImpl.Uid.Proc ps = null;
7993 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7994 synchronized (stats) {
7995 ps = stats.getProcessStatsLocked(info.uid, proc);
7996 }
7997 return new ProcessRecord(ps, thread, info, proc);
7998 }
7999
8000 final ProcessRecord addAppLocked(ApplicationInfo info) {
8001 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
8002
8003 if (app == null) {
8004 app = newProcessRecordLocked(null, info, null);
8005 mProcessNames.put(info.processName, info.uid, app);
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008006 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008007 }
8008
8009 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
8010 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
8011 app.persistent = true;
8012 app.maxAdj = CORE_SERVER_ADJ;
8013 }
8014 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
8015 mPersistentStartingProcesses.add(app);
8016 startProcessLocked(app, "added application", app.processName);
8017 }
8018
8019 return app;
8020 }
8021
8022 public void unhandledBack() {
8023 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
8024 "unhandledBack()");
8025
8026 synchronized(this) {
8027 int count = mHistory.size();
Dianne Hackborn03abb812010-01-04 18:43:19 -08008028 if (DEBUG_SWITCH) Log.d(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008029 TAG, "Performing unhandledBack(): stack size = " + count);
8030 if (count > 1) {
8031 final long origId = Binder.clearCallingIdentity();
8032 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
8033 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
8034 Binder.restoreCallingIdentity(origId);
8035 }
8036 }
8037 }
8038
8039 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
8040 String name = uri.getAuthority();
8041 ContentProviderHolder cph = getContentProviderExternal(name);
8042 ParcelFileDescriptor pfd = null;
8043 if (cph != null) {
8044 // We record the binder invoker's uid in thread-local storage before
8045 // going to the content provider to open the file. Later, in the code
8046 // that handles all permissions checks, we look for this uid and use
8047 // that rather than the Activity Manager's own uid. The effect is that
8048 // we do the check against the caller's permissions even though it looks
8049 // to the content provider like the Activity Manager itself is making
8050 // the request.
8051 sCallerIdentity.set(new Identity(
8052 Binder.getCallingPid(), Binder.getCallingUid()));
8053 try {
8054 pfd = cph.provider.openFile(uri, "r");
8055 } catch (FileNotFoundException e) {
8056 // do nothing; pfd will be returned null
8057 } finally {
8058 // Ensure that whatever happens, we clean up the identity state
8059 sCallerIdentity.remove();
8060 }
8061
8062 // We've got the fd now, so we're done with the provider.
8063 removeContentProviderExternal(name);
8064 } else {
8065 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
8066 }
8067 return pfd;
8068 }
8069
8070 public void goingToSleep() {
8071 synchronized(this) {
8072 mSleeping = true;
8073 mWindowManager.setEventDispatching(false);
8074
8075 if (mResumedActivity != null) {
8076 pauseIfSleepingLocked();
8077 } else {
8078 Log.w(TAG, "goingToSleep with no resumed activity!");
8079 }
8080 }
8081 }
8082
Dianne Hackborn55280a92009-05-07 15:53:46 -07008083 public boolean shutdown(int timeout) {
8084 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
8085 != PackageManager.PERMISSION_GRANTED) {
8086 throw new SecurityException("Requires permission "
8087 + android.Manifest.permission.SHUTDOWN);
8088 }
8089
8090 boolean timedout = false;
8091
8092 synchronized(this) {
8093 mShuttingDown = true;
8094 mWindowManager.setEventDispatching(false);
8095
8096 if (mResumedActivity != null) {
8097 pauseIfSleepingLocked();
8098 final long endTime = System.currentTimeMillis() + timeout;
8099 while (mResumedActivity != null || mPausingActivity != null) {
8100 long delay = endTime - System.currentTimeMillis();
8101 if (delay <= 0) {
8102 Log.w(TAG, "Activity manager shutdown timed out");
8103 timedout = true;
8104 break;
8105 }
8106 try {
8107 this.wait();
8108 } catch (InterruptedException e) {
8109 }
8110 }
8111 }
8112 }
8113
8114 mUsageStatsService.shutdown();
8115 mBatteryStatsService.shutdown();
8116
8117 return timedout;
8118 }
8119
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008120 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07008121 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008122 if (!mGoingToSleep.isHeld()) {
8123 mGoingToSleep.acquire();
8124 if (mLaunchingActivity.isHeld()) {
8125 mLaunchingActivity.release();
8126 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
8127 }
8128 }
8129
8130 // If we are not currently pausing an activity, get the current
8131 // one to pause. If we are pausing one, we will just let that stuff
8132 // run and release the wake lock when all done.
8133 if (mPausingActivity == null) {
8134 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
8135 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
8136 startPausingLocked(false, true);
8137 }
8138 }
8139 }
8140
8141 public void wakingUp() {
8142 synchronized(this) {
8143 if (mGoingToSleep.isHeld()) {
8144 mGoingToSleep.release();
8145 }
8146 mWindowManager.setEventDispatching(true);
8147 mSleeping = false;
8148 resumeTopActivityLocked(null);
8149 }
8150 }
8151
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07008152 public void stopAppSwitches() {
8153 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8154 != PackageManager.PERMISSION_GRANTED) {
8155 throw new SecurityException("Requires permission "
8156 + android.Manifest.permission.STOP_APP_SWITCHES);
8157 }
8158
8159 synchronized(this) {
8160 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
8161 + APP_SWITCH_DELAY_TIME;
8162 mDidAppSwitch = false;
8163 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8164 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8165 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
8166 }
8167 }
8168
8169 public void resumeAppSwitches() {
8170 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8171 != PackageManager.PERMISSION_GRANTED) {
8172 throw new SecurityException("Requires permission "
8173 + android.Manifest.permission.STOP_APP_SWITCHES);
8174 }
8175
8176 synchronized(this) {
8177 // Note that we don't execute any pending app switches... we will
8178 // let those wait until either the timeout, or the next start
8179 // activity request.
8180 mAppSwitchesAllowedTime = 0;
8181 }
8182 }
8183
8184 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
8185 String name) {
8186 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
8187 return true;
8188 }
8189
8190 final int perm = checkComponentPermission(
8191 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
8192 callingUid, -1);
8193 if (perm == PackageManager.PERMISSION_GRANTED) {
8194 return true;
8195 }
8196
8197 Log.w(TAG, name + " request from " + callingUid + " stopped");
8198 return false;
8199 }
8200
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008201 public void setDebugApp(String packageName, boolean waitForDebugger,
8202 boolean persistent) {
8203 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
8204 "setDebugApp()");
8205
8206 // Note that this is not really thread safe if there are multiple
8207 // callers into it at the same time, but that's not a situation we
8208 // care about.
8209 if (persistent) {
8210 final ContentResolver resolver = mContext.getContentResolver();
8211 Settings.System.putString(
8212 resolver, Settings.System.DEBUG_APP,
8213 packageName);
8214 Settings.System.putInt(
8215 resolver, Settings.System.WAIT_FOR_DEBUGGER,
8216 waitForDebugger ? 1 : 0);
8217 }
8218
8219 synchronized (this) {
8220 if (!persistent) {
8221 mOrigDebugApp = mDebugApp;
8222 mOrigWaitForDebugger = mWaitForDebugger;
8223 }
8224 mDebugApp = packageName;
8225 mWaitForDebugger = waitForDebugger;
8226 mDebugTransient = !persistent;
8227 if (packageName != null) {
8228 final long origId = Binder.clearCallingIdentity();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08008229 forceStopPackageLocked(packageName, -1, false, false, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008230 Binder.restoreCallingIdentity(origId);
8231 }
8232 }
8233 }
8234
8235 public void setAlwaysFinish(boolean enabled) {
8236 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
8237 "setAlwaysFinish()");
8238
8239 Settings.System.putInt(
8240 mContext.getContentResolver(),
8241 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
8242
8243 synchronized (this) {
8244 mAlwaysFinishActivities = enabled;
8245 }
8246 }
8247
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008248 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008249 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008250 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008251 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008252 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008253 }
8254 }
8255
Dianne Hackborn9327f4f2010-01-29 10:38:29 -08008256 public boolean isUserAMonkey() {
8257 // For now the fact that there is a controller implies
8258 // we have a monkey.
8259 synchronized (this) {
8260 return mController != null;
8261 }
8262 }
8263
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008264 public void registerActivityWatcher(IActivityWatcher watcher) {
8265 mWatchers.register(watcher);
8266 }
8267
8268 public void unregisterActivityWatcher(IActivityWatcher watcher) {
8269 mWatchers.unregister(watcher);
8270 }
8271
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008272 public final void enterSafeMode() {
8273 synchronized(this) {
8274 // It only makes sense to do this before the system is ready
8275 // and started launching other packages.
8276 if (!mSystemReady) {
8277 try {
8278 ActivityThread.getPackageManager().enterSafeMode();
8279 } catch (RemoteException e) {
8280 }
8281
8282 View v = LayoutInflater.from(mContext).inflate(
8283 com.android.internal.R.layout.safe_mode, null);
8284 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8285 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8286 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8287 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8288 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8289 lp.format = v.getBackground().getOpacity();
8290 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8291 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8292 ((WindowManager)mContext.getSystemService(
8293 Context.WINDOW_SERVICE)).addView(v, lp);
8294 }
8295 }
8296 }
8297
8298 public void noteWakeupAlarm(IIntentSender sender) {
8299 if (!(sender instanceof PendingIntentRecord)) {
8300 return;
8301 }
8302 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8303 synchronized (stats) {
8304 if (mBatteryStatsService.isOnBattery()) {
8305 mBatteryStatsService.enforceCallingPermission();
8306 PendingIntentRecord rec = (PendingIntentRecord)sender;
8307 int MY_UID = Binder.getCallingUid();
8308 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8309 BatteryStatsImpl.Uid.Pkg pkg =
8310 stats.getPackageStatsLocked(uid, rec.key.packageName);
8311 pkg.incWakeupsLocked();
8312 }
8313 }
8314 }
8315
8316 public boolean killPidsForMemory(int[] pids) {
8317 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8318 throw new SecurityException("killPidsForMemory only available to the system");
8319 }
8320
8321 // XXX Note: don't acquire main activity lock here, because the window
8322 // manager calls in with its locks held.
8323
8324 boolean killed = false;
8325 synchronized (mPidsSelfLocked) {
8326 int[] types = new int[pids.length];
8327 int worstType = 0;
8328 for (int i=0; i<pids.length; i++) {
8329 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8330 if (proc != null) {
8331 int type = proc.setAdj;
8332 types[i] = type;
8333 if (type > worstType) {
8334 worstType = type;
8335 }
8336 }
8337 }
8338
8339 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8340 // then constrain it so we will kill all hidden procs.
8341 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8342 worstType = HIDDEN_APP_MIN_ADJ;
8343 }
8344 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8345 for (int i=0; i<pids.length; i++) {
8346 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8347 if (proc == null) {
8348 continue;
8349 }
8350 int adj = proc.setAdj;
8351 if (adj >= worstType) {
8352 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8353 + adj + ")");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008354 EventLog.writeEvent(EventLogTags.AM_KILL_FOR_MEMORY, proc.pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008355 proc.processName, adj);
8356 killed = true;
8357 Process.killProcess(pids[i]);
8358 }
8359 }
8360 }
8361 return killed;
8362 }
8363
8364 public void reportPss(IApplicationThread caller, int pss) {
8365 Watchdog.PssRequestor req;
8366 String name;
8367 ProcessRecord callerApp;
8368 synchronized (this) {
8369 if (caller == null) {
8370 return;
8371 }
8372 callerApp = getRecordForAppLocked(caller);
8373 if (callerApp == null) {
8374 return;
8375 }
8376 callerApp.lastPss = pss;
8377 req = callerApp;
8378 name = callerApp.processName;
8379 }
8380 Watchdog.getInstance().reportPss(req, name, pss);
8381 if (!callerApp.persistent) {
8382 removeRequestedPss(callerApp);
8383 }
8384 }
8385
8386 public void requestPss(Runnable completeCallback) {
8387 ArrayList<ProcessRecord> procs;
8388 synchronized (this) {
8389 mRequestPssCallback = completeCallback;
8390 mRequestPssList.clear();
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008391 for (int i=mLruProcesses.size()-1; i>=0; i--) {
8392 ProcessRecord proc = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008393 if (!proc.persistent) {
8394 mRequestPssList.add(proc);
8395 }
8396 }
8397 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8398 }
8399
8400 int oldPri = Process.getThreadPriority(Process.myTid());
8401 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8402 for (int i=procs.size()-1; i>=0; i--) {
8403 ProcessRecord proc = procs.get(i);
8404 proc.lastPss = 0;
8405 proc.requestPss();
8406 }
8407 Process.setThreadPriority(oldPri);
8408 }
8409
8410 void removeRequestedPss(ProcessRecord proc) {
8411 Runnable callback = null;
8412 synchronized (this) {
8413 if (mRequestPssList.remove(proc)) {
8414 if (mRequestPssList.size() == 0) {
8415 callback = mRequestPssCallback;
8416 mRequestPssCallback = null;
8417 }
8418 }
8419 }
8420
8421 if (callback != null) {
8422 callback.run();
8423 }
8424 }
8425
8426 public void collectPss(Watchdog.PssStats stats) {
8427 stats.mEmptyPss = 0;
8428 stats.mEmptyCount = 0;
8429 stats.mBackgroundPss = 0;
8430 stats.mBackgroundCount = 0;
8431 stats.mServicePss = 0;
8432 stats.mServiceCount = 0;
8433 stats.mVisiblePss = 0;
8434 stats.mVisibleCount = 0;
8435 stats.mForegroundPss = 0;
8436 stats.mForegroundCount = 0;
8437 stats.mNoPssCount = 0;
8438 synchronized (this) {
8439 int i;
8440 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8441 ? mProcDeaths.length : stats.mProcDeaths.length;
8442 int aggr = 0;
8443 for (i=0; i<NPD; i++) {
8444 aggr += mProcDeaths[i];
8445 stats.mProcDeaths[i] = aggr;
8446 }
8447 while (i<stats.mProcDeaths.length) {
8448 stats.mProcDeaths[i] = 0;
8449 i++;
8450 }
8451
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008452 for (i=mLruProcesses.size()-1; i>=0; i--) {
8453 ProcessRecord proc = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008454 if (proc.persistent) {
8455 continue;
8456 }
8457 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8458 if (proc.lastPss == 0) {
8459 stats.mNoPssCount++;
8460 continue;
8461 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -08008462 if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8463 if (proc.empty) {
8464 stats.mEmptyPss += proc.lastPss;
8465 stats.mEmptyCount++;
8466 } else {
8467 stats.mBackgroundPss += proc.lastPss;
8468 stats.mBackgroundCount++;
8469 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008470 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8471 stats.mVisiblePss += proc.lastPss;
8472 stats.mVisibleCount++;
8473 } else {
8474 stats.mForegroundPss += proc.lastPss;
8475 stats.mForegroundCount++;
8476 }
8477 }
8478 }
8479 }
8480
8481 public final void startRunning(String pkg, String cls, String action,
8482 String data) {
8483 synchronized(this) {
8484 if (mStartRunning) {
8485 return;
8486 }
8487 mStartRunning = true;
8488 mTopComponent = pkg != null && cls != null
8489 ? new ComponentName(pkg, cls) : null;
8490 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8491 mTopData = data;
8492 if (!mSystemReady) {
8493 return;
8494 }
8495 }
8496
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008497 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008498 }
8499
8500 private void retrieveSettings() {
8501 final ContentResolver resolver = mContext.getContentResolver();
8502 String debugApp = Settings.System.getString(
8503 resolver, Settings.System.DEBUG_APP);
8504 boolean waitForDebugger = Settings.System.getInt(
8505 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8506 boolean alwaysFinishActivities = Settings.System.getInt(
8507 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8508
8509 Configuration configuration = new Configuration();
8510 Settings.System.getConfiguration(resolver, configuration);
8511
8512 synchronized (this) {
8513 mDebugApp = mOrigDebugApp = debugApp;
8514 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8515 mAlwaysFinishActivities = alwaysFinishActivities;
8516 // This happens before any activities are started, so we can
8517 // change mConfiguration in-place.
8518 mConfiguration.updateFrom(configuration);
Dianne Hackborne36d6e22010-02-17 19:46:25 -08008519 mConfigurationSeq = mConfiguration.seq = 1;
Dianne Hackborndc6b6352009-09-30 14:20:09 -07008520 if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008521 }
8522 }
8523
8524 public boolean testIsSystemReady() {
8525 // no need to synchronize(this) just to read & return the value
8526 return mSystemReady;
8527 }
8528
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008529 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008530 // In the simulator, startRunning will never have been called, which
8531 // normally sets a few crucial variables. Do it here instead.
8532 if (!Process.supportsProcesses()) {
8533 mStartRunning = true;
8534 mTopAction = Intent.ACTION_MAIN;
8535 }
8536
8537 synchronized(this) {
8538 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008539 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008540 return;
8541 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008542
8543 // Check to see if there are any update receivers to run.
8544 if (!mDidUpdate) {
8545 if (mWaitingUpdate) {
8546 return;
8547 }
8548 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8549 List<ResolveInfo> ris = null;
8550 try {
8551 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8552 intent, null, 0);
8553 } catch (RemoteException e) {
8554 }
8555 if (ris != null) {
8556 for (int i=ris.size()-1; i>=0; i--) {
8557 if ((ris.get(i).activityInfo.applicationInfo.flags
8558 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8559 ris.remove(i);
8560 }
8561 }
8562 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8563 for (int i=0; i<ris.size(); i++) {
8564 ActivityInfo ai = ris.get(i).activityInfo;
8565 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8566 IIntentReceiver finisher = null;
Dianne Hackbornd6847842010-01-12 18:14:19 -08008567 if (i == ris.size()-1) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008568 finisher = new IIntentReceiver.Stub() {
8569 public void performReceive(Intent intent, int resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -07008570 String data, Bundle extras, boolean ordered,
8571 boolean sticky)
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008572 throws RemoteException {
8573 synchronized (ActivityManagerService.this) {
8574 mDidUpdate = true;
8575 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008576 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008577 }
8578 };
8579 }
8580 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8581 broadcastIntentLocked(null, null, intent, null, finisher,
8582 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornd6847842010-01-12 18:14:19 -08008583 if (finisher != null) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008584 mWaitingUpdate = true;
8585 }
8586 }
8587 }
8588 if (mWaitingUpdate) {
8589 return;
8590 }
8591 mDidUpdate = true;
8592 }
8593
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008594 mSystemReady = true;
8595 if (!mStartRunning) {
8596 return;
8597 }
8598 }
8599
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008600 ArrayList<ProcessRecord> procsToKill = null;
8601 synchronized(mPidsSelfLocked) {
8602 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8603 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8604 if (!isAllowedWhileBooting(proc.info)){
8605 if (procsToKill == null) {
8606 procsToKill = new ArrayList<ProcessRecord>();
8607 }
8608 procsToKill.add(proc);
8609 }
8610 }
8611 }
8612
8613 if (procsToKill != null) {
8614 synchronized(this) {
8615 for (int i=procsToKill.size()-1; i>=0; i--) {
8616 ProcessRecord proc = procsToKill.get(i);
8617 Log.i(TAG, "Removing system update proc: " + proc);
8618 removeProcessLocked(proc, true);
8619 }
8620 }
8621 }
8622
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008623 Log.i(TAG, "System now ready");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008624 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008625 SystemClock.uptimeMillis());
8626
8627 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008628 // Make sure we have no pre-ready processes sitting around.
8629
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008630 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8631 ResolveInfo ri = mContext.getPackageManager()
8632 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008633 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008634 CharSequence errorMsg = null;
8635 if (ri != null) {
8636 ActivityInfo ai = ri.activityInfo;
8637 ApplicationInfo app = ai.applicationInfo;
8638 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8639 mTopAction = Intent.ACTION_FACTORY_TEST;
8640 mTopData = null;
8641 mTopComponent = new ComponentName(app.packageName,
8642 ai.name);
8643 } else {
8644 errorMsg = mContext.getResources().getText(
8645 com.android.internal.R.string.factorytest_not_system);
8646 }
8647 } else {
8648 errorMsg = mContext.getResources().getText(
8649 com.android.internal.R.string.factorytest_no_action);
8650 }
8651 if (errorMsg != null) {
8652 mTopAction = null;
8653 mTopData = null;
8654 mTopComponent = null;
8655 Message msg = Message.obtain();
8656 msg.what = SHOW_FACTORY_ERROR_MSG;
8657 msg.getData().putCharSequence("msg", errorMsg);
8658 mHandler.sendMessage(msg);
8659 }
8660 }
8661 }
8662
8663 retrieveSettings();
8664
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008665 if (goingCallback != null) goingCallback.run();
8666
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008667 synchronized (this) {
8668 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8669 try {
8670 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008671 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008672 if (apps != null) {
8673 int N = apps.size();
8674 int i;
8675 for (i=0; i<N; i++) {
8676 ApplicationInfo info
8677 = (ApplicationInfo)apps.get(i);
8678 if (info != null &&
8679 !info.packageName.equals("android")) {
8680 addAppLocked(info);
8681 }
8682 }
8683 }
8684 } catch (RemoteException ex) {
8685 // pm is in same process, this will never happen.
8686 }
8687 }
8688
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008689 // Start up initial activity.
8690 mBooting = true;
8691
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008692 try {
8693 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8694 Message msg = Message.obtain();
8695 msg.what = SHOW_UID_ERROR_MSG;
8696 mHandler.sendMessage(msg);
8697 }
8698 } catch (RemoteException e) {
8699 }
8700
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008701 resumeTopActivityLocked(null);
8702 }
8703 }
8704
Dan Egnorb7f03672009-12-09 16:22:32 -08008705 private boolean makeAppCrashingLocked(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008706 String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008707 app.crashing = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008708 app.crashingReport = generateProcessError(app,
Dan Egnor60d87622009-12-16 16:32:58 -08008709 ActivityManager.ProcessErrorStateInfo.CRASHED, null, shortMsg, longMsg, stackTrace);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008710 startAppProblemLocked(app);
8711 app.stopFreezingAllLocked();
8712 return handleAppCrashLocked(app);
8713 }
8714
Dan Egnorb7f03672009-12-09 16:22:32 -08008715 private void makeAppNotRespondingLocked(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008716 String activity, String shortMsg, String longMsg) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008717 app.notResponding = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008718 app.notRespondingReport = generateProcessError(app,
Dan Egnor60d87622009-12-16 16:32:58 -08008719 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING,
8720 activity, shortMsg, longMsg, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008721 startAppProblemLocked(app);
8722 app.stopFreezingAllLocked();
8723 }
8724
8725 /**
8726 * Generate a process error record, suitable for attachment to a ProcessRecord.
8727 *
8728 * @param app The ProcessRecord in which the error occurred.
8729 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8730 * ActivityManager.AppErrorStateInfo
Dan Egnor60d87622009-12-16 16:32:58 -08008731 * @param activity The activity associated with the crash, if known.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008732 * @param shortMsg Short message describing the crash.
8733 * @param longMsg Long message describing the crash.
Dan Egnorb7f03672009-12-09 16:22:32 -08008734 * @param stackTrace Full crash stack trace, may be null.
8735 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008736 * @return Returns a fully-formed AppErrorStateInfo record.
8737 */
8738 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
Dan Egnor60d87622009-12-16 16:32:58 -08008739 int condition, String activity, String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008740 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
Dan Egnorb7f03672009-12-09 16:22:32 -08008741
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008742 report.condition = condition;
8743 report.processName = app.processName;
8744 report.pid = app.pid;
8745 report.uid = app.info.uid;
Dan Egnor60d87622009-12-16 16:32:58 -08008746 report.tag = activity;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008747 report.shortMsg = shortMsg;
8748 report.longMsg = longMsg;
Dan Egnorb7f03672009-12-09 16:22:32 -08008749 report.stackTrace = stackTrace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008750
8751 return report;
8752 }
8753
Dan Egnor42471dd2010-01-07 17:25:22 -08008754 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008755 synchronized (this) {
8756 app.crashing = false;
8757 app.crashingReport = null;
8758 app.notResponding = false;
8759 app.notRespondingReport = null;
8760 if (app.anrDialog == fromDialog) {
8761 app.anrDialog = null;
8762 }
8763 if (app.waitDialog == fromDialog) {
8764 app.waitDialog = null;
8765 }
8766 if (app.pid > 0 && app.pid != MY_PID) {
Dan Egnor42471dd2010-01-07 17:25:22 -08008767 handleAppCrashLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008768 Log.i(ActivityManagerService.TAG, "Killing process "
8769 + app.processName
8770 + " (pid=" + app.pid + ") at user's request");
8771 Process.killProcess(app.pid);
8772 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008773 }
8774 }
Dan Egnor42471dd2010-01-07 17:25:22 -08008775
Dan Egnorb7f03672009-12-09 16:22:32 -08008776 private boolean handleAppCrashLocked(ProcessRecord app) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008777 long now = SystemClock.uptimeMillis();
8778
8779 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8780 app.info.uid);
8781 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8782 // This process loses!
8783 Log.w(TAG, "Process " + app.info.processName
8784 + " has crashed too many times: killing!");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008785 EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008786 app.info.processName, app.info.uid);
8787 killServicesLocked(app, false);
8788 for (int i=mHistory.size()-1; i>=0; i--) {
8789 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8790 if (r.app == app) {
Dianne Hackborn03abb812010-01-04 18:43:19 -08008791 Log.w(TAG, " Force finishing activity "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008792 + r.intent.getComponent().flattenToShortString());
8793 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8794 }
8795 }
8796 if (!app.persistent) {
8797 // We don't want to start this process again until the user
8798 // explicitly does so... but for persistent process, we really
8799 // need to keep it running. If a persistent process is actually
8800 // repeatedly crashing, then badness for everyone.
Doug Zongker2bec3d42009-12-04 12:52:44 -08008801 EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008802 app.info.processName);
8803 mBadProcesses.put(app.info.processName, app.info.uid, now);
8804 app.bad = true;
8805 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8806 app.removed = true;
8807 removeProcessLocked(app, false);
8808 return false;
8809 }
8810 }
8811
8812 // Bump up the crash count of any services currently running in the proc.
8813 if (app.services.size() != 0) {
8814 // Any services running in the application need to be placed
8815 // back in the pending list.
8816 Iterator it = app.services.iterator();
8817 while (it.hasNext()) {
8818 ServiceRecord sr = (ServiceRecord)it.next();
8819 sr.crashCount++;
8820 }
8821 }
8822
8823 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8824 return true;
8825 }
8826
8827 void startAppProblemLocked(ProcessRecord app) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -08008828 app.errorReportReceiver = ApplicationErrorReport.getErrorReportReceiver(
8829 mContext, app.info.packageName, app.info.flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008830 skipCurrentReceiverLocked(app);
8831 }
8832
8833 void skipCurrentReceiverLocked(ProcessRecord app) {
8834 boolean reschedule = false;
8835 BroadcastRecord r = app.curReceiver;
8836 if (r != null) {
8837 // The current broadcast is waiting for this app's receiver
8838 // to be finished. Looks like that's not going to happen, so
8839 // let the broadcast continue.
8840 logBroadcastReceiverDiscard(r);
8841 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8842 r.resultExtras, r.resultAbort, true);
8843 reschedule = true;
8844 }
8845 r = mPendingBroadcast;
8846 if (r != null && r.curApp == app) {
8847 if (DEBUG_BROADCAST) Log.v(TAG,
8848 "skip & discard pending app " + r);
8849 logBroadcastReceiverDiscard(r);
8850 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8851 r.resultExtras, r.resultAbort, true);
8852 reschedule = true;
8853 }
8854 if (reschedule) {
8855 scheduleBroadcastsLocked();
8856 }
8857 }
8858
Dan Egnor60d87622009-12-16 16:32:58 -08008859 /**
8860 * Used by {@link com.android.internal.os.RuntimeInit} to report when an application crashes.
8861 * The application process will exit immediately after this call returns.
8862 * @param app object of the crashing app, null for the system server
8863 * @param crashInfo describing the exception
8864 */
8865 public void handleApplicationCrash(IBinder app, ApplicationErrorReport.CrashInfo crashInfo) {
8866 ProcessRecord r = findAppProcess(app);
8867
8868 EventLog.writeEvent(EventLogTags.AM_CRASH, Binder.getCallingPid(),
8869 app == null ? "system" : (r == null ? "unknown" : r.processName),
Dan Egnor2780e732010-01-22 14:47:35 -08008870 r == null ? -1 : r.info.flags,
Dan Egnor60d87622009-12-16 16:32:58 -08008871 crashInfo.exceptionClassName,
8872 crashInfo.exceptionMessage,
8873 crashInfo.throwFileName,
8874 crashInfo.throwLineNumber);
8875
Dan Egnor42471dd2010-01-07 17:25:22 -08008876 addErrorToDropBox("crash", r, null, null, null, null, null, crashInfo);
Dan Egnor60d87622009-12-16 16:32:58 -08008877
8878 crashApplication(r, crashInfo);
8879 }
8880
8881 /**
8882 * Used by {@link Log} via {@link com.android.internal.os.RuntimeInit} to report serious errors.
8883 * @param app object of the crashing app, null for the system server
8884 * @param tag reported by the caller
8885 * @param crashInfo describing the context of the error
8886 * @return true if the process should exit immediately (WTF is fatal)
8887 */
8888 public boolean handleApplicationWtf(IBinder app, String tag,
Dan Egnorb7f03672009-12-09 16:22:32 -08008889 ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnor60d87622009-12-16 16:32:58 -08008890 ProcessRecord r = findAppProcess(app);
8891
8892 EventLog.writeEvent(EventLogTags.AM_WTF, Binder.getCallingPid(),
8893 app == null ? "system" : (r == null ? "unknown" : r.processName),
Dan Egnor2780e732010-01-22 14:47:35 -08008894 r == null ? -1 : r.info.flags,
Dan Egnor60d87622009-12-16 16:32:58 -08008895 tag, crashInfo.exceptionMessage);
8896
Dan Egnor42471dd2010-01-07 17:25:22 -08008897 addErrorToDropBox("wtf", r, null, null, tag, null, null, crashInfo);
Dan Egnor60d87622009-12-16 16:32:58 -08008898
Doug Zongker43866e02010-01-07 12:09:54 -08008899 if (Settings.Secure.getInt(mContext.getContentResolver(),
8900 Settings.Secure.WTF_IS_FATAL, 0) != 0) {
Dan Egnor60d87622009-12-16 16:32:58 -08008901 crashApplication(r, crashInfo);
8902 return true;
8903 } else {
8904 return false;
8905 }
8906 }
8907
8908 /**
8909 * @param app object of some object (as stored in {@link com.android.internal.os.RuntimeInit})
8910 * @return the corresponding {@link ProcessRecord} object, or null if none could be found
8911 */
8912 private ProcessRecord findAppProcess(IBinder app) {
8913 if (app == null) {
8914 return null;
8915 }
8916
8917 synchronized (this) {
8918 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8919 final int NA = apps.size();
8920 for (int ia=0; ia<NA; ia++) {
8921 ProcessRecord p = apps.valueAt(ia);
8922 if (p.thread != null && p.thread.asBinder() == app) {
8923 return p;
8924 }
8925 }
8926 }
8927
8928 Log.w(TAG, "Can't find mystery application: " + app);
8929 return null;
8930 }
8931 }
8932
8933 /**
Dan Egnor42471dd2010-01-07 17:25:22 -08008934 * Write a description of an error (crash, WTF, ANR) to the drop box.
Dan Egnor60d87622009-12-16 16:32:58 -08008935 * @param eventType to include in the drop box tag ("crash", "wtf", etc.)
Dan Egnor42471dd2010-01-07 17:25:22 -08008936 * @param process which caused the error, null means the system server
8937 * @param activity which triggered the error, null if unknown
8938 * @param parent activity related to the error, null if unknown
8939 * @param subject line related to the error, null if absent
8940 * @param report in long form describing the error, null if absent
8941 * @param logFile to include in the report, null if none
8942 * @param crashInfo giving an application stack trace, null if absent
Dan Egnor60d87622009-12-16 16:32:58 -08008943 */
Dan Egnor42471dd2010-01-07 17:25:22 -08008944 private void addErrorToDropBox(String eventType,
8945 ProcessRecord process, HistoryRecord activity, HistoryRecord parent,
8946 String subject, String report, File logFile,
Dan Egnor60d87622009-12-16 16:32:58 -08008947 ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnor42471dd2010-01-07 17:25:22 -08008948 String dropboxTag;
8949 if (process == null || process.pid == MY_PID) {
Dan Egnor60d87622009-12-16 16:32:58 -08008950 dropboxTag = "system_server_" + eventType;
Dan Egnor42471dd2010-01-07 17:25:22 -08008951 } else if ((process.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
Dan Egnor60d87622009-12-16 16:32:58 -08008952 dropboxTag = "system_app_" + eventType;
8953 } else {
8954 dropboxTag = "data_app_" + eventType;
8955 }
8956
8957 DropBoxManager dbox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
8958 if (dbox != null && dbox.isTagEnabled(dropboxTag)) {
8959 StringBuilder sb = new StringBuilder(1024);
Dan Egnor42471dd2010-01-07 17:25:22 -08008960 if (process == null || process.pid == MY_PID) {
Dan Egnor60d87622009-12-16 16:32:58 -08008961 sb.append("Process: system_server\n");
8962 } else {
Dan Egnor42471dd2010-01-07 17:25:22 -08008963 sb.append("Process: ").append(process.processName).append("\n");
Dan Egnor66c40e72010-01-26 16:23:11 -08008964 }
8965 if (process != null) {
8966 int flags = process.info.flags;
8967 IPackageManager pm = ActivityThread.getPackageManager();
8968 sb.append("Flags: 0x").append(Integer.toString(flags, 16)).append("\n");
8969 for (String pkg : process.pkgList) {
8970 sb.append("Package: ").append(pkg);
8971 try {
8972 PackageInfo pi = pm.getPackageInfo(pkg, 0);
8973 if (pi != null) {
8974 sb.append(" v").append(pi.versionCode);
8975 if (pi.versionName != null) {
8976 sb.append(" (").append(pi.versionName).append(")");
8977 }
8978 }
8979 } catch (RemoteException e) {
8980 Log.e(TAG, "Error getting package info: " + pkg, e);
8981 }
8982 sb.append("\n");
8983 }
Dan Egnor42471dd2010-01-07 17:25:22 -08008984 }
8985 if (activity != null) {
8986 sb.append("Activity: ").append(activity.shortComponentName).append("\n");
8987 }
8988 if (parent != null && parent.app != null && parent.app.pid != process.pid) {
8989 sb.append("Parent-Process: ").append(parent.app.processName).append("\n");
8990 }
8991 if (parent != null && parent != activity) {
8992 sb.append("Parent-Activity: ").append(parent.shortComponentName).append("\n");
8993 }
8994 if (subject != null) {
8995 sb.append("Subject: ").append(subject).append("\n");
8996 }
8997 sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
8998 sb.append("\n");
8999 if (report != null) {
9000 sb.append(report);
9001 }
9002 if (logFile != null) {
9003 try {
9004 sb.append(FileUtils.readTextFile(logFile, 128 * 1024, "\n\n[[TRUNCATED]]"));
9005 } catch (IOException e) {
9006 Log.e(TAG, "Error reading " + logFile, e);
Dan Egnor60d87622009-12-16 16:32:58 -08009007 }
9008 }
Dan Egnor60d87622009-12-16 16:32:58 -08009009 if (crashInfo != null && crashInfo.stackTrace != null) {
Dan Egnor42471dd2010-01-07 17:25:22 -08009010 sb.append(crashInfo.stackTrace);
Dan Egnor60d87622009-12-16 16:32:58 -08009011 }
9012 dbox.addText(dropboxTag, sb.toString());
9013 }
9014 }
9015
9016 /**
9017 * Bring up the "unexpected error" dialog box for a crashing app.
9018 * Deal with edge cases (intercepts from instrumented applications,
9019 * ActivityController, error intent receivers, that sort of thing).
9020 * @param r the application crashing
9021 * @param crashInfo describing the failure
9022 */
9023 private void crashApplication(ProcessRecord r, ApplicationErrorReport.CrashInfo crashInfo) {
Dan Egnorb7f03672009-12-09 16:22:32 -08009024 long timeMillis = System.currentTimeMillis();
9025 String shortMsg = crashInfo.exceptionClassName;
9026 String longMsg = crashInfo.exceptionMessage;
9027 String stackTrace = crashInfo.stackTrace;
9028 if (shortMsg != null && longMsg != null) {
9029 longMsg = shortMsg + ": " + longMsg;
9030 } else if (shortMsg != null) {
9031 longMsg = shortMsg;
9032 }
9033
Dan Egnor60d87622009-12-16 16:32:58 -08009034 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009035 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07009036 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009037 try {
9038 String name = r != null ? r.processName : null;
9039 int pid = r != null ? r.pid : Binder.getCallingPid();
Dan Egnor60d87622009-12-16 16:32:58 -08009040 if (!mController.appCrashed(name, pid,
Dan Egnorb7f03672009-12-09 16:22:32 -08009041 shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009042 Log.w(TAG, "Force-killing crashed app " + name
9043 + " at watcher's request");
9044 Process.killProcess(pid);
Dan Egnorb7f03672009-12-09 16:22:32 -08009045 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009046 }
9047 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07009048 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009049 }
9050 }
9051
9052 final long origId = Binder.clearCallingIdentity();
9053
9054 // If this process is running instrumentation, finish it.
9055 if (r != null && r.instrumentationClass != null) {
9056 Log.w(TAG, "Error in app " + r.processName
9057 + " running instrumentation " + r.instrumentationClass + ":");
9058 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
9059 if (longMsg != null) Log.w(TAG, " " + longMsg);
9060 Bundle info = new Bundle();
9061 info.putString("shortMsg", shortMsg);
9062 info.putString("longMsg", longMsg);
9063 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
9064 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08009065 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009066 }
9067
Dan Egnor60d87622009-12-16 16:32:58 -08009068 // If we can't identify the process or it's already exceeded its crash quota,
9069 // quit right away without showing a crash dialog.
9070 if (r == null || !makeAppCrashingLocked(r, shortMsg, longMsg, stackTrace)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009071 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08009072 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009073 }
9074
9075 Message msg = Message.obtain();
9076 msg.what = SHOW_ERROR_MSG;
9077 HashMap data = new HashMap();
9078 data.put("result", result);
9079 data.put("app", r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009080 msg.obj = data;
9081 mHandler.sendMessage(msg);
9082
9083 Binder.restoreCallingIdentity(origId);
9084 }
9085
9086 int res = result.get();
9087
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009088 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009089 synchronized (this) {
9090 if (r != null) {
9091 mProcessCrashTimes.put(r.info.processName, r.info.uid,
9092 SystemClock.uptimeMillis());
9093 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009094 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
Dan Egnorb7f03672009-12-09 16:22:32 -08009095 appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009096 }
9097 }
9098
9099 if (appErrorIntent != null) {
9100 try {
9101 mContext.startActivity(appErrorIntent);
9102 } catch (ActivityNotFoundException e) {
9103 Log.w(TAG, "bug report receiver dissappeared", e);
9104 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009105 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009106 }
Dan Egnorb7f03672009-12-09 16:22:32 -08009107
9108 Intent createAppErrorIntentLocked(ProcessRecord r,
9109 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
9110 ApplicationErrorReport report = createAppErrorReportLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009111 if (report == null) {
9112 return null;
9113 }
9114 Intent result = new Intent(Intent.ACTION_APP_ERROR);
9115 result.setComponent(r.errorReportReceiver);
9116 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
9117 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
9118 return result;
9119 }
9120
Dan Egnorb7f03672009-12-09 16:22:32 -08009121 private ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r,
9122 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009123 if (r.errorReportReceiver == null) {
9124 return null;
9125 }
9126
9127 if (!r.crashing && !r.notResponding) {
9128 return null;
9129 }
9130
Dan Egnorb7f03672009-12-09 16:22:32 -08009131 ApplicationErrorReport report = new ApplicationErrorReport();
9132 report.packageName = r.info.packageName;
9133 report.installerPackageName = r.errorReportReceiver.getPackageName();
9134 report.processName = r.processName;
9135 report.time = timeMillis;
Jacek Surazskie0ee6ef2010-01-07 16:23:03 +01009136 report.systemApp = (r.info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009137
Dan Egnorb7f03672009-12-09 16:22:32 -08009138 if (r.crashing) {
9139 report.type = ApplicationErrorReport.TYPE_CRASH;
9140 report.crashInfo = crashInfo;
9141 } else if (r.notResponding) {
9142 report.type = ApplicationErrorReport.TYPE_ANR;
9143 report.anrInfo = new ApplicationErrorReport.AnrInfo();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009144
Dan Egnorb7f03672009-12-09 16:22:32 -08009145 report.anrInfo.activity = r.notRespondingReport.tag;
9146 report.anrInfo.cause = r.notRespondingReport.shortMsg;
9147 report.anrInfo.info = r.notRespondingReport.longMsg;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009148 }
9149
Dan Egnorb7f03672009-12-09 16:22:32 -08009150 return report;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02009151 }
9152
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009153 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
9154 // assume our apps are happy - lazy create the list
9155 List<ActivityManager.ProcessErrorStateInfo> errList = null;
9156
9157 synchronized (this) {
9158
9159 // iterate across all processes
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009160 for (int i=mLruProcesses.size()-1; i>=0; i--) {
9161 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009162 if ((app.thread != null) && (app.crashing || app.notResponding)) {
9163 // This one's in trouble, so we'll generate a report for it
9164 // crashes are higher priority (in case there's a crash *and* an anr)
9165 ActivityManager.ProcessErrorStateInfo report = null;
9166 if (app.crashing) {
9167 report = app.crashingReport;
9168 } else if (app.notResponding) {
9169 report = app.notRespondingReport;
9170 }
9171
9172 if (report != null) {
9173 if (errList == null) {
9174 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
9175 }
9176 errList.add(report);
9177 } else {
9178 Log.w(TAG, "Missing app error report, app = " + app.processName +
9179 " crashing = " + app.crashing +
9180 " notResponding = " + app.notResponding);
9181 }
9182 }
9183 }
9184 }
9185
9186 return errList;
9187 }
9188
9189 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
9190 // Lazy instantiation of list
9191 List<ActivityManager.RunningAppProcessInfo> runList = null;
9192 synchronized (this) {
9193 // Iterate across all processes
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009194 for (int i=mLruProcesses.size()-1; i>=0; i--) {
9195 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009196 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
9197 // Generate process state info for running application
9198 ActivityManager.RunningAppProcessInfo currApp =
9199 new ActivityManager.RunningAppProcessInfo(app.processName,
9200 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07009201 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009202 int adj = app.curAdj;
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009203 if (adj >= EMPTY_APP_ADJ) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009204 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
9205 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
9206 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08009207 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
9208 } else if (adj >= HOME_APP_ADJ) {
9209 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
9210 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009211 } else if (adj >= SECONDARY_SERVER_ADJ) {
9212 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
9213 } else if (adj >= VISIBLE_APP_ADJ) {
9214 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
9215 } else {
9216 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
9217 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07009218 currApp.importanceReasonCode = app.adjTypeCode;
9219 if (app.adjSource instanceof ProcessRecord) {
9220 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
9221 } else if (app.adjSource instanceof HistoryRecord) {
9222 HistoryRecord r = (HistoryRecord)app.adjSource;
9223 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
9224 }
9225 if (app.adjTarget instanceof ComponentName) {
9226 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
9227 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009228 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
9229 // + " lru=" + currApp.lru);
9230 if (runList == null) {
9231 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
9232 }
9233 runList.add(currApp);
9234 }
9235 }
9236 }
9237 return runList;
9238 }
9239
9240 @Override
9241 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009242 if (checkCallingPermission(android.Manifest.permission.DUMP)
9243 != PackageManager.PERMISSION_GRANTED) {
9244 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9245 + Binder.getCallingPid()
9246 + ", uid=" + Binder.getCallingUid()
9247 + " without permission "
9248 + android.Manifest.permission.DUMP);
9249 return;
9250 }
9251
9252 boolean dumpAll = false;
9253
9254 int opti = 0;
9255 while (opti < args.length) {
9256 String opt = args[opti];
9257 if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') {
9258 break;
9259 }
9260 opti++;
9261 if ("-a".equals(opt)) {
9262 dumpAll = true;
9263 } else if ("-h".equals(opt)) {
9264 pw.println("Activity manager dump options:");
9265 pw.println(" [-a] [h- [cmd] ...");
9266 pw.println(" cmd may be one of:");
9267 pw.println(" activities: activity stack state");
9268 pw.println(" broadcasts: broadcast state");
9269 pw.println(" intents: pending intent state");
9270 pw.println(" processes: process state");
9271 pw.println(" providers: content provider state");
9272 pw.println(" services: service state");
9273 pw.println(" service [name]: service client-side state");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009274 return;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009275 } else {
9276 pw.println("Unknown argument: " + opt + "; use -h for help");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009277 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009278 }
9279
9280 // Is the caller requesting to dump a particular piece of data?
9281 if (opti < args.length) {
9282 String cmd = args[opti];
9283 opti++;
9284 if ("activities".equals(cmd) || "a".equals(cmd)) {
9285 synchronized (this) {
9286 dumpActivitiesLocked(fd, pw, args, opti, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009287 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009288 return;
9289 } else if ("broadcasts".equals(cmd) || "b".equals(cmd)) {
9290 synchronized (this) {
9291 dumpBroadcastsLocked(fd, pw, args, opti, true);
9292 }
9293 return;
9294 } else if ("intents".equals(cmd) || "i".equals(cmd)) {
9295 synchronized (this) {
9296 dumpPendingIntentsLocked(fd, pw, args, opti, true);
9297 }
9298 return;
9299 } else if ("processes".equals(cmd) || "p".equals(cmd)) {
9300 synchronized (this) {
9301 dumpProcessesLocked(fd, pw, args, opti, true);
9302 }
9303 return;
9304 } else if ("providers".equals(cmd) || "prov".equals(cmd)) {
9305 synchronized (this) {
9306 dumpProvidersLocked(fd, pw, args, opti, true);
9307 }
9308 return;
9309 } else if ("service".equals(cmd)) {
9310 dumpService(fd, pw, args, opti, true);
9311 return;
9312 } else if ("services".equals(cmd) || "s".equals(cmd)) {
9313 synchronized (this) {
9314 dumpServicesLocked(fd, pw, args, opti, true);
9315 }
9316 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009317 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009318 }
9319
9320 // No piece of data specified, dump everything.
9321 synchronized (this) {
9322 boolean needSep;
9323 if (dumpAll) {
9324 pw.println("Providers in Current Activity Manager State:");
9325 }
9326 needSep = dumpProvidersLocked(fd, pw, args, opti, dumpAll);
9327 if (needSep) {
9328 pw.println(" ");
9329 }
9330 if (dumpAll) {
9331 pw.println("-------------------------------------------------------------------------------");
9332 pw.println("Broadcasts in Current Activity Manager State:");
9333 }
9334 needSep = dumpBroadcastsLocked(fd, pw, args, opti, dumpAll);
9335 if (needSep) {
9336 pw.println(" ");
9337 }
9338 if (dumpAll) {
9339 pw.println("-------------------------------------------------------------------------------");
9340 pw.println("Services in Current Activity Manager State:");
9341 }
9342 needSep = dumpServicesLocked(fd, pw, args, opti, dumpAll);
9343 if (needSep) {
9344 pw.println(" ");
9345 }
9346 if (dumpAll) {
9347 pw.println("-------------------------------------------------------------------------------");
9348 pw.println("PendingIntents in Current Activity Manager State:");
9349 }
9350 needSep = dumpPendingIntentsLocked(fd, pw, args, opti, dumpAll);
9351 if (needSep) {
9352 pw.println(" ");
9353 }
9354 if (dumpAll) {
9355 pw.println("-------------------------------------------------------------------------------");
9356 pw.println("Activities in Current Activity Manager State:");
9357 }
9358 needSep = dumpActivitiesLocked(fd, pw, args, opti, dumpAll, !dumpAll);
9359 if (needSep) {
9360 pw.println(" ");
9361 }
9362 if (dumpAll) {
9363 pw.println("-------------------------------------------------------------------------------");
9364 pw.println("Processes in Current Activity Manager State:");
9365 }
9366 dumpProcessesLocked(fd, pw, args, opti, dumpAll);
9367 }
9368 }
9369
9370 boolean dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9371 int opti, boolean dumpAll, boolean needHeader) {
9372 if (needHeader) {
9373 pw.println(" Activity stack:");
9374 }
9375 dumpHistoryList(pw, mHistory, " ", "Hist", true);
9376 pw.println(" ");
9377 pw.println(" Running activities (most recent first):");
9378 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
9379 if (mWaitingVisibleActivities.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009380 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009381 pw.println(" Activities waiting for another to become visible:");
9382 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
9383 }
9384 if (mStoppingActivities.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009385 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009386 pw.println(" Activities waiting to stop:");
9387 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
9388 }
9389 if (mFinishingActivities.size() > 0) {
9390 pw.println(" ");
9391 pw.println(" Activities waiting to finish:");
9392 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
9393 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009394
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009395 pw.println(" ");
9396 pw.println(" mPausingActivity: " + mPausingActivity);
9397 pw.println(" mResumedActivity: " + mResumedActivity);
9398 pw.println(" mFocusedActivity: " + mFocusedActivity);
9399 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009400
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009401 if (dumpAll && mRecentTasks.size() > 0) {
9402 pw.println(" ");
9403 pw.println("Recent tasks in Current Activity Manager State:");
9404
9405 final int N = mRecentTasks.size();
9406 for (int i=0; i<N; i++) {
9407 TaskRecord tr = mRecentTasks.get(i);
9408 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
9409 pw.println(tr);
9410 mRecentTasks.get(i).dump(pw, " ");
9411 }
9412 }
9413
9414 pw.println(" ");
9415 pw.println(" mCurTask: " + mCurTask);
9416
9417 return true;
9418 }
9419
9420 boolean dumpProcessesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9421 int opti, boolean dumpAll) {
9422 boolean needSep = false;
9423 int numPers = 0;
9424
9425 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009426 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
9427 final int NA = procs.size();
9428 for (int ia=0; ia<NA; ia++) {
9429 if (!needSep) {
9430 pw.println(" All known processes:");
9431 needSep = true;
9432 }
9433 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009434 pw.print(r.persistent ? " *PERS*" : " *APP*");
9435 pw.print(" UID "); pw.print(procs.keyAt(ia));
9436 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009437 r.dump(pw, " ");
9438 if (r.persistent) {
9439 numPers++;
9440 }
9441 }
9442 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009443 }
9444
9445 if (mLruProcesses.size() > 0) {
9446 if (needSep) pw.println(" ");
9447 needSep = true;
9448 pw.println(" Running processes (most recent first):");
9449 dumpProcessList(pw, this, mLruProcesses, " ",
9450 "App ", "PERS", true);
9451 needSep = true;
9452 }
9453
9454 synchronized (mPidsSelfLocked) {
9455 if (mPidsSelfLocked.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009456 if (needSep) pw.println(" ");
9457 needSep = true;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009458 pw.println(" PID mappings:");
9459 for (int i=0; i<mPidsSelfLocked.size(); i++) {
9460 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9461 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009462 }
9463 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009464 }
9465
9466 if (mForegroundProcesses.size() > 0) {
9467 if (needSep) pw.println(" ");
9468 needSep = true;
9469 pw.println(" Foreground Processes:");
9470 for (int i=0; i<mForegroundProcesses.size(); i++) {
9471 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9472 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009473 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009474 }
9475
9476 if (mPersistentStartingProcesses.size() > 0) {
9477 if (needSep) pw.println(" ");
9478 needSep = true;
9479 pw.println(" Persisent processes that are starting:");
9480 dumpProcessList(pw, this, mPersistentStartingProcesses, " ",
9481 "Starting Norm", "Restarting PERS", false);
9482 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009483
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009484 if (mStartingProcesses.size() > 0) {
9485 if (needSep) pw.println(" ");
9486 needSep = true;
9487 pw.println(" Processes that are starting:");
9488 dumpProcessList(pw, this, mStartingProcesses, " ",
9489 "Starting Norm", "Starting PERS", false);
9490 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009491
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009492 if (mRemovedProcesses.size() > 0) {
9493 if (needSep) pw.println(" ");
9494 needSep = true;
9495 pw.println(" Processes that are being removed:");
9496 dumpProcessList(pw, this, mRemovedProcesses, " ",
9497 "Removed Norm", "Removed PERS", false);
9498 }
9499
9500 if (mProcessesOnHold.size() > 0) {
9501 if (needSep) pw.println(" ");
9502 needSep = true;
9503 pw.println(" Processes that are on old until the system is ready:");
9504 dumpProcessList(pw, this, mProcessesOnHold, " ",
9505 "OnHold Norm", "OnHold PERS", false);
9506 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009507
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009508 if (mProcessesToGc.size() > 0) {
9509 if (needSep) pw.println(" ");
9510 needSep = true;
9511 pw.println(" Processes that are waiting to GC:");
9512 long now = SystemClock.uptimeMillis();
9513 for (int i=0; i<mProcessesToGc.size(); i++) {
9514 ProcessRecord proc = mProcessesToGc.get(i);
9515 pw.print(" Process "); pw.println(proc);
9516 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9517 pw.print(", last gced=");
9518 pw.print(now-proc.lastRequestedGc);
9519 pw.print(" ms ago, last lowMem=");
9520 pw.print(now-proc.lastLowMemory);
9521 pw.println(" ms ago");
9522
9523 }
9524 }
9525
9526 if (mProcessCrashTimes.getMap().size() > 0) {
9527 if (needSep) pw.println(" ");
9528 needSep = true;
9529 pw.println(" Time since processes crashed:");
9530 long now = SystemClock.uptimeMillis();
9531 for (Map.Entry<String, SparseArray<Long>> procs
9532 : mProcessCrashTimes.getMap().entrySet()) {
9533 SparseArray<Long> uids = procs.getValue();
9534 final int N = uids.size();
9535 for (int i=0; i<N; i++) {
9536 pw.print(" Process "); pw.print(procs.getKey());
9537 pw.print(" uid "); pw.print(uids.keyAt(i));
9538 pw.print(": last crashed ");
9539 pw.print((now-uids.valueAt(i)));
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009540 pw.println(" ms ago");
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009541 }
9542 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009543 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009544
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009545 if (mBadProcesses.getMap().size() > 0) {
9546 if (needSep) pw.println(" ");
9547 needSep = true;
9548 pw.println(" Bad processes:");
9549 for (Map.Entry<String, SparseArray<Long>> procs
9550 : mBadProcesses.getMap().entrySet()) {
9551 SparseArray<Long> uids = procs.getValue();
9552 final int N = uids.size();
9553 for (int i=0; i<N; i++) {
9554 pw.print(" Bad process "); pw.print(procs.getKey());
9555 pw.print(" uid "); pw.print(uids.keyAt(i));
9556 pw.print(": crashed at time ");
9557 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009558 }
9559 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009560 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009561
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009562 pw.println(" ");
9563 pw.println(" mHomeProcess: " + mHomeProcess);
9564 pw.println(" mConfiguration: " + mConfiguration);
9565 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
9566 if (mDebugApp != null || mOrigDebugApp != null || mDebugTransient
9567 || mOrigWaitForDebugger) {
9568 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9569 + " mDebugTransient=" + mDebugTransient
9570 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9571 }
9572 if (mAlwaysFinishActivities || mController != null) {
9573 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
9574 + " mController=" + mController);
9575 }
9576 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009577 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009578 pw.println(" mStartRunning=" + mStartRunning
9579 + " mSystemReady=" + mSystemReady
9580 + " mBooting=" + mBooting
9581 + " mBooted=" + mBooted
9582 + " mFactoryTest=" + mFactoryTest);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009583 pw.println(" mGoingToSleep=" + mGoingToSleep);
9584 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009585 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009586
9587 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009588 }
9589
9590 /**
9591 * There are three ways to call this:
9592 * - no service specified: dump all the services
9593 * - a flattened component name that matched an existing service was specified as the
9594 * first arg: dump that one service
9595 * - the first arg isn't the flattened component name of an existing service:
9596 * dump all services whose component contains the first arg as a substring
9597 */
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009598 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args,
9599 int opti, boolean dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009600 String[] newArgs;
9601 String componentNameString;
9602 ServiceRecord r;
Kenny Root3619b9ab2010-02-13 10:05:42 -08009603 if (opti >= args.length) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009604 componentNameString = null;
9605 newArgs = EMPTY_STRING_ARRAY;
9606 r = null;
9607 } else {
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009608 componentNameString = args[opti];
9609 opti++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009610 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9611 r = componentName != null ? mServices.get(componentName) : null;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009612 newArgs = new String[args.length - opti];
9613 if (args.length > 2) System.arraycopy(args, opti, newArgs, 0, args.length - opti);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009614 }
9615
9616 if (r != null) {
9617 dumpService(fd, pw, r, newArgs);
9618 } else {
9619 for (ServiceRecord r1 : mServices.values()) {
9620 if (componentNameString == null
9621 || r1.name.flattenToString().contains(componentNameString)) {
9622 dumpService(fd, pw, r1, newArgs);
9623 }
9624 }
9625 }
9626 }
9627
9628 /**
9629 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9630 * there is a thread associated with the service.
9631 */
9632 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9633 pw.println(" Service " + r.name.flattenToString());
9634 if (r.app != null && r.app.thread != null) {
9635 try {
9636 // flush anything that is already in the PrintWriter since the thread is going
9637 // to write to the file descriptor directly
9638 pw.flush();
9639 r.app.thread.dumpService(fd, r, args);
9640 pw.print("\n");
9641 } catch (RemoteException e) {
9642 pw.println("got a RemoteException while dumping the service");
9643 }
9644 }
9645 }
9646
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009647 boolean dumpBroadcastsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9648 int opti, boolean dumpAll) {
9649 boolean needSep = false;
9650
9651 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009652 if (mRegisteredReceivers.size() > 0) {
9653 pw.println(" ");
9654 pw.println(" Registered Receivers:");
9655 Iterator it = mRegisteredReceivers.values().iterator();
9656 while (it.hasNext()) {
9657 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009658 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009659 r.dump(pw, " ");
9660 }
9661 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009662
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009663 pw.println(" ");
9664 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009665 mReceiverResolver.dump(pw, " ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009666 needSep = true;
9667 }
9668
9669 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9670 || mPendingBroadcast != null) {
9671 if (mParallelBroadcasts.size() > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009672 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009673 pw.println(" Active broadcasts:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009674 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009675 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9676 pw.println(" Broadcast #" + i + ":");
9677 mParallelBroadcasts.get(i).dump(pw, " ");
9678 }
9679 if (mOrderedBroadcasts.size() > 0) {
9680 pw.println(" ");
9681 pw.println(" Active serialized broadcasts:");
9682 }
9683 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9684 pw.println(" Serialized Broadcast #" + i + ":");
9685 mOrderedBroadcasts.get(i).dump(pw, " ");
9686 }
9687 pw.println(" ");
9688 pw.println(" Pending broadcast:");
9689 if (mPendingBroadcast != null) {
9690 mPendingBroadcast.dump(pw, " ");
9691 } else {
9692 pw.println(" (null)");
9693 }
9694 needSep = true;
9695 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009696
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009697 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009698 pw.println(" ");
Dianne Hackborn12527f92009-11-11 17:39:50 -08009699 pw.println(" Historical broadcasts:");
9700 for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
9701 BroadcastRecord r = mBroadcastHistory[i];
9702 if (r == null) {
9703 break;
9704 }
9705 pw.println(" Historical Broadcast #" + i + ":");
9706 r.dump(pw, " ");
9707 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009708 needSep = true;
9709 }
9710
9711 if (mStickyBroadcasts != null) {
Dianne Hackborn12527f92009-11-11 17:39:50 -08009712 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009713 pw.println(" Sticky broadcasts:");
9714 StringBuilder sb = new StringBuilder(128);
9715 for (Map.Entry<String, ArrayList<Intent>> ent
9716 : mStickyBroadcasts.entrySet()) {
9717 pw.print(" * Sticky action "); pw.print(ent.getKey());
9718 pw.println(":");
9719 ArrayList<Intent> intents = ent.getValue();
9720 final int N = intents.size();
9721 for (int i=0; i<N; i++) {
9722 sb.setLength(0);
9723 sb.append(" Intent: ");
9724 intents.get(i).toShortString(sb, true, false);
9725 pw.println(sb.toString());
9726 Bundle bundle = intents.get(i).getExtras();
9727 if (bundle != null) {
9728 pw.print(" ");
9729 pw.println(bundle.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009730 }
9731 }
9732 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009733 needSep = true;
9734 }
9735
9736 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009737 pw.println(" ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009738 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009739 pw.println(" mHandler:");
9740 mHandler.dump(new PrintWriterPrinter(pw), " ");
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009741 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009742 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009743
9744 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009745 }
9746
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009747 boolean dumpServicesLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9748 int opti, boolean dumpAll) {
9749 boolean needSep = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009750
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009751 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009752 if (mServices.size() > 0) {
9753 pw.println(" Active services:");
9754 Iterator<ServiceRecord> it = mServices.values().iterator();
9755 while (it.hasNext()) {
9756 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009757 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009758 r.dump(pw, " ");
9759 }
9760 needSep = true;
9761 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009762 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009763
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009764 if (mPendingServices.size() > 0) {
9765 if (needSep) pw.println(" ");
9766 pw.println(" Pending services:");
9767 for (int i=0; i<mPendingServices.size(); i++) {
9768 ServiceRecord r = mPendingServices.get(i);
9769 pw.print(" * Pending "); pw.println(r);
9770 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009771 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009772 needSep = true;
9773 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009774
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009775 if (mRestartingServices.size() > 0) {
9776 if (needSep) pw.println(" ");
9777 pw.println(" Restarting services:");
9778 for (int i=0; i<mRestartingServices.size(); i++) {
9779 ServiceRecord r = mRestartingServices.get(i);
9780 pw.print(" * Restarting "); pw.println(r);
9781 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009782 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009783 needSep = true;
9784 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009785
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009786 if (mStoppingServices.size() > 0) {
9787 if (needSep) pw.println(" ");
9788 pw.println(" Stopping services:");
9789 for (int i=0; i<mStoppingServices.size(); i++) {
9790 ServiceRecord r = mStoppingServices.get(i);
9791 pw.print(" * Stopping "); pw.println(r);
9792 r.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009793 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009794 needSep = true;
9795 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009796
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009797 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009798 if (mServiceConnections.size() > 0) {
9799 if (needSep) pw.println(" ");
9800 pw.println(" Connection bindings to services:");
9801 Iterator<ConnectionRecord> it
9802 = mServiceConnections.values().iterator();
9803 while (it.hasNext()) {
9804 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009805 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009806 r.dump(pw, " ");
9807 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009808 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009809 }
9810 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009811
9812 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009813 }
9814
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009815 boolean dumpProvidersLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9816 int opti, boolean dumpAll) {
9817 boolean needSep = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009818
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009819 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009820 if (mProvidersByClass.size() > 0) {
9821 if (needSep) pw.println(" ");
9822 pw.println(" Published content providers (by class):");
9823 Iterator it = mProvidersByClass.entrySet().iterator();
9824 while (it.hasNext()) {
9825 Map.Entry e = (Map.Entry)it.next();
9826 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009827 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009828 r.dump(pw, " ");
9829 }
9830 needSep = true;
9831 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009832
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009833 if (mProvidersByName.size() > 0) {
9834 pw.println(" ");
9835 pw.println(" Authority to provider mappings:");
9836 Iterator it = mProvidersByName.entrySet().iterator();
9837 while (it.hasNext()) {
9838 Map.Entry e = (Map.Entry)it.next();
9839 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9840 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9841 pw.println(r);
9842 }
9843 needSep = true;
9844 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009845 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009846
9847 if (mLaunchingProviders.size() > 0) {
9848 if (needSep) pw.println(" ");
9849 pw.println(" Launching content providers:");
9850 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
9851 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9852 pw.println(mLaunchingProviders.get(i));
9853 }
9854 needSep = true;
9855 }
9856
9857 if (mGrantedUriPermissions.size() > 0) {
9858 pw.println();
9859 pw.println("Granted Uri Permissions:");
9860 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9861 int uid = mGrantedUriPermissions.keyAt(i);
9862 HashMap<Uri, UriPermission> perms
9863 = mGrantedUriPermissions.valueAt(i);
9864 pw.print(" * UID "); pw.print(uid);
9865 pw.println(" holds:");
9866 for (UriPermission perm : perms.values()) {
9867 pw.print(" "); pw.println(perm);
9868 perm.dump(pw, " ");
9869 }
9870 }
9871 needSep = true;
9872 }
9873
9874 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009875 }
9876
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009877 boolean dumpPendingIntentsLocked(FileDescriptor fd, PrintWriter pw, String[] args,
9878 int opti, boolean dumpAll) {
9879 boolean needSep = false;
9880
9881 if (dumpAll) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009882 if (this.mIntentSenderRecords.size() > 0) {
9883 Iterator<WeakReference<PendingIntentRecord>> it
9884 = mIntentSenderRecords.values().iterator();
9885 while (it.hasNext()) {
9886 WeakReference<PendingIntentRecord> ref = it.next();
9887 PendingIntentRecord rec = ref != null ? ref.get(): null;
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009888 needSep = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009889 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009890 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009891 rec.dump(pw, " ");
9892 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009893 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009894 }
9895 }
9896 }
9897 }
Dianne Hackbornc59411b2009-12-21 20:10:14 -08009898
9899 return needSep;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009900 }
9901
9902 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009903 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009904 TaskRecord lastTask = null;
9905 for (int i=list.size()-1; i>=0; i--) {
9906 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009907 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009908 if (lastTask != r.task) {
9909 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009910 pw.print(prefix);
9911 pw.print(full ? "* " : " ");
9912 pw.println(lastTask);
9913 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009914 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009915 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009916 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009917 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9918 pw.print(" #"); pw.print(i); pw.print(": ");
9919 pw.println(r);
9920 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009921 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009922 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009923 }
9924 }
9925
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009926 private static String buildOomTag(String prefix, String space, int val, int base) {
9927 if (val == base) {
9928 if (space == null) return prefix;
9929 return prefix + " ";
9930 }
9931 return prefix + "+" + Integer.toString(val-base);
9932 }
9933
9934 private static final int dumpProcessList(PrintWriter pw,
9935 ActivityManagerService service, List list,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009936 String prefix, String normalLabel, String persistentLabel,
9937 boolean inclOomAdj) {
9938 int numPers = 0;
9939 for (int i=list.size()-1; i>=0; i--) {
9940 ProcessRecord r = (ProcessRecord)list.get(i);
9941 if (false) {
9942 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9943 + " #" + i + ":");
9944 r.dump(pw, prefix + " ");
9945 } else if (inclOomAdj) {
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009946 String oomAdj;
9947 if (r.setAdj >= EMPTY_APP_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009948 oomAdj = buildOomTag("empty", null, r.setAdj, EMPTY_APP_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009949 } else if (r.setAdj >= HIDDEN_APP_MIN_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009950 oomAdj = buildOomTag("bak", " ", r.setAdj, HIDDEN_APP_MIN_ADJ);
9951 } else if (r.setAdj >= HOME_APP_ADJ) {
9952 oomAdj = buildOomTag("home ", null, r.setAdj, HOME_APP_ADJ);
9953 } else if (r.setAdj >= SECONDARY_SERVER_ADJ) {
9954 oomAdj = buildOomTag("svc", " ", r.setAdj, SECONDARY_SERVER_ADJ);
9955 } else if (r.setAdj >= BACKUP_APP_ADJ) {
9956 oomAdj = buildOomTag("bckup", null, r.setAdj, BACKUP_APP_ADJ);
9957 } else if (r.setAdj >= VISIBLE_APP_ADJ) {
9958 oomAdj = buildOomTag("vis ", null, r.setAdj, VISIBLE_APP_ADJ);
9959 } else if (r.setAdj >= FOREGROUND_APP_ADJ) {
9960 oomAdj = buildOomTag("fore ", null, r.setAdj, FOREGROUND_APP_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009961 } else if (r.setAdj >= CORE_SERVER_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009962 oomAdj = buildOomTag("core ", null, r.setAdj, CORE_SERVER_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009963 } else if (r.setAdj >= SYSTEM_ADJ) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009964 oomAdj = buildOomTag("sys ", null, r.setAdj, SYSTEM_ADJ);
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009965 } else {
9966 oomAdj = Integer.toString(r.setAdj);
9967 }
9968 String schedGroup;
9969 switch (r.setSchedGroup) {
9970 case Process.THREAD_GROUP_BG_NONINTERACTIVE:
9971 schedGroup = "B";
9972 break;
9973 case Process.THREAD_GROUP_DEFAULT:
9974 schedGroup = "F";
9975 break;
9976 default:
9977 schedGroup = Integer.toString(r.setSchedGroup);
9978 break;
9979 }
9980 pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009981 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009982 i, oomAdj, schedGroup, r.toShortString(), r.adjType));
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009983 if (r.adjSource != null || r.adjTarget != null) {
9984 pw.println(prefix + " " + r.adjTarget
Dianne Hackborndd71fc82009-12-16 19:24:32 -08009985 + "<=" + r.adjSource);
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009986 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009987 } else {
9988 pw.println(String.format("%s%s #%2d: %s",
9989 prefix, (r.persistent ? persistentLabel : normalLabel),
9990 i, r.toString()));
9991 }
9992 if (r.persistent) {
9993 numPers++;
9994 }
9995 }
9996 return numPers;
9997 }
9998
9999 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
10000 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -070010001 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010002 long uptime = SystemClock.uptimeMillis();
10003 long realtime = SystemClock.elapsedRealtime();
10004
10005 if (isCheckinRequest) {
10006 // short checkin version
10007 pw.println(uptime + "," + realtime);
10008 pw.flush();
10009 } else {
10010 pw.println("Applications Memory Usage (kB):");
10011 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
10012 }
10013 for (int i = list.size() - 1 ; i >= 0 ; i--) {
10014 ProcessRecord r = (ProcessRecord)list.get(i);
10015 if (r.thread != null) {
10016 if (!isCheckinRequest) {
10017 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
10018 pw.flush();
10019 }
10020 try {
10021 r.thread.asBinder().dump(fd, args);
10022 } catch (RemoteException e) {
10023 if (!isCheckinRequest) {
10024 pw.println("Got RemoteException!");
10025 pw.flush();
10026 }
10027 }
10028 }
10029 }
10030 }
10031
10032 /**
10033 * Searches array of arguments for the specified string
10034 * @param args array of argument strings
10035 * @param value value to search for
10036 * @return true if the value is contained in the array
10037 */
10038 private static boolean scanArgs(String[] args, String value) {
10039 if (args != null) {
10040 for (String arg : args) {
10041 if (value.equals(arg)) {
10042 return true;
10043 }
10044 }
10045 }
10046 return false;
10047 }
10048
Dianne Hackborn75b03852009-06-12 15:43:26 -070010049 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010050 int count = mHistory.size();
10051
10052 // convert the token to an entry in the history.
10053 HistoryRecord r = null;
10054 int index = -1;
10055 for (int i=count-1; i>=0; i--) {
10056 Object o = mHistory.get(i);
10057 if (o == token) {
10058 r = (HistoryRecord)o;
10059 index = i;
10060 break;
10061 }
10062 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010063
10064 return index;
10065 }
10066
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010067 private final void killServicesLocked(ProcessRecord app,
10068 boolean allowRestart) {
10069 // Report disconnected services.
10070 if (false) {
10071 // XXX we are letting the client link to the service for
10072 // death notifications.
10073 if (app.services.size() > 0) {
10074 Iterator it = app.services.iterator();
10075 while (it.hasNext()) {
10076 ServiceRecord r = (ServiceRecord)it.next();
10077 if (r.connections.size() > 0) {
10078 Iterator<ConnectionRecord> jt
10079 = r.connections.values().iterator();
10080 while (jt.hasNext()) {
10081 ConnectionRecord c = jt.next();
10082 if (c.binding.client != app) {
10083 try {
10084 //c.conn.connected(r.className, null);
10085 } catch (Exception e) {
10086 // todo: this should be asynchronous!
10087 Log.w(TAG, "Exception thrown disconnected servce "
10088 + r.shortName
10089 + " from app " + app.processName, e);
10090 }
10091 }
10092 }
10093 }
10094 }
10095 }
10096 }
10097
10098 // Clean up any connections this application has to other services.
10099 if (app.connections.size() > 0) {
10100 Iterator<ConnectionRecord> it = app.connections.iterator();
10101 while (it.hasNext()) {
10102 ConnectionRecord r = it.next();
10103 removeConnectionLocked(r, app, null);
10104 }
10105 }
10106 app.connections.clear();
10107
10108 if (app.services.size() != 0) {
10109 // Any services running in the application need to be placed
10110 // back in the pending list.
10111 Iterator it = app.services.iterator();
10112 while (it.hasNext()) {
10113 ServiceRecord sr = (ServiceRecord)it.next();
10114 synchronized (sr.stats.getBatteryStats()) {
10115 sr.stats.stopLaunchedLocked();
10116 }
10117 sr.app = null;
10118 sr.executeNesting = 0;
10119 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010120
10121 boolean hasClients = sr.bindings.size() > 0;
10122 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010123 Iterator<IntentBindRecord> bindings
10124 = sr.bindings.values().iterator();
10125 while (bindings.hasNext()) {
10126 IntentBindRecord b = bindings.next();
10127 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
10128 + ": shouldUnbind=" + b.hasBound);
10129 b.binder = null;
10130 b.requested = b.received = b.hasBound = false;
10131 }
10132 }
10133
10134 if (sr.crashCount >= 2) {
10135 Log.w(TAG, "Service crashed " + sr.crashCount
10136 + " times, stopping: " + sr);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010137 EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010138 sr.crashCount, sr.shortName, app.pid);
10139 bringDownServiceLocked(sr, true);
10140 } else if (!allowRestart) {
10141 bringDownServiceLocked(sr, true);
10142 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010143 boolean canceled = scheduleServiceRestartLocked(sr, true);
10144
10145 // Should the service remain running? Note that in the
10146 // extreme case of so many attempts to deliver a command
10147 // that it failed, that we also will stop it here.
10148 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
10149 if (sr.pendingStarts.size() == 0) {
10150 sr.startRequested = false;
10151 if (!hasClients) {
10152 // Whoops, no reason to restart!
10153 bringDownServiceLocked(sr, true);
10154 }
10155 }
10156 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010157 }
10158 }
10159
10160 if (!allowRestart) {
10161 app.services.clear();
10162 }
10163 }
10164
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010165 // Make sure we have no more records on the stopping list.
10166 int i = mStoppingServices.size();
10167 while (i > 0) {
10168 i--;
10169 ServiceRecord sr = mStoppingServices.get(i);
10170 if (sr.app == app) {
10171 mStoppingServices.remove(i);
10172 }
10173 }
10174
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010175 app.executingServices.clear();
10176 }
10177
10178 private final void removeDyingProviderLocked(ProcessRecord proc,
10179 ContentProviderRecord cpr) {
10180 synchronized (cpr) {
10181 cpr.launchingApp = null;
10182 cpr.notifyAll();
10183 }
10184
10185 mProvidersByClass.remove(cpr.info.name);
10186 String names[] = cpr.info.authority.split(";");
10187 for (int j = 0; j < names.length; j++) {
10188 mProvidersByName.remove(names[j]);
10189 }
10190
10191 Iterator<ProcessRecord> cit = cpr.clients.iterator();
10192 while (cit.hasNext()) {
10193 ProcessRecord capp = cit.next();
10194 if (!capp.persistent && capp.thread != null
10195 && capp.pid != 0
10196 && capp.pid != MY_PID) {
10197 Log.i(TAG, "Killing app " + capp.processName
10198 + " (pid " + capp.pid
10199 + ") because provider " + cpr.info.name
10200 + " is in dying process " + proc.processName);
10201 Process.killProcess(capp.pid);
10202 }
10203 }
10204
10205 mLaunchingProviders.remove(cpr);
10206 }
10207
10208 /**
10209 * Main code for cleaning up a process when it has gone away. This is
10210 * called both as a result of the process dying, or directly when stopping
10211 * a process when running in single process mode.
10212 */
10213 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
10214 boolean restarting, int index) {
10215 if (index >= 0) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080010216 mLruProcesses.remove(index);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010217 }
10218
Dianne Hackborn36124872009-10-08 16:22:03 -070010219 mProcessesToGc.remove(app);
10220
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010221 // Dismiss any open dialogs.
10222 if (app.crashDialog != null) {
10223 app.crashDialog.dismiss();
10224 app.crashDialog = null;
10225 }
10226 if (app.anrDialog != null) {
10227 app.anrDialog.dismiss();
10228 app.anrDialog = null;
10229 }
10230 if (app.waitDialog != null) {
10231 app.waitDialog.dismiss();
10232 app.waitDialog = null;
10233 }
10234
10235 app.crashing = false;
10236 app.notResponding = false;
10237
10238 app.resetPackageList();
10239 app.thread = null;
10240 app.forcingToForeground = null;
10241 app.foregroundServices = false;
10242
10243 killServicesLocked(app, true);
10244
10245 boolean restart = false;
10246
10247 int NL = mLaunchingProviders.size();
10248
10249 // Remove published content providers.
10250 if (!app.pubProviders.isEmpty()) {
10251 Iterator it = app.pubProviders.values().iterator();
10252 while (it.hasNext()) {
10253 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
10254 cpr.provider = null;
10255 cpr.app = null;
10256
10257 // See if someone is waiting for this provider... in which
10258 // case we don't remove it, but just let it restart.
10259 int i = 0;
10260 if (!app.bad) {
10261 for (; i<NL; i++) {
10262 if (mLaunchingProviders.get(i) == cpr) {
10263 restart = true;
10264 break;
10265 }
10266 }
10267 } else {
10268 i = NL;
10269 }
10270
10271 if (i >= NL) {
10272 removeDyingProviderLocked(app, cpr);
10273 NL = mLaunchingProviders.size();
10274 }
10275 }
10276 app.pubProviders.clear();
10277 }
10278
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010279 // Take care of any launching providers waiting for this process.
10280 if (checkAppInLaunchingProvidersLocked(app, false)) {
10281 restart = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010282 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010283
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010284 // Unregister from connected content providers.
10285 if (!app.conProviders.isEmpty()) {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -070010286 Iterator it = app.conProviders.keySet().iterator();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010287 while (it.hasNext()) {
10288 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
10289 cpr.clients.remove(app);
10290 }
10291 app.conProviders.clear();
10292 }
10293
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010294 // At this point there may be remaining entries in mLaunchingProviders
10295 // where we were the only one waiting, so they are no longer of use.
10296 // Look for these and clean up if found.
10297 // XXX Commented out for now. Trying to figure out a way to reproduce
10298 // the actual situation to identify what is actually going on.
10299 if (false) {
10300 for (int i=0; i<NL; i++) {
10301 ContentProviderRecord cpr = (ContentProviderRecord)
10302 mLaunchingProviders.get(i);
10303 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
10304 synchronized (cpr) {
10305 cpr.launchingApp = null;
10306 cpr.notifyAll();
10307 }
10308 }
10309 }
10310 }
10311
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010312 skipCurrentReceiverLocked(app);
10313
10314 // Unregister any receivers.
10315 if (app.receivers.size() > 0) {
10316 Iterator<ReceiverList> it = app.receivers.iterator();
10317 while (it.hasNext()) {
10318 removeReceiverLocked(it.next());
10319 }
10320 app.receivers.clear();
10321 }
10322
Christopher Tate181fafa2009-05-14 11:12:14 -070010323 // If the app is undergoing backup, tell the backup manager about it
10324 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
10325 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
10326 try {
10327 IBackupManager bm = IBackupManager.Stub.asInterface(
10328 ServiceManager.getService(Context.BACKUP_SERVICE));
10329 bm.agentDisconnected(app.info.packageName);
10330 } catch (RemoteException e) {
10331 // can't happen; backup manager is local
10332 }
10333 }
10334
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010335 // If the caller is restarting this app, then leave it in its
10336 // current lists and let the caller take care of it.
10337 if (restarting) {
10338 return;
10339 }
10340
10341 if (!app.persistent) {
10342 if (DEBUG_PROCESSES) Log.v(TAG,
10343 "Removing non-persistent process during cleanup: " + app);
10344 mProcessNames.remove(app.processName, app.info.uid);
10345 } else if (!app.removed) {
10346 // This app is persistent, so we need to keep its record around.
10347 // If it is not already on the pending app list, add it there
10348 // and start a new process for it.
10349 app.thread = null;
10350 app.forcingToForeground = null;
10351 app.foregroundServices = false;
10352 if (mPersistentStartingProcesses.indexOf(app) < 0) {
10353 mPersistentStartingProcesses.add(app);
10354 restart = true;
10355 }
10356 }
10357 mProcessesOnHold.remove(app);
10358
The Android Open Source Project4df24232009-03-05 14:34:35 -080010359 if (app == mHomeProcess) {
10360 mHomeProcess = null;
10361 }
10362
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010363 if (restart) {
10364 // We have components that still need to be running in the
10365 // process, so re-launch it.
10366 mProcessNames.put(app.processName, app.info.uid, app);
10367 startProcessLocked(app, "restart", app.processName);
10368 } else if (app.pid > 0 && app.pid != MY_PID) {
10369 // Goodbye!
10370 synchronized (mPidsSelfLocked) {
10371 mPidsSelfLocked.remove(app.pid);
10372 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
10373 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -070010374 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010375 }
10376 }
10377
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010378 boolean checkAppInLaunchingProvidersLocked(ProcessRecord app, boolean alwaysBad) {
10379 // Look through the content providers we are waiting to have launched,
10380 // and if any run in this process then either schedule a restart of
10381 // the process or kill the client waiting for it if this process has
10382 // gone bad.
10383 int NL = mLaunchingProviders.size();
10384 boolean restart = false;
10385 for (int i=0; i<NL; i++) {
10386 ContentProviderRecord cpr = (ContentProviderRecord)
10387 mLaunchingProviders.get(i);
10388 if (cpr.launchingApp == app) {
10389 if (!alwaysBad && !app.bad) {
10390 restart = true;
10391 } else {
10392 removeDyingProviderLocked(app, cpr);
10393 NL = mLaunchingProviders.size();
10394 }
10395 }
10396 }
10397 return restart;
10398 }
10399
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010400 // =========================================================
10401 // SERVICES
10402 // =========================================================
10403
10404 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
10405 ActivityManager.RunningServiceInfo info =
10406 new ActivityManager.RunningServiceInfo();
10407 info.service = r.name;
10408 if (r.app != null) {
10409 info.pid = r.app.pid;
10410 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010411 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010412 info.process = r.processName;
10413 info.foreground = r.isForeground;
10414 info.activeSince = r.createTime;
10415 info.started = r.startRequested;
10416 info.clientCount = r.connections.size();
10417 info.crashCount = r.crashCount;
10418 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010419 if (r.isForeground) {
10420 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
10421 }
10422 if (r.startRequested) {
10423 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
10424 }
Dan Egnor42471dd2010-01-07 17:25:22 -080010425 if (r.app != null && r.app.pid == MY_PID) {
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010426 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
10427 }
10428 if (r.app != null && r.app.persistent) {
10429 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
10430 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010431 for (ConnectionRecord conn : r.connections.values()) {
10432 if (conn.clientLabel != 0) {
10433 info.clientPackage = conn.binding.client.info.packageName;
10434 info.clientLabel = conn.clientLabel;
10435 break;
10436 }
10437 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010438 return info;
10439 }
10440
10441 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
10442 int flags) {
10443 synchronized (this) {
10444 ArrayList<ActivityManager.RunningServiceInfo> res
10445 = new ArrayList<ActivityManager.RunningServiceInfo>();
10446
10447 if (mServices.size() > 0) {
10448 Iterator<ServiceRecord> it = mServices.values().iterator();
10449 while (it.hasNext() && res.size() < maxNum) {
10450 res.add(makeRunningServiceInfoLocked(it.next()));
10451 }
10452 }
10453
10454 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
10455 ServiceRecord r = mRestartingServices.get(i);
10456 ActivityManager.RunningServiceInfo info =
10457 makeRunningServiceInfoLocked(r);
10458 info.restarting = r.nextRestartTime;
10459 res.add(info);
10460 }
10461
10462 return res;
10463 }
10464 }
10465
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010466 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
10467 synchronized (this) {
10468 ServiceRecord r = mServices.get(name);
10469 if (r != null) {
10470 for (ConnectionRecord conn : r.connections.values()) {
10471 if (conn.clientIntent != null) {
10472 return conn.clientIntent;
10473 }
10474 }
10475 }
10476 }
10477 return null;
10478 }
10479
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010480 private final ServiceRecord findServiceLocked(ComponentName name,
10481 IBinder token) {
10482 ServiceRecord r = mServices.get(name);
10483 return r == token ? r : null;
10484 }
10485
10486 private final class ServiceLookupResult {
10487 final ServiceRecord record;
10488 final String permission;
10489
10490 ServiceLookupResult(ServiceRecord _record, String _permission) {
10491 record = _record;
10492 permission = _permission;
10493 }
10494 };
10495
10496 private ServiceLookupResult findServiceLocked(Intent service,
10497 String resolvedType) {
10498 ServiceRecord r = null;
10499 if (service.getComponent() != null) {
10500 r = mServices.get(service.getComponent());
10501 }
10502 if (r == null) {
10503 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10504 r = mServicesByIntent.get(filter);
10505 }
10506
10507 if (r == null) {
10508 try {
10509 ResolveInfo rInfo =
10510 ActivityThread.getPackageManager().resolveService(
10511 service, resolvedType, 0);
10512 ServiceInfo sInfo =
10513 rInfo != null ? rInfo.serviceInfo : null;
10514 if (sInfo == null) {
10515 return null;
10516 }
10517
10518 ComponentName name = new ComponentName(
10519 sInfo.applicationInfo.packageName, sInfo.name);
10520 r = mServices.get(name);
10521 } catch (RemoteException ex) {
10522 // pm is in same process, this will never happen.
10523 }
10524 }
10525 if (r != null) {
10526 int callingPid = Binder.getCallingPid();
10527 int callingUid = Binder.getCallingUid();
10528 if (checkComponentPermission(r.permission,
10529 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10530 != PackageManager.PERMISSION_GRANTED) {
10531 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10532 + " from pid=" + callingPid
10533 + ", uid=" + callingUid
10534 + " requires " + r.permission);
10535 return new ServiceLookupResult(null, r.permission);
10536 }
10537 return new ServiceLookupResult(r, null);
10538 }
10539 return null;
10540 }
10541
10542 private class ServiceRestarter implements Runnable {
10543 private ServiceRecord mService;
10544
10545 void setService(ServiceRecord service) {
10546 mService = service;
10547 }
10548
10549 public void run() {
10550 synchronized(ActivityManagerService.this) {
10551 performServiceRestartLocked(mService);
10552 }
10553 }
10554 }
10555
10556 private ServiceLookupResult retrieveServiceLocked(Intent service,
10557 String resolvedType, int callingPid, int callingUid) {
10558 ServiceRecord r = null;
10559 if (service.getComponent() != null) {
10560 r = mServices.get(service.getComponent());
10561 }
10562 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10563 r = mServicesByIntent.get(filter);
10564 if (r == null) {
10565 try {
10566 ResolveInfo rInfo =
10567 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010568 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010569 ServiceInfo sInfo =
10570 rInfo != null ? rInfo.serviceInfo : null;
10571 if (sInfo == null) {
10572 Log.w(TAG, "Unable to start service " + service +
10573 ": not found");
10574 return null;
10575 }
10576
10577 ComponentName name = new ComponentName(
10578 sInfo.applicationInfo.packageName, sInfo.name);
10579 r = mServices.get(name);
10580 if (r == null) {
10581 filter = new Intent.FilterComparison(service.cloneFilter());
10582 ServiceRestarter res = new ServiceRestarter();
10583 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10584 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10585 synchronized (stats) {
10586 ss = stats.getServiceStatsLocked(
10587 sInfo.applicationInfo.uid, sInfo.packageName,
10588 sInfo.name);
10589 }
Dianne Hackbornb1c4a2a2010-01-19 15:36:42 -080010590 r = new ServiceRecord(this, ss, name, filter, sInfo, res);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010591 res.setService(r);
10592 mServices.put(name, r);
10593 mServicesByIntent.put(filter, r);
10594
10595 // Make sure this component isn't in the pending list.
10596 int N = mPendingServices.size();
10597 for (int i=0; i<N; i++) {
10598 ServiceRecord pr = mPendingServices.get(i);
10599 if (pr.name.equals(name)) {
10600 mPendingServices.remove(i);
10601 i--;
10602 N--;
10603 }
10604 }
10605 }
10606 } catch (RemoteException ex) {
10607 // pm is in same process, this will never happen.
10608 }
10609 }
10610 if (r != null) {
10611 if (checkComponentPermission(r.permission,
10612 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10613 != PackageManager.PERMISSION_GRANTED) {
10614 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10615 + " from pid=" + Binder.getCallingPid()
10616 + ", uid=" + Binder.getCallingUid()
10617 + " requires " + r.permission);
10618 return new ServiceLookupResult(null, r.permission);
10619 }
10620 return new ServiceLookupResult(r, null);
10621 }
10622 return null;
10623 }
10624
10625 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10626 long now = SystemClock.uptimeMillis();
10627 if (r.executeNesting == 0 && r.app != null) {
10628 if (r.app.executingServices.size() == 0) {
10629 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10630 msg.obj = r.app;
10631 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10632 }
10633 r.app.executingServices.add(r);
10634 }
10635 r.executeNesting++;
10636 r.executingStart = now;
10637 }
10638
10639 private final void sendServiceArgsLocked(ServiceRecord r,
10640 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010641 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010642 if (N == 0) {
10643 return;
10644 }
10645
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010646 int i = 0;
10647 while (i < N) {
10648 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010649 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010650 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010651 + r.name + " " + r.intent + " args=" + si.intent);
Dianne Hackbornfed534e2009-09-23 00:42:12 -070010652 if (si.intent == null && N > 1) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010653 // If somehow we got a dummy start at the front, then
10654 // just drop it here.
10655 i++;
10656 continue;
10657 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010658 bumpServiceExecutingLocked(r);
10659 if (!oomAdjusted) {
10660 oomAdjusted = true;
10661 updateOomAdjLocked(r.app);
10662 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010663 int flags = 0;
10664 if (si.deliveryCount > 0) {
10665 flags |= Service.START_FLAG_RETRY;
10666 }
10667 if (si.doneExecutingCount > 0) {
10668 flags |= Service.START_FLAG_REDELIVERY;
10669 }
10670 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10671 si.deliveredTime = SystemClock.uptimeMillis();
10672 r.deliveredStarts.add(si);
10673 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010674 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010675 } catch (RemoteException e) {
10676 // Remote process gone... we'll let the normal cleanup take
10677 // care of this.
10678 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010679 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010680 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010681 break;
10682 }
10683 }
10684 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010685 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010686 } else {
10687 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010688 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010689 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010690 }
10691 }
10692 }
10693
10694 private final boolean requestServiceBindingLocked(ServiceRecord r,
10695 IntentBindRecord i, boolean rebind) {
10696 if (r.app == null || r.app.thread == null) {
10697 // If service is not currently running, can't yet bind.
10698 return false;
10699 }
10700 if ((!i.requested || rebind) && i.apps.size() > 0) {
10701 try {
10702 bumpServiceExecutingLocked(r);
10703 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10704 + ": shouldUnbind=" + i.hasBound);
10705 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10706 if (!rebind) {
10707 i.requested = true;
10708 }
10709 i.hasBound = true;
10710 i.doRebind = false;
10711 } catch (RemoteException e) {
10712 return false;
10713 }
10714 }
10715 return true;
10716 }
10717
10718 private final void requestServiceBindingsLocked(ServiceRecord r) {
10719 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10720 while (bindings.hasNext()) {
10721 IntentBindRecord i = bindings.next();
10722 if (!requestServiceBindingLocked(r, i, false)) {
10723 break;
10724 }
10725 }
10726 }
10727
10728 private final void realStartServiceLocked(ServiceRecord r,
10729 ProcessRecord app) throws RemoteException {
10730 if (app.thread == null) {
10731 throw new RemoteException();
10732 }
10733
10734 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010735 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010736
10737 app.services.add(r);
10738 bumpServiceExecutingLocked(r);
Dianne Hackborndd71fc82009-12-16 19:24:32 -080010739 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010740
10741 boolean created = false;
10742 try {
10743 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10744 + r.name + " " + r.intent);
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010745 mStringBuilder.setLength(0);
10746 r.intent.getIntent().toShortString(mStringBuilder, false, true);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010747 EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010748 System.identityHashCode(r), r.shortName,
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010749 mStringBuilder.toString(), r.app.pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010750 synchronized (r.stats.getBatteryStats()) {
10751 r.stats.startLaunchedLocked();
10752 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010753 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010754 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010755 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010756 created = true;
10757 } finally {
10758 if (!created) {
10759 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010760 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010761 }
10762 }
10763
10764 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010765
10766 // If the service is in the started state, and there are no
10767 // pending arguments, then fake up one so its onStartCommand() will
10768 // be called.
10769 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10770 r.lastStartId++;
10771 if (r.lastStartId < 1) {
10772 r.lastStartId = 1;
10773 }
10774 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10775 }
10776
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010777 sendServiceArgsLocked(r, true);
10778 }
10779
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010780 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10781 boolean allowCancel) {
10782 boolean canceled = false;
10783
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010784 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010785 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010786 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010787
10788 // Any delivered but not yet finished starts should be put back
10789 // on the pending list.
10790 final int N = r.deliveredStarts.size();
10791 if (N > 0) {
10792 for (int i=N-1; i>=0; i--) {
10793 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10794 if (si.intent == null) {
10795 // We'll generate this again if needed.
10796 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10797 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10798 r.pendingStarts.add(0, si);
10799 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10800 dur *= 2;
10801 if (minDuration < dur) minDuration = dur;
10802 if (resetTime < dur) resetTime = dur;
10803 } else {
10804 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10805 + r.name);
10806 canceled = true;
10807 }
10808 }
10809 r.deliveredStarts.clear();
10810 }
10811
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010812 r.totalRestartCount++;
10813 if (r.restartDelay == 0) {
10814 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010815 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010816 } else {
10817 // If it has been a "reasonably long time" since the service
10818 // was started, then reset our restart duration back to
10819 // the beginning, so we don't infinitely increase the duration
10820 // on a service that just occasionally gets killed (which is
10821 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010822 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010823 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010824 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010825 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010826 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010827 if (r.restartDelay < minDuration) {
10828 r.restartDelay = minDuration;
10829 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010830 }
10831 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010832
10833 r.nextRestartTime = now + r.restartDelay;
10834
10835 // Make sure that we don't end up restarting a bunch of services
10836 // all at the same time.
10837 boolean repeat;
10838 do {
10839 repeat = false;
10840 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10841 ServiceRecord r2 = mRestartingServices.get(i);
10842 if (r2 != r && r.nextRestartTime
10843 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10844 && r.nextRestartTime
10845 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10846 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10847 r.restartDelay = r.nextRestartTime - now;
10848 repeat = true;
10849 break;
10850 }
10851 }
10852 } while (repeat);
10853
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010854 if (!mRestartingServices.contains(r)) {
10855 mRestartingServices.add(r);
10856 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010857
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010858 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010859
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010860 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010861 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010862 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10863 Log.w(TAG, "Scheduling restart of crashed service "
10864 + r.shortName + " in " + r.restartDelay + "ms");
Doug Zongker2bec3d42009-12-04 12:52:44 -080010865 EventLog.writeEvent(EventLogTags.AM_SCHEDULE_SERVICE_RESTART,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010866 r.shortName, r.restartDelay);
10867
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010868 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010869 }
10870
10871 final void performServiceRestartLocked(ServiceRecord r) {
10872 if (!mRestartingServices.contains(r)) {
10873 return;
10874 }
10875 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10876 }
10877
10878 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10879 if (r.restartDelay == 0) {
10880 return false;
10881 }
10882 r.resetRestartCounter();
10883 mRestartingServices.remove(r);
10884 mHandler.removeCallbacks(r.restarter);
10885 return true;
10886 }
10887
10888 private final boolean bringUpServiceLocked(ServiceRecord r,
10889 int intentFlags, boolean whileRestarting) {
10890 //Log.i(TAG, "Bring up service:");
10891 //r.dump(" ");
10892
Dianne Hackborn36124872009-10-08 16:22:03 -070010893 if (r.app != null && r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010894 sendServiceArgsLocked(r, false);
10895 return true;
10896 }
10897
10898 if (!whileRestarting && r.restartDelay > 0) {
10899 // If waiting for a restart, then do nothing.
10900 return true;
10901 }
10902
10903 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10904 + " " + r.intent);
10905
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010906 // We are now bringing the service up, so no longer in the
10907 // restarting state.
10908 mRestartingServices.remove(r);
10909
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010910 final String appName = r.processName;
10911 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10912 if (app != null && app.thread != null) {
10913 try {
10914 realStartServiceLocked(r, app);
10915 return true;
10916 } catch (RemoteException e) {
10917 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10918 }
10919
10920 // If a dead object exception was thrown -- fall through to
10921 // restart the application.
10922 }
10923
Dianne Hackborn36124872009-10-08 16:22:03 -070010924 // Not running -- get it started, and enqueue this service record
10925 // to be executed when the app comes up.
10926 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
10927 "service", r.name, false) == null) {
10928 Log.w(TAG, "Unable to launch app "
10929 + r.appInfo.packageName + "/"
10930 + r.appInfo.uid + " for service "
10931 + r.intent.getIntent() + ": process is bad");
10932 bringDownServiceLocked(r, true);
10933 return false;
10934 }
10935
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010936 if (!mPendingServices.contains(r)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010937 mPendingServices.add(r);
10938 }
Dianne Hackborn36124872009-10-08 16:22:03 -070010939
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010940 return true;
10941 }
10942
10943 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10944 //Log.i(TAG, "Bring down service:");
10945 //r.dump(" ");
10946
10947 // Does it still need to run?
10948 if (!force && r.startRequested) {
10949 return;
10950 }
10951 if (r.connections.size() > 0) {
10952 if (!force) {
10953 // XXX should probably keep a count of the number of auto-create
10954 // connections directly in the service.
10955 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10956 while (it.hasNext()) {
10957 ConnectionRecord cr = it.next();
10958 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10959 return;
10960 }
10961 }
10962 }
10963
10964 // Report to all of the connections that the service is no longer
10965 // available.
10966 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10967 while (it.hasNext()) {
10968 ConnectionRecord c = it.next();
10969 try {
10970 // todo: shouldn't be a synchronous call!
10971 c.conn.connected(r.name, null);
10972 } catch (Exception e) {
10973 Log.w(TAG, "Failure disconnecting service " + r.name +
10974 " to connection " + c.conn.asBinder() +
10975 " (in " + c.binding.client.processName + ")", e);
10976 }
10977 }
10978 }
10979
10980 // Tell the service that it has been unbound.
10981 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10982 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10983 while (it.hasNext()) {
10984 IntentBindRecord ibr = it.next();
10985 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10986 + ": hasBound=" + ibr.hasBound);
10987 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10988 try {
10989 bumpServiceExecutingLocked(r);
10990 updateOomAdjLocked(r.app);
10991 ibr.hasBound = false;
10992 r.app.thread.scheduleUnbindService(r,
10993 ibr.intent.getIntent());
10994 } catch (Exception e) {
10995 Log.w(TAG, "Exception when unbinding service "
10996 + r.shortName, e);
10997 serviceDoneExecutingLocked(r, true);
10998 }
10999 }
11000 }
11001 }
11002
11003 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
11004 + " " + r.intent);
Doug Zongker2bec3d42009-12-04 12:52:44 -080011005 EventLog.writeEvent(EventLogTags.AM_DESTROY_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011006 System.identityHashCode(r), r.shortName,
11007 (r.app != null) ? r.app.pid : -1);
11008
11009 mServices.remove(r.name);
11010 mServicesByIntent.remove(r.intent);
11011 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
11012 r.totalRestartCount = 0;
11013 unscheduleServiceRestartLocked(r);
11014
11015 // Also make sure it is not on the pending list.
11016 int N = mPendingServices.size();
11017 for (int i=0; i<N; i++) {
11018 if (mPendingServices.get(i) == r) {
11019 mPendingServices.remove(i);
11020 if (DEBUG_SERVICE) Log.v(
11021 TAG, "Removed pending service: " + r.shortName);
11022 i--;
11023 N--;
11024 }
11025 }
11026
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011027 r.cancelNotification();
11028 r.isForeground = false;
11029 r.foregroundId = 0;
11030 r.foregroundNoti = null;
11031
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011032 // Clear start entries.
11033 r.deliveredStarts.clear();
11034 r.pendingStarts.clear();
11035
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011036 if (r.app != null) {
11037 synchronized (r.stats.getBatteryStats()) {
11038 r.stats.stopLaunchedLocked();
11039 }
11040 r.app.services.remove(r);
11041 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011042 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070011043 if (DEBUG_SERVICE) Log.v(TAG,
11044 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011045 bumpServiceExecutingLocked(r);
11046 mStoppingServices.add(r);
11047 updateOomAdjLocked(r.app);
11048 r.app.thread.scheduleStopService(r);
11049 } catch (Exception e) {
11050 Log.w(TAG, "Exception when stopping service "
11051 + r.shortName, e);
11052 serviceDoneExecutingLocked(r, true);
11053 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011054 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011055 } else {
11056 if (DEBUG_SERVICE) Log.v(
11057 TAG, "Removed service that has no process: " + r.shortName);
11058 }
11059 } else {
11060 if (DEBUG_SERVICE) Log.v(
11061 TAG, "Removed service that is not running: " + r.shortName);
11062 }
11063 }
11064
11065 ComponentName startServiceLocked(IApplicationThread caller,
11066 Intent service, String resolvedType,
11067 int callingPid, int callingUid) {
11068 synchronized(this) {
11069 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
11070 + " type=" + resolvedType + " args=" + service.getExtras());
11071
11072 if (caller != null) {
11073 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11074 if (callerApp == null) {
11075 throw new SecurityException(
11076 "Unable to find app for caller " + caller
11077 + " (pid=" + Binder.getCallingPid()
11078 + ") when starting service " + service);
11079 }
11080 }
11081
11082 ServiceLookupResult res =
11083 retrieveServiceLocked(service, resolvedType,
11084 callingPid, callingUid);
11085 if (res == null) {
11086 return null;
11087 }
11088 if (res.record == null) {
11089 return new ComponentName("!", res.permission != null
11090 ? res.permission : "private to package");
11091 }
11092 ServiceRecord r = res.record;
11093 if (unscheduleServiceRestartLocked(r)) {
11094 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
11095 + r.shortName);
11096 }
11097 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011098 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011099 r.lastStartId++;
11100 if (r.lastStartId < 1) {
11101 r.lastStartId = 1;
11102 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011103 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011104 r.lastActivity = SystemClock.uptimeMillis();
11105 synchronized (r.stats.getBatteryStats()) {
11106 r.stats.startRunningLocked();
11107 }
11108 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
11109 return new ComponentName("!", "Service process is bad");
11110 }
11111 return r.name;
11112 }
11113 }
11114
11115 public ComponentName startService(IApplicationThread caller, Intent service,
11116 String resolvedType) {
11117 // Refuse possible leaked file descriptors
11118 if (service != null && service.hasFileDescriptors() == true) {
11119 throw new IllegalArgumentException("File descriptors passed in Intent");
11120 }
11121
11122 synchronized(this) {
11123 final int callingPid = Binder.getCallingPid();
11124 final int callingUid = Binder.getCallingUid();
11125 final long origId = Binder.clearCallingIdentity();
11126 ComponentName res = startServiceLocked(caller, service,
11127 resolvedType, callingPid, callingUid);
11128 Binder.restoreCallingIdentity(origId);
11129 return res;
11130 }
11131 }
11132
11133 ComponentName startServiceInPackage(int uid,
11134 Intent service, String resolvedType) {
11135 synchronized(this) {
11136 final long origId = Binder.clearCallingIdentity();
11137 ComponentName res = startServiceLocked(null, service,
11138 resolvedType, -1, uid);
11139 Binder.restoreCallingIdentity(origId);
11140 return res;
11141 }
11142 }
11143
11144 public int stopService(IApplicationThread caller, Intent service,
11145 String resolvedType) {
11146 // Refuse possible leaked file descriptors
11147 if (service != null && service.hasFileDescriptors() == true) {
11148 throw new IllegalArgumentException("File descriptors passed in Intent");
11149 }
11150
11151 synchronized(this) {
11152 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
11153 + " type=" + resolvedType);
11154
11155 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11156 if (caller != null && callerApp == null) {
11157 throw new SecurityException(
11158 "Unable to find app for caller " + caller
11159 + " (pid=" + Binder.getCallingPid()
11160 + ") when stopping service " + service);
11161 }
11162
11163 // If this service is active, make sure it is stopped.
11164 ServiceLookupResult r = findServiceLocked(service, resolvedType);
11165 if (r != null) {
11166 if (r.record != null) {
11167 synchronized (r.record.stats.getBatteryStats()) {
11168 r.record.stats.stopRunningLocked();
11169 }
11170 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011171 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011172 final long origId = Binder.clearCallingIdentity();
11173 bringDownServiceLocked(r.record, false);
11174 Binder.restoreCallingIdentity(origId);
11175 return 1;
11176 }
11177 return -1;
11178 }
11179 }
11180
11181 return 0;
11182 }
11183
11184 public IBinder peekService(Intent service, String resolvedType) {
11185 // Refuse possible leaked file descriptors
11186 if (service != null && service.hasFileDescriptors() == true) {
11187 throw new IllegalArgumentException("File descriptors passed in Intent");
11188 }
11189
11190 IBinder ret = null;
11191
11192 synchronized(this) {
11193 ServiceLookupResult r = findServiceLocked(service, resolvedType);
11194
11195 if (r != null) {
11196 // r.record is null if findServiceLocked() failed the caller permission check
11197 if (r.record == null) {
11198 throw new SecurityException(
11199 "Permission Denial: Accessing service " + r.record.name
11200 + " from pid=" + Binder.getCallingPid()
11201 + ", uid=" + Binder.getCallingUid()
11202 + " requires " + r.permission);
11203 }
11204 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
11205 if (ib != null) {
11206 ret = ib.binder;
11207 }
11208 }
11209 }
11210
11211 return ret;
11212 }
11213
11214 public boolean stopServiceToken(ComponentName className, IBinder token,
11215 int startId) {
11216 synchronized(this) {
11217 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
11218 + " " + token + " startId=" + startId);
11219 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011220 if (r != null) {
11221 if (startId >= 0) {
11222 // Asked to only stop if done with all work. Note that
11223 // to avoid leaks, we will take this as dropping all
11224 // start items up to and including this one.
11225 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11226 if (si != null) {
11227 while (r.deliveredStarts.size() > 0) {
11228 if (r.deliveredStarts.remove(0) == si) {
11229 break;
11230 }
11231 }
11232 }
11233
11234 if (r.lastStartId != startId) {
11235 return false;
11236 }
11237
11238 if (r.deliveredStarts.size() > 0) {
11239 Log.w(TAG, "stopServiceToken startId " + startId
11240 + " is last, but have " + r.deliveredStarts.size()
11241 + " remaining args");
11242 }
11243 }
11244
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011245 synchronized (r.stats.getBatteryStats()) {
11246 r.stats.stopRunningLocked();
11247 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011248 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011249 }
11250 final long origId = Binder.clearCallingIdentity();
11251 bringDownServiceLocked(r, false);
11252 Binder.restoreCallingIdentity(origId);
11253 return true;
11254 }
11255 }
11256 return false;
11257 }
11258
11259 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011260 int id, Notification notification, boolean removeNotification) {
11261 final long origId = Binder.clearCallingIdentity();
11262 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011263 synchronized(this) {
11264 ServiceRecord r = findServiceLocked(className, token);
11265 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011266 if (id != 0) {
11267 if (notification == null) {
11268 throw new IllegalArgumentException("null notification");
11269 }
11270 if (r.foregroundId != id) {
11271 r.cancelNotification();
11272 r.foregroundId = id;
11273 }
11274 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
11275 r.foregroundNoti = notification;
11276 r.isForeground = true;
11277 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011278 if (r.app != null) {
11279 updateServiceForegroundLocked(r.app, true);
11280 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011281 } else {
11282 if (r.isForeground) {
11283 r.isForeground = false;
11284 if (r.app != null) {
11285 updateServiceForegroundLocked(r.app, true);
11286 }
11287 }
11288 if (removeNotification) {
11289 r.cancelNotification();
11290 r.foregroundId = 0;
11291 r.foregroundNoti = null;
11292 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011293 }
11294 }
11295 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070011296 } finally {
11297 Binder.restoreCallingIdentity(origId);
11298 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011299 }
11300
11301 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
11302 boolean anyForeground = false;
11303 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
11304 if (sr.isForeground) {
11305 anyForeground = true;
11306 break;
11307 }
11308 }
11309 if (anyForeground != proc.foregroundServices) {
11310 proc.foregroundServices = anyForeground;
11311 if (oomAdj) {
11312 updateOomAdjLocked();
11313 }
11314 }
11315 }
11316
11317 public int bindService(IApplicationThread caller, IBinder token,
11318 Intent service, String resolvedType,
11319 IServiceConnection connection, int flags) {
11320 // Refuse possible leaked file descriptors
11321 if (service != null && service.hasFileDescriptors() == true) {
11322 throw new IllegalArgumentException("File descriptors passed in Intent");
11323 }
11324
11325 synchronized(this) {
11326 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
11327 + " type=" + resolvedType + " conn=" + connection.asBinder()
11328 + " flags=0x" + Integer.toHexString(flags));
11329 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11330 if (callerApp == null) {
11331 throw new SecurityException(
11332 "Unable to find app for caller " + caller
11333 + " (pid=" + Binder.getCallingPid()
11334 + ") when binding service " + service);
11335 }
11336
11337 HistoryRecord activity = null;
11338 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070011339 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011340 if (aindex < 0) {
11341 Log.w(TAG, "Binding with unknown activity: " + token);
11342 return 0;
11343 }
11344 activity = (HistoryRecord)mHistory.get(aindex);
11345 }
11346
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011347 int clientLabel = 0;
11348 PendingIntent clientIntent = null;
11349
11350 if (callerApp.info.uid == Process.SYSTEM_UID) {
11351 // Hacky kind of thing -- allow system stuff to tell us
11352 // what they are, so we can report this elsewhere for
11353 // others to know why certain services are running.
11354 try {
11355 clientIntent = (PendingIntent)service.getParcelableExtra(
11356 Intent.EXTRA_CLIENT_INTENT);
11357 } catch (RuntimeException e) {
11358 }
11359 if (clientIntent != null) {
11360 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
11361 if (clientLabel != 0) {
11362 // There are no useful extras in the intent, trash them.
11363 // System code calling with this stuff just needs to know
11364 // this will happen.
11365 service = service.cloneFilter();
11366 }
11367 }
11368 }
11369
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011370 ServiceLookupResult res =
11371 retrieveServiceLocked(service, resolvedType,
11372 Binder.getCallingPid(), Binder.getCallingUid());
11373 if (res == null) {
11374 return 0;
11375 }
11376 if (res.record == null) {
11377 return -1;
11378 }
11379 ServiceRecord s = res.record;
11380
11381 final long origId = Binder.clearCallingIdentity();
11382
11383 if (unscheduleServiceRestartLocked(s)) {
11384 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
11385 + s.shortName);
11386 }
11387
11388 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
11389 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011390 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011391
11392 IBinder binder = connection.asBinder();
11393 s.connections.put(binder, c);
11394 b.connections.add(c);
11395 if (activity != null) {
11396 if (activity.connections == null) {
11397 activity.connections = new HashSet<ConnectionRecord>();
11398 }
11399 activity.connections.add(c);
11400 }
11401 b.client.connections.add(c);
11402 mServiceConnections.put(binder, c);
11403
11404 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
11405 s.lastActivity = SystemClock.uptimeMillis();
11406 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
11407 return 0;
11408 }
11409 }
11410
11411 if (s.app != null) {
11412 // This could have made the service more important.
11413 updateOomAdjLocked(s.app);
11414 }
11415
11416 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
11417 + ": received=" + b.intent.received
11418 + " apps=" + b.intent.apps.size()
11419 + " doRebind=" + b.intent.doRebind);
11420
11421 if (s.app != null && b.intent.received) {
11422 // Service is already running, so we can immediately
11423 // publish the connection.
11424 try {
11425 c.conn.connected(s.name, b.intent.binder);
11426 } catch (Exception e) {
11427 Log.w(TAG, "Failure sending service " + s.shortName
11428 + " to connection " + c.conn.asBinder()
11429 + " (in " + c.binding.client.processName + ")", e);
11430 }
11431
11432 // If this is the first app connected back to this binding,
11433 // and the service had previously asked to be told when
11434 // rebound, then do so.
11435 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
11436 requestServiceBindingLocked(s, b.intent, true);
11437 }
11438 } else if (!b.intent.requested) {
11439 requestServiceBindingLocked(s, b.intent, false);
11440 }
11441
11442 Binder.restoreCallingIdentity(origId);
11443 }
11444
11445 return 1;
11446 }
11447
11448 private void removeConnectionLocked(
11449 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
11450 IBinder binder = c.conn.asBinder();
11451 AppBindRecord b = c.binding;
11452 ServiceRecord s = b.service;
11453 s.connections.remove(binder);
11454 b.connections.remove(c);
11455 if (c.activity != null && c.activity != skipAct) {
11456 if (c.activity.connections != null) {
11457 c.activity.connections.remove(c);
11458 }
11459 }
11460 if (b.client != skipApp) {
11461 b.client.connections.remove(c);
11462 }
11463 mServiceConnections.remove(binder);
11464
11465 if (b.connections.size() == 0) {
11466 b.intent.apps.remove(b.client);
11467 }
11468
11469 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
11470 + ": shouldUnbind=" + b.intent.hasBound);
11471 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
11472 && b.intent.hasBound) {
11473 try {
11474 bumpServiceExecutingLocked(s);
11475 updateOomAdjLocked(s.app);
11476 b.intent.hasBound = false;
11477 // Assume the client doesn't want to know about a rebind;
11478 // we will deal with that later if it asks for one.
11479 b.intent.doRebind = false;
11480 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
11481 } catch (Exception e) {
11482 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
11483 serviceDoneExecutingLocked(s, true);
11484 }
11485 }
11486
11487 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
11488 bringDownServiceLocked(s, false);
11489 }
11490 }
11491
11492 public boolean unbindService(IServiceConnection connection) {
11493 synchronized (this) {
11494 IBinder binder = connection.asBinder();
11495 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11496 ConnectionRecord r = mServiceConnections.get(binder);
11497 if (r == null) {
11498 Log.w(TAG, "Unbind failed: could not find connection for "
11499 + connection.asBinder());
11500 return false;
11501 }
11502
11503 final long origId = Binder.clearCallingIdentity();
11504
11505 removeConnectionLocked(r, null, null);
11506
11507 if (r.binding.service.app != null) {
11508 // This could have made the service less important.
11509 updateOomAdjLocked(r.binding.service.app);
11510 }
11511
11512 Binder.restoreCallingIdentity(origId);
11513 }
11514
11515 return true;
11516 }
11517
11518 public void publishService(IBinder token, Intent intent, IBinder service) {
11519 // Refuse possible leaked file descriptors
11520 if (intent != null && intent.hasFileDescriptors() == true) {
11521 throw new IllegalArgumentException("File descriptors passed in Intent");
11522 }
11523
11524 synchronized(this) {
11525 if (!(token instanceof ServiceRecord)) {
11526 throw new IllegalArgumentException("Invalid service token");
11527 }
11528 ServiceRecord r = (ServiceRecord)token;
11529
11530 final long origId = Binder.clearCallingIdentity();
11531
11532 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11533 + " " + intent + ": " + service);
11534 if (r != null) {
11535 Intent.FilterComparison filter
11536 = new Intent.FilterComparison(intent);
11537 IntentBindRecord b = r.bindings.get(filter);
11538 if (b != null && !b.received) {
11539 b.binder = service;
11540 b.requested = true;
11541 b.received = true;
11542 if (r.connections.size() > 0) {
11543 Iterator<ConnectionRecord> it
11544 = r.connections.values().iterator();
11545 while (it.hasNext()) {
11546 ConnectionRecord c = it.next();
11547 if (!filter.equals(c.binding.intent.intent)) {
11548 if (DEBUG_SERVICE) Log.v(
11549 TAG, "Not publishing to: " + c);
11550 if (DEBUG_SERVICE) Log.v(
11551 TAG, "Bound intent: " + c.binding.intent.intent);
11552 if (DEBUG_SERVICE) Log.v(
11553 TAG, "Published intent: " + intent);
11554 continue;
11555 }
11556 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11557 try {
11558 c.conn.connected(r.name, service);
11559 } catch (Exception e) {
11560 Log.w(TAG, "Failure sending service " + r.name +
11561 " to connection " + c.conn.asBinder() +
11562 " (in " + c.binding.client.processName + ")", e);
11563 }
11564 }
11565 }
11566 }
11567
11568 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11569
11570 Binder.restoreCallingIdentity(origId);
11571 }
11572 }
11573 }
11574
11575 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11576 // Refuse possible leaked file descriptors
11577 if (intent != null && intent.hasFileDescriptors() == true) {
11578 throw new IllegalArgumentException("File descriptors passed in Intent");
11579 }
11580
11581 synchronized(this) {
11582 if (!(token instanceof ServiceRecord)) {
11583 throw new IllegalArgumentException("Invalid service token");
11584 }
11585 ServiceRecord r = (ServiceRecord)token;
11586
11587 final long origId = Binder.clearCallingIdentity();
11588
11589 if (r != null) {
11590 Intent.FilterComparison filter
11591 = new Intent.FilterComparison(intent);
11592 IntentBindRecord b = r.bindings.get(filter);
11593 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11594 + " at " + b + ": apps="
11595 + (b != null ? b.apps.size() : 0));
11596 if (b != null) {
11597 if (b.apps.size() > 0) {
11598 // Applications have already bound since the last
11599 // unbind, so just rebind right here.
11600 requestServiceBindingLocked(r, b, true);
11601 } else {
11602 // Note to tell the service the next time there is
11603 // a new client.
11604 b.doRebind = true;
11605 }
11606 }
11607
11608 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11609
11610 Binder.restoreCallingIdentity(origId);
11611 }
11612 }
11613 }
11614
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011615 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011616 synchronized(this) {
11617 if (!(token instanceof ServiceRecord)) {
11618 throw new IllegalArgumentException("Invalid service token");
11619 }
11620 ServiceRecord r = (ServiceRecord)token;
11621 boolean inStopping = mStoppingServices.contains(token);
11622 if (r != null) {
11623 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11624 + ": nesting=" + r.executeNesting
11625 + ", inStopping=" + inStopping);
11626 if (r != token) {
11627 Log.w(TAG, "Done executing service " + r.name
11628 + " with incorrect token: given " + token
11629 + ", expected " + r);
11630 return;
11631 }
11632
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011633 if (type == 1) {
11634 // This is a call from a service start... take care of
11635 // book-keeping.
11636 r.callStart = true;
11637 switch (res) {
11638 case Service.START_STICKY_COMPATIBILITY:
11639 case Service.START_STICKY: {
11640 // We are done with the associated start arguments.
11641 r.findDeliveredStart(startId, true);
11642 // Don't stop if killed.
11643 r.stopIfKilled = false;
11644 break;
11645 }
11646 case Service.START_NOT_STICKY: {
11647 // We are done with the associated start arguments.
11648 r.findDeliveredStart(startId, true);
11649 if (r.lastStartId == startId) {
11650 // There is no more work, and this service
11651 // doesn't want to hang around if killed.
11652 r.stopIfKilled = true;
11653 }
11654 break;
11655 }
11656 case Service.START_REDELIVER_INTENT: {
11657 // We'll keep this item until they explicitly
11658 // call stop for it, but keep track of the fact
11659 // that it was delivered.
11660 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11661 if (si != null) {
11662 si.deliveryCount = 0;
11663 si.doneExecutingCount++;
11664 // Don't stop if killed.
11665 r.stopIfKilled = true;
11666 }
11667 break;
11668 }
11669 default:
11670 throw new IllegalArgumentException(
11671 "Unknown service start result: " + res);
11672 }
11673 if (res == Service.START_STICKY_COMPATIBILITY) {
11674 r.callStart = false;
11675 }
11676 }
11677
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011678 final long origId = Binder.clearCallingIdentity();
11679 serviceDoneExecutingLocked(r, inStopping);
11680 Binder.restoreCallingIdentity(origId);
11681 } else {
11682 Log.w(TAG, "Done executing unknown service " + r.name
11683 + " with token " + token);
11684 }
11685 }
11686 }
11687
11688 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11689 r.executeNesting--;
11690 if (r.executeNesting <= 0 && r.app != null) {
11691 r.app.executingServices.remove(r);
11692 if (r.app.executingServices.size() == 0) {
11693 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11694 }
11695 if (inStopping) {
11696 mStoppingServices.remove(r);
11697 }
11698 updateOomAdjLocked(r.app);
11699 }
11700 }
11701
11702 void serviceTimeout(ProcessRecord proc) {
11703 synchronized(this) {
11704 if (proc.executingServices.size() == 0 || proc.thread == null) {
11705 return;
11706 }
11707 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11708 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11709 ServiceRecord timeout = null;
11710 long nextTime = 0;
11711 while (it.hasNext()) {
11712 ServiceRecord sr = it.next();
11713 if (sr.executingStart < maxTime) {
11714 timeout = sr;
11715 break;
11716 }
11717 if (sr.executingStart > nextTime) {
11718 nextTime = sr.executingStart;
11719 }
11720 }
Dianne Hackborndd71fc82009-12-16 19:24:32 -080011721 if (timeout != null && mLruProcesses.contains(proc)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011722 Log.w(TAG, "Timeout executing service: " + timeout);
Dan Egnor42471dd2010-01-07 17:25:22 -080011723 appNotRespondingLocked(proc, null, null, "Executing service " + timeout.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011724 } else {
11725 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11726 msg.obj = proc;
11727 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11728 }
11729 }
11730 }
11731
11732 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011733 // BACKUP AND RESTORE
11734 // =========================================================
11735
11736 // Cause the target app to be launched if necessary and its backup agent
11737 // instantiated. The backup agent will invoke backupAgentCreated() on the
11738 // activity manager to announce its creation.
11739 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11740 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11741 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11742
11743 synchronized(this) {
11744 // !!! TODO: currently no check here that we're already bound
11745 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11746 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11747 synchronized (stats) {
11748 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11749 }
11750
11751 BackupRecord r = new BackupRecord(ss, app, backupMode);
11752 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11753 // startProcessLocked() returns existing proc's record if it's already running
11754 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011755 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011756 if (proc == null) {
11757 Log.e(TAG, "Unable to start backup agent process " + r);
11758 return false;
11759 }
11760
11761 r.app = proc;
11762 mBackupTarget = r;
11763 mBackupAppName = app.packageName;
11764
Christopher Tate6fa95972009-06-05 18:43:55 -070011765 // Try not to kill the process during backup
11766 updateOomAdjLocked(proc);
11767
Christopher Tate181fafa2009-05-14 11:12:14 -070011768 // If the process is already attached, schedule the creation of the backup agent now.
11769 // If it is not yet live, this will be done when it attaches to the framework.
11770 if (proc.thread != null) {
11771 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11772 try {
11773 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11774 } catch (RemoteException e) {
Christopher Tate436344a2009-09-30 16:17:37 -070011775 // Will time out on the backup manager side
Christopher Tate181fafa2009-05-14 11:12:14 -070011776 }
11777 } else {
11778 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11779 }
11780 // Invariants: at this point, the target app process exists and the application
11781 // is either already running or in the process of coming up. mBackupTarget and
11782 // mBackupAppName describe the app, so that when it binds back to the AM we
11783 // know that it's scheduled for a backup-agent operation.
11784 }
11785
11786 return true;
11787 }
11788
11789 // A backup agent has just come up
11790 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11791 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11792 + " = " + agent);
11793
11794 synchronized(this) {
11795 if (!agentPackageName.equals(mBackupAppName)) {
11796 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11797 return;
11798 }
11799
Christopher Tate043dadc2009-06-02 16:11:00 -070011800 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011801 try {
11802 IBackupManager bm = IBackupManager.Stub.asInterface(
11803 ServiceManager.getService(Context.BACKUP_SERVICE));
11804 bm.agentConnected(agentPackageName, agent);
11805 } catch (RemoteException e) {
11806 // can't happen; the backup manager service is local
11807 } catch (Exception e) {
11808 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11809 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011810 } finally {
11811 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011812 }
11813 }
11814 }
11815
11816 // done with this agent
11817 public void unbindBackupAgent(ApplicationInfo appInfo) {
11818 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011819 if (appInfo == null) {
11820 Log.w(TAG, "unbind backup agent for null app");
11821 return;
11822 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011823
11824 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011825 if (mBackupAppName == null) {
11826 Log.w(TAG, "Unbinding backup agent with no active backup");
11827 return;
11828 }
11829
Christopher Tate181fafa2009-05-14 11:12:14 -070011830 if (!mBackupAppName.equals(appInfo.packageName)) {
11831 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11832 return;
11833 }
11834
Christopher Tate6fa95972009-06-05 18:43:55 -070011835 ProcessRecord proc = mBackupTarget.app;
11836 mBackupTarget = null;
11837 mBackupAppName = null;
11838
11839 // Not backing this app up any more; reset its OOM adjustment
11840 updateOomAdjLocked(proc);
11841
Christopher Tatec7b31e32009-06-10 15:49:30 -070011842 // If the app crashed during backup, 'thread' will be null here
11843 if (proc.thread != null) {
11844 try {
11845 proc.thread.scheduleDestroyBackupAgent(appInfo);
11846 } catch (Exception e) {
11847 Log.e(TAG, "Exception when unbinding backup agent:");
11848 e.printStackTrace();
11849 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011850 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011851 }
11852 }
11853 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011854 // BROADCASTS
11855 // =========================================================
11856
11857 private final List getStickies(String action, IntentFilter filter,
11858 List cur) {
11859 final ContentResolver resolver = mContext.getContentResolver();
11860 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11861 if (list == null) {
11862 return cur;
11863 }
11864 int N = list.size();
11865 for (int i=0; i<N; i++) {
11866 Intent intent = list.get(i);
11867 if (filter.match(resolver, intent, true, TAG) >= 0) {
11868 if (cur == null) {
11869 cur = new ArrayList<Intent>();
11870 }
11871 cur.add(intent);
11872 }
11873 }
11874 return cur;
11875 }
11876
11877 private final void scheduleBroadcastsLocked() {
11878 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11879 + mBroadcastsScheduled);
11880
11881 if (mBroadcastsScheduled) {
11882 return;
11883 }
11884 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11885 mBroadcastsScheduled = true;
11886 }
11887
11888 public Intent registerReceiver(IApplicationThread caller,
11889 IIntentReceiver receiver, IntentFilter filter, String permission) {
11890 synchronized(this) {
11891 ProcessRecord callerApp = null;
11892 if (caller != null) {
11893 callerApp = getRecordForAppLocked(caller);
11894 if (callerApp == null) {
11895 throw new SecurityException(
11896 "Unable to find app for caller " + caller
11897 + " (pid=" + Binder.getCallingPid()
11898 + ") when registering receiver " + receiver);
11899 }
11900 }
11901
11902 List allSticky = null;
11903
11904 // Look for any matching sticky broadcasts...
11905 Iterator actions = filter.actionsIterator();
11906 if (actions != null) {
11907 while (actions.hasNext()) {
11908 String action = (String)actions.next();
11909 allSticky = getStickies(action, filter, allSticky);
11910 }
11911 } else {
11912 allSticky = getStickies(null, filter, allSticky);
11913 }
11914
11915 // The first sticky in the list is returned directly back to
11916 // the client.
11917 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11918
11919 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11920 + ": " + sticky);
11921
11922 if (receiver == null) {
11923 return sticky;
11924 }
11925
11926 ReceiverList rl
11927 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11928 if (rl == null) {
11929 rl = new ReceiverList(this, callerApp,
11930 Binder.getCallingPid(),
11931 Binder.getCallingUid(), receiver);
11932 if (rl.app != null) {
11933 rl.app.receivers.add(rl);
11934 } else {
11935 try {
11936 receiver.asBinder().linkToDeath(rl, 0);
11937 } catch (RemoteException e) {
11938 return sticky;
11939 }
11940 rl.linkedToDeath = true;
11941 }
11942 mRegisteredReceivers.put(receiver.asBinder(), rl);
11943 }
11944 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11945 rl.add(bf);
11946 if (!bf.debugCheck()) {
11947 Log.w(TAG, "==> For Dynamic broadast");
11948 }
11949 mReceiverResolver.addFilter(bf);
11950
11951 // Enqueue broadcasts for all existing stickies that match
11952 // this filter.
11953 if (allSticky != null) {
11954 ArrayList receivers = new ArrayList();
11955 receivers.add(bf);
11956
11957 int N = allSticky.size();
11958 for (int i=0; i<N; i++) {
11959 Intent intent = (Intent)allSticky.get(i);
11960 BroadcastRecord r = new BroadcastRecord(intent, null,
11961 null, -1, -1, null, receivers, null, 0, null, null,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011962 false, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011963 if (mParallelBroadcasts.size() == 0) {
11964 scheduleBroadcastsLocked();
11965 }
11966 mParallelBroadcasts.add(r);
11967 }
11968 }
11969
11970 return sticky;
11971 }
11972 }
11973
11974 public void unregisterReceiver(IIntentReceiver receiver) {
11975 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11976
11977 boolean doNext = false;
11978
11979 synchronized(this) {
11980 ReceiverList rl
11981 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11982 if (rl != null) {
11983 if (rl.curBroadcast != null) {
11984 BroadcastRecord r = rl.curBroadcast;
11985 doNext = finishReceiverLocked(
11986 receiver.asBinder(), r.resultCode, r.resultData,
11987 r.resultExtras, r.resultAbort, true);
11988 }
11989
11990 if (rl.app != null) {
11991 rl.app.receivers.remove(rl);
11992 }
11993 removeReceiverLocked(rl);
11994 if (rl.linkedToDeath) {
11995 rl.linkedToDeath = false;
11996 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11997 }
11998 }
11999 }
12000
12001 if (!doNext) {
12002 return;
12003 }
12004
12005 final long origId = Binder.clearCallingIdentity();
12006 processNextBroadcast(false);
12007 trimApplications();
12008 Binder.restoreCallingIdentity(origId);
12009 }
12010
12011 void removeReceiverLocked(ReceiverList rl) {
12012 mRegisteredReceivers.remove(rl.receiver.asBinder());
12013 int N = rl.size();
12014 for (int i=0; i<N; i++) {
12015 mReceiverResolver.removeFilter(rl.get(i));
12016 }
12017 }
12018
12019 private final int broadcastIntentLocked(ProcessRecord callerApp,
12020 String callerPackage, Intent intent, String resolvedType,
12021 IIntentReceiver resultTo, int resultCode, String resultData,
12022 Bundle map, String requiredPermission,
12023 boolean ordered, boolean sticky, int callingPid, int callingUid) {
12024 intent = new Intent(intent);
12025
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012026 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012027 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
12028 + " ordered=" + ordered);
12029 if ((resultTo != null) && !ordered) {
12030 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
12031 }
12032
12033 // Handle special intents: if this broadcast is from the package
12034 // manager about a package being removed, we need to remove all of
12035 // its activities from the history stack.
12036 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
12037 intent.getAction());
12038 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
12039 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
Suchi Amalapurapub56ae202010-02-04 22:51:07 -080012040 || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012041 || uidRemoved) {
12042 if (checkComponentPermission(
12043 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
12044 callingPid, callingUid, -1)
12045 == PackageManager.PERMISSION_GRANTED) {
12046 if (uidRemoved) {
12047 final Bundle intentExtras = intent.getExtras();
12048 final int uid = intentExtras != null
12049 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
12050 if (uid >= 0) {
12051 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
12052 synchronized (bs) {
12053 bs.removeUidStatsLocked(uid);
12054 }
12055 }
12056 } else {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080012057 // If resources are unvailble just force stop all
12058 // those packages and flush the attribute cache as well.
Suchi Amalapurapub56ae202010-02-04 22:51:07 -080012059 if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080012060 String list[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
12061 if (list != null && (list.length > 0)) {
12062 for (String pkg : list) {
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080012063 forceStopPackageLocked(pkg, -1, false, true, true);
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080012064 }
12065 }
12066 } else {
12067 Uri data = intent.getData();
12068 String ssp;
12069 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
12070 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
12071 forceStopPackageLocked(ssp,
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080012072 intent.getIntExtra(Intent.EXTRA_UID, -1), false, true, true);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070012073 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012074 }
12075 }
12076 }
12077 } else {
12078 String msg = "Permission Denial: " + intent.getAction()
12079 + " broadcast from " + callerPackage + " (pid=" + callingPid
12080 + ", uid=" + callingUid + ")"
12081 + " requires "
12082 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
12083 Log.w(TAG, msg);
12084 throw new SecurityException(msg);
12085 }
12086 }
12087
12088 /*
12089 * If this is the time zone changed action, queue up a message that will reset the timezone
12090 * of all currently running processes. This message will get queued up before the broadcast
12091 * happens.
12092 */
12093 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
12094 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
12095 }
12096
Dianne Hackborn854060af2009-07-09 18:14:31 -070012097 /*
12098 * Prevent non-system code (defined here to be non-persistent
12099 * processes) from sending protected broadcasts.
12100 */
12101 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
12102 || callingUid == Process.SHELL_UID || callingUid == 0) {
12103 // Always okay.
12104 } else if (callerApp == null || !callerApp.persistent) {
12105 try {
12106 if (ActivityThread.getPackageManager().isProtectedBroadcast(
12107 intent.getAction())) {
12108 String msg = "Permission Denial: not allowed to send broadcast "
12109 + intent.getAction() + " from pid="
12110 + callingPid + ", uid=" + callingUid;
12111 Log.w(TAG, msg);
12112 throw new SecurityException(msg);
12113 }
12114 } catch (RemoteException e) {
12115 Log.w(TAG, "Remote exception", e);
12116 return BROADCAST_SUCCESS;
12117 }
12118 }
12119
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012120 // Add to the sticky list if requested.
12121 if (sticky) {
12122 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
12123 callingPid, callingUid)
12124 != PackageManager.PERMISSION_GRANTED) {
12125 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
12126 + callingPid + ", uid=" + callingUid
12127 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
12128 Log.w(TAG, msg);
12129 throw new SecurityException(msg);
12130 }
12131 if (requiredPermission != null) {
12132 Log.w(TAG, "Can't broadcast sticky intent " + intent
12133 + " and enforce permission " + requiredPermission);
12134 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
12135 }
12136 if (intent.getComponent() != null) {
12137 throw new SecurityException(
12138 "Sticky broadcasts can't target a specific component");
12139 }
12140 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12141 if (list == null) {
12142 list = new ArrayList<Intent>();
12143 mStickyBroadcasts.put(intent.getAction(), list);
12144 }
12145 int N = list.size();
12146 int i;
12147 for (i=0; i<N; i++) {
12148 if (intent.filterEquals(list.get(i))) {
12149 // This sticky already exists, replace it.
12150 list.set(i, new Intent(intent));
12151 break;
12152 }
12153 }
12154 if (i >= N) {
12155 list.add(new Intent(intent));
12156 }
12157 }
12158
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012159 // Figure out who all will receive this broadcast.
12160 List receivers = null;
12161 List<BroadcastFilter> registeredReceivers = null;
12162 try {
12163 if (intent.getComponent() != null) {
12164 // Broadcast is going to one specific receiver class...
12165 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070012166 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012167 if (ai != null) {
12168 receivers = new ArrayList();
12169 ResolveInfo ri = new ResolveInfo();
12170 ri.activityInfo = ai;
12171 receivers.add(ri);
12172 }
12173 } else {
12174 // Need to resolve the intent to interested receivers...
12175 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
12176 == 0) {
12177 receivers =
12178 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012179 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012180 }
Mihai Preda074edef2009-05-18 17:13:31 +020012181 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012182 }
12183 } catch (RemoteException ex) {
12184 // pm is in same process, this will never happen.
12185 }
12186
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012187 final boolean replacePending =
12188 (intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
12189
12190 if (DEBUG_BROADCAST) Log.v(TAG, "Enqueing broadcast: " + intent.getAction()
12191 + " replacePending=" + replacePending);
12192
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012193 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
12194 if (!ordered && NR > 0) {
12195 // If we are not serializing this broadcast, then send the
12196 // registered receivers separately so they don't wait for the
12197 // components to be launched.
12198 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
12199 callerPackage, callingPid, callingUid, requiredPermission,
12200 registeredReceivers, resultTo, resultCode, resultData, map,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012201 ordered, sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012202 if (DEBUG_BROADCAST) Log.v(
12203 TAG, "Enqueueing parallel broadcast " + r
12204 + ": prev had " + mParallelBroadcasts.size());
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012205 boolean replaced = false;
12206 if (replacePending) {
12207 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
12208 if (intent.filterEquals(mParallelBroadcasts.get(i).intent)) {
12209 if (DEBUG_BROADCAST) Log.v(TAG,
12210 "***** DROPPING PARALLEL: " + intent);
12211 mParallelBroadcasts.set(i, r);
12212 replaced = true;
12213 break;
12214 }
12215 }
12216 }
12217 if (!replaced) {
12218 mParallelBroadcasts.add(r);
12219 scheduleBroadcastsLocked();
12220 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012221 registeredReceivers = null;
12222 NR = 0;
12223 }
12224
12225 // Merge into one list.
12226 int ir = 0;
12227 if (receivers != null) {
12228 // A special case for PACKAGE_ADDED: do not allow the package
12229 // being added to see this broadcast. This prevents them from
12230 // using this as a back door to get run as soon as they are
12231 // installed. Maybe in the future we want to have a special install
12232 // broadcast or such for apps, but we'd like to deliberately make
12233 // this decision.
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080012234 String skipPackages[] = null;
12235 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())
12236 || intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())
12237 || intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
12238 Uri data = intent.getData();
12239 if (data != null) {
12240 String pkgName = data.getSchemeSpecificPart();
12241 if (pkgName != null) {
12242 skipPackages = new String[] { pkgName };
12243 }
12244 }
Suchi Amalapurapub56ae202010-02-04 22:51:07 -080012245 } else if (intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) {
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080012246 skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
The Android Open Source Project10592532009-03-18 17:39:46 -070012247 }
Suchi Amalapurapu08675a32010-01-28 09:57:30 -080012248 if (skipPackages != null && (skipPackages.length > 0)) {
12249 for (String skipPackage : skipPackages) {
12250 if (skipPackage != null) {
12251 int NT = receivers.size();
12252 for (int it=0; it<NT; it++) {
12253 ResolveInfo curt = (ResolveInfo)receivers.get(it);
12254 if (curt.activityInfo.packageName.equals(skipPackage)) {
12255 receivers.remove(it);
12256 it--;
12257 NT--;
12258 }
12259 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012260 }
12261 }
12262 }
12263
12264 int NT = receivers != null ? receivers.size() : 0;
12265 int it = 0;
12266 ResolveInfo curt = null;
12267 BroadcastFilter curr = null;
12268 while (it < NT && ir < NR) {
12269 if (curt == null) {
12270 curt = (ResolveInfo)receivers.get(it);
12271 }
12272 if (curr == null) {
12273 curr = registeredReceivers.get(ir);
12274 }
12275 if (curr.getPriority() >= curt.priority) {
12276 // Insert this broadcast record into the final list.
12277 receivers.add(it, curr);
12278 ir++;
12279 curr = null;
12280 it++;
12281 NT++;
12282 } else {
12283 // Skip to the next ResolveInfo in the final list.
12284 it++;
12285 curt = null;
12286 }
12287 }
12288 }
12289 while (ir < NR) {
12290 if (receivers == null) {
12291 receivers = new ArrayList();
12292 }
12293 receivers.add(registeredReceivers.get(ir));
12294 ir++;
12295 }
12296
12297 if ((receivers != null && receivers.size() > 0)
12298 || resultTo != null) {
12299 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
12300 callerPackage, callingPid, callingUid, requiredPermission,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012301 receivers, resultTo, resultCode, resultData, map, ordered,
12302 sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012303 if (DEBUG_BROADCAST) Log.v(
12304 TAG, "Enqueueing ordered broadcast " + r
12305 + ": prev had " + mOrderedBroadcasts.size());
12306 if (DEBUG_BROADCAST) {
12307 int seq = r.intent.getIntExtra("seq", -1);
12308 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
12309 }
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080012310 boolean replaced = false;
12311 if (replacePending) {
12312 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
12313 if (intent.filterEquals(mOrderedBroadcasts.get(i).intent)) {
12314 if (DEBUG_BROADCAST) Log.v(TAG,
12315 "***** DROPPING ORDERED: " + intent);
12316 mOrderedBroadcasts.set(i, r);
12317 replaced = true;
12318 break;
12319 }
12320 }
12321 }
12322 if (!replaced) {
12323 mOrderedBroadcasts.add(r);
12324 scheduleBroadcastsLocked();
12325 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012326 }
12327
12328 return BROADCAST_SUCCESS;
12329 }
12330
12331 public final int broadcastIntent(IApplicationThread caller,
12332 Intent intent, String resolvedType, IIntentReceiver resultTo,
12333 int resultCode, String resultData, Bundle map,
12334 String requiredPermission, boolean serialized, boolean sticky) {
12335 // Refuse possible leaked file descriptors
12336 if (intent != null && intent.hasFileDescriptors() == true) {
12337 throw new IllegalArgumentException("File descriptors passed in Intent");
12338 }
12339
12340 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012341 int flags = intent.getFlags();
12342
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012343 if (!mSystemReady) {
12344 // if the caller really truly claims to know what they're doing, go
12345 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012346 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
12347 intent = new Intent(intent);
12348 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
12349 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
12350 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
12351 + " before boot completion");
12352 throw new IllegalStateException("Cannot broadcast before boot completed");
12353 }
12354 }
12355
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012356 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
12357 throw new IllegalArgumentException(
12358 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
12359 }
12360
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012361 final ProcessRecord callerApp = getRecordForAppLocked(caller);
12362 final int callingPid = Binder.getCallingPid();
12363 final int callingUid = Binder.getCallingUid();
12364 final long origId = Binder.clearCallingIdentity();
12365 int res = broadcastIntentLocked(callerApp,
12366 callerApp != null ? callerApp.info.packageName : null,
12367 intent, resolvedType, resultTo,
12368 resultCode, resultData, map, requiredPermission, serialized,
12369 sticky, callingPid, callingUid);
12370 Binder.restoreCallingIdentity(origId);
12371 return res;
12372 }
12373 }
12374
12375 int broadcastIntentInPackage(String packageName, int uid,
12376 Intent intent, String resolvedType, IIntentReceiver resultTo,
12377 int resultCode, String resultData, Bundle map,
12378 String requiredPermission, boolean serialized, boolean sticky) {
12379 synchronized(this) {
12380 final long origId = Binder.clearCallingIdentity();
12381 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
12382 resultTo, resultCode, resultData, map, requiredPermission,
12383 serialized, sticky, -1, uid);
12384 Binder.restoreCallingIdentity(origId);
12385 return res;
12386 }
12387 }
12388
12389 public final void unbroadcastIntent(IApplicationThread caller,
12390 Intent intent) {
12391 // Refuse possible leaked file descriptors
12392 if (intent != null && intent.hasFileDescriptors() == true) {
12393 throw new IllegalArgumentException("File descriptors passed in Intent");
12394 }
12395
12396 synchronized(this) {
12397 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
12398 != PackageManager.PERMISSION_GRANTED) {
12399 String msg = "Permission Denial: unbroadcastIntent() from pid="
12400 + Binder.getCallingPid()
12401 + ", uid=" + Binder.getCallingUid()
12402 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
12403 Log.w(TAG, msg);
12404 throw new SecurityException(msg);
12405 }
12406 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12407 if (list != null) {
12408 int N = list.size();
12409 int i;
12410 for (i=0; i<N; i++) {
12411 if (intent.filterEquals(list.get(i))) {
12412 list.remove(i);
12413 break;
12414 }
12415 }
12416 }
12417 }
12418 }
12419
12420 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
12421 String resultData, Bundle resultExtras, boolean resultAbort,
12422 boolean explicit) {
12423 if (mOrderedBroadcasts.size() == 0) {
12424 if (explicit) {
12425 Log.w(TAG, "finishReceiver called but no pending broadcasts");
12426 }
12427 return false;
12428 }
12429 BroadcastRecord r = mOrderedBroadcasts.get(0);
12430 if (r.receiver == null) {
12431 if (explicit) {
12432 Log.w(TAG, "finishReceiver called but none active");
12433 }
12434 return false;
12435 }
12436 if (r.receiver != receiver) {
12437 Log.w(TAG, "finishReceiver called but active receiver is different");
12438 return false;
12439 }
12440 int state = r.state;
12441 r.state = r.IDLE;
12442 if (state == r.IDLE) {
12443 if (explicit) {
12444 Log.w(TAG, "finishReceiver called but state is IDLE");
12445 }
12446 }
12447 r.receiver = null;
12448 r.intent.setComponent(null);
12449 if (r.curApp != null) {
12450 r.curApp.curReceiver = null;
12451 }
12452 if (r.curFilter != null) {
12453 r.curFilter.receiverList.curBroadcast = null;
12454 }
12455 r.curFilter = null;
12456 r.curApp = null;
12457 r.curComponent = null;
12458 r.curReceiver = null;
12459 mPendingBroadcast = null;
12460
12461 r.resultCode = resultCode;
12462 r.resultData = resultData;
12463 r.resultExtras = resultExtras;
12464 r.resultAbort = resultAbort;
12465
12466 // We will process the next receiver right now if this is finishing
12467 // an app receiver (which is always asynchronous) or after we have
12468 // come back from calling a receiver.
12469 return state == BroadcastRecord.APP_RECEIVE
12470 || state == BroadcastRecord.CALL_DONE_RECEIVE;
12471 }
12472
12473 public void finishReceiver(IBinder who, int resultCode, String resultData,
12474 Bundle resultExtras, boolean resultAbort) {
12475 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
12476
12477 // Refuse possible leaked file descriptors
12478 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
12479 throw new IllegalArgumentException("File descriptors passed in Bundle");
12480 }
12481
12482 boolean doNext;
12483
12484 final long origId = Binder.clearCallingIdentity();
12485
12486 synchronized(this) {
12487 doNext = finishReceiverLocked(
12488 who, resultCode, resultData, resultExtras, resultAbort, true);
12489 }
12490
12491 if (doNext) {
12492 processNextBroadcast(false);
12493 }
12494 trimApplications();
12495
12496 Binder.restoreCallingIdentity(origId);
12497 }
12498
12499 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
12500 if (r.nextReceiver > 0) {
12501 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12502 if (curReceiver instanceof BroadcastFilter) {
12503 BroadcastFilter bf = (BroadcastFilter) curReceiver;
Doug Zongker2bec3d42009-12-04 12:52:44 -080012504 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012505 System.identityHashCode(r),
12506 r.intent.getAction(),
12507 r.nextReceiver - 1,
12508 System.identityHashCode(bf));
12509 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -080012510 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012511 System.identityHashCode(r),
12512 r.intent.getAction(),
12513 r.nextReceiver - 1,
12514 ((ResolveInfo)curReceiver).toString());
12515 }
12516 } else {
12517 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
12518 + r);
Doug Zongker2bec3d42009-12-04 12:52:44 -080012519 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012520 System.identityHashCode(r),
12521 r.intent.getAction(),
12522 r.nextReceiver,
12523 "NONE");
12524 }
12525 }
12526
12527 private final void broadcastTimeout() {
12528 synchronized (this) {
12529 if (mOrderedBroadcasts.size() == 0) {
12530 return;
12531 }
12532 long now = SystemClock.uptimeMillis();
12533 BroadcastRecord r = mOrderedBroadcasts.get(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012534 if ((r.receiverTime+BROADCAST_TIMEOUT) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012535 if (DEBUG_BROADCAST) Log.v(TAG,
12536 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012537 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012538 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012539 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012540 return;
12541 }
12542
12543 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012544 r.receiverTime = now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012545 r.anrCount++;
12546
12547 // Current receiver has passed its expiration date.
12548 if (r.nextReceiver <= 0) {
12549 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12550 return;
12551 }
12552
12553 ProcessRecord app = null;
12554
12555 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12556 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12557 logBroadcastReceiverDiscard(r);
12558 if (curReceiver instanceof BroadcastFilter) {
12559 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12560 if (bf.receiverList.pid != 0
12561 && bf.receiverList.pid != MY_PID) {
12562 synchronized (this.mPidsSelfLocked) {
12563 app = this.mPidsSelfLocked.get(
12564 bf.receiverList.pid);
12565 }
12566 }
12567 } else {
12568 app = r.curApp;
12569 }
12570
12571 if (app != null) {
Dan Egnorb7f03672009-12-09 16:22:32 -080012572 appNotRespondingLocked(app, null, null, "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012573 }
12574
12575 if (mPendingBroadcast == r) {
12576 mPendingBroadcast = null;
12577 }
12578
12579 // Move on to the next receiver.
12580 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12581 r.resultExtras, r.resultAbort, true);
12582 scheduleBroadcastsLocked();
12583 }
12584 }
12585
12586 private final void processCurBroadcastLocked(BroadcastRecord r,
12587 ProcessRecord app) throws RemoteException {
12588 if (app.thread == null) {
12589 throw new RemoteException();
12590 }
12591 r.receiver = app.thread.asBinder();
12592 r.curApp = app;
12593 app.curReceiver = r;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080012594 updateLruProcessLocked(app, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012595
12596 // Tell the application to launch this receiver.
12597 r.intent.setComponent(r.curComponent);
12598
12599 boolean started = false;
12600 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012601 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012602 "Delivering to component " + r.curComponent
12603 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012604 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012605 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12606 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12607 started = true;
12608 } finally {
12609 if (!started) {
12610 r.receiver = null;
12611 r.curApp = null;
12612 app.curReceiver = null;
12613 }
12614 }
12615
12616 }
12617
12618 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012619 Intent intent, int resultCode, String data, Bundle extras,
12620 boolean ordered, boolean sticky) throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012621 if (app != null && app.thread != null) {
12622 // If we have an app thread, do the call through that so it is
12623 // correctly ordered with other one-way calls.
12624 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012625 data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012626 } else {
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012627 receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012628 }
12629 }
12630
12631 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12632 BroadcastFilter filter, boolean ordered) {
12633 boolean skip = false;
12634 if (filter.requiredPermission != null) {
12635 int perm = checkComponentPermission(filter.requiredPermission,
12636 r.callingPid, r.callingUid, -1);
12637 if (perm != PackageManager.PERMISSION_GRANTED) {
12638 Log.w(TAG, "Permission Denial: broadcasting "
12639 + r.intent.toString()
12640 + " from " + r.callerPackage + " (pid="
12641 + r.callingPid + ", uid=" + r.callingUid + ")"
12642 + " requires " + filter.requiredPermission
12643 + " due to registered receiver " + filter);
12644 skip = true;
12645 }
12646 }
12647 if (r.requiredPermission != null) {
12648 int perm = checkComponentPermission(r.requiredPermission,
12649 filter.receiverList.pid, filter.receiverList.uid, -1);
12650 if (perm != PackageManager.PERMISSION_GRANTED) {
12651 Log.w(TAG, "Permission Denial: receiving "
12652 + r.intent.toString()
12653 + " to " + filter.receiverList.app
12654 + " (pid=" + filter.receiverList.pid
12655 + ", uid=" + filter.receiverList.uid + ")"
12656 + " requires " + r.requiredPermission
12657 + " due to sender " + r.callerPackage
12658 + " (uid " + r.callingUid + ")");
12659 skip = true;
12660 }
12661 }
12662
12663 if (!skip) {
12664 // If this is not being sent as an ordered broadcast, then we
12665 // don't want to touch the fields that keep track of the current
12666 // state of ordered broadcasts.
12667 if (ordered) {
12668 r.receiver = filter.receiverList.receiver.asBinder();
12669 r.curFilter = filter;
12670 filter.receiverList.curBroadcast = r;
12671 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012672 if (filter.receiverList.app != null) {
12673 // Bump hosting application to no longer be in background
12674 // scheduling class. Note that we can't do that if there
12675 // isn't an app... but we can only be in that case for
12676 // things that directly call the IActivityManager API, which
12677 // are already core system stuff so don't matter for this.
12678 r.curApp = filter.receiverList.app;
12679 filter.receiverList.app.curReceiver = r;
12680 updateOomAdjLocked();
12681 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012682 }
12683 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012684 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012685 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012686 Log.i(TAG, "Delivering to " + filter.receiverList.app
12687 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012688 }
12689 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12690 new Intent(r.intent), r.resultCode,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012691 r.resultData, r.resultExtras, r.ordered, r.initialSticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012692 if (ordered) {
12693 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12694 }
12695 } catch (RemoteException e) {
12696 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12697 if (ordered) {
12698 r.receiver = null;
12699 r.curFilter = null;
12700 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012701 if (filter.receiverList.app != null) {
12702 filter.receiverList.app.curReceiver = null;
12703 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012704 }
12705 }
12706 }
12707 }
12708
Dianne Hackborn12527f92009-11-11 17:39:50 -080012709 private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
12710 if (r.callingUid < 0) {
12711 // This was from a registerReceiver() call; ignore it.
12712 return;
12713 }
12714 System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
12715 MAX_BROADCAST_HISTORY-1);
12716 r.finishTime = SystemClock.uptimeMillis();
12717 mBroadcastHistory[0] = r;
12718 }
12719
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012720 private final void processNextBroadcast(boolean fromMsg) {
12721 synchronized(this) {
12722 BroadcastRecord r;
12723
12724 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12725 + mParallelBroadcasts.size() + " broadcasts, "
12726 + mOrderedBroadcasts.size() + " serialized broadcasts");
12727
12728 updateCpuStats();
12729
12730 if (fromMsg) {
12731 mBroadcastsScheduled = false;
12732 }
12733
12734 // First, deliver any non-serialized broadcasts right away.
12735 while (mParallelBroadcasts.size() > 0) {
12736 r = mParallelBroadcasts.remove(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012737 r.dispatchTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012738 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012739 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12740 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012741 for (int i=0; i<N; i++) {
12742 Object target = r.receivers.get(i);
12743 if (DEBUG_BROADCAST) Log.v(TAG,
12744 "Delivering non-serialized to registered "
12745 + target + ": " + r);
12746 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12747 }
Dianne Hackborn12527f92009-11-11 17:39:50 -080012748 addBroadcastToHistoryLocked(r);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012749 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12750 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012751 }
12752
12753 // Now take care of the next serialized one...
12754
12755 // If we are waiting for a process to come up to handle the next
12756 // broadcast, then do nothing at this point. Just in case, we
12757 // check that the process we're waiting for still exists.
12758 if (mPendingBroadcast != null) {
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -070012759 if (DEBUG_BROADCAST_LIGHT) {
12760 Log.v(TAG, "processNextBroadcast: waiting for "
12761 + mPendingBroadcast.curApp);
12762 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012763
12764 boolean isDead;
12765 synchronized (mPidsSelfLocked) {
12766 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12767 }
12768 if (!isDead) {
12769 // It's still alive, so keep waiting
12770 return;
12771 } else {
12772 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12773 + " died before responding to broadcast");
12774 mPendingBroadcast = null;
12775 }
12776 }
12777
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012778 boolean looped = false;
12779
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012780 do {
12781 if (mOrderedBroadcasts.size() == 0) {
12782 // No more broadcasts pending, so all done!
12783 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012784 if (looped) {
12785 // If we had finished the last ordered broadcast, then
12786 // make sure all processes have correct oom and sched
12787 // adjustments.
12788 updateOomAdjLocked();
12789 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012790 return;
12791 }
12792 r = mOrderedBroadcasts.get(0);
12793 boolean forceReceive = false;
12794
12795 // Ensure that even if something goes awry with the timeout
12796 // detection, we catch "hung" broadcasts here, discard them,
12797 // and continue to make progress.
12798 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12799 long now = SystemClock.uptimeMillis();
12800 if (r.dispatchTime > 0) {
12801 if ((numReceivers > 0) &&
12802 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12803 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12804 + " now=" + now
12805 + " dispatchTime=" + r.dispatchTime
Dianne Hackborn12527f92009-11-11 17:39:50 -080012806 + " startTime=" + r.receiverTime
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012807 + " intent=" + r.intent
12808 + " numReceivers=" + numReceivers
12809 + " nextReceiver=" + r.nextReceiver
12810 + " state=" + r.state);
12811 broadcastTimeout(); // forcibly finish this broadcast
12812 forceReceive = true;
12813 r.state = BroadcastRecord.IDLE;
12814 }
12815 }
12816
12817 if (r.state != BroadcastRecord.IDLE) {
12818 if (DEBUG_BROADCAST) Log.d(TAG,
12819 "processNextBroadcast() called when not idle (state="
12820 + r.state + ")");
12821 return;
12822 }
12823
12824 if (r.receivers == null || r.nextReceiver >= numReceivers
12825 || r.resultAbort || forceReceive) {
12826 // No more receivers for this broadcast! Send the final
12827 // result if requested...
12828 if (r.resultTo != null) {
12829 try {
12830 if (DEBUG_BROADCAST) {
12831 int seq = r.intent.getIntExtra("seq", -1);
12832 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12833 + " seq=" + seq + " app=" + r.callerApp);
12834 }
12835 performReceive(r.callerApp, r.resultTo,
12836 new Intent(r.intent), r.resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012837 r.resultData, r.resultExtras, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012838 } catch (RemoteException e) {
12839 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12840 }
12841 }
12842
12843 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12844 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12845
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012846 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12847 + r);
12848
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012849 // ... and on to the next...
Dianne Hackborn12527f92009-11-11 17:39:50 -080012850 addBroadcastToHistoryLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012851 mOrderedBroadcasts.remove(0);
12852 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012853 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012854 continue;
12855 }
12856 } while (r == null);
12857
12858 // Get the next receiver...
12859 int recIdx = r.nextReceiver++;
12860
12861 // Keep track of when this receiver started, and make sure there
12862 // is a timeout message pending to kill it if need be.
Dianne Hackborn12527f92009-11-11 17:39:50 -080012863 r.receiverTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012864 if (recIdx == 0) {
Dianne Hackborn12527f92009-11-11 17:39:50 -080012865 r.dispatchTime = r.receiverTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012866
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012867 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12868 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012869 if (DEBUG_BROADCAST) Log.v(TAG,
12870 "Submitting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012871 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012872 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012873 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012874 }
12875
12876 Object nextReceiver = r.receivers.get(recIdx);
12877 if (nextReceiver instanceof BroadcastFilter) {
12878 // Simple case: this is a registered receiver who gets
12879 // a direct call.
12880 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12881 if (DEBUG_BROADCAST) Log.v(TAG,
12882 "Delivering serialized to registered "
12883 + filter + ": " + r);
12884 deliverToRegisteredReceiver(r, filter, r.ordered);
12885 if (r.receiver == null || !r.ordered) {
12886 // The receiver has already finished, so schedule to
12887 // process the next one.
12888 r.state = BroadcastRecord.IDLE;
12889 scheduleBroadcastsLocked();
12890 }
12891 return;
12892 }
12893
12894 // Hard case: need to instantiate the receiver, possibly
12895 // starting its application process to host it.
12896
12897 ResolveInfo info =
12898 (ResolveInfo)nextReceiver;
12899
12900 boolean skip = false;
12901 int perm = checkComponentPermission(info.activityInfo.permission,
12902 r.callingPid, r.callingUid,
12903 info.activityInfo.exported
12904 ? -1 : info.activityInfo.applicationInfo.uid);
12905 if (perm != PackageManager.PERMISSION_GRANTED) {
12906 Log.w(TAG, "Permission Denial: broadcasting "
12907 + r.intent.toString()
12908 + " from " + r.callerPackage + " (pid=" + r.callingPid
12909 + ", uid=" + r.callingUid + ")"
12910 + " requires " + info.activityInfo.permission
12911 + " due to receiver " + info.activityInfo.packageName
12912 + "/" + info.activityInfo.name);
12913 skip = true;
12914 }
12915 if (r.callingUid != Process.SYSTEM_UID &&
12916 r.requiredPermission != null) {
12917 try {
12918 perm = ActivityThread.getPackageManager().
12919 checkPermission(r.requiredPermission,
12920 info.activityInfo.applicationInfo.packageName);
12921 } catch (RemoteException e) {
12922 perm = PackageManager.PERMISSION_DENIED;
12923 }
12924 if (perm != PackageManager.PERMISSION_GRANTED) {
12925 Log.w(TAG, "Permission Denial: receiving "
12926 + r.intent + " to "
12927 + info.activityInfo.applicationInfo.packageName
12928 + " requires " + r.requiredPermission
12929 + " due to sender " + r.callerPackage
12930 + " (uid " + r.callingUid + ")");
12931 skip = true;
12932 }
12933 }
12934 if (r.curApp != null && r.curApp.crashing) {
12935 // If the target process is crashing, just skip it.
12936 skip = true;
12937 }
12938
12939 if (skip) {
12940 r.receiver = null;
12941 r.curFilter = null;
12942 r.state = BroadcastRecord.IDLE;
12943 scheduleBroadcastsLocked();
12944 return;
12945 }
12946
12947 r.state = BroadcastRecord.APP_RECEIVE;
12948 String targetProcess = info.activityInfo.processName;
12949 r.curComponent = new ComponentName(
12950 info.activityInfo.applicationInfo.packageName,
12951 info.activityInfo.name);
12952 r.curReceiver = info.activityInfo;
12953
12954 // Is this receiver's application already running?
12955 ProcessRecord app = getProcessRecordLocked(targetProcess,
12956 info.activityInfo.applicationInfo.uid);
12957 if (app != null && app.thread != null) {
12958 try {
12959 processCurBroadcastLocked(r, app);
12960 return;
12961 } catch (RemoteException e) {
12962 Log.w(TAG, "Exception when sending broadcast to "
12963 + r.curComponent, e);
12964 }
12965
12966 // If a dead object exception was thrown -- fall through to
12967 // restart the application.
12968 }
12969
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012970 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012971 if ((r.curApp=startProcessLocked(targetProcess,
12972 info.activityInfo.applicationInfo, true,
12973 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012974 "broadcast", r.curComponent,
12975 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12976 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012977 // Ah, this recipient is unavailable. Finish it if necessary,
12978 // and mark the broadcast record as ready for the next.
12979 Log.w(TAG, "Unable to launch app "
12980 + info.activityInfo.applicationInfo.packageName + "/"
12981 + info.activityInfo.applicationInfo.uid + " for broadcast "
12982 + r.intent + ": process is bad");
12983 logBroadcastReceiverDiscard(r);
12984 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12985 r.resultExtras, r.resultAbort, true);
12986 scheduleBroadcastsLocked();
12987 r.state = BroadcastRecord.IDLE;
12988 return;
12989 }
12990
12991 mPendingBroadcast = r;
12992 }
12993 }
12994
12995 // =========================================================
12996 // INSTRUMENTATION
12997 // =========================================================
12998
12999 public boolean startInstrumentation(ComponentName className,
13000 String profileFile, int flags, Bundle arguments,
13001 IInstrumentationWatcher watcher) {
13002 // Refuse possible leaked file descriptors
13003 if (arguments != null && arguments.hasFileDescriptors()) {
13004 throw new IllegalArgumentException("File descriptors passed in Bundle");
13005 }
13006
13007 synchronized(this) {
13008 InstrumentationInfo ii = null;
13009 ApplicationInfo ai = null;
13010 try {
13011 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070013012 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013013 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070013014 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013015 } catch (PackageManager.NameNotFoundException e) {
13016 }
13017 if (ii == null) {
13018 reportStartInstrumentationFailure(watcher, className,
13019 "Unable to find instrumentation info for: " + className);
13020 return false;
13021 }
13022 if (ai == null) {
13023 reportStartInstrumentationFailure(watcher, className,
13024 "Unable to find instrumentation target package: " + ii.targetPackage);
13025 return false;
13026 }
13027
13028 int match = mContext.getPackageManager().checkSignatures(
13029 ii.targetPackage, ii.packageName);
13030 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
13031 String msg = "Permission Denial: starting instrumentation "
13032 + className + " from pid="
13033 + Binder.getCallingPid()
13034 + ", uid=" + Binder.getCallingPid()
13035 + " not allowed because package " + ii.packageName
13036 + " does not have a signature matching the target "
13037 + ii.targetPackage;
13038 reportStartInstrumentationFailure(watcher, className, msg);
13039 throw new SecurityException(msg);
13040 }
13041
13042 final long origId = Binder.clearCallingIdentity();
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080013043 forceStopPackageLocked(ii.targetPackage, -1, true, false, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013044 ProcessRecord app = addAppLocked(ai);
13045 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070013046 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013047 app.instrumentationProfileFile = profileFile;
13048 app.instrumentationArguments = arguments;
13049 app.instrumentationWatcher = watcher;
13050 app.instrumentationResultClass = className;
13051 Binder.restoreCallingIdentity(origId);
13052 }
13053
13054 return true;
13055 }
13056
13057 /**
13058 * Report errors that occur while attempting to start Instrumentation. Always writes the
13059 * error to the logs, but if somebody is watching, send the report there too. This enables
13060 * the "am" command to report errors with more information.
13061 *
13062 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
13063 * @param cn The component name of the instrumentation.
13064 * @param report The error report.
13065 */
13066 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
13067 ComponentName cn, String report) {
13068 Log.w(TAG, report);
13069 try {
13070 if (watcher != null) {
13071 Bundle results = new Bundle();
13072 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
13073 results.putString("Error", report);
13074 watcher.instrumentationStatus(cn, -1, results);
13075 }
13076 } catch (RemoteException e) {
13077 Log.w(TAG, e);
13078 }
13079 }
13080
13081 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
13082 if (app.instrumentationWatcher != null) {
13083 try {
13084 // NOTE: IInstrumentationWatcher *must* be oneway here
13085 app.instrumentationWatcher.instrumentationFinished(
13086 app.instrumentationClass,
13087 resultCode,
13088 results);
13089 } catch (RemoteException e) {
13090 }
13091 }
13092 app.instrumentationWatcher = null;
13093 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070013094 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013095 app.instrumentationProfileFile = null;
13096 app.instrumentationArguments = null;
13097
Dianne Hackborn21f1bd12010-02-19 17:02:21 -080013098 forceStopPackageLocked(app.processName, -1, false, false, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013099 }
13100
13101 public void finishInstrumentation(IApplicationThread target,
13102 int resultCode, Bundle results) {
13103 // Refuse possible leaked file descriptors
13104 if (results != null && results.hasFileDescriptors()) {
13105 throw new IllegalArgumentException("File descriptors passed in Intent");
13106 }
13107
13108 synchronized(this) {
13109 ProcessRecord app = getRecordForAppLocked(target);
13110 if (app == null) {
13111 Log.w(TAG, "finishInstrumentation: no app for " + target);
13112 return;
13113 }
13114 final long origId = Binder.clearCallingIdentity();
13115 finishInstrumentationLocked(app, resultCode, results);
13116 Binder.restoreCallingIdentity(origId);
13117 }
13118 }
13119
13120 // =========================================================
13121 // CONFIGURATION
13122 // =========================================================
13123
13124 public ConfigurationInfo getDeviceConfigurationInfo() {
13125 ConfigurationInfo config = new ConfigurationInfo();
13126 synchronized (this) {
13127 config.reqTouchScreen = mConfiguration.touchscreen;
13128 config.reqKeyboardType = mConfiguration.keyboard;
13129 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070013130 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
13131 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013132 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
13133 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070013134 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
13135 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013136 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
13137 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070013138 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013139 }
13140 return config;
13141 }
13142
13143 public Configuration getConfiguration() {
13144 Configuration ci;
13145 synchronized(this) {
13146 ci = new Configuration(mConfiguration);
13147 }
13148 return ci;
13149 }
13150
13151 public void updateConfiguration(Configuration values) {
13152 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
13153 "updateConfiguration()");
13154
13155 synchronized(this) {
13156 if (values == null && mWindowManager != null) {
13157 // sentinel: fetch the current configuration from the window manager
13158 values = mWindowManager.computeNewConfiguration();
13159 }
13160
13161 final long origId = Binder.clearCallingIdentity();
13162 updateConfigurationLocked(values, null);
13163 Binder.restoreCallingIdentity(origId);
13164 }
13165 }
13166
13167 /**
13168 * Do either or both things: (1) change the current configuration, and (2)
13169 * make sure the given activity is running with the (now) current
13170 * configuration. Returns true if the activity has been left running, or
13171 * false if <var>starting</var> is being destroyed to match the new
13172 * configuration.
13173 */
13174 public boolean updateConfigurationLocked(Configuration values,
13175 HistoryRecord starting) {
13176 int changes = 0;
13177
13178 boolean kept = true;
13179
13180 if (values != null) {
13181 Configuration newConfig = new Configuration(mConfiguration);
13182 changes = newConfig.updateFrom(values);
13183 if (changes != 0) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013184 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013185 Log.i(TAG, "Updating configuration to: " + values);
13186 }
13187
Doug Zongker2bec3d42009-12-04 12:52:44 -080013188 EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013189
13190 if (values.locale != null) {
13191 saveLocaleLocked(values.locale,
13192 !values.locale.equals(mConfiguration.locale),
13193 values.userSetLocale);
13194 }
13195
Dianne Hackborne36d6e22010-02-17 19:46:25 -080013196 mConfigurationSeq++;
13197 if (mConfigurationSeq <= 0) {
13198 mConfigurationSeq = 1;
13199 }
13200 newConfig.seq = mConfigurationSeq;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013201 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070013202 Log.i(TAG, "Config changed: " + newConfig);
Dianne Hackborn826d17c2009-11-12 12:55:51 -080013203
13204 AttributeCache ac = AttributeCache.instance();
13205 if (ac != null) {
13206 ac.updateConfiguration(mConfiguration);
13207 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013208
13209 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
13210 msg.obj = new Configuration(mConfiguration);
13211 mHandler.sendMessage(msg);
13212
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013213 for (int i=mLruProcesses.size()-1; i>=0; i--) {
13214 ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013215 try {
13216 if (app.thread != null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013217 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending to proc "
13218 + app.processName + " new config " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013219 app.thread.scheduleConfigurationChanged(mConfiguration);
13220 }
13221 } catch (Exception e) {
13222 }
13223 }
13224 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -080013225 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
13226 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013227 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
13228 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackborn362d5b92009-11-11 18:04:39 -080013229 if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
13230 broadcastIntentLocked(null, null,
13231 new Intent(Intent.ACTION_LOCALE_CHANGED),
13232 null, null, 0, null, null,
13233 null, false, false, MY_PID, Process.SYSTEM_UID);
13234 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013235 }
13236 }
13237
13238 if (changes != 0 && starting == null) {
13239 // If the configuration changed, and the caller is not already
13240 // in the process of starting an activity, then find the top
13241 // activity to check if its configuration needs to change.
13242 starting = topRunningActivityLocked(null);
13243 }
13244
13245 if (starting != null) {
13246 kept = ensureActivityConfigurationLocked(starting, changes);
13247 if (kept) {
13248 // If this didn't result in the starting activity being
13249 // destroyed, then we need to make sure at this point that all
13250 // other activities are made visible.
13251 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
13252 + ", ensuring others are correct.");
13253 ensureActivitiesVisibleLocked(starting, changes);
13254 }
13255 }
13256
Dianne Hackborne36d6e22010-02-17 19:46:25 -080013257 if (values != null && mWindowManager != null) {
13258 mWindowManager.setNewConfiguration(mConfiguration);
13259 }
13260
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013261 return kept;
13262 }
13263
13264 private final boolean relaunchActivityLocked(HistoryRecord r,
13265 int changes, boolean andResume) {
13266 List<ResultInfo> results = null;
13267 List<Intent> newIntents = null;
13268 if (andResume) {
13269 results = r.results;
13270 newIntents = r.newIntents;
13271 }
13272 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
13273 + " with results=" + results + " newIntents=" + newIntents
13274 + " andResume=" + andResume);
Doug Zongker2bec3d42009-12-04 12:52:44 -080013275 EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
13276 : EventLogTags.AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013277 r.task.taskId, r.shortComponentName);
13278
13279 r.startFreezingScreenLocked(r.app, 0);
13280
13281 try {
13282 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
13283 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
Dianne Hackborn871ecdc2009-12-11 15:24:33 -080013284 changes, !andResume, mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013285 // Note: don't need to call pauseIfSleepingLocked() here, because
13286 // the caller will only pass in 'andResume' if this activity is
13287 // currently resumed, which implies we aren't sleeping.
13288 } catch (RemoteException e) {
13289 return false;
13290 }
13291
13292 if (andResume) {
13293 r.results = null;
13294 r.newIntents = null;
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -070013295 reportResumedActivityLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013296 }
13297
13298 return true;
13299 }
13300
13301 /**
13302 * Make sure the given activity matches the current configuration. Returns
13303 * false if the activity had to be destroyed. Returns true if the
13304 * configuration is the same, or the activity will remain running as-is
13305 * for whatever reason. Ensures the HistoryRecord is updated with the
13306 * correct configuration and all other bookkeeping is handled.
13307 */
13308 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
13309 int globalChanges) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013310 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13311 "Ensuring correct configuration: " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013312
13313 // Short circuit: if the two configurations are the exact same
13314 // object (the common case), then there is nothing to do.
13315 Configuration newConfig = mConfiguration;
13316 if (r.configuration == newConfig) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013317 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13318 "Configuration unchanged in " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013319 return true;
13320 }
13321
13322 // We don't worry about activities that are finishing.
13323 if (r.finishing) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013324 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013325 "Configuration doesn't matter in finishing " + r);
13326 r.stopFreezingScreenLocked(false);
13327 return true;
13328 }
13329
13330 // Okay we now are going to make this activity have the new config.
13331 // But then we need to figure out how it needs to deal with that.
13332 Configuration oldConfig = r.configuration;
13333 r.configuration = newConfig;
13334
13335 // If the activity isn't currently running, just leave the new
13336 // configuration and it will pick that up next time it starts.
13337 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013338 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013339 "Configuration doesn't matter not running " + r);
13340 r.stopFreezingScreenLocked(false);
13341 return true;
13342 }
13343
13344 // If the activity isn't persistent, there is a chance we will
13345 // need to restart it.
13346 if (!r.persistent) {
13347
13348 // Figure out what has changed between the two configurations.
13349 int changes = oldConfig.diff(newConfig);
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013350 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
13351 Log.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013352 + Integer.toHexString(changes) + ", handles=0x"
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013353 + Integer.toHexString(r.info.configChanges)
13354 + ", newConfig=" + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013355 }
13356 if ((changes&(~r.info.configChanges)) != 0) {
13357 // Aha, the activity isn't handling the change, so DIE DIE DIE.
13358 r.configChangeFlags |= changes;
13359 r.startFreezingScreenLocked(r.app, globalChanges);
13360 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013361 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13362 "Switch is destroying non-running " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013363 destroyActivityLocked(r, true);
13364 } else if (r.state == ActivityState.PAUSING) {
13365 // A little annoying: we are waiting for this activity to
13366 // finish pausing. Let's not do anything now, but just
13367 // flag that it needs to be restarted when done pausing.
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013368 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13369 "Switch is skipping already pausing " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013370 r.configDestroy = true;
13371 return true;
13372 } else if (r.state == ActivityState.RESUMED) {
13373 // Try to optimize this case: the configuration is changing
13374 // and we need to restart the top, resumed activity.
13375 // Instead of doing the normal handshaking, just say
13376 // "restart!".
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013377 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13378 "Switch is restarting resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013379 relaunchActivityLocked(r, r.configChangeFlags, true);
13380 r.configChangeFlags = 0;
13381 } else {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013382 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
13383 "Switch is restarting non-resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013384 relaunchActivityLocked(r, r.configChangeFlags, false);
13385 r.configChangeFlags = 0;
13386 }
13387
13388 // All done... tell the caller we weren't able to keep this
13389 // activity around.
13390 return false;
13391 }
13392 }
13393
13394 // Default case: the activity can handle this new configuration, so
13395 // hand it over. Note that we don't need to give it the new
13396 // configuration, since we always send configuration changes to all
13397 // process when they happen so it can just use whatever configuration
13398 // it last got.
13399 if (r.app != null && r.app.thread != null) {
13400 try {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013401 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending new config to " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013402 r.app.thread.scheduleActivityConfigurationChanged(r);
13403 } catch (RemoteException e) {
13404 // If process died, whatever.
13405 }
13406 }
13407 r.stopFreezingScreenLocked(false);
13408
13409 return true;
13410 }
13411
13412 /**
13413 * Save the locale. You must be inside a synchronized (this) block.
13414 */
13415 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
13416 if(isDiff) {
13417 SystemProperties.set("user.language", l.getLanguage());
13418 SystemProperties.set("user.region", l.getCountry());
13419 }
13420
13421 if(isPersist) {
13422 SystemProperties.set("persist.sys.language", l.getLanguage());
13423 SystemProperties.set("persist.sys.country", l.getCountry());
13424 SystemProperties.set("persist.sys.localevar", l.getVariant());
13425 }
13426 }
13427
13428 // =========================================================
13429 // LIFETIME MANAGEMENT
13430 // =========================================================
13431
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013432 private final int computeOomAdjLocked(ProcessRecord app, int hiddenAdj,
13433 ProcessRecord TOP_APP, boolean recursed) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013434 if (mAdjSeq == app.adjSeq) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013435 // This adjustment has already been computed. If we are calling
13436 // from the top, we may have already computed our adjustment with
13437 // an earlier hidden adjustment that isn't really for us... if
13438 // so, use the new hidden adjustment.
13439 if (!recursed && app.hidden) {
13440 app.curAdj = hiddenAdj;
13441 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013442 return app.curAdj;
13443 }
13444
13445 if (app.thread == null) {
13446 app.adjSeq = mAdjSeq;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013447 app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013448 return (app.curAdj=EMPTY_APP_ADJ);
13449 }
13450
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013451 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
13452 // The max adjustment doesn't allow this app to be anything
13453 // below foreground, so it is not worth doing work for it.
13454 app.adjType = "fixed";
13455 app.adjSeq = mAdjSeq;
13456 app.curRawAdj = app.maxAdj;
13457 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
13458 return (app.curAdj=app.maxAdj);
13459 }
13460
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013461 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013462 app.adjSource = null;
13463 app.adjTarget = null;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013464 app.empty = false;
13465 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013466
The Android Open Source Project4df24232009-03-05 14:34:35 -080013467 // Determine the importance of the process, starting with most
13468 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013469 int adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013470 int schedGroup;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013471 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013472 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013473 // The last app on the list is the foreground app.
13474 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013475 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013476 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013477 } else if (app.instrumentationClass != null) {
13478 // Don't want to kill running instrumentation.
13479 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013480 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013481 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013482 } else if (app.persistentActivities > 0) {
13483 // Special persistent activities... shouldn't be used these days.
13484 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013485 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013486 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013487 } else if (app.curReceiver != null ||
13488 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
13489 // An app that is currently receiving a broadcast also
13490 // counts as being in the foreground.
13491 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013492 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013493 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013494 } else if (app.executingServices.size() > 0) {
13495 // An app that is currently executing a service callback also
13496 // counts as being in the foreground.
13497 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013498 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013499 app.adjType = "exec-service";
13500 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013501 // The user is aware of this app, so make it visible.
13502 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013503 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013504 app.adjType = "foreground-service";
13505 } else if (app.forcingToForeground != null) {
13506 // The user is aware of this app, so make it visible.
13507 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013508 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013509 app.adjType = "force-foreground";
13510 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080013511 } else if (app == mHomeProcess) {
13512 // This process is hosting what we currently consider to be the
13513 // home app, so we don't want to let it go into the background.
13514 adj = HOME_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013515 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013516 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013517 } else if ((N=app.activities.size()) != 0) {
13518 // This app is in the background with paused activities.
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013519 app.hidden = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013520 adj = hiddenAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013521 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013522 app.adjType = "bg-activities";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013523 N = app.activities.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013524 for (int j=0; j<N; j++) {
13525 if (((HistoryRecord)app.activities.get(j)).visible) {
13526 // This app has a visible activity!
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013527 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013528 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013529 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013530 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013531 break;
13532 }
13533 }
13534 } else {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013535 // A very not-needed process. If this is lower in the lru list,
13536 // we will push it in to the empty bucket.
13537 app.hidden = true;
13538 app.empty = true;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013539 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013540 adj = hiddenAdj;
13541 app.adjType = "bg-empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013542 }
13543
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013544 //Log.i(TAG, "OOM " + app + ": initial adj=" + adj);
13545
The Android Open Source Project4df24232009-03-05 14:34:35 -080013546 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013547 // there are applications dependent on our services or providers, but
13548 // this gives us a baseline and makes sure we don't get into an
13549 // infinite recursion.
13550 app.adjSeq = mAdjSeq;
13551 app.curRawAdj = adj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013552
Christopher Tate6fa95972009-06-05 18:43:55 -070013553 if (mBackupTarget != null && app == mBackupTarget.app) {
13554 // If possible we want to avoid killing apps while they're being backed up
13555 if (adj > BACKUP_APP_ADJ) {
13556 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
13557 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013558 app.adjType = "backup";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013559 app.hidden = false;
Christopher Tate6fa95972009-06-05 18:43:55 -070013560 }
13561 }
13562
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013563 if (app.services.size() != 0 && (adj > FOREGROUND_APP_ADJ
13564 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013565 final long now = SystemClock.uptimeMillis();
13566 // This process is more important if the top activity is
13567 // bound to the service.
13568 Iterator jt = app.services.iterator();
13569 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13570 ServiceRecord s = (ServiceRecord)jt.next();
13571 if (s.startRequested) {
13572 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
13573 // This service has seen some activity within
13574 // recent memory, so we will keep its process ahead
13575 // of the background processes.
13576 if (adj > SECONDARY_SERVER_ADJ) {
13577 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013578 app.adjType = "started-services";
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013579 app.hidden = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013580 }
13581 }
Dianne Hackborn5ce7d282010-02-12 19:30:02 -080013582 // If we have let the service slide into the background
13583 // state, still have some text describing what it is doing
13584 // even though the service no longer has an impact.
13585 if (adj > SECONDARY_SERVER_ADJ) {
13586 app.adjType = "started-bg-services";
13587 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013588 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013589 if (s.connections.size() > 0 && (adj > FOREGROUND_APP_ADJ
13590 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013591 Iterator<ConnectionRecord> kt
13592 = s.connections.values().iterator();
13593 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13594 // XXX should compute this based on the max of
13595 // all connected clients.
13596 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013597 if (cr.binding.client == app) {
13598 // Binding to ourself is not interesting.
13599 continue;
13600 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013601 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
13602 ProcessRecord client = cr.binding.client;
13603 int myHiddenAdj = hiddenAdj;
13604 if (myHiddenAdj > client.hiddenAdj) {
13605 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
13606 myHiddenAdj = client.hiddenAdj;
13607 } else {
13608 myHiddenAdj = VISIBLE_APP_ADJ;
13609 }
13610 }
13611 int clientAdj = computeOomAdjLocked(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013612 client, myHiddenAdj, TOP_APP, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013613 if (adj > clientAdj) {
13614 adj = clientAdj > VISIBLE_APP_ADJ
13615 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013616 if (!client.hidden) {
13617 app.hidden = false;
13618 }
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013619 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013620 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13621 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013622 app.adjSource = cr.binding.client;
13623 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013624 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013625 if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
13626 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13627 schedGroup = Process.THREAD_GROUP_DEFAULT;
13628 }
13629 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013630 }
13631 HistoryRecord a = cr.activity;
13632 //if (a != null) {
13633 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13634 //}
13635 if (a != null && adj > FOREGROUND_APP_ADJ &&
13636 (a.state == ActivityState.RESUMED
13637 || a.state == ActivityState.PAUSING)) {
13638 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013639 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013640 app.hidden = false;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013641 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013642 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13643 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013644 app.adjSource = a;
13645 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013646 }
13647 }
13648 }
13649 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013650
13651 // Finally, f this process has active services running in it, we
13652 // would like to avoid killing it unless it would prevent the current
13653 // application from running. By default we put the process in
13654 // with the rest of the background processes; as we scan through
13655 // its services we may bump it up from there.
13656 if (adj > hiddenAdj) {
13657 adj = hiddenAdj;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013658 app.hidden = false;
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013659 app.adjType = "bg-services";
13660 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013661 }
13662
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013663 if (app.pubProviders.size() != 0 && (adj > FOREGROUND_APP_ADJ
13664 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013665 Iterator jt = app.pubProviders.values().iterator();
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013666 while (jt.hasNext() && (adj > FOREGROUND_APP_ADJ
13667 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013668 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13669 if (cpr.clients.size() != 0) {
13670 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13671 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13672 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013673 if (client == app) {
13674 // Being our own client is not interesting.
13675 continue;
13676 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013677 int myHiddenAdj = hiddenAdj;
13678 if (myHiddenAdj > client.hiddenAdj) {
13679 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13680 myHiddenAdj = client.hiddenAdj;
13681 } else {
13682 myHiddenAdj = FOREGROUND_APP_ADJ;
13683 }
13684 }
13685 int clientAdj = computeOomAdjLocked(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013686 client, myHiddenAdj, TOP_APP, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013687 if (adj > clientAdj) {
13688 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013689 ? clientAdj : FOREGROUND_APP_ADJ;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013690 if (!client.hidden) {
13691 app.hidden = false;
13692 }
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013693 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013694 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13695 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013696 app.adjSource = client;
13697 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013698 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013699 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13700 schedGroup = Process.THREAD_GROUP_DEFAULT;
13701 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013702 }
13703 }
13704 // If the provider has external (non-framework) process
13705 // dependencies, ensure that its adjustment is at least
13706 // FOREGROUND_APP_ADJ.
13707 if (cpr.externals != 0) {
13708 if (adj > FOREGROUND_APP_ADJ) {
13709 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013710 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013711 app.hidden = false;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013712 app.adjType = "provider";
13713 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013714 }
13715 }
13716 }
13717 }
13718
13719 app.curRawAdj = adj;
13720
13721 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13722 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13723 if (adj > app.maxAdj) {
13724 adj = app.maxAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013725 if (app.maxAdj <= VISIBLE_APP_ADJ) {
13726 schedGroup = Process.THREAD_GROUP_DEFAULT;
13727 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013728 }
13729
13730 app.curAdj = adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013731 app.curSchedGroup = schedGroup;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013732
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013733 return adj;
13734 }
13735
13736 /**
13737 * Ask a given process to GC right now.
13738 */
13739 final void performAppGcLocked(ProcessRecord app) {
13740 try {
13741 app.lastRequestedGc = SystemClock.uptimeMillis();
13742 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013743 if (app.reportLowMemory) {
13744 app.reportLowMemory = false;
13745 app.thread.scheduleLowMemory();
13746 } else {
13747 app.thread.processInBackground();
13748 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013749 }
13750 } catch (Exception e) {
13751 // whatever.
13752 }
13753 }
13754
13755 /**
13756 * Returns true if things are idle enough to perform GCs.
13757 */
13758 private final boolean canGcNow() {
13759 return mParallelBroadcasts.size() == 0
13760 && mOrderedBroadcasts.size() == 0
13761 && (mSleeping || (mResumedActivity != null &&
13762 mResumedActivity.idle));
13763 }
13764
13765 /**
13766 * Perform GCs on all processes that are waiting for it, but only
13767 * if things are idle.
13768 */
13769 final void performAppGcsLocked() {
13770 final int N = mProcessesToGc.size();
13771 if (N <= 0) {
13772 return;
13773 }
13774 if (canGcNow()) {
13775 while (mProcessesToGc.size() > 0) {
13776 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013777 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13778 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13779 <= SystemClock.uptimeMillis()) {
13780 // To avoid spamming the system, we will GC processes one
13781 // at a time, waiting a few seconds between each.
13782 performAppGcLocked(proc);
13783 scheduleAppGcsLocked();
13784 return;
13785 } else {
13786 // It hasn't been long enough since we last GCed this
13787 // process... put it in the list to wait for its time.
13788 addProcessToGcListLocked(proc);
13789 break;
13790 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013791 }
13792 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013793
13794 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013795 }
13796 }
13797
13798 /**
13799 * If all looks good, perform GCs on all processes waiting for them.
13800 */
13801 final void performAppGcsIfAppropriateLocked() {
13802 if (canGcNow()) {
13803 performAppGcsLocked();
13804 return;
13805 }
13806 // Still not idle, wait some more.
13807 scheduleAppGcsLocked();
13808 }
13809
13810 /**
13811 * Schedule the execution of all pending app GCs.
13812 */
13813 final void scheduleAppGcsLocked() {
13814 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013815
13816 if (mProcessesToGc.size() > 0) {
13817 // Schedule a GC for the time to the next process.
13818 ProcessRecord proc = mProcessesToGc.get(0);
13819 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13820
13821 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13822 long now = SystemClock.uptimeMillis();
13823 if (when < (now+GC_TIMEOUT)) {
13824 when = now + GC_TIMEOUT;
13825 }
13826 mHandler.sendMessageAtTime(msg, when);
13827 }
13828 }
13829
13830 /**
13831 * Add a process to the array of processes waiting to be GCed. Keeps the
13832 * list in sorted order by the last GC time. The process can't already be
13833 * on the list.
13834 */
13835 final void addProcessToGcListLocked(ProcessRecord proc) {
13836 boolean added = false;
13837 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13838 if (mProcessesToGc.get(i).lastRequestedGc <
13839 proc.lastRequestedGc) {
13840 added = true;
13841 mProcessesToGc.add(i+1, proc);
13842 break;
13843 }
13844 }
13845 if (!added) {
13846 mProcessesToGc.add(0, proc);
13847 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013848 }
13849
13850 /**
13851 * Set up to ask a process to GC itself. This will either do it
13852 * immediately, or put it on the list of processes to gc the next
13853 * time things are idle.
13854 */
13855 final void scheduleAppGcLocked(ProcessRecord app) {
13856 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013857 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013858 return;
13859 }
13860 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013861 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013862 scheduleAppGcsLocked();
13863 }
13864 }
13865
13866 private final boolean updateOomAdjLocked(
13867 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13868 app.hiddenAdj = hiddenAdj;
13869
13870 if (app.thread == null) {
13871 return true;
13872 }
13873
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013874 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013875
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013876 if ((app.pid != 0 && app.pid != MY_PID) || Process.supportsProcesses()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013877 if (app.curRawAdj != app.setRawAdj) {
13878 if (app.curRawAdj > FOREGROUND_APP_ADJ
13879 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13880 // If this app is transitioning from foreground to
13881 // non-foreground, have it do a gc.
13882 scheduleAppGcLocked(app);
13883 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13884 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13885 // Likewise do a gc when an app is moving in to the
13886 // background (such as a service stopping).
13887 scheduleAppGcLocked(app);
13888 }
13889 app.setRawAdj = app.curRawAdj;
13890 }
13891 if (adj != app.setAdj) {
13892 if (Process.setOomAdj(app.pid, adj)) {
13893 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13894 TAG, "Set app " + app.processName +
13895 " oom adj to " + adj);
13896 app.setAdj = adj;
13897 } else {
13898 return false;
13899 }
13900 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013901 if (app.setSchedGroup != app.curSchedGroup) {
13902 app.setSchedGroup = app.curSchedGroup;
13903 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13904 "Setting process group of " + app.processName
13905 + " to " + app.curSchedGroup);
13906 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013907 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013908 try {
13909 Process.setProcessGroup(app.pid, app.curSchedGroup);
13910 } catch (Exception e) {
13911 Log.w(TAG, "Failed setting process group of " + app.pid
13912 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013913 e.printStackTrace();
13914 } finally {
13915 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013916 }
13917 }
13918 if (false) {
13919 if (app.thread != null) {
13920 try {
13921 app.thread.setSchedulingGroup(app.curSchedGroup);
13922 } catch (RemoteException e) {
13923 }
13924 }
13925 }
13926 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013927 }
13928
13929 return true;
13930 }
13931
13932 private final HistoryRecord resumedAppLocked() {
13933 HistoryRecord resumedActivity = mResumedActivity;
13934 if (resumedActivity == null || resumedActivity.app == null) {
13935 resumedActivity = mPausingActivity;
13936 if (resumedActivity == null || resumedActivity.app == null) {
13937 resumedActivity = topRunningActivityLocked(null);
13938 }
13939 }
13940 return resumedActivity;
13941 }
13942
13943 private final boolean updateOomAdjLocked(ProcessRecord app) {
13944 final HistoryRecord TOP_ACT = resumedAppLocked();
13945 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13946 int curAdj = app.curAdj;
13947 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13948 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13949
13950 mAdjSeq++;
13951
13952 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13953 if (res) {
13954 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13955 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13956 if (nowHidden != wasHidden) {
13957 // Changed to/from hidden state, so apps after it in the LRU
13958 // list may also be changed.
13959 updateOomAdjLocked();
13960 }
13961 }
13962 return res;
13963 }
13964
13965 private final boolean updateOomAdjLocked() {
13966 boolean didOomAdj = true;
13967 final HistoryRecord TOP_ACT = resumedAppLocked();
13968 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13969
13970 if (false) {
13971 RuntimeException e = new RuntimeException();
13972 e.fillInStackTrace();
13973 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13974 }
13975
13976 mAdjSeq++;
13977
Dianne Hackborn5ce7d282010-02-12 19:30:02 -080013978 // Let's determine how many processes we have running vs.
13979 // how many slots we have for background processes; we may want
13980 // to put multiple processes in a slot of there are enough of
13981 // them.
13982 int numSlots = HIDDEN_APP_MAX_ADJ - HIDDEN_APP_MIN_ADJ + 1;
13983 int factor = (mLruProcesses.size()-4)/numSlots;
13984 if (factor < 1) factor = 1;
13985 int step = 0;
13986
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013987 // First try updating the OOM adjustment for each of the
13988 // application processes based on their current state.
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013989 int i = mLruProcesses.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013990 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13991 while (i > 0) {
13992 i--;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013993 ProcessRecord app = mLruProcesses.get(i);
13994 //Log.i(TAG, "OOM " + app + ": cur hidden=" + curHiddenAdj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013995 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080013996 if (curHiddenAdj < EMPTY_APP_ADJ
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013997 && app.curAdj == curHiddenAdj) {
Dianne Hackborn5ce7d282010-02-12 19:30:02 -080013998 step++;
13999 if (step >= factor) {
14000 step = 0;
14001 curHiddenAdj++;
14002 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014003 }
14004 } else {
14005 didOomAdj = false;
14006 }
14007 }
14008
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014009 // If we return false, we will fall back on killing processes to
14010 // have a fixed limit. Do this if a limit has been requested; else
14011 // only return false if one of the adjustments failed.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014012 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
14013 }
14014
14015 private final void trimApplications() {
14016 synchronized (this) {
14017 int i;
14018
14019 // First remove any unused application processes whose package
14020 // has been removed.
14021 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
14022 final ProcessRecord app = mRemovedProcesses.get(i);
14023 if (app.activities.size() == 0
14024 && app.curReceiver == null && app.services.size() == 0) {
14025 Log.i(
14026 TAG, "Exiting empty application process "
14027 + app.processName + " ("
14028 + (app.thread != null ? app.thread.asBinder() : null)
14029 + ")\n");
14030 if (app.pid > 0 && app.pid != MY_PID) {
14031 Process.killProcess(app.pid);
14032 } else {
14033 try {
14034 app.thread.scheduleExit();
14035 } catch (Exception e) {
14036 // Ignore exceptions.
14037 }
14038 }
14039 cleanUpApplicationRecordLocked(app, false, -1);
14040 mRemovedProcesses.remove(i);
14041
14042 if (app.persistent) {
14043 if (app.persistent) {
14044 addAppLocked(app.info);
14045 }
14046 }
14047 }
14048 }
14049
14050 // Now try updating the OOM adjustment for each of the
14051 // application processes based on their current state.
14052 // If the setOomAdj() API is not supported, then go with our
14053 // back-up plan...
14054 if (!updateOomAdjLocked()) {
14055
14056 // Count how many processes are running services.
14057 int numServiceProcs = 0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014058 for (i=mLruProcesses.size()-1; i>=0; i--) {
14059 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014060
14061 if (app.persistent || app.services.size() != 0
14062 || app.curReceiver != null
14063 || app.persistentActivities > 0) {
14064 // Don't count processes holding services against our
14065 // maximum process count.
14066 if (localLOGV) Log.v(
14067 TAG, "Not trimming app " + app + " with services: "
14068 + app.services);
14069 numServiceProcs++;
14070 }
14071 }
14072
14073 int curMaxProcs = mProcessLimit;
14074 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
14075 if (mAlwaysFinishActivities) {
14076 curMaxProcs = 1;
14077 }
14078 curMaxProcs += numServiceProcs;
14079
14080 // Quit as many processes as we can to get down to the desired
14081 // process count. First remove any processes that no longer
14082 // have activites running in them.
14083 for ( i=0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014084 i<mLruProcesses.size()
14085 && mLruProcesses.size() > curMaxProcs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014086 i++) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014087 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014088 // Quit an application only if it is not currently
14089 // running any activities.
14090 if (!app.persistent && app.activities.size() == 0
14091 && app.curReceiver == null && app.services.size() == 0) {
14092 Log.i(
14093 TAG, "Exiting empty application process "
14094 + app.processName + " ("
14095 + (app.thread != null ? app.thread.asBinder() : null)
14096 + ")\n");
14097 if (app.pid > 0 && app.pid != MY_PID) {
14098 Process.killProcess(app.pid);
14099 } else {
14100 try {
14101 app.thread.scheduleExit();
14102 } catch (Exception e) {
14103 // Ignore exceptions.
14104 }
14105 }
14106 // todo: For now we assume the application is not buggy
14107 // or evil, and will quit as a result of our request.
14108 // Eventually we need to drive this off of the death
14109 // notification, and kill the process if it takes too long.
14110 cleanUpApplicationRecordLocked(app, false, i);
14111 i--;
14112 }
14113 }
14114
14115 // If we still have too many processes, now from the least
14116 // recently used process we start finishing activities.
14117 if (Config.LOGV) Log.v(
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014118 TAG, "*** NOW HAVE " + mLruProcesses.size() +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014119 " of " + curMaxProcs + " processes");
14120 for ( i=0;
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014121 i<mLruProcesses.size()
14122 && mLruProcesses.size() > curMaxProcs;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014123 i++) {
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014124 final ProcessRecord app = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014125 // Quit the application only if we have a state saved for
14126 // all of its activities.
14127 boolean canQuit = !app.persistent && app.curReceiver == null
14128 && app.services.size() == 0
14129 && app.persistentActivities == 0;
14130 int NUMA = app.activities.size();
14131 int j;
14132 if (Config.LOGV) Log.v(
14133 TAG, "Looking to quit " + app.processName);
14134 for (j=0; j<NUMA && canQuit; j++) {
14135 HistoryRecord r = (HistoryRecord)app.activities.get(j);
14136 if (Config.LOGV) Log.v(
14137 TAG, " " + r.intent.getComponent().flattenToShortString()
14138 + ": frozen=" + r.haveState + ", visible=" + r.visible);
14139 canQuit = (r.haveState || !r.stateNotNeeded)
14140 && !r.visible && r.stopped;
14141 }
14142 if (canQuit) {
14143 // Finish all of the activities, and then the app itself.
14144 for (j=0; j<NUMA; j++) {
14145 HistoryRecord r = (HistoryRecord)app.activities.get(j);
14146 if (!r.finishing) {
14147 destroyActivityLocked(r, false);
14148 }
14149 r.resultTo = null;
14150 }
14151 Log.i(TAG, "Exiting application process "
14152 + app.processName + " ("
14153 + (app.thread != null ? app.thread.asBinder() : null)
14154 + ")\n");
14155 if (app.pid > 0 && app.pid != MY_PID) {
14156 Process.killProcess(app.pid);
14157 } else {
14158 try {
14159 app.thread.scheduleExit();
14160 } catch (Exception e) {
14161 // Ignore exceptions.
14162 }
14163 }
14164 // todo: For now we assume the application is not buggy
14165 // or evil, and will quit as a result of our request.
14166 // Eventually we need to drive this off of the death
14167 // notification, and kill the process if it takes too long.
14168 cleanUpApplicationRecordLocked(app, false, i);
14169 i--;
14170 //dump();
14171 }
14172 }
14173
14174 }
14175
14176 int curMaxActivities = MAX_ACTIVITIES;
14177 if (mAlwaysFinishActivities) {
14178 curMaxActivities = 1;
14179 }
14180
14181 // Finally, if there are too many activities now running, try to
14182 // finish as many as we can to get back down to the limit.
14183 for ( i=0;
14184 i<mLRUActivities.size()
14185 && mLRUActivities.size() > curMaxActivities;
14186 i++) {
14187 final HistoryRecord r
14188 = (HistoryRecord)mLRUActivities.get(i);
14189
14190 // We can finish this one if we have its icicle saved and
14191 // it is not persistent.
14192 if ((r.haveState || !r.stateNotNeeded) && !r.visible
14193 && r.stopped && !r.persistent && !r.finishing) {
14194 final int origSize = mLRUActivities.size();
14195 destroyActivityLocked(r, true);
14196
14197 // This will remove it from the LRU list, so keep
14198 // our index at the same value. Note that this check to
14199 // see if the size changes is just paranoia -- if
14200 // something unexpected happens, we don't want to end up
14201 // in an infinite loop.
14202 if (origSize > mLRUActivities.size()) {
14203 i--;
14204 }
14205 }
14206 }
14207 }
14208 }
14209
14210 /** This method sends the specified signal to each of the persistent apps */
14211 public void signalPersistentProcesses(int sig) throws RemoteException {
14212 if (sig != Process.SIGNAL_USR1) {
14213 throw new SecurityException("Only SIGNAL_USR1 is allowed");
14214 }
14215
14216 synchronized (this) {
14217 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
14218 != PackageManager.PERMISSION_GRANTED) {
14219 throw new SecurityException("Requires permission "
14220 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
14221 }
14222
Dianne Hackborndd71fc82009-12-16 19:24:32 -080014223 for (int i = mLruProcesses.size() - 1 ; i >= 0 ; i--) {
14224 ProcessRecord r = mLruProcesses.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014225 if (r.thread != null && r.persistent) {
14226 Process.sendSignal(r.pid, sig);
14227 }
14228 }
14229 }
14230 }
14231
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014232 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014233 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014234
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014235 try {
14236 synchronized (this) {
14237 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
14238 // its own permission.
14239 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
14240 != PackageManager.PERMISSION_GRANTED) {
14241 throw new SecurityException("Requires permission "
14242 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014243 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014244
14245 if (start && fd == null) {
14246 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014247 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014248
14249 ProcessRecord proc = null;
14250 try {
14251 int pid = Integer.parseInt(process);
14252 synchronized (mPidsSelfLocked) {
14253 proc = mPidsSelfLocked.get(pid);
14254 }
14255 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014256 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014257
14258 if (proc == null) {
14259 HashMap<String, SparseArray<ProcessRecord>> all
14260 = mProcessNames.getMap();
14261 SparseArray<ProcessRecord> procs = all.get(process);
14262 if (procs != null && procs.size() > 0) {
14263 proc = procs.valueAt(0);
14264 }
14265 }
14266
14267 if (proc == null || proc.thread == null) {
14268 throw new IllegalArgumentException("Unknown process: " + process);
14269 }
14270
14271 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
14272 if (isSecure) {
14273 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
14274 throw new SecurityException("Process not debuggable: " + proc);
14275 }
14276 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014277
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014278 proc.thread.profilerControl(start, path, fd);
14279 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014280 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070014281 }
14282 } catch (RemoteException e) {
14283 throw new IllegalStateException("Process disappeared");
14284 } finally {
14285 if (fd != null) {
14286 try {
14287 fd.close();
14288 } catch (IOException e) {
14289 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080014290 }
14291 }
14292 }
14293
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080014294 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
14295 public void monitor() {
14296 synchronized (this) { }
14297 }
14298}