blob: d9c7d6fcfcad84f56c7913aaf913c58763569056 [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
28import android.app.Activity;
29import android.app.ActivityManager;
30import android.app.ActivityManagerNative;
31import android.app.ActivityThread;
32import android.app.AlertDialog;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020033import android.app.ApplicationErrorReport;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.app.Dialog;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070035import android.app.IActivityController;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.app.IActivityWatcher;
37import android.app.IApplicationThread;
38import android.app.IInstrumentationWatcher;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.app.IServiceConnection;
40import android.app.IThumbnailReceiver;
41import android.app.Instrumentation;
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070042import android.app.Notification;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043import android.app.PendingIntent;
44import android.app.ResultInfo;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070045import android.app.Service;
Christopher Tate181fafa2009-05-14 11:12:14 -070046import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020047import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.content.ComponentName;
49import android.content.ContentResolver;
50import android.content.Context;
51import android.content.Intent;
52import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070053import android.content.IIntentReceiver;
54import android.content.IIntentSender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -070055import android.content.IntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.content.pm.ActivityInfo;
57import android.content.pm.ApplicationInfo;
58import android.content.pm.ConfigurationInfo;
59import android.content.pm.IPackageDataObserver;
60import android.content.pm.IPackageManager;
61import android.content.pm.InstrumentationInfo;
62import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070063import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import android.content.pm.ProviderInfo;
65import android.content.pm.ResolveInfo;
66import android.content.pm.ServiceInfo;
67import android.content.res.Configuration;
68import android.graphics.Bitmap;
69import android.net.Uri;
70import android.os.Binder;
71import android.os.Bundle;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070072import android.os.Debug;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073import android.os.Environment;
74import android.os.FileUtils;
75import android.os.Handler;
76import android.os.IBinder;
77import android.os.IPermissionController;
78import android.os.Looper;
79import android.os.Message;
80import android.os.Parcel;
81import android.os.ParcelFileDescriptor;
82import android.os.PowerManager;
83import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070084import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085import android.os.RemoteException;
86import android.os.ServiceManager;
87import android.os.SystemClock;
88import android.os.SystemProperties;
89import android.provider.Checkin;
90import android.provider.Settings;
91import android.text.TextUtils;
92import android.util.Config;
93import android.util.EventLog;
94import android.util.Log;
95import android.util.PrintWriterPrinter;
96import android.util.SparseArray;
97import android.view.Gravity;
98import android.view.LayoutInflater;
99import android.view.View;
100import android.view.WindowManager;
101import android.view.WindowManagerPolicy;
102
103import dalvik.system.Zygote;
104
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200105import java.io.ByteArrayInputStream;
106import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107import java.io.File;
108import java.io.FileDescriptor;
109import java.io.FileInputStream;
110import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200111import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800112import java.io.PrintWriter;
113import java.lang.IllegalStateException;
114import java.lang.ref.WeakReference;
115import java.util.ArrayList;
116import java.util.HashMap;
117import java.util.HashSet;
118import java.util.Iterator;
119import java.util.List;
120import java.util.Locale;
121import java.util.Map;
122
123public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
124 static final String TAG = "ActivityManager";
125 static final boolean DEBUG = false;
126 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
127 static final boolean DEBUG_SWITCH = localLOGV || false;
128 static final boolean DEBUG_TASKS = localLOGV || false;
129 static final boolean DEBUG_PAUSE = localLOGV || false;
130 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
131 static final boolean DEBUG_TRANSITION = localLOGV || false;
132 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700133 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 static final boolean DEBUG_SERVICE = localLOGV || false;
135 static final boolean DEBUG_VISBILITY = localLOGV || false;
136 static final boolean DEBUG_PROCESSES = localLOGV || false;
Dianne Hackborna1e989b2009-09-01 19:54:29 -0700137 static final boolean DEBUG_PROVIDER = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700139 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate436344a2009-09-30 16:17:37 -0700140 static final boolean DEBUG_BACKUP = localLOGV || false;
Dianne Hackborndc6b6352009-09-30 14:20:09 -0700141 static final boolean DEBUG_CONFIGURATION = localLOGV || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800142 static final boolean VALIDATE_TOKENS = false;
143 static final boolean SHOW_ACTIVITY_START_TIME = true;
144
145 // Control over CPU and battery monitoring.
146 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
147 static final boolean MONITOR_CPU_USAGE = true;
148 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
149 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
150 static final boolean MONITOR_THREAD_CPU_USAGE = false;
151
Dianne Hackborn1655be42009-05-08 14:29:01 -0700152 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700153 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700154
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 private static final String SYSTEM_SECURE = "ro.secure";
156
157 // This is the maximum number of application processes we would like
158 // to have running. Due to the asynchronous nature of things, we can
159 // temporarily go beyond this limit.
160 static final int MAX_PROCESSES = 2;
161
162 // Set to false to leave processes running indefinitely, relying on
163 // the kernel killing them as resources are required.
164 static final boolean ENFORCE_PROCESS_LIMIT = false;
165
166 // This is the maximum number of activities that we would like to have
167 // running at a given time.
168 static final int MAX_ACTIVITIES = 20;
169
170 // Maximum number of recent tasks that we can remember.
171 static final int MAX_RECENT_TASKS = 20;
172
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700173 // Amount of time after a call to stopAppSwitches() during which we will
174 // prevent further untrusted switches from happening.
175 static final long APP_SWITCH_DELAY_TIME = 5*1000;
176
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800177 // How long until we reset a task when the user returns to it. Currently
178 // 30 minutes.
179 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
180
181 // Set to true to disable the icon that is shown while a new activity
182 // is being started.
183 static final boolean SHOW_APP_STARTING_ICON = true;
184
185 // How long we wait until giving up on the last activity to pause. This
186 // is short because it directly impacts the responsiveness of starting the
187 // next activity.
188 static final int PAUSE_TIMEOUT = 500;
189
190 /**
191 * How long we can hold the launch wake lock before giving up.
192 */
193 static final int LAUNCH_TIMEOUT = 10*1000;
194
195 // How long we wait for a launched process to attach to the activity manager
196 // before we decide it's never going to come up for real.
197 static final int PROC_START_TIMEOUT = 10*1000;
198
199 // How long we wait until giving up on the last activity telling us it
200 // is idle.
201 static final int IDLE_TIMEOUT = 10*1000;
202
203 // How long to wait after going idle before forcing apps to GC.
204 static final int GC_TIMEOUT = 5*1000;
205
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700206 // The minimum amount of time between successive GC requests for a process.
207 static final int GC_MIN_INTERVAL = 60*1000;
208
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800209 // How long we wait until giving up on an activity telling us it has
210 // finished destroying itself.
211 static final int DESTROY_TIMEOUT = 10*1000;
212
213 // How long we allow a receiver to run before giving up on it.
214 static final int BROADCAST_TIMEOUT = 10*1000;
215
216 // How long we wait for a service to finish executing.
217 static final int SERVICE_TIMEOUT = 20*1000;
218
219 // How long a service needs to be running until restarting its process
220 // is no longer considered to be a relaunch of the service.
221 static final int SERVICE_RESTART_DURATION = 5*1000;
222
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700223 // How long a service needs to be running until it will start back at
224 // SERVICE_RESTART_DURATION after being killed.
225 static final int SERVICE_RESET_RUN_DURATION = 60*1000;
226
227 // Multiplying factor to increase restart duration time by, for each time
228 // a service is killed before it has run for SERVICE_RESET_RUN_DURATION.
229 static final int SERVICE_RESTART_DURATION_FACTOR = 4;
230
231 // The minimum amount of time between restarting services that we allow.
232 // That is, when multiple services are restarting, we won't allow each
233 // to restart less than this amount of time from the last one.
234 static final int SERVICE_MIN_RESTART_TIME_BETWEEN = 10*1000;
235
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800236 // Maximum amount of time for there to be no activity on a service before
237 // we consider it non-essential and allow its process to go on the
238 // LRU background list.
Dianne Hackbornfd12af42009-08-27 00:44:33 -0700239 static final int MAX_SERVICE_INACTIVITY = 30*60*1000;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240
241 // How long we wait until we timeout on key dispatching.
242 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
243
244 // The minimum time we allow between crashes, for us to consider this
245 // application to be bad and stop and its services and reject broadcasts.
246 static final int MIN_CRASH_INTERVAL = 60*1000;
247
248 // How long we wait until we timeout on key dispatching during instrumentation.
249 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
250
251 // OOM adjustments for processes in various states:
252
253 // This is a process without anything currently running in it. Definitely
254 // the first to go! Value set in system/rootdir/init.rc on startup.
255 // This value is initalized in the constructor, careful when refering to
256 // this static variable externally.
257 static int EMPTY_APP_ADJ;
258
259 // This is a process with a content provider that does not have any clients
260 // attached to it. If it did have any clients, its adjustment would be the
261 // one for the highest-priority of those processes.
262 static int CONTENT_PROVIDER_ADJ;
263
264 // This is a process only hosting activities that are not visible,
265 // so it can be killed without any disruption. Value set in
266 // system/rootdir/init.rc on startup.
267 final int HIDDEN_APP_MAX_ADJ;
268 static int HIDDEN_APP_MIN_ADJ;
269
The Android Open Source Project4df24232009-03-05 14:34:35 -0800270 // This is a process holding the home application -- we want to try
271 // avoiding killing it, even if it would normally be in the background,
272 // because the user interacts with it so much.
273 final int HOME_APP_ADJ;
274
Christopher Tate6fa95972009-06-05 18:43:55 -0700275 // This is a process currently hosting a backup operation. Killing it
276 // is not entirely fatal but is generally a bad idea.
277 final int BACKUP_APP_ADJ;
278
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800279 // This is a process holding a secondary server -- killing it will not
280 // have much of an impact as far as the user is concerned. Value set in
281 // system/rootdir/init.rc on startup.
282 final int SECONDARY_SERVER_ADJ;
283
284 // This is a process only hosting activities that are visible to the
285 // user, so we'd prefer they don't disappear. Value set in
286 // system/rootdir/init.rc on startup.
287 final int VISIBLE_APP_ADJ;
288
289 // This is the process running the current foreground app. We'd really
290 // rather not kill it! Value set in system/rootdir/init.rc on startup.
291 final int FOREGROUND_APP_ADJ;
292
293 // This is a process running a core server, such as telephony. Definitely
294 // don't want to kill it, but doing so is not completely fatal.
295 static final int CORE_SERVER_ADJ = -12;
296
297 // The system process runs at the default adjustment.
298 static final int SYSTEM_ADJ = -16;
299
300 // Memory pages are 4K.
301 static final int PAGE_SIZE = 4*1024;
302
Jacek Surazski82a73df2009-06-17 14:33:18 +0200303 // System property defining error report receiver for system apps
304 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
305
306 // System property defining default error report receiver
307 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
308
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800309 // Corresponding memory levels for above adjustments.
310 final int EMPTY_APP_MEM;
311 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800312 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700313 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800314 final int SECONDARY_SERVER_MEM;
315 final int VISIBLE_APP_MEM;
316 final int FOREGROUND_APP_MEM;
317
318 final int MY_PID;
319
320 static final String[] EMPTY_STRING_ARRAY = new String[0];
321
322 enum ActivityState {
323 INITIALIZING,
324 RESUMED,
325 PAUSING,
326 PAUSED,
327 STOPPING,
328 STOPPED,
329 FINISHING,
330 DESTROYING,
331 DESTROYED
332 }
333
334 /**
335 * The back history of all previous (and possibly still
336 * running) activities. It contains HistoryRecord objects.
337 */
338 final ArrayList mHistory = new ArrayList();
339
340 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700341 * Description of a request to start a new activity, which has been held
342 * due to app switches being disabled.
343 */
344 class PendingActivityLaunch {
345 HistoryRecord r;
346 HistoryRecord sourceRecord;
347 Uri[] grantedUriPermissions;
348 int grantedMode;
349 boolean onlyIfNeeded;
350 }
351
352 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
353 = new ArrayList<PendingActivityLaunch>();
354
355 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800356 * List of all active broadcasts that are to be executed immediately
357 * (without waiting for another broadcast to finish). Currently this only
358 * contains broadcasts to registered receivers, to avoid spinning up
359 * a bunch of processes to execute IntentReceiver components.
360 */
361 final ArrayList<BroadcastRecord> mParallelBroadcasts
362 = new ArrayList<BroadcastRecord>();
363
364 /**
365 * List of all active broadcasts that are to be executed one at a time.
366 * The object at the top of the list is the currently activity broadcasts;
367 * those after it are waiting for the top to finish..
368 */
369 final ArrayList<BroadcastRecord> mOrderedBroadcasts
370 = new ArrayList<BroadcastRecord>();
371
372 /**
Dianne Hackborn12527f92009-11-11 17:39:50 -0800373 * Historical data of past broadcasts, for debugging.
374 */
375 static final int MAX_BROADCAST_HISTORY = 100;
376 final BroadcastRecord[] mBroadcastHistory
377 = new BroadcastRecord[MAX_BROADCAST_HISTORY];
378
379 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 * Set when we current have a BROADCAST_INTENT_MSG in flight.
381 */
382 boolean mBroadcastsScheduled = false;
383
384 /**
385 * Set to indicate whether to issue an onUserLeaving callback when a
386 * newly launched activity is being brought in front of us.
387 */
388 boolean mUserLeaving = false;
389
390 /**
391 * When we are in the process of pausing an activity, before starting the
392 * next one, this variable holds the activity that is currently being paused.
393 */
394 HistoryRecord mPausingActivity = null;
395
396 /**
397 * Current activity that is resumed, or null if there is none.
398 */
399 HistoryRecord mResumedActivity = null;
400
401 /**
402 * Activity we have told the window manager to have key focus.
403 */
404 HistoryRecord mFocusedActivity = null;
405
406 /**
407 * This is the last activity that we put into the paused state. This is
408 * used to determine if we need to do an activity transition while sleeping,
409 * when we normally hold the top activity paused.
410 */
411 HistoryRecord mLastPausedActivity = null;
412
413 /**
414 * List of activities that are waiting for a new activity
415 * to become visible before completing whatever operation they are
416 * supposed to do.
417 */
418 final ArrayList mWaitingVisibleActivities = new ArrayList();
419
420 /**
421 * List of activities that are ready to be stopped, but waiting
422 * for the next activity to settle down before doing so. It contains
423 * HistoryRecord objects.
424 */
425 final ArrayList<HistoryRecord> mStoppingActivities
426 = new ArrayList<HistoryRecord>();
427
428 /**
Dianne Hackbornbfe319e2009-09-21 00:34:05 -0700429 * Animations that for the current transition have requested not to
430 * be considered for the transition animation.
431 */
432 final ArrayList<HistoryRecord> mNoAnimActivities
433 = new ArrayList<HistoryRecord>();
434
435 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436 * List of intents that were used to start the most recent tasks.
437 */
438 final ArrayList<TaskRecord> mRecentTasks
439 = new ArrayList<TaskRecord>();
440
441 /**
442 * List of activities that are ready to be finished, but waiting
443 * for the previous activity to settle down before doing so. It contains
444 * HistoryRecord objects.
445 */
446 final ArrayList mFinishingActivities = new ArrayList();
447
448 /**
449 * All of the applications we currently have running organized by name.
450 * The keys are strings of the application package name (as
451 * returned by the package manager), and the keys are ApplicationRecord
452 * objects.
453 */
454 final ProcessMap<ProcessRecord> mProcessNames
455 = new ProcessMap<ProcessRecord>();
456
457 /**
458 * The last time that various processes have crashed.
459 */
460 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
461
462 /**
463 * Set of applications that we consider to be bad, and will reject
464 * incoming broadcasts from (which the user has no control over).
465 * Processes are added to this set when they have crashed twice within
466 * a minimum amount of time; they are removed from it when they are
467 * later restarted (hopefully due to some user action). The value is the
468 * time it was added to the list.
469 */
470 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
471
472 /**
473 * All of the processes we currently have running organized by pid.
474 * The keys are the pid running the application.
475 *
476 * <p>NOTE: This object is protected by its own lock, NOT the global
477 * activity manager lock!
478 */
479 final SparseArray<ProcessRecord> mPidsSelfLocked
480 = new SparseArray<ProcessRecord>();
481
482 /**
483 * All of the processes that have been forced to be foreground. The key
484 * is the pid of the caller who requested it (we hold a death
485 * link on it).
486 */
487 abstract class ForegroundToken implements IBinder.DeathRecipient {
488 int pid;
489 IBinder token;
490 }
491 final SparseArray<ForegroundToken> mForegroundProcesses
492 = new SparseArray<ForegroundToken>();
493
494 /**
495 * List of records for processes that someone had tried to start before the
496 * system was ready. We don't start them at that point, but ensure they
497 * are started by the time booting is complete.
498 */
499 final ArrayList<ProcessRecord> mProcessesOnHold
500 = new ArrayList<ProcessRecord>();
501
502 /**
503 * List of records for processes that we have started and are waiting
504 * for them to call back. This is really only needed when running in
505 * single processes mode, in which case we do not have a unique pid for
506 * each process.
507 */
508 final ArrayList<ProcessRecord> mStartingProcesses
509 = new ArrayList<ProcessRecord>();
510
511 /**
512 * List of persistent applications that are in the process
513 * of being started.
514 */
515 final ArrayList<ProcessRecord> mPersistentStartingProcesses
516 = new ArrayList<ProcessRecord>();
517
518 /**
519 * Processes that are being forcibly torn down.
520 */
521 final ArrayList<ProcessRecord> mRemovedProcesses
522 = new ArrayList<ProcessRecord>();
523
524 /**
525 * List of running applications, sorted by recent usage.
526 * The first entry in the list is the least recently used.
527 * It contains ApplicationRecord objects. This list does NOT include
528 * any persistent application records (since we never want to exit them).
529 */
530 final ArrayList<ProcessRecord> mLRUProcesses
531 = new ArrayList<ProcessRecord>();
532
533 /**
534 * List of processes that should gc as soon as things are idle.
535 */
536 final ArrayList<ProcessRecord> mProcessesToGc
537 = new ArrayList<ProcessRecord>();
538
539 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800540 * This is the process holding what we currently consider to be
541 * the "home" activity.
542 */
543 private ProcessRecord mHomeProcess;
544
545 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800546 * List of running activities, sorted by recent usage.
547 * The first entry in the list is the least recently used.
548 * It contains HistoryRecord objects.
549 */
550 private final ArrayList mLRUActivities = new ArrayList();
551
552 /**
553 * Set of PendingResultRecord objects that are currently active.
554 */
555 final HashSet mPendingResultRecords = new HashSet();
556
557 /**
558 * Set of IntentSenderRecord objects that are currently active.
559 */
560 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
561 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
562
563 /**
564 * Intent broadcast that we have tried to start, but are
565 * waiting for its application's process to be created. We only
566 * need one (instead of a list) because we always process broadcasts
567 * one at a time, so no others can be started while waiting for this
568 * one.
569 */
570 BroadcastRecord mPendingBroadcast = null;
571
572 /**
573 * Keeps track of all IIntentReceivers that have been registered for
574 * broadcasts. Hash keys are the receiver IBinder, hash value is
575 * a ReceiverList.
576 */
577 final HashMap mRegisteredReceivers = new HashMap();
578
579 /**
580 * Resolver for broadcast intents to registered receivers.
581 * Holds BroadcastFilter (subclass of IntentFilter).
582 */
583 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
584 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
585 @Override
586 protected boolean allowFilterResult(
587 BroadcastFilter filter, List<BroadcastFilter> dest) {
588 IBinder target = filter.receiverList.receiver.asBinder();
589 for (int i=dest.size()-1; i>=0; i--) {
590 if (dest.get(i).receiverList.receiver.asBinder() == target) {
591 return false;
592 }
593 }
594 return true;
595 }
596 };
597
598 /**
599 * State of all active sticky broadcasts. Keys are the action of the
600 * sticky Intent, values are an ArrayList of all broadcasted intents with
601 * that action (which should usually be one).
602 */
603 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
604 new HashMap<String, ArrayList<Intent>>();
605
606 /**
607 * All currently running services.
608 */
609 final HashMap<ComponentName, ServiceRecord> mServices =
610 new HashMap<ComponentName, ServiceRecord>();
611
612 /**
613 * All currently running services indexed by the Intent used to start them.
614 */
615 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
616 new HashMap<Intent.FilterComparison, ServiceRecord>();
617
618 /**
619 * All currently bound service connections. Keys are the IBinder of
620 * the client's IServiceConnection.
621 */
622 final HashMap<IBinder, ConnectionRecord> mServiceConnections
623 = new HashMap<IBinder, ConnectionRecord>();
624
625 /**
626 * List of services that we have been asked to start,
627 * but haven't yet been able to. It is used to hold start requests
628 * while waiting for their corresponding application thread to get
629 * going.
630 */
631 final ArrayList<ServiceRecord> mPendingServices
632 = new ArrayList<ServiceRecord>();
633
634 /**
635 * List of services that are scheduled to restart following a crash.
636 */
637 final ArrayList<ServiceRecord> mRestartingServices
638 = new ArrayList<ServiceRecord>();
639
640 /**
641 * List of services that are in the process of being stopped.
642 */
643 final ArrayList<ServiceRecord> mStoppingServices
644 = new ArrayList<ServiceRecord>();
645
646 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700647 * Backup/restore process management
648 */
649 String mBackupAppName = null;
650 BackupRecord mBackupTarget = null;
651
652 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800653 * List of PendingThumbnailsRecord objects of clients who are still
654 * waiting to receive all of the thumbnails for a task.
655 */
656 final ArrayList mPendingThumbnails = new ArrayList();
657
658 /**
659 * List of HistoryRecord objects that have been finished and must
660 * still report back to a pending thumbnail receiver.
661 */
662 final ArrayList mCancelledThumbnails = new ArrayList();
663
664 /**
665 * All of the currently running global content providers. Keys are a
666 * string containing the provider name and values are a
667 * ContentProviderRecord object containing the data about it. Note
668 * that a single provider may be published under multiple names, so
669 * there may be multiple entries here for a single one in mProvidersByClass.
670 */
671 final HashMap mProvidersByName = new HashMap();
672
673 /**
674 * All of the currently running global content providers. Keys are a
675 * string containing the provider's implementation class and values are a
676 * ContentProviderRecord object containing the data about it.
677 */
678 final HashMap mProvidersByClass = new HashMap();
679
680 /**
681 * List of content providers who have clients waiting for them. The
682 * application is currently being launched and the provider will be
683 * removed from this list once it is published.
684 */
685 final ArrayList mLaunchingProviders = new ArrayList();
686
687 /**
688 * Global set of specific Uri permissions that have been granted.
689 */
690 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
691 = new SparseArray<HashMap<Uri, UriPermission>>();
692
693 /**
694 * Thread-local storage used to carry caller permissions over through
695 * indirect content-provider access.
696 * @see #ActivityManagerService.openContentUri()
697 */
698 private class Identity {
699 public int pid;
700 public int uid;
701
702 Identity(int _pid, int _uid) {
703 pid = _pid;
704 uid = _uid;
705 }
706 }
707 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
708
709 /**
710 * All information we have collected about the runtime performance of
711 * any user id that can impact battery performance.
712 */
713 final BatteryStatsService mBatteryStatsService;
714
715 /**
716 * information about component usage
717 */
718 final UsageStatsService mUsageStatsService;
719
720 /**
721 * Current configuration information. HistoryRecord objects are given
722 * a reference to this object to indicate which configuration they are
723 * currently running in, so this object must be kept immutable.
724 */
725 Configuration mConfiguration = new Configuration();
726
727 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700728 * Hardware-reported OpenGLES version.
729 */
730 final int GL_ES_VERSION;
731
732 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800733 * List of initialization arguments to pass to all processes when binding applications to them.
734 * For example, references to the commonly used services.
735 */
736 HashMap<String, IBinder> mAppBindArgs;
737
738 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700739 * Temporary to avoid allocations. Protected by main lock.
740 */
741 final StringBuilder mStringBuilder = new StringBuilder(256);
742
743 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800744 * Used to control how we initialize the service.
745 */
746 boolean mStartRunning = false;
747 ComponentName mTopComponent;
748 String mTopAction;
749 String mTopData;
750 boolean mSystemReady = false;
751 boolean mBooting = false;
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700752 boolean mWaitingUpdate = false;
753 boolean mDidUpdate = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800754
755 Context mContext;
756
757 int mFactoryTest;
758
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700759 boolean mCheckedForSetup;
760
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700762 * The time at which we will allow normal application switches again,
763 * after a call to {@link #stopAppSwitches()}.
764 */
765 long mAppSwitchesAllowedTime;
766
767 /**
768 * This is set to true after the first switch after mAppSwitchesAllowedTime
769 * is set; any switches after that will clear the time.
770 */
771 boolean mDidAppSwitch;
772
773 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800774 * Set while we are wanting to sleep, to prevent any
775 * activities from being started/resumed.
776 */
777 boolean mSleeping = false;
778
779 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700780 * Set if we are shutting down the system, similar to sleeping.
781 */
782 boolean mShuttingDown = false;
783
784 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800785 * Set when the system is going to sleep, until we have
786 * successfully paused the current activity and released our wake lock.
787 * At that point the system is allowed to actually sleep.
788 */
789 PowerManager.WakeLock mGoingToSleep;
790
791 /**
792 * We don't want to allow the device to go to sleep while in the process
793 * of launching an activity. This is primarily to allow alarm intent
794 * receivers to launch an activity and get that to run before the device
795 * goes back to sleep.
796 */
797 PowerManager.WakeLock mLaunchingActivity;
798
799 /**
800 * Task identifier that activities are currently being started
801 * in. Incremented each time a new task is created.
802 * todo: Replace this with a TokenSpace class that generates non-repeating
803 * integers that won't wrap.
804 */
805 int mCurTask = 1;
806
807 /**
808 * Current sequence id for oom_adj computation traversal.
809 */
810 int mAdjSeq = 0;
811
812 /**
813 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
814 * is set, indicating the user wants processes started in such a way
815 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
816 * running in each process (thus no pre-initialized process, etc).
817 */
818 boolean mSimpleProcessManagement = false;
819
820 /**
821 * System monitoring: number of processes that died since the last
822 * N procs were started.
823 */
824 int[] mProcDeaths = new int[20];
825
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700826 /**
827 * This is set if we had to do a delayed dexopt of an app before launching
828 * it, to increasing the ANR timeouts in that case.
829 */
830 boolean mDidDexOpt;
831
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800832 String mDebugApp = null;
833 boolean mWaitForDebugger = false;
834 boolean mDebugTransient = false;
835 String mOrigDebugApp = null;
836 boolean mOrigWaitForDebugger = false;
837 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700838 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800839
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700840 final RemoteCallbackList<IActivityWatcher> mWatchers
841 = new RemoteCallbackList<IActivityWatcher>();
842
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800843 /**
844 * Callback of last caller to {@link #requestPss}.
845 */
846 Runnable mRequestPssCallback;
847
848 /**
849 * Remaining processes for which we are waiting results from the last
850 * call to {@link #requestPss}.
851 */
852 final ArrayList<ProcessRecord> mRequestPssList
853 = new ArrayList<ProcessRecord>();
854
855 /**
856 * Runtime statistics collection thread. This object's lock is used to
857 * protect all related state.
858 */
859 final Thread mProcessStatsThread;
860
861 /**
862 * Used to collect process stats when showing not responding dialog.
863 * Protected by mProcessStatsThread.
864 */
865 final ProcessStats mProcessStats = new ProcessStats(
866 MONITOR_THREAD_CPU_USAGE);
867 long mLastCpuTime = 0;
868 long mLastWriteTime = 0;
869
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700870 long mInitialStartTime = 0;
871
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800872 /**
873 * Set to true after the system has finished booting.
874 */
875 boolean mBooted = false;
876
877 int mProcessLimit = 0;
878
879 WindowManagerService mWindowManager;
880
881 static ActivityManagerService mSelf;
882 static ActivityThread mSystemThread;
883
884 private final class AppDeathRecipient implements IBinder.DeathRecipient {
885 final ProcessRecord mApp;
886 final int mPid;
887 final IApplicationThread mAppThread;
888
889 AppDeathRecipient(ProcessRecord app, int pid,
890 IApplicationThread thread) {
891 if (localLOGV) Log.v(
892 TAG, "New death recipient " + this
893 + " for thread " + thread.asBinder());
894 mApp = app;
895 mPid = pid;
896 mAppThread = thread;
897 }
898
899 public void binderDied() {
900 if (localLOGV) Log.v(
901 TAG, "Death received in " + this
902 + " for thread " + mAppThread.asBinder());
903 removeRequestedPss(mApp);
904 synchronized(ActivityManagerService.this) {
905 appDiedLocked(mApp, mPid, mAppThread);
906 }
907 }
908 }
909
910 static final int SHOW_ERROR_MSG = 1;
911 static final int SHOW_NOT_RESPONDING_MSG = 2;
912 static final int SHOW_FACTORY_ERROR_MSG = 3;
913 static final int UPDATE_CONFIGURATION_MSG = 4;
914 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
915 static final int WAIT_FOR_DEBUGGER_MSG = 6;
916 static final int BROADCAST_INTENT_MSG = 7;
917 static final int BROADCAST_TIMEOUT_MSG = 8;
918 static final int PAUSE_TIMEOUT_MSG = 9;
919 static final int IDLE_TIMEOUT_MSG = 10;
920 static final int IDLE_NOW_MSG = 11;
921 static final int SERVICE_TIMEOUT_MSG = 12;
922 static final int UPDATE_TIME_ZONE = 13;
923 static final int SHOW_UID_ERROR_MSG = 14;
924 static final int IM_FEELING_LUCKY_MSG = 15;
925 static final int LAUNCH_TIMEOUT_MSG = 16;
926 static final int DESTROY_TIMEOUT_MSG = 17;
927 static final int SERVICE_ERROR_MSG = 18;
928 static final int RESUME_TOP_ACTIVITY_MSG = 19;
929 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700930 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700931 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800932
933 AlertDialog mUidAlert;
934
935 final Handler mHandler = new Handler() {
936 //public Handler() {
937 // if (localLOGV) Log.v(TAG, "Handler started!");
938 //}
939
940 public void handleMessage(Message msg) {
941 switch (msg.what) {
942 case SHOW_ERROR_MSG: {
943 HashMap data = (HashMap) msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800944 synchronized (ActivityManagerService.this) {
945 ProcessRecord proc = (ProcessRecord)data.get("app");
946 if (proc != null && proc.crashDialog != null) {
947 Log.e(TAG, "App already has crash dialog: " + proc);
948 return;
949 }
950 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700951 if (!mSleeping && !mShuttingDown) {
Dan Egnorb7f03672009-12-09 16:22:32 -0800952 Dialog d = new AppErrorDialog(mContext, res, proc);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800953 d.show();
954 proc.crashDialog = d;
955 } else {
956 // The device is asleep, so just pretend that the user
957 // saw a crash dialog and hit "force quit".
958 res.set(0);
959 }
960 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700961
962 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800963 } break;
964 case SHOW_NOT_RESPONDING_MSG: {
965 synchronized (ActivityManagerService.this) {
966 HashMap data = (HashMap) msg.obj;
967 ProcessRecord proc = (ProcessRecord)data.get("app");
968 if (proc != null && proc.anrDialog != null) {
969 Log.e(TAG, "App already has anr dialog: " + proc);
970 return;
971 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800972
973 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
974 null, null, 0, null, null, null,
975 false, false, MY_PID, Process.SYSTEM_UID);
976
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800977 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
978 mContext, proc, (HistoryRecord)data.get("activity"));
979 d.show();
980 proc.anrDialog = d;
981 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700982
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700983 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800984 } break;
985 case SHOW_FACTORY_ERROR_MSG: {
986 Dialog d = new FactoryErrorDialog(
987 mContext, msg.getData().getCharSequence("msg"));
988 d.show();
Dianne Hackborn9acc0302009-08-25 00:27:12 -0700989 ensureBootCompleted();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800990 } break;
991 case UPDATE_CONFIGURATION_MSG: {
992 final ContentResolver resolver = mContext.getContentResolver();
993 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
994 } break;
995 case GC_BACKGROUND_PROCESSES_MSG: {
996 synchronized (ActivityManagerService.this) {
997 performAppGcsIfAppropriateLocked();
998 }
999 } break;
1000 case WAIT_FOR_DEBUGGER_MSG: {
1001 synchronized (ActivityManagerService.this) {
1002 ProcessRecord app = (ProcessRecord)msg.obj;
1003 if (msg.arg1 != 0) {
1004 if (!app.waitedForDebugger) {
1005 Dialog d = new AppWaitingForDebuggerDialog(
1006 ActivityManagerService.this,
1007 mContext, app);
1008 app.waitDialog = d;
1009 app.waitedForDebugger = true;
1010 d.show();
1011 }
1012 } else {
1013 if (app.waitDialog != null) {
1014 app.waitDialog.dismiss();
1015 app.waitDialog = null;
1016 }
1017 }
1018 }
1019 } break;
1020 case BROADCAST_INTENT_MSG: {
1021 if (DEBUG_BROADCAST) Log.v(
1022 TAG, "Received BROADCAST_INTENT_MSG");
1023 processNextBroadcast(true);
1024 } break;
1025 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001026 if (mDidDexOpt) {
1027 mDidDexOpt = false;
1028 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1029 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1030 return;
1031 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001032 broadcastTimeout();
1033 } break;
1034 case PAUSE_TIMEOUT_MSG: {
1035 IBinder token = (IBinder)msg.obj;
1036 // We don't at this point know if the activity is fullscreen,
1037 // so we need to be conservative and assume it isn't.
1038 Log.w(TAG, "Activity pause timeout for " + token);
1039 activityPaused(token, null, true);
1040 } break;
1041 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001042 if (mDidDexOpt) {
1043 mDidDexOpt = false;
1044 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1045 nmsg.obj = msg.obj;
1046 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1047 return;
1048 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001049 // We don't at this point know if the activity is fullscreen,
1050 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001051 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001052 Log.w(TAG, "Activity idle timeout for " + token);
Dianne Hackborne88846e2009-09-30 21:34:25 -07001053 activityIdleInternal(token, true, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001054 } break;
1055 case DESTROY_TIMEOUT_MSG: {
1056 IBinder token = (IBinder)msg.obj;
1057 // We don't at this point know if the activity is fullscreen,
1058 // so we need to be conservative and assume it isn't.
1059 Log.w(TAG, "Activity destroy timeout for " + token);
1060 activityDestroyed(token);
1061 } break;
1062 case IDLE_NOW_MSG: {
1063 IBinder token = (IBinder)msg.obj;
Dianne Hackborne88846e2009-09-30 21:34:25 -07001064 activityIdle(token, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 } break;
1066 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001067 if (mDidDexOpt) {
1068 mDidDexOpt = false;
1069 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1070 nmsg.obj = msg.obj;
1071 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1072 return;
1073 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001074 serviceTimeout((ProcessRecord)msg.obj);
1075 } break;
1076 case UPDATE_TIME_ZONE: {
1077 synchronized (ActivityManagerService.this) {
1078 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1079 ProcessRecord r = mLRUProcesses.get(i);
1080 if (r.thread != null) {
1081 try {
1082 r.thread.updateTimeZone();
1083 } catch (RemoteException ex) {
1084 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1085 }
1086 }
1087 }
1088 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001089 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001090 case SHOW_UID_ERROR_MSG: {
1091 // XXX This is a temporary dialog, no need to localize.
1092 AlertDialog d = new BaseErrorDialog(mContext);
1093 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1094 d.setCancelable(false);
1095 d.setTitle("System UIDs Inconsistent");
1096 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1097 d.setButton("I'm Feeling Lucky",
1098 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1099 mUidAlert = d;
1100 d.show();
1101 } break;
1102 case IM_FEELING_LUCKY_MSG: {
1103 if (mUidAlert != null) {
1104 mUidAlert.dismiss();
1105 mUidAlert = null;
1106 }
1107 } break;
1108 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001109 if (mDidDexOpt) {
1110 mDidDexOpt = false;
1111 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1112 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1113 return;
1114 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001115 synchronized (ActivityManagerService.this) {
1116 if (mLaunchingActivity.isHeld()) {
1117 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1118 mLaunchingActivity.release();
1119 }
1120 }
1121 } break;
1122 case SERVICE_ERROR_MSG: {
1123 ServiceRecord srv = (ServiceRecord)msg.obj;
1124 // This needs to be *un*synchronized to avoid deadlock.
1125 Checkin.logEvent(mContext.getContentResolver(),
1126 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1127 srv.name.toShortString());
1128 } break;
1129 case RESUME_TOP_ACTIVITY_MSG: {
1130 synchronized (ActivityManagerService.this) {
1131 resumeTopActivityLocked(null);
1132 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001133 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001134 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001135 if (mDidDexOpt) {
1136 mDidDexOpt = false;
1137 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1138 nmsg.obj = msg.obj;
1139 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1140 return;
1141 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001142 ProcessRecord app = (ProcessRecord)msg.obj;
1143 synchronized (ActivityManagerService.this) {
1144 processStartTimedOutLocked(app);
1145 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001146 } break;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001147 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1148 synchronized (ActivityManagerService.this) {
1149 doPendingActivityLaunchesLocked(true);
1150 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07001151 } break;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001152 case KILL_APPLICATION_MSG: {
1153 synchronized (ActivityManagerService.this) {
1154 int uid = msg.arg1;
1155 boolean restart = (msg.arg2 == 1);
1156 String pkg = (String) msg.obj;
1157 uninstallPackageLocked(pkg, uid, restart);
1158 }
1159 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001160 }
1161 }
1162 };
1163
1164 public static void setSystemProcess() {
1165 try {
1166 ActivityManagerService m = mSelf;
1167
1168 ServiceManager.addService("activity", m);
1169 ServiceManager.addService("meminfo", new MemBinder(m));
1170 if (MONITOR_CPU_USAGE) {
1171 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1172 }
1173 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1174 ServiceManager.addService("activity.services", new ServicesBinder(m));
1175 ServiceManager.addService("activity.senders", new SendersBinder(m));
1176 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1177 ServiceManager.addService("permission", new PermissionController(m));
1178
1179 ApplicationInfo info =
1180 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001181 "android", STOCK_PM_FLAGS);
Mike Cleron432b7132009-09-24 15:28:29 -07001182 mSystemThread.installSystemApplicationInfo(info);
1183
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001184 synchronized (mSelf) {
1185 ProcessRecord app = mSelf.newProcessRecordLocked(
1186 mSystemThread.getApplicationThread(), info,
1187 info.processName);
1188 app.persistent = true;
1189 app.pid = Process.myPid();
1190 app.maxAdj = SYSTEM_ADJ;
1191 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1192 synchronized (mSelf.mPidsSelfLocked) {
1193 mSelf.mPidsSelfLocked.put(app.pid, app);
1194 }
1195 mSelf.updateLRUListLocked(app, true);
1196 }
1197 } catch (PackageManager.NameNotFoundException e) {
1198 throw new RuntimeException(
1199 "Unable to find android system package", e);
1200 }
1201 }
1202
1203 public void setWindowManager(WindowManagerService wm) {
1204 mWindowManager = wm;
1205 }
1206
1207 public static final Context main(int factoryTest) {
1208 AThread thr = new AThread();
1209 thr.start();
1210
1211 synchronized (thr) {
1212 while (thr.mService == null) {
1213 try {
1214 thr.wait();
1215 } catch (InterruptedException e) {
1216 }
1217 }
1218 }
1219
1220 ActivityManagerService m = thr.mService;
1221 mSelf = m;
1222 ActivityThread at = ActivityThread.systemMain();
1223 mSystemThread = at;
1224 Context context = at.getSystemContext();
1225 m.mContext = context;
1226 m.mFactoryTest = factoryTest;
1227 PowerManager pm =
1228 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1229 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1230 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1231 m.mLaunchingActivity.setReferenceCounted(false);
1232
1233 m.mBatteryStatsService.publish(context);
1234 m.mUsageStatsService.publish(context);
1235
1236 synchronized (thr) {
1237 thr.mReady = true;
1238 thr.notifyAll();
1239 }
1240
1241 m.startRunning(null, null, null, null);
1242
1243 return context;
1244 }
1245
1246 public static ActivityManagerService self() {
1247 return mSelf;
1248 }
1249
1250 static class AThread extends Thread {
1251 ActivityManagerService mService;
1252 boolean mReady = false;
1253
1254 public AThread() {
1255 super("ActivityManager");
1256 }
1257
1258 public void run() {
1259 Looper.prepare();
1260
1261 android.os.Process.setThreadPriority(
1262 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1263
1264 ActivityManagerService m = new ActivityManagerService();
1265
1266 synchronized (this) {
1267 mService = m;
1268 notifyAll();
1269 }
1270
1271 synchronized (this) {
1272 while (!mReady) {
1273 try {
1274 wait();
1275 } catch (InterruptedException e) {
1276 }
1277 }
1278 }
1279
1280 Looper.loop();
1281 }
1282 }
1283
1284 static class BroadcastsBinder extends Binder {
1285 ActivityManagerService mActivityManagerService;
1286 BroadcastsBinder(ActivityManagerService activityManagerService) {
1287 mActivityManagerService = activityManagerService;
1288 }
1289
1290 @Override
1291 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1292 mActivityManagerService.dumpBroadcasts(pw);
1293 }
1294 }
1295
1296 static class ServicesBinder extends Binder {
1297 ActivityManagerService mActivityManagerService;
1298 ServicesBinder(ActivityManagerService activityManagerService) {
1299 mActivityManagerService = activityManagerService;
1300 }
1301
1302 @Override
1303 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1304 mActivityManagerService.dumpServices(pw);
1305 }
1306 }
1307
1308 static class SendersBinder extends Binder {
1309 ActivityManagerService mActivityManagerService;
1310 SendersBinder(ActivityManagerService activityManagerService) {
1311 mActivityManagerService = activityManagerService;
1312 }
1313
1314 @Override
1315 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1316 mActivityManagerService.dumpSenders(pw);
1317 }
1318 }
1319
1320 static class ProvidersBinder extends Binder {
1321 ActivityManagerService mActivityManagerService;
1322 ProvidersBinder(ActivityManagerService activityManagerService) {
1323 mActivityManagerService = activityManagerService;
1324 }
1325
1326 @Override
1327 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1328 mActivityManagerService.dumpProviders(pw);
1329 }
1330 }
1331
1332 static class MemBinder extends Binder {
1333 ActivityManagerService mActivityManagerService;
1334 MemBinder(ActivityManagerService activityManagerService) {
1335 mActivityManagerService = activityManagerService;
1336 }
1337
1338 @Override
1339 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1340 ActivityManagerService service = mActivityManagerService;
1341 ArrayList<ProcessRecord> procs;
1342 synchronized (mActivityManagerService) {
1343 if (args != null && args.length > 0
1344 && args[0].charAt(0) != '-') {
1345 procs = new ArrayList<ProcessRecord>();
1346 int pid = -1;
1347 try {
1348 pid = Integer.parseInt(args[0]);
1349 } catch (NumberFormatException e) {
1350
1351 }
1352 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1353 ProcessRecord proc = service.mLRUProcesses.get(i);
1354 if (proc.pid == pid) {
1355 procs.add(proc);
1356 } else if (proc.processName.equals(args[0])) {
1357 procs.add(proc);
1358 }
1359 }
1360 if (procs.size() <= 0) {
1361 pw.println("No process found for: " + args[0]);
1362 return;
1363 }
1364 } else {
1365 procs = service.mLRUProcesses;
1366 }
1367 }
1368 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1369 }
1370 }
1371
1372 static class CpuBinder extends Binder {
1373 ActivityManagerService mActivityManagerService;
1374 CpuBinder(ActivityManagerService activityManagerService) {
1375 mActivityManagerService = activityManagerService;
1376 }
1377
1378 @Override
1379 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1380 synchronized (mActivityManagerService.mProcessStatsThread) {
1381 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1382 }
1383 }
1384 }
1385
1386 private ActivityManagerService() {
1387 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1388 if (v != null && Integer.getInteger(v) != 0) {
1389 mSimpleProcessManagement = true;
1390 }
1391 v = System.getenv("ANDROID_DEBUG_APP");
1392 if (v != null) {
1393 mSimpleProcessManagement = true;
1394 }
1395
Dianne Hackborn2c6c5e62009-10-08 17:55:49 -07001396 Log.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());
1397
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398 MY_PID = Process.myPid();
1399
1400 File dataDir = Environment.getDataDirectory();
1401 File systemDir = new File(dataDir, "system");
1402 systemDir.mkdirs();
1403 mBatteryStatsService = new BatteryStatsService(new File(
1404 systemDir, "batterystats.bin").toString());
1405 mBatteryStatsService.getActiveStatistics().readLocked();
1406 mBatteryStatsService.getActiveStatistics().writeLocked();
1407
1408 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001409 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001410
Jack Palevichb90d28c2009-07-22 15:35:24 -07001411 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1412 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1413
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001414 mConfiguration.makeDefault();
1415 mProcessStats.init();
1416
1417 // Add ourself to the Watchdog monitors.
1418 Watchdog.getInstance().addMonitor(this);
1419
1420 // These values are set in system/rootdir/init.rc on startup.
1421 FOREGROUND_APP_ADJ =
1422 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1423 VISIBLE_APP_ADJ =
1424 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1425 SECONDARY_SERVER_ADJ =
1426 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001427 BACKUP_APP_ADJ =
1428 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001429 HOME_APP_ADJ =
1430 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001431 HIDDEN_APP_MIN_ADJ =
1432 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1433 CONTENT_PROVIDER_ADJ =
1434 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1435 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1436 EMPTY_APP_ADJ =
1437 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1438 FOREGROUND_APP_MEM =
1439 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1440 VISIBLE_APP_MEM =
1441 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1442 SECONDARY_SERVER_MEM =
1443 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001444 BACKUP_APP_MEM =
1445 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001446 HOME_APP_MEM =
1447 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001448 HIDDEN_APP_MEM =
1449 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1450 EMPTY_APP_MEM =
1451 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1452
1453 mProcessStatsThread = new Thread("ProcessStats") {
1454 public void run() {
1455 while (true) {
1456 try {
1457 try {
1458 synchronized(this) {
1459 final long now = SystemClock.uptimeMillis();
1460 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1461 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1462 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1463 // + ", write delay=" + nextWriteDelay);
1464 if (nextWriteDelay < nextCpuDelay) {
1465 nextCpuDelay = nextWriteDelay;
1466 }
1467 if (nextCpuDelay > 0) {
1468 this.wait(nextCpuDelay);
1469 }
1470 }
1471 } catch (InterruptedException e) {
1472 }
1473
1474 updateCpuStatsNow();
1475 } catch (Exception e) {
1476 Log.e(TAG, "Unexpected exception collecting process stats", e);
1477 }
1478 }
1479 }
1480 };
1481 mProcessStatsThread.start();
1482 }
1483
1484 @Override
1485 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1486 throws RemoteException {
1487 try {
1488 return super.onTransact(code, data, reply, flags);
1489 } catch (RuntimeException e) {
1490 // The activity manager only throws security exceptions, so let's
1491 // log all others.
1492 if (!(e instanceof SecurityException)) {
1493 Log.e(TAG, "Activity Manager Crash", e);
1494 }
1495 throw e;
1496 }
1497 }
1498
1499 void updateCpuStats() {
1500 synchronized (mProcessStatsThread) {
1501 final long now = SystemClock.uptimeMillis();
1502 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1503 mProcessStatsThread.notify();
1504 }
1505 }
1506 }
1507
1508 void updateCpuStatsNow() {
1509 synchronized (mProcessStatsThread) {
1510 final long now = SystemClock.uptimeMillis();
1511 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001512
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001513 if (MONITOR_CPU_USAGE &&
1514 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1515 mLastCpuTime = now;
1516 haveNewCpuStats = true;
1517 mProcessStats.update();
1518 //Log.i(TAG, mProcessStats.printCurrentState());
1519 //Log.i(TAG, "Total CPU usage: "
1520 // + mProcessStats.getTotalCpuPercent() + "%");
1521
1522 // Log the cpu usage if the property is set.
1523 if ("true".equals(SystemProperties.get("events.cpu"))) {
1524 int user = mProcessStats.getLastUserTime();
1525 int system = mProcessStats.getLastSystemTime();
1526 int iowait = mProcessStats.getLastIoWaitTime();
1527 int irq = mProcessStats.getLastIrqTime();
1528 int softIrq = mProcessStats.getLastSoftIrqTime();
1529 int idle = mProcessStats.getLastIdleTime();
1530
1531 int total = user + system + iowait + irq + softIrq + idle;
1532 if (total == 0) total = 1;
1533
Doug Zongker2bec3d42009-12-04 12:52:44 -08001534 EventLog.writeEvent(EventLogTags.CPU,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001535 ((user+system+iowait+irq+softIrq) * 100) / total,
1536 (user * 100) / total,
1537 (system * 100) / total,
1538 (iowait * 100) / total,
1539 (irq * 100) / total,
1540 (softIrq * 100) / total);
1541 }
1542 }
1543
Amith Yamasanie43530a2009-08-21 13:11:37 -07001544 long[] cpuSpeedTimes = mProcessStats.getLastCpuSpeedTimes();
Amith Yamasani819f9282009-06-24 23:18:15 -07001545 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001546 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001547 synchronized(mPidsSelfLocked) {
1548 if (haveNewCpuStats) {
1549 if (mBatteryStatsService.isOnBattery()) {
1550 final int N = mProcessStats.countWorkingStats();
1551 for (int i=0; i<N; i++) {
1552 ProcessStats.Stats st
1553 = mProcessStats.getWorkingStats(i);
1554 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1555 if (pr != null) {
1556 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1557 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001558 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001559 } else {
1560 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001561 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001562 if (ps != null) {
1563 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasanie43530a2009-08-21 13:11:37 -07001564 ps.addSpeedStepTimes(cpuSpeedTimes);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001565 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001566 }
1567 }
1568 }
1569 }
1570 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001571
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001572 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1573 mLastWriteTime = now;
1574 mBatteryStatsService.getActiveStatistics().writeLocked();
1575 }
1576 }
1577 }
1578 }
1579
1580 /**
1581 * Initialize the application bind args. These are passed to each
1582 * process when the bindApplication() IPC is sent to the process. They're
1583 * lazily setup to make sure the services are running when they're asked for.
1584 */
1585 private HashMap<String, IBinder> getCommonServicesLocked() {
1586 if (mAppBindArgs == null) {
1587 mAppBindArgs = new HashMap<String, IBinder>();
1588
1589 // Setup the application init args
1590 mAppBindArgs.put("package", ServiceManager.getService("package"));
1591 mAppBindArgs.put("window", ServiceManager.getService("window"));
1592 mAppBindArgs.put(Context.ALARM_SERVICE,
1593 ServiceManager.getService(Context.ALARM_SERVICE));
1594 }
1595 return mAppBindArgs;
1596 }
1597
1598 private final void setFocusedActivityLocked(HistoryRecord r) {
1599 if (mFocusedActivity != r) {
1600 mFocusedActivity = r;
1601 mWindowManager.setFocusedApp(r, true);
1602 }
1603 }
1604
1605 private final void updateLRUListLocked(ProcessRecord app,
1606 boolean oomAdj) {
1607 // put it on the LRU to keep track of when it should be exited.
1608 int lrui = mLRUProcesses.indexOf(app);
1609 if (lrui >= 0) mLRUProcesses.remove(lrui);
1610 mLRUProcesses.add(app);
1611 //Log.i(TAG, "Putting proc to front: " + app.processName);
1612 if (oomAdj) {
1613 updateOomAdjLocked();
1614 }
1615 }
1616
1617 private final boolean updateLRUListLocked(HistoryRecord r) {
1618 final boolean hadit = mLRUActivities.remove(r);
1619 mLRUActivities.add(r);
1620 return hadit;
1621 }
1622
1623 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1624 int i = mHistory.size()-1;
1625 while (i >= 0) {
1626 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1627 if (!r.finishing && r != notTop) {
1628 return r;
1629 }
1630 i--;
1631 }
1632 return null;
1633 }
1634
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001635 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1636 int i = mHistory.size()-1;
1637 while (i >= 0) {
1638 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1639 if (!r.finishing && !r.delayedResume && r != notTop) {
1640 return r;
1641 }
1642 i--;
1643 }
1644 return null;
1645 }
1646
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001647 /**
1648 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001649 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001650 *
1651 * @param token If non-null, any history records matching this token will be skipped.
1652 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1653 *
1654 * @return Returns the HistoryRecord of the next activity on the stack.
1655 */
1656 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1657 int i = mHistory.size()-1;
1658 while (i >= 0) {
1659 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1660 // Note: the taskId check depends on real taskId fields being non-zero
1661 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1662 return r;
1663 }
1664 i--;
1665 }
1666 return null;
1667 }
1668
1669 private final ProcessRecord getProcessRecordLocked(
1670 String processName, int uid) {
1671 if (uid == Process.SYSTEM_UID) {
1672 // The system gets to run in any process. If there are multiple
1673 // processes with the same uid, just pick the first (this
1674 // should never happen).
1675 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1676 processName);
1677 return procs != null ? procs.valueAt(0) : null;
1678 }
1679 ProcessRecord proc = mProcessNames.get(processName, uid);
1680 return proc;
1681 }
1682
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001683 private void ensurePackageDexOpt(String packageName) {
1684 IPackageManager pm = ActivityThread.getPackageManager();
1685 try {
1686 if (pm.performDexOpt(packageName)) {
1687 mDidDexOpt = true;
1688 }
1689 } catch (RemoteException e) {
1690 }
1691 }
1692
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001693 private boolean isNextTransitionForward() {
1694 int transit = mWindowManager.getPendingAppTransition();
1695 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1696 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1697 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1698 }
1699
1700 private final boolean realStartActivityLocked(HistoryRecord r,
1701 ProcessRecord app, boolean andResume, boolean checkConfig)
1702 throws RemoteException {
1703
1704 r.startFreezingScreenLocked(app, 0);
1705 mWindowManager.setAppVisibility(r, true);
1706
1707 // Have the window manager re-evaluate the orientation of
1708 // the screen based on the new activity order. Note that
1709 // as a result of this, it can call back into the activity
1710 // manager with a new orientation. We don't care about that,
1711 // because the activity is not currently running so we are
1712 // just restarting it anyway.
1713 if (checkConfig) {
1714 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001715 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001716 r.mayFreezeScreenLocked(app) ? r : null);
1717 updateConfigurationLocked(config, r);
1718 }
1719
1720 r.app = app;
1721
1722 if (localLOGV) Log.v(TAG, "Launching: " + r);
1723
1724 int idx = app.activities.indexOf(r);
1725 if (idx < 0) {
1726 app.activities.add(r);
1727 }
1728 updateLRUListLocked(app, true);
1729
1730 try {
1731 if (app.thread == null) {
1732 throw new RemoteException();
1733 }
1734 List<ResultInfo> results = null;
1735 List<Intent> newIntents = null;
1736 if (andResume) {
1737 results = r.results;
1738 newIntents = r.newIntents;
1739 }
1740 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1741 + " icicle=" + r.icicle
1742 + " with results=" + results + " newIntents=" + newIntents
1743 + " andResume=" + andResume);
1744 if (andResume) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08001745 EventLog.writeEvent(EventLogTags.AM_RESTART_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001746 System.identityHashCode(r),
1747 r.task.taskId, r.shortComponentName);
1748 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001749 if (r.isHomeActivity) {
1750 mHomeProcess = app;
1751 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001752 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001753 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001754 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001755 r.info, r.icicle, results, newIntents, !andResume,
1756 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001757 } catch (RemoteException e) {
1758 if (r.launchFailed) {
1759 // This is the second time we failed -- finish activity
1760 // and give up.
1761 Log.e(TAG, "Second failure launching "
1762 + r.intent.getComponent().flattenToShortString()
1763 + ", giving up", e);
1764 appDiedLocked(app, app.pid, app.thread);
1765 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1766 "2nd-crash");
1767 return false;
1768 }
1769
1770 // This is the first time we failed -- restart process and
1771 // retry.
1772 app.activities.remove(r);
1773 throw e;
1774 }
1775
1776 r.launchFailed = false;
1777 if (updateLRUListLocked(r)) {
1778 Log.w(TAG, "Activity " + r
1779 + " being launched, but already in LRU list");
1780 }
1781
1782 if (andResume) {
1783 // As part of the process of launching, ActivityThread also performs
1784 // a resume.
1785 r.state = ActivityState.RESUMED;
1786 r.icicle = null;
1787 r.haveState = false;
1788 r.stopped = false;
1789 mResumedActivity = r;
1790 r.task.touchActiveTime();
1791 completeResumeLocked(r);
1792 pauseIfSleepingLocked();
1793 } else {
1794 // This activity is not starting in the resumed state... which
1795 // should look like we asked it to pause+stop (but remain visible),
1796 // and it has done so and reported back the current icicle and
1797 // other state.
1798 r.state = ActivityState.STOPPED;
1799 r.stopped = true;
1800 }
1801
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001802 // Launch the new version setup screen if needed. We do this -after-
1803 // launching the initial activity (that is, home), so that it can have
1804 // a chance to initialize itself while in the background, making the
1805 // switch back to it faster and look better.
1806 startSetupActivityLocked();
1807
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001808 return true;
1809 }
1810
1811 private final void startSpecificActivityLocked(HistoryRecord r,
1812 boolean andResume, boolean checkConfig) {
1813 // Is this activity's application already running?
1814 ProcessRecord app = getProcessRecordLocked(r.processName,
1815 r.info.applicationInfo.uid);
1816
1817 if (r.startTime == 0) {
1818 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001819 if (mInitialStartTime == 0) {
1820 mInitialStartTime = r.startTime;
1821 }
1822 } else if (mInitialStartTime == 0) {
1823 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001824 }
1825
1826 if (app != null && app.thread != null) {
1827 try {
1828 realStartActivityLocked(r, app, andResume, checkConfig);
1829 return;
1830 } catch (RemoteException e) {
1831 Log.w(TAG, "Exception when starting activity "
1832 + r.intent.getComponent().flattenToShortString(), e);
1833 }
1834
1835 // If a dead object exception was thrown -- fall through to
1836 // restart the application.
1837 }
1838
1839 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001840 "activity", r.intent.getComponent(), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001841 }
1842
1843 private final ProcessRecord startProcessLocked(String processName,
1844 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001845 String hostingType, ComponentName hostingName, boolean allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001846 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1847 // We don't have to do anything more if:
1848 // (1) There is an existing application record; and
1849 // (2) The caller doesn't think it is dead, OR there is no thread
1850 // object attached to it so we know it couldn't have crashed; and
1851 // (3) There is a pid assigned to it, so it is either starting or
1852 // already running.
1853 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1854 + " app=" + app + " knownToBeDead=" + knownToBeDead
1855 + " thread=" + (app != null ? app.thread : null)
1856 + " pid=" + (app != null ? app.pid : -1));
1857 if (app != null &&
1858 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1859 return app;
1860 }
1861
1862 String hostingNameStr = hostingName != null
1863 ? hostingName.flattenToShortString() : null;
1864
1865 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1866 // If we are in the background, then check to see if this process
1867 // is bad. If so, we will just silently fail.
1868 if (mBadProcesses.get(info.processName, info.uid) != null) {
1869 return null;
1870 }
1871 } else {
1872 // When the user is explicitly starting a process, then clear its
1873 // crash count so that we won't make it bad until they see at
1874 // least one crash dialog again, and make the process good again
1875 // if it had been bad.
1876 mProcessCrashTimes.remove(info.processName, info.uid);
1877 if (mBadProcesses.get(info.processName, info.uid) != null) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08001878 EventLog.writeEvent(EventLogTags.AM_PROC_GOOD, info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001879 info.processName);
1880 mBadProcesses.remove(info.processName, info.uid);
1881 if (app != null) {
1882 app.bad = false;
1883 }
1884 }
1885 }
1886
1887 if (app == null) {
1888 app = newProcessRecordLocked(null, info, processName);
1889 mProcessNames.put(processName, info.uid, app);
1890 } else {
1891 // If this is a new package in the process, add the package to the list
1892 app.addPackage(info.packageName);
1893 }
1894
1895 // If the system is not ready yet, then hold off on starting this
1896 // process until it is.
1897 if (!mSystemReady
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001898 && !isAllowedWhileBooting(info)
1899 && !allowWhileBooting) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001900 if (!mProcessesOnHold.contains(app)) {
1901 mProcessesOnHold.add(app);
1902 }
1903 return app;
1904 }
1905
1906 startProcessLocked(app, hostingType, hostingNameStr);
1907 return (app.pid != 0) ? app : null;
1908 }
1909
Dianne Hackborn9acc0302009-08-25 00:27:12 -07001910 boolean isAllowedWhileBooting(ApplicationInfo ai) {
1911 return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
1912 }
1913
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001914 private final void startProcessLocked(ProcessRecord app,
1915 String hostingType, String hostingNameStr) {
1916 if (app.pid > 0 && app.pid != MY_PID) {
1917 synchronized (mPidsSelfLocked) {
1918 mPidsSelfLocked.remove(app.pid);
1919 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1920 }
1921 app.pid = 0;
1922 }
1923
1924 mProcessesOnHold.remove(app);
1925
1926 updateCpuStats();
1927
1928 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1929 mProcDeaths[0] = 0;
1930
1931 try {
1932 int uid = app.info.uid;
1933 int[] gids = null;
1934 try {
1935 gids = mContext.getPackageManager().getPackageGids(
1936 app.info.packageName);
1937 } catch (PackageManager.NameNotFoundException e) {
1938 Log.w(TAG, "Unable to retrieve gids", e);
1939 }
1940 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1941 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1942 && mTopComponent != null
1943 && app.processName.equals(mTopComponent.getPackageName())) {
1944 uid = 0;
1945 }
1946 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1947 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1948 uid = 0;
1949 }
1950 }
1951 int debugFlags = 0;
1952 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1953 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1954 }
1955 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1956 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1957 }
1958 if ("1".equals(SystemProperties.get("debug.assert"))) {
1959 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1960 }
1961 int pid = Process.start("android.app.ActivityThread",
1962 mSimpleProcessManagement ? app.processName : null, uid, uid,
1963 gids, debugFlags, null);
1964 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1965 synchronized (bs) {
1966 if (bs.isOnBattery()) {
1967 app.batteryStats.incStartsLocked();
1968 }
1969 }
1970
Doug Zongker2bec3d42009-12-04 12:52:44 -08001971 EventLog.writeEvent(EventLogTags.AM_PROC_START, pid, uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001972 app.processName, hostingType,
1973 hostingNameStr != null ? hostingNameStr : "");
1974
1975 if (app.persistent) {
1976 Watchdog.getInstance().processStarted(app, app.processName, pid);
1977 }
1978
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001979 StringBuilder buf = mStringBuilder;
1980 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001981 buf.append("Start proc ");
1982 buf.append(app.processName);
1983 buf.append(" for ");
1984 buf.append(hostingType);
1985 if (hostingNameStr != null) {
1986 buf.append(" ");
1987 buf.append(hostingNameStr);
1988 }
1989 buf.append(": pid=");
1990 buf.append(pid);
1991 buf.append(" uid=");
1992 buf.append(uid);
1993 buf.append(" gids={");
1994 if (gids != null) {
1995 for (int gi=0; gi<gids.length; gi++) {
1996 if (gi != 0) buf.append(", ");
1997 buf.append(gids[gi]);
1998
1999 }
2000 }
2001 buf.append("}");
2002 Log.i(TAG, buf.toString());
2003 if (pid == 0 || pid == MY_PID) {
2004 // Processes are being emulated with threads.
2005 app.pid = MY_PID;
2006 app.removed = false;
2007 mStartingProcesses.add(app);
2008 } else if (pid > 0) {
2009 app.pid = pid;
2010 app.removed = false;
2011 synchronized (mPidsSelfLocked) {
2012 this.mPidsSelfLocked.put(pid, app);
2013 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2014 msg.obj = app;
2015 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2016 }
2017 } else {
2018 app.pid = 0;
2019 RuntimeException e = new RuntimeException(
2020 "Failure starting process " + app.processName
2021 + ": returned pid=" + pid);
2022 Log.e(TAG, e.getMessage(), e);
2023 }
2024 } catch (RuntimeException e) {
2025 // XXX do better error recovery.
2026 app.pid = 0;
2027 Log.e(TAG, "Failure starting process " + app.processName, e);
2028 }
2029 }
2030
2031 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2032 if (mPausingActivity != null) {
2033 RuntimeException e = new RuntimeException();
2034 Log.e(TAG, "Trying to pause when pause is already pending for "
2035 + mPausingActivity, e);
2036 }
2037 HistoryRecord prev = mResumedActivity;
2038 if (prev == null) {
2039 RuntimeException e = new RuntimeException();
2040 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2041 resumeTopActivityLocked(null);
2042 return;
2043 }
2044 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2045 mResumedActivity = null;
2046 mPausingActivity = prev;
2047 mLastPausedActivity = prev;
2048 prev.state = ActivityState.PAUSING;
2049 prev.task.touchActiveTime();
2050
2051 updateCpuStats();
2052
2053 if (prev.app != null && prev.app.thread != null) {
2054 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2055 try {
Doug Zongker2bec3d42009-12-04 12:52:44 -08002056 EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002057 System.identityHashCode(prev),
2058 prev.shortComponentName);
2059 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2060 prev.configChangeFlags);
2061 updateUsageStats(prev, false);
2062 } catch (Exception e) {
2063 // Ignore exception, if process died other code will cleanup.
2064 Log.w(TAG, "Exception thrown during pause", e);
2065 mPausingActivity = null;
2066 mLastPausedActivity = null;
2067 }
2068 } else {
2069 mPausingActivity = null;
2070 mLastPausedActivity = null;
2071 }
2072
2073 // If we are not going to sleep, we want to ensure the device is
2074 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002075 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002076 mLaunchingActivity.acquire();
2077 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2078 // To be safe, don't allow the wake lock to be held for too long.
2079 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2080 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2081 }
2082 }
2083
2084
2085 if (mPausingActivity != null) {
2086 // Have the window manager pause its key dispatching until the new
2087 // activity has started. If we're pausing the activity just because
2088 // the screen is being turned off and the UI is sleeping, don't interrupt
2089 // key dispatch; the same activity will pick it up again on wakeup.
2090 if (!uiSleeping) {
2091 prev.pauseKeyDispatchingLocked();
2092 } else {
2093 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2094 }
2095
2096 // Schedule a pause timeout in case the app doesn't respond.
2097 // We don't give it much time because this directly impacts the
2098 // responsiveness seen by the user.
2099 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2100 msg.obj = prev;
2101 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2102 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2103 } else {
2104 // This activity failed to schedule the
2105 // pause, so just treat it as being paused now.
2106 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2107 resumeTopActivityLocked(null);
2108 }
2109 }
2110
2111 private final void completePauseLocked() {
2112 HistoryRecord prev = mPausingActivity;
2113 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2114
2115 if (prev != null) {
2116 if (prev.finishing) {
2117 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2118 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2119 } else if (prev.app != null) {
2120 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2121 if (prev.waitingVisible) {
2122 prev.waitingVisible = false;
2123 mWaitingVisibleActivities.remove(prev);
2124 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2125 TAG, "Complete pause, no longer waiting: " + prev);
2126 }
2127 if (prev.configDestroy) {
2128 // The previous is being paused because the configuration
2129 // is changing, which means it is actually stopping...
2130 // To juggle the fact that we are also starting a new
2131 // instance right now, we need to first completely stop
2132 // the current instance before starting the new one.
2133 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2134 destroyActivityLocked(prev, true);
2135 } else {
2136 mStoppingActivities.add(prev);
2137 if (mStoppingActivities.size() > 3) {
2138 // If we already have a few activities waiting to stop,
2139 // then give up on things going idle and start clearing
2140 // them out.
2141 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2142 Message msg = Message.obtain();
2143 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2144 mHandler.sendMessage(msg);
2145 }
2146 }
2147 } else {
2148 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2149 prev = null;
2150 }
2151 mPausingActivity = null;
2152 }
2153
Dianne Hackborn55280a92009-05-07 15:53:46 -07002154 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002155 resumeTopActivityLocked(prev);
2156 } else {
2157 if (mGoingToSleep.isHeld()) {
2158 mGoingToSleep.release();
2159 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002160 if (mShuttingDown) {
2161 notifyAll();
2162 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002163 }
2164
2165 if (prev != null) {
2166 prev.resumeKeyDispatchingLocked();
2167 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002168
2169 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2170 long diff = 0;
2171 synchronized (mProcessStatsThread) {
2172 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2173 }
2174 if (diff > 0) {
2175 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2176 synchronized (bsi) {
2177 BatteryStatsImpl.Uid.Proc ps =
2178 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2179 prev.info.packageName);
2180 if (ps != null) {
2181 ps.addForegroundTimeLocked(diff);
2182 }
2183 }
2184 }
2185 }
2186 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002187 }
2188
2189 /**
2190 * Once we know that we have asked an application to put an activity in
2191 * the resumed state (either by launching it or explicitly telling it),
2192 * this function updates the rest of our state to match that fact.
2193 */
2194 private final void completeResumeLocked(HistoryRecord next) {
2195 next.idle = false;
2196 next.results = null;
2197 next.newIntents = null;
2198
2199 // schedule an idle timeout in case the app doesn't do it for us.
2200 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2201 msg.obj = next;
2202 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2203
2204 if (false) {
2205 // The activity was never told to pause, so just keep
2206 // things going as-is. To maintain our own state,
2207 // we need to emulate it coming back and saying it is
2208 // idle.
2209 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2210 msg.obj = next;
2211 mHandler.sendMessage(msg);
2212 }
2213
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002214 reportResumedActivityLocked(next);
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002215
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002216 next.thumbnail = null;
2217 setFocusedActivityLocked(next);
2218 next.resumeKeyDispatchingLocked();
2219 ensureActivitiesVisibleLocked(null, 0);
2220 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002221 mNoAnimActivities.clear();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002222
2223 // Mark the point when the activity is resuming
2224 // TODO: To be more accurate, the mark should be before the onCreate,
2225 // not after the onResume. But for subsequent starts, onResume is fine.
2226 if (next.app != null) {
2227 synchronized (mProcessStatsThread) {
2228 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2229 }
2230 } else {
2231 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2232 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002233 }
2234
2235 /**
2236 * Make sure that all activities that need to be visible (that is, they
2237 * currently can be seen by the user) actually are.
2238 */
2239 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2240 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2241 if (DEBUG_VISBILITY) Log.v(
2242 TAG, "ensureActivitiesVisible behind " + top
2243 + " configChanges=0x" + Integer.toHexString(configChanges));
2244
2245 // If the top activity is not fullscreen, then we need to
2246 // make sure any activities under it are now visible.
2247 final int count = mHistory.size();
2248 int i = count-1;
2249 while (mHistory.get(i) != top) {
2250 i--;
2251 }
2252 HistoryRecord r;
2253 boolean behindFullscreen = false;
2254 for (; i>=0; i--) {
2255 r = (HistoryRecord)mHistory.get(i);
2256 if (DEBUG_VISBILITY) Log.v(
2257 TAG, "Make visible? " + r + " finishing=" + r.finishing
2258 + " state=" + r.state);
2259 if (r.finishing) {
2260 continue;
2261 }
2262
2263 final boolean doThisProcess = onlyThisProcess == null
2264 || onlyThisProcess.equals(r.processName);
2265
2266 // First: if this is not the current activity being started, make
2267 // sure it matches the current configuration.
2268 if (r != starting && doThisProcess) {
2269 ensureActivityConfigurationLocked(r, 0);
2270 }
2271
2272 if (r.app == null || r.app.thread == null) {
2273 if (onlyThisProcess == null
2274 || onlyThisProcess.equals(r.processName)) {
2275 // This activity needs to be visible, but isn't even
2276 // running... get it started, but don't resume it
2277 // at this point.
2278 if (DEBUG_VISBILITY) Log.v(
2279 TAG, "Start and freeze screen for " + r);
2280 if (r != starting) {
2281 r.startFreezingScreenLocked(r.app, configChanges);
2282 }
2283 if (!r.visible) {
2284 if (DEBUG_VISBILITY) Log.v(
2285 TAG, "Starting and making visible: " + r);
2286 mWindowManager.setAppVisibility(r, true);
2287 }
2288 if (r != starting) {
2289 startSpecificActivityLocked(r, false, false);
2290 }
2291 }
2292
2293 } else if (r.visible) {
2294 // If this activity is already visible, then there is nothing
2295 // else to do here.
2296 if (DEBUG_VISBILITY) Log.v(
2297 TAG, "Skipping: already visible at " + r);
2298 r.stopFreezingScreenLocked(false);
2299
2300 } else if (onlyThisProcess == null) {
2301 // This activity is not currently visible, but is running.
2302 // Tell it to become visible.
2303 r.visible = true;
2304 if (r.state != ActivityState.RESUMED && r != starting) {
2305 // If this activity is paused, tell it
2306 // to now show its window.
2307 if (DEBUG_VISBILITY) Log.v(
2308 TAG, "Making visible and scheduling visibility: " + r);
2309 try {
2310 mWindowManager.setAppVisibility(r, true);
2311 r.app.thread.scheduleWindowVisibility(r, true);
2312 r.stopFreezingScreenLocked(false);
2313 } catch (Exception e) {
2314 // Just skip on any failure; we'll make it
2315 // visible when it next restarts.
2316 Log.w(TAG, "Exception thrown making visibile: "
2317 + r.intent.getComponent(), e);
2318 }
2319 }
2320 }
2321
2322 // Aggregate current change flags.
2323 configChanges |= r.configChangeFlags;
2324
2325 if (r.fullscreen) {
2326 // At this point, nothing else needs to be shown
2327 if (DEBUG_VISBILITY) Log.v(
2328 TAG, "Stopping: fullscreen at " + r);
2329 behindFullscreen = true;
2330 i--;
2331 break;
2332 }
2333 }
2334
2335 // Now for any activities that aren't visible to the user, make
2336 // sure they no longer are keeping the screen frozen.
2337 while (i >= 0) {
2338 r = (HistoryRecord)mHistory.get(i);
2339 if (DEBUG_VISBILITY) Log.v(
2340 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2341 + " state=" + r.state
2342 + " behindFullscreen=" + behindFullscreen);
2343 if (!r.finishing) {
2344 if (behindFullscreen) {
2345 if (r.visible) {
2346 if (DEBUG_VISBILITY) Log.v(
2347 TAG, "Making invisible: " + r);
2348 r.visible = false;
2349 try {
2350 mWindowManager.setAppVisibility(r, false);
2351 if ((r.state == ActivityState.STOPPING
2352 || r.state == ActivityState.STOPPED)
2353 && r.app != null && r.app.thread != null) {
2354 if (DEBUG_VISBILITY) Log.v(
2355 TAG, "Scheduling invisibility: " + r);
2356 r.app.thread.scheduleWindowVisibility(r, false);
2357 }
2358 } catch (Exception e) {
2359 // Just skip on any failure; we'll make it
2360 // visible when it next restarts.
2361 Log.w(TAG, "Exception thrown making hidden: "
2362 + r.intent.getComponent(), e);
2363 }
2364 } else {
2365 if (DEBUG_VISBILITY) Log.v(
2366 TAG, "Already invisible: " + r);
2367 }
2368 } else if (r.fullscreen) {
2369 if (DEBUG_VISBILITY) Log.v(
2370 TAG, "Now behindFullscreen: " + r);
2371 behindFullscreen = true;
2372 }
2373 }
2374 i--;
2375 }
2376 }
2377
2378 /**
2379 * Version of ensureActivitiesVisible that can easily be called anywhere.
2380 */
2381 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2382 int configChanges) {
2383 HistoryRecord r = topRunningActivityLocked(null);
2384 if (r != null) {
2385 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2386 }
2387 }
2388
2389 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2390 if (resumed) {
2391 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2392 } else {
2393 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2394 }
2395 }
2396
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002397 private boolean startHomeActivityLocked() {
2398 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2399 && mTopAction == null) {
2400 // We are running in factory test mode, but unable to find
2401 // the factory test app, so just sit around displaying the
2402 // error message and don't try to start anything.
2403 return false;
2404 }
2405 Intent intent = new Intent(
2406 mTopAction,
2407 mTopData != null ? Uri.parse(mTopData) : null);
2408 intent.setComponent(mTopComponent);
2409 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2410 intent.addCategory(Intent.CATEGORY_HOME);
2411 }
2412 ActivityInfo aInfo =
2413 intent.resolveActivityInfo(mContext.getPackageManager(),
2414 STOCK_PM_FLAGS);
2415 if (aInfo != null) {
2416 intent.setComponent(new ComponentName(
2417 aInfo.applicationInfo.packageName, aInfo.name));
2418 // Don't do this if the home app is currently being
2419 // instrumented.
2420 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2421 aInfo.applicationInfo.uid);
2422 if (app == null || app.instrumentationClass == null) {
2423 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2424 startActivityLocked(null, intent, null, null, 0, aInfo,
2425 null, null, 0, 0, 0, false, false);
2426 }
2427 }
2428
2429
2430 return true;
2431 }
2432
2433 /**
2434 * Starts the "new version setup screen" if appropriate.
2435 */
2436 private void startSetupActivityLocked() {
2437 // Only do this once per boot.
2438 if (mCheckedForSetup) {
2439 return;
2440 }
2441
2442 // We will show this screen if the current one is a different
2443 // version than the last one shown, and we are not running in
2444 // low-level factory test mode.
2445 final ContentResolver resolver = mContext.getContentResolver();
2446 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2447 Settings.Secure.getInt(resolver,
2448 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2449 mCheckedForSetup = true;
2450
2451 // See if we should be showing the platform update setup UI.
2452 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2453 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2454 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2455
2456 // We don't allow third party apps to replace this.
2457 ResolveInfo ri = null;
2458 for (int i=0; ris != null && i<ris.size(); i++) {
2459 if ((ris.get(i).activityInfo.applicationInfo.flags
2460 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2461 ri = ris.get(i);
2462 break;
2463 }
2464 }
2465
2466 if (ri != null) {
2467 String vers = ri.activityInfo.metaData != null
2468 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2469 : null;
2470 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2471 vers = ri.activityInfo.applicationInfo.metaData.getString(
2472 Intent.METADATA_SETUP_VERSION);
2473 }
2474 String lastVers = Settings.Secure.getString(
2475 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2476 if (vers != null && !vers.equals(lastVers)) {
2477 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2478 intent.setComponent(new ComponentName(
2479 ri.activityInfo.packageName, ri.activityInfo.name));
2480 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2481 null, null, 0, 0, 0, false, false);
2482 }
2483 }
2484 }
2485 }
2486
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -07002487 private void reportResumedActivityLocked(HistoryRecord r) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002488 //Log.i(TAG, "**** REPORT RESUME: " + r);
2489
2490 final int identHash = System.identityHashCode(r);
2491 updateUsageStats(r, true);
2492
2493 int i = mWatchers.beginBroadcast();
2494 while (i > 0) {
2495 i--;
2496 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2497 if (w != null) {
2498 try {
2499 w.activityResuming(identHash);
2500 } catch (RemoteException e) {
2501 }
2502 }
2503 }
2504 mWatchers.finishBroadcast();
2505 }
2506
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002507 /**
2508 * Ensure that the top activity in the stack is resumed.
2509 *
2510 * @param prev The previously resumed activity, for when in the process
2511 * of pausing; can be null to call from elsewhere.
2512 *
2513 * @return Returns true if something is being resumed, or false if
2514 * nothing happened.
2515 */
2516 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2517 // Find the first activity that is not finishing.
2518 HistoryRecord next = topRunningActivityLocked(null);
2519
2520 // Remember how we'll process this pause/resume situation, and ensure
2521 // that the state is reset however we wind up proceeding.
2522 final boolean userLeaving = mUserLeaving;
2523 mUserLeaving = false;
2524
2525 if (next == null) {
2526 // There are no more activities! Let's just start up the
2527 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002528 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002529 }
2530
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002531 next.delayedResume = false;
2532
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002533 // If the top activity is the resumed one, nothing to do.
2534 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2535 // Make sure we have executed any pending transitions, since there
2536 // should be nothing left to do at this point.
2537 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002538 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002539 return false;
2540 }
2541
2542 // If we are sleeping, and there is no resumed activity, and the top
2543 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002544 if ((mSleeping || mShuttingDown)
2545 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002546 // Make sure we have executed any pending transitions, since there
2547 // should be nothing left to do at this point.
2548 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002549 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002550 return false;
2551 }
2552
2553 // The activity may be waiting for stop, but that is no longer
2554 // appropriate for it.
2555 mStoppingActivities.remove(next);
2556 mWaitingVisibleActivities.remove(next);
2557
2558 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2559
2560 // If we are currently pausing an activity, then don't do anything
2561 // until that is done.
2562 if (mPausingActivity != null) {
2563 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2564 return false;
2565 }
2566
2567 // We need to start pausing the current activity so the top one
2568 // can be resumed...
2569 if (mResumedActivity != null) {
2570 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2571 startPausingLocked(userLeaving, false);
2572 return true;
2573 }
2574
2575 if (prev != null && prev != next) {
2576 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2577 prev.waitingVisible = true;
2578 mWaitingVisibleActivities.add(prev);
2579 if (DEBUG_SWITCH) Log.v(
2580 TAG, "Resuming top, waiting visible to hide: " + prev);
2581 } else {
2582 // The next activity is already visible, so hide the previous
2583 // activity's windows right now so we can show the new one ASAP.
2584 // We only do this if the previous is finishing, which should mean
2585 // it is on top of the one being resumed so hiding it quickly
2586 // is good. Otherwise, we want to do the normal route of allowing
2587 // the resumed activity to be shown so we can decide if the
2588 // previous should actually be hidden depending on whether the
2589 // new one is found to be full-screen or not.
2590 if (prev.finishing) {
2591 mWindowManager.setAppVisibility(prev, false);
2592 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2593 + prev + ", waitingVisible="
2594 + (prev != null ? prev.waitingVisible : null)
2595 + ", nowVisible=" + next.nowVisible);
2596 } else {
2597 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2598 + prev + ", waitingVisible="
2599 + (prev != null ? prev.waitingVisible : null)
2600 + ", nowVisible=" + next.nowVisible);
2601 }
2602 }
2603 }
2604
2605 // We are starting up the next activity, so tell the window manager
2606 // that the previous one will be hidden soon. This way it can know
2607 // to ignore it when computing the desired screen orientation.
2608 if (prev != null) {
2609 if (prev.finishing) {
2610 if (DEBUG_TRANSITION) Log.v(TAG,
2611 "Prepare close transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002612 if (mNoAnimActivities.contains(prev)) {
2613 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2614 } else {
2615 mWindowManager.prepareAppTransition(prev.task == next.task
2616 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2617 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2618 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002619 mWindowManager.setAppWillBeHidden(prev);
2620 mWindowManager.setAppVisibility(prev, false);
2621 } else {
2622 if (DEBUG_TRANSITION) Log.v(TAG,
2623 "Prepare open transition: prev=" + prev);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002624 if (mNoAnimActivities.contains(next)) {
2625 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2626 } else {
2627 mWindowManager.prepareAppTransition(prev.task == next.task
2628 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2629 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2630 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002631 }
2632 if (false) {
2633 mWindowManager.setAppWillBeHidden(prev);
2634 mWindowManager.setAppVisibility(prev, false);
2635 }
2636 } else if (mHistory.size() > 1) {
2637 if (DEBUG_TRANSITION) Log.v(TAG,
2638 "Prepare open transition: no previous");
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002639 if (mNoAnimActivities.contains(next)) {
2640 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2641 } else {
2642 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2643 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002644 }
2645
2646 if (next.app != null && next.app.thread != null) {
2647 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2648
2649 // This activity is now becoming visible.
2650 mWindowManager.setAppVisibility(next, true);
2651
2652 HistoryRecord lastResumedActivity = mResumedActivity;
2653 ActivityState lastState = next.state;
2654
2655 updateCpuStats();
2656
2657 next.state = ActivityState.RESUMED;
2658 mResumedActivity = next;
2659 next.task.touchActiveTime();
2660 updateLRUListLocked(next.app, true);
2661 updateLRUListLocked(next);
2662
2663 // Have the window manager re-evaluate the orientation of
2664 // the screen based on the new activity order.
Eric Fischerd4d04de2009-10-27 18:55:57 -07002665 boolean updated;
2666 synchronized (this) {
2667 Configuration config = mWindowManager.updateOrientationFromAppTokens(
2668 mConfiguration,
2669 next.mayFreezeScreenLocked(next.app) ? next : null);
2670 if (config != null) {
2671 /*
2672 * Explicitly restore the locale to the one from the
2673 * old configuration, since the one that comes back from
2674 * the window manager has the default (boot) locale.
2675 *
2676 * It looks like previously the locale picker only worked
2677 * by coincidence: usually it would do its setting of
2678 * the locale after the activity transition, so it didn't
2679 * matter that this lost it. With the synchronized
2680 * block now keeping them from happening at the same time,
2681 * this one always would happen second and undo what the
2682 * locale picker had just done.
2683 */
2684 config.locale = mConfiguration.locale;
2685 next.frozenBeforeDestroy = true;
2686 }
2687 updated = updateConfigurationLocked(config, next);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002688 }
Eric Fischerd4d04de2009-10-27 18:55:57 -07002689 if (!updated) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002690 // The configuration update wasn't able to keep the existing
2691 // instance of the activity, and instead started a new one.
2692 // We should be all done, but let's just make sure our activity
2693 // is still at the top and schedule another run if something
2694 // weird happened.
2695 HistoryRecord nextNext = topRunningActivityLocked(null);
2696 if (DEBUG_SWITCH) Log.i(TAG,
2697 "Activity config changed during resume: " + next
2698 + ", new next: " + nextNext);
2699 if (nextNext != next) {
2700 // Do over!
2701 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2702 }
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07002703 setFocusedActivityLocked(next);
2704 ensureActivitiesVisibleLocked(null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002705 mWindowManager.executeAppTransition();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002706 mNoAnimActivities.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002707 return true;
2708 }
2709
2710 try {
2711 // Deliver all pending results.
2712 ArrayList a = next.results;
2713 if (a != null) {
2714 final int N = a.size();
2715 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002716 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002717 TAG, "Delivering results to " + next
2718 + ": " + a);
2719 next.app.thread.scheduleSendResult(next, a);
2720 }
2721 }
2722
2723 if (next.newIntents != null) {
2724 next.app.thread.scheduleNewIntent(next.newIntents, next);
2725 }
2726
Doug Zongker2bec3d42009-12-04 12:52:44 -08002727 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002728 System.identityHashCode(next),
2729 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002730
2731 next.app.thread.scheduleResumeActivity(next,
2732 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002733
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002734 pauseIfSleepingLocked();
2735
2736 } catch (Exception e) {
2737 // Whoops, need to restart this activity!
2738 next.state = lastState;
2739 mResumedActivity = lastResumedActivity;
2740 if (Config.LOGD) Log.d(TAG,
2741 "Restarting because process died: " + next);
2742 if (!next.hasBeenLaunched) {
2743 next.hasBeenLaunched = true;
2744 } else {
2745 if (SHOW_APP_STARTING_ICON) {
2746 mWindowManager.setAppStartingWindow(
2747 next, next.packageName, next.theme,
2748 next.nonLocalizedLabel,
2749 next.labelRes, next.icon, null, true);
2750 }
2751 }
2752 startSpecificActivityLocked(next, true, false);
2753 return true;
2754 }
2755
2756 // From this point on, if something goes wrong there is no way
2757 // to recover the activity.
2758 try {
2759 next.visible = true;
2760 completeResumeLocked(next);
2761 } catch (Exception e) {
2762 // If any exception gets thrown, toss away this
2763 // activity and try the next one.
2764 Log.w(TAG, "Exception thrown during resume of " + next, e);
2765 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2766 "resume-exception");
2767 return true;
2768 }
2769
2770 // Didn't need to use the icicle, and it is now out of date.
2771 next.icicle = null;
2772 next.haveState = false;
2773 next.stopped = false;
2774
2775 } else {
2776 // Whoops, need to restart this activity!
2777 if (!next.hasBeenLaunched) {
2778 next.hasBeenLaunched = true;
2779 } else {
2780 if (SHOW_APP_STARTING_ICON) {
2781 mWindowManager.setAppStartingWindow(
2782 next, next.packageName, next.theme,
2783 next.nonLocalizedLabel,
2784 next.labelRes, next.icon, null, true);
2785 }
2786 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2787 }
2788 startSpecificActivityLocked(next, true, true);
2789 }
2790
2791 return true;
2792 }
2793
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002794 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2795 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002796 final int NH = mHistory.size();
2797
2798 int addPos = -1;
2799
2800 if (!newTask) {
2801 // If starting in an existing task, find where that is...
2802 HistoryRecord next = null;
2803 boolean startIt = true;
2804 for (int i = NH-1; i >= 0; i--) {
2805 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2806 if (p.finishing) {
2807 continue;
2808 }
2809 if (p.task == r.task) {
2810 // Here it is! Now, if this is not yet visible to the
2811 // user, then just add it without starting; it will
2812 // get started when the user navigates back to it.
2813 addPos = i+1;
2814 if (!startIt) {
2815 mHistory.add(addPos, r);
2816 r.inHistory = true;
2817 r.task.numActivities++;
2818 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2819 r.info.screenOrientation, r.fullscreen);
2820 if (VALIDATE_TOKENS) {
2821 mWindowManager.validateAppTokens(mHistory);
2822 }
2823 return;
2824 }
2825 break;
2826 }
2827 if (p.fullscreen) {
2828 startIt = false;
2829 }
2830 next = p;
2831 }
2832 }
2833
2834 // Place a new activity at top of stack, so it is next to interact
2835 // with the user.
2836 if (addPos < 0) {
2837 addPos = mHistory.size();
2838 }
2839
2840 // If we are not placing the new activity frontmost, we do not want
2841 // to deliver the onUserLeaving callback to the actual frontmost
2842 // activity
2843 if (addPos < NH) {
2844 mUserLeaving = false;
2845 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2846 }
2847
2848 // Slot the activity into the history stack and proceed
2849 mHistory.add(addPos, r);
2850 r.inHistory = true;
2851 r.frontOfTask = newTask;
2852 r.task.numActivities++;
2853 if (NH > 0) {
2854 // We want to show the starting preview window if we are
2855 // switching to a new task, or the next activity's process is
2856 // not currently running.
2857 boolean showStartingIcon = newTask;
2858 ProcessRecord proc = r.app;
2859 if (proc == null) {
2860 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2861 }
2862 if (proc == null || proc.thread == null) {
2863 showStartingIcon = true;
2864 }
2865 if (DEBUG_TRANSITION) Log.v(TAG,
2866 "Prepare open transition: starting " + r);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07002867 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
2868 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
2869 mNoAnimActivities.add(r);
2870 } else if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
2871 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_OPEN);
2872 mNoAnimActivities.remove(r);
2873 } else {
2874 mWindowManager.prepareAppTransition(newTask
2875 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2876 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2877 mNoAnimActivities.remove(r);
2878 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002879 mWindowManager.addAppToken(
2880 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2881 boolean doShow = true;
2882 if (newTask) {
2883 // Even though this activity is starting fresh, we still need
2884 // to reset it to make sure we apply affinities to move any
2885 // existing activities from other tasks in to it.
2886 // If the caller has requested that the target task be
2887 // reset, then do so.
2888 if ((r.intent.getFlags()
2889 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2890 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002891 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002892 }
2893 }
2894 if (SHOW_APP_STARTING_ICON && doShow) {
2895 // Figure out if we are transitioning from another activity that is
2896 // "has the same starting icon" as the next one. This allows the
2897 // window manager to keep the previous window it had previously
2898 // created, if it still had one.
2899 HistoryRecord prev = mResumedActivity;
2900 if (prev != null) {
2901 // We don't want to reuse the previous starting preview if:
2902 // (1) The current activity is in a different task.
2903 if (prev.task != r.task) prev = null;
2904 // (2) The current activity is already displayed.
2905 else if (prev.nowVisible) prev = null;
2906 }
2907 mWindowManager.setAppStartingWindow(
2908 r, r.packageName, r.theme, r.nonLocalizedLabel,
2909 r.labelRes, r.icon, prev, showStartingIcon);
2910 }
2911 } else {
2912 // If this is the first activity, don't do any fancy animations,
2913 // because there is nothing for it to animate on top of.
2914 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2915 r.info.screenOrientation, r.fullscreen);
2916 }
2917 if (VALIDATE_TOKENS) {
2918 mWindowManager.validateAppTokens(mHistory);
2919 }
2920
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002921 if (doResume) {
2922 resumeTopActivityLocked(null);
2923 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002924 }
2925
2926 /**
2927 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002928 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2929 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002930 * an instance of that activity in the stack and, if found, finish all
2931 * activities on top of it and return the instance.
2932 *
2933 * @param newR Description of the new activity being started.
2934 * @return Returns the old activity that should be continue to be used,
2935 * or null if none was found.
2936 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002937 private final HistoryRecord performClearTaskLocked(int taskId,
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002938 HistoryRecord newR, int launchFlags, boolean doClear) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002939 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002940
2941 // First find the requested task.
2942 while (i > 0) {
2943 i--;
2944 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2945 if (r.task.taskId == taskId) {
2946 i++;
2947 break;
2948 }
2949 }
2950
2951 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002952 while (i > 0) {
2953 i--;
2954 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2955 if (r.finishing) {
2956 continue;
2957 }
2958 if (r.task.taskId != taskId) {
2959 return null;
2960 }
2961 if (r.realActivity.equals(newR.realActivity)) {
2962 // Here it is! Now finish everything in front...
2963 HistoryRecord ret = r;
2964 if (doClear) {
2965 while (i < (mHistory.size()-1)) {
2966 i++;
2967 r = (HistoryRecord)mHistory.get(i);
2968 if (r.finishing) {
2969 continue;
2970 }
2971 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2972 null, "clear")) {
2973 i--;
2974 }
2975 }
2976 }
2977
2978 // Finally, if this is a normal launch mode (that is, not
2979 // expecting onNewIntent()), then we will finish the current
2980 // instance of the activity so a new fresh one can be started.
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07002981 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE
2982 && (launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002983 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002984 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002985 if (index >= 0) {
2986 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2987 null, "clear");
2988 }
2989 return null;
2990 }
2991 }
2992
2993 return ret;
2994 }
2995 }
2996
2997 return null;
2998 }
2999
3000 /**
3001 * Find the activity in the history stack within the given task. Returns
3002 * the index within the history at which it's found, or < 0 if not found.
3003 */
3004 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
3005 int i = mHistory.size();
3006 while (i > 0) {
3007 i--;
3008 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
3009 if (candidate.task.taskId != task) {
3010 break;
3011 }
3012 if (candidate.realActivity.equals(r.realActivity)) {
3013 return i;
3014 }
3015 }
3016
3017 return -1;
3018 }
3019
3020 /**
3021 * Reorder the history stack so that the activity at the given index is
3022 * brought to the front.
3023 */
3024 private final HistoryRecord moveActivityToFrontLocked(int where) {
3025 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
3026 int top = mHistory.size();
3027 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
3028 mHistory.add(top, newTop);
3029 oldTop.frontOfTask = false;
3030 newTop.frontOfTask = true;
3031 return newTop;
3032 }
3033
3034 /**
3035 * Deliver a new Intent to an existing activity, so that its onNewIntent()
3036 * method will be called at the proper time.
3037 */
3038 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
3039 boolean sent = false;
3040 if (r.state == ActivityState.RESUMED
3041 && r.app != null && r.app.thread != null) {
3042 try {
3043 ArrayList<Intent> ar = new ArrayList<Intent>();
3044 ar.add(new Intent(intent));
3045 r.app.thread.scheduleNewIntent(ar, r);
3046 sent = true;
3047 } catch (Exception e) {
3048 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3049 }
3050 }
3051 if (!sent) {
3052 r.addNewIntentLocked(new Intent(intent));
3053 }
3054 }
3055
3056 private final void logStartActivity(int tag, HistoryRecord r,
3057 TaskRecord task) {
3058 EventLog.writeEvent(tag,
3059 System.identityHashCode(r), task.taskId,
3060 r.shortComponentName, r.intent.getAction(),
3061 r.intent.getType(), r.intent.getDataString(),
3062 r.intent.getFlags());
3063 }
3064
3065 private final int startActivityLocked(IApplicationThread caller,
3066 Intent intent, String resolvedType,
3067 Uri[] grantedUriPermissions,
3068 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3069 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003070 int callingPid, int callingUid, boolean onlyIfNeeded,
3071 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003072 Log.i(TAG, "Starting activity: " + intent);
3073
3074 HistoryRecord sourceRecord = null;
3075 HistoryRecord resultRecord = null;
3076 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003077 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003078 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003079 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3080 if (index >= 0) {
3081 sourceRecord = (HistoryRecord)mHistory.get(index);
3082 if (requestCode >= 0 && !sourceRecord.finishing) {
3083 resultRecord = sourceRecord;
3084 }
3085 }
3086 }
3087
3088 int launchFlags = intent.getFlags();
3089
3090 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3091 && sourceRecord != null) {
3092 // Transfer the result target from the source activity to the new
3093 // one being started, including any failures.
3094 if (requestCode >= 0) {
3095 return START_FORWARD_AND_REQUEST_CONFLICT;
3096 }
3097 resultRecord = sourceRecord.resultTo;
3098 resultWho = sourceRecord.resultWho;
3099 requestCode = sourceRecord.requestCode;
3100 sourceRecord.resultTo = null;
3101 if (resultRecord != null) {
3102 resultRecord.removeResultsLocked(
3103 sourceRecord, resultWho, requestCode);
3104 }
3105 }
3106
3107 int err = START_SUCCESS;
3108
3109 if (intent.getComponent() == null) {
3110 // We couldn't find a class that can handle the given Intent.
3111 // That's the end of that!
3112 err = START_INTENT_NOT_RESOLVED;
3113 }
3114
3115 if (err == START_SUCCESS && aInfo == null) {
3116 // We couldn't find the specific class specified in the Intent.
3117 // Also the end of the line.
3118 err = START_CLASS_NOT_FOUND;
3119 }
3120
3121 ProcessRecord callerApp = null;
3122 if (err == START_SUCCESS && caller != null) {
3123 callerApp = getRecordForAppLocked(caller);
3124 if (callerApp != null) {
3125 callingPid = callerApp.pid;
3126 callingUid = callerApp.info.uid;
3127 } else {
3128 Log.w(TAG, "Unable to find app for caller " + caller
3129 + " (pid=" + callingPid + ") when starting: "
3130 + intent.toString());
3131 err = START_PERMISSION_DENIED;
3132 }
3133 }
3134
3135 if (err != START_SUCCESS) {
3136 if (resultRecord != null) {
3137 sendActivityResultLocked(-1,
3138 resultRecord, resultWho, requestCode,
3139 Activity.RESULT_CANCELED, null);
3140 }
3141 return err;
3142 }
3143
3144 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3145 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3146 if (perm != PackageManager.PERMISSION_GRANTED) {
3147 if (resultRecord != null) {
3148 sendActivityResultLocked(-1,
3149 resultRecord, resultWho, requestCode,
3150 Activity.RESULT_CANCELED, null);
3151 }
3152 String msg = "Permission Denial: starting " + intent.toString()
3153 + " from " + callerApp + " (pid=" + callingPid
3154 + ", uid=" + callingUid + ")"
3155 + " requires " + aInfo.permission;
3156 Log.w(TAG, msg);
3157 throw new SecurityException(msg);
3158 }
3159
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003160 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003161 boolean abort = false;
3162 try {
3163 // The Intent we give to the watcher has the extra data
3164 // stripped off, since it can contain private information.
3165 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003166 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003167 aInfo.applicationInfo.packageName);
3168 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003169 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003170 }
3171
3172 if (abort) {
3173 if (resultRecord != null) {
3174 sendActivityResultLocked(-1,
3175 resultRecord, resultWho, requestCode,
3176 Activity.RESULT_CANCELED, null);
3177 }
3178 // We pretend to the caller that it was really started, but
3179 // they will just get a cancel result.
3180 return START_SUCCESS;
3181 }
3182 }
3183
3184 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3185 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003186 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003187
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003188 if (mResumedActivity == null
3189 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3190 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3191 PendingActivityLaunch pal = new PendingActivityLaunch();
3192 pal.r = r;
3193 pal.sourceRecord = sourceRecord;
3194 pal.grantedUriPermissions = grantedUriPermissions;
3195 pal.grantedMode = grantedMode;
3196 pal.onlyIfNeeded = onlyIfNeeded;
3197 mPendingActivityLaunches.add(pal);
3198 return START_SWITCHES_CANCELED;
3199 }
3200 }
3201
3202 if (mDidAppSwitch) {
3203 // This is the second allowed switch since we stopped switches,
3204 // so now just generally allow switches. Use case: user presses
3205 // home (switches disabled, switch to home, mDidAppSwitch now true);
3206 // user taps a home icon (coming from home so allowed, we hit here
3207 // and now allow anyone to switch again).
3208 mAppSwitchesAllowedTime = 0;
3209 } else {
3210 mDidAppSwitch = true;
3211 }
3212
3213 doPendingActivityLaunchesLocked(false);
3214
3215 return startActivityUncheckedLocked(r, sourceRecord,
3216 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3217 }
3218
3219 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3220 final int N = mPendingActivityLaunches.size();
3221 if (N <= 0) {
3222 return;
3223 }
3224 for (int i=0; i<N; i++) {
3225 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3226 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3227 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3228 doResume && i == (N-1));
3229 }
3230 mPendingActivityLaunches.clear();
3231 }
3232
3233 private final int startActivityUncheckedLocked(HistoryRecord r,
3234 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3235 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3236 final Intent intent = r.intent;
3237 final int callingUid = r.launchedFromUid;
3238
3239 int launchFlags = intent.getFlags();
3240
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003241 // We'll invoke onUserLeaving before onPause only if the launching
3242 // activity did not explicitly state that this is an automated launch.
3243 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3244 if (DEBUG_USER_LEAVING) Log.v(TAG,
3245 "startActivity() => mUserLeaving=" + mUserLeaving);
3246
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003247 // If the caller has asked not to resume at this point, we make note
3248 // of this in the record so that we can skip it when trying to find
3249 // the top running activity.
3250 if (!doResume) {
3251 r.delayedResume = true;
3252 }
3253
3254 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3255 != 0 ? r : null;
3256
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003257 // If the onlyIfNeeded flag is set, then we can do this if the activity
3258 // being launched is the same as the one making the call... or, as
3259 // a special case, if we do not know the caller then we count the
3260 // current top activity as the caller.
3261 if (onlyIfNeeded) {
3262 HistoryRecord checkedCaller = sourceRecord;
3263 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003264 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003265 }
3266 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3267 // Caller is not the same as launcher, so always needed.
3268 onlyIfNeeded = false;
3269 }
3270 }
3271
3272 if (grantedUriPermissions != null && callingUid > 0) {
3273 for (int i=0; i<grantedUriPermissions.length; i++) {
3274 grantUriPermissionLocked(callingUid, r.packageName,
3275 grantedUriPermissions[i], grantedMode, r);
3276 }
3277 }
3278
3279 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3280 intent, r);
3281
3282 if (sourceRecord == null) {
3283 // This activity is not being started from another... in this
3284 // case we -always- start a new task.
3285 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3286 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3287 + intent);
3288 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3289 }
3290 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3291 // The original activity who is starting us is running as a single
3292 // instance... this new activity it is starting must go on its
3293 // own task.
3294 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3295 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3296 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3297 // The activity being started is a single instance... it always
3298 // gets launched into its own task.
3299 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3300 }
3301
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003302 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003303 // For whatever reason this activity is being launched into a new
3304 // task... yet the caller has requested a result back. Well, that
3305 // is pretty messed up, so instead immediately send back a cancel
3306 // and let the new task continue launched as normal without a
3307 // dependency on its originator.
3308 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3309 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003310 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003311 Activity.RESULT_CANCELED, null);
3312 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003313 }
3314
3315 boolean addingToTask = false;
3316 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3317 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3318 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3319 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3320 // If bring to front is requested, and no result is requested, and
3321 // we can find a task that was started with this same
3322 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003323 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003324 // See if there is a task to bring to the front. If this is
3325 // a SINGLE_INSTANCE activity, there can be one and only one
3326 // instance of it in the history, and it is always in its own
3327 // unique task, so we do a special search.
3328 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3329 ? findTaskLocked(intent, r.info)
3330 : findActivityLocked(intent, r.info);
3331 if (taskTop != null) {
3332 if (taskTop.task.intent == null) {
3333 // This task was started because of movement of
3334 // the activity based on affinity... now that we
3335 // are actually launching it, we can assign the
3336 // base intent.
3337 taskTop.task.setIntent(intent, r.info);
3338 }
3339 // If the target task is not in the front, then we need
3340 // to bring it to the front... except... well, with
3341 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3342 // to have the same behavior as if a new instance was
3343 // being started, which means not bringing it to the front
3344 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003345 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003346 if (curTop.task != taskTop.task) {
3347 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3348 boolean callerAtFront = sourceRecord == null
3349 || curTop.task == sourceRecord.task;
3350 if (callerAtFront) {
3351 // We really do want to push this one into the
3352 // user's face, right now.
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07003353 moveTaskToFrontLocked(taskTop.task, r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003354 }
3355 }
3356 // If the caller has requested that the target task be
3357 // reset, then do so.
3358 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3359 taskTop = resetTaskIfNeededLocked(taskTop, r);
3360 }
3361 if (onlyIfNeeded) {
3362 // We don't need to start a new activity, and
3363 // the client said not to do anything if that
3364 // is the case, so this is it! And for paranoia, make
3365 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003366 if (doResume) {
3367 resumeTopActivityLocked(null);
3368 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003369 return START_RETURN_INTENT_TO_CALLER;
3370 }
3371 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3372 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3373 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3374 // In this situation we want to remove all activities
3375 // from the task up to the one being started. In most
3376 // cases this means we are resetting the task to its
3377 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003378 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003379 taskTop.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003380 if (top != null) {
3381 if (top.frontOfTask) {
3382 // Activity aliases may mean we use different
3383 // intents for the top activity, so make sure
3384 // the task now has the identity of the new
3385 // intent.
3386 top.task.setIntent(r.intent, r.info);
3387 }
Doug Zongker2bec3d42009-12-04 12:52:44 -08003388 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003389 deliverNewIntentLocked(top, r.intent);
3390 } else {
3391 // A special case: we need to
3392 // start the activity because it is not currently
3393 // running, and the caller has asked to clear the
3394 // current task to have this activity at the top.
3395 addingToTask = true;
3396 // Now pretend like this activity is being started
3397 // by the top of its task, so it is put in the
3398 // right place.
3399 sourceRecord = taskTop;
3400 }
3401 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3402 // In this case the top activity on the task is the
3403 // same as the one being launched, so we take that
3404 // as a request to bring the task to the foreground.
3405 // If the top activity in the task is the root
3406 // activity, deliver this new intent to it if it
3407 // desires.
3408 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3409 && taskTop.realActivity.equals(r.realActivity)) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003410 logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003411 if (taskTop.frontOfTask) {
3412 taskTop.task.setIntent(r.intent, r.info);
3413 }
3414 deliverNewIntentLocked(taskTop, r.intent);
3415 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3416 // In this case we are launching the root activity
3417 // of the task, but with a different intent. We
3418 // should start a new instance on top.
3419 addingToTask = true;
3420 sourceRecord = taskTop;
3421 }
3422 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3423 // In this case an activity is being launched in to an
3424 // existing task, without resetting that task. This
3425 // is typically the situation of launching an activity
3426 // from a notification or shortcut. We want to place
3427 // the new activity on top of the current task.
3428 addingToTask = true;
3429 sourceRecord = taskTop;
3430 } else if (!taskTop.task.rootWasReset) {
3431 // In this case we are launching in to an existing task
3432 // that has not yet been started from its front door.
3433 // The current task has been brought to the front.
3434 // Ideally, we'd probably like to place this new task
3435 // at the bottom of its stack, but that's a little hard
3436 // to do with the current organization of the code so
3437 // for now we'll just drop it.
3438 taskTop.task.setIntent(r.intent, r.info);
3439 }
3440 if (!addingToTask) {
3441 // We didn't do anything... but it was needed (a.k.a., client
3442 // don't use that intent!) And for paranoia, make
3443 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003444 if (doResume) {
3445 resumeTopActivityLocked(null);
3446 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003447 return START_TASK_TO_FRONT;
3448 }
3449 }
3450 }
3451 }
3452
3453 //String uri = r.intent.toURI();
3454 //Intent intent2 = new Intent(uri);
3455 //Log.i(TAG, "Given intent: " + r.intent);
3456 //Log.i(TAG, "URI is: " + uri);
3457 //Log.i(TAG, "To intent: " + intent2);
3458
3459 if (r.packageName != null) {
3460 // If the activity being launched is the same as the one currently
3461 // at the top, then we need to check if it should only be launched
3462 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003463 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3464 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003465 if (top.realActivity.equals(r.realActivity)) {
3466 if (top.app != null && top.app.thread != null) {
3467 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3468 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3469 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003470 logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003471 // For paranoia, make sure we have correctly
3472 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003473 if (doResume) {
3474 resumeTopActivityLocked(null);
3475 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003476 if (onlyIfNeeded) {
3477 // We don't need to start a new activity, and
3478 // the client said not to do anything if that
3479 // is the case, so this is it!
3480 return START_RETURN_INTENT_TO_CALLER;
3481 }
3482 deliverNewIntentLocked(top, r.intent);
3483 return START_DELIVERED_TO_TOP;
3484 }
3485 }
3486 }
3487 }
3488
3489 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003490 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003491 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003492 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003493 Activity.RESULT_CANCELED, null);
3494 }
3495 return START_CLASS_NOT_FOUND;
3496 }
3497
3498 boolean newTask = false;
3499
3500 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003501 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003502 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3503 // todo: should do better management of integers.
3504 mCurTask++;
3505 if (mCurTask <= 0) {
3506 mCurTask = 1;
3507 }
3508 r.task = new TaskRecord(mCurTask, r.info, intent,
3509 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3510 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3511 + " in new task " + r.task);
3512 newTask = true;
3513 addRecentTask(r.task);
3514
3515 } else if (sourceRecord != null) {
3516 if (!addingToTask &&
3517 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3518 // In this case, we are adding the activity to an existing
3519 // task, but the caller has asked to clear that task if the
3520 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003521 HistoryRecord top = performClearTaskLocked(
Dianne Hackbornaa52f9a2009-08-25 16:01:15 -07003522 sourceRecord.task.taskId, r, launchFlags, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003523 if (top != null) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003524 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003525 deliverNewIntentLocked(top, r.intent);
3526 // For paranoia, make sure we have correctly
3527 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003528 if (doResume) {
3529 resumeTopActivityLocked(null);
3530 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003531 return START_DELIVERED_TO_TOP;
3532 }
3533 } else if (!addingToTask &&
3534 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3535 // In this case, we are launching an activity in our own task
3536 // that may already be running somewhere in the history, and
3537 // we want to shuffle it to the front of the stack if so.
3538 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3539 if (where >= 0) {
3540 HistoryRecord top = moveActivityToFrontLocked(where);
Doug Zongker2bec3d42009-12-04 12:52:44 -08003541 logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003542 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003543 if (doResume) {
3544 resumeTopActivityLocked(null);
3545 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003546 return START_DELIVERED_TO_TOP;
3547 }
3548 }
3549 // An existing activity is starting this new activity, so we want
3550 // to keep the new one in the same task as the one that is starting
3551 // it.
3552 r.task = sourceRecord.task;
3553 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3554 + " in existing task " + r.task);
3555
3556 } else {
3557 // This not being started from an existing activity, and not part
3558 // of a new task... just put it in the top task, though these days
3559 // this case should never happen.
3560 final int N = mHistory.size();
3561 HistoryRecord prev =
3562 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3563 r.task = prev != null
3564 ? prev.task
3565 : new TaskRecord(mCurTask, r.info, intent,
3566 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3567 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3568 + " in new guessed " + r.task);
3569 }
3570 if (newTask) {
Doug Zongker2bec3d42009-12-04 12:52:44 -08003571 EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.task.taskId);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003572 }
Doug Zongker2bec3d42009-12-04 12:52:44 -08003573 logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003574 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003575 return START_SUCCESS;
3576 }
3577
3578 public final int startActivity(IApplicationThread caller,
3579 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3580 int grantedMode, IBinder resultTo,
3581 String resultWho, int requestCode, boolean onlyIfNeeded,
3582 boolean debug) {
3583 // Refuse possible leaked file descriptors
3584 if (intent != null && intent.hasFileDescriptors()) {
3585 throw new IllegalArgumentException("File descriptors passed in Intent");
3586 }
3587
The Android Open Source Project4df24232009-03-05 14:34:35 -08003588 final boolean componentSpecified = intent.getComponent() != null;
3589
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003590 // Don't modify the client's object!
3591 intent = new Intent(intent);
3592
3593 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003594 ActivityInfo aInfo;
3595 try {
3596 ResolveInfo rInfo =
3597 ActivityThread.getPackageManager().resolveIntent(
3598 intent, resolvedType,
3599 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003600 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003601 aInfo = rInfo != null ? rInfo.activityInfo : null;
3602 } catch (RemoteException e) {
3603 aInfo = null;
3604 }
3605
3606 if (aInfo != null) {
3607 // Store the found target back into the intent, because now that
3608 // we have it we never want to do this again. For example, if the
3609 // user navigates back to this point in the history, we should
3610 // always restart the exact same activity.
3611 intent.setComponent(new ComponentName(
3612 aInfo.applicationInfo.packageName, aInfo.name));
3613
3614 // Don't debug things in the system process
3615 if (debug) {
3616 if (!aInfo.processName.equals("system")) {
3617 setDebugApp(aInfo.processName, true, false);
3618 }
3619 }
3620 }
3621
3622 synchronized(this) {
3623 final long origId = Binder.clearCallingIdentity();
3624 int res = startActivityLocked(caller, intent, resolvedType,
3625 grantedUriPermissions, grantedMode, aInfo,
3626 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003627 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003628 Binder.restoreCallingIdentity(origId);
3629 return res;
3630 }
3631 }
3632
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003633 public int startActivityIntentSender(IApplicationThread caller,
3634 IntentSender intent, Intent fillInIntent, String resolvedType,
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003635 IBinder resultTo, String resultWho, int requestCode,
3636 int flagsMask, int flagsValues) {
3637 // Refuse possible leaked file descriptors
3638 if (fillInIntent != null && fillInIntent.hasFileDescriptors()) {
3639 throw new IllegalArgumentException("File descriptors passed in Intent");
3640 }
3641
3642 IIntentSender sender = intent.getTarget();
3643 if (!(sender instanceof PendingIntentRecord)) {
3644 throw new IllegalArgumentException("Bad PendingIntent object");
3645 }
3646
3647 PendingIntentRecord pir = (PendingIntentRecord)sender;
Dianne Hackbornfa82f222009-09-17 15:14:12 -07003648
3649 synchronized (this) {
3650 // If this is coming from the currently resumed activity, it is
3651 // effectively saying that app switches are allowed at this point.
3652 if (mResumedActivity != null
3653 && mResumedActivity.info.applicationInfo.uid ==
3654 Binder.getCallingUid()) {
3655 mAppSwitchesAllowedTime = 0;
3656 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -07003657 }
3658
3659 return pir.sendInner(0, fillInIntent, resolvedType,
3660 null, resultTo, resultWho, requestCode, flagsMask, flagsValues);
3661 }
3662
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003663 public boolean startNextMatchingActivity(IBinder callingActivity,
3664 Intent intent) {
3665 // Refuse possible leaked file descriptors
3666 if (intent != null && intent.hasFileDescriptors() == true) {
3667 throw new IllegalArgumentException("File descriptors passed in Intent");
3668 }
3669
3670 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003671 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003672 if (index < 0) {
3673 return false;
3674 }
3675 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3676 if (r.app == null || r.app.thread == null) {
3677 // The caller is not running... d'oh!
3678 return false;
3679 }
3680 intent = new Intent(intent);
3681 // The caller is not allowed to change the data.
3682 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3683 // And we are resetting to find the next component...
3684 intent.setComponent(null);
3685
3686 ActivityInfo aInfo = null;
3687 try {
3688 List<ResolveInfo> resolves =
3689 ActivityThread.getPackageManager().queryIntentActivities(
3690 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003691 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003692
3693 // Look for the original activity in the list...
3694 final int N = resolves != null ? resolves.size() : 0;
3695 for (int i=0; i<N; i++) {
3696 ResolveInfo rInfo = resolves.get(i);
3697 if (rInfo.activityInfo.packageName.equals(r.packageName)
3698 && rInfo.activityInfo.name.equals(r.info.name)) {
3699 // We found the current one... the next matching is
3700 // after it.
3701 i++;
3702 if (i<N) {
3703 aInfo = resolves.get(i).activityInfo;
3704 }
3705 break;
3706 }
3707 }
3708 } catch (RemoteException e) {
3709 }
3710
3711 if (aInfo == null) {
3712 // Nobody who is next!
3713 return false;
3714 }
3715
3716 intent.setComponent(new ComponentName(
3717 aInfo.applicationInfo.packageName, aInfo.name));
3718 intent.setFlags(intent.getFlags()&~(
3719 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3720 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3721 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3722 Intent.FLAG_ACTIVITY_NEW_TASK));
3723
3724 // Okay now we need to start the new activity, replacing the
3725 // currently running activity. This is a little tricky because
3726 // we want to start the new one as if the current one is finished,
3727 // but not finish the current one first so that there is no flicker.
3728 // And thus...
3729 final boolean wasFinishing = r.finishing;
3730 r.finishing = true;
3731
3732 // Propagate reply information over to the new activity.
3733 final HistoryRecord resultTo = r.resultTo;
3734 final String resultWho = r.resultWho;
3735 final int requestCode = r.requestCode;
3736 r.resultTo = null;
3737 if (resultTo != null) {
3738 resultTo.removeResultsLocked(r, resultWho, requestCode);
3739 }
3740
3741 final long origId = Binder.clearCallingIdentity();
3742 // XXX we are not dealing with propagating grantedUriPermissions...
3743 // those are not yet exposed to user code, so there is no need.
3744 int res = startActivityLocked(r.app.thread, intent,
3745 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003746 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003747 Binder.restoreCallingIdentity(origId);
3748
3749 r.finishing = wasFinishing;
3750 if (res != START_SUCCESS) {
3751 return false;
3752 }
3753 return true;
3754 }
3755 }
3756
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003757 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003758 Intent intent, String resolvedType, IBinder resultTo,
3759 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003760
3761 // This is so super not safe, that only the system (or okay root)
3762 // can do it.
3763 final int callingUid = Binder.getCallingUid();
3764 if (callingUid != 0 && callingUid != Process.myUid()) {
3765 throw new SecurityException(
3766 "startActivityInPackage only available to the system");
3767 }
3768
The Android Open Source Project4df24232009-03-05 14:34:35 -08003769 final boolean componentSpecified = intent.getComponent() != null;
3770
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003771 // Don't modify the client's object!
3772 intent = new Intent(intent);
3773
3774 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003775 ActivityInfo aInfo;
3776 try {
3777 ResolveInfo rInfo =
3778 ActivityThread.getPackageManager().resolveIntent(
3779 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003780 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003781 aInfo = rInfo != null ? rInfo.activityInfo : null;
3782 } catch (RemoteException e) {
3783 aInfo = null;
3784 }
3785
3786 if (aInfo != null) {
3787 // Store the found target back into the intent, because now that
3788 // we have it we never want to do this again. For example, if the
3789 // user navigates back to this point in the history, we should
3790 // always restart the exact same activity.
3791 intent.setComponent(new ComponentName(
3792 aInfo.applicationInfo.packageName, aInfo.name));
3793 }
3794
3795 synchronized(this) {
3796 return startActivityLocked(null, intent, resolvedType,
3797 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003798 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003799 }
3800 }
3801
3802 private final void addRecentTask(TaskRecord task) {
3803 // Remove any existing entries that are the same kind of task.
3804 int N = mRecentTasks.size();
3805 for (int i=0; i<N; i++) {
3806 TaskRecord tr = mRecentTasks.get(i);
3807 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3808 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3809 mRecentTasks.remove(i);
3810 i--;
3811 N--;
3812 if (task.intent == null) {
3813 // If the new recent task we are adding is not fully
3814 // specified, then replace it with the existing recent task.
3815 task = tr;
3816 }
3817 }
3818 }
3819 if (N >= MAX_RECENT_TASKS) {
3820 mRecentTasks.remove(N-1);
3821 }
3822 mRecentTasks.add(0, task);
3823 }
3824
3825 public void setRequestedOrientation(IBinder token,
3826 int requestedOrientation) {
3827 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003828 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003829 if (index < 0) {
3830 return;
3831 }
3832 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3833 final long origId = Binder.clearCallingIdentity();
3834 mWindowManager.setAppOrientation(r, requestedOrientation);
3835 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003836 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003837 r.mayFreezeScreenLocked(r.app) ? r : null);
3838 if (config != null) {
3839 r.frozenBeforeDestroy = true;
3840 if (!updateConfigurationLocked(config, r)) {
3841 resumeTopActivityLocked(null);
3842 }
3843 }
3844 Binder.restoreCallingIdentity(origId);
3845 }
3846 }
3847
3848 public int getRequestedOrientation(IBinder token) {
3849 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003850 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003851 if (index < 0) {
3852 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3853 }
3854 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3855 return mWindowManager.getAppOrientation(r);
3856 }
3857 }
3858
3859 private final void stopActivityLocked(HistoryRecord r) {
3860 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3861 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3862 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3863 if (!r.finishing) {
3864 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3865 "no-history");
3866 }
3867 } else if (r.app != null && r.app.thread != null) {
3868 if (mFocusedActivity == r) {
3869 setFocusedActivityLocked(topRunningActivityLocked(null));
3870 }
3871 r.resumeKeyDispatchingLocked();
3872 try {
3873 r.stopped = false;
3874 r.state = ActivityState.STOPPING;
3875 if (DEBUG_VISBILITY) Log.v(
3876 TAG, "Stopping visible=" + r.visible + " for " + r);
3877 if (!r.visible) {
3878 mWindowManager.setAppVisibility(r, false);
3879 }
3880 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3881 } catch (Exception e) {
3882 // Maybe just ignore exceptions here... if the process
3883 // has crashed, our death notification will clean things
3884 // up.
3885 Log.w(TAG, "Exception thrown during pause", e);
3886 // Just in case, assume it to be stopped.
3887 r.stopped = true;
3888 r.state = ActivityState.STOPPED;
3889 if (r.configDestroy) {
3890 destroyActivityLocked(r, true);
3891 }
3892 }
3893 }
3894 }
3895
3896 /**
3897 * @return Returns true if the activity is being finished, false if for
3898 * some reason it is being left as-is.
3899 */
3900 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3901 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003902 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003903 TAG, "Finishing activity: token=" + token
3904 + ", result=" + resultCode + ", data=" + resultData);
3905
Dianne Hackborn75b03852009-06-12 15:43:26 -07003906 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003907 if (index < 0) {
3908 return false;
3909 }
3910 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3911
3912 // Is this the last activity left?
3913 boolean lastActivity = true;
3914 for (int i=mHistory.size()-1; i>=0; i--) {
3915 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3916 if (!p.finishing && p != r) {
3917 lastActivity = false;
3918 break;
3919 }
3920 }
3921
3922 // If this is the last activity, but it is the home activity, then
3923 // just don't finish it.
3924 if (lastActivity) {
3925 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3926 return false;
3927 }
3928 }
3929
3930 finishActivityLocked(r, index, resultCode, resultData, reason);
3931 return true;
3932 }
3933
3934 /**
3935 * @return Returns true if this activity has been removed from the history
3936 * list, or false if it is still in the list and will be removed later.
3937 */
3938 private final boolean finishActivityLocked(HistoryRecord r, int index,
3939 int resultCode, Intent resultData, String reason) {
3940 if (r.finishing) {
3941 Log.w(TAG, "Duplicate finish request for " + r);
3942 return false;
3943 }
3944
3945 r.finishing = true;
Doug Zongker2bec3d42009-12-04 12:52:44 -08003946 EventLog.writeEvent(EventLogTags.AM_FINISH_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003947 System.identityHashCode(r),
3948 r.task.taskId, r.shortComponentName, reason);
3949 r.task.numActivities--;
3950 if (r.frontOfTask && index < (mHistory.size()-1)) {
3951 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3952 if (next.task == r.task) {
3953 next.frontOfTask = true;
3954 }
3955 }
3956
3957 r.pauseKeyDispatchingLocked();
3958 if (mFocusedActivity == r) {
3959 setFocusedActivityLocked(topRunningActivityLocked(null));
3960 }
3961
3962 // send the result
3963 HistoryRecord resultTo = r.resultTo;
3964 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003965 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3966 + " who=" + r.resultWho + " req=" + r.requestCode
3967 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003968 if (r.info.applicationInfo.uid > 0) {
3969 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3970 r.packageName, resultData, r);
3971 }
3972 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3973 resultData);
3974 r.resultTo = null;
3975 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003976 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003977
3978 // Make sure this HistoryRecord is not holding on to other resources,
3979 // because clients have remote IPC references to this object so we
3980 // can't assume that will go away and want to avoid circular IPC refs.
3981 r.results = null;
3982 r.pendingResults = null;
3983 r.newIntents = null;
3984 r.icicle = null;
3985
3986 if (mPendingThumbnails.size() > 0) {
3987 // There are clients waiting to receive thumbnails so, in case
3988 // this is an activity that someone is waiting for, add it
3989 // to the pending list so we can correctly update the clients.
3990 mCancelledThumbnails.add(r);
3991 }
3992
3993 if (mResumedActivity == r) {
3994 boolean endTask = index <= 0
3995 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3996 if (DEBUG_TRANSITION) Log.v(TAG,
3997 "Prepare close transition: finishing " + r);
3998 mWindowManager.prepareAppTransition(endTask
3999 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
4000 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
4001
4002 // Tell window manager to prepare for this one to be removed.
4003 mWindowManager.setAppVisibility(r, false);
4004
4005 if (mPausingActivity == null) {
4006 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
4007 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
4008 startPausingLocked(false, false);
4009 }
4010
4011 } else if (r.state != ActivityState.PAUSING) {
4012 // If the activity is PAUSING, we will complete the finish once
4013 // it is done pausing; else we can just directly finish it here.
4014 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
4015 return finishCurrentActivityLocked(r, index,
4016 FINISH_AFTER_PAUSE) == null;
4017 } else {
4018 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
4019 }
4020
4021 return false;
4022 }
4023
4024 private static final int FINISH_IMMEDIATELY = 0;
4025 private static final int FINISH_AFTER_PAUSE = 1;
4026 private static final int FINISH_AFTER_VISIBLE = 2;
4027
4028 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4029 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004030 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004031 if (index < 0) {
4032 return null;
4033 }
4034
4035 return finishCurrentActivityLocked(r, index, mode);
4036 }
4037
4038 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
4039 int index, int mode) {
4040 // First things first: if this activity is currently visible,
4041 // and the resumed activity is not yet visible, then hold off on
4042 // finishing until the resumed one becomes visible.
4043 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
4044 if (!mStoppingActivities.contains(r)) {
4045 mStoppingActivities.add(r);
4046 if (mStoppingActivities.size() > 3) {
4047 // If we already have a few activities waiting to stop,
4048 // then give up on things going idle and start clearing
4049 // them out.
4050 Message msg = Message.obtain();
4051 msg.what = ActivityManagerService.IDLE_NOW_MSG;
4052 mHandler.sendMessage(msg);
4053 }
4054 }
4055 r.state = ActivityState.STOPPING;
4056 updateOomAdjLocked();
4057 return r;
4058 }
4059
4060 // make sure the record is cleaned out of other places.
4061 mStoppingActivities.remove(r);
4062 mWaitingVisibleActivities.remove(r);
4063 if (mResumedActivity == r) {
4064 mResumedActivity = null;
4065 }
4066 final ActivityState prevState = r.state;
4067 r.state = ActivityState.FINISHING;
4068
4069 if (mode == FINISH_IMMEDIATELY
4070 || prevState == ActivityState.STOPPED
4071 || prevState == ActivityState.INITIALIZING) {
4072 // If this activity is already stopped, we can just finish
4073 // it right now.
4074 return destroyActivityLocked(r, true) ? null : r;
4075 } else {
4076 // Need to go through the full pause cycle to get this
4077 // activity into the stopped state and then finish it.
4078 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4079 mFinishingActivities.add(r);
4080 resumeTopActivityLocked(null);
4081 }
4082 return r;
4083 }
4084
4085 /**
4086 * This is the internal entry point for handling Activity.finish().
4087 *
4088 * @param token The Binder token referencing the Activity we want to finish.
4089 * @param resultCode Result code, if any, from this Activity.
4090 * @param resultData Result data (Intent), if any, from this Activity.
4091 *
4092 * @result Returns true if the activity successfully finished, or false if it is still running.
4093 */
4094 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4095 // Refuse possible leaked file descriptors
4096 if (resultData != null && resultData.hasFileDescriptors() == true) {
4097 throw new IllegalArgumentException("File descriptors passed in Intent");
4098 }
4099
4100 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004101 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004102 // Find the first activity that is not finishing.
4103 HistoryRecord next = topRunningActivityLocked(token, 0);
4104 if (next != null) {
4105 // ask watcher if this is allowed
4106 boolean resumeOK = true;
4107 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004108 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004109 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004110 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004111 }
4112
4113 if (!resumeOK) {
4114 return false;
4115 }
4116 }
4117 }
4118 final long origId = Binder.clearCallingIdentity();
4119 boolean res = requestFinishActivityLocked(token, resultCode,
4120 resultData, "app-request");
4121 Binder.restoreCallingIdentity(origId);
4122 return res;
4123 }
4124 }
4125
4126 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4127 String resultWho, int requestCode, int resultCode, Intent data) {
4128
4129 if (callingUid > 0) {
4130 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4131 data, r);
4132 }
4133
The Android Open Source Project10592532009-03-18 17:39:46 -07004134 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4135 + " : who=" + resultWho + " req=" + requestCode
4136 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004137 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4138 try {
4139 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4140 list.add(new ResultInfo(resultWho, requestCode,
4141 resultCode, data));
4142 r.app.thread.scheduleSendResult(r, list);
4143 return;
4144 } catch (Exception e) {
4145 Log.w(TAG, "Exception thrown sending result to " + r, e);
4146 }
4147 }
4148
4149 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4150 }
4151
4152 public final void finishSubActivity(IBinder token, String resultWho,
4153 int requestCode) {
4154 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004155 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004156 if (index < 0) {
4157 return;
4158 }
4159 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4160
4161 final long origId = Binder.clearCallingIdentity();
4162
4163 int i;
4164 for (i=mHistory.size()-1; i>=0; i--) {
4165 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4166 if (r.resultTo == self && r.requestCode == requestCode) {
4167 if ((r.resultWho == null && resultWho == null) ||
4168 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4169 finishActivityLocked(r, i,
4170 Activity.RESULT_CANCELED, null, "request-sub");
4171 }
4172 }
4173 }
4174
4175 Binder.restoreCallingIdentity(origId);
4176 }
4177 }
4178
Dianne Hackborn3b3e1452009-09-24 19:22:12 -07004179 public void overridePendingTransition(IBinder token, String packageName,
4180 int enterAnim, int exitAnim) {
4181 synchronized(this) {
4182 int index = indexOfTokenLocked(token);
4183 if (index < 0) {
4184 return;
4185 }
4186 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4187
4188 final long origId = Binder.clearCallingIdentity();
4189
4190 if (self.state == ActivityState.RESUMED
4191 || self.state == ActivityState.PAUSING) {
4192 mWindowManager.overridePendingAppTransition(packageName,
4193 enterAnim, exitAnim);
4194 }
4195
4196 Binder.restoreCallingIdentity(origId);
4197 }
4198 }
4199
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004200 /**
4201 * Perform clean-up of service connections in an activity record.
4202 */
4203 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4204 // Throw away any services that have been bound by this activity.
4205 if (r.connections != null) {
4206 Iterator<ConnectionRecord> it = r.connections.iterator();
4207 while (it.hasNext()) {
4208 ConnectionRecord c = it.next();
4209 removeConnectionLocked(c, null, r);
4210 }
4211 r.connections = null;
4212 }
4213 }
4214
4215 /**
4216 * Perform the common clean-up of an activity record. This is called both
4217 * as part of destroyActivityLocked() (when destroying the client-side
4218 * representation) and cleaning things up as a result of its hosting
4219 * processing going away, in which case there is no remaining client-side
4220 * state to destroy so only the cleanup here is needed.
4221 */
4222 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4223 if (mResumedActivity == r) {
4224 mResumedActivity = null;
4225 }
4226 if (mFocusedActivity == r) {
4227 mFocusedActivity = null;
4228 }
4229
4230 r.configDestroy = false;
4231 r.frozenBeforeDestroy = false;
4232
4233 // Make sure this record is no longer in the pending finishes list.
4234 // This could happen, for example, if we are trimming activities
4235 // down to the max limit while they are still waiting to finish.
4236 mFinishingActivities.remove(r);
4237 mWaitingVisibleActivities.remove(r);
4238
4239 // Remove any pending results.
4240 if (r.finishing && r.pendingResults != null) {
4241 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4242 PendingIntentRecord rec = apr.get();
4243 if (rec != null) {
4244 cancelIntentSenderLocked(rec, false);
4245 }
4246 }
4247 r.pendingResults = null;
4248 }
4249
4250 if (cleanServices) {
4251 cleanUpActivityServicesLocked(r);
4252 }
4253
4254 if (mPendingThumbnails.size() > 0) {
4255 // There are clients waiting to receive thumbnails so, in case
4256 // this is an activity that someone is waiting for, add it
4257 // to the pending list so we can correctly update the clients.
4258 mCancelledThumbnails.add(r);
4259 }
4260
4261 // Get rid of any pending idle timeouts.
4262 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4263 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4264 }
4265
4266 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4267 if (r.state != ActivityState.DESTROYED) {
4268 mHistory.remove(r);
4269 r.inHistory = false;
4270 r.state = ActivityState.DESTROYED;
4271 mWindowManager.removeAppToken(r);
4272 if (VALIDATE_TOKENS) {
4273 mWindowManager.validateAppTokens(mHistory);
4274 }
4275 cleanUpActivityServicesLocked(r);
4276 removeActivityUriPermissionsLocked(r);
4277 }
4278 }
4279
4280 /**
4281 * Destroy the current CLIENT SIDE instance of an activity. This may be
4282 * called both when actually finishing an activity, or when performing
4283 * a configuration switch where we destroy the current client-side object
4284 * but then create a new client-side object for this same HistoryRecord.
4285 */
4286 private final boolean destroyActivityLocked(HistoryRecord r,
4287 boolean removeFromApp) {
4288 if (DEBUG_SWITCH) Log.v(
4289 TAG, "Removing activity: token=" + r
4290 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
Doug Zongker2bec3d42009-12-04 12:52:44 -08004291 EventLog.writeEvent(EventLogTags.AM_DESTROY_ACTIVITY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004292 System.identityHashCode(r),
4293 r.task.taskId, r.shortComponentName);
4294
4295 boolean removedFromHistory = false;
4296
4297 cleanUpActivityLocked(r, false);
4298
4299 if (r.app != null) {
4300 if (removeFromApp) {
4301 int idx = r.app.activities.indexOf(r);
4302 if (idx >= 0) {
4303 r.app.activities.remove(idx);
4304 }
4305 if (r.persistent) {
4306 decPersistentCountLocked(r.app);
4307 }
4308 }
4309
4310 boolean skipDestroy = false;
4311
4312 try {
4313 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4314 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4315 r.configChangeFlags);
4316 } catch (Exception e) {
4317 // We can just ignore exceptions here... if the process
4318 // has crashed, our death notification will clean things
4319 // up.
4320 //Log.w(TAG, "Exception thrown during finish", e);
4321 if (r.finishing) {
4322 removeActivityFromHistoryLocked(r);
4323 removedFromHistory = true;
4324 skipDestroy = true;
4325 }
4326 }
4327
4328 r.app = null;
4329 r.nowVisible = false;
4330
4331 if (r.finishing && !skipDestroy) {
4332 r.state = ActivityState.DESTROYING;
4333 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4334 msg.obj = r;
4335 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4336 } else {
4337 r.state = ActivityState.DESTROYED;
4338 }
4339 } else {
4340 // remove this record from the history.
4341 if (r.finishing) {
4342 removeActivityFromHistoryLocked(r);
4343 removedFromHistory = true;
4344 } else {
4345 r.state = ActivityState.DESTROYED;
4346 }
4347 }
4348
4349 r.configChangeFlags = 0;
4350
4351 if (!mLRUActivities.remove(r)) {
4352 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4353 }
4354
4355 return removedFromHistory;
4356 }
4357
4358 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4359 ProcessRecord app)
4360 {
4361 int i = list.size();
4362 if (localLOGV) Log.v(
4363 TAG, "Removing app " + app + " from list " + list
4364 + " with " + i + " entries");
4365 while (i > 0) {
4366 i--;
4367 HistoryRecord r = (HistoryRecord)list.get(i);
4368 if (localLOGV) Log.v(
4369 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4370 if (r.app == app) {
4371 if (localLOGV) Log.v(TAG, "Removing this entry!");
4372 list.remove(i);
4373 }
4374 }
4375 }
4376
4377 /**
4378 * Main function for removing an existing process from the activity manager
4379 * as a result of that process going away. Clears out all connections
4380 * to the process.
4381 */
4382 private final void handleAppDiedLocked(ProcessRecord app,
4383 boolean restarting) {
4384 cleanUpApplicationRecordLocked(app, restarting, -1);
4385 if (!restarting) {
4386 mLRUProcesses.remove(app);
4387 }
4388
4389 // Just in case...
4390 if (mPausingActivity != null && mPausingActivity.app == app) {
4391 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4392 mPausingActivity = null;
4393 }
4394 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4395 mLastPausedActivity = null;
4396 }
4397
4398 // Remove this application's activities from active lists.
4399 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4400 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4401 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4402 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4403
4404 boolean atTop = true;
4405 boolean hasVisibleActivities = false;
4406
4407 // Clean out the history list.
4408 int i = mHistory.size();
4409 if (localLOGV) Log.v(
4410 TAG, "Removing app " + app + " from history with " + i + " entries");
4411 while (i > 0) {
4412 i--;
4413 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4414 if (localLOGV) Log.v(
4415 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4416 if (r.app == app) {
4417 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4418 if (localLOGV) Log.v(
4419 TAG, "Removing this entry! frozen=" + r.haveState
4420 + " finishing=" + r.finishing);
4421 mHistory.remove(i);
4422
4423 r.inHistory = false;
4424 mWindowManager.removeAppToken(r);
4425 if (VALIDATE_TOKENS) {
4426 mWindowManager.validateAppTokens(mHistory);
4427 }
4428 removeActivityUriPermissionsLocked(r);
4429
4430 } else {
4431 // We have the current state for this activity, so
4432 // it can be restarted later when needed.
4433 if (localLOGV) Log.v(
4434 TAG, "Keeping entry, setting app to null");
4435 if (r.visible) {
4436 hasVisibleActivities = true;
4437 }
4438 r.app = null;
4439 r.nowVisible = false;
4440 if (!r.haveState) {
4441 r.icicle = null;
4442 }
4443 }
4444
4445 cleanUpActivityLocked(r, true);
4446 r.state = ActivityState.STOPPED;
4447 }
4448 atTop = false;
4449 }
4450
4451 app.activities.clear();
4452
4453 if (app.instrumentationClass != null) {
4454 Log.w(TAG, "Crash of app " + app.processName
4455 + " running instrumentation " + app.instrumentationClass);
4456 Bundle info = new Bundle();
4457 info.putString("shortMsg", "Process crashed.");
4458 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4459 }
4460
4461 if (!restarting) {
4462 if (!resumeTopActivityLocked(null)) {
4463 // If there was nothing to resume, and we are not already
4464 // restarting this process, but there is a visible activity that
4465 // is hosted by the process... then make sure all visible
4466 // activities are running, taking care of restarting this
4467 // process.
4468 if (hasVisibleActivities) {
4469 ensureActivitiesVisibleLocked(null, 0);
4470 }
4471 }
4472 }
4473 }
4474
4475 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4476 IBinder threadBinder = thread.asBinder();
4477
4478 // Find the application record.
4479 int count = mLRUProcesses.size();
4480 int i;
4481 for (i=0; i<count; i++) {
4482 ProcessRecord rec = mLRUProcesses.get(i);
4483 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4484 return i;
4485 }
4486 }
4487 return -1;
4488 }
4489
4490 private final ProcessRecord getRecordForAppLocked(
4491 IApplicationThread thread) {
4492 if (thread == null) {
4493 return null;
4494 }
4495
4496 int appIndex = getLRURecordIndexForAppLocked(thread);
4497 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4498 }
4499
4500 private final void appDiedLocked(ProcessRecord app, int pid,
4501 IApplicationThread thread) {
4502
4503 mProcDeaths[0]++;
4504
4505 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4506 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4507 + ") has died.");
Doug Zongker2bec3d42009-12-04 12:52:44 -08004508 EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004509 if (localLOGV) Log.v(
4510 TAG, "Dying app: " + app + ", pid: " + pid
4511 + ", thread: " + thread.asBinder());
4512 boolean doLowMem = app.instrumentationClass == null;
4513 handleAppDiedLocked(app, false);
4514
4515 if (doLowMem) {
4516 // If there are no longer any background processes running,
4517 // and the app that died was not running instrumentation,
4518 // then tell everyone we are now low on memory.
4519 boolean haveBg = false;
4520 int count = mLRUProcesses.size();
4521 int i;
4522 for (i=0; i<count; i++) {
4523 ProcessRecord rec = mLRUProcesses.get(i);
4524 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4525 haveBg = true;
4526 break;
4527 }
4528 }
4529
4530 if (!haveBg) {
4531 Log.i(TAG, "Low Memory: No more background processes.");
Doug Zongker2bec3d42009-12-04 12:52:44 -08004532 EventLog.writeEvent(EventLogTags.AM_LOW_MEMORY, mLRUProcesses.size());
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004533 long now = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004534 for (i=0; i<count; i++) {
4535 ProcessRecord rec = mLRUProcesses.get(i);
Dianne Hackborn36124872009-10-08 16:22:03 -07004536 if (rec != app && rec.thread != null &&
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004537 (rec.lastLowMemory+GC_MIN_INTERVAL) <= now) {
4538 // The low memory report is overriding any current
4539 // state for a GC request. Make sure to do
4540 // visible/foreground processes first.
4541 if (rec.setAdj <= VISIBLE_APP_ADJ) {
4542 rec.lastRequestedGc = 0;
4543 } else {
4544 rec.lastRequestedGc = rec.lastLowMemory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004545 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004546 rec.reportLowMemory = true;
4547 rec.lastLowMemory = now;
4548 mProcessesToGc.remove(rec);
4549 addProcessToGcListLocked(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004550 }
4551 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -07004552 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004553 }
4554 }
4555 } else if (Config.LOGD) {
4556 Log.d(TAG, "Received spurious death notification for thread "
4557 + thread.asBinder());
4558 }
4559 }
4560
4561 final String readFile(String filename) {
4562 try {
4563 FileInputStream fs = new FileInputStream(filename);
4564 byte[] inp = new byte[8192];
4565 int size = fs.read(inp);
4566 fs.close();
4567 return new String(inp, 0, 0, size);
4568 } catch (java.io.IOException e) {
4569 }
4570 return "";
4571 }
4572
4573 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004574 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004575 if (app.notResponding || app.crashing) {
4576 return;
4577 }
4578
4579 // Log the ANR to the event log.
Doug Zongker2bec3d42009-12-04 12:52:44 -08004580 EventLog.writeEvent(EventLogTags.ANR, app.pid, app.processName, annotation);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004581
4582 // If we are on a secure build and the application is not interesting to the user (it is
4583 // not visible or in the background), just kill it instead of displaying a dialog.
4584 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4585 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4586 Process.killProcess(app.pid);
4587 return;
4588 }
4589
4590 // DeviceMonitor.start();
4591
4592 String processInfo = null;
4593 if (MONITOR_CPU_USAGE) {
4594 updateCpuStatsNow();
4595 synchronized (mProcessStatsThread) {
4596 processInfo = mProcessStats.printCurrentState();
4597 }
4598 }
4599
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004600 StringBuilder info = mStringBuilder;
4601 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004602 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004603 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004604 if (reportedActivity != null && reportedActivity.app != null) {
4605 info.append(" (last in ");
4606 info.append(reportedActivity.app.processName);
4607 info.append(")");
4608 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004609 if (annotation != null) {
4610 info.append("\nAnnotation: ");
4611 info.append(annotation);
4612 }
4613 if (MONITOR_CPU_USAGE) {
4614 info.append("\nCPU usage:\n");
4615 info.append(processInfo);
4616 }
4617 Log.i(TAG, info.toString());
4618
4619 // The application is not responding. Dump as many thread traces as we can.
4620 boolean fileDump = prepareTraceFile(true);
4621 if (!fileDump) {
4622 // Dumping traces to the log, just dump the process that isn't responding so
4623 // we don't overflow the log
4624 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4625 } else {
4626 // Dumping traces to a file so dump all active processes we know about
4627 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004628 // First, these are the most important processes.
4629 final int[] imppids = new int[3];
4630 int i=0;
4631 imppids[0] = app.pid;
4632 i++;
4633 if (reportedActivity != null && reportedActivity.app != null
4634 && reportedActivity.app.thread != null
4635 && reportedActivity.app.pid != app.pid) {
4636 imppids[i] = reportedActivity.app.pid;
4637 i++;
4638 }
4639 imppids[i] = Process.myPid();
4640 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4641 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4642 synchronized (this) {
4643 try {
4644 wait(200);
4645 } catch (InterruptedException e) {
4646 }
4647 }
4648 }
4649 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004650 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004651 boolean done = false;
4652 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4653 if (imppids[j] == r.pid) {
4654 done = true;
4655 break;
4656 }
4657 }
4658 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004659 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004660 synchronized (this) {
4661 try {
4662 wait(200);
4663 } catch (InterruptedException e) {
4664 }
4665 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004666 }
4667 }
4668 }
4669 }
4670
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004671 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004672 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004673 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004674 app.pid, info.toString());
4675 if (res != 0) {
4676 if (res < 0) {
4677 // wait until the SIGQUIT has had a chance to process before killing the
4678 // process.
4679 try {
4680 wait(2000);
4681 } catch (InterruptedException e) {
4682 }
4683
4684 Process.killProcess(app.pid);
4685 return;
4686 }
4687 }
4688 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004689 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004690 }
4691 }
4692
4693 makeAppNotRespondingLocked(app,
4694 activity != null ? activity.shortComponentName : null,
4695 annotation != null ? "ANR " + annotation : "ANR",
Dan Egnorb7f03672009-12-09 16:22:32 -08004696 info.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004697 Message msg = Message.obtain();
4698 HashMap map = new HashMap();
4699 msg.what = SHOW_NOT_RESPONDING_MSG;
4700 msg.obj = map;
4701 map.put("app", app);
4702 if (activity != null) {
4703 map.put("activity", activity);
4704 }
4705
4706 mHandler.sendMessage(msg);
4707 return;
4708 }
4709
4710 /**
4711 * If a stack trace file has been configured, prepare the filesystem
4712 * by creating the directory if it doesn't exist and optionally
4713 * removing the old trace file.
4714 *
4715 * @param removeExisting If set, the existing trace file will be removed.
4716 * @return Returns true if the trace file preparations succeeded
4717 */
4718 public static boolean prepareTraceFile(boolean removeExisting) {
4719 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4720 boolean fileReady = false;
4721 if (!TextUtils.isEmpty(tracesPath)) {
4722 File f = new File(tracesPath);
4723 if (!f.exists()) {
4724 // Ensure the enclosing directory exists
4725 File dir = f.getParentFile();
4726 if (!dir.exists()) {
4727 fileReady = dir.mkdirs();
4728 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004729 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004730 } else if (dir.isDirectory()) {
4731 fileReady = true;
4732 }
4733 } else if (removeExisting) {
4734 // Remove the previous traces file, so we don't fill the disk.
4735 // The VM will recreate it
4736 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4737 fileReady = f.delete();
4738 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004739
4740 if (removeExisting) {
4741 try {
4742 f.createNewFile();
4743 FileUtils.setPermissions(f.getAbsolutePath(),
4744 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4745 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4746 fileReady = true;
4747 } catch (IOException e) {
4748 Log.w(TAG, "Unable to make ANR traces file", e);
4749 }
4750 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004751 }
4752
4753 return fileReady;
4754 }
4755
4756
4757 private final void decPersistentCountLocked(ProcessRecord app)
4758 {
4759 app.persistentActivities--;
4760 if (app.persistentActivities > 0) {
4761 // Still more of 'em...
4762 return;
4763 }
4764 if (app.persistent) {
4765 // Ah, but the application itself is persistent. Whatever!
4766 return;
4767 }
4768
4769 // App is no longer persistent... make sure it and the ones
4770 // following it in the LRU list have the correc oom_adj.
4771 updateOomAdjLocked();
4772 }
4773
4774 public void setPersistent(IBinder token, boolean isPersistent) {
4775 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4776 != PackageManager.PERMISSION_GRANTED) {
4777 String msg = "Permission Denial: setPersistent() from pid="
4778 + Binder.getCallingPid()
4779 + ", uid=" + Binder.getCallingUid()
4780 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4781 Log.w(TAG, msg);
4782 throw new SecurityException(msg);
4783 }
4784
4785 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004786 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004787 if (index < 0) {
4788 return;
4789 }
4790 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4791 ProcessRecord app = r.app;
4792
4793 if (localLOGV) Log.v(
4794 TAG, "Setting persistence " + isPersistent + ": " + r);
4795
4796 if (isPersistent) {
4797 if (r.persistent) {
4798 // Okay okay, I heard you already!
4799 if (localLOGV) Log.v(TAG, "Already persistent!");
4800 return;
4801 }
4802 r.persistent = true;
4803 app.persistentActivities++;
4804 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4805 if (app.persistentActivities > 1) {
4806 // We aren't the first...
4807 if (localLOGV) Log.v(TAG, "Not the first!");
4808 return;
4809 }
4810 if (app.persistent) {
4811 // This would be redundant.
4812 if (localLOGV) Log.v(TAG, "App is persistent!");
4813 return;
4814 }
4815
4816 // App is now persistent... make sure it and the ones
4817 // following it now have the correct oom_adj.
4818 final long origId = Binder.clearCallingIdentity();
4819 updateOomAdjLocked();
4820 Binder.restoreCallingIdentity(origId);
4821
4822 } else {
4823 if (!r.persistent) {
4824 // Okay okay, I heard you already!
4825 return;
4826 }
4827 r.persistent = false;
4828 final long origId = Binder.clearCallingIdentity();
4829 decPersistentCountLocked(app);
4830 Binder.restoreCallingIdentity(origId);
4831
4832 }
4833 }
4834 }
4835
4836 public boolean clearApplicationUserData(final String packageName,
4837 final IPackageDataObserver observer) {
4838 int uid = Binder.getCallingUid();
4839 int pid = Binder.getCallingPid();
4840 long callingId = Binder.clearCallingIdentity();
4841 try {
4842 IPackageManager pm = ActivityThread.getPackageManager();
4843 int pkgUid = -1;
4844 synchronized(this) {
4845 try {
4846 pkgUid = pm.getPackageUid(packageName);
4847 } catch (RemoteException e) {
4848 }
4849 if (pkgUid == -1) {
4850 Log.w(TAG, "Invalid packageName:" + packageName);
4851 return false;
4852 }
4853 if (uid == pkgUid || checkComponentPermission(
4854 android.Manifest.permission.CLEAR_APP_USER_DATA,
4855 pid, uid, -1)
4856 == PackageManager.PERMISSION_GRANTED) {
4857 restartPackageLocked(packageName, pkgUid);
4858 } else {
4859 throw new SecurityException(pid+" does not have permission:"+
4860 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4861 "for process:"+packageName);
4862 }
4863 }
4864
4865 try {
4866 //clear application user data
4867 pm.clearApplicationUserData(packageName, observer);
4868 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4869 Uri.fromParts("package", packageName, null));
4870 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4871 broadcastIntentLocked(null, null, intent,
4872 null, null, 0, null, null, null,
4873 false, false, MY_PID, Process.SYSTEM_UID);
4874 } catch (RemoteException e) {
4875 }
4876 } finally {
4877 Binder.restoreCallingIdentity(callingId);
4878 }
4879 return true;
4880 }
4881
4882 public void restartPackage(final String packageName) {
4883 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4884 != PackageManager.PERMISSION_GRANTED) {
4885 String msg = "Permission Denial: restartPackage() from pid="
4886 + Binder.getCallingPid()
4887 + ", uid=" + Binder.getCallingUid()
4888 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4889 Log.w(TAG, msg);
4890 throw new SecurityException(msg);
4891 }
4892
4893 long callingId = Binder.clearCallingIdentity();
4894 try {
4895 IPackageManager pm = ActivityThread.getPackageManager();
4896 int pkgUid = -1;
4897 synchronized(this) {
4898 try {
4899 pkgUid = pm.getPackageUid(packageName);
4900 } catch (RemoteException e) {
4901 }
4902 if (pkgUid == -1) {
4903 Log.w(TAG, "Invalid packageName: " + packageName);
4904 return;
4905 }
4906 restartPackageLocked(packageName, pkgUid);
4907 }
4908 } finally {
4909 Binder.restoreCallingIdentity(callingId);
4910 }
4911 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004912
4913 /*
4914 * The pkg name and uid have to be specified.
4915 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4916 */
4917 public void killApplicationWithUid(String pkg, int uid) {
4918 if (pkg == null) {
4919 return;
4920 }
4921 // Make sure the uid is valid.
4922 if (uid < 0) {
4923 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4924 return;
4925 }
4926 int callerUid = Binder.getCallingUid();
4927 // Only the system server can kill an application
4928 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004929 // Post an aysnc message to kill the application
4930 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4931 msg.arg1 = uid;
4932 msg.arg2 = 0;
4933 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004934 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004935 } else {
4936 throw new SecurityException(callerUid + " cannot kill pkg: " +
4937 pkg);
4938 }
4939 }
4940
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004941 public void closeSystemDialogs(String reason) {
4942 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4943 if (reason != null) {
4944 intent.putExtra("reason", reason);
4945 }
4946
4947 final int uid = Binder.getCallingUid();
4948 final long origId = Binder.clearCallingIdentity();
4949 synchronized (this) {
4950 int i = mWatchers.beginBroadcast();
4951 while (i > 0) {
4952 i--;
4953 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4954 if (w != null) {
4955 try {
4956 w.closingSystemDialogs(reason);
4957 } catch (RemoteException e) {
4958 }
4959 }
4960 }
4961 mWatchers.finishBroadcast();
4962
Dianne Hackbornffa42482009-09-23 22:20:11 -07004963 mWindowManager.closeSystemDialogs(reason);
4964
4965 for (i=mHistory.size()-1; i>=0; i--) {
4966 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4967 if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
4968 finishActivityLocked(r, i,
4969 Activity.RESULT_CANCELED, null, "close-sys");
4970 }
4971 }
4972
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004973 broadcastIntentLocked(null, null, intent, null,
4974 null, 0, null, null, null, false, false, -1, uid);
4975 }
4976 Binder.restoreCallingIdentity(origId);
4977 }
4978
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004979 public Debug.MemoryInfo[] getProcessMemoryInfo(int[] pids)
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004980 throws RemoteException {
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004981 Debug.MemoryInfo[] infos = new Debug.MemoryInfo[pids.length];
4982 for (int i=pids.length-1; i>=0; i--) {
4983 infos[i] = new Debug.MemoryInfo();
4984 Debug.getMemoryInfo(pids[i], infos[i]);
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004985 }
Dianne Hackborn4f21c4c2009-09-17 10:24:05 -07004986 return infos;
Dianne Hackborn3025ef32009-08-31 21:31:47 -07004987 }
Christopher Tate5e1ab332009-09-01 20:32:49 -07004988
4989 public void killApplicationProcess(String processName, int uid) {
4990 if (processName == null) {
4991 return;
4992 }
4993
4994 int callerUid = Binder.getCallingUid();
4995 // Only the system server can kill an application
4996 if (callerUid == Process.SYSTEM_UID) {
4997 synchronized (this) {
4998 ProcessRecord app = getProcessRecordLocked(processName, uid);
4999 if (app != null) {
5000 try {
5001 app.thread.scheduleSuicide();
5002 } catch (RemoteException e) {
5003 // If the other end already died, then our work here is done.
5004 }
5005 } else {
5006 Log.w(TAG, "Process/uid not found attempting kill of "
5007 + processName + " / " + uid);
5008 }
5009 }
5010 } else {
5011 throw new SecurityException(callerUid + " cannot kill app process: " +
5012 processName);
5013 }
5014 }
5015
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005016 private void restartPackageLocked(final String packageName, int uid) {
5017 uninstallPackageLocked(packageName, uid, false);
5018 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
5019 Uri.fromParts("package", packageName, null));
5020 intent.putExtra(Intent.EXTRA_UID, uid);
5021 broadcastIntentLocked(null, null, intent,
5022 null, null, 0, null, null, null,
5023 false, false, MY_PID, Process.SYSTEM_UID);
5024 }
5025
5026 private final void uninstallPackageLocked(String name, int uid,
5027 boolean callerWillRestart) {
5028 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
5029
5030 int i, N;
5031
5032 final String procNamePrefix = name + ":";
5033 if (uid < 0) {
5034 try {
5035 uid = ActivityThread.getPackageManager().getPackageUid(name);
5036 } catch (RemoteException e) {
5037 }
5038 }
5039
5040 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
5041 while (badApps.hasNext()) {
5042 SparseArray<Long> ba = badApps.next();
5043 if (ba.get(uid) != null) {
5044 badApps.remove();
5045 }
5046 }
5047
5048 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
5049
5050 // Remove all processes this package may have touched: all with the
5051 // same UID (except for the system or root user), and all whose name
5052 // matches the package name.
5053 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
5054 final int NA = apps.size();
5055 for (int ia=0; ia<NA; ia++) {
5056 ProcessRecord app = apps.valueAt(ia);
5057 if (app.removed) {
5058 procs.add(app);
5059 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
5060 || app.processName.equals(name)
5061 || app.processName.startsWith(procNamePrefix)) {
5062 app.removed = true;
5063 procs.add(app);
5064 }
5065 }
5066 }
5067
5068 N = procs.size();
5069 for (i=0; i<N; i++) {
5070 removeProcessLocked(procs.get(i), callerWillRestart);
5071 }
5072
5073 for (i=mHistory.size()-1; i>=0; i--) {
5074 HistoryRecord r = (HistoryRecord)mHistory.get(i);
5075 if (r.packageName.equals(name)) {
5076 if (Config.LOGD) Log.d(
5077 TAG, " Force finishing activity "
5078 + r.intent.getComponent().flattenToShortString());
5079 if (r.app != null) {
5080 r.app.removed = true;
5081 }
5082 r.app = null;
5083 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
5084 }
5085 }
5086
5087 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
5088 for (ServiceRecord service : mServices.values()) {
5089 if (service.packageName.equals(name)) {
5090 if (service.app != null) {
5091 service.app.removed = true;
5092 }
5093 service.app = null;
5094 services.add(service);
5095 }
5096 }
5097
5098 N = services.size();
5099 for (i=0; i<N; i++) {
5100 bringDownServiceLocked(services.get(i), true);
5101 }
5102
5103 resumeTopActivityLocked(null);
5104 }
5105
5106 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
5107 final String name = app.processName;
5108 final int uid = app.info.uid;
5109 if (Config.LOGD) Log.d(
5110 TAG, "Force removing process " + app + " (" + name
5111 + "/" + uid + ")");
5112
5113 mProcessNames.remove(name, uid);
5114 boolean needRestart = false;
5115 if (app.pid > 0 && app.pid != MY_PID) {
5116 int pid = app.pid;
5117 synchronized (mPidsSelfLocked) {
5118 mPidsSelfLocked.remove(pid);
5119 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5120 }
5121 handleAppDiedLocked(app, true);
5122 mLRUProcesses.remove(app);
5123 Process.killProcess(pid);
5124
5125 if (app.persistent) {
5126 if (!callerWillRestart) {
5127 addAppLocked(app.info);
5128 } else {
5129 needRestart = true;
5130 }
5131 }
5132 } else {
5133 mRemovedProcesses.add(app);
5134 }
5135
5136 return needRestart;
5137 }
5138
5139 private final void processStartTimedOutLocked(ProcessRecord app) {
5140 final int pid = app.pid;
5141 boolean gone = false;
5142 synchronized (mPidsSelfLocked) {
5143 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
5144 if (knownApp != null && knownApp.thread == null) {
5145 mPidsSelfLocked.remove(pid);
5146 gone = true;
5147 }
5148 }
5149
5150 if (gone) {
5151 Log.w(TAG, "Process " + app + " failed to attach");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005152 EventLog.writeEvent(EventLogTags.AM_PROCESS_START_TIMEOUT, pid, app.info.uid,
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005153 app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005154 mProcessNames.remove(app.processName, app.info.uid);
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005155 // Take care of any launching providers waiting for this process.
5156 checkAppInLaunchingProvidersLocked(app, true);
5157 // Take care of any services that are waiting for the process.
5158 for (int i=0; i<mPendingServices.size(); i++) {
5159 ServiceRecord sr = mPendingServices.get(i);
5160 if (app.info.uid == sr.appInfo.uid
5161 && app.processName.equals(sr.processName)) {
5162 Log.w(TAG, "Forcing bringing down service: " + sr);
5163 mPendingServices.remove(i);
5164 i--;
5165 bringDownServiceLocked(sr, true);
5166 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005167 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005168 Process.killProcess(pid);
Christopher Tate181fafa2009-05-14 11:12:14 -07005169 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5170 Log.w(TAG, "Unattached app died before backup, skipping");
5171 try {
5172 IBackupManager bm = IBackupManager.Stub.asInterface(
5173 ServiceManager.getService(Context.BACKUP_SERVICE));
5174 bm.agentDisconnected(app.info.packageName);
5175 } catch (RemoteException e) {
5176 // Can't happen; the backup manager is local
5177 }
5178 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08005179 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5180 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5181 mPendingBroadcast = null;
5182 scheduleBroadcastsLocked();
5183 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005184 } else {
5185 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5186 }
5187 }
5188
5189 private final boolean attachApplicationLocked(IApplicationThread thread,
5190 int pid) {
5191
5192 // Find the application record that is being attached... either via
5193 // the pid if we are running in multiple processes, or just pull the
5194 // next app record if we are emulating process with anonymous threads.
5195 ProcessRecord app;
5196 if (pid != MY_PID && pid >= 0) {
5197 synchronized (mPidsSelfLocked) {
5198 app = mPidsSelfLocked.get(pid);
5199 }
5200 } else if (mStartingProcesses.size() > 0) {
5201 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005202 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005203 } else {
5204 app = null;
5205 }
5206
5207 if (app == null) {
5208 Log.w(TAG, "No pending application record for pid " + pid
5209 + " (IApplicationThread " + thread + "); dropping process");
Doug Zongker2bec3d42009-12-04 12:52:44 -08005210 EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005211 if (pid > 0 && pid != MY_PID) {
5212 Process.killProcess(pid);
5213 } else {
5214 try {
5215 thread.scheduleExit();
5216 } catch (Exception e) {
5217 // Ignore exceptions.
5218 }
5219 }
5220 return false;
5221 }
5222
5223 // If this application record is still attached to a previous
5224 // process, clean it up now.
5225 if (app.thread != null) {
5226 handleAppDiedLocked(app, true);
5227 }
5228
5229 // Tell the process all about itself.
5230
5231 if (localLOGV) Log.v(
5232 TAG, "Binding process pid " + pid + " to record " + app);
5233
5234 String processName = app.processName;
5235 try {
5236 thread.asBinder().linkToDeath(new AppDeathRecipient(
5237 app, pid, thread), 0);
5238 } catch (RemoteException e) {
5239 app.resetPackageList();
5240 startProcessLocked(app, "link fail", processName);
5241 return false;
5242 }
5243
Doug Zongker2bec3d42009-12-04 12:52:44 -08005244 EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.pid, app.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005245
5246 app.thread = thread;
5247 app.curAdj = app.setAdj = -100;
Dianne Hackborn09c916b2009-12-08 14:50:51 -08005248 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
5249 app.setSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005250 app.forcingToForeground = null;
5251 app.foregroundServices = false;
5252 app.debugging = false;
5253
5254 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5255
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005256 boolean normalMode = mSystemReady || isAllowedWhileBooting(app.info);
5257 List providers = normalMode ? generateApplicationProvidersLocked(app) : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005258
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005259 if (!normalMode) {
5260 Log.i(TAG, "Launching preboot mode app: " + app);
5261 }
5262
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005263 if (localLOGV) Log.v(
5264 TAG, "New app record " + app
5265 + " thread=" + thread.asBinder() + " pid=" + pid);
5266 try {
5267 int testMode = IApplicationThread.DEBUG_OFF;
5268 if (mDebugApp != null && mDebugApp.equals(processName)) {
5269 testMode = mWaitForDebugger
5270 ? IApplicationThread.DEBUG_WAIT
5271 : IApplicationThread.DEBUG_ON;
5272 app.debugging = true;
5273 if (mDebugTransient) {
5274 mDebugApp = mOrigDebugApp;
5275 mWaitForDebugger = mOrigWaitForDebugger;
5276 }
5277 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005278
Christopher Tate181fafa2009-05-14 11:12:14 -07005279 // If the app is being launched for restore or full backup, set it up specially
5280 boolean isRestrictedBackupMode = false;
5281 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5282 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5283 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5284 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005285
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005286 ensurePackageDexOpt(app.instrumentationInfo != null
5287 ? app.instrumentationInfo.packageName
5288 : app.info.packageName);
5289 if (app.instrumentationClass != null) {
5290 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005291 }
Dianne Hackborndc6b6352009-09-30 14:20:09 -07005292 if (DEBUG_CONFIGURATION) Log.v(TAG, "Binding proc "
5293 + processName + " with config " + mConfiguration);
Dianne Hackborn1655be42009-05-08 14:29:01 -07005294 thread.bindApplication(processName, app.instrumentationInfo != null
5295 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005296 app.instrumentationClass, app.instrumentationProfileFile,
5297 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005298 isRestrictedBackupMode || !normalMode,
5299 mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005300 updateLRUListLocked(app, false);
Dianne Hackbornfd12af42009-08-27 00:44:33 -07005301 app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005302 } catch (Exception e) {
5303 // todo: Yikes! What should we do? For now we will try to
5304 // start another process, but that could easily get us in
5305 // an infinite loop of restarting processes...
5306 Log.w(TAG, "Exception thrown during bind!", e);
5307
5308 app.resetPackageList();
5309 startProcessLocked(app, "bind fail", processName);
5310 return false;
5311 }
5312
5313 // Remove this record from the list of starting applications.
5314 mPersistentStartingProcesses.remove(app);
5315 mProcessesOnHold.remove(app);
5316
5317 boolean badApp = false;
5318 boolean didSomething = false;
5319
5320 // See if the top visible activity is waiting to run in this process...
5321 HistoryRecord hr = topRunningActivityLocked(null);
5322 if (hr != null) {
5323 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5324 && processName.equals(hr.processName)) {
5325 try {
5326 if (realStartActivityLocked(hr, app, true, true)) {
5327 didSomething = true;
5328 }
5329 } catch (Exception e) {
5330 Log.w(TAG, "Exception in new application when starting activity "
5331 + hr.intent.getComponent().flattenToShortString(), e);
5332 badApp = true;
5333 }
5334 } else {
5335 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5336 }
5337 }
5338
5339 // Find any services that should be running in this process...
5340 if (!badApp && mPendingServices.size() > 0) {
5341 ServiceRecord sr = null;
5342 try {
5343 for (int i=0; i<mPendingServices.size(); i++) {
5344 sr = mPendingServices.get(i);
5345 if (app.info.uid != sr.appInfo.uid
5346 || !processName.equals(sr.processName)) {
5347 continue;
5348 }
5349
5350 mPendingServices.remove(i);
5351 i--;
5352 realStartServiceLocked(sr, app);
5353 didSomething = true;
5354 }
5355 } catch (Exception e) {
5356 Log.w(TAG, "Exception in new application when starting service "
5357 + sr.shortName, e);
5358 badApp = true;
5359 }
5360 }
5361
5362 // Check if the next broadcast receiver is in this process...
5363 BroadcastRecord br = mPendingBroadcast;
5364 if (!badApp && br != null && br.curApp == app) {
5365 try {
5366 mPendingBroadcast = null;
5367 processCurBroadcastLocked(br, app);
5368 didSomething = true;
5369 } catch (Exception e) {
5370 Log.w(TAG, "Exception in new application when starting receiver "
5371 + br.curComponent.flattenToShortString(), e);
5372 badApp = true;
5373 logBroadcastReceiverDiscard(br);
5374 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5375 br.resultExtras, br.resultAbort, true);
5376 scheduleBroadcastsLocked();
5377 }
5378 }
5379
Christopher Tate181fafa2009-05-14 11:12:14 -07005380 // Check whether the next backup agent is in this process...
5381 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5382 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005383 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005384 try {
5385 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5386 } catch (Exception e) {
5387 Log.w(TAG, "Exception scheduling backup agent creation: ");
5388 e.printStackTrace();
5389 }
5390 }
5391
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005392 if (badApp) {
5393 // todo: Also need to kill application to deal with all
5394 // kinds of exceptions.
5395 handleAppDiedLocked(app, false);
5396 return false;
5397 }
5398
5399 if (!didSomething) {
5400 updateOomAdjLocked();
5401 }
5402
5403 return true;
5404 }
5405
5406 public final void attachApplication(IApplicationThread thread) {
5407 synchronized (this) {
5408 int callingPid = Binder.getCallingPid();
5409 final long origId = Binder.clearCallingIdentity();
5410 attachApplicationLocked(thread, callingPid);
5411 Binder.restoreCallingIdentity(origId);
5412 }
5413 }
5414
Dianne Hackborne88846e2009-09-30 21:34:25 -07005415 public final void activityIdle(IBinder token, Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005416 final long origId = Binder.clearCallingIdentity();
Dianne Hackborne88846e2009-09-30 21:34:25 -07005417 activityIdleInternal(token, false, config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005418 Binder.restoreCallingIdentity(origId);
5419 }
5420
5421 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5422 boolean remove) {
5423 int N = mStoppingActivities.size();
5424 if (N <= 0) return null;
5425
5426 ArrayList<HistoryRecord> stops = null;
5427
5428 final boolean nowVisible = mResumedActivity != null
5429 && mResumedActivity.nowVisible
5430 && !mResumedActivity.waitingVisible;
5431 for (int i=0; i<N; i++) {
5432 HistoryRecord s = mStoppingActivities.get(i);
5433 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5434 + nowVisible + " waitingVisible=" + s.waitingVisible
5435 + " finishing=" + s.finishing);
5436 if (s.waitingVisible && nowVisible) {
5437 mWaitingVisibleActivities.remove(s);
5438 s.waitingVisible = false;
5439 if (s.finishing) {
5440 // If this activity is finishing, it is sitting on top of
5441 // everyone else but we now know it is no longer needed...
5442 // so get rid of it. Otherwise, we need to go through the
5443 // normal flow and hide it once we determine that it is
5444 // hidden by the activities in front of it.
5445 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5446 mWindowManager.setAppVisibility(s, false);
5447 }
5448 }
5449 if (!s.waitingVisible && remove) {
5450 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5451 if (stops == null) {
5452 stops = new ArrayList<HistoryRecord>();
5453 }
5454 stops.add(s);
5455 mStoppingActivities.remove(i);
5456 N--;
5457 i--;
5458 }
5459 }
5460
5461 return stops;
5462 }
5463
5464 void enableScreenAfterBoot() {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005465 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005466 SystemClock.uptimeMillis());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005467 mWindowManager.enableScreenAfterBoot();
5468 }
5469
Dianne Hackborne88846e2009-09-30 21:34:25 -07005470 final void activityIdleInternal(IBinder token, boolean fromTimeout,
5471 Configuration config) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005472 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5473
5474 ArrayList<HistoryRecord> stops = null;
5475 ArrayList<HistoryRecord> finishes = null;
5476 ArrayList<HistoryRecord> thumbnails = null;
5477 int NS = 0;
5478 int NF = 0;
5479 int NT = 0;
5480 IApplicationThread sendThumbnail = null;
5481 boolean booting = false;
5482 boolean enableScreen = false;
5483
5484 synchronized (this) {
5485 if (token != null) {
5486 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5487 }
5488
5489 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005490 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005491 if (index >= 0) {
5492 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5493
Dianne Hackborne88846e2009-09-30 21:34:25 -07005494 // This is a hack to semi-deal with a race condition
5495 // in the client where it can be constructed with a
5496 // newer configuration from when we asked it to launch.
5497 // We'll update with whatever configuration it now says
5498 // it used to launch.
5499 if (config != null) {
5500 r.configuration = config;
5501 }
5502
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005503 // No longer need to keep the device awake.
5504 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5505 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5506 mLaunchingActivity.release();
5507 }
5508
5509 // We are now idle. If someone is waiting for a thumbnail from
5510 // us, we can now deliver.
5511 r.idle = true;
5512 scheduleAppGcsLocked();
5513 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5514 sendThumbnail = r.app.thread;
5515 r.thumbnailNeeded = false;
5516 }
5517
5518 // If this activity is fullscreen, set up to hide those under it.
5519
5520 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5521 ensureActivitiesVisibleLocked(null, 0);
5522
5523 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5524 if (!mBooted && !fromTimeout) {
5525 mBooted = true;
5526 enableScreen = true;
5527 }
5528 }
5529
5530 // Atomically retrieve all of the other things to do.
5531 stops = processStoppingActivitiesLocked(true);
5532 NS = stops != null ? stops.size() : 0;
5533 if ((NF=mFinishingActivities.size()) > 0) {
5534 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5535 mFinishingActivities.clear();
5536 }
5537 if ((NT=mCancelledThumbnails.size()) > 0) {
5538 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5539 mCancelledThumbnails.clear();
5540 }
5541
5542 booting = mBooting;
5543 mBooting = false;
5544 }
5545
5546 int i;
5547
5548 // Send thumbnail if requested.
5549 if (sendThumbnail != null) {
5550 try {
5551 sendThumbnail.requestThumbnail(token);
5552 } catch (Exception e) {
5553 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5554 sendPendingThumbnail(null, token, null, null, true);
5555 }
5556 }
5557
5558 // Stop any activities that are scheduled to do so but have been
5559 // waiting for the next one to start.
5560 for (i=0; i<NS; i++) {
5561 HistoryRecord r = (HistoryRecord)stops.get(i);
5562 synchronized (this) {
5563 if (r.finishing) {
5564 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5565 } else {
5566 stopActivityLocked(r);
5567 }
5568 }
5569 }
5570
5571 // Finish any activities that are scheduled to do so but have been
5572 // waiting for the next one to start.
5573 for (i=0; i<NF; i++) {
5574 HistoryRecord r = (HistoryRecord)finishes.get(i);
5575 synchronized (this) {
5576 destroyActivityLocked(r, true);
5577 }
5578 }
5579
5580 // Report back to any thumbnail receivers.
5581 for (i=0; i<NT; i++) {
5582 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5583 sendPendingThumbnail(r, null, null, null, true);
5584 }
5585
5586 if (booting) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005587 finishBooting();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005588 }
5589
5590 trimApplications();
5591 //dump();
5592 //mWindowManager.dump();
5593
5594 if (enableScreen) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005595 enableScreenAfterBoot();
5596 }
5597 }
5598
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005599 final void finishBooting() {
5600 // Ensure that any processes we had put on hold are now started
5601 // up.
5602 final int NP = mProcessesOnHold.size();
5603 if (NP > 0) {
5604 ArrayList<ProcessRecord> procs =
5605 new ArrayList<ProcessRecord>(mProcessesOnHold);
5606 for (int ip=0; ip<NP; ip++) {
5607 this.startProcessLocked(procs.get(ip), "on-hold", null);
5608 }
5609 }
5610 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5611 // Tell anyone interested that we are done booting!
5612 synchronized (this) {
5613 broadcastIntentLocked(null, null,
5614 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5615 null, null, 0, null, null,
5616 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5617 false, false, MY_PID, Process.SYSTEM_UID);
5618 }
5619 }
5620 }
5621
5622 final void ensureBootCompleted() {
5623 boolean booting;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005624 boolean enableScreen;
5625 synchronized (this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005626 booting = mBooting;
5627 mBooting = false;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005628 enableScreen = !mBooted;
5629 mBooted = true;
5630 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005631
5632 if (booting) {
5633 finishBooting();
5634 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005635
5636 if (enableScreen) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005637 enableScreenAfterBoot();
5638 }
5639 }
5640
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005641 public final void activityPaused(IBinder token, Bundle icicle) {
5642 // Refuse possible leaked file descriptors
5643 if (icicle != null && icicle.hasFileDescriptors()) {
5644 throw new IllegalArgumentException("File descriptors passed in Bundle");
5645 }
5646
5647 final long origId = Binder.clearCallingIdentity();
5648 activityPaused(token, icicle, false);
5649 Binder.restoreCallingIdentity(origId);
5650 }
5651
5652 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5653 if (DEBUG_PAUSE) Log.v(
5654 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5655 + ", timeout=" + timeout);
5656
5657 HistoryRecord r = null;
5658
5659 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005660 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005661 if (index >= 0) {
5662 r = (HistoryRecord)mHistory.get(index);
5663 if (!timeout) {
5664 r.icicle = icicle;
5665 r.haveState = true;
5666 }
5667 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5668 if (mPausingActivity == r) {
5669 r.state = ActivityState.PAUSED;
5670 completePauseLocked();
5671 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -08005672 EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005673 System.identityHashCode(r), r.shortComponentName,
5674 mPausingActivity != null
5675 ? mPausingActivity.shortComponentName : "(none)");
5676 }
5677 }
5678 }
5679 }
5680
5681 public final void activityStopped(IBinder token, Bitmap thumbnail,
5682 CharSequence description) {
5683 if (localLOGV) Log.v(
5684 TAG, "Activity stopped: token=" + token);
5685
5686 HistoryRecord r = null;
5687
5688 final long origId = Binder.clearCallingIdentity();
5689
5690 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005691 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005692 if (index >= 0) {
5693 r = (HistoryRecord)mHistory.get(index);
5694 r.thumbnail = thumbnail;
5695 r.description = description;
5696 r.stopped = true;
5697 r.state = ActivityState.STOPPED;
5698 if (!r.finishing) {
5699 if (r.configDestroy) {
5700 destroyActivityLocked(r, true);
5701 resumeTopActivityLocked(null);
5702 }
5703 }
5704 }
5705 }
5706
5707 if (r != null) {
5708 sendPendingThumbnail(r, null, null, null, false);
5709 }
5710
5711 trimApplications();
5712
5713 Binder.restoreCallingIdentity(origId);
5714 }
5715
5716 public final void activityDestroyed(IBinder token) {
5717 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5718 synchronized (this) {
5719 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5720
Dianne Hackborn75b03852009-06-12 15:43:26 -07005721 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005722 if (index >= 0) {
5723 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5724 if (r.state == ActivityState.DESTROYING) {
5725 final long origId = Binder.clearCallingIdentity();
5726 removeActivityFromHistoryLocked(r);
5727 Binder.restoreCallingIdentity(origId);
5728 }
5729 }
5730 }
5731 }
5732
5733 public String getCallingPackage(IBinder token) {
5734 synchronized (this) {
5735 HistoryRecord r = getCallingRecordLocked(token);
Dianne Hackborn9bbcb912009-10-20 15:42:38 -07005736 return r != null && r.app != null ? r.info.packageName : null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005737 }
5738 }
5739
5740 public ComponentName getCallingActivity(IBinder token) {
5741 synchronized (this) {
5742 HistoryRecord r = getCallingRecordLocked(token);
5743 return r != null ? r.intent.getComponent() : null;
5744 }
5745 }
5746
5747 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005748 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005749 if (index >= 0) {
5750 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5751 if (r != null) {
5752 return r.resultTo;
5753 }
5754 }
5755 return null;
5756 }
5757
5758 public ComponentName getActivityClassForToken(IBinder token) {
5759 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005760 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005761 if (index >= 0) {
5762 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5763 return r.intent.getComponent();
5764 }
5765 return null;
5766 }
5767 }
5768
5769 public String getPackageForToken(IBinder token) {
5770 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005771 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005772 if (index >= 0) {
5773 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5774 return r.packageName;
5775 }
5776 return null;
5777 }
5778 }
5779
5780 public IIntentSender getIntentSender(int type,
5781 String packageName, IBinder token, String resultWho,
5782 int requestCode, Intent intent, String resolvedType, int flags) {
5783 // Refuse possible leaked file descriptors
5784 if (intent != null && intent.hasFileDescriptors() == true) {
5785 throw new IllegalArgumentException("File descriptors passed in Intent");
5786 }
5787
Dianne Hackborn9acc0302009-08-25 00:27:12 -07005788 if (type == INTENT_SENDER_BROADCAST) {
5789 if ((intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
5790 throw new IllegalArgumentException(
5791 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
5792 }
5793 }
5794
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005795 synchronized(this) {
5796 int callingUid = Binder.getCallingUid();
5797 try {
5798 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5799 Process.supportsProcesses()) {
5800 int uid = ActivityThread.getPackageManager()
5801 .getPackageUid(packageName);
5802 if (uid != Binder.getCallingUid()) {
5803 String msg = "Permission Denial: getIntentSender() from pid="
5804 + Binder.getCallingPid()
5805 + ", uid=" + Binder.getCallingUid()
5806 + ", (need uid=" + uid + ")"
5807 + " is not allowed to send as package " + packageName;
5808 Log.w(TAG, msg);
5809 throw new SecurityException(msg);
5810 }
5811 }
5812 } catch (RemoteException e) {
5813 throw new SecurityException(e);
5814 }
5815 HistoryRecord activity = null;
5816 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005817 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005818 if (index < 0) {
5819 return null;
5820 }
5821 activity = (HistoryRecord)mHistory.get(index);
5822 if (activity.finishing) {
5823 return null;
5824 }
5825 }
5826
5827 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5828 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5829 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5830 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5831 |PendingIntent.FLAG_UPDATE_CURRENT);
5832
5833 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5834 type, packageName, activity, resultWho,
5835 requestCode, intent, resolvedType, flags);
5836 WeakReference<PendingIntentRecord> ref;
5837 ref = mIntentSenderRecords.get(key);
5838 PendingIntentRecord rec = ref != null ? ref.get() : null;
5839 if (rec != null) {
5840 if (!cancelCurrent) {
5841 if (updateCurrent) {
5842 rec.key.requestIntent.replaceExtras(intent);
5843 }
5844 return rec;
5845 }
5846 rec.canceled = true;
5847 mIntentSenderRecords.remove(key);
5848 }
5849 if (noCreate) {
5850 return rec;
5851 }
5852 rec = new PendingIntentRecord(this, key, callingUid);
5853 mIntentSenderRecords.put(key, rec.ref);
5854 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5855 if (activity.pendingResults == null) {
5856 activity.pendingResults
5857 = new HashSet<WeakReference<PendingIntentRecord>>();
5858 }
5859 activity.pendingResults.add(rec.ref);
5860 }
5861 return rec;
5862 }
5863 }
5864
5865 public void cancelIntentSender(IIntentSender sender) {
5866 if (!(sender instanceof PendingIntentRecord)) {
5867 return;
5868 }
5869 synchronized(this) {
5870 PendingIntentRecord rec = (PendingIntentRecord)sender;
5871 try {
5872 int uid = ActivityThread.getPackageManager()
5873 .getPackageUid(rec.key.packageName);
5874 if (uid != Binder.getCallingUid()) {
5875 String msg = "Permission Denial: cancelIntentSender() from pid="
5876 + Binder.getCallingPid()
5877 + ", uid=" + Binder.getCallingUid()
5878 + " is not allowed to cancel packges "
5879 + rec.key.packageName;
5880 Log.w(TAG, msg);
5881 throw new SecurityException(msg);
5882 }
5883 } catch (RemoteException e) {
5884 throw new SecurityException(e);
5885 }
5886 cancelIntentSenderLocked(rec, true);
5887 }
5888 }
5889
5890 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5891 rec.canceled = true;
5892 mIntentSenderRecords.remove(rec.key);
5893 if (cleanActivity && rec.key.activity != null) {
5894 rec.key.activity.pendingResults.remove(rec.ref);
5895 }
5896 }
5897
5898 public String getPackageForIntentSender(IIntentSender pendingResult) {
5899 if (!(pendingResult instanceof PendingIntentRecord)) {
5900 return null;
5901 }
5902 synchronized(this) {
5903 try {
5904 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5905 return res.key.packageName;
5906 } catch (ClassCastException e) {
5907 }
5908 }
5909 return null;
5910 }
5911
5912 public void setProcessLimit(int max) {
5913 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5914 "setProcessLimit()");
5915 mProcessLimit = max;
5916 }
5917
5918 public int getProcessLimit() {
5919 return mProcessLimit;
5920 }
5921
5922 void foregroundTokenDied(ForegroundToken token) {
5923 synchronized (ActivityManagerService.this) {
5924 synchronized (mPidsSelfLocked) {
5925 ForegroundToken cur
5926 = mForegroundProcesses.get(token.pid);
5927 if (cur != token) {
5928 return;
5929 }
5930 mForegroundProcesses.remove(token.pid);
5931 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5932 if (pr == null) {
5933 return;
5934 }
5935 pr.forcingToForeground = null;
5936 pr.foregroundServices = false;
5937 }
5938 updateOomAdjLocked();
5939 }
5940 }
5941
5942 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5943 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5944 "setProcessForeground()");
5945 synchronized(this) {
5946 boolean changed = false;
5947
5948 synchronized (mPidsSelfLocked) {
5949 ProcessRecord pr = mPidsSelfLocked.get(pid);
5950 if (pr == null) {
5951 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5952 return;
5953 }
5954 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5955 if (oldToken != null) {
5956 oldToken.token.unlinkToDeath(oldToken, 0);
5957 mForegroundProcesses.remove(pid);
5958 pr.forcingToForeground = null;
5959 changed = true;
5960 }
5961 if (isForeground && token != null) {
5962 ForegroundToken newToken = new ForegroundToken() {
5963 public void binderDied() {
5964 foregroundTokenDied(this);
5965 }
5966 };
5967 newToken.pid = pid;
5968 newToken.token = token;
5969 try {
5970 token.linkToDeath(newToken, 0);
5971 mForegroundProcesses.put(pid, newToken);
5972 pr.forcingToForeground = token;
5973 changed = true;
5974 } catch (RemoteException e) {
5975 // If the process died while doing this, we will later
5976 // do the cleanup with the process death link.
5977 }
5978 }
5979 }
5980
5981 if (changed) {
5982 updateOomAdjLocked();
5983 }
5984 }
5985 }
5986
5987 // =========================================================
5988 // PERMISSIONS
5989 // =========================================================
5990
5991 static class PermissionController extends IPermissionController.Stub {
5992 ActivityManagerService mActivityManagerService;
5993 PermissionController(ActivityManagerService activityManagerService) {
5994 mActivityManagerService = activityManagerService;
5995 }
5996
5997 public boolean checkPermission(String permission, int pid, int uid) {
5998 return mActivityManagerService.checkPermission(permission, pid,
5999 uid) == PackageManager.PERMISSION_GRANTED;
6000 }
6001 }
6002
6003 /**
6004 * This can be called with or without the global lock held.
6005 */
6006 int checkComponentPermission(String permission, int pid, int uid,
6007 int reqUid) {
6008 // We might be performing an operation on behalf of an indirect binder
6009 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
6010 // client identity accordingly before proceeding.
6011 Identity tlsIdentity = sCallerIdentity.get();
6012 if (tlsIdentity != null) {
6013 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
6014 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
6015 uid = tlsIdentity.uid;
6016 pid = tlsIdentity.pid;
6017 }
6018
6019 // Root, system server and our own process get to do everything.
6020 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
6021 !Process.supportsProcesses()) {
6022 return PackageManager.PERMISSION_GRANTED;
6023 }
6024 // If the target requires a specific UID, always fail for others.
6025 if (reqUid >= 0 && uid != reqUid) {
6026 return PackageManager.PERMISSION_DENIED;
6027 }
6028 if (permission == null) {
6029 return PackageManager.PERMISSION_GRANTED;
6030 }
6031 try {
6032 return ActivityThread.getPackageManager()
6033 .checkUidPermission(permission, uid);
6034 } catch (RemoteException e) {
6035 // Should never happen, but if it does... deny!
6036 Log.e(TAG, "PackageManager is dead?!?", e);
6037 }
6038 return PackageManager.PERMISSION_DENIED;
6039 }
6040
6041 /**
6042 * As the only public entry point for permissions checking, this method
6043 * can enforce the semantic that requesting a check on a null global
6044 * permission is automatically denied. (Internally a null permission
6045 * string is used when calling {@link #checkComponentPermission} in cases
6046 * when only uid-based security is needed.)
6047 *
6048 * This can be called with or without the global lock held.
6049 */
6050 public int checkPermission(String permission, int pid, int uid) {
6051 if (permission == null) {
6052 return PackageManager.PERMISSION_DENIED;
6053 }
6054 return checkComponentPermission(permission, pid, uid, -1);
6055 }
6056
6057 /**
6058 * Binder IPC calls go through the public entry point.
6059 * This can be called with or without the global lock held.
6060 */
6061 int checkCallingPermission(String permission) {
6062 return checkPermission(permission,
6063 Binder.getCallingPid(),
6064 Binder.getCallingUid());
6065 }
6066
6067 /**
6068 * This can be called with or without the global lock held.
6069 */
6070 void enforceCallingPermission(String permission, String func) {
6071 if (checkCallingPermission(permission)
6072 == PackageManager.PERMISSION_GRANTED) {
6073 return;
6074 }
6075
6076 String msg = "Permission Denial: " + func + " from pid="
6077 + Binder.getCallingPid()
6078 + ", uid=" + Binder.getCallingUid()
6079 + " requires " + permission;
6080 Log.w(TAG, msg);
6081 throw new SecurityException(msg);
6082 }
6083
6084 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
6085 ProviderInfo pi, int uid, int modeFlags) {
6086 try {
6087 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6088 if ((pi.readPermission != null) &&
6089 (pm.checkUidPermission(pi.readPermission, uid)
6090 != PackageManager.PERMISSION_GRANTED)) {
6091 return false;
6092 }
6093 }
6094 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6095 if ((pi.writePermission != null) &&
6096 (pm.checkUidPermission(pi.writePermission, uid)
6097 != PackageManager.PERMISSION_GRANTED)) {
6098 return false;
6099 }
6100 }
6101 return true;
6102 } catch (RemoteException e) {
6103 return false;
6104 }
6105 }
6106
6107 private final boolean checkUriPermissionLocked(Uri uri, int uid,
6108 int modeFlags) {
6109 // Root gets to do everything.
6110 if (uid == 0 || !Process.supportsProcesses()) {
6111 return true;
6112 }
6113 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
6114 if (perms == null) return false;
6115 UriPermission perm = perms.get(uri);
6116 if (perm == null) return false;
6117 return (modeFlags&perm.modeFlags) == modeFlags;
6118 }
6119
6120 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
6121 // Another redirected-binder-call permissions check as in
6122 // {@link checkComponentPermission}.
6123 Identity tlsIdentity = sCallerIdentity.get();
6124 if (tlsIdentity != null) {
6125 uid = tlsIdentity.uid;
6126 pid = tlsIdentity.pid;
6127 }
6128
6129 // Our own process gets to do everything.
6130 if (pid == MY_PID) {
6131 return PackageManager.PERMISSION_GRANTED;
6132 }
6133 synchronized(this) {
6134 return checkUriPermissionLocked(uri, uid, modeFlags)
6135 ? PackageManager.PERMISSION_GRANTED
6136 : PackageManager.PERMISSION_DENIED;
6137 }
6138 }
6139
6140 private void grantUriPermissionLocked(int callingUid,
6141 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
6142 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6143 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6144 if (modeFlags == 0) {
6145 return;
6146 }
6147
6148 final IPackageManager pm = ActivityThread.getPackageManager();
6149
6150 // If this is not a content: uri, we can't do anything with it.
6151 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
6152 return;
6153 }
6154
6155 String name = uri.getAuthority();
6156 ProviderInfo pi = null;
6157 ContentProviderRecord cpr
6158 = (ContentProviderRecord)mProvidersByName.get(name);
6159 if (cpr != null) {
6160 pi = cpr.info;
6161 } else {
6162 try {
6163 pi = pm.resolveContentProvider(name,
6164 PackageManager.GET_URI_PERMISSION_PATTERNS);
6165 } catch (RemoteException ex) {
6166 }
6167 }
6168 if (pi == null) {
6169 Log.w(TAG, "No content provider found for: " + name);
6170 return;
6171 }
6172
6173 int targetUid;
6174 try {
6175 targetUid = pm.getPackageUid(targetPkg);
6176 if (targetUid < 0) {
6177 return;
6178 }
6179 } catch (RemoteException ex) {
6180 return;
6181 }
6182
6183 // First... does the target actually need this permission?
6184 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
6185 // No need to grant the target this permission.
6186 return;
6187 }
6188
6189 // Second... maybe someone else has already granted the
6190 // permission?
6191 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
6192 // No need to grant the target this permission.
6193 return;
6194 }
6195
6196 // Third... is the provider allowing granting of URI permissions?
6197 if (!pi.grantUriPermissions) {
6198 throw new SecurityException("Provider " + pi.packageName
6199 + "/" + pi.name
6200 + " does not allow granting of Uri permissions (uri "
6201 + uri + ")");
6202 }
6203 if (pi.uriPermissionPatterns != null) {
6204 final int N = pi.uriPermissionPatterns.length;
6205 boolean allowed = false;
6206 for (int i=0; i<N; i++) {
6207 if (pi.uriPermissionPatterns[i] != null
6208 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6209 allowed = true;
6210 break;
6211 }
6212 }
6213 if (!allowed) {
6214 throw new SecurityException("Provider " + pi.packageName
6215 + "/" + pi.name
6216 + " does not allow granting of permission to path of Uri "
6217 + uri);
6218 }
6219 }
6220
6221 // Fourth... does the caller itself have permission to access
6222 // this uri?
6223 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6224 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6225 throw new SecurityException("Uid " + callingUid
6226 + " does not have permission to uri " + uri);
6227 }
6228 }
6229
6230 // Okay! So here we are: the caller has the assumed permission
6231 // to the uri, and the target doesn't. Let's now give this to
6232 // the target.
6233
6234 HashMap<Uri, UriPermission> targetUris
6235 = mGrantedUriPermissions.get(targetUid);
6236 if (targetUris == null) {
6237 targetUris = new HashMap<Uri, UriPermission>();
6238 mGrantedUriPermissions.put(targetUid, targetUris);
6239 }
6240
6241 UriPermission perm = targetUris.get(uri);
6242 if (perm == null) {
6243 perm = new UriPermission(targetUid, uri);
6244 targetUris.put(uri, perm);
6245
6246 }
6247 perm.modeFlags |= modeFlags;
6248 if (activity == null) {
6249 perm.globalModeFlags |= modeFlags;
6250 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6251 perm.readActivities.add(activity);
6252 if (activity.readUriPermissions == null) {
6253 activity.readUriPermissions = new HashSet<UriPermission>();
6254 }
6255 activity.readUriPermissions.add(perm);
6256 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6257 perm.writeActivities.add(activity);
6258 if (activity.writeUriPermissions == null) {
6259 activity.writeUriPermissions = new HashSet<UriPermission>();
6260 }
6261 activity.writeUriPermissions.add(perm);
6262 }
6263 }
6264
6265 private void grantUriPermissionFromIntentLocked(int callingUid,
6266 String targetPkg, Intent intent, HistoryRecord activity) {
6267 if (intent == null) {
6268 return;
6269 }
6270 Uri data = intent.getData();
6271 if (data == null) {
6272 return;
6273 }
6274 grantUriPermissionLocked(callingUid, targetPkg, data,
6275 intent.getFlags(), activity);
6276 }
6277
6278 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6279 Uri uri, int modeFlags) {
6280 synchronized(this) {
6281 final ProcessRecord r = getRecordForAppLocked(caller);
6282 if (r == null) {
6283 throw new SecurityException("Unable to find app for caller "
6284 + caller
6285 + " when granting permission to uri " + uri);
6286 }
6287 if (targetPkg == null) {
6288 Log.w(TAG, "grantUriPermission: null target");
6289 return;
6290 }
6291 if (uri == null) {
6292 Log.w(TAG, "grantUriPermission: null uri");
6293 return;
6294 }
6295
6296 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6297 null);
6298 }
6299 }
6300
6301 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6302 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6303 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6304 HashMap<Uri, UriPermission> perms
6305 = mGrantedUriPermissions.get(perm.uid);
6306 if (perms != null) {
6307 perms.remove(perm.uri);
6308 if (perms.size() == 0) {
6309 mGrantedUriPermissions.remove(perm.uid);
6310 }
6311 }
6312 }
6313 }
6314
6315 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6316 if (activity.readUriPermissions != null) {
6317 for (UriPermission perm : activity.readUriPermissions) {
6318 perm.readActivities.remove(activity);
6319 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6320 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6321 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6322 removeUriPermissionIfNeededLocked(perm);
6323 }
6324 }
6325 }
6326 if (activity.writeUriPermissions != null) {
6327 for (UriPermission perm : activity.writeUriPermissions) {
6328 perm.writeActivities.remove(activity);
6329 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6330 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6331 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6332 removeUriPermissionIfNeededLocked(perm);
6333 }
6334 }
6335 }
6336 }
6337
6338 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6339 int modeFlags) {
6340 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6341 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6342 if (modeFlags == 0) {
6343 return;
6344 }
6345
6346 final IPackageManager pm = ActivityThread.getPackageManager();
6347
6348 final String authority = uri.getAuthority();
6349 ProviderInfo pi = null;
6350 ContentProviderRecord cpr
6351 = (ContentProviderRecord)mProvidersByName.get(authority);
6352 if (cpr != null) {
6353 pi = cpr.info;
6354 } else {
6355 try {
6356 pi = pm.resolveContentProvider(authority,
6357 PackageManager.GET_URI_PERMISSION_PATTERNS);
6358 } catch (RemoteException ex) {
6359 }
6360 }
6361 if (pi == null) {
6362 Log.w(TAG, "No content provider found for: " + authority);
6363 return;
6364 }
6365
6366 // Does the caller have this permission on the URI?
6367 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6368 // Right now, if you are not the original owner of the permission,
6369 // you are not allowed to revoke it.
6370 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6371 throw new SecurityException("Uid " + callingUid
6372 + " does not have permission to uri " + uri);
6373 //}
6374 }
6375
6376 // Go through all of the permissions and remove any that match.
6377 final List<String> SEGMENTS = uri.getPathSegments();
6378 if (SEGMENTS != null) {
6379 final int NS = SEGMENTS.size();
6380 int N = mGrantedUriPermissions.size();
6381 for (int i=0; i<N; i++) {
6382 HashMap<Uri, UriPermission> perms
6383 = mGrantedUriPermissions.valueAt(i);
6384 Iterator<UriPermission> it = perms.values().iterator();
6385 toploop:
6386 while (it.hasNext()) {
6387 UriPermission perm = it.next();
6388 Uri targetUri = perm.uri;
6389 if (!authority.equals(targetUri.getAuthority())) {
6390 continue;
6391 }
6392 List<String> targetSegments = targetUri.getPathSegments();
6393 if (targetSegments == null) {
6394 continue;
6395 }
6396 if (targetSegments.size() < NS) {
6397 continue;
6398 }
6399 for (int j=0; j<NS; j++) {
6400 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6401 continue toploop;
6402 }
6403 }
6404 perm.clearModes(modeFlags);
6405 if (perm.modeFlags == 0) {
6406 it.remove();
6407 }
6408 }
6409 if (perms.size() == 0) {
6410 mGrantedUriPermissions.remove(
6411 mGrantedUriPermissions.keyAt(i));
6412 N--;
6413 i--;
6414 }
6415 }
6416 }
6417 }
6418
6419 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6420 int modeFlags) {
6421 synchronized(this) {
6422 final ProcessRecord r = getRecordForAppLocked(caller);
6423 if (r == null) {
6424 throw new SecurityException("Unable to find app for caller "
6425 + caller
6426 + " when revoking permission to uri " + uri);
6427 }
6428 if (uri == null) {
6429 Log.w(TAG, "revokeUriPermission: null uri");
6430 return;
6431 }
6432
6433 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6434 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6435 if (modeFlags == 0) {
6436 return;
6437 }
6438
6439 final IPackageManager pm = ActivityThread.getPackageManager();
6440
6441 final String authority = uri.getAuthority();
6442 ProviderInfo pi = null;
6443 ContentProviderRecord cpr
6444 = (ContentProviderRecord)mProvidersByName.get(authority);
6445 if (cpr != null) {
6446 pi = cpr.info;
6447 } else {
6448 try {
6449 pi = pm.resolveContentProvider(authority,
6450 PackageManager.GET_URI_PERMISSION_PATTERNS);
6451 } catch (RemoteException ex) {
6452 }
6453 }
6454 if (pi == null) {
6455 Log.w(TAG, "No content provider found for: " + authority);
6456 return;
6457 }
6458
6459 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6460 }
6461 }
6462
6463 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6464 synchronized (this) {
6465 ProcessRecord app =
6466 who != null ? getRecordForAppLocked(who) : null;
6467 if (app == null) return;
6468
6469 Message msg = Message.obtain();
6470 msg.what = WAIT_FOR_DEBUGGER_MSG;
6471 msg.obj = app;
6472 msg.arg1 = waiting ? 1 : 0;
6473 mHandler.sendMessage(msg);
6474 }
6475 }
6476
6477 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6478 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006479 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006480 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006481 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006482 }
6483
6484 // =========================================================
6485 // TASK MANAGEMENT
6486 // =========================================================
6487
6488 public List getTasks(int maxNum, int flags,
6489 IThumbnailReceiver receiver) {
6490 ArrayList list = new ArrayList();
6491
6492 PendingThumbnailsRecord pending = null;
6493 IApplicationThread topThumbnail = null;
6494 HistoryRecord topRecord = null;
6495
6496 synchronized(this) {
6497 if (localLOGV) Log.v(
6498 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6499 + ", receiver=" + receiver);
6500
6501 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6502 != PackageManager.PERMISSION_GRANTED) {
6503 if (receiver != null) {
6504 // If the caller wants to wait for pending thumbnails,
6505 // it ain't gonna get them.
6506 try {
6507 receiver.finished();
6508 } catch (RemoteException ex) {
6509 }
6510 }
6511 String msg = "Permission Denial: getTasks() from pid="
6512 + Binder.getCallingPid()
6513 + ", uid=" + Binder.getCallingUid()
6514 + " requires " + android.Manifest.permission.GET_TASKS;
6515 Log.w(TAG, msg);
6516 throw new SecurityException(msg);
6517 }
6518
6519 int pos = mHistory.size()-1;
6520 HistoryRecord next =
6521 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6522 HistoryRecord top = null;
6523 CharSequence topDescription = null;
6524 TaskRecord curTask = null;
6525 int numActivities = 0;
6526 int numRunning = 0;
6527 while (pos >= 0 && maxNum > 0) {
6528 final HistoryRecord r = next;
6529 pos--;
6530 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6531
6532 // Initialize state for next task if needed.
6533 if (top == null ||
6534 (top.state == ActivityState.INITIALIZING
6535 && top.task == r.task)) {
6536 top = r;
6537 topDescription = r.description;
6538 curTask = r.task;
6539 numActivities = numRunning = 0;
6540 }
6541
6542 // Add 'r' into the current task.
6543 numActivities++;
6544 if (r.app != null && r.app.thread != null) {
6545 numRunning++;
6546 }
6547 if (topDescription == null) {
6548 topDescription = r.description;
6549 }
6550
6551 if (localLOGV) Log.v(
6552 TAG, r.intent.getComponent().flattenToShortString()
6553 + ": task=" + r.task);
6554
6555 // If the next one is a different task, generate a new
6556 // TaskInfo entry for what we have.
6557 if (next == null || next.task != curTask) {
6558 ActivityManager.RunningTaskInfo ci
6559 = new ActivityManager.RunningTaskInfo();
6560 ci.id = curTask.taskId;
6561 ci.baseActivity = r.intent.getComponent();
6562 ci.topActivity = top.intent.getComponent();
6563 ci.thumbnail = top.thumbnail;
6564 ci.description = topDescription;
6565 ci.numActivities = numActivities;
6566 ci.numRunning = numRunning;
6567 //System.out.println(
6568 // "#" + maxNum + ": " + " descr=" + ci.description);
6569 if (ci.thumbnail == null && receiver != null) {
6570 if (localLOGV) Log.v(
6571 TAG, "State=" + top.state + "Idle=" + top.idle
6572 + " app=" + top.app
6573 + " thr=" + (top.app != null ? top.app.thread : null));
6574 if (top.state == ActivityState.RESUMED
6575 || top.state == ActivityState.PAUSING) {
6576 if (top.idle && top.app != null
6577 && top.app.thread != null) {
6578 topRecord = top;
6579 topThumbnail = top.app.thread;
6580 } else {
6581 top.thumbnailNeeded = true;
6582 }
6583 }
6584 if (pending == null) {
6585 pending = new PendingThumbnailsRecord(receiver);
6586 }
6587 pending.pendingRecords.add(top);
6588 }
6589 list.add(ci);
6590 maxNum--;
6591 top = null;
6592 }
6593 }
6594
6595 if (pending != null) {
6596 mPendingThumbnails.add(pending);
6597 }
6598 }
6599
6600 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6601
6602 if (topThumbnail != null) {
6603 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6604 try {
6605 topThumbnail.requestThumbnail(topRecord);
6606 } catch (Exception e) {
6607 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6608 sendPendingThumbnail(null, topRecord, null, null, true);
6609 }
6610 }
6611
6612 if (pending == null && receiver != null) {
6613 // In this case all thumbnails were available and the client
6614 // is being asked to be told when the remaining ones come in...
6615 // which is unusually, since the top-most currently running
6616 // activity should never have a canned thumbnail! Oh well.
6617 try {
6618 receiver.finished();
6619 } catch (RemoteException ex) {
6620 }
6621 }
6622
6623 return list;
6624 }
6625
6626 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6627 int flags) {
6628 synchronized (this) {
6629 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6630 "getRecentTasks()");
6631
6632 final int N = mRecentTasks.size();
6633 ArrayList<ActivityManager.RecentTaskInfo> res
6634 = new ArrayList<ActivityManager.RecentTaskInfo>(
6635 maxNum < N ? maxNum : N);
6636 for (int i=0; i<N && maxNum > 0; i++) {
6637 TaskRecord tr = mRecentTasks.get(i);
6638 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6639 || (tr.intent == null)
6640 || ((tr.intent.getFlags()
6641 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6642 ActivityManager.RecentTaskInfo rti
6643 = new ActivityManager.RecentTaskInfo();
6644 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6645 rti.baseIntent = new Intent(
6646 tr.intent != null ? tr.intent : tr.affinityIntent);
6647 rti.origActivity = tr.origActivity;
6648 res.add(rti);
6649 maxNum--;
6650 }
6651 }
6652 return res;
6653 }
6654 }
6655
6656 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6657 int j;
6658 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6659 TaskRecord jt = startTask;
6660
6661 // First look backwards
6662 for (j=startIndex-1; j>=0; j--) {
6663 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6664 if (r.task != jt) {
6665 jt = r.task;
6666 if (affinity.equals(jt.affinity)) {
6667 return j;
6668 }
6669 }
6670 }
6671
6672 // Now look forwards
6673 final int N = mHistory.size();
6674 jt = startTask;
6675 for (j=startIndex+1; j<N; j++) {
6676 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6677 if (r.task != jt) {
6678 if (affinity.equals(jt.affinity)) {
6679 return j;
6680 }
6681 jt = r.task;
6682 }
6683 }
6684
6685 // Might it be at the top?
6686 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6687 return N-1;
6688 }
6689
6690 return -1;
6691 }
6692
6693 /**
6694 * Perform a reset of the given task, if needed as part of launching it.
6695 * Returns the new HistoryRecord at the top of the task.
6696 */
6697 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6698 HistoryRecord newActivity) {
6699 boolean forceReset = (newActivity.info.flags
6700 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6701 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6702 if ((newActivity.info.flags
6703 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6704 forceReset = true;
6705 }
6706 }
6707
6708 final TaskRecord task = taskTop.task;
6709
6710 // We are going to move through the history list so that we can look
6711 // at each activity 'target' with 'below' either the interesting
6712 // activity immediately below it in the stack or null.
6713 HistoryRecord target = null;
6714 int targetI = 0;
6715 int taskTopI = -1;
6716 int replyChainEnd = -1;
6717 int lastReparentPos = -1;
6718 for (int i=mHistory.size()-1; i>=-1; i--) {
6719 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6720
6721 if (below != null && below.finishing) {
6722 continue;
6723 }
6724 if (target == null) {
6725 target = below;
6726 targetI = i;
6727 // If we were in the middle of a reply chain before this
6728 // task, it doesn't appear like the root of the chain wants
6729 // anything interesting, so drop it.
6730 replyChainEnd = -1;
6731 continue;
6732 }
6733
6734 final int flags = target.info.flags;
6735
6736 final boolean finishOnTaskLaunch =
6737 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6738 final boolean allowTaskReparenting =
6739 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6740
6741 if (target.task == task) {
6742 // We are inside of the task being reset... we'll either
6743 // finish this activity, push it out for another task,
6744 // or leave it as-is. We only do this
6745 // for activities that are not the root of the task (since
6746 // if we finish the root, we may no longer have the task!).
6747 if (taskTopI < 0) {
6748 taskTopI = targetI;
6749 }
6750 if (below != null && below.task == task) {
6751 final boolean clearWhenTaskReset =
6752 (target.intent.getFlags()
6753 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006754 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006755 // If this activity is sending a reply to a previous
6756 // activity, we can't do anything with it now until
6757 // we reach the start of the reply chain.
6758 // XXX note that we are assuming the result is always
6759 // to the previous activity, which is almost always
6760 // the case but we really shouldn't count on.
6761 if (replyChainEnd < 0) {
6762 replyChainEnd = targetI;
6763 }
Ed Heyl73798232009-03-24 21:32:21 -07006764 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006765 && target.taskAffinity != null
6766 && !target.taskAffinity.equals(task.affinity)) {
6767 // If this activity has an affinity for another
6768 // task, then we need to move it out of here. We will
6769 // move it as far out of the way as possible, to the
6770 // bottom of the activity stack. This also keeps it
6771 // correctly ordered with any activities we previously
6772 // moved.
6773 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6774 if (target.taskAffinity != null
6775 && target.taskAffinity.equals(p.task.affinity)) {
6776 // If the activity currently at the bottom has the
6777 // same task affinity as the one we are moving,
6778 // then merge it into the same task.
6779 target.task = p.task;
6780 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6781 + " out to bottom task " + p.task);
6782 } else {
6783 mCurTask++;
6784 if (mCurTask <= 0) {
6785 mCurTask = 1;
6786 }
6787 target.task = new TaskRecord(mCurTask, target.info, null,
6788 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6789 target.task.affinityIntent = target.intent;
6790 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6791 + " out to new task " + target.task);
6792 }
6793 mWindowManager.setAppGroupId(target, task.taskId);
6794 if (replyChainEnd < 0) {
6795 replyChainEnd = targetI;
6796 }
6797 int dstPos = 0;
6798 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6799 p = (HistoryRecord)mHistory.get(srcPos);
6800 if (p.finishing) {
6801 continue;
6802 }
6803 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6804 + " out to target's task " + target.task);
6805 task.numActivities--;
6806 p.task = target.task;
6807 target.task.numActivities++;
6808 mHistory.remove(srcPos);
6809 mHistory.add(dstPos, p);
6810 mWindowManager.moveAppToken(dstPos, p);
6811 mWindowManager.setAppGroupId(p, p.task.taskId);
6812 dstPos++;
6813 if (VALIDATE_TOKENS) {
6814 mWindowManager.validateAppTokens(mHistory);
6815 }
6816 i++;
6817 }
6818 if (taskTop == p) {
6819 taskTop = below;
6820 }
6821 if (taskTopI == replyChainEnd) {
6822 taskTopI = -1;
6823 }
6824 replyChainEnd = -1;
6825 addRecentTask(target.task);
6826 } else if (forceReset || finishOnTaskLaunch
6827 || clearWhenTaskReset) {
6828 // If the activity should just be removed -- either
6829 // because it asks for it, or the task should be
6830 // cleared -- then finish it and anything that is
6831 // part of its reply chain.
6832 if (clearWhenTaskReset) {
6833 // In this case, we want to finish this activity
6834 // and everything above it, so be sneaky and pretend
6835 // like these are all in the reply chain.
6836 replyChainEnd = targetI+1;
6837 while (replyChainEnd < mHistory.size() &&
6838 ((HistoryRecord)mHistory.get(
6839 replyChainEnd)).task == task) {
6840 replyChainEnd++;
6841 }
6842 replyChainEnd--;
6843 } else if (replyChainEnd < 0) {
6844 replyChainEnd = targetI;
6845 }
6846 HistoryRecord p = null;
6847 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6848 p = (HistoryRecord)mHistory.get(srcPos);
6849 if (p.finishing) {
6850 continue;
6851 }
6852 if (finishActivityLocked(p, srcPos,
6853 Activity.RESULT_CANCELED, null, "reset")) {
6854 replyChainEnd--;
6855 srcPos--;
6856 }
6857 }
6858 if (taskTop == p) {
6859 taskTop = below;
6860 }
6861 if (taskTopI == replyChainEnd) {
6862 taskTopI = -1;
6863 }
6864 replyChainEnd = -1;
6865 } else {
6866 // If we were in the middle of a chain, well the
6867 // activity that started it all doesn't want anything
6868 // special, so leave it all as-is.
6869 replyChainEnd = -1;
6870 }
6871 } else {
6872 // Reached the bottom of the task -- any reply chain
6873 // should be left as-is.
6874 replyChainEnd = -1;
6875 }
6876
6877 } else if (target.resultTo != null) {
6878 // If this activity is sending a reply to a previous
6879 // activity, we can't do anything with it now until
6880 // we reach the start of the reply chain.
6881 // XXX note that we are assuming the result is always
6882 // to the previous activity, which is almost always
6883 // the case but we really shouldn't count on.
6884 if (replyChainEnd < 0) {
6885 replyChainEnd = targetI;
6886 }
6887
6888 } else if (taskTopI >= 0 && allowTaskReparenting
6889 && task.affinity != null
6890 && task.affinity.equals(target.taskAffinity)) {
6891 // We are inside of another task... if this activity has
6892 // an affinity for our task, then either remove it if we are
6893 // clearing or move it over to our task. Note that
6894 // we currently punt on the case where we are resetting a
6895 // task that is not at the top but who has activities above
6896 // with an affinity to it... this is really not a normal
6897 // case, and we will need to later pull that task to the front
6898 // and usually at that point we will do the reset and pick
6899 // up those remaining activities. (This only happens if
6900 // someone starts an activity in a new task from an activity
6901 // in a task that is not currently on top.)
6902 if (forceReset || finishOnTaskLaunch) {
6903 if (replyChainEnd < 0) {
6904 replyChainEnd = targetI;
6905 }
6906 HistoryRecord p = null;
6907 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6908 p = (HistoryRecord)mHistory.get(srcPos);
6909 if (p.finishing) {
6910 continue;
6911 }
6912 if (finishActivityLocked(p, srcPos,
6913 Activity.RESULT_CANCELED, null, "reset")) {
6914 taskTopI--;
6915 lastReparentPos--;
6916 replyChainEnd--;
6917 srcPos--;
6918 }
6919 }
6920 replyChainEnd = -1;
6921 } else {
6922 if (replyChainEnd < 0) {
6923 replyChainEnd = targetI;
6924 }
6925 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6926 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6927 if (p.finishing) {
6928 continue;
6929 }
6930 if (lastReparentPos < 0) {
6931 lastReparentPos = taskTopI;
6932 taskTop = p;
6933 } else {
6934 lastReparentPos--;
6935 }
6936 mHistory.remove(srcPos);
6937 p.task.numActivities--;
6938 p.task = task;
6939 mHistory.add(lastReparentPos, p);
6940 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6941 + " in to resetting task " + task);
6942 task.numActivities++;
6943 mWindowManager.moveAppToken(lastReparentPos, p);
6944 mWindowManager.setAppGroupId(p, p.task.taskId);
6945 if (VALIDATE_TOKENS) {
6946 mWindowManager.validateAppTokens(mHistory);
6947 }
6948 }
6949 replyChainEnd = -1;
6950
6951 // Now we've moved it in to place... but what if this is
6952 // a singleTop activity and we have put it on top of another
6953 // instance of the same activity? Then we drop the instance
6954 // below so it remains singleTop.
6955 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6956 for (int j=lastReparentPos-1; j>=0; j--) {
6957 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6958 if (p.finishing) {
6959 continue;
6960 }
6961 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6962 if (finishActivityLocked(p, j,
6963 Activity.RESULT_CANCELED, null, "replace")) {
6964 taskTopI--;
6965 lastReparentPos--;
6966 }
6967 }
6968 }
6969 }
6970 }
6971 }
6972
6973 target = below;
6974 targetI = i;
6975 }
6976
6977 return taskTop;
6978 }
6979
6980 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006981 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006982 */
6983 public void moveTaskToFront(int task) {
6984 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6985 "moveTaskToFront()");
6986
6987 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006988 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6989 Binder.getCallingUid(), "Task to front")) {
6990 return;
6991 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006992 final long origId = Binder.clearCallingIdentity();
6993 try {
6994 int N = mRecentTasks.size();
6995 for (int i=0; i<N; i++) {
6996 TaskRecord tr = mRecentTasks.get(i);
6997 if (tr.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07006998 moveTaskToFrontLocked(tr, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006999 return;
7000 }
7001 }
7002 for (int i=mHistory.size()-1; i>=0; i--) {
7003 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
7004 if (hr.task.taskId == task) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007005 moveTaskToFrontLocked(hr.task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007006 return;
7007 }
7008 }
7009 } finally {
7010 Binder.restoreCallingIdentity(origId);
7011 }
7012 }
7013 }
7014
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007015 private final void moveTaskToFrontLocked(TaskRecord tr, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007016 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
7017
7018 final int task = tr.taskId;
7019 int top = mHistory.size()-1;
7020
7021 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
7022 // nothing to do!
7023 return;
7024 }
7025
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007026 ArrayList moved = new ArrayList();
7027
7028 // Applying the affinities may have removed entries from the history,
7029 // so get the size again.
7030 top = mHistory.size()-1;
7031 int pos = top;
7032
7033 // Shift all activities with this task up to the top
7034 // of the stack, keeping them in the same internal order.
7035 while (pos >= 0) {
7036 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7037 if (localLOGV) Log.v(
7038 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7039 boolean first = true;
7040 if (r.task.taskId == task) {
7041 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
7042 mHistory.remove(pos);
7043 mHistory.add(top, r);
7044 moved.add(0, r);
7045 top--;
7046 if (first) {
7047 addRecentTask(r.task);
7048 first = false;
7049 }
7050 }
7051 pos--;
7052 }
7053
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007054 if (DEBUG_TRANSITION) Log.v(TAG,
7055 "Prepare to front transition: task=" + tr);
7056 if (reason != null &&
7057 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7058 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7059 HistoryRecord r = topRunningActivityLocked(null);
7060 if (r != null) {
7061 mNoAnimActivities.add(r);
7062 }
7063 } else {
7064 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
7065 }
7066
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007067 mWindowManager.moveAppTokensToTop(moved);
7068 if (VALIDATE_TOKENS) {
7069 mWindowManager.validateAppTokens(mHistory);
7070 }
7071
7072 finishTaskMove(task);
Doug Zongker2bec3d42009-12-04 12:52:44 -08007073 EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007074 }
7075
7076 private final void finishTaskMove(int task) {
7077 resumeTopActivityLocked(null);
7078 }
7079
7080 public void moveTaskToBack(int task) {
7081 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7082 "moveTaskToBack()");
7083
7084 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007085 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
7086 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7087 Binder.getCallingUid(), "Task to back")) {
7088 return;
7089 }
7090 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007091 final long origId = Binder.clearCallingIdentity();
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007092 moveTaskToBackLocked(task, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007093 Binder.restoreCallingIdentity(origId);
7094 }
7095 }
7096
7097 /**
7098 * Moves an activity, and all of the other activities within the same task, to the bottom
7099 * of the history stack. The activity's order within the task is unchanged.
7100 *
7101 * @param token A reference to the activity we wish to move
7102 * @param nonRoot If false then this only works if the activity is the root
7103 * of a task; if true it will work for any activity in a task.
7104 * @return Returns true if the move completed, false if not.
7105 */
7106 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
7107 synchronized(this) {
7108 final long origId = Binder.clearCallingIdentity();
7109 int taskId = getTaskForActivityLocked(token, !nonRoot);
7110 if (taskId >= 0) {
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007111 return moveTaskToBackLocked(taskId, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007112 }
7113 Binder.restoreCallingIdentity(origId);
7114 }
7115 return false;
7116 }
7117
7118 /**
7119 * Worker method for rearranging history stack. Implements the function of moving all
7120 * activities for a specific task (gathering them if disjoint) into a single group at the
7121 * bottom of the stack.
7122 *
7123 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
7124 * to premeptively cancel the move.
7125 *
7126 * @param task The taskId to collect and move to the bottom.
7127 * @return Returns true if the move completed, false if not.
7128 */
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007129 private final boolean moveTaskToBackLocked(int task, HistoryRecord reason) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007130 Log.i(TAG, "moveTaskToBack: " + task);
7131
7132 // If we have a watcher, preflight the move before committing to it. First check
7133 // for *other* available tasks, but if none are available, then try again allowing the
7134 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007135 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007136 HistoryRecord next = topRunningActivityLocked(null, task);
7137 if (next == null) {
7138 next = topRunningActivityLocked(null, 0);
7139 }
7140 if (next != null) {
7141 // ask watcher if this is allowed
7142 boolean moveOK = true;
7143 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007144 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007145 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007146 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007147 }
7148 if (!moveOK) {
7149 return false;
7150 }
7151 }
7152 }
7153
7154 ArrayList moved = new ArrayList();
7155
7156 if (DEBUG_TRANSITION) Log.v(TAG,
7157 "Prepare to back transition: task=" + task);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007158
7159 final int N = mHistory.size();
7160 int bottom = 0;
7161 int pos = 0;
7162
7163 // Shift all activities with this task down to the bottom
7164 // of the stack, keeping them in the same internal order.
7165 while (pos < N) {
7166 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
7167 if (localLOGV) Log.v(
7168 TAG, "At " + pos + " ckp " + r.task + ": " + r);
7169 if (r.task.taskId == task) {
7170 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
7171 mHistory.remove(pos);
7172 mHistory.add(bottom, r);
7173 moved.add(r);
7174 bottom++;
7175 }
7176 pos++;
7177 }
7178
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007179 if (reason != null &&
7180 (reason.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
7181 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_NONE);
7182 HistoryRecord r = topRunningActivityLocked(null);
7183 if (r != null) {
7184 mNoAnimActivities.add(r);
7185 }
7186 } else {
Suchi Amalapurapuc9568e32009-11-05 18:51:16 -08007187 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
Dianne Hackbornbfe319e2009-09-21 00:34:05 -07007188 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007189 mWindowManager.moveAppTokensToBottom(moved);
7190 if (VALIDATE_TOKENS) {
7191 mWindowManager.validateAppTokens(mHistory);
7192 }
7193
7194 finishTaskMove(task);
7195 return true;
7196 }
7197
7198 public void moveTaskBackwards(int task) {
7199 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
7200 "moveTaskBackwards()");
7201
7202 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007203 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
7204 Binder.getCallingUid(), "Task backwards")) {
7205 return;
7206 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007207 final long origId = Binder.clearCallingIdentity();
7208 moveTaskBackwardsLocked(task);
7209 Binder.restoreCallingIdentity(origId);
7210 }
7211 }
7212
7213 private final void moveTaskBackwardsLocked(int task) {
7214 Log.e(TAG, "moveTaskBackwards not yet implemented!");
7215 }
7216
7217 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
7218 synchronized(this) {
7219 return getTaskForActivityLocked(token, onlyRoot);
7220 }
7221 }
7222
7223 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7224 final int N = mHistory.size();
7225 TaskRecord lastTask = null;
7226 for (int i=0; i<N; i++) {
7227 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7228 if (r == token) {
7229 if (!onlyRoot || lastTask != r.task) {
7230 return r.task.taskId;
7231 }
7232 return -1;
7233 }
7234 lastTask = r.task;
7235 }
7236
7237 return -1;
7238 }
7239
7240 /**
7241 * Returns the top activity in any existing task matching the given
7242 * Intent. Returns null if no such task is found.
7243 */
7244 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7245 ComponentName cls = intent.getComponent();
7246 if (info.targetActivity != null) {
7247 cls = new ComponentName(info.packageName, info.targetActivity);
7248 }
7249
7250 TaskRecord cp = null;
7251
7252 final int N = mHistory.size();
7253 for (int i=(N-1); i>=0; i--) {
7254 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7255 if (!r.finishing && r.task != cp
7256 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7257 cp = r.task;
7258 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7259 // + "/aff=" + r.task.affinity + " to new cls="
7260 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7261 if (r.task.affinity != null) {
7262 if (r.task.affinity.equals(info.taskAffinity)) {
7263 //Log.i(TAG, "Found matching affinity!");
7264 return r;
7265 }
7266 } else if (r.task.intent != null
7267 && r.task.intent.getComponent().equals(cls)) {
7268 //Log.i(TAG, "Found matching class!");
7269 //dump();
7270 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7271 return r;
7272 } else if (r.task.affinityIntent != null
7273 && r.task.affinityIntent.getComponent().equals(cls)) {
7274 //Log.i(TAG, "Found matching class!");
7275 //dump();
7276 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7277 return r;
7278 }
7279 }
7280 }
7281
7282 return null;
7283 }
7284
7285 /**
7286 * Returns the first activity (starting from the top of the stack) that
7287 * is the same as the given activity. Returns null if no such activity
7288 * is found.
7289 */
7290 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7291 ComponentName cls = intent.getComponent();
7292 if (info.targetActivity != null) {
7293 cls = new ComponentName(info.packageName, info.targetActivity);
7294 }
7295
7296 final int N = mHistory.size();
7297 for (int i=(N-1); i>=0; i--) {
7298 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7299 if (!r.finishing) {
7300 if (r.intent.getComponent().equals(cls)) {
7301 //Log.i(TAG, "Found matching class!");
7302 //dump();
7303 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7304 return r;
7305 }
7306 }
7307 }
7308
7309 return null;
7310 }
7311
7312 public void finishOtherInstances(IBinder token, ComponentName className) {
7313 synchronized(this) {
7314 final long origId = Binder.clearCallingIdentity();
7315
7316 int N = mHistory.size();
7317 TaskRecord lastTask = null;
7318 for (int i=0; i<N; i++) {
7319 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7320 if (r.realActivity.equals(className)
7321 && r != token && lastTask != r.task) {
7322 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7323 null, "others")) {
7324 i--;
7325 N--;
7326 }
7327 }
7328 lastTask = r.task;
7329 }
7330
7331 Binder.restoreCallingIdentity(origId);
7332 }
7333 }
7334
7335 // =========================================================
7336 // THUMBNAILS
7337 // =========================================================
7338
7339 public void reportThumbnail(IBinder token,
7340 Bitmap thumbnail, CharSequence description) {
7341 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7342 final long origId = Binder.clearCallingIdentity();
7343 sendPendingThumbnail(null, token, thumbnail, description, true);
7344 Binder.restoreCallingIdentity(origId);
7345 }
7346
7347 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7348 Bitmap thumbnail, CharSequence description, boolean always) {
7349 TaskRecord task = null;
7350 ArrayList receivers = null;
7351
7352 //System.out.println("Send pending thumbnail: " + r);
7353
7354 synchronized(this) {
7355 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007356 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007357 if (index < 0) {
7358 return;
7359 }
7360 r = (HistoryRecord)mHistory.get(index);
7361 }
7362 if (thumbnail == null) {
7363 thumbnail = r.thumbnail;
7364 description = r.description;
7365 }
7366 if (thumbnail == null && !always) {
7367 // If there is no thumbnail, and this entry is not actually
7368 // going away, then abort for now and pick up the next
7369 // thumbnail we get.
7370 return;
7371 }
7372 task = r.task;
7373
7374 int N = mPendingThumbnails.size();
7375 int i=0;
7376 while (i<N) {
7377 PendingThumbnailsRecord pr =
7378 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7379 //System.out.println("Looking in " + pr.pendingRecords);
7380 if (pr.pendingRecords.remove(r)) {
7381 if (receivers == null) {
7382 receivers = new ArrayList();
7383 }
7384 receivers.add(pr);
7385 if (pr.pendingRecords.size() == 0) {
7386 pr.finished = true;
7387 mPendingThumbnails.remove(i);
7388 N--;
7389 continue;
7390 }
7391 }
7392 i++;
7393 }
7394 }
7395
7396 if (receivers != null) {
7397 final int N = receivers.size();
7398 for (int i=0; i<N; i++) {
7399 try {
7400 PendingThumbnailsRecord pr =
7401 (PendingThumbnailsRecord)receivers.get(i);
7402 pr.receiver.newThumbnail(
7403 task != null ? task.taskId : -1, thumbnail, description);
7404 if (pr.finished) {
7405 pr.receiver.finished();
7406 }
7407 } catch (Exception e) {
7408 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7409 }
7410 }
7411 }
7412 }
7413
7414 // =========================================================
7415 // CONTENT PROVIDERS
7416 // =========================================================
7417
7418 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7419 List providers = null;
7420 try {
7421 providers = ActivityThread.getPackageManager().
7422 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007423 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007424 } catch (RemoteException ex) {
7425 }
7426 if (providers != null) {
7427 final int N = providers.size();
7428 for (int i=0; i<N; i++) {
7429 ProviderInfo cpi =
7430 (ProviderInfo)providers.get(i);
7431 ContentProviderRecord cpr =
7432 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7433 if (cpr == null) {
7434 cpr = new ContentProviderRecord(cpi, app.info);
7435 mProvidersByClass.put(cpi.name, cpr);
7436 }
7437 app.pubProviders.put(cpi.name, cpr);
7438 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007439 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007440 }
7441 }
7442 return providers;
7443 }
7444
7445 private final String checkContentProviderPermissionLocked(
7446 ProviderInfo cpi, ProcessRecord r, int mode) {
7447 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7448 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7449 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7450 cpi.exported ? -1 : cpi.applicationInfo.uid)
7451 == PackageManager.PERMISSION_GRANTED
7452 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7453 return null;
7454 }
7455 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7456 cpi.exported ? -1 : cpi.applicationInfo.uid)
7457 == PackageManager.PERMISSION_GRANTED) {
7458 return null;
7459 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007460
7461 PathPermission[] pps = cpi.pathPermissions;
7462 if (pps != null) {
7463 int i = pps.length;
7464 while (i > 0) {
7465 i--;
7466 PathPermission pp = pps[i];
7467 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7468 cpi.exported ? -1 : cpi.applicationInfo.uid)
7469 == PackageManager.PERMISSION_GRANTED
7470 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7471 return null;
7472 }
7473 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7474 cpi.exported ? -1 : cpi.applicationInfo.uid)
7475 == PackageManager.PERMISSION_GRANTED) {
7476 return null;
7477 }
7478 }
7479 }
7480
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007481 String msg = "Permission Denial: opening provider " + cpi.name
7482 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7483 + ", uid=" + callingUid + ") requires "
7484 + cpi.readPermission + " or " + cpi.writePermission;
7485 Log.w(TAG, msg);
7486 return msg;
7487 }
7488
7489 private final ContentProviderHolder getContentProviderImpl(
7490 IApplicationThread caller, String name) {
7491 ContentProviderRecord cpr;
7492 ProviderInfo cpi = null;
7493
7494 synchronized(this) {
7495 ProcessRecord r = null;
7496 if (caller != null) {
7497 r = getRecordForAppLocked(caller);
7498 if (r == null) {
7499 throw new SecurityException(
7500 "Unable to find app for caller " + caller
7501 + " (pid=" + Binder.getCallingPid()
7502 + ") when getting content provider " + name);
7503 }
7504 }
7505
7506 // First check if this content provider has been published...
7507 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7508 if (cpr != null) {
7509 cpi = cpr.info;
7510 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7511 return new ContentProviderHolder(cpi,
7512 cpi.readPermission != null
7513 ? cpi.readPermission : cpi.writePermission);
7514 }
7515
7516 if (r != null && cpr.canRunHere(r)) {
7517 // This provider has been published or is in the process
7518 // of being published... but it is also allowed to run
7519 // in the caller's process, so don't make a connection
7520 // and just let the caller instantiate its own instance.
7521 if (cpr.provider != null) {
7522 // don't give caller the provider object, it needs
7523 // to make its own.
7524 cpr = new ContentProviderRecord(cpr);
7525 }
7526 return cpr;
7527 }
7528
7529 final long origId = Binder.clearCallingIdentity();
7530
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007531 // In this case the provider instance already exists, so we can
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007532 // return it right away.
7533 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007534 if (DEBUG_PROVIDER) Log.v(TAG,
7535 "Adding provider requested by "
7536 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007537 + cpr.info.processName);
7538 Integer cnt = r.conProviders.get(cpr);
7539 if (cnt == null) {
7540 r.conProviders.put(cpr, new Integer(1));
7541 } else {
7542 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7543 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007544 cpr.clients.add(r);
7545 } else {
7546 cpr.externals++;
7547 }
7548
7549 if (cpr.app != null) {
7550 updateOomAdjLocked(cpr.app);
7551 }
7552
7553 Binder.restoreCallingIdentity(origId);
7554
7555 } else {
7556 try {
7557 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007558 resolveContentProvider(name,
7559 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007560 } catch (RemoteException ex) {
7561 }
7562 if (cpi == null) {
7563 return null;
7564 }
7565
7566 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7567 return new ContentProviderHolder(cpi,
7568 cpi.readPermission != null
7569 ? cpi.readPermission : cpi.writePermission);
7570 }
7571
7572 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7573 final boolean firstClass = cpr == null;
7574 if (firstClass) {
7575 try {
7576 ApplicationInfo ai =
7577 ActivityThread.getPackageManager().
7578 getApplicationInfo(
7579 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007580 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007581 if (ai == null) {
7582 Log.w(TAG, "No package info for content provider "
7583 + cpi.name);
7584 return null;
7585 }
7586 cpr = new ContentProviderRecord(cpi, ai);
7587 } catch (RemoteException ex) {
7588 // pm is in same process, this will never happen.
7589 }
7590 }
7591
7592 if (r != null && cpr.canRunHere(r)) {
7593 // If this is a multiprocess provider, then just return its
7594 // info and allow the caller to instantiate it. Only do
7595 // this if the provider is the same user as the caller's
7596 // process, or can run as root (so can be in any process).
7597 return cpr;
7598 }
7599
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007600 if (DEBUG_PROVIDER) {
7601 RuntimeException e = new RuntimeException("here");
7602 Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7603 + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007604 }
7605
7606 // This is single process, and our app is now connecting to it.
7607 // See if we are already in the process of launching this
7608 // provider.
7609 final int N = mLaunchingProviders.size();
7610 int i;
7611 for (i=0; i<N; i++) {
7612 if (mLaunchingProviders.get(i) == cpr) {
7613 break;
7614 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007615 }
7616
7617 // If the provider is not already being launched, then get it
7618 // started.
7619 if (i >= N) {
7620 final long origId = Binder.clearCallingIdentity();
7621 ProcessRecord proc = startProcessLocked(cpi.processName,
7622 cpr.appInfo, false, 0, "content provider",
7623 new ComponentName(cpi.applicationInfo.packageName,
Dianne Hackborn9acc0302009-08-25 00:27:12 -07007624 cpi.name), false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007625 if (proc == null) {
7626 Log.w(TAG, "Unable to launch app "
7627 + cpi.applicationInfo.packageName + "/"
7628 + cpi.applicationInfo.uid + " for provider "
7629 + name + ": process is bad");
7630 return null;
7631 }
7632 cpr.launchingApp = proc;
7633 mLaunchingProviders.add(cpr);
7634 Binder.restoreCallingIdentity(origId);
7635 }
7636
7637 // Make sure the provider is published (the same provider class
7638 // may be published under multiple names).
7639 if (firstClass) {
7640 mProvidersByClass.put(cpi.name, cpr);
7641 }
7642 mProvidersByName.put(name, cpr);
7643
7644 if (r != null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007645 if (DEBUG_PROVIDER) Log.v(TAG,
7646 "Adding provider requested by "
7647 + r.processName + " from process "
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007648 + cpr.info.processName);
7649 Integer cnt = r.conProviders.get(cpr);
7650 if (cnt == null) {
7651 r.conProviders.put(cpr, new Integer(1));
7652 } else {
7653 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
7654 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007655 cpr.clients.add(r);
7656 } else {
7657 cpr.externals++;
7658 }
7659 }
7660 }
7661
7662 // Wait for the provider to be published...
7663 synchronized (cpr) {
7664 while (cpr.provider == null) {
7665 if (cpr.launchingApp == null) {
7666 Log.w(TAG, "Unable to launch app "
7667 + cpi.applicationInfo.packageName + "/"
7668 + cpi.applicationInfo.uid + " for provider "
7669 + name + ": launching app became null");
Doug Zongker2bec3d42009-12-04 12:52:44 -08007670 EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007671 cpi.applicationInfo.packageName,
7672 cpi.applicationInfo.uid, name);
7673 return null;
7674 }
7675 try {
7676 cpr.wait();
7677 } catch (InterruptedException ex) {
7678 }
7679 }
7680 }
7681 return cpr;
7682 }
7683
7684 public final ContentProviderHolder getContentProvider(
7685 IApplicationThread caller, String name) {
7686 if (caller == null) {
7687 String msg = "null IApplicationThread when getting content provider "
7688 + name;
7689 Log.w(TAG, msg);
7690 throw new SecurityException(msg);
7691 }
7692
7693 return getContentProviderImpl(caller, name);
7694 }
7695
7696 private ContentProviderHolder getContentProviderExternal(String name) {
7697 return getContentProviderImpl(null, name);
7698 }
7699
7700 /**
7701 * Drop a content provider from a ProcessRecord's bookkeeping
7702 * @param cpr
7703 */
7704 public void removeContentProvider(IApplicationThread caller, String name) {
7705 synchronized (this) {
7706 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7707 if(cpr == null) {
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007708 // remove from mProvidersByClass
7709 if (DEBUG_PROVIDER) Log.v(TAG, name +
7710 " provider not found in providers list");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007711 return;
7712 }
7713 final ProcessRecord r = getRecordForAppLocked(caller);
7714 if (r == null) {
7715 throw new SecurityException(
7716 "Unable to find app for caller " + caller +
7717 " when removing content provider " + name);
7718 }
7719 //update content provider record entry info
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007720 ContentProviderRecord localCpr = (ContentProviderRecord)
7721 mProvidersByClass.get(cpr.info.name);
7722 if (DEBUG_PROVIDER) Log.v(TAG, "Removing provider requested by "
7723 + r.info.processName + " from process "
7724 + localCpr.appInfo.processName);
7725 if (localCpr.app == r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007726 //should not happen. taken care of as a local provider
Dianne Hackborna1e989b2009-09-01 19:54:29 -07007727 Log.w(TAG, "removeContentProvider called on local provider: "
7728 + cpr.info.name + " in process " + r.processName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007729 return;
7730 } else {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07007731 Integer cnt = r.conProviders.get(localCpr);
7732 if (cnt == null || cnt.intValue() <= 1) {
7733 localCpr.clients.remove(r);
7734 r.conProviders.remove(localCpr);
7735 } else {
7736 r.conProviders.put(localCpr, new Integer(cnt.intValue()-1));
7737 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007738 }
7739 updateOomAdjLocked();
7740 }
7741 }
7742
7743 private void removeContentProviderExternal(String name) {
7744 synchronized (this) {
7745 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7746 if(cpr == null) {
7747 //remove from mProvidersByClass
7748 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7749 return;
7750 }
7751
7752 //update content provider record entry info
7753 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7754 localCpr.externals--;
7755 if (localCpr.externals < 0) {
7756 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7757 }
7758 updateOomAdjLocked();
7759 }
7760 }
7761
7762 public final void publishContentProviders(IApplicationThread caller,
7763 List<ContentProviderHolder> providers) {
7764 if (providers == null) {
7765 return;
7766 }
7767
7768 synchronized(this) {
7769 final ProcessRecord r = getRecordForAppLocked(caller);
7770 if (r == null) {
7771 throw new SecurityException(
7772 "Unable to find app for caller " + caller
7773 + " (pid=" + Binder.getCallingPid()
7774 + ") when publishing content providers");
7775 }
7776
7777 final long origId = Binder.clearCallingIdentity();
7778
7779 final int N = providers.size();
7780 for (int i=0; i<N; i++) {
7781 ContentProviderHolder src = providers.get(i);
7782 if (src == null || src.info == null || src.provider == null) {
7783 continue;
7784 }
7785 ContentProviderRecord dst =
7786 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7787 if (dst != null) {
7788 mProvidersByClass.put(dst.info.name, dst);
7789 String names[] = dst.info.authority.split(";");
7790 for (int j = 0; j < names.length; j++) {
7791 mProvidersByName.put(names[j], dst);
7792 }
7793
7794 int NL = mLaunchingProviders.size();
7795 int j;
7796 for (j=0; j<NL; j++) {
7797 if (mLaunchingProviders.get(j) == dst) {
7798 mLaunchingProviders.remove(j);
7799 j--;
7800 NL--;
7801 }
7802 }
7803 synchronized (dst) {
7804 dst.provider = src.provider;
7805 dst.app = r;
7806 dst.notifyAll();
7807 }
7808 updateOomAdjLocked(r);
7809 }
7810 }
7811
7812 Binder.restoreCallingIdentity(origId);
7813 }
7814 }
7815
7816 public static final void installSystemProviders() {
7817 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7818 List providers = mSelf.generateApplicationProvidersLocked(app);
7819 mSystemThread.installSystemProviders(providers);
7820 }
7821
7822 // =========================================================
7823 // GLOBAL MANAGEMENT
7824 // =========================================================
7825
7826 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7827 ApplicationInfo info, String customProcess) {
7828 String proc = customProcess != null ? customProcess : info.processName;
7829 BatteryStatsImpl.Uid.Proc ps = null;
7830 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7831 synchronized (stats) {
7832 ps = stats.getProcessStatsLocked(info.uid, proc);
7833 }
7834 return new ProcessRecord(ps, thread, info, proc);
7835 }
7836
7837 final ProcessRecord addAppLocked(ApplicationInfo info) {
7838 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7839
7840 if (app == null) {
7841 app = newProcessRecordLocked(null, info, null);
7842 mProcessNames.put(info.processName, info.uid, app);
7843 updateLRUListLocked(app, true);
7844 }
7845
7846 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7847 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7848 app.persistent = true;
7849 app.maxAdj = CORE_SERVER_ADJ;
7850 }
7851 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7852 mPersistentStartingProcesses.add(app);
7853 startProcessLocked(app, "added application", app.processName);
7854 }
7855
7856 return app;
7857 }
7858
7859 public void unhandledBack() {
7860 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7861 "unhandledBack()");
7862
7863 synchronized(this) {
7864 int count = mHistory.size();
7865 if (Config.LOGD) Log.d(
7866 TAG, "Performing unhandledBack(): stack size = " + count);
7867 if (count > 1) {
7868 final long origId = Binder.clearCallingIdentity();
7869 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7870 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7871 Binder.restoreCallingIdentity(origId);
7872 }
7873 }
7874 }
7875
7876 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7877 String name = uri.getAuthority();
7878 ContentProviderHolder cph = getContentProviderExternal(name);
7879 ParcelFileDescriptor pfd = null;
7880 if (cph != null) {
7881 // We record the binder invoker's uid in thread-local storage before
7882 // going to the content provider to open the file. Later, in the code
7883 // that handles all permissions checks, we look for this uid and use
7884 // that rather than the Activity Manager's own uid. The effect is that
7885 // we do the check against the caller's permissions even though it looks
7886 // to the content provider like the Activity Manager itself is making
7887 // the request.
7888 sCallerIdentity.set(new Identity(
7889 Binder.getCallingPid(), Binder.getCallingUid()));
7890 try {
7891 pfd = cph.provider.openFile(uri, "r");
7892 } catch (FileNotFoundException e) {
7893 // do nothing; pfd will be returned null
7894 } finally {
7895 // Ensure that whatever happens, we clean up the identity state
7896 sCallerIdentity.remove();
7897 }
7898
7899 // We've got the fd now, so we're done with the provider.
7900 removeContentProviderExternal(name);
7901 } else {
7902 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7903 }
7904 return pfd;
7905 }
7906
7907 public void goingToSleep() {
7908 synchronized(this) {
7909 mSleeping = true;
7910 mWindowManager.setEventDispatching(false);
7911
7912 if (mResumedActivity != null) {
7913 pauseIfSleepingLocked();
7914 } else {
7915 Log.w(TAG, "goingToSleep with no resumed activity!");
7916 }
7917 }
7918 }
7919
Dianne Hackborn55280a92009-05-07 15:53:46 -07007920 public boolean shutdown(int timeout) {
7921 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7922 != PackageManager.PERMISSION_GRANTED) {
7923 throw new SecurityException("Requires permission "
7924 + android.Manifest.permission.SHUTDOWN);
7925 }
7926
7927 boolean timedout = false;
7928
7929 synchronized(this) {
7930 mShuttingDown = true;
7931 mWindowManager.setEventDispatching(false);
7932
7933 if (mResumedActivity != null) {
7934 pauseIfSleepingLocked();
7935 final long endTime = System.currentTimeMillis() + timeout;
7936 while (mResumedActivity != null || mPausingActivity != null) {
7937 long delay = endTime - System.currentTimeMillis();
7938 if (delay <= 0) {
7939 Log.w(TAG, "Activity manager shutdown timed out");
7940 timedout = true;
7941 break;
7942 }
7943 try {
7944 this.wait();
7945 } catch (InterruptedException e) {
7946 }
7947 }
7948 }
7949 }
7950
7951 mUsageStatsService.shutdown();
7952 mBatteryStatsService.shutdown();
7953
7954 return timedout;
7955 }
7956
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007957 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007958 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007959 if (!mGoingToSleep.isHeld()) {
7960 mGoingToSleep.acquire();
7961 if (mLaunchingActivity.isHeld()) {
7962 mLaunchingActivity.release();
7963 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7964 }
7965 }
7966
7967 // If we are not currently pausing an activity, get the current
7968 // one to pause. If we are pausing one, we will just let that stuff
7969 // run and release the wake lock when all done.
7970 if (mPausingActivity == null) {
7971 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7972 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7973 startPausingLocked(false, true);
7974 }
7975 }
7976 }
7977
7978 public void wakingUp() {
7979 synchronized(this) {
7980 if (mGoingToSleep.isHeld()) {
7981 mGoingToSleep.release();
7982 }
7983 mWindowManager.setEventDispatching(true);
7984 mSleeping = false;
7985 resumeTopActivityLocked(null);
7986 }
7987 }
7988
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007989 public void stopAppSwitches() {
7990 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7991 != PackageManager.PERMISSION_GRANTED) {
7992 throw new SecurityException("Requires permission "
7993 + android.Manifest.permission.STOP_APP_SWITCHES);
7994 }
7995
7996 synchronized(this) {
7997 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7998 + APP_SWITCH_DELAY_TIME;
7999 mDidAppSwitch = false;
8000 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8001 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
8002 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
8003 }
8004 }
8005
8006 public void resumeAppSwitches() {
8007 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
8008 != PackageManager.PERMISSION_GRANTED) {
8009 throw new SecurityException("Requires permission "
8010 + android.Manifest.permission.STOP_APP_SWITCHES);
8011 }
8012
8013 synchronized(this) {
8014 // Note that we don't execute any pending app switches... we will
8015 // let those wait until either the timeout, or the next start
8016 // activity request.
8017 mAppSwitchesAllowedTime = 0;
8018 }
8019 }
8020
8021 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
8022 String name) {
8023 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
8024 return true;
8025 }
8026
8027 final int perm = checkComponentPermission(
8028 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
8029 callingUid, -1);
8030 if (perm == PackageManager.PERMISSION_GRANTED) {
8031 return true;
8032 }
8033
8034 Log.w(TAG, name + " request from " + callingUid + " stopped");
8035 return false;
8036 }
8037
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008038 public void setDebugApp(String packageName, boolean waitForDebugger,
8039 boolean persistent) {
8040 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
8041 "setDebugApp()");
8042
8043 // Note that this is not really thread safe if there are multiple
8044 // callers into it at the same time, but that's not a situation we
8045 // care about.
8046 if (persistent) {
8047 final ContentResolver resolver = mContext.getContentResolver();
8048 Settings.System.putString(
8049 resolver, Settings.System.DEBUG_APP,
8050 packageName);
8051 Settings.System.putInt(
8052 resolver, Settings.System.WAIT_FOR_DEBUGGER,
8053 waitForDebugger ? 1 : 0);
8054 }
8055
8056 synchronized (this) {
8057 if (!persistent) {
8058 mOrigDebugApp = mDebugApp;
8059 mOrigWaitForDebugger = mWaitForDebugger;
8060 }
8061 mDebugApp = packageName;
8062 mWaitForDebugger = waitForDebugger;
8063 mDebugTransient = !persistent;
8064 if (packageName != null) {
8065 final long origId = Binder.clearCallingIdentity();
8066 uninstallPackageLocked(packageName, -1, false);
8067 Binder.restoreCallingIdentity(origId);
8068 }
8069 }
8070 }
8071
8072 public void setAlwaysFinish(boolean enabled) {
8073 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
8074 "setAlwaysFinish()");
8075
8076 Settings.System.putInt(
8077 mContext.getContentResolver(),
8078 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
8079
8080 synchronized (this) {
8081 mAlwaysFinishActivities = enabled;
8082 }
8083 }
8084
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008085 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008086 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008087 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008088 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008089 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008090 }
8091 }
8092
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008093 public void registerActivityWatcher(IActivityWatcher watcher) {
8094 mWatchers.register(watcher);
8095 }
8096
8097 public void unregisterActivityWatcher(IActivityWatcher watcher) {
8098 mWatchers.unregister(watcher);
8099 }
8100
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008101 public final void enterSafeMode() {
8102 synchronized(this) {
8103 // It only makes sense to do this before the system is ready
8104 // and started launching other packages.
8105 if (!mSystemReady) {
8106 try {
8107 ActivityThread.getPackageManager().enterSafeMode();
8108 } catch (RemoteException e) {
8109 }
8110
8111 View v = LayoutInflater.from(mContext).inflate(
8112 com.android.internal.R.layout.safe_mode, null);
8113 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
8114 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
8115 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
8116 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
8117 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
8118 lp.format = v.getBackground().getOpacity();
8119 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
8120 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
8121 ((WindowManager)mContext.getSystemService(
8122 Context.WINDOW_SERVICE)).addView(v, lp);
8123 }
8124 }
8125 }
8126
8127 public void noteWakeupAlarm(IIntentSender sender) {
8128 if (!(sender instanceof PendingIntentRecord)) {
8129 return;
8130 }
8131 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
8132 synchronized (stats) {
8133 if (mBatteryStatsService.isOnBattery()) {
8134 mBatteryStatsService.enforceCallingPermission();
8135 PendingIntentRecord rec = (PendingIntentRecord)sender;
8136 int MY_UID = Binder.getCallingUid();
8137 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
8138 BatteryStatsImpl.Uid.Pkg pkg =
8139 stats.getPackageStatsLocked(uid, rec.key.packageName);
8140 pkg.incWakeupsLocked();
8141 }
8142 }
8143 }
8144
8145 public boolean killPidsForMemory(int[] pids) {
8146 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
8147 throw new SecurityException("killPidsForMemory only available to the system");
8148 }
8149
8150 // XXX Note: don't acquire main activity lock here, because the window
8151 // manager calls in with its locks held.
8152
8153 boolean killed = false;
8154 synchronized (mPidsSelfLocked) {
8155 int[] types = new int[pids.length];
8156 int worstType = 0;
8157 for (int i=0; i<pids.length; i++) {
8158 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8159 if (proc != null) {
8160 int type = proc.setAdj;
8161 types[i] = type;
8162 if (type > worstType) {
8163 worstType = type;
8164 }
8165 }
8166 }
8167
8168 // If the worse oom_adj is somewhere in the hidden proc LRU range,
8169 // then constrain it so we will kill all hidden procs.
8170 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
8171 worstType = HIDDEN_APP_MIN_ADJ;
8172 }
8173 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
8174 for (int i=0; i<pids.length; i++) {
8175 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
8176 if (proc == null) {
8177 continue;
8178 }
8179 int adj = proc.setAdj;
8180 if (adj >= worstType) {
8181 Log.w(TAG, "Killing for memory: " + proc + " (adj "
8182 + adj + ")");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008183 EventLog.writeEvent(EventLogTags.AM_KILL_FOR_MEMORY, proc.pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008184 proc.processName, adj);
8185 killed = true;
8186 Process.killProcess(pids[i]);
8187 }
8188 }
8189 }
8190 return killed;
8191 }
8192
8193 public void reportPss(IApplicationThread caller, int pss) {
8194 Watchdog.PssRequestor req;
8195 String name;
8196 ProcessRecord callerApp;
8197 synchronized (this) {
8198 if (caller == null) {
8199 return;
8200 }
8201 callerApp = getRecordForAppLocked(caller);
8202 if (callerApp == null) {
8203 return;
8204 }
8205 callerApp.lastPss = pss;
8206 req = callerApp;
8207 name = callerApp.processName;
8208 }
8209 Watchdog.getInstance().reportPss(req, name, pss);
8210 if (!callerApp.persistent) {
8211 removeRequestedPss(callerApp);
8212 }
8213 }
8214
8215 public void requestPss(Runnable completeCallback) {
8216 ArrayList<ProcessRecord> procs;
8217 synchronized (this) {
8218 mRequestPssCallback = completeCallback;
8219 mRequestPssList.clear();
8220 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
8221 ProcessRecord proc = mLRUProcesses.get(i);
8222 if (!proc.persistent) {
8223 mRequestPssList.add(proc);
8224 }
8225 }
8226 procs = new ArrayList<ProcessRecord>(mRequestPssList);
8227 }
8228
8229 int oldPri = Process.getThreadPriority(Process.myTid());
8230 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
8231 for (int i=procs.size()-1; i>=0; i--) {
8232 ProcessRecord proc = procs.get(i);
8233 proc.lastPss = 0;
8234 proc.requestPss();
8235 }
8236 Process.setThreadPriority(oldPri);
8237 }
8238
8239 void removeRequestedPss(ProcessRecord proc) {
8240 Runnable callback = null;
8241 synchronized (this) {
8242 if (mRequestPssList.remove(proc)) {
8243 if (mRequestPssList.size() == 0) {
8244 callback = mRequestPssCallback;
8245 mRequestPssCallback = null;
8246 }
8247 }
8248 }
8249
8250 if (callback != null) {
8251 callback.run();
8252 }
8253 }
8254
8255 public void collectPss(Watchdog.PssStats stats) {
8256 stats.mEmptyPss = 0;
8257 stats.mEmptyCount = 0;
8258 stats.mBackgroundPss = 0;
8259 stats.mBackgroundCount = 0;
8260 stats.mServicePss = 0;
8261 stats.mServiceCount = 0;
8262 stats.mVisiblePss = 0;
8263 stats.mVisibleCount = 0;
8264 stats.mForegroundPss = 0;
8265 stats.mForegroundCount = 0;
8266 stats.mNoPssCount = 0;
8267 synchronized (this) {
8268 int i;
8269 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8270 ? mProcDeaths.length : stats.mProcDeaths.length;
8271 int aggr = 0;
8272 for (i=0; i<NPD; i++) {
8273 aggr += mProcDeaths[i];
8274 stats.mProcDeaths[i] = aggr;
8275 }
8276 while (i<stats.mProcDeaths.length) {
8277 stats.mProcDeaths[i] = 0;
8278 i++;
8279 }
8280
8281 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8282 ProcessRecord proc = mLRUProcesses.get(i);
8283 if (proc.persistent) {
8284 continue;
8285 }
8286 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8287 if (proc.lastPss == 0) {
8288 stats.mNoPssCount++;
8289 continue;
8290 }
8291 if (proc.setAdj == EMPTY_APP_ADJ) {
8292 stats.mEmptyPss += proc.lastPss;
8293 stats.mEmptyCount++;
8294 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8295 stats.mEmptyPss += proc.lastPss;
8296 stats.mEmptyCount++;
8297 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8298 stats.mBackgroundPss += proc.lastPss;
8299 stats.mBackgroundCount++;
8300 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8301 stats.mVisiblePss += proc.lastPss;
8302 stats.mVisibleCount++;
8303 } else {
8304 stats.mForegroundPss += proc.lastPss;
8305 stats.mForegroundCount++;
8306 }
8307 }
8308 }
8309 }
8310
8311 public final void startRunning(String pkg, String cls, String action,
8312 String data) {
8313 synchronized(this) {
8314 if (mStartRunning) {
8315 return;
8316 }
8317 mStartRunning = true;
8318 mTopComponent = pkg != null && cls != null
8319 ? new ComponentName(pkg, cls) : null;
8320 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8321 mTopData = data;
8322 if (!mSystemReady) {
8323 return;
8324 }
8325 }
8326
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008327 systemReady(null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008328 }
8329
8330 private void retrieveSettings() {
8331 final ContentResolver resolver = mContext.getContentResolver();
8332 String debugApp = Settings.System.getString(
8333 resolver, Settings.System.DEBUG_APP);
8334 boolean waitForDebugger = Settings.System.getInt(
8335 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8336 boolean alwaysFinishActivities = Settings.System.getInt(
8337 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8338
8339 Configuration configuration = new Configuration();
8340 Settings.System.getConfiguration(resolver, configuration);
8341
8342 synchronized (this) {
8343 mDebugApp = mOrigDebugApp = debugApp;
8344 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8345 mAlwaysFinishActivities = alwaysFinishActivities;
8346 // This happens before any activities are started, so we can
8347 // change mConfiguration in-place.
8348 mConfiguration.updateFrom(configuration);
Dianne Hackborndc6b6352009-09-30 14:20:09 -07008349 if (DEBUG_CONFIGURATION) Log.v(TAG, "Initial config: " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008350 }
8351 }
8352
8353 public boolean testIsSystemReady() {
8354 // no need to synchronize(this) just to read & return the value
8355 return mSystemReady;
8356 }
8357
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008358 public void systemReady(final Runnable goingCallback) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008359 // In the simulator, startRunning will never have been called, which
8360 // normally sets a few crucial variables. Do it here instead.
8361 if (!Process.supportsProcesses()) {
8362 mStartRunning = true;
8363 mTopAction = Intent.ACTION_MAIN;
8364 }
8365
8366 synchronized(this) {
8367 if (mSystemReady) {
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008368 if (goingCallback != null) goingCallback.run();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008369 return;
8370 }
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008371
8372 // Check to see if there are any update receivers to run.
8373 if (!mDidUpdate) {
8374 if (mWaitingUpdate) {
8375 return;
8376 }
8377 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
8378 List<ResolveInfo> ris = null;
8379 try {
8380 ris = ActivityThread.getPackageManager().queryIntentReceivers(
8381 intent, null, 0);
8382 } catch (RemoteException e) {
8383 }
8384 if (ris != null) {
8385 for (int i=ris.size()-1; i>=0; i--) {
8386 if ((ris.get(i).activityInfo.applicationInfo.flags
8387 &ApplicationInfo.FLAG_SYSTEM) == 0) {
8388 ris.remove(i);
8389 }
8390 }
8391 intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
8392 for (int i=0; i<ris.size(); i++) {
8393 ActivityInfo ai = ris.get(i).activityInfo;
8394 intent.setComponent(new ComponentName(ai.packageName, ai.name));
8395 IIntentReceiver finisher = null;
8396 if (i == 0) {
8397 finisher = new IIntentReceiver.Stub() {
8398 public void performReceive(Intent intent, int resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -07008399 String data, Bundle extras, boolean ordered,
8400 boolean sticky)
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008401 throws RemoteException {
8402 synchronized (ActivityManagerService.this) {
8403 mDidUpdate = true;
8404 }
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008405 systemReady(goingCallback);
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008406 }
8407 };
8408 }
8409 Log.i(TAG, "Sending system update to: " + intent.getComponent());
8410 broadcastIntentLocked(null, null, intent, null, finisher,
8411 0, null, null, null, true, false, MY_PID, Process.SYSTEM_UID);
8412 if (i == 0) {
8413 mWaitingUpdate = true;
8414 }
8415 }
8416 }
8417 if (mWaitingUpdate) {
8418 return;
8419 }
8420 mDidUpdate = true;
8421 }
8422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008423 mSystemReady = true;
8424 if (!mStartRunning) {
8425 return;
8426 }
8427 }
8428
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008429 ArrayList<ProcessRecord> procsToKill = null;
8430 synchronized(mPidsSelfLocked) {
8431 for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
8432 ProcessRecord proc = mPidsSelfLocked.valueAt(i);
8433 if (!isAllowedWhileBooting(proc.info)){
8434 if (procsToKill == null) {
8435 procsToKill = new ArrayList<ProcessRecord>();
8436 }
8437 procsToKill.add(proc);
8438 }
8439 }
8440 }
8441
8442 if (procsToKill != null) {
8443 synchronized(this) {
8444 for (int i=procsToKill.size()-1; i>=0; i--) {
8445 ProcessRecord proc = procsToKill.get(i);
8446 Log.i(TAG, "Removing system update proc: " + proc);
8447 removeProcessLocked(proc, true);
8448 }
8449 }
8450 }
8451
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008452 Log.i(TAG, "System now ready");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008453 EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_AMS_READY,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008454 SystemClock.uptimeMillis());
8455
8456 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008457 // Make sure we have no pre-ready processes sitting around.
8458
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008459 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8460 ResolveInfo ri = mContext.getPackageManager()
8461 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008462 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008463 CharSequence errorMsg = null;
8464 if (ri != null) {
8465 ActivityInfo ai = ri.activityInfo;
8466 ApplicationInfo app = ai.applicationInfo;
8467 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8468 mTopAction = Intent.ACTION_FACTORY_TEST;
8469 mTopData = null;
8470 mTopComponent = new ComponentName(app.packageName,
8471 ai.name);
8472 } else {
8473 errorMsg = mContext.getResources().getText(
8474 com.android.internal.R.string.factorytest_not_system);
8475 }
8476 } else {
8477 errorMsg = mContext.getResources().getText(
8478 com.android.internal.R.string.factorytest_no_action);
8479 }
8480 if (errorMsg != null) {
8481 mTopAction = null;
8482 mTopData = null;
8483 mTopComponent = null;
8484 Message msg = Message.obtain();
8485 msg.what = SHOW_FACTORY_ERROR_MSG;
8486 msg.getData().putCharSequence("msg", errorMsg);
8487 mHandler.sendMessage(msg);
8488 }
8489 }
8490 }
8491
8492 retrieveSettings();
8493
Dianne Hackborna34f1ad2009-09-02 13:26:28 -07008494 if (goingCallback != null) goingCallback.run();
8495
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008496 synchronized (this) {
8497 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8498 try {
8499 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008500 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008501 if (apps != null) {
8502 int N = apps.size();
8503 int i;
8504 for (i=0; i<N; i++) {
8505 ApplicationInfo info
8506 = (ApplicationInfo)apps.get(i);
8507 if (info != null &&
8508 !info.packageName.equals("android")) {
8509 addAppLocked(info);
8510 }
8511 }
8512 }
8513 } catch (RemoteException ex) {
8514 // pm is in same process, this will never happen.
8515 }
8516 }
8517
Dianne Hackborn9acc0302009-08-25 00:27:12 -07008518 // Start up initial activity.
8519 mBooting = true;
8520
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008521 try {
8522 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8523 Message msg = Message.obtain();
8524 msg.what = SHOW_UID_ERROR_MSG;
8525 mHandler.sendMessage(msg);
8526 }
8527 } catch (RemoteException e) {
8528 }
8529
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008530 resumeTopActivityLocked(null);
8531 }
8532 }
8533
Dan Egnorb7f03672009-12-09 16:22:32 -08008534 private boolean makeAppCrashingLocked(ProcessRecord app,
8535 String tag, String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008536 app.crashing = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008537 app.crashingReport = generateProcessError(app,
8538 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg,
8539 stackTrace);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008540 startAppProblemLocked(app);
8541 app.stopFreezingAllLocked();
8542 return handleAppCrashLocked(app);
8543 }
8544
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008545 private ComponentName getErrorReportReceiver(ProcessRecord app) {
Jacek Surazskia2339432009-09-18 15:01:26 +02008546 // check if error reporting is enabled in Gservices
8547 int enabled = Settings.Gservices.getInt(mContext.getContentResolver(),
8548 Settings.Gservices.SEND_ACTION_APP_ERROR, 0);
8549 if (enabled == 0) {
8550 return null;
8551 }
8552
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008553 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008554
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008555 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008556 // look for receiver in the installer package
8557 String candidate = pm.getInstallerPackageName(app.info.packageName);
8558 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8559 if (result != null) {
8560 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008561 }
8562
Jacek Surazski82a73df2009-06-17 14:33:18 +02008563 // if the error app is on the system image, look for system apps
8564 // error receiver
8565 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8566 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8567 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8568 if (result != null) {
8569 return result;
8570 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008571 }
8572
Jacek Surazski82a73df2009-06-17 14:33:18 +02008573 // if there is a default receiver, try that
8574 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8575 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008576 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008577 // should not happen
8578 Log.e(TAG, "error talking to PackageManager", e);
8579 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008580 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008581 }
8582
8583 /**
8584 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8585 *
8586 * @param pm PackageManager isntance
8587 * @param errorPackage package which caused the error
8588 * @param receiverPackage candidate package to receive the error
8589 * @return activity component within receiverPackage which handles
8590 * ACTION_APP_ERROR, or null if not found
8591 */
8592 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8593 String receiverPackage) throws RemoteException {
8594 if (receiverPackage == null || receiverPackage.length() == 0) {
8595 return null;
8596 }
8597
8598 // break the loop if it's the error report receiver package that crashed
8599 if (receiverPackage.equals(errorPackage)) {
8600 return null;
8601 }
8602
8603 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8604 intent.setPackage(receiverPackage);
8605 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8606 if (info == null || info.activityInfo == null) {
8607 return null;
8608 }
8609 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008610 }
8611
Dan Egnorb7f03672009-12-09 16:22:32 -08008612 private void makeAppNotRespondingLocked(ProcessRecord app,
8613 String tag, String shortMsg, String longMsg) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008614 app.notResponding = true;
Dan Egnorb7f03672009-12-09 16:22:32 -08008615 app.notRespondingReport = generateProcessError(app,
8616 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg, null);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008617 startAppProblemLocked(app);
8618 app.stopFreezingAllLocked();
8619 }
8620
8621 /**
8622 * Generate a process error record, suitable for attachment to a ProcessRecord.
8623 *
8624 * @param app The ProcessRecord in which the error occurred.
8625 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8626 * ActivityManager.AppErrorStateInfo
8627 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8628 * @param shortMsg Short message describing the crash.
8629 * @param longMsg Long message describing the crash.
Dan Egnorb7f03672009-12-09 16:22:32 -08008630 * @param stackTrace Full crash stack trace, may be null.
8631 *
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008632 * @return Returns a fully-formed AppErrorStateInfo record.
8633 */
8634 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
Dan Egnorb7f03672009-12-09 16:22:32 -08008635 int condition, String tag, String shortMsg, String longMsg, String stackTrace) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008636 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
Dan Egnorb7f03672009-12-09 16:22:32 -08008637
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008638 report.condition = condition;
8639 report.processName = app.processName;
8640 report.pid = app.pid;
8641 report.uid = app.info.uid;
8642 report.tag = tag;
8643 report.shortMsg = shortMsg;
8644 report.longMsg = longMsg;
Dan Egnorb7f03672009-12-09 16:22:32 -08008645 report.stackTrace = stackTrace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008646
8647 return report;
8648 }
8649
8650 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8651 boolean crashed) {
8652 synchronized (this) {
8653 app.crashing = false;
8654 app.crashingReport = null;
8655 app.notResponding = false;
8656 app.notRespondingReport = null;
8657 if (app.anrDialog == fromDialog) {
8658 app.anrDialog = null;
8659 }
8660 if (app.waitDialog == fromDialog) {
8661 app.waitDialog = null;
8662 }
8663 if (app.pid > 0 && app.pid != MY_PID) {
8664 if (crashed) {
8665 handleAppCrashLocked(app);
8666 }
8667 Log.i(ActivityManagerService.TAG, "Killing process "
8668 + app.processName
8669 + " (pid=" + app.pid + ") at user's request");
8670 Process.killProcess(app.pid);
8671 }
8672
8673 }
8674 }
8675
Dan Egnorb7f03672009-12-09 16:22:32 -08008676 private boolean handleAppCrashLocked(ProcessRecord app) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008677 long now = SystemClock.uptimeMillis();
8678
8679 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8680 app.info.uid);
8681 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8682 // This process loses!
8683 Log.w(TAG, "Process " + app.info.processName
8684 + " has crashed too many times: killing!");
Doug Zongker2bec3d42009-12-04 12:52:44 -08008685 EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008686 app.info.processName, app.info.uid);
8687 killServicesLocked(app, false);
8688 for (int i=mHistory.size()-1; i>=0; i--) {
8689 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8690 if (r.app == app) {
8691 if (Config.LOGD) Log.d(
8692 TAG, " Force finishing activity "
8693 + r.intent.getComponent().flattenToShortString());
8694 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8695 }
8696 }
8697 if (!app.persistent) {
8698 // We don't want to start this process again until the user
8699 // explicitly does so... but for persistent process, we really
8700 // need to keep it running. If a persistent process is actually
8701 // repeatedly crashing, then badness for everyone.
Doug Zongker2bec3d42009-12-04 12:52:44 -08008702 EventLog.writeEvent(EventLogTags.AM_PROC_BAD, app.info.uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008703 app.info.processName);
8704 mBadProcesses.put(app.info.processName, app.info.uid, now);
8705 app.bad = true;
8706 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8707 app.removed = true;
8708 removeProcessLocked(app, false);
8709 return false;
8710 }
8711 }
8712
8713 // Bump up the crash count of any services currently running in the proc.
8714 if (app.services.size() != 0) {
8715 // Any services running in the application need to be placed
8716 // back in the pending list.
8717 Iterator it = app.services.iterator();
8718 while (it.hasNext()) {
8719 ServiceRecord sr = (ServiceRecord)it.next();
8720 sr.crashCount++;
8721 }
8722 }
8723
8724 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8725 return true;
8726 }
8727
8728 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008729 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008730 skipCurrentReceiverLocked(app);
8731 }
8732
8733 void skipCurrentReceiverLocked(ProcessRecord app) {
8734 boolean reschedule = false;
8735 BroadcastRecord r = app.curReceiver;
8736 if (r != null) {
8737 // The current broadcast is waiting for this app's receiver
8738 // to be finished. Looks like that's not going to happen, so
8739 // let the broadcast continue.
8740 logBroadcastReceiverDiscard(r);
8741 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8742 r.resultExtras, r.resultAbort, true);
8743 reschedule = true;
8744 }
8745 r = mPendingBroadcast;
8746 if (r != null && r.curApp == app) {
8747 if (DEBUG_BROADCAST) Log.v(TAG,
8748 "skip & discard pending app " + r);
8749 logBroadcastReceiverDiscard(r);
8750 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8751 r.resultExtras, r.resultAbort, true);
8752 reschedule = true;
8753 }
8754 if (reschedule) {
8755 scheduleBroadcastsLocked();
8756 }
8757 }
8758
Dan Egnorb7f03672009-12-09 16:22:32 -08008759 public void handleApplicationError(IBinder app, String tag,
8760 ApplicationErrorReport.CrashInfo crashInfo) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008761 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008762 ProcessRecord r = null;
Dan Egnorb7f03672009-12-09 16:22:32 -08008763 long timeMillis = System.currentTimeMillis();
8764 String shortMsg = crashInfo.exceptionClassName;
8765 String longMsg = crashInfo.exceptionMessage;
8766 String stackTrace = crashInfo.stackTrace;
8767 if (shortMsg != null && longMsg != null) {
8768 longMsg = shortMsg + ": " + longMsg;
8769 } else if (shortMsg != null) {
8770 longMsg = shortMsg;
8771 }
8772
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008773 synchronized (this) {
8774 if (app != null) {
8775 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8776 final int NA = apps.size();
8777 for (int ia=0; ia<NA; ia++) {
8778 ProcessRecord p = apps.valueAt(ia);
8779 if (p.thread != null && p.thread.asBinder() == app) {
8780 r = p;
8781 break;
8782 }
8783 }
8784 }
8785 }
8786
8787 if (r != null) {
8788 // The application has crashed. Send the SIGQUIT to the process so
8789 // that it can dump its state.
8790 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8791 //Log.i(TAG, "Current system threads:");
8792 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8793 }
8794
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008795 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008796 try {
8797 String name = r != null ? r.processName : null;
8798 int pid = r != null ? r.pid : Binder.getCallingPid();
Dan Egnorb7f03672009-12-09 16:22:32 -08008799 if (!mController.appCrashed(name, pid, tag,
8800 shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008801 Log.w(TAG, "Force-killing crashed app " + name
8802 + " at watcher's request");
8803 Process.killProcess(pid);
Dan Egnorb7f03672009-12-09 16:22:32 -08008804 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008805 }
8806 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008807 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008808 }
8809 }
8810
8811 final long origId = Binder.clearCallingIdentity();
8812
8813 // If this process is running instrumentation, finish it.
8814 if (r != null && r.instrumentationClass != null) {
8815 Log.w(TAG, "Error in app " + r.processName
8816 + " running instrumentation " + r.instrumentationClass + ":");
8817 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8818 if (longMsg != null) Log.w(TAG, " " + longMsg);
8819 Bundle info = new Bundle();
8820 info.putString("shortMsg", shortMsg);
8821 info.putString("longMsg", longMsg);
8822 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8823 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08008824 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008825 }
8826
8827 if (r != null) {
Dan Egnorb7f03672009-12-09 16:22:32 -08008828 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, stackTrace)) {
8829 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008830 }
8831 } else {
8832 Log.w(TAG, "Some application object " + app + " tag " + tag
8833 + " has crashed, but I don't know who it is.");
8834 Log.w(TAG, "ShortMsg:" + shortMsg);
8835 Log.w(TAG, "LongMsg:" + longMsg);
8836 Binder.restoreCallingIdentity(origId);
Dan Egnorb7f03672009-12-09 16:22:32 -08008837 return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008838 }
8839
8840 Message msg = Message.obtain();
8841 msg.what = SHOW_ERROR_MSG;
8842 HashMap data = new HashMap();
8843 data.put("result", result);
8844 data.put("app", r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008845 msg.obj = data;
8846 mHandler.sendMessage(msg);
8847
8848 Binder.restoreCallingIdentity(origId);
8849 }
8850
8851 int res = result.get();
8852
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008853 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008854 synchronized (this) {
8855 if (r != null) {
8856 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8857 SystemClock.uptimeMillis());
8858 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008859 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
Dan Egnorb7f03672009-12-09 16:22:32 -08008860 appErrorIntent = createAppErrorIntentLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008861 }
8862 }
8863
8864 if (appErrorIntent != null) {
8865 try {
8866 mContext.startActivity(appErrorIntent);
8867 } catch (ActivityNotFoundException e) {
8868 Log.w(TAG, "bug report receiver dissappeared", e);
8869 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008870 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008871 }
Dan Egnorb7f03672009-12-09 16:22:32 -08008872
8873 Intent createAppErrorIntentLocked(ProcessRecord r,
8874 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
8875 ApplicationErrorReport report = createAppErrorReportLocked(r, timeMillis, crashInfo);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008876 if (report == null) {
8877 return null;
8878 }
8879 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8880 result.setComponent(r.errorReportReceiver);
8881 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8882 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8883 return result;
8884 }
8885
Dan Egnorb7f03672009-12-09 16:22:32 -08008886 private ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r,
8887 long timeMillis, ApplicationErrorReport.CrashInfo crashInfo) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008888 if (r.errorReportReceiver == null) {
8889 return null;
8890 }
8891
8892 if (!r.crashing && !r.notResponding) {
8893 return null;
8894 }
8895
Dan Egnorb7f03672009-12-09 16:22:32 -08008896 ApplicationErrorReport report = new ApplicationErrorReport();
8897 report.packageName = r.info.packageName;
8898 report.installerPackageName = r.errorReportReceiver.getPackageName();
8899 report.processName = r.processName;
8900 report.time = timeMillis;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008901
Dan Egnorb7f03672009-12-09 16:22:32 -08008902 if (r.crashing) {
8903 report.type = ApplicationErrorReport.TYPE_CRASH;
8904 report.crashInfo = crashInfo;
8905 } else if (r.notResponding) {
8906 report.type = ApplicationErrorReport.TYPE_ANR;
8907 report.anrInfo = new ApplicationErrorReport.AnrInfo();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008908
Dan Egnorb7f03672009-12-09 16:22:32 -08008909 report.anrInfo.activity = r.notRespondingReport.tag;
8910 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8911 report.anrInfo.info = r.notRespondingReport.longMsg;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008912 }
8913
Dan Egnorb7f03672009-12-09 16:22:32 -08008914 return report;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008915 }
8916
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008917 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8918 // assume our apps are happy - lazy create the list
8919 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8920
8921 synchronized (this) {
8922
8923 // iterate across all processes
8924 final int N = mLRUProcesses.size();
8925 for (int i = 0; i < N; i++) {
8926 ProcessRecord app = mLRUProcesses.get(i);
8927 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8928 // This one's in trouble, so we'll generate a report for it
8929 // crashes are higher priority (in case there's a crash *and* an anr)
8930 ActivityManager.ProcessErrorStateInfo report = null;
8931 if (app.crashing) {
8932 report = app.crashingReport;
8933 } else if (app.notResponding) {
8934 report = app.notRespondingReport;
8935 }
8936
8937 if (report != null) {
8938 if (errList == null) {
8939 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8940 }
8941 errList.add(report);
8942 } else {
8943 Log.w(TAG, "Missing app error report, app = " + app.processName +
8944 " crashing = " + app.crashing +
8945 " notResponding = " + app.notResponding);
8946 }
8947 }
8948 }
8949 }
8950
8951 return errList;
8952 }
8953
8954 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8955 // Lazy instantiation of list
8956 List<ActivityManager.RunningAppProcessInfo> runList = null;
8957 synchronized (this) {
8958 // Iterate across all processes
8959 final int N = mLRUProcesses.size();
8960 for (int i = 0; i < N; i++) {
8961 ProcessRecord app = mLRUProcesses.get(i);
8962 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8963 // Generate process state info for running application
8964 ActivityManager.RunningAppProcessInfo currApp =
8965 new ActivityManager.RunningAppProcessInfo(app.processName,
8966 app.pid, app.getPackageList());
Dianne Hackborneb034652009-09-07 00:49:58 -07008967 currApp.uid = app.info.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008968 int adj = app.curAdj;
8969 if (adj >= CONTENT_PROVIDER_ADJ) {
8970 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8971 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8972 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008973 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8974 } else if (adj >= HOME_APP_ADJ) {
8975 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8976 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008977 } else if (adj >= SECONDARY_SERVER_ADJ) {
8978 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8979 } else if (adj >= VISIBLE_APP_ADJ) {
8980 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8981 } else {
8982 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8983 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -07008984 currApp.importanceReasonCode = app.adjTypeCode;
8985 if (app.adjSource instanceof ProcessRecord) {
8986 currApp.importanceReasonPid = ((ProcessRecord)app.adjSource).pid;
8987 } else if (app.adjSource instanceof HistoryRecord) {
8988 HistoryRecord r = (HistoryRecord)app.adjSource;
8989 if (r.app != null) currApp.importanceReasonPid = r.app.pid;
8990 }
8991 if (app.adjTarget instanceof ComponentName) {
8992 currApp.importanceReasonComponent = (ComponentName)app.adjTarget;
8993 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008994 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8995 // + " lru=" + currApp.lru);
8996 if (runList == null) {
8997 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8998 }
8999 runList.add(currApp);
9000 }
9001 }
9002 }
9003 return runList;
9004 }
9005
9006 @Override
9007 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
9008 synchronized (this) {
9009 if (checkCallingPermission(android.Manifest.permission.DUMP)
9010 != PackageManager.PERMISSION_GRANTED) {
9011 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9012 + Binder.getCallingPid()
9013 + ", uid=" + Binder.getCallingUid()
9014 + " without permission "
9015 + android.Manifest.permission.DUMP);
9016 return;
9017 }
9018 if (args.length != 0 && "service".equals(args[0])) {
9019 dumpService(fd, pw, args);
9020 return;
9021 }
9022 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009023 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009024 pw.println(" ");
9025 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009026 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009027 if (mWaitingVisibleActivities.size() > 0) {
9028 pw.println(" ");
9029 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009030 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009031 }
9032 if (mStoppingActivities.size() > 0) {
9033 pw.println(" ");
9034 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009035 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009036 }
9037 if (mFinishingActivities.size() > 0) {
9038 pw.println(" ");
9039 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009040 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009041 }
9042
9043 pw.println(" ");
9044 pw.println(" mPausingActivity: " + mPausingActivity);
9045 pw.println(" mResumedActivity: " + mResumedActivity);
9046 pw.println(" mFocusedActivity: " + mFocusedActivity);
9047 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
9048
9049 if (mRecentTasks.size() > 0) {
9050 pw.println(" ");
9051 pw.println("Recent tasks in Current Activity Manager State:");
9052
9053 final int N = mRecentTasks.size();
9054 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009055 TaskRecord tr = mRecentTasks.get(i);
9056 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
9057 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009058 mRecentTasks.get(i).dump(pw, " ");
9059 }
9060 }
9061
9062 pw.println(" ");
9063 pw.println(" mCurTask: " + mCurTask);
9064
9065 pw.println(" ");
9066 pw.println("Processes in Current Activity Manager State:");
9067
9068 boolean needSep = false;
9069 int numPers = 0;
9070
9071 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
9072 final int NA = procs.size();
9073 for (int ia=0; ia<NA; ia++) {
9074 if (!needSep) {
9075 pw.println(" All known processes:");
9076 needSep = true;
9077 }
9078 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009079 pw.print(r.persistent ? " *PERS*" : " *APP*");
9080 pw.print(" UID "); pw.print(procs.keyAt(ia));
9081 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009082 r.dump(pw, " ");
9083 if (r.persistent) {
9084 numPers++;
9085 }
9086 }
9087 }
9088
9089 if (mLRUProcesses.size() > 0) {
9090 if (needSep) pw.println(" ");
9091 needSep = true;
9092 pw.println(" Running processes (most recent first):");
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009093 dumpProcessList(pw, this, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009094 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009095 needSep = true;
9096 }
9097
9098 synchronized (mPidsSelfLocked) {
9099 if (mPidsSelfLocked.size() > 0) {
9100 if (needSep) pw.println(" ");
9101 needSep = true;
9102 pw.println(" PID mappings:");
9103 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009104 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
9105 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009106 }
9107 }
9108 }
9109
9110 if (mForegroundProcesses.size() > 0) {
9111 if (needSep) pw.println(" ");
9112 needSep = true;
9113 pw.println(" Foreground Processes:");
9114 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009115 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
9116 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009117 }
9118 }
9119
9120 if (mPersistentStartingProcesses.size() > 0) {
9121 if (needSep) pw.println(" ");
9122 needSep = true;
9123 pw.println(" Persisent processes that are starting:");
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009124 dumpProcessList(pw, this, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009125 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009126 }
9127
9128 if (mStartingProcesses.size() > 0) {
9129 if (needSep) pw.println(" ");
9130 needSep = true;
9131 pw.println(" Processes that are starting:");
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009132 dumpProcessList(pw, this, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009133 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009134 }
9135
9136 if (mRemovedProcesses.size() > 0) {
9137 if (needSep) pw.println(" ");
9138 needSep = true;
9139 pw.println(" Processes that are being removed:");
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009140 dumpProcessList(pw, this, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009141 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009142 }
9143
9144 if (mProcessesOnHold.size() > 0) {
9145 if (needSep) pw.println(" ");
9146 needSep = true;
9147 pw.println(" Processes that are on old until the system is ready:");
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009148 dumpProcessList(pw, this, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009149 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009150 }
9151
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009152 if (mProcessesToGc.size() > 0) {
9153 if (needSep) pw.println(" ");
9154 needSep = true;
9155 pw.println(" Processes that are waiting to GC:");
9156 long now = SystemClock.uptimeMillis();
9157 for (int i=0; i<mProcessesToGc.size(); i++) {
9158 ProcessRecord proc = mProcessesToGc.get(i);
9159 pw.print(" Process "); pw.println(proc);
9160 pw.print(" lowMem="); pw.print(proc.reportLowMemory);
9161 pw.print(", last gced=");
9162 pw.print(now-proc.lastRequestedGc);
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -07009163 pw.print(" ms ago, last lowMem=");
Dianne Hackbornfd12af42009-08-27 00:44:33 -07009164 pw.print(now-proc.lastLowMemory);
9165 pw.println(" ms ago");
9166
9167 }
9168 }
9169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009170 if (mProcessCrashTimes.getMap().size() > 0) {
9171 if (needSep) pw.println(" ");
9172 needSep = true;
9173 pw.println(" Time since processes crashed:");
9174 long now = SystemClock.uptimeMillis();
9175 for (Map.Entry<String, SparseArray<Long>> procs
9176 : mProcessCrashTimes.getMap().entrySet()) {
9177 SparseArray<Long> uids = procs.getValue();
9178 final int N = uids.size();
9179 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009180 pw.print(" Process "); pw.print(procs.getKey());
9181 pw.print(" uid "); pw.print(uids.keyAt(i));
9182 pw.print(": last crashed ");
9183 pw.print((now-uids.valueAt(i)));
9184 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009185 }
9186 }
9187 }
9188
9189 if (mBadProcesses.getMap().size() > 0) {
9190 if (needSep) pw.println(" ");
9191 needSep = true;
9192 pw.println(" Bad processes:");
9193 for (Map.Entry<String, SparseArray<Long>> procs
9194 : mBadProcesses.getMap().entrySet()) {
9195 SparseArray<Long> uids = procs.getValue();
9196 final int N = uids.size();
9197 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009198 pw.print(" Bad process "); pw.print(procs.getKey());
9199 pw.print(" uid "); pw.print(uids.keyAt(i));
9200 pw.print(": crashed at time ");
9201 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009202 }
9203 }
9204 }
9205
9206 pw.println(" ");
9207 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08009208 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009209 pw.println(" mConfiguration: " + mConfiguration);
9210 pw.println(" mStartRunning=" + mStartRunning
9211 + " mSystemReady=" + mSystemReady
9212 + " mBooting=" + mBooting
9213 + " mBooted=" + mBooted
9214 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07009215 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009216 pw.println(" mGoingToSleep=" + mGoingToSleep);
9217 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
9218 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
9219 + " mDebugTransient=" + mDebugTransient
9220 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
9221 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07009222 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009223 }
9224 }
9225
9226 /**
9227 * There are three ways to call this:
9228 * - no service specified: dump all the services
9229 * - a flattened component name that matched an existing service was specified as the
9230 * first arg: dump that one service
9231 * - the first arg isn't the flattened component name of an existing service:
9232 * dump all services whose component contains the first arg as a substring
9233 */
9234 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
9235 String[] newArgs;
9236 String componentNameString;
9237 ServiceRecord r;
9238 if (args.length == 1) {
9239 componentNameString = null;
9240 newArgs = EMPTY_STRING_ARRAY;
9241 r = null;
9242 } else {
9243 componentNameString = args[1];
9244 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
9245 r = componentName != null ? mServices.get(componentName) : null;
9246 newArgs = new String[args.length - 2];
9247 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
9248 }
9249
9250 if (r != null) {
9251 dumpService(fd, pw, r, newArgs);
9252 } else {
9253 for (ServiceRecord r1 : mServices.values()) {
9254 if (componentNameString == null
9255 || r1.name.flattenToString().contains(componentNameString)) {
9256 dumpService(fd, pw, r1, newArgs);
9257 }
9258 }
9259 }
9260 }
9261
9262 /**
9263 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
9264 * there is a thread associated with the service.
9265 */
9266 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
9267 pw.println(" Service " + r.name.flattenToString());
9268 if (r.app != null && r.app.thread != null) {
9269 try {
9270 // flush anything that is already in the PrintWriter since the thread is going
9271 // to write to the file descriptor directly
9272 pw.flush();
9273 r.app.thread.dumpService(fd, r, args);
9274 pw.print("\n");
9275 } catch (RemoteException e) {
9276 pw.println("got a RemoteException while dumping the service");
9277 }
9278 }
9279 }
9280
9281 void dumpBroadcasts(PrintWriter pw) {
9282 synchronized (this) {
9283 if (checkCallingPermission(android.Manifest.permission.DUMP)
9284 != PackageManager.PERMISSION_GRANTED) {
9285 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9286 + Binder.getCallingPid()
9287 + ", uid=" + Binder.getCallingUid()
9288 + " without permission "
9289 + android.Manifest.permission.DUMP);
9290 return;
9291 }
9292 pw.println("Broadcasts in Current Activity Manager State:");
9293
9294 if (mRegisteredReceivers.size() > 0) {
9295 pw.println(" ");
9296 pw.println(" Registered Receivers:");
9297 Iterator it = mRegisteredReceivers.values().iterator();
9298 while (it.hasNext()) {
9299 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009300 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009301 r.dump(pw, " ");
9302 }
9303 }
9304
9305 pw.println(" ");
9306 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009307 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009308
9309 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
9310 || mPendingBroadcast != null) {
9311 if (mParallelBroadcasts.size() > 0) {
9312 pw.println(" ");
9313 pw.println(" Active broadcasts:");
9314 }
9315 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
9316 pw.println(" Broadcast #" + i + ":");
9317 mParallelBroadcasts.get(i).dump(pw, " ");
9318 }
9319 if (mOrderedBroadcasts.size() > 0) {
9320 pw.println(" ");
9321 pw.println(" Active serialized broadcasts:");
9322 }
9323 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
9324 pw.println(" Serialized Broadcast #" + i + ":");
9325 mOrderedBroadcasts.get(i).dump(pw, " ");
9326 }
9327 pw.println(" ");
9328 pw.println(" Pending broadcast:");
9329 if (mPendingBroadcast != null) {
9330 mPendingBroadcast.dump(pw, " ");
9331 } else {
9332 pw.println(" (null)");
9333 }
9334 }
9335
9336 pw.println(" ");
Dianne Hackborn12527f92009-11-11 17:39:50 -08009337 pw.println(" Historical broadcasts:");
9338 for (int i=0; i<MAX_BROADCAST_HISTORY; i++) {
9339 BroadcastRecord r = mBroadcastHistory[i];
9340 if (r == null) {
9341 break;
9342 }
9343 pw.println(" Historical Broadcast #" + i + ":");
9344 r.dump(pw, " ");
9345 }
9346
9347 pw.println(" ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009348 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9349 if (mStickyBroadcasts != null) {
9350 pw.println(" ");
9351 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009352 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009353 for (Map.Entry<String, ArrayList<Intent>> ent
9354 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009355 pw.print(" * Sticky action "); pw.print(ent.getKey());
9356 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009357 ArrayList<Intent> intents = ent.getValue();
9358 final int N = intents.size();
9359 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009360 sb.setLength(0);
9361 sb.append(" Intent: ");
9362 intents.get(i).toShortString(sb, true, false);
9363 pw.println(sb.toString());
9364 Bundle bundle = intents.get(i).getExtras();
9365 if (bundle != null) {
9366 pw.print(" ");
9367 pw.println(bundle.toString());
9368 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009369 }
9370 }
9371 }
9372
9373 pw.println(" ");
9374 pw.println(" mHandler:");
9375 mHandler.dump(new PrintWriterPrinter(pw), " ");
9376 }
9377 }
9378
9379 void dumpServices(PrintWriter pw) {
9380 synchronized (this) {
9381 if (checkCallingPermission(android.Manifest.permission.DUMP)
9382 != PackageManager.PERMISSION_GRANTED) {
9383 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9384 + Binder.getCallingPid()
9385 + ", uid=" + Binder.getCallingUid()
9386 + " without permission "
9387 + android.Manifest.permission.DUMP);
9388 return;
9389 }
9390 pw.println("Services in Current Activity Manager State:");
9391
9392 boolean needSep = false;
9393
9394 if (mServices.size() > 0) {
9395 pw.println(" Active services:");
9396 Iterator<ServiceRecord> it = mServices.values().iterator();
9397 while (it.hasNext()) {
9398 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009399 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009400 r.dump(pw, " ");
9401 }
9402 needSep = true;
9403 }
9404
9405 if (mPendingServices.size() > 0) {
9406 if (needSep) pw.println(" ");
9407 pw.println(" Pending services:");
9408 for (int i=0; i<mPendingServices.size(); i++) {
9409 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009410 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009411 r.dump(pw, " ");
9412 }
9413 needSep = true;
9414 }
9415
9416 if (mRestartingServices.size() > 0) {
9417 if (needSep) pw.println(" ");
9418 pw.println(" Restarting services:");
9419 for (int i=0; i<mRestartingServices.size(); i++) {
9420 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009421 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009422 r.dump(pw, " ");
9423 }
9424 needSep = true;
9425 }
9426
9427 if (mStoppingServices.size() > 0) {
9428 if (needSep) pw.println(" ");
9429 pw.println(" Stopping services:");
9430 for (int i=0; i<mStoppingServices.size(); i++) {
9431 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009432 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009433 r.dump(pw, " ");
9434 }
9435 needSep = true;
9436 }
9437
9438 if (mServiceConnections.size() > 0) {
9439 if (needSep) pw.println(" ");
9440 pw.println(" Connection bindings to services:");
9441 Iterator<ConnectionRecord> it
9442 = mServiceConnections.values().iterator();
9443 while (it.hasNext()) {
9444 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009445 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009446 r.dump(pw, " ");
9447 }
9448 }
9449 }
9450 }
9451
9452 void dumpProviders(PrintWriter pw) {
9453 synchronized (this) {
9454 if (checkCallingPermission(android.Manifest.permission.DUMP)
9455 != PackageManager.PERMISSION_GRANTED) {
9456 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9457 + Binder.getCallingPid()
9458 + ", uid=" + Binder.getCallingUid()
9459 + " without permission "
9460 + android.Manifest.permission.DUMP);
9461 return;
9462 }
9463
9464 pw.println("Content Providers in Current Activity Manager State:");
9465
9466 boolean needSep = false;
9467
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009468 if (mProvidersByClass.size() > 0) {
9469 if (needSep) pw.println(" ");
9470 pw.println(" Published content providers (by class):");
9471 Iterator it = mProvidersByClass.entrySet().iterator();
9472 while (it.hasNext()) {
9473 Map.Entry e = (Map.Entry)it.next();
9474 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009475 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009476 r.dump(pw, " ");
9477 }
9478 needSep = true;
9479 }
9480
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009481 if (mProvidersByName.size() > 0) {
9482 pw.println(" ");
9483 pw.println(" Authority to provider mappings:");
9484 Iterator it = mProvidersByName.entrySet().iterator();
9485 while (it.hasNext()) {
9486 Map.Entry e = (Map.Entry)it.next();
9487 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9488 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9489 pw.println(r);
9490 }
9491 needSep = true;
9492 }
9493
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009494 if (mLaunchingProviders.size() > 0) {
9495 if (needSep) pw.println(" ");
9496 pw.println(" Launching content providers:");
9497 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009498 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9499 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009500 }
9501 needSep = true;
9502 }
9503
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009504 if (mGrantedUriPermissions.size() > 0) {
9505 pw.println();
9506 pw.println("Granted Uri Permissions:");
9507 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9508 int uid = mGrantedUriPermissions.keyAt(i);
9509 HashMap<Uri, UriPermission> perms
9510 = mGrantedUriPermissions.valueAt(i);
9511 pw.print(" * UID "); pw.print(uid);
9512 pw.println(" holds:");
9513 for (UriPermission perm : perms.values()) {
9514 pw.print(" "); pw.println(perm);
9515 perm.dump(pw, " ");
9516 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009517 }
9518 }
9519 }
9520 }
9521
9522 void dumpSenders(PrintWriter pw) {
9523 synchronized (this) {
9524 if (checkCallingPermission(android.Manifest.permission.DUMP)
9525 != PackageManager.PERMISSION_GRANTED) {
9526 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9527 + Binder.getCallingPid()
9528 + ", uid=" + Binder.getCallingUid()
9529 + " without permission "
9530 + android.Manifest.permission.DUMP);
9531 return;
9532 }
9533
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009534 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009535
9536 if (this.mIntentSenderRecords.size() > 0) {
9537 Iterator<WeakReference<PendingIntentRecord>> it
9538 = mIntentSenderRecords.values().iterator();
9539 while (it.hasNext()) {
9540 WeakReference<PendingIntentRecord> ref = it.next();
9541 PendingIntentRecord rec = ref != null ? ref.get(): null;
9542 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009543 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009544 rec.dump(pw, " ");
9545 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009546 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009547 }
9548 }
9549 }
9550 }
9551 }
9552
9553 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009554 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009555 TaskRecord lastTask = null;
9556 for (int i=list.size()-1; i>=0; i--) {
9557 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009558 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009559 if (lastTask != r.task) {
9560 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009561 pw.print(prefix);
9562 pw.print(full ? "* " : " ");
9563 pw.println(lastTask);
9564 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009565 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009566 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009567 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009568 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9569 pw.print(" #"); pw.print(i); pw.print(": ");
9570 pw.println(r);
9571 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009572 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009573 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009574 }
9575 }
9576
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009577 private static String buildOomTag(String prefix, String space, int val, int base) {
9578 if (val == base) {
9579 if (space == null) return prefix;
9580 return prefix + " ";
9581 }
9582 return prefix + "+" + Integer.toString(val-base);
9583 }
9584
9585 private static final int dumpProcessList(PrintWriter pw,
9586 ActivityManagerService service, List list,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009587 String prefix, String normalLabel, String persistentLabel,
9588 boolean inclOomAdj) {
9589 int numPers = 0;
9590 for (int i=list.size()-1; i>=0; i--) {
9591 ProcessRecord r = (ProcessRecord)list.get(i);
9592 if (false) {
9593 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9594 + " #" + i + ":");
9595 r.dump(pw, prefix + " ");
9596 } else if (inclOomAdj) {
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009597 String oomAdj;
9598 if (r.setAdj >= EMPTY_APP_ADJ) {
9599 oomAdj = buildOomTag("empty", null, r.setAdj,
9600 EMPTY_APP_ADJ);
9601 } else if (r.setAdj >= CONTENT_PROVIDER_ADJ) {
9602 oomAdj = buildOomTag("cprov", null, r.setAdj,
9603 CONTENT_PROVIDER_ADJ);
9604 } else if (r.setAdj >= HIDDEN_APP_MIN_ADJ) {
9605 oomAdj = buildOomTag("hid", " ", r.setAdj,
9606 HIDDEN_APP_MIN_ADJ);
9607 } else if (r.setAdj >= service.HOME_APP_ADJ) {
9608 oomAdj = buildOomTag("home ", null, r.setAdj,
9609 service.HOME_APP_ADJ);
9610 } else if (r.setAdj >= service.SECONDARY_SERVER_ADJ) {
9611 oomAdj = buildOomTag("svc", " ", r.setAdj,
9612 service.SECONDARY_SERVER_ADJ);
9613 } else if (r.setAdj >= service.BACKUP_APP_ADJ) {
9614 oomAdj = buildOomTag("bckup", null, r.setAdj,
9615 service.BACKUP_APP_ADJ);
9616 } else if (r.setAdj >= service.VISIBLE_APP_ADJ) {
9617 oomAdj = buildOomTag("vis ", null, r.setAdj,
9618 service.VISIBLE_APP_ADJ);
9619 } else if (r.setAdj >= service.FOREGROUND_APP_ADJ) {
9620 oomAdj = buildOomTag("fore ", null, r.setAdj,
9621 service.FOREGROUND_APP_ADJ);
9622 } else if (r.setAdj >= CORE_SERVER_ADJ) {
9623 oomAdj = buildOomTag("core ", null, r.setAdj,
9624 CORE_SERVER_ADJ);
9625 } else if (r.setAdj >= SYSTEM_ADJ) {
9626 oomAdj = buildOomTag("sys ", null, r.setAdj,
9627 SYSTEM_ADJ);
9628 } else {
9629 oomAdj = Integer.toString(r.setAdj);
9630 }
9631 String schedGroup;
9632 switch (r.setSchedGroup) {
9633 case Process.THREAD_GROUP_BG_NONINTERACTIVE:
9634 schedGroup = "B";
9635 break;
9636 case Process.THREAD_GROUP_DEFAULT:
9637 schedGroup = "F";
9638 break;
9639 default:
9640 schedGroup = Integer.toString(r.setSchedGroup);
9641 break;
9642 }
9643 pw.println(String.format("%s%s #%2d: adj=%s/%s %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009644 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborn09c916b2009-12-08 14:50:51 -08009645 i, oomAdj, schedGroup, r.toString(), r.adjType));
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009646 if (r.adjSource != null || r.adjTarget != null) {
9647 pw.println(prefix + " " + r.adjTarget
9648 + " used by " + r.adjSource);
9649 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009650 } else {
9651 pw.println(String.format("%s%s #%2d: %s",
9652 prefix, (r.persistent ? persistentLabel : normalLabel),
9653 i, r.toString()));
9654 }
9655 if (r.persistent) {
9656 numPers++;
9657 }
9658 }
9659 return numPers;
9660 }
9661
9662 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9663 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009664 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009665 long uptime = SystemClock.uptimeMillis();
9666 long realtime = SystemClock.elapsedRealtime();
9667
9668 if (isCheckinRequest) {
9669 // short checkin version
9670 pw.println(uptime + "," + realtime);
9671 pw.flush();
9672 } else {
9673 pw.println("Applications Memory Usage (kB):");
9674 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9675 }
9676 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9677 ProcessRecord r = (ProcessRecord)list.get(i);
9678 if (r.thread != null) {
9679 if (!isCheckinRequest) {
9680 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9681 pw.flush();
9682 }
9683 try {
9684 r.thread.asBinder().dump(fd, args);
9685 } catch (RemoteException e) {
9686 if (!isCheckinRequest) {
9687 pw.println("Got RemoteException!");
9688 pw.flush();
9689 }
9690 }
9691 }
9692 }
9693 }
9694
9695 /**
9696 * Searches array of arguments for the specified string
9697 * @param args array of argument strings
9698 * @param value value to search for
9699 * @return true if the value is contained in the array
9700 */
9701 private static boolean scanArgs(String[] args, String value) {
9702 if (args != null) {
9703 for (String arg : args) {
9704 if (value.equals(arg)) {
9705 return true;
9706 }
9707 }
9708 }
9709 return false;
9710 }
9711
Dianne Hackborn75b03852009-06-12 15:43:26 -07009712 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009713 int count = mHistory.size();
9714
9715 // convert the token to an entry in the history.
9716 HistoryRecord r = null;
9717 int index = -1;
9718 for (int i=count-1; i>=0; i--) {
9719 Object o = mHistory.get(i);
9720 if (o == token) {
9721 r = (HistoryRecord)o;
9722 index = i;
9723 break;
9724 }
9725 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009726
9727 return index;
9728 }
9729
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009730 private final void killServicesLocked(ProcessRecord app,
9731 boolean allowRestart) {
9732 // Report disconnected services.
9733 if (false) {
9734 // XXX we are letting the client link to the service for
9735 // death notifications.
9736 if (app.services.size() > 0) {
9737 Iterator it = app.services.iterator();
9738 while (it.hasNext()) {
9739 ServiceRecord r = (ServiceRecord)it.next();
9740 if (r.connections.size() > 0) {
9741 Iterator<ConnectionRecord> jt
9742 = r.connections.values().iterator();
9743 while (jt.hasNext()) {
9744 ConnectionRecord c = jt.next();
9745 if (c.binding.client != app) {
9746 try {
9747 //c.conn.connected(r.className, null);
9748 } catch (Exception e) {
9749 // todo: this should be asynchronous!
9750 Log.w(TAG, "Exception thrown disconnected servce "
9751 + r.shortName
9752 + " from app " + app.processName, e);
9753 }
9754 }
9755 }
9756 }
9757 }
9758 }
9759 }
9760
9761 // Clean up any connections this application has to other services.
9762 if (app.connections.size() > 0) {
9763 Iterator<ConnectionRecord> it = app.connections.iterator();
9764 while (it.hasNext()) {
9765 ConnectionRecord r = it.next();
9766 removeConnectionLocked(r, app, null);
9767 }
9768 }
9769 app.connections.clear();
9770
9771 if (app.services.size() != 0) {
9772 // Any services running in the application need to be placed
9773 // back in the pending list.
9774 Iterator it = app.services.iterator();
9775 while (it.hasNext()) {
9776 ServiceRecord sr = (ServiceRecord)it.next();
9777 synchronized (sr.stats.getBatteryStats()) {
9778 sr.stats.stopLaunchedLocked();
9779 }
9780 sr.app = null;
9781 sr.executeNesting = 0;
9782 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009783
9784 boolean hasClients = sr.bindings.size() > 0;
9785 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009786 Iterator<IntentBindRecord> bindings
9787 = sr.bindings.values().iterator();
9788 while (bindings.hasNext()) {
9789 IntentBindRecord b = bindings.next();
9790 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9791 + ": shouldUnbind=" + b.hasBound);
9792 b.binder = null;
9793 b.requested = b.received = b.hasBound = false;
9794 }
9795 }
9796
9797 if (sr.crashCount >= 2) {
9798 Log.w(TAG, "Service crashed " + sr.crashCount
9799 + " times, stopping: " + sr);
Doug Zongker2bec3d42009-12-04 12:52:44 -08009800 EventLog.writeEvent(EventLogTags.AM_SERVICE_CRASHED_TOO_MUCH,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009801 sr.crashCount, sr.shortName, app.pid);
9802 bringDownServiceLocked(sr, true);
9803 } else if (!allowRestart) {
9804 bringDownServiceLocked(sr, true);
9805 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009806 boolean canceled = scheduleServiceRestartLocked(sr, true);
9807
9808 // Should the service remain running? Note that in the
9809 // extreme case of so many attempts to deliver a command
9810 // that it failed, that we also will stop it here.
9811 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
9812 if (sr.pendingStarts.size() == 0) {
9813 sr.startRequested = false;
9814 if (!hasClients) {
9815 // Whoops, no reason to restart!
9816 bringDownServiceLocked(sr, true);
9817 }
9818 }
9819 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009820 }
9821 }
9822
9823 if (!allowRestart) {
9824 app.services.clear();
9825 }
9826 }
9827
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009828 // Make sure we have no more records on the stopping list.
9829 int i = mStoppingServices.size();
9830 while (i > 0) {
9831 i--;
9832 ServiceRecord sr = mStoppingServices.get(i);
9833 if (sr.app == app) {
9834 mStoppingServices.remove(i);
9835 }
9836 }
9837
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009838 app.executingServices.clear();
9839 }
9840
9841 private final void removeDyingProviderLocked(ProcessRecord proc,
9842 ContentProviderRecord cpr) {
9843 synchronized (cpr) {
9844 cpr.launchingApp = null;
9845 cpr.notifyAll();
9846 }
9847
9848 mProvidersByClass.remove(cpr.info.name);
9849 String names[] = cpr.info.authority.split(";");
9850 for (int j = 0; j < names.length; j++) {
9851 mProvidersByName.remove(names[j]);
9852 }
9853
9854 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9855 while (cit.hasNext()) {
9856 ProcessRecord capp = cit.next();
9857 if (!capp.persistent && capp.thread != null
9858 && capp.pid != 0
9859 && capp.pid != MY_PID) {
9860 Log.i(TAG, "Killing app " + capp.processName
9861 + " (pid " + capp.pid
9862 + ") because provider " + cpr.info.name
9863 + " is in dying process " + proc.processName);
9864 Process.killProcess(capp.pid);
9865 }
9866 }
9867
9868 mLaunchingProviders.remove(cpr);
9869 }
9870
9871 /**
9872 * Main code for cleaning up a process when it has gone away. This is
9873 * called both as a result of the process dying, or directly when stopping
9874 * a process when running in single process mode.
9875 */
9876 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9877 boolean restarting, int index) {
9878 if (index >= 0) {
9879 mLRUProcesses.remove(index);
9880 }
9881
Dianne Hackborn36124872009-10-08 16:22:03 -07009882 mProcessesToGc.remove(app);
9883
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009884 // Dismiss any open dialogs.
9885 if (app.crashDialog != null) {
9886 app.crashDialog.dismiss();
9887 app.crashDialog = null;
9888 }
9889 if (app.anrDialog != null) {
9890 app.anrDialog.dismiss();
9891 app.anrDialog = null;
9892 }
9893 if (app.waitDialog != null) {
9894 app.waitDialog.dismiss();
9895 app.waitDialog = null;
9896 }
9897
9898 app.crashing = false;
9899 app.notResponding = false;
9900
9901 app.resetPackageList();
9902 app.thread = null;
9903 app.forcingToForeground = null;
9904 app.foregroundServices = false;
9905
9906 killServicesLocked(app, true);
9907
9908 boolean restart = false;
9909
9910 int NL = mLaunchingProviders.size();
9911
9912 // Remove published content providers.
9913 if (!app.pubProviders.isEmpty()) {
9914 Iterator it = app.pubProviders.values().iterator();
9915 while (it.hasNext()) {
9916 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9917 cpr.provider = null;
9918 cpr.app = null;
9919
9920 // See if someone is waiting for this provider... in which
9921 // case we don't remove it, but just let it restart.
9922 int i = 0;
9923 if (!app.bad) {
9924 for (; i<NL; i++) {
9925 if (mLaunchingProviders.get(i) == cpr) {
9926 restart = true;
9927 break;
9928 }
9929 }
9930 } else {
9931 i = NL;
9932 }
9933
9934 if (i >= NL) {
9935 removeDyingProviderLocked(app, cpr);
9936 NL = mLaunchingProviders.size();
9937 }
9938 }
9939 app.pubProviders.clear();
9940 }
9941
Dianne Hackbornf670ef72009-11-16 13:59:16 -08009942 // Take care of any launching providers waiting for this process.
9943 if (checkAppInLaunchingProvidersLocked(app, false)) {
9944 restart = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009945 }
Dianne Hackbornf670ef72009-11-16 13:59:16 -08009946
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009947 // Unregister from connected content providers.
9948 if (!app.conProviders.isEmpty()) {
Dianne Hackborn0c3154d2009-10-06 17:18:05 -07009949 Iterator it = app.conProviders.keySet().iterator();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009950 while (it.hasNext()) {
9951 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9952 cpr.clients.remove(app);
9953 }
9954 app.conProviders.clear();
9955 }
9956
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009957 // At this point there may be remaining entries in mLaunchingProviders
9958 // where we were the only one waiting, so they are no longer of use.
9959 // Look for these and clean up if found.
9960 // XXX Commented out for now. Trying to figure out a way to reproduce
9961 // the actual situation to identify what is actually going on.
9962 if (false) {
9963 for (int i=0; i<NL; i++) {
9964 ContentProviderRecord cpr = (ContentProviderRecord)
9965 mLaunchingProviders.get(i);
9966 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
9967 synchronized (cpr) {
9968 cpr.launchingApp = null;
9969 cpr.notifyAll();
9970 }
9971 }
9972 }
9973 }
9974
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009975 skipCurrentReceiverLocked(app);
9976
9977 // Unregister any receivers.
9978 if (app.receivers.size() > 0) {
9979 Iterator<ReceiverList> it = app.receivers.iterator();
9980 while (it.hasNext()) {
9981 removeReceiverLocked(it.next());
9982 }
9983 app.receivers.clear();
9984 }
9985
Christopher Tate181fafa2009-05-14 11:12:14 -07009986 // If the app is undergoing backup, tell the backup manager about it
9987 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9988 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9989 try {
9990 IBackupManager bm = IBackupManager.Stub.asInterface(
9991 ServiceManager.getService(Context.BACKUP_SERVICE));
9992 bm.agentDisconnected(app.info.packageName);
9993 } catch (RemoteException e) {
9994 // can't happen; backup manager is local
9995 }
9996 }
9997
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009998 // If the caller is restarting this app, then leave it in its
9999 // current lists and let the caller take care of it.
10000 if (restarting) {
10001 return;
10002 }
10003
10004 if (!app.persistent) {
10005 if (DEBUG_PROCESSES) Log.v(TAG,
10006 "Removing non-persistent process during cleanup: " + app);
10007 mProcessNames.remove(app.processName, app.info.uid);
10008 } else if (!app.removed) {
10009 // This app is persistent, so we need to keep its record around.
10010 // If it is not already on the pending app list, add it there
10011 // and start a new process for it.
10012 app.thread = null;
10013 app.forcingToForeground = null;
10014 app.foregroundServices = false;
10015 if (mPersistentStartingProcesses.indexOf(app) < 0) {
10016 mPersistentStartingProcesses.add(app);
10017 restart = true;
10018 }
10019 }
10020 mProcessesOnHold.remove(app);
10021
The Android Open Source Project4df24232009-03-05 14:34:35 -080010022 if (app == mHomeProcess) {
10023 mHomeProcess = null;
10024 }
10025
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010026 if (restart) {
10027 // We have components that still need to be running in the
10028 // process, so re-launch it.
10029 mProcessNames.put(app.processName, app.info.uid, app);
10030 startProcessLocked(app, "restart", app.processName);
10031 } else if (app.pid > 0 && app.pid != MY_PID) {
10032 // Goodbye!
10033 synchronized (mPidsSelfLocked) {
10034 mPidsSelfLocked.remove(app.pid);
10035 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
10036 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -070010037 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010038 }
10039 }
10040
Dianne Hackbornf670ef72009-11-16 13:59:16 -080010041 boolean checkAppInLaunchingProvidersLocked(ProcessRecord app, boolean alwaysBad) {
10042 // Look through the content providers we are waiting to have launched,
10043 // and if any run in this process then either schedule a restart of
10044 // the process or kill the client waiting for it if this process has
10045 // gone bad.
10046 int NL = mLaunchingProviders.size();
10047 boolean restart = false;
10048 for (int i=0; i<NL; i++) {
10049 ContentProviderRecord cpr = (ContentProviderRecord)
10050 mLaunchingProviders.get(i);
10051 if (cpr.launchingApp == app) {
10052 if (!alwaysBad && !app.bad) {
10053 restart = true;
10054 } else {
10055 removeDyingProviderLocked(app, cpr);
10056 NL = mLaunchingProviders.size();
10057 }
10058 }
10059 }
10060 return restart;
10061 }
10062
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010063 // =========================================================
10064 // SERVICES
10065 // =========================================================
10066
10067 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
10068 ActivityManager.RunningServiceInfo info =
10069 new ActivityManager.RunningServiceInfo();
10070 info.service = r.name;
10071 if (r.app != null) {
10072 info.pid = r.app.pid;
10073 }
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010074 info.uid = r.appInfo.uid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010075 info.process = r.processName;
10076 info.foreground = r.isForeground;
10077 info.activeSince = r.createTime;
10078 info.started = r.startRequested;
10079 info.clientCount = r.connections.size();
10080 info.crashCount = r.crashCount;
10081 info.lastActivityTime = r.lastActivity;
Dianne Hackborn3025ef32009-08-31 21:31:47 -070010082 if (r.isForeground) {
10083 info.flags |= ActivityManager.RunningServiceInfo.FLAG_FOREGROUND;
10084 }
10085 if (r.startRequested) {
10086 info.flags |= ActivityManager.RunningServiceInfo.FLAG_STARTED;
10087 }
10088 if (r.app != null && r.app.pid == Process.myPid()) {
10089 info.flags |= ActivityManager.RunningServiceInfo.FLAG_SYSTEM_PROCESS;
10090 }
10091 if (r.app != null && r.app.persistent) {
10092 info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
10093 }
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010094 for (ConnectionRecord conn : r.connections.values()) {
10095 if (conn.clientLabel != 0) {
10096 info.clientPackage = conn.binding.client.info.packageName;
10097 info.clientLabel = conn.clientLabel;
10098 break;
10099 }
10100 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010101 return info;
10102 }
10103
10104 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
10105 int flags) {
10106 synchronized (this) {
10107 ArrayList<ActivityManager.RunningServiceInfo> res
10108 = new ArrayList<ActivityManager.RunningServiceInfo>();
10109
10110 if (mServices.size() > 0) {
10111 Iterator<ServiceRecord> it = mServices.values().iterator();
10112 while (it.hasNext() && res.size() < maxNum) {
10113 res.add(makeRunningServiceInfoLocked(it.next()));
10114 }
10115 }
10116
10117 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
10118 ServiceRecord r = mRestartingServices.get(i);
10119 ActivityManager.RunningServiceInfo info =
10120 makeRunningServiceInfoLocked(r);
10121 info.restarting = r.nextRestartTime;
10122 res.add(info);
10123 }
10124
10125 return res;
10126 }
10127 }
10128
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070010129 public PendingIntent getRunningServiceControlPanel(ComponentName name) {
10130 synchronized (this) {
10131 ServiceRecord r = mServices.get(name);
10132 if (r != null) {
10133 for (ConnectionRecord conn : r.connections.values()) {
10134 if (conn.clientIntent != null) {
10135 return conn.clientIntent;
10136 }
10137 }
10138 }
10139 }
10140 return null;
10141 }
10142
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010143 private final ServiceRecord findServiceLocked(ComponentName name,
10144 IBinder token) {
10145 ServiceRecord r = mServices.get(name);
10146 return r == token ? r : null;
10147 }
10148
10149 private final class ServiceLookupResult {
10150 final ServiceRecord record;
10151 final String permission;
10152
10153 ServiceLookupResult(ServiceRecord _record, String _permission) {
10154 record = _record;
10155 permission = _permission;
10156 }
10157 };
10158
10159 private ServiceLookupResult findServiceLocked(Intent service,
10160 String resolvedType) {
10161 ServiceRecord r = null;
10162 if (service.getComponent() != null) {
10163 r = mServices.get(service.getComponent());
10164 }
10165 if (r == null) {
10166 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10167 r = mServicesByIntent.get(filter);
10168 }
10169
10170 if (r == null) {
10171 try {
10172 ResolveInfo rInfo =
10173 ActivityThread.getPackageManager().resolveService(
10174 service, resolvedType, 0);
10175 ServiceInfo sInfo =
10176 rInfo != null ? rInfo.serviceInfo : null;
10177 if (sInfo == null) {
10178 return null;
10179 }
10180
10181 ComponentName name = new ComponentName(
10182 sInfo.applicationInfo.packageName, sInfo.name);
10183 r = mServices.get(name);
10184 } catch (RemoteException ex) {
10185 // pm is in same process, this will never happen.
10186 }
10187 }
10188 if (r != null) {
10189 int callingPid = Binder.getCallingPid();
10190 int callingUid = Binder.getCallingUid();
10191 if (checkComponentPermission(r.permission,
10192 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10193 != PackageManager.PERMISSION_GRANTED) {
10194 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10195 + " from pid=" + callingPid
10196 + ", uid=" + callingUid
10197 + " requires " + r.permission);
10198 return new ServiceLookupResult(null, r.permission);
10199 }
10200 return new ServiceLookupResult(r, null);
10201 }
10202 return null;
10203 }
10204
10205 private class ServiceRestarter implements Runnable {
10206 private ServiceRecord mService;
10207
10208 void setService(ServiceRecord service) {
10209 mService = service;
10210 }
10211
10212 public void run() {
10213 synchronized(ActivityManagerService.this) {
10214 performServiceRestartLocked(mService);
10215 }
10216 }
10217 }
10218
10219 private ServiceLookupResult retrieveServiceLocked(Intent service,
10220 String resolvedType, int callingPid, int callingUid) {
10221 ServiceRecord r = null;
10222 if (service.getComponent() != null) {
10223 r = mServices.get(service.getComponent());
10224 }
10225 Intent.FilterComparison filter = new Intent.FilterComparison(service);
10226 r = mServicesByIntent.get(filter);
10227 if (r == null) {
10228 try {
10229 ResolveInfo rInfo =
10230 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010231 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010232 ServiceInfo sInfo =
10233 rInfo != null ? rInfo.serviceInfo : null;
10234 if (sInfo == null) {
10235 Log.w(TAG, "Unable to start service " + service +
10236 ": not found");
10237 return null;
10238 }
10239
10240 ComponentName name = new ComponentName(
10241 sInfo.applicationInfo.packageName, sInfo.name);
10242 r = mServices.get(name);
10243 if (r == null) {
10244 filter = new Intent.FilterComparison(service.cloneFilter());
10245 ServiceRestarter res = new ServiceRestarter();
10246 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10247 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10248 synchronized (stats) {
10249 ss = stats.getServiceStatsLocked(
10250 sInfo.applicationInfo.uid, sInfo.packageName,
10251 sInfo.name);
10252 }
10253 r = new ServiceRecord(ss, name, filter, sInfo, res);
10254 res.setService(r);
10255 mServices.put(name, r);
10256 mServicesByIntent.put(filter, r);
10257
10258 // Make sure this component isn't in the pending list.
10259 int N = mPendingServices.size();
10260 for (int i=0; i<N; i++) {
10261 ServiceRecord pr = mPendingServices.get(i);
10262 if (pr.name.equals(name)) {
10263 mPendingServices.remove(i);
10264 i--;
10265 N--;
10266 }
10267 }
10268 }
10269 } catch (RemoteException ex) {
10270 // pm is in same process, this will never happen.
10271 }
10272 }
10273 if (r != null) {
10274 if (checkComponentPermission(r.permission,
10275 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
10276 != PackageManager.PERMISSION_GRANTED) {
10277 Log.w(TAG, "Permission Denial: Accessing service " + r.name
10278 + " from pid=" + Binder.getCallingPid()
10279 + ", uid=" + Binder.getCallingUid()
10280 + " requires " + r.permission);
10281 return new ServiceLookupResult(null, r.permission);
10282 }
10283 return new ServiceLookupResult(r, null);
10284 }
10285 return null;
10286 }
10287
10288 private final void bumpServiceExecutingLocked(ServiceRecord r) {
10289 long now = SystemClock.uptimeMillis();
10290 if (r.executeNesting == 0 && r.app != null) {
10291 if (r.app.executingServices.size() == 0) {
10292 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10293 msg.obj = r.app;
10294 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
10295 }
10296 r.app.executingServices.add(r);
10297 }
10298 r.executeNesting++;
10299 r.executingStart = now;
10300 }
10301
10302 private final void sendServiceArgsLocked(ServiceRecord r,
10303 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010304 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010305 if (N == 0) {
10306 return;
10307 }
10308
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010309 int i = 0;
10310 while (i < N) {
10311 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010312 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010313 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010314 + r.name + " " + r.intent + " args=" + si.intent);
Dianne Hackbornfed534e2009-09-23 00:42:12 -070010315 if (si.intent == null && N > 1) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010316 // If somehow we got a dummy start at the front, then
10317 // just drop it here.
10318 i++;
10319 continue;
10320 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010321 bumpServiceExecutingLocked(r);
10322 if (!oomAdjusted) {
10323 oomAdjusted = true;
10324 updateOomAdjLocked(r.app);
10325 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010326 int flags = 0;
10327 if (si.deliveryCount > 0) {
10328 flags |= Service.START_FLAG_RETRY;
10329 }
10330 if (si.doneExecutingCount > 0) {
10331 flags |= Service.START_FLAG_REDELIVERY;
10332 }
10333 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
10334 si.deliveredTime = SystemClock.uptimeMillis();
10335 r.deliveredStarts.add(si);
10336 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010337 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010338 } catch (RemoteException e) {
10339 // Remote process gone... we'll let the normal cleanup take
10340 // care of this.
10341 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010342 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010343 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010344 break;
10345 }
10346 }
10347 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010348 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010349 } else {
10350 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010351 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010352 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010353 }
10354 }
10355 }
10356
10357 private final boolean requestServiceBindingLocked(ServiceRecord r,
10358 IntentBindRecord i, boolean rebind) {
10359 if (r.app == null || r.app.thread == null) {
10360 // If service is not currently running, can't yet bind.
10361 return false;
10362 }
10363 if ((!i.requested || rebind) && i.apps.size() > 0) {
10364 try {
10365 bumpServiceExecutingLocked(r);
10366 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
10367 + ": shouldUnbind=" + i.hasBound);
10368 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
10369 if (!rebind) {
10370 i.requested = true;
10371 }
10372 i.hasBound = true;
10373 i.doRebind = false;
10374 } catch (RemoteException e) {
10375 return false;
10376 }
10377 }
10378 return true;
10379 }
10380
10381 private final void requestServiceBindingsLocked(ServiceRecord r) {
10382 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
10383 while (bindings.hasNext()) {
10384 IntentBindRecord i = bindings.next();
10385 if (!requestServiceBindingLocked(r, i, false)) {
10386 break;
10387 }
10388 }
10389 }
10390
10391 private final void realStartServiceLocked(ServiceRecord r,
10392 ProcessRecord app) throws RemoteException {
10393 if (app.thread == null) {
10394 throw new RemoteException();
10395 }
10396
10397 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -070010398 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010399
10400 app.services.add(r);
10401 bumpServiceExecutingLocked(r);
10402 updateLRUListLocked(app, true);
10403
10404 boolean created = false;
10405 try {
10406 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
10407 + r.name + " " + r.intent);
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010408 mStringBuilder.setLength(0);
10409 r.intent.getIntent().toShortString(mStringBuilder, false, true);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010410 EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010411 System.identityHashCode(r), r.shortName,
Dianne Hackborna33e3f72009-09-29 17:28:24 -070010412 mStringBuilder.toString(), r.app.pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010413 synchronized (r.stats.getBatteryStats()) {
10414 r.stats.startLaunchedLocked();
10415 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070010416 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010417 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010418 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010419 created = true;
10420 } finally {
10421 if (!created) {
10422 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010423 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010424 }
10425 }
10426
10427 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010428
10429 // If the service is in the started state, and there are no
10430 // pending arguments, then fake up one so its onStartCommand() will
10431 // be called.
10432 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
10433 r.lastStartId++;
10434 if (r.lastStartId < 1) {
10435 r.lastStartId = 1;
10436 }
10437 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
10438 }
10439
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010440 sendServiceArgsLocked(r, true);
10441 }
10442
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010443 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10444 boolean allowCancel) {
10445 boolean canceled = false;
10446
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010447 final long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010448 long minDuration = SERVICE_RESTART_DURATION;
Dianne Hackborn6ccd2af2009-08-27 12:26:44 -070010449 long resetTime = SERVICE_RESET_RUN_DURATION;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010450
10451 // Any delivered but not yet finished starts should be put back
10452 // on the pending list.
10453 final int N = r.deliveredStarts.size();
10454 if (N > 0) {
10455 for (int i=N-1; i>=0; i--) {
10456 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10457 if (si.intent == null) {
10458 // We'll generate this again if needed.
10459 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10460 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10461 r.pendingStarts.add(0, si);
10462 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10463 dur *= 2;
10464 if (minDuration < dur) minDuration = dur;
10465 if (resetTime < dur) resetTime = dur;
10466 } else {
10467 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10468 + r.name);
10469 canceled = true;
10470 }
10471 }
10472 r.deliveredStarts.clear();
10473 }
10474
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010475 r.totalRestartCount++;
10476 if (r.restartDelay == 0) {
10477 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010478 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010479 } else {
10480 // If it has been a "reasonably long time" since the service
10481 // was started, then reset our restart duration back to
10482 // the beginning, so we don't infinitely increase the duration
10483 // on a service that just occasionally gets killed (which is
10484 // a normal case, due to process being killed to reclaim memory).
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010485 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010486 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010487 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010488 } else {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010489 r.restartDelay *= SERVICE_RESTART_DURATION_FACTOR;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010490 if (r.restartDelay < minDuration) {
10491 r.restartDelay = minDuration;
10492 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010493 }
10494 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010495
10496 r.nextRestartTime = now + r.restartDelay;
10497
10498 // Make sure that we don't end up restarting a bunch of services
10499 // all at the same time.
10500 boolean repeat;
10501 do {
10502 repeat = false;
10503 for (int i=mRestartingServices.size()-1; i>=0; i--) {
10504 ServiceRecord r2 = mRestartingServices.get(i);
10505 if (r2 != r && r.nextRestartTime
10506 >= (r2.nextRestartTime-SERVICE_MIN_RESTART_TIME_BETWEEN)
10507 && r.nextRestartTime
10508 < (r2.nextRestartTime+SERVICE_MIN_RESTART_TIME_BETWEEN)) {
10509 r.nextRestartTime = r2.nextRestartTime + SERVICE_MIN_RESTART_TIME_BETWEEN;
10510 r.restartDelay = r.nextRestartTime - now;
10511 repeat = true;
10512 break;
10513 }
10514 }
10515 } while (repeat);
10516
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010517 if (!mRestartingServices.contains(r)) {
10518 mRestartingServices.add(r);
10519 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010520
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010521 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010522
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010523 mHandler.removeCallbacks(r.restarter);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070010524 mHandler.postAtTime(r.restarter, r.nextRestartTime);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010525 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10526 Log.w(TAG, "Scheduling restart of crashed service "
10527 + r.shortName + " in " + r.restartDelay + "ms");
Doug Zongker2bec3d42009-12-04 12:52:44 -080010528 EventLog.writeEvent(EventLogTags.AM_SCHEDULE_SERVICE_RESTART,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010529 r.shortName, r.restartDelay);
10530
10531 Message msg = Message.obtain();
10532 msg.what = SERVICE_ERROR_MSG;
10533 msg.obj = r;
10534 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010535
10536 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010537 }
10538
10539 final void performServiceRestartLocked(ServiceRecord r) {
10540 if (!mRestartingServices.contains(r)) {
10541 return;
10542 }
10543 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10544 }
10545
10546 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10547 if (r.restartDelay == 0) {
10548 return false;
10549 }
10550 r.resetRestartCounter();
10551 mRestartingServices.remove(r);
10552 mHandler.removeCallbacks(r.restarter);
10553 return true;
10554 }
10555
10556 private final boolean bringUpServiceLocked(ServiceRecord r,
10557 int intentFlags, boolean whileRestarting) {
10558 //Log.i(TAG, "Bring up service:");
10559 //r.dump(" ");
10560
Dianne Hackborn36124872009-10-08 16:22:03 -070010561 if (r.app != null && r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010562 sendServiceArgsLocked(r, false);
10563 return true;
10564 }
10565
10566 if (!whileRestarting && r.restartDelay > 0) {
10567 // If waiting for a restart, then do nothing.
10568 return true;
10569 }
10570
10571 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10572 + " " + r.intent);
10573
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010574 // We are now bringing the service up, so no longer in the
10575 // restarting state.
10576 mRestartingServices.remove(r);
10577
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010578 final String appName = r.processName;
10579 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10580 if (app != null && app.thread != null) {
10581 try {
10582 realStartServiceLocked(r, app);
10583 return true;
10584 } catch (RemoteException e) {
10585 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10586 }
10587
10588 // If a dead object exception was thrown -- fall through to
10589 // restart the application.
10590 }
10591
Dianne Hackborn36124872009-10-08 16:22:03 -070010592 // Not running -- get it started, and enqueue this service record
10593 // to be executed when the app comes up.
10594 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
10595 "service", r.name, false) == null) {
10596 Log.w(TAG, "Unable to launch app "
10597 + r.appInfo.packageName + "/"
10598 + r.appInfo.uid + " for service "
10599 + r.intent.getIntent() + ": process is bad");
10600 bringDownServiceLocked(r, true);
10601 return false;
10602 }
10603
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010604 if (!mPendingServices.contains(r)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010605 mPendingServices.add(r);
10606 }
Dianne Hackborn36124872009-10-08 16:22:03 -070010607
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010608 return true;
10609 }
10610
10611 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10612 //Log.i(TAG, "Bring down service:");
10613 //r.dump(" ");
10614
10615 // Does it still need to run?
10616 if (!force && r.startRequested) {
10617 return;
10618 }
10619 if (r.connections.size() > 0) {
10620 if (!force) {
10621 // XXX should probably keep a count of the number of auto-create
10622 // connections directly in the service.
10623 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10624 while (it.hasNext()) {
10625 ConnectionRecord cr = it.next();
10626 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10627 return;
10628 }
10629 }
10630 }
10631
10632 // Report to all of the connections that the service is no longer
10633 // available.
10634 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10635 while (it.hasNext()) {
10636 ConnectionRecord c = it.next();
10637 try {
10638 // todo: shouldn't be a synchronous call!
10639 c.conn.connected(r.name, null);
10640 } catch (Exception e) {
10641 Log.w(TAG, "Failure disconnecting service " + r.name +
10642 " to connection " + c.conn.asBinder() +
10643 " (in " + c.binding.client.processName + ")", e);
10644 }
10645 }
10646 }
10647
10648 // Tell the service that it has been unbound.
10649 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10650 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10651 while (it.hasNext()) {
10652 IntentBindRecord ibr = it.next();
10653 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10654 + ": hasBound=" + ibr.hasBound);
10655 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10656 try {
10657 bumpServiceExecutingLocked(r);
10658 updateOomAdjLocked(r.app);
10659 ibr.hasBound = false;
10660 r.app.thread.scheduleUnbindService(r,
10661 ibr.intent.getIntent());
10662 } catch (Exception e) {
10663 Log.w(TAG, "Exception when unbinding service "
10664 + r.shortName, e);
10665 serviceDoneExecutingLocked(r, true);
10666 }
10667 }
10668 }
10669 }
10670
10671 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10672 + " " + r.intent);
Doug Zongker2bec3d42009-12-04 12:52:44 -080010673 EventLog.writeEvent(EventLogTags.AM_DESTROY_SERVICE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010674 System.identityHashCode(r), r.shortName,
10675 (r.app != null) ? r.app.pid : -1);
10676
10677 mServices.remove(r.name);
10678 mServicesByIntent.remove(r.intent);
10679 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10680 r.totalRestartCount = 0;
10681 unscheduleServiceRestartLocked(r);
10682
10683 // Also make sure it is not on the pending list.
10684 int N = mPendingServices.size();
10685 for (int i=0; i<N; i++) {
10686 if (mPendingServices.get(i) == r) {
10687 mPendingServices.remove(i);
10688 if (DEBUG_SERVICE) Log.v(
10689 TAG, "Removed pending service: " + r.shortName);
10690 i--;
10691 N--;
10692 }
10693 }
10694
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010695 r.cancelNotification();
10696 r.isForeground = false;
10697 r.foregroundId = 0;
10698 r.foregroundNoti = null;
10699
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010700 // Clear start entries.
10701 r.deliveredStarts.clear();
10702 r.pendingStarts.clear();
10703
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010704 if (r.app != null) {
10705 synchronized (r.stats.getBatteryStats()) {
10706 r.stats.stopLaunchedLocked();
10707 }
10708 r.app.services.remove(r);
10709 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010710 try {
Dianne Hackborna1e989b2009-09-01 19:54:29 -070010711 if (DEBUG_SERVICE) Log.v(TAG,
10712 "Stopping service: " + r.shortName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010713 bumpServiceExecutingLocked(r);
10714 mStoppingServices.add(r);
10715 updateOomAdjLocked(r.app);
10716 r.app.thread.scheduleStopService(r);
10717 } catch (Exception e) {
10718 Log.w(TAG, "Exception when stopping service "
10719 + r.shortName, e);
10720 serviceDoneExecutingLocked(r, true);
10721 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010722 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010723 } else {
10724 if (DEBUG_SERVICE) Log.v(
10725 TAG, "Removed service that has no process: " + r.shortName);
10726 }
10727 } else {
10728 if (DEBUG_SERVICE) Log.v(
10729 TAG, "Removed service that is not running: " + r.shortName);
10730 }
10731 }
10732
10733 ComponentName startServiceLocked(IApplicationThread caller,
10734 Intent service, String resolvedType,
10735 int callingPid, int callingUid) {
10736 synchronized(this) {
10737 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10738 + " type=" + resolvedType + " args=" + service.getExtras());
10739
10740 if (caller != null) {
10741 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10742 if (callerApp == null) {
10743 throw new SecurityException(
10744 "Unable to find app for caller " + caller
10745 + " (pid=" + Binder.getCallingPid()
10746 + ") when starting service " + service);
10747 }
10748 }
10749
10750 ServiceLookupResult res =
10751 retrieveServiceLocked(service, resolvedType,
10752 callingPid, callingUid);
10753 if (res == null) {
10754 return null;
10755 }
10756 if (res.record == null) {
10757 return new ComponentName("!", res.permission != null
10758 ? res.permission : "private to package");
10759 }
10760 ServiceRecord r = res.record;
10761 if (unscheduleServiceRestartLocked(r)) {
10762 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10763 + r.shortName);
10764 }
10765 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010766 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010767 r.lastStartId++;
10768 if (r.lastStartId < 1) {
10769 r.lastStartId = 1;
10770 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010771 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010772 r.lastActivity = SystemClock.uptimeMillis();
10773 synchronized (r.stats.getBatteryStats()) {
10774 r.stats.startRunningLocked();
10775 }
10776 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10777 return new ComponentName("!", "Service process is bad");
10778 }
10779 return r.name;
10780 }
10781 }
10782
10783 public ComponentName startService(IApplicationThread caller, Intent service,
10784 String resolvedType) {
10785 // Refuse possible leaked file descriptors
10786 if (service != null && service.hasFileDescriptors() == true) {
10787 throw new IllegalArgumentException("File descriptors passed in Intent");
10788 }
10789
10790 synchronized(this) {
10791 final int callingPid = Binder.getCallingPid();
10792 final int callingUid = Binder.getCallingUid();
10793 final long origId = Binder.clearCallingIdentity();
10794 ComponentName res = startServiceLocked(caller, service,
10795 resolvedType, callingPid, callingUid);
10796 Binder.restoreCallingIdentity(origId);
10797 return res;
10798 }
10799 }
10800
10801 ComponentName startServiceInPackage(int uid,
10802 Intent service, String resolvedType) {
10803 synchronized(this) {
10804 final long origId = Binder.clearCallingIdentity();
10805 ComponentName res = startServiceLocked(null, service,
10806 resolvedType, -1, uid);
10807 Binder.restoreCallingIdentity(origId);
10808 return res;
10809 }
10810 }
10811
10812 public int stopService(IApplicationThread caller, Intent service,
10813 String resolvedType) {
10814 // Refuse possible leaked file descriptors
10815 if (service != null && service.hasFileDescriptors() == true) {
10816 throw new IllegalArgumentException("File descriptors passed in Intent");
10817 }
10818
10819 synchronized(this) {
10820 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10821 + " type=" + resolvedType);
10822
10823 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10824 if (caller != null && callerApp == null) {
10825 throw new SecurityException(
10826 "Unable to find app for caller " + caller
10827 + " (pid=" + Binder.getCallingPid()
10828 + ") when stopping service " + service);
10829 }
10830
10831 // If this service is active, make sure it is stopped.
10832 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10833 if (r != null) {
10834 if (r.record != null) {
10835 synchronized (r.record.stats.getBatteryStats()) {
10836 r.record.stats.stopRunningLocked();
10837 }
10838 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010839 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010840 final long origId = Binder.clearCallingIdentity();
10841 bringDownServiceLocked(r.record, false);
10842 Binder.restoreCallingIdentity(origId);
10843 return 1;
10844 }
10845 return -1;
10846 }
10847 }
10848
10849 return 0;
10850 }
10851
10852 public IBinder peekService(Intent service, String resolvedType) {
10853 // Refuse possible leaked file descriptors
10854 if (service != null && service.hasFileDescriptors() == true) {
10855 throw new IllegalArgumentException("File descriptors passed in Intent");
10856 }
10857
10858 IBinder ret = null;
10859
10860 synchronized(this) {
10861 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10862
10863 if (r != null) {
10864 // r.record is null if findServiceLocked() failed the caller permission check
10865 if (r.record == null) {
10866 throw new SecurityException(
10867 "Permission Denial: Accessing service " + r.record.name
10868 + " from pid=" + Binder.getCallingPid()
10869 + ", uid=" + Binder.getCallingUid()
10870 + " requires " + r.permission);
10871 }
10872 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10873 if (ib != null) {
10874 ret = ib.binder;
10875 }
10876 }
10877 }
10878
10879 return ret;
10880 }
10881
10882 public boolean stopServiceToken(ComponentName className, IBinder token,
10883 int startId) {
10884 synchronized(this) {
10885 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10886 + " " + token + " startId=" + startId);
10887 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010888 if (r != null) {
10889 if (startId >= 0) {
10890 // Asked to only stop if done with all work. Note that
10891 // to avoid leaks, we will take this as dropping all
10892 // start items up to and including this one.
10893 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
10894 if (si != null) {
10895 while (r.deliveredStarts.size() > 0) {
10896 if (r.deliveredStarts.remove(0) == si) {
10897 break;
10898 }
10899 }
10900 }
10901
10902 if (r.lastStartId != startId) {
10903 return false;
10904 }
10905
10906 if (r.deliveredStarts.size() > 0) {
10907 Log.w(TAG, "stopServiceToken startId " + startId
10908 + " is last, but have " + r.deliveredStarts.size()
10909 + " remaining args");
10910 }
10911 }
10912
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010913 synchronized (r.stats.getBatteryStats()) {
10914 r.stats.stopRunningLocked();
10915 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010916 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010917 }
10918 final long origId = Binder.clearCallingIdentity();
10919 bringDownServiceLocked(r, false);
10920 Binder.restoreCallingIdentity(origId);
10921 return true;
10922 }
10923 }
10924 return false;
10925 }
10926
10927 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010928 int id, Notification notification, boolean removeNotification) {
10929 final long origId = Binder.clearCallingIdentity();
10930 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010931 synchronized(this) {
10932 ServiceRecord r = findServiceLocked(className, token);
10933 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010934 if (id != 0) {
10935 if (notification == null) {
10936 throw new IllegalArgumentException("null notification");
10937 }
10938 if (r.foregroundId != id) {
10939 r.cancelNotification();
10940 r.foregroundId = id;
10941 }
10942 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
10943 r.foregroundNoti = notification;
10944 r.isForeground = true;
10945 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010946 if (r.app != null) {
10947 updateServiceForegroundLocked(r.app, true);
10948 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010949 } else {
10950 if (r.isForeground) {
10951 r.isForeground = false;
10952 if (r.app != null) {
10953 updateServiceForegroundLocked(r.app, true);
10954 }
10955 }
10956 if (removeNotification) {
10957 r.cancelNotification();
10958 r.foregroundId = 0;
10959 r.foregroundNoti = null;
10960 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010961 }
10962 }
10963 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010964 } finally {
10965 Binder.restoreCallingIdentity(origId);
10966 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010967 }
10968
10969 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10970 boolean anyForeground = false;
10971 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10972 if (sr.isForeground) {
10973 anyForeground = true;
10974 break;
10975 }
10976 }
10977 if (anyForeground != proc.foregroundServices) {
10978 proc.foregroundServices = anyForeground;
10979 if (oomAdj) {
10980 updateOomAdjLocked();
10981 }
10982 }
10983 }
10984
10985 public int bindService(IApplicationThread caller, IBinder token,
10986 Intent service, String resolvedType,
10987 IServiceConnection connection, int flags) {
10988 // Refuse possible leaked file descriptors
10989 if (service != null && service.hasFileDescriptors() == true) {
10990 throw new IllegalArgumentException("File descriptors passed in Intent");
10991 }
10992
10993 synchronized(this) {
10994 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10995 + " type=" + resolvedType + " conn=" + connection.asBinder()
10996 + " flags=0x" + Integer.toHexString(flags));
10997 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10998 if (callerApp == null) {
10999 throw new SecurityException(
11000 "Unable to find app for caller " + caller
11001 + " (pid=" + Binder.getCallingPid()
11002 + ") when binding service " + service);
11003 }
11004
11005 HistoryRecord activity = null;
11006 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070011007 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011008 if (aindex < 0) {
11009 Log.w(TAG, "Binding with unknown activity: " + token);
11010 return 0;
11011 }
11012 activity = (HistoryRecord)mHistory.get(aindex);
11013 }
11014
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011015 int clientLabel = 0;
11016 PendingIntent clientIntent = null;
11017
11018 if (callerApp.info.uid == Process.SYSTEM_UID) {
11019 // Hacky kind of thing -- allow system stuff to tell us
11020 // what they are, so we can report this elsewhere for
11021 // others to know why certain services are running.
11022 try {
11023 clientIntent = (PendingIntent)service.getParcelableExtra(
11024 Intent.EXTRA_CLIENT_INTENT);
11025 } catch (RuntimeException e) {
11026 }
11027 if (clientIntent != null) {
11028 clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
11029 if (clientLabel != 0) {
11030 // There are no useful extras in the intent, trash them.
11031 // System code calling with this stuff just needs to know
11032 // this will happen.
11033 service = service.cloneFilter();
11034 }
11035 }
11036 }
11037
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011038 ServiceLookupResult res =
11039 retrieveServiceLocked(service, resolvedType,
11040 Binder.getCallingPid(), Binder.getCallingUid());
11041 if (res == null) {
11042 return 0;
11043 }
11044 if (res.record == null) {
11045 return -1;
11046 }
11047 ServiceRecord s = res.record;
11048
11049 final long origId = Binder.clearCallingIdentity();
11050
11051 if (unscheduleServiceRestartLocked(s)) {
11052 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
11053 + s.shortName);
11054 }
11055
11056 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
11057 ConnectionRecord c = new ConnectionRecord(b, activity,
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070011058 connection, flags, clientLabel, clientIntent);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011059
11060 IBinder binder = connection.asBinder();
11061 s.connections.put(binder, c);
11062 b.connections.add(c);
11063 if (activity != null) {
11064 if (activity.connections == null) {
11065 activity.connections = new HashSet<ConnectionRecord>();
11066 }
11067 activity.connections.add(c);
11068 }
11069 b.client.connections.add(c);
11070 mServiceConnections.put(binder, c);
11071
11072 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
11073 s.lastActivity = SystemClock.uptimeMillis();
11074 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
11075 return 0;
11076 }
11077 }
11078
11079 if (s.app != null) {
11080 // This could have made the service more important.
11081 updateOomAdjLocked(s.app);
11082 }
11083
11084 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
11085 + ": received=" + b.intent.received
11086 + " apps=" + b.intent.apps.size()
11087 + " doRebind=" + b.intent.doRebind);
11088
11089 if (s.app != null && b.intent.received) {
11090 // Service is already running, so we can immediately
11091 // publish the connection.
11092 try {
11093 c.conn.connected(s.name, b.intent.binder);
11094 } catch (Exception e) {
11095 Log.w(TAG, "Failure sending service " + s.shortName
11096 + " to connection " + c.conn.asBinder()
11097 + " (in " + c.binding.client.processName + ")", e);
11098 }
11099
11100 // If this is the first app connected back to this binding,
11101 // and the service had previously asked to be told when
11102 // rebound, then do so.
11103 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
11104 requestServiceBindingLocked(s, b.intent, true);
11105 }
11106 } else if (!b.intent.requested) {
11107 requestServiceBindingLocked(s, b.intent, false);
11108 }
11109
11110 Binder.restoreCallingIdentity(origId);
11111 }
11112
11113 return 1;
11114 }
11115
11116 private void removeConnectionLocked(
11117 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
11118 IBinder binder = c.conn.asBinder();
11119 AppBindRecord b = c.binding;
11120 ServiceRecord s = b.service;
11121 s.connections.remove(binder);
11122 b.connections.remove(c);
11123 if (c.activity != null && c.activity != skipAct) {
11124 if (c.activity.connections != null) {
11125 c.activity.connections.remove(c);
11126 }
11127 }
11128 if (b.client != skipApp) {
11129 b.client.connections.remove(c);
11130 }
11131 mServiceConnections.remove(binder);
11132
11133 if (b.connections.size() == 0) {
11134 b.intent.apps.remove(b.client);
11135 }
11136
11137 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
11138 + ": shouldUnbind=" + b.intent.hasBound);
11139 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
11140 && b.intent.hasBound) {
11141 try {
11142 bumpServiceExecutingLocked(s);
11143 updateOomAdjLocked(s.app);
11144 b.intent.hasBound = false;
11145 // Assume the client doesn't want to know about a rebind;
11146 // we will deal with that later if it asks for one.
11147 b.intent.doRebind = false;
11148 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
11149 } catch (Exception e) {
11150 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
11151 serviceDoneExecutingLocked(s, true);
11152 }
11153 }
11154
11155 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
11156 bringDownServiceLocked(s, false);
11157 }
11158 }
11159
11160 public boolean unbindService(IServiceConnection connection) {
11161 synchronized (this) {
11162 IBinder binder = connection.asBinder();
11163 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
11164 ConnectionRecord r = mServiceConnections.get(binder);
11165 if (r == null) {
11166 Log.w(TAG, "Unbind failed: could not find connection for "
11167 + connection.asBinder());
11168 return false;
11169 }
11170
11171 final long origId = Binder.clearCallingIdentity();
11172
11173 removeConnectionLocked(r, null, null);
11174
11175 if (r.binding.service.app != null) {
11176 // This could have made the service less important.
11177 updateOomAdjLocked(r.binding.service.app);
11178 }
11179
11180 Binder.restoreCallingIdentity(origId);
11181 }
11182
11183 return true;
11184 }
11185
11186 public void publishService(IBinder token, Intent intent, IBinder service) {
11187 // Refuse possible leaked file descriptors
11188 if (intent != null && intent.hasFileDescriptors() == true) {
11189 throw new IllegalArgumentException("File descriptors passed in Intent");
11190 }
11191
11192 synchronized(this) {
11193 if (!(token instanceof ServiceRecord)) {
11194 throw new IllegalArgumentException("Invalid service token");
11195 }
11196 ServiceRecord r = (ServiceRecord)token;
11197
11198 final long origId = Binder.clearCallingIdentity();
11199
11200 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
11201 + " " + intent + ": " + service);
11202 if (r != null) {
11203 Intent.FilterComparison filter
11204 = new Intent.FilterComparison(intent);
11205 IntentBindRecord b = r.bindings.get(filter);
11206 if (b != null && !b.received) {
11207 b.binder = service;
11208 b.requested = true;
11209 b.received = true;
11210 if (r.connections.size() > 0) {
11211 Iterator<ConnectionRecord> it
11212 = r.connections.values().iterator();
11213 while (it.hasNext()) {
11214 ConnectionRecord c = it.next();
11215 if (!filter.equals(c.binding.intent.intent)) {
11216 if (DEBUG_SERVICE) Log.v(
11217 TAG, "Not publishing to: " + c);
11218 if (DEBUG_SERVICE) Log.v(
11219 TAG, "Bound intent: " + c.binding.intent.intent);
11220 if (DEBUG_SERVICE) Log.v(
11221 TAG, "Published intent: " + intent);
11222 continue;
11223 }
11224 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
11225 try {
11226 c.conn.connected(r.name, service);
11227 } catch (Exception e) {
11228 Log.w(TAG, "Failure sending service " + r.name +
11229 " to connection " + c.conn.asBinder() +
11230 " (in " + c.binding.client.processName + ")", e);
11231 }
11232 }
11233 }
11234 }
11235
11236 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11237
11238 Binder.restoreCallingIdentity(origId);
11239 }
11240 }
11241 }
11242
11243 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
11244 // Refuse possible leaked file descriptors
11245 if (intent != null && intent.hasFileDescriptors() == true) {
11246 throw new IllegalArgumentException("File descriptors passed in Intent");
11247 }
11248
11249 synchronized(this) {
11250 if (!(token instanceof ServiceRecord)) {
11251 throw new IllegalArgumentException("Invalid service token");
11252 }
11253 ServiceRecord r = (ServiceRecord)token;
11254
11255 final long origId = Binder.clearCallingIdentity();
11256
11257 if (r != null) {
11258 Intent.FilterComparison filter
11259 = new Intent.FilterComparison(intent);
11260 IntentBindRecord b = r.bindings.get(filter);
11261 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
11262 + " at " + b + ": apps="
11263 + (b != null ? b.apps.size() : 0));
11264 if (b != null) {
11265 if (b.apps.size() > 0) {
11266 // Applications have already bound since the last
11267 // unbind, so just rebind right here.
11268 requestServiceBindingLocked(r, b, true);
11269 } else {
11270 // Note to tell the service the next time there is
11271 // a new client.
11272 b.doRebind = true;
11273 }
11274 }
11275
11276 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
11277
11278 Binder.restoreCallingIdentity(origId);
11279 }
11280 }
11281 }
11282
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011283 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011284 synchronized(this) {
11285 if (!(token instanceof ServiceRecord)) {
11286 throw new IllegalArgumentException("Invalid service token");
11287 }
11288 ServiceRecord r = (ServiceRecord)token;
11289 boolean inStopping = mStoppingServices.contains(token);
11290 if (r != null) {
11291 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
11292 + ": nesting=" + r.executeNesting
11293 + ", inStopping=" + inStopping);
11294 if (r != token) {
11295 Log.w(TAG, "Done executing service " + r.name
11296 + " with incorrect token: given " + token
11297 + ", expected " + r);
11298 return;
11299 }
11300
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070011301 if (type == 1) {
11302 // This is a call from a service start... take care of
11303 // book-keeping.
11304 r.callStart = true;
11305 switch (res) {
11306 case Service.START_STICKY_COMPATIBILITY:
11307 case Service.START_STICKY: {
11308 // We are done with the associated start arguments.
11309 r.findDeliveredStart(startId, true);
11310 // Don't stop if killed.
11311 r.stopIfKilled = false;
11312 break;
11313 }
11314 case Service.START_NOT_STICKY: {
11315 // We are done with the associated start arguments.
11316 r.findDeliveredStart(startId, true);
11317 if (r.lastStartId == startId) {
11318 // There is no more work, and this service
11319 // doesn't want to hang around if killed.
11320 r.stopIfKilled = true;
11321 }
11322 break;
11323 }
11324 case Service.START_REDELIVER_INTENT: {
11325 // We'll keep this item until they explicitly
11326 // call stop for it, but keep track of the fact
11327 // that it was delivered.
11328 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
11329 if (si != null) {
11330 si.deliveryCount = 0;
11331 si.doneExecutingCount++;
11332 // Don't stop if killed.
11333 r.stopIfKilled = true;
11334 }
11335 break;
11336 }
11337 default:
11338 throw new IllegalArgumentException(
11339 "Unknown service start result: " + res);
11340 }
11341 if (res == Service.START_STICKY_COMPATIBILITY) {
11342 r.callStart = false;
11343 }
11344 }
11345
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011346 final long origId = Binder.clearCallingIdentity();
11347 serviceDoneExecutingLocked(r, inStopping);
11348 Binder.restoreCallingIdentity(origId);
11349 } else {
11350 Log.w(TAG, "Done executing unknown service " + r.name
11351 + " with token " + token);
11352 }
11353 }
11354 }
11355
11356 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
11357 r.executeNesting--;
11358 if (r.executeNesting <= 0 && r.app != null) {
11359 r.app.executingServices.remove(r);
11360 if (r.app.executingServices.size() == 0) {
11361 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
11362 }
11363 if (inStopping) {
11364 mStoppingServices.remove(r);
11365 }
11366 updateOomAdjLocked(r.app);
11367 }
11368 }
11369
11370 void serviceTimeout(ProcessRecord proc) {
11371 synchronized(this) {
11372 if (proc.executingServices.size() == 0 || proc.thread == null) {
11373 return;
11374 }
11375 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
11376 Iterator<ServiceRecord> it = proc.executingServices.iterator();
11377 ServiceRecord timeout = null;
11378 long nextTime = 0;
11379 while (it.hasNext()) {
11380 ServiceRecord sr = it.next();
11381 if (sr.executingStart < maxTime) {
11382 timeout = sr;
11383 break;
11384 }
11385 if (sr.executingStart > nextTime) {
11386 nextTime = sr.executingStart;
11387 }
11388 }
11389 if (timeout != null && mLRUProcesses.contains(proc)) {
11390 Log.w(TAG, "Timeout executing service: " + timeout);
Dan Egnorb7f03672009-12-09 16:22:32 -080011391 appNotRespondingLocked(proc, null, null, "Executing service " + timeout.name);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011392 } else {
11393 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
11394 msg.obj = proc;
11395 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
11396 }
11397 }
11398 }
11399
11400 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070011401 // BACKUP AND RESTORE
11402 // =========================================================
11403
11404 // Cause the target app to be launched if necessary and its backup agent
11405 // instantiated. The backup agent will invoke backupAgentCreated() on the
11406 // activity manager to announce its creation.
11407 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
11408 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
11409 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
11410
11411 synchronized(this) {
11412 // !!! TODO: currently no check here that we're already bound
11413 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
11414 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
11415 synchronized (stats) {
11416 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
11417 }
11418
11419 BackupRecord r = new BackupRecord(ss, app, backupMode);
11420 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
11421 // startProcessLocked() returns existing proc's record if it's already running
11422 ProcessRecord proc = startProcessLocked(app.processName, app,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011423 false, 0, "backup", hostingName, false);
Christopher Tate181fafa2009-05-14 11:12:14 -070011424 if (proc == null) {
11425 Log.e(TAG, "Unable to start backup agent process " + r);
11426 return false;
11427 }
11428
11429 r.app = proc;
11430 mBackupTarget = r;
11431 mBackupAppName = app.packageName;
11432
Christopher Tate6fa95972009-06-05 18:43:55 -070011433 // Try not to kill the process during backup
11434 updateOomAdjLocked(proc);
11435
Christopher Tate181fafa2009-05-14 11:12:14 -070011436 // If the process is already attached, schedule the creation of the backup agent now.
11437 // If it is not yet live, this will be done when it attaches to the framework.
11438 if (proc.thread != null) {
11439 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
11440 try {
11441 proc.thread.scheduleCreateBackupAgent(app, backupMode);
11442 } catch (RemoteException e) {
Christopher Tate436344a2009-09-30 16:17:37 -070011443 // Will time out on the backup manager side
Christopher Tate181fafa2009-05-14 11:12:14 -070011444 }
11445 } else {
11446 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
11447 }
11448 // Invariants: at this point, the target app process exists and the application
11449 // is either already running or in the process of coming up. mBackupTarget and
11450 // mBackupAppName describe the app, so that when it binds back to the AM we
11451 // know that it's scheduled for a backup-agent operation.
11452 }
11453
11454 return true;
11455 }
11456
11457 // A backup agent has just come up
11458 public void backupAgentCreated(String agentPackageName, IBinder agent) {
11459 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
11460 + " = " + agent);
11461
11462 synchronized(this) {
11463 if (!agentPackageName.equals(mBackupAppName)) {
11464 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
11465 return;
11466 }
11467
Christopher Tate043dadc2009-06-02 16:11:00 -070011468 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070011469 try {
11470 IBackupManager bm = IBackupManager.Stub.asInterface(
11471 ServiceManager.getService(Context.BACKUP_SERVICE));
11472 bm.agentConnected(agentPackageName, agent);
11473 } catch (RemoteException e) {
11474 // can't happen; the backup manager service is local
11475 } catch (Exception e) {
11476 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
11477 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070011478 } finally {
11479 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070011480 }
11481 }
11482 }
11483
11484 // done with this agent
11485 public void unbindBackupAgent(ApplicationInfo appInfo) {
11486 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070011487 if (appInfo == null) {
11488 Log.w(TAG, "unbind backup agent for null app");
11489 return;
11490 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011491
11492 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011493 if (mBackupAppName == null) {
11494 Log.w(TAG, "Unbinding backup agent with no active backup");
11495 return;
11496 }
11497
Christopher Tate181fafa2009-05-14 11:12:14 -070011498 if (!mBackupAppName.equals(appInfo.packageName)) {
11499 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11500 return;
11501 }
11502
Christopher Tate6fa95972009-06-05 18:43:55 -070011503 ProcessRecord proc = mBackupTarget.app;
11504 mBackupTarget = null;
11505 mBackupAppName = null;
11506
11507 // Not backing this app up any more; reset its OOM adjustment
11508 updateOomAdjLocked(proc);
11509
Christopher Tatec7b31e32009-06-10 15:49:30 -070011510 // If the app crashed during backup, 'thread' will be null here
11511 if (proc.thread != null) {
11512 try {
11513 proc.thread.scheduleDestroyBackupAgent(appInfo);
11514 } catch (Exception e) {
11515 Log.e(TAG, "Exception when unbinding backup agent:");
11516 e.printStackTrace();
11517 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011518 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011519 }
11520 }
11521 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011522 // BROADCASTS
11523 // =========================================================
11524
11525 private final List getStickies(String action, IntentFilter filter,
11526 List cur) {
11527 final ContentResolver resolver = mContext.getContentResolver();
11528 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11529 if (list == null) {
11530 return cur;
11531 }
11532 int N = list.size();
11533 for (int i=0; i<N; i++) {
11534 Intent intent = list.get(i);
11535 if (filter.match(resolver, intent, true, TAG) >= 0) {
11536 if (cur == null) {
11537 cur = new ArrayList<Intent>();
11538 }
11539 cur.add(intent);
11540 }
11541 }
11542 return cur;
11543 }
11544
11545 private final void scheduleBroadcastsLocked() {
11546 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11547 + mBroadcastsScheduled);
11548
11549 if (mBroadcastsScheduled) {
11550 return;
11551 }
11552 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11553 mBroadcastsScheduled = true;
11554 }
11555
11556 public Intent registerReceiver(IApplicationThread caller,
11557 IIntentReceiver receiver, IntentFilter filter, String permission) {
11558 synchronized(this) {
11559 ProcessRecord callerApp = null;
11560 if (caller != null) {
11561 callerApp = getRecordForAppLocked(caller);
11562 if (callerApp == null) {
11563 throw new SecurityException(
11564 "Unable to find app for caller " + caller
11565 + " (pid=" + Binder.getCallingPid()
11566 + ") when registering receiver " + receiver);
11567 }
11568 }
11569
11570 List allSticky = null;
11571
11572 // Look for any matching sticky broadcasts...
11573 Iterator actions = filter.actionsIterator();
11574 if (actions != null) {
11575 while (actions.hasNext()) {
11576 String action = (String)actions.next();
11577 allSticky = getStickies(action, filter, allSticky);
11578 }
11579 } else {
11580 allSticky = getStickies(null, filter, allSticky);
11581 }
11582
11583 // The first sticky in the list is returned directly back to
11584 // the client.
11585 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11586
11587 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11588 + ": " + sticky);
11589
11590 if (receiver == null) {
11591 return sticky;
11592 }
11593
11594 ReceiverList rl
11595 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11596 if (rl == null) {
11597 rl = new ReceiverList(this, callerApp,
11598 Binder.getCallingPid(),
11599 Binder.getCallingUid(), receiver);
11600 if (rl.app != null) {
11601 rl.app.receivers.add(rl);
11602 } else {
11603 try {
11604 receiver.asBinder().linkToDeath(rl, 0);
11605 } catch (RemoteException e) {
11606 return sticky;
11607 }
11608 rl.linkedToDeath = true;
11609 }
11610 mRegisteredReceivers.put(receiver.asBinder(), rl);
11611 }
11612 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11613 rl.add(bf);
11614 if (!bf.debugCheck()) {
11615 Log.w(TAG, "==> For Dynamic broadast");
11616 }
11617 mReceiverResolver.addFilter(bf);
11618
11619 // Enqueue broadcasts for all existing stickies that match
11620 // this filter.
11621 if (allSticky != null) {
11622 ArrayList receivers = new ArrayList();
11623 receivers.add(bf);
11624
11625 int N = allSticky.size();
11626 for (int i=0; i<N; i++) {
11627 Intent intent = (Intent)allSticky.get(i);
11628 BroadcastRecord r = new BroadcastRecord(intent, null,
11629 null, -1, -1, null, receivers, null, 0, null, null,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011630 false, true, true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011631 if (mParallelBroadcasts.size() == 0) {
11632 scheduleBroadcastsLocked();
11633 }
11634 mParallelBroadcasts.add(r);
11635 }
11636 }
11637
11638 return sticky;
11639 }
11640 }
11641
11642 public void unregisterReceiver(IIntentReceiver receiver) {
11643 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11644
11645 boolean doNext = false;
11646
11647 synchronized(this) {
11648 ReceiverList rl
11649 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11650 if (rl != null) {
11651 if (rl.curBroadcast != null) {
11652 BroadcastRecord r = rl.curBroadcast;
11653 doNext = finishReceiverLocked(
11654 receiver.asBinder(), r.resultCode, r.resultData,
11655 r.resultExtras, r.resultAbort, true);
11656 }
11657
11658 if (rl.app != null) {
11659 rl.app.receivers.remove(rl);
11660 }
11661 removeReceiverLocked(rl);
11662 if (rl.linkedToDeath) {
11663 rl.linkedToDeath = false;
11664 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11665 }
11666 }
11667 }
11668
11669 if (!doNext) {
11670 return;
11671 }
11672
11673 final long origId = Binder.clearCallingIdentity();
11674 processNextBroadcast(false);
11675 trimApplications();
11676 Binder.restoreCallingIdentity(origId);
11677 }
11678
11679 void removeReceiverLocked(ReceiverList rl) {
11680 mRegisteredReceivers.remove(rl.receiver.asBinder());
11681 int N = rl.size();
11682 for (int i=0; i<N; i++) {
11683 mReceiverResolver.removeFilter(rl.get(i));
11684 }
11685 }
11686
11687 private final int broadcastIntentLocked(ProcessRecord callerApp,
11688 String callerPackage, Intent intent, String resolvedType,
11689 IIntentReceiver resultTo, int resultCode, String resultData,
11690 Bundle map, String requiredPermission,
11691 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11692 intent = new Intent(intent);
11693
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011694 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011695 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11696 + " ordered=" + ordered);
11697 if ((resultTo != null) && !ordered) {
11698 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11699 }
11700
11701 // Handle special intents: if this broadcast is from the package
11702 // manager about a package being removed, we need to remove all of
11703 // its activities from the history stack.
11704 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11705 intent.getAction());
11706 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11707 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11708 || uidRemoved) {
11709 if (checkComponentPermission(
11710 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11711 callingPid, callingUid, -1)
11712 == PackageManager.PERMISSION_GRANTED) {
11713 if (uidRemoved) {
11714 final Bundle intentExtras = intent.getExtras();
11715 final int uid = intentExtras != null
11716 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11717 if (uid >= 0) {
11718 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11719 synchronized (bs) {
11720 bs.removeUidStatsLocked(uid);
11721 }
11722 }
11723 } else {
11724 Uri data = intent.getData();
11725 String ssp;
11726 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11727 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11728 uninstallPackageLocked(ssp,
11729 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011730 AttributeCache ac = AttributeCache.instance();
11731 if (ac != null) {
11732 ac.removePackage(ssp);
11733 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011734 }
11735 }
11736 }
11737 } else {
11738 String msg = "Permission Denial: " + intent.getAction()
11739 + " broadcast from " + callerPackage + " (pid=" + callingPid
11740 + ", uid=" + callingUid + ")"
11741 + " requires "
11742 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11743 Log.w(TAG, msg);
11744 throw new SecurityException(msg);
11745 }
11746 }
11747
11748 /*
11749 * If this is the time zone changed action, queue up a message that will reset the timezone
11750 * of all currently running processes. This message will get queued up before the broadcast
11751 * happens.
11752 */
11753 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11754 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11755 }
11756
Dianne Hackborn854060af2009-07-09 18:14:31 -070011757 /*
11758 * Prevent non-system code (defined here to be non-persistent
11759 * processes) from sending protected broadcasts.
11760 */
11761 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11762 || callingUid == Process.SHELL_UID || callingUid == 0) {
11763 // Always okay.
11764 } else if (callerApp == null || !callerApp.persistent) {
11765 try {
11766 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11767 intent.getAction())) {
11768 String msg = "Permission Denial: not allowed to send broadcast "
11769 + intent.getAction() + " from pid="
11770 + callingPid + ", uid=" + callingUid;
11771 Log.w(TAG, msg);
11772 throw new SecurityException(msg);
11773 }
11774 } catch (RemoteException e) {
11775 Log.w(TAG, "Remote exception", e);
11776 return BROADCAST_SUCCESS;
11777 }
11778 }
11779
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011780 // Add to the sticky list if requested.
11781 if (sticky) {
11782 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11783 callingPid, callingUid)
11784 != PackageManager.PERMISSION_GRANTED) {
11785 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11786 + callingPid + ", uid=" + callingUid
11787 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11788 Log.w(TAG, msg);
11789 throw new SecurityException(msg);
11790 }
11791 if (requiredPermission != null) {
11792 Log.w(TAG, "Can't broadcast sticky intent " + intent
11793 + " and enforce permission " + requiredPermission);
11794 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11795 }
11796 if (intent.getComponent() != null) {
11797 throw new SecurityException(
11798 "Sticky broadcasts can't target a specific component");
11799 }
11800 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11801 if (list == null) {
11802 list = new ArrayList<Intent>();
11803 mStickyBroadcasts.put(intent.getAction(), list);
11804 }
11805 int N = list.size();
11806 int i;
11807 for (i=0; i<N; i++) {
11808 if (intent.filterEquals(list.get(i))) {
11809 // This sticky already exists, replace it.
11810 list.set(i, new Intent(intent));
11811 break;
11812 }
11813 }
11814 if (i >= N) {
11815 list.add(new Intent(intent));
11816 }
11817 }
11818
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011819 // Figure out who all will receive this broadcast.
11820 List receivers = null;
11821 List<BroadcastFilter> registeredReceivers = null;
11822 try {
11823 if (intent.getComponent() != null) {
11824 // Broadcast is going to one specific receiver class...
11825 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011826 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011827 if (ai != null) {
11828 receivers = new ArrayList();
11829 ResolveInfo ri = new ResolveInfo();
11830 ri.activityInfo = ai;
11831 receivers.add(ri);
11832 }
11833 } else {
11834 // Need to resolve the intent to interested receivers...
11835 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11836 == 0) {
11837 receivers =
11838 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011839 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011840 }
Mihai Preda074edef2009-05-18 17:13:31 +020011841 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011842 }
11843 } catch (RemoteException ex) {
11844 // pm is in same process, this will never happen.
11845 }
11846
11847 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11848 if (!ordered && NR > 0) {
11849 // If we are not serializing this broadcast, then send the
11850 // registered receivers separately so they don't wait for the
11851 // components to be launched.
11852 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11853 callerPackage, callingPid, callingUid, requiredPermission,
11854 registeredReceivers, resultTo, resultCode, resultData, map,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011855 ordered, sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011856 if (DEBUG_BROADCAST) Log.v(
11857 TAG, "Enqueueing parallel broadcast " + r
11858 + ": prev had " + mParallelBroadcasts.size());
11859 mParallelBroadcasts.add(r);
11860 scheduleBroadcastsLocked();
11861 registeredReceivers = null;
11862 NR = 0;
11863 }
11864
11865 // Merge into one list.
11866 int ir = 0;
11867 if (receivers != null) {
11868 // A special case for PACKAGE_ADDED: do not allow the package
11869 // being added to see this broadcast. This prevents them from
11870 // using this as a back door to get run as soon as they are
11871 // installed. Maybe in the future we want to have a special install
11872 // broadcast or such for apps, but we'd like to deliberately make
11873 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011874 boolean skip = false;
11875 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011876 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011877 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11878 skip = true;
11879 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11880 skip = true;
11881 }
11882 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011883 ? intent.getData().getSchemeSpecificPart()
11884 : null;
11885 if (skipPackage != null && receivers != null) {
11886 int NT = receivers.size();
11887 for (int it=0; it<NT; it++) {
11888 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11889 if (curt.activityInfo.packageName.equals(skipPackage)) {
11890 receivers.remove(it);
11891 it--;
11892 NT--;
11893 }
11894 }
11895 }
11896
11897 int NT = receivers != null ? receivers.size() : 0;
11898 int it = 0;
11899 ResolveInfo curt = null;
11900 BroadcastFilter curr = null;
11901 while (it < NT && ir < NR) {
11902 if (curt == null) {
11903 curt = (ResolveInfo)receivers.get(it);
11904 }
11905 if (curr == null) {
11906 curr = registeredReceivers.get(ir);
11907 }
11908 if (curr.getPriority() >= curt.priority) {
11909 // Insert this broadcast record into the final list.
11910 receivers.add(it, curr);
11911 ir++;
11912 curr = null;
11913 it++;
11914 NT++;
11915 } else {
11916 // Skip to the next ResolveInfo in the final list.
11917 it++;
11918 curt = null;
11919 }
11920 }
11921 }
11922 while (ir < NR) {
11923 if (receivers == null) {
11924 receivers = new ArrayList();
11925 }
11926 receivers.add(registeredReceivers.get(ir));
11927 ir++;
11928 }
11929
11930 if ((receivers != null && receivers.size() > 0)
11931 || resultTo != null) {
11932 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11933 callerPackage, callingPid, callingUid, requiredPermission,
Dianne Hackborn12527f92009-11-11 17:39:50 -080011934 receivers, resultTo, resultCode, resultData, map, ordered,
11935 sticky, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011936 if (DEBUG_BROADCAST) Log.v(
11937 TAG, "Enqueueing ordered broadcast " + r
11938 + ": prev had " + mOrderedBroadcasts.size());
11939 if (DEBUG_BROADCAST) {
11940 int seq = r.intent.getIntExtra("seq", -1);
11941 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11942 }
11943 mOrderedBroadcasts.add(r);
11944 scheduleBroadcastsLocked();
11945 }
11946
11947 return BROADCAST_SUCCESS;
11948 }
11949
11950 public final int broadcastIntent(IApplicationThread caller,
11951 Intent intent, String resolvedType, IIntentReceiver resultTo,
11952 int resultCode, String resultData, Bundle map,
11953 String requiredPermission, boolean serialized, boolean sticky) {
11954 // Refuse possible leaked file descriptors
11955 if (intent != null && intent.hasFileDescriptors() == true) {
11956 throw new IllegalArgumentException("File descriptors passed in Intent");
11957 }
11958
11959 synchronized(this) {
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011960 int flags = intent.getFlags();
11961
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011962 if (!mSystemReady) {
11963 // if the caller really truly claims to know what they're doing, go
11964 // ahead and allow the broadcast without launching any receivers
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011965 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11966 intent = new Intent(intent);
11967 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11968 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11969 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11970 + " before boot completion");
11971 throw new IllegalStateException("Cannot broadcast before boot completed");
11972 }
11973 }
11974
Dianne Hackborn9acc0302009-08-25 00:27:12 -070011975 if ((flags&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0) {
11976 throw new IllegalArgumentException(
11977 "Can't use FLAG_RECEIVER_BOOT_UPGRADE here");
11978 }
11979
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011980 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11981 final int callingPid = Binder.getCallingPid();
11982 final int callingUid = Binder.getCallingUid();
11983 final long origId = Binder.clearCallingIdentity();
11984 int res = broadcastIntentLocked(callerApp,
11985 callerApp != null ? callerApp.info.packageName : null,
11986 intent, resolvedType, resultTo,
11987 resultCode, resultData, map, requiredPermission, serialized,
11988 sticky, callingPid, callingUid);
11989 Binder.restoreCallingIdentity(origId);
11990 return res;
11991 }
11992 }
11993
11994 int broadcastIntentInPackage(String packageName, int uid,
11995 Intent intent, String resolvedType, IIntentReceiver resultTo,
11996 int resultCode, String resultData, Bundle map,
11997 String requiredPermission, boolean serialized, boolean sticky) {
11998 synchronized(this) {
11999 final long origId = Binder.clearCallingIdentity();
12000 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
12001 resultTo, resultCode, resultData, map, requiredPermission,
12002 serialized, sticky, -1, uid);
12003 Binder.restoreCallingIdentity(origId);
12004 return res;
12005 }
12006 }
12007
12008 public final void unbroadcastIntent(IApplicationThread caller,
12009 Intent intent) {
12010 // Refuse possible leaked file descriptors
12011 if (intent != null && intent.hasFileDescriptors() == true) {
12012 throw new IllegalArgumentException("File descriptors passed in Intent");
12013 }
12014
12015 synchronized(this) {
12016 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
12017 != PackageManager.PERMISSION_GRANTED) {
12018 String msg = "Permission Denial: unbroadcastIntent() from pid="
12019 + Binder.getCallingPid()
12020 + ", uid=" + Binder.getCallingUid()
12021 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
12022 Log.w(TAG, msg);
12023 throw new SecurityException(msg);
12024 }
12025 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
12026 if (list != null) {
12027 int N = list.size();
12028 int i;
12029 for (i=0; i<N; i++) {
12030 if (intent.filterEquals(list.get(i))) {
12031 list.remove(i);
12032 break;
12033 }
12034 }
12035 }
12036 }
12037 }
12038
12039 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
12040 String resultData, Bundle resultExtras, boolean resultAbort,
12041 boolean explicit) {
12042 if (mOrderedBroadcasts.size() == 0) {
12043 if (explicit) {
12044 Log.w(TAG, "finishReceiver called but no pending broadcasts");
12045 }
12046 return false;
12047 }
12048 BroadcastRecord r = mOrderedBroadcasts.get(0);
12049 if (r.receiver == null) {
12050 if (explicit) {
12051 Log.w(TAG, "finishReceiver called but none active");
12052 }
12053 return false;
12054 }
12055 if (r.receiver != receiver) {
12056 Log.w(TAG, "finishReceiver called but active receiver is different");
12057 return false;
12058 }
12059 int state = r.state;
12060 r.state = r.IDLE;
12061 if (state == r.IDLE) {
12062 if (explicit) {
12063 Log.w(TAG, "finishReceiver called but state is IDLE");
12064 }
12065 }
12066 r.receiver = null;
12067 r.intent.setComponent(null);
12068 if (r.curApp != null) {
12069 r.curApp.curReceiver = null;
12070 }
12071 if (r.curFilter != null) {
12072 r.curFilter.receiverList.curBroadcast = null;
12073 }
12074 r.curFilter = null;
12075 r.curApp = null;
12076 r.curComponent = null;
12077 r.curReceiver = null;
12078 mPendingBroadcast = null;
12079
12080 r.resultCode = resultCode;
12081 r.resultData = resultData;
12082 r.resultExtras = resultExtras;
12083 r.resultAbort = resultAbort;
12084
12085 // We will process the next receiver right now if this is finishing
12086 // an app receiver (which is always asynchronous) or after we have
12087 // come back from calling a receiver.
12088 return state == BroadcastRecord.APP_RECEIVE
12089 || state == BroadcastRecord.CALL_DONE_RECEIVE;
12090 }
12091
12092 public void finishReceiver(IBinder who, int resultCode, String resultData,
12093 Bundle resultExtras, boolean resultAbort) {
12094 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
12095
12096 // Refuse possible leaked file descriptors
12097 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
12098 throw new IllegalArgumentException("File descriptors passed in Bundle");
12099 }
12100
12101 boolean doNext;
12102
12103 final long origId = Binder.clearCallingIdentity();
12104
12105 synchronized(this) {
12106 doNext = finishReceiverLocked(
12107 who, resultCode, resultData, resultExtras, resultAbort, true);
12108 }
12109
12110 if (doNext) {
12111 processNextBroadcast(false);
12112 }
12113 trimApplications();
12114
12115 Binder.restoreCallingIdentity(origId);
12116 }
12117
12118 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
12119 if (r.nextReceiver > 0) {
12120 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12121 if (curReceiver instanceof BroadcastFilter) {
12122 BroadcastFilter bf = (BroadcastFilter) curReceiver;
Doug Zongker2bec3d42009-12-04 12:52:44 -080012123 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_FILTER,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012124 System.identityHashCode(r),
12125 r.intent.getAction(),
12126 r.nextReceiver - 1,
12127 System.identityHashCode(bf));
12128 } else {
Doug Zongker2bec3d42009-12-04 12:52:44 -080012129 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012130 System.identityHashCode(r),
12131 r.intent.getAction(),
12132 r.nextReceiver - 1,
12133 ((ResolveInfo)curReceiver).toString());
12134 }
12135 } else {
12136 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
12137 + r);
Doug Zongker2bec3d42009-12-04 12:52:44 -080012138 EventLog.writeEvent(EventLogTags.AM_BROADCAST_DISCARD_APP,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012139 System.identityHashCode(r),
12140 r.intent.getAction(),
12141 r.nextReceiver,
12142 "NONE");
12143 }
12144 }
12145
12146 private final void broadcastTimeout() {
12147 synchronized (this) {
12148 if (mOrderedBroadcasts.size() == 0) {
12149 return;
12150 }
12151 long now = SystemClock.uptimeMillis();
12152 BroadcastRecord r = mOrderedBroadcasts.get(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012153 if ((r.receiverTime+BROADCAST_TIMEOUT) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012154 if (DEBUG_BROADCAST) Log.v(TAG,
12155 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012156 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012157 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012158 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012159 return;
12160 }
12161
12162 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012163 r.receiverTime = now;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012164 r.anrCount++;
12165
12166 // Current receiver has passed its expiration date.
12167 if (r.nextReceiver <= 0) {
12168 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
12169 return;
12170 }
12171
12172 ProcessRecord app = null;
12173
12174 Object curReceiver = r.receivers.get(r.nextReceiver-1);
12175 Log.w(TAG, "Receiver during timeout: " + curReceiver);
12176 logBroadcastReceiverDiscard(r);
12177 if (curReceiver instanceof BroadcastFilter) {
12178 BroadcastFilter bf = (BroadcastFilter)curReceiver;
12179 if (bf.receiverList.pid != 0
12180 && bf.receiverList.pid != MY_PID) {
12181 synchronized (this.mPidsSelfLocked) {
12182 app = this.mPidsSelfLocked.get(
12183 bf.receiverList.pid);
12184 }
12185 }
12186 } else {
12187 app = r.curApp;
12188 }
12189
12190 if (app != null) {
Dan Egnorb7f03672009-12-09 16:22:32 -080012191 appNotRespondingLocked(app, null, null, "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012192 }
12193
12194 if (mPendingBroadcast == r) {
12195 mPendingBroadcast = null;
12196 }
12197
12198 // Move on to the next receiver.
12199 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12200 r.resultExtras, r.resultAbort, true);
12201 scheduleBroadcastsLocked();
12202 }
12203 }
12204
12205 private final void processCurBroadcastLocked(BroadcastRecord r,
12206 ProcessRecord app) throws RemoteException {
12207 if (app.thread == null) {
12208 throw new RemoteException();
12209 }
12210 r.receiver = app.thread.asBinder();
12211 r.curApp = app;
12212 app.curReceiver = r;
12213 updateLRUListLocked(app, true);
12214
12215 // Tell the application to launch this receiver.
12216 r.intent.setComponent(r.curComponent);
12217
12218 boolean started = false;
12219 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012220 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012221 "Delivering to component " + r.curComponent
12222 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070012223 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012224 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
12225 r.resultCode, r.resultData, r.resultExtras, r.ordered);
12226 started = true;
12227 } finally {
12228 if (!started) {
12229 r.receiver = null;
12230 r.curApp = null;
12231 app.curReceiver = null;
12232 }
12233 }
12234
12235 }
12236
12237 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012238 Intent intent, int resultCode, String data, Bundle extras,
12239 boolean ordered, boolean sticky) throws RemoteException {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012240 if (app != null && app.thread != null) {
12241 // If we have an app thread, do the call through that so it is
12242 // correctly ordered with other one-way calls.
12243 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012244 data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012245 } else {
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012246 receiver.performReceive(intent, resultCode, data, extras, ordered, sticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012247 }
12248 }
12249
12250 private final void deliverToRegisteredReceiver(BroadcastRecord r,
12251 BroadcastFilter filter, boolean ordered) {
12252 boolean skip = false;
12253 if (filter.requiredPermission != null) {
12254 int perm = checkComponentPermission(filter.requiredPermission,
12255 r.callingPid, r.callingUid, -1);
12256 if (perm != PackageManager.PERMISSION_GRANTED) {
12257 Log.w(TAG, "Permission Denial: broadcasting "
12258 + r.intent.toString()
12259 + " from " + r.callerPackage + " (pid="
12260 + r.callingPid + ", uid=" + r.callingUid + ")"
12261 + " requires " + filter.requiredPermission
12262 + " due to registered receiver " + filter);
12263 skip = true;
12264 }
12265 }
12266 if (r.requiredPermission != null) {
12267 int perm = checkComponentPermission(r.requiredPermission,
12268 filter.receiverList.pid, filter.receiverList.uid, -1);
12269 if (perm != PackageManager.PERMISSION_GRANTED) {
12270 Log.w(TAG, "Permission Denial: receiving "
12271 + r.intent.toString()
12272 + " to " + filter.receiverList.app
12273 + " (pid=" + filter.receiverList.pid
12274 + ", uid=" + filter.receiverList.uid + ")"
12275 + " requires " + r.requiredPermission
12276 + " due to sender " + r.callerPackage
12277 + " (uid " + r.callingUid + ")");
12278 skip = true;
12279 }
12280 }
12281
12282 if (!skip) {
12283 // If this is not being sent as an ordered broadcast, then we
12284 // don't want to touch the fields that keep track of the current
12285 // state of ordered broadcasts.
12286 if (ordered) {
12287 r.receiver = filter.receiverList.receiver.asBinder();
12288 r.curFilter = filter;
12289 filter.receiverList.curBroadcast = r;
12290 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012291 if (filter.receiverList.app != null) {
12292 // Bump hosting application to no longer be in background
12293 // scheduling class. Note that we can't do that if there
12294 // isn't an app... but we can only be in that case for
12295 // things that directly call the IActivityManager API, which
12296 // are already core system stuff so don't matter for this.
12297 r.curApp = filter.receiverList.app;
12298 filter.receiverList.app.curReceiver = r;
12299 updateOomAdjLocked();
12300 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012301 }
12302 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012303 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012304 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012305 Log.i(TAG, "Delivering to " + filter.receiverList.app
12306 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012307 }
12308 performReceive(filter.receiverList.app, filter.receiverList.receiver,
12309 new Intent(r.intent), r.resultCode,
Dianne Hackborn12527f92009-11-11 17:39:50 -080012310 r.resultData, r.resultExtras, r.ordered, r.initialSticky);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012311 if (ordered) {
12312 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
12313 }
12314 } catch (RemoteException e) {
12315 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
12316 if (ordered) {
12317 r.receiver = null;
12318 r.curFilter = null;
12319 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012320 if (filter.receiverList.app != null) {
12321 filter.receiverList.app.curReceiver = null;
12322 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012323 }
12324 }
12325 }
12326 }
12327
Dianne Hackborn12527f92009-11-11 17:39:50 -080012328 private final void addBroadcastToHistoryLocked(BroadcastRecord r) {
12329 if (r.callingUid < 0) {
12330 // This was from a registerReceiver() call; ignore it.
12331 return;
12332 }
12333 System.arraycopy(mBroadcastHistory, 0, mBroadcastHistory, 1,
12334 MAX_BROADCAST_HISTORY-1);
12335 r.finishTime = SystemClock.uptimeMillis();
12336 mBroadcastHistory[0] = r;
12337 }
12338
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012339 private final void processNextBroadcast(boolean fromMsg) {
12340 synchronized(this) {
12341 BroadcastRecord r;
12342
12343 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
12344 + mParallelBroadcasts.size() + " broadcasts, "
12345 + mOrderedBroadcasts.size() + " serialized broadcasts");
12346
12347 updateCpuStats();
12348
12349 if (fromMsg) {
12350 mBroadcastsScheduled = false;
12351 }
12352
12353 // First, deliver any non-serialized broadcasts right away.
12354 while (mParallelBroadcasts.size() > 0) {
12355 r = mParallelBroadcasts.remove(0);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012356 r.dispatchTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012357 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012358 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
12359 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012360 for (int i=0; i<N; i++) {
12361 Object target = r.receivers.get(i);
12362 if (DEBUG_BROADCAST) Log.v(TAG,
12363 "Delivering non-serialized to registered "
12364 + target + ": " + r);
12365 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
12366 }
Dianne Hackborn12527f92009-11-11 17:39:50 -080012367 addBroadcastToHistoryLocked(r);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012368 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
12369 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012370 }
12371
12372 // Now take care of the next serialized one...
12373
12374 // If we are waiting for a process to come up to handle the next
12375 // broadcast, then do nothing at this point. Just in case, we
12376 // check that the process we're waiting for still exists.
12377 if (mPendingBroadcast != null) {
Dianne Hackbornbd0a81f2009-10-04 13:30:50 -070012378 if (DEBUG_BROADCAST_LIGHT) {
12379 Log.v(TAG, "processNextBroadcast: waiting for "
12380 + mPendingBroadcast.curApp);
12381 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012382
12383 boolean isDead;
12384 synchronized (mPidsSelfLocked) {
12385 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
12386 }
12387 if (!isDead) {
12388 // It's still alive, so keep waiting
12389 return;
12390 } else {
12391 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
12392 + " died before responding to broadcast");
12393 mPendingBroadcast = null;
12394 }
12395 }
12396
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012397 boolean looped = false;
12398
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012399 do {
12400 if (mOrderedBroadcasts.size() == 0) {
12401 // No more broadcasts pending, so all done!
12402 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012403 if (looped) {
12404 // If we had finished the last ordered broadcast, then
12405 // make sure all processes have correct oom and sched
12406 // adjustments.
12407 updateOomAdjLocked();
12408 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012409 return;
12410 }
12411 r = mOrderedBroadcasts.get(0);
12412 boolean forceReceive = false;
12413
12414 // Ensure that even if something goes awry with the timeout
12415 // detection, we catch "hung" broadcasts here, discard them,
12416 // and continue to make progress.
12417 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
12418 long now = SystemClock.uptimeMillis();
12419 if (r.dispatchTime > 0) {
12420 if ((numReceivers > 0) &&
12421 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
12422 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
12423 + " now=" + now
12424 + " dispatchTime=" + r.dispatchTime
Dianne Hackborn12527f92009-11-11 17:39:50 -080012425 + " startTime=" + r.receiverTime
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012426 + " intent=" + r.intent
12427 + " numReceivers=" + numReceivers
12428 + " nextReceiver=" + r.nextReceiver
12429 + " state=" + r.state);
12430 broadcastTimeout(); // forcibly finish this broadcast
12431 forceReceive = true;
12432 r.state = BroadcastRecord.IDLE;
12433 }
12434 }
12435
12436 if (r.state != BroadcastRecord.IDLE) {
12437 if (DEBUG_BROADCAST) Log.d(TAG,
12438 "processNextBroadcast() called when not idle (state="
12439 + r.state + ")");
12440 return;
12441 }
12442
12443 if (r.receivers == null || r.nextReceiver >= numReceivers
12444 || r.resultAbort || forceReceive) {
12445 // No more receivers for this broadcast! Send the final
12446 // result if requested...
12447 if (r.resultTo != null) {
12448 try {
12449 if (DEBUG_BROADCAST) {
12450 int seq = r.intent.getIntExtra("seq", -1);
12451 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
12452 + " seq=" + seq + " app=" + r.callerApp);
12453 }
12454 performReceive(r.callerApp, r.resultTo,
12455 new Intent(r.intent), r.resultCode,
Dianne Hackborn68d881c2009-10-05 13:58:17 -070012456 r.resultData, r.resultExtras, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012457 } catch (RemoteException e) {
12458 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
12459 }
12460 }
12461
12462 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
12463 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
12464
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012465 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
12466 + r);
12467
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012468 // ... and on to the next...
Dianne Hackborn12527f92009-11-11 17:39:50 -080012469 addBroadcastToHistoryLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012470 mOrderedBroadcasts.remove(0);
12471 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012472 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012473 continue;
12474 }
12475 } while (r == null);
12476
12477 // Get the next receiver...
12478 int recIdx = r.nextReceiver++;
12479
12480 // Keep track of when this receiver started, and make sure there
12481 // is a timeout message pending to kill it if need be.
Dianne Hackborn12527f92009-11-11 17:39:50 -080012482 r.receiverTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012483 if (recIdx == 0) {
Dianne Hackborn12527f92009-11-11 17:39:50 -080012484 r.dispatchTime = r.receiverTime;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012485
Dianne Hackborn82f3f002009-06-16 18:49:05 -070012486 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
12487 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012488 if (DEBUG_BROADCAST) Log.v(TAG,
12489 "Submitting BROADCAST_TIMEOUT_MSG for "
Dianne Hackborn12527f92009-11-11 17:39:50 -080012490 + (r.receiverTime + BROADCAST_TIMEOUT));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012491 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
Dianne Hackborn12527f92009-11-11 17:39:50 -080012492 mHandler.sendMessageAtTime(msg, r.receiverTime+BROADCAST_TIMEOUT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012493 }
12494
12495 Object nextReceiver = r.receivers.get(recIdx);
12496 if (nextReceiver instanceof BroadcastFilter) {
12497 // Simple case: this is a registered receiver who gets
12498 // a direct call.
12499 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
12500 if (DEBUG_BROADCAST) Log.v(TAG,
12501 "Delivering serialized to registered "
12502 + filter + ": " + r);
12503 deliverToRegisteredReceiver(r, filter, r.ordered);
12504 if (r.receiver == null || !r.ordered) {
12505 // The receiver has already finished, so schedule to
12506 // process the next one.
12507 r.state = BroadcastRecord.IDLE;
12508 scheduleBroadcastsLocked();
12509 }
12510 return;
12511 }
12512
12513 // Hard case: need to instantiate the receiver, possibly
12514 // starting its application process to host it.
12515
12516 ResolveInfo info =
12517 (ResolveInfo)nextReceiver;
12518
12519 boolean skip = false;
12520 int perm = checkComponentPermission(info.activityInfo.permission,
12521 r.callingPid, r.callingUid,
12522 info.activityInfo.exported
12523 ? -1 : info.activityInfo.applicationInfo.uid);
12524 if (perm != PackageManager.PERMISSION_GRANTED) {
12525 Log.w(TAG, "Permission Denial: broadcasting "
12526 + r.intent.toString()
12527 + " from " + r.callerPackage + " (pid=" + r.callingPid
12528 + ", uid=" + r.callingUid + ")"
12529 + " requires " + info.activityInfo.permission
12530 + " due to receiver " + info.activityInfo.packageName
12531 + "/" + info.activityInfo.name);
12532 skip = true;
12533 }
12534 if (r.callingUid != Process.SYSTEM_UID &&
12535 r.requiredPermission != null) {
12536 try {
12537 perm = ActivityThread.getPackageManager().
12538 checkPermission(r.requiredPermission,
12539 info.activityInfo.applicationInfo.packageName);
12540 } catch (RemoteException e) {
12541 perm = PackageManager.PERMISSION_DENIED;
12542 }
12543 if (perm != PackageManager.PERMISSION_GRANTED) {
12544 Log.w(TAG, "Permission Denial: receiving "
12545 + r.intent + " to "
12546 + info.activityInfo.applicationInfo.packageName
12547 + " requires " + r.requiredPermission
12548 + " due to sender " + r.callerPackage
12549 + " (uid " + r.callingUid + ")");
12550 skip = true;
12551 }
12552 }
12553 if (r.curApp != null && r.curApp.crashing) {
12554 // If the target process is crashing, just skip it.
12555 skip = true;
12556 }
12557
12558 if (skip) {
12559 r.receiver = null;
12560 r.curFilter = null;
12561 r.state = BroadcastRecord.IDLE;
12562 scheduleBroadcastsLocked();
12563 return;
12564 }
12565
12566 r.state = BroadcastRecord.APP_RECEIVE;
12567 String targetProcess = info.activityInfo.processName;
12568 r.curComponent = new ComponentName(
12569 info.activityInfo.applicationInfo.packageName,
12570 info.activityInfo.name);
12571 r.curReceiver = info.activityInfo;
12572
12573 // Is this receiver's application already running?
12574 ProcessRecord app = getProcessRecordLocked(targetProcess,
12575 info.activityInfo.applicationInfo.uid);
12576 if (app != null && app.thread != null) {
12577 try {
12578 processCurBroadcastLocked(r, app);
12579 return;
12580 } catch (RemoteException e) {
12581 Log.w(TAG, "Exception when sending broadcast to "
12582 + r.curComponent, e);
12583 }
12584
12585 // If a dead object exception was thrown -- fall through to
12586 // restart the application.
12587 }
12588
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012589 // Not running -- get it started, to be executed when the app comes up.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012590 if ((r.curApp=startProcessLocked(targetProcess,
12591 info.activityInfo.applicationInfo, true,
12592 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
Dianne Hackborn9acc0302009-08-25 00:27:12 -070012593 "broadcast", r.curComponent,
12594 (r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0))
12595 == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012596 // Ah, this recipient is unavailable. Finish it if necessary,
12597 // and mark the broadcast record as ready for the next.
12598 Log.w(TAG, "Unable to launch app "
12599 + info.activityInfo.applicationInfo.packageName + "/"
12600 + info.activityInfo.applicationInfo.uid + " for broadcast "
12601 + r.intent + ": process is bad");
12602 logBroadcastReceiverDiscard(r);
12603 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12604 r.resultExtras, r.resultAbort, true);
12605 scheduleBroadcastsLocked();
12606 r.state = BroadcastRecord.IDLE;
12607 return;
12608 }
12609
12610 mPendingBroadcast = r;
12611 }
12612 }
12613
12614 // =========================================================
12615 // INSTRUMENTATION
12616 // =========================================================
12617
12618 public boolean startInstrumentation(ComponentName className,
12619 String profileFile, int flags, Bundle arguments,
12620 IInstrumentationWatcher watcher) {
12621 // Refuse possible leaked file descriptors
12622 if (arguments != null && arguments.hasFileDescriptors()) {
12623 throw new IllegalArgumentException("File descriptors passed in Bundle");
12624 }
12625
12626 synchronized(this) {
12627 InstrumentationInfo ii = null;
12628 ApplicationInfo ai = null;
12629 try {
12630 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012631 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012632 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012633 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012634 } catch (PackageManager.NameNotFoundException e) {
12635 }
12636 if (ii == null) {
12637 reportStartInstrumentationFailure(watcher, className,
12638 "Unable to find instrumentation info for: " + className);
12639 return false;
12640 }
12641 if (ai == null) {
12642 reportStartInstrumentationFailure(watcher, className,
12643 "Unable to find instrumentation target package: " + ii.targetPackage);
12644 return false;
12645 }
12646
12647 int match = mContext.getPackageManager().checkSignatures(
12648 ii.targetPackage, ii.packageName);
12649 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12650 String msg = "Permission Denial: starting instrumentation "
12651 + className + " from pid="
12652 + Binder.getCallingPid()
12653 + ", uid=" + Binder.getCallingPid()
12654 + " not allowed because package " + ii.packageName
12655 + " does not have a signature matching the target "
12656 + ii.targetPackage;
12657 reportStartInstrumentationFailure(watcher, className, msg);
12658 throw new SecurityException(msg);
12659 }
12660
12661 final long origId = Binder.clearCallingIdentity();
12662 uninstallPackageLocked(ii.targetPackage, -1, true);
12663 ProcessRecord app = addAppLocked(ai);
12664 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012665 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012666 app.instrumentationProfileFile = profileFile;
12667 app.instrumentationArguments = arguments;
12668 app.instrumentationWatcher = watcher;
12669 app.instrumentationResultClass = className;
12670 Binder.restoreCallingIdentity(origId);
12671 }
12672
12673 return true;
12674 }
12675
12676 /**
12677 * Report errors that occur while attempting to start Instrumentation. Always writes the
12678 * error to the logs, but if somebody is watching, send the report there too. This enables
12679 * the "am" command to report errors with more information.
12680 *
12681 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12682 * @param cn The component name of the instrumentation.
12683 * @param report The error report.
12684 */
12685 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12686 ComponentName cn, String report) {
12687 Log.w(TAG, report);
12688 try {
12689 if (watcher != null) {
12690 Bundle results = new Bundle();
12691 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12692 results.putString("Error", report);
12693 watcher.instrumentationStatus(cn, -1, results);
12694 }
12695 } catch (RemoteException e) {
12696 Log.w(TAG, e);
12697 }
12698 }
12699
12700 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12701 if (app.instrumentationWatcher != null) {
12702 try {
12703 // NOTE: IInstrumentationWatcher *must* be oneway here
12704 app.instrumentationWatcher.instrumentationFinished(
12705 app.instrumentationClass,
12706 resultCode,
12707 results);
12708 } catch (RemoteException e) {
12709 }
12710 }
12711 app.instrumentationWatcher = null;
12712 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012713 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012714 app.instrumentationProfileFile = null;
12715 app.instrumentationArguments = null;
12716
12717 uninstallPackageLocked(app.processName, -1, false);
12718 }
12719
12720 public void finishInstrumentation(IApplicationThread target,
12721 int resultCode, Bundle results) {
12722 // Refuse possible leaked file descriptors
12723 if (results != null && results.hasFileDescriptors()) {
12724 throw new IllegalArgumentException("File descriptors passed in Intent");
12725 }
12726
12727 synchronized(this) {
12728 ProcessRecord app = getRecordForAppLocked(target);
12729 if (app == null) {
12730 Log.w(TAG, "finishInstrumentation: no app for " + target);
12731 return;
12732 }
12733 final long origId = Binder.clearCallingIdentity();
12734 finishInstrumentationLocked(app, resultCode, results);
12735 Binder.restoreCallingIdentity(origId);
12736 }
12737 }
12738
12739 // =========================================================
12740 // CONFIGURATION
12741 // =========================================================
12742
12743 public ConfigurationInfo getDeviceConfigurationInfo() {
12744 ConfigurationInfo config = new ConfigurationInfo();
12745 synchronized (this) {
12746 config.reqTouchScreen = mConfiguration.touchscreen;
12747 config.reqKeyboardType = mConfiguration.keyboard;
12748 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012749 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12750 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012751 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12752 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012753 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12754 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012755 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12756 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012757 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012758 }
12759 return config;
12760 }
12761
12762 public Configuration getConfiguration() {
12763 Configuration ci;
12764 synchronized(this) {
12765 ci = new Configuration(mConfiguration);
12766 }
12767 return ci;
12768 }
12769
12770 public void updateConfiguration(Configuration values) {
12771 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12772 "updateConfiguration()");
12773
12774 synchronized(this) {
12775 if (values == null && mWindowManager != null) {
12776 // sentinel: fetch the current configuration from the window manager
12777 values = mWindowManager.computeNewConfiguration();
12778 }
12779
12780 final long origId = Binder.clearCallingIdentity();
12781 updateConfigurationLocked(values, null);
12782 Binder.restoreCallingIdentity(origId);
12783 }
12784 }
12785
12786 /**
12787 * Do either or both things: (1) change the current configuration, and (2)
12788 * make sure the given activity is running with the (now) current
12789 * configuration. Returns true if the activity has been left running, or
12790 * false if <var>starting</var> is being destroyed to match the new
12791 * configuration.
12792 */
12793 public boolean updateConfigurationLocked(Configuration values,
12794 HistoryRecord starting) {
12795 int changes = 0;
12796
12797 boolean kept = true;
12798
12799 if (values != null) {
12800 Configuration newConfig = new Configuration(mConfiguration);
12801 changes = newConfig.updateFrom(values);
12802 if (changes != 0) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012803 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012804 Log.i(TAG, "Updating configuration to: " + values);
12805 }
12806
Doug Zongker2bec3d42009-12-04 12:52:44 -080012807 EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012808
12809 if (values.locale != null) {
12810 saveLocaleLocked(values.locale,
12811 !values.locale.equals(mConfiguration.locale),
12812 values.userSetLocale);
12813 }
12814
12815 mConfiguration = newConfig;
Dianne Hackborna8f60182009-09-01 19:01:50 -070012816 Log.i(TAG, "Config changed: " + newConfig);
Dianne Hackborn826d17c2009-11-12 12:55:51 -080012817
12818 AttributeCache ac = AttributeCache.instance();
12819 if (ac != null) {
12820 ac.updateConfiguration(mConfiguration);
12821 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012822
12823 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12824 msg.obj = new Configuration(mConfiguration);
12825 mHandler.sendMessage(msg);
12826
12827 final int N = mLRUProcesses.size();
12828 for (int i=0; i<N; i++) {
12829 ProcessRecord app = mLRUProcesses.get(i);
12830 try {
12831 if (app.thread != null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012832 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending to proc "
12833 + app.processName + " new config " + mConfiguration);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012834 app.thread.scheduleConfigurationChanged(mConfiguration);
12835 }
12836 } catch (Exception e) {
12837 }
12838 }
12839 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
Dianne Hackborn362d5b92009-11-11 18:04:39 -080012840 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012841 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12842 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackborn362d5b92009-11-11 18:04:39 -080012843 if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) {
12844 broadcastIntentLocked(null, null,
12845 new Intent(Intent.ACTION_LOCALE_CHANGED),
12846 null, null, 0, null, null,
12847 null, false, false, MY_PID, Process.SYSTEM_UID);
12848 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012849 }
12850 }
12851
12852 if (changes != 0 && starting == null) {
12853 // If the configuration changed, and the caller is not already
12854 // in the process of starting an activity, then find the top
12855 // activity to check if its configuration needs to change.
12856 starting = topRunningActivityLocked(null);
12857 }
12858
12859 if (starting != null) {
12860 kept = ensureActivityConfigurationLocked(starting, changes);
12861 if (kept) {
12862 // If this didn't result in the starting activity being
12863 // destroyed, then we need to make sure at this point that all
12864 // other activities are made visible.
12865 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12866 + ", ensuring others are correct.");
12867 ensureActivitiesVisibleLocked(starting, changes);
12868 }
12869 }
12870
12871 return kept;
12872 }
12873
12874 private final boolean relaunchActivityLocked(HistoryRecord r,
12875 int changes, boolean andResume) {
12876 List<ResultInfo> results = null;
12877 List<Intent> newIntents = null;
12878 if (andResume) {
12879 results = r.results;
12880 newIntents = r.newIntents;
12881 }
12882 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12883 + " with results=" + results + " newIntents=" + newIntents
12884 + " andResume=" + andResume);
Doug Zongker2bec3d42009-12-04 12:52:44 -080012885 EventLog.writeEvent(andResume ? EventLogTags.AM_RELAUNCH_RESUME_ACTIVITY
12886 : EventLogTags.AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012887 r.task.taskId, r.shortComponentName);
12888
12889 r.startFreezingScreenLocked(r.app, 0);
12890
12891 try {
12892 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12893 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12894 changes, !andResume);
12895 // Note: don't need to call pauseIfSleepingLocked() here, because
12896 // the caller will only pass in 'andResume' if this activity is
12897 // currently resumed, which implies we aren't sleeping.
12898 } catch (RemoteException e) {
12899 return false;
12900 }
12901
12902 if (andResume) {
12903 r.results = null;
12904 r.newIntents = null;
Dianne Hackborn1bcf5a82009-09-30 15:22:29 -070012905 reportResumedActivityLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012906 }
12907
12908 return true;
12909 }
12910
12911 /**
12912 * Make sure the given activity matches the current configuration. Returns
12913 * false if the activity had to be destroyed. Returns true if the
12914 * configuration is the same, or the activity will remain running as-is
12915 * for whatever reason. Ensures the HistoryRecord is updated with the
12916 * correct configuration and all other bookkeeping is handled.
12917 */
12918 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12919 int globalChanges) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012920 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12921 "Ensuring correct configuration: " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012922
12923 // Short circuit: if the two configurations are the exact same
12924 // object (the common case), then there is nothing to do.
12925 Configuration newConfig = mConfiguration;
12926 if (r.configuration == newConfig) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012927 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12928 "Configuration unchanged in " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012929 return true;
12930 }
12931
12932 // We don't worry about activities that are finishing.
12933 if (r.finishing) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012934 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012935 "Configuration doesn't matter in finishing " + r);
12936 r.stopFreezingScreenLocked(false);
12937 return true;
12938 }
12939
12940 // Okay we now are going to make this activity have the new config.
12941 // But then we need to figure out how it needs to deal with that.
12942 Configuration oldConfig = r.configuration;
12943 r.configuration = newConfig;
12944
12945 // If the activity isn't currently running, just leave the new
12946 // configuration and it will pick that up next time it starts.
12947 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012948 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012949 "Configuration doesn't matter not running " + r);
12950 r.stopFreezingScreenLocked(false);
12951 return true;
12952 }
12953
12954 // If the activity isn't persistent, there is a chance we will
12955 // need to restart it.
12956 if (!r.persistent) {
12957
12958 // Figure out what has changed between the two configurations.
12959 int changes = oldConfig.diff(newConfig);
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012960 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) {
12961 Log.v(TAG, "Checking to restart " + r.info.name + ": changed=0x"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012962 + Integer.toHexString(changes) + ", handles=0x"
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012963 + Integer.toHexString(r.info.configChanges)
12964 + ", newConfig=" + newConfig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012965 }
12966 if ((changes&(~r.info.configChanges)) != 0) {
12967 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12968 r.configChangeFlags |= changes;
12969 r.startFreezingScreenLocked(r.app, globalChanges);
12970 if (r.app == null || r.app.thread == null) {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012971 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12972 "Switch is destroying non-running " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012973 destroyActivityLocked(r, true);
12974 } else if (r.state == ActivityState.PAUSING) {
12975 // A little annoying: we are waiting for this activity to
12976 // finish pausing. Let's not do anything now, but just
12977 // flag that it needs to be restarted when done pausing.
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012978 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12979 "Switch is skipping already pausing " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012980 r.configDestroy = true;
12981 return true;
12982 } else if (r.state == ActivityState.RESUMED) {
12983 // Try to optimize this case: the configuration is changing
12984 // and we need to restart the top, resumed activity.
12985 // Instead of doing the normal handshaking, just say
12986 // "restart!".
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012987 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12988 "Switch is restarting resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012989 relaunchActivityLocked(r, r.configChangeFlags, true);
12990 r.configChangeFlags = 0;
12991 } else {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070012992 if (DEBUG_SWITCH || DEBUG_CONFIGURATION) Log.v(TAG,
12993 "Switch is restarting non-resumed " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012994 relaunchActivityLocked(r, r.configChangeFlags, false);
12995 r.configChangeFlags = 0;
12996 }
12997
12998 // All done... tell the caller we weren't able to keep this
12999 // activity around.
13000 return false;
13001 }
13002 }
13003
13004 // Default case: the activity can handle this new configuration, so
13005 // hand it over. Note that we don't need to give it the new
13006 // configuration, since we always send configuration changes to all
13007 // process when they happen so it can just use whatever configuration
13008 // it last got.
13009 if (r.app != null && r.app.thread != null) {
13010 try {
Dianne Hackborndc6b6352009-09-30 14:20:09 -070013011 if (DEBUG_CONFIGURATION) Log.v(TAG, "Sending new config to " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013012 r.app.thread.scheduleActivityConfigurationChanged(r);
13013 } catch (RemoteException e) {
13014 // If process died, whatever.
13015 }
13016 }
13017 r.stopFreezingScreenLocked(false);
13018
13019 return true;
13020 }
13021
13022 /**
13023 * Save the locale. You must be inside a synchronized (this) block.
13024 */
13025 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
13026 if(isDiff) {
13027 SystemProperties.set("user.language", l.getLanguage());
13028 SystemProperties.set("user.region", l.getCountry());
13029 }
13030
13031 if(isPersist) {
13032 SystemProperties.set("persist.sys.language", l.getLanguage());
13033 SystemProperties.set("persist.sys.country", l.getCountry());
13034 SystemProperties.set("persist.sys.localevar", l.getVariant());
13035 }
13036 }
13037
13038 // =========================================================
13039 // LIFETIME MANAGEMENT
13040 // =========================================================
13041
13042 private final int computeOomAdjLocked(
13043 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13044 if (mAdjSeq == app.adjSeq) {
13045 // This adjustment has already been computed.
13046 return app.curAdj;
13047 }
13048
13049 if (app.thread == null) {
13050 app.adjSeq = mAdjSeq;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013051 app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013052 return (app.curAdj=EMPTY_APP_ADJ);
13053 }
13054
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013055 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
13056 // The max adjustment doesn't allow this app to be anything
13057 // below foreground, so it is not worth doing work for it.
13058 app.adjType = "fixed";
13059 app.adjSeq = mAdjSeq;
13060 app.curRawAdj = app.maxAdj;
13061 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
13062 return (app.curAdj=app.maxAdj);
13063 }
13064
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013065 app.adjTypeCode = ActivityManager.RunningAppProcessInfo.REASON_UNKNOWN;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013066 app.adjSource = null;
13067 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013068
The Android Open Source Project4df24232009-03-05 14:34:35 -080013069 // Determine the importance of the process, starting with most
13070 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013071 int adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013072 int schedGroup;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013073 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013074 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013075 // The last app on the list is the foreground app.
13076 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013077 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013078 app.adjType = "top-activity";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013079 } else if (app.instrumentationClass != null) {
13080 // Don't want to kill running instrumentation.
13081 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013082 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013083 app.adjType = "instrumentation";
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013084 } else if (app.persistentActivities > 0) {
13085 // Special persistent activities... shouldn't be used these days.
13086 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013087 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013088 app.adjType = "persistent";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013089 } else if (app.curReceiver != null ||
13090 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
13091 // An app that is currently receiving a broadcast also
13092 // counts as being in the foreground.
13093 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013094 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013095 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013096 } else if (app.executingServices.size() > 0) {
13097 // An app that is currently executing a service callback also
13098 // counts as being in the foreground.
13099 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013100 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013101 app.adjType = "exec-service";
13102 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013103 // The user is aware of this app, so make it visible.
13104 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013105 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013106 app.adjType = "foreground-service";
13107 } else if (app.forcingToForeground != null) {
13108 // The user is aware of this app, so make it visible.
13109 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013110 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013111 app.adjType = "force-foreground";
13112 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080013113 } else if (app == mHomeProcess) {
13114 // This process is hosting what we currently consider to be the
13115 // home app, so we don't want to let it go into the background.
13116 adj = HOME_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013117 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013118 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013119 } else if ((N=app.activities.size()) != 0) {
13120 // This app is in the background with paused activities.
13121 adj = hiddenAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013122 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013123 app.adjType = "bg-activities";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013124 for (int j=0; j<N; j++) {
13125 if (((HistoryRecord)app.activities.get(j)).visible) {
13126 // This app has a visible activity!
13127 adj = VISIBLE_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013128 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013129 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013130 break;
13131 }
13132 }
13133 } else {
13134 // A very not-needed process.
13135 adj = EMPTY_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013136 schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013137 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013138 }
13139
The Android Open Source Project4df24232009-03-05 14:34:35 -080013140 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013141 // there are applications dependent on our services or providers, but
13142 // this gives us a baseline and makes sure we don't get into an
13143 // infinite recursion.
13144 app.adjSeq = mAdjSeq;
13145 app.curRawAdj = adj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013146
Christopher Tate6fa95972009-06-05 18:43:55 -070013147 if (mBackupTarget != null && app == mBackupTarget.app) {
13148 // If possible we want to avoid killing apps while they're being backed up
13149 if (adj > BACKUP_APP_ADJ) {
13150 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
13151 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013152 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070013153 }
13154 }
13155
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013156 if (app.services.size() != 0 && (adj > FOREGROUND_APP_ADJ
13157 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013158 final long now = SystemClock.uptimeMillis();
13159 // This process is more important if the top activity is
13160 // bound to the service.
13161 Iterator jt = app.services.iterator();
13162 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13163 ServiceRecord s = (ServiceRecord)jt.next();
13164 if (s.startRequested) {
13165 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
13166 // This service has seen some activity within
13167 // recent memory, so we will keep its process ahead
13168 // of the background processes.
13169 if (adj > SECONDARY_SERVER_ADJ) {
13170 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013171 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013172 }
13173 }
13174 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013175 if (s.connections.size() > 0 && (adj > FOREGROUND_APP_ADJ
13176 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013177 Iterator<ConnectionRecord> kt
13178 = s.connections.values().iterator();
13179 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13180 // XXX should compute this based on the max of
13181 // all connected clients.
13182 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013183 if (cr.binding.client == app) {
13184 // Binding to ourself is not interesting.
13185 continue;
13186 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013187 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
13188 ProcessRecord client = cr.binding.client;
13189 int myHiddenAdj = hiddenAdj;
13190 if (myHiddenAdj > client.hiddenAdj) {
13191 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
13192 myHiddenAdj = client.hiddenAdj;
13193 } else {
13194 myHiddenAdj = VISIBLE_APP_ADJ;
13195 }
13196 }
13197 int clientAdj = computeOomAdjLocked(
13198 client, myHiddenAdj, TOP_APP);
13199 if (adj > clientAdj) {
13200 adj = clientAdj > VISIBLE_APP_ADJ
13201 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013202 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013203 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13204 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013205 app.adjSource = cr.binding.client;
13206 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013207 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013208 if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
13209 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13210 schedGroup = Process.THREAD_GROUP_DEFAULT;
13211 }
13212 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013213 }
13214 HistoryRecord a = cr.activity;
13215 //if (a != null) {
13216 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
13217 //}
13218 if (a != null && adj > FOREGROUND_APP_ADJ &&
13219 (a.state == ActivityState.RESUMED
13220 || a.state == ActivityState.PAUSING)) {
13221 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013222 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013223 app.adjType = "service";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013224 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13225 .REASON_SERVICE_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013226 app.adjSource = a;
13227 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013228 }
13229 }
13230 }
13231 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013232
13233 // Finally, f this process has active services running in it, we
13234 // would like to avoid killing it unless it would prevent the current
13235 // application from running. By default we put the process in
13236 // with the rest of the background processes; as we scan through
13237 // its services we may bump it up from there.
13238 if (adj > hiddenAdj) {
13239 adj = hiddenAdj;
13240 app.adjType = "bg-services";
13241 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013242 }
13243
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013244 if (app.pubProviders.size() != 0 && (adj > FOREGROUND_APP_ADJ
13245 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013246 Iterator jt = app.pubProviders.values().iterator();
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013247 while (jt.hasNext() && (adj > FOREGROUND_APP_ADJ
13248 || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013249 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
13250 if (cpr.clients.size() != 0) {
13251 Iterator<ProcessRecord> kt = cpr.clients.iterator();
13252 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
13253 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070013254 if (client == app) {
13255 // Being our own client is not interesting.
13256 continue;
13257 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013258 int myHiddenAdj = hiddenAdj;
13259 if (myHiddenAdj > client.hiddenAdj) {
13260 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
13261 myHiddenAdj = client.hiddenAdj;
13262 } else {
13263 myHiddenAdj = FOREGROUND_APP_ADJ;
13264 }
13265 }
13266 int clientAdj = computeOomAdjLocked(
13267 client, myHiddenAdj, TOP_APP);
13268 if (adj > clientAdj) {
13269 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013270 ? clientAdj : FOREGROUND_APP_ADJ;
13271 app.adjType = "provider";
Dianne Hackborndd9b82c2009-09-03 00:18:47 -070013272 app.adjTypeCode = ActivityManager.RunningAppProcessInfo
13273 .REASON_PROVIDER_IN_USE;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013274 app.adjSource = client;
13275 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013276 }
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013277 if (client.curSchedGroup == Process.THREAD_GROUP_DEFAULT) {
13278 schedGroup = Process.THREAD_GROUP_DEFAULT;
13279 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013280 }
13281 }
13282 // If the provider has external (non-framework) process
13283 // dependencies, ensure that its adjustment is at least
13284 // FOREGROUND_APP_ADJ.
13285 if (cpr.externals != 0) {
13286 if (adj > FOREGROUND_APP_ADJ) {
13287 adj = FOREGROUND_APP_ADJ;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013288 schedGroup = Process.THREAD_GROUP_DEFAULT;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070013289 app.adjType = "provider";
13290 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013291 }
13292 }
13293 }
Dianne Hackbornbcbcaa72009-09-10 10:54:46 -070013294
13295 // Finally, if this process has published any content providers,
13296 // then its adjustment makes it at least as important as any of the
13297 // processes using those providers, and no less important than
13298 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
13299 if (adj > CONTENT_PROVIDER_ADJ) {
13300 adj = CONTENT_PROVIDER_ADJ;
13301 app.adjType = "pub-providers";
13302 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013303 }
13304
13305 app.curRawAdj = adj;
13306
13307 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
13308 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
13309 if (adj > app.maxAdj) {
13310 adj = app.maxAdj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013311 if (app.maxAdj <= VISIBLE_APP_ADJ) {
13312 schedGroup = Process.THREAD_GROUP_DEFAULT;
13313 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013314 }
13315
13316 app.curAdj = adj;
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013317 app.curSchedGroup = schedGroup;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013318
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013319 return adj;
13320 }
13321
13322 /**
13323 * Ask a given process to GC right now.
13324 */
13325 final void performAppGcLocked(ProcessRecord app) {
13326 try {
13327 app.lastRequestedGc = SystemClock.uptimeMillis();
13328 if (app.thread != null) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013329 if (app.reportLowMemory) {
13330 app.reportLowMemory = false;
13331 app.thread.scheduleLowMemory();
13332 } else {
13333 app.thread.processInBackground();
13334 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013335 }
13336 } catch (Exception e) {
13337 // whatever.
13338 }
13339 }
13340
13341 /**
13342 * Returns true if things are idle enough to perform GCs.
13343 */
13344 private final boolean canGcNow() {
13345 return mParallelBroadcasts.size() == 0
13346 && mOrderedBroadcasts.size() == 0
13347 && (mSleeping || (mResumedActivity != null &&
13348 mResumedActivity.idle));
13349 }
13350
13351 /**
13352 * Perform GCs on all processes that are waiting for it, but only
13353 * if things are idle.
13354 */
13355 final void performAppGcsLocked() {
13356 final int N = mProcessesToGc.size();
13357 if (N <= 0) {
13358 return;
13359 }
13360 if (canGcNow()) {
13361 while (mProcessesToGc.size() > 0) {
13362 ProcessRecord proc = mProcessesToGc.remove(0);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013363 if (proc.curRawAdj > VISIBLE_APP_ADJ || proc.reportLowMemory) {
13364 if ((proc.lastRequestedGc+GC_MIN_INTERVAL)
13365 <= SystemClock.uptimeMillis()) {
13366 // To avoid spamming the system, we will GC processes one
13367 // at a time, waiting a few seconds between each.
13368 performAppGcLocked(proc);
13369 scheduleAppGcsLocked();
13370 return;
13371 } else {
13372 // It hasn't been long enough since we last GCed this
13373 // process... put it in the list to wait for its time.
13374 addProcessToGcListLocked(proc);
13375 break;
13376 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013377 }
13378 }
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013379
13380 scheduleAppGcsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013381 }
13382 }
13383
13384 /**
13385 * If all looks good, perform GCs on all processes waiting for them.
13386 */
13387 final void performAppGcsIfAppropriateLocked() {
13388 if (canGcNow()) {
13389 performAppGcsLocked();
13390 return;
13391 }
13392 // Still not idle, wait some more.
13393 scheduleAppGcsLocked();
13394 }
13395
13396 /**
13397 * Schedule the execution of all pending app GCs.
13398 */
13399 final void scheduleAppGcsLocked() {
13400 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013401
13402 if (mProcessesToGc.size() > 0) {
13403 // Schedule a GC for the time to the next process.
13404 ProcessRecord proc = mProcessesToGc.get(0);
13405 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
13406
13407 long when = mProcessesToGc.get(0).lastRequestedGc + GC_MIN_INTERVAL;
13408 long now = SystemClock.uptimeMillis();
13409 if (when < (now+GC_TIMEOUT)) {
13410 when = now + GC_TIMEOUT;
13411 }
13412 mHandler.sendMessageAtTime(msg, when);
13413 }
13414 }
13415
13416 /**
13417 * Add a process to the array of processes waiting to be GCed. Keeps the
13418 * list in sorted order by the last GC time. The process can't already be
13419 * on the list.
13420 */
13421 final void addProcessToGcListLocked(ProcessRecord proc) {
13422 boolean added = false;
13423 for (int i=mProcessesToGc.size()-1; i>=0; i--) {
13424 if (mProcessesToGc.get(i).lastRequestedGc <
13425 proc.lastRequestedGc) {
13426 added = true;
13427 mProcessesToGc.add(i+1, proc);
13428 break;
13429 }
13430 }
13431 if (!added) {
13432 mProcessesToGc.add(0, proc);
13433 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013434 }
13435
13436 /**
13437 * Set up to ask a process to GC itself. This will either do it
13438 * immediately, or put it on the list of processes to gc the next
13439 * time things are idle.
13440 */
13441 final void scheduleAppGcLocked(ProcessRecord app) {
13442 long now = SystemClock.uptimeMillis();
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013443 if ((app.lastRequestedGc+GC_MIN_INTERVAL) > now) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013444 return;
13445 }
13446 if (!mProcessesToGc.contains(app)) {
Dianne Hackbornfd12af42009-08-27 00:44:33 -070013447 addProcessToGcListLocked(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013448 scheduleAppGcsLocked();
13449 }
13450 }
13451
13452 private final boolean updateOomAdjLocked(
13453 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
13454 app.hiddenAdj = hiddenAdj;
13455
13456 if (app.thread == null) {
13457 return true;
13458 }
13459
13460 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
13461
Dianne Hackborn09c916b2009-12-08 14:50:51 -080013462 if ((app.pid != 0 && app.pid != MY_PID) || Process.supportsProcesses()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013463 if (app.curRawAdj != app.setRawAdj) {
13464 if (app.curRawAdj > FOREGROUND_APP_ADJ
13465 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
13466 // If this app is transitioning from foreground to
13467 // non-foreground, have it do a gc.
13468 scheduleAppGcLocked(app);
13469 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
13470 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
13471 // Likewise do a gc when an app is moving in to the
13472 // background (such as a service stopping).
13473 scheduleAppGcLocked(app);
13474 }
13475 app.setRawAdj = app.curRawAdj;
13476 }
13477 if (adj != app.setAdj) {
13478 if (Process.setOomAdj(app.pid, adj)) {
13479 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
13480 TAG, "Set app " + app.processName +
13481 " oom adj to " + adj);
13482 app.setAdj = adj;
13483 } else {
13484 return false;
13485 }
13486 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013487 if (app.setSchedGroup != app.curSchedGroup) {
13488 app.setSchedGroup = app.curSchedGroup;
13489 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
13490 "Setting process group of " + app.processName
13491 + " to " + app.curSchedGroup);
13492 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070013493 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013494 try {
13495 Process.setProcessGroup(app.pid, app.curSchedGroup);
13496 } catch (Exception e) {
13497 Log.w(TAG, "Failed setting process group of " + app.pid
13498 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070013499 e.printStackTrace();
13500 } finally {
13501 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070013502 }
13503 }
13504 if (false) {
13505 if (app.thread != null) {
13506 try {
13507 app.thread.setSchedulingGroup(app.curSchedGroup);
13508 } catch (RemoteException e) {
13509 }
13510 }
13511 }
13512 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013513 }
13514
13515 return true;
13516 }
13517
13518 private final HistoryRecord resumedAppLocked() {
13519 HistoryRecord resumedActivity = mResumedActivity;
13520 if (resumedActivity == null || resumedActivity.app == null) {
13521 resumedActivity = mPausingActivity;
13522 if (resumedActivity == null || resumedActivity.app == null) {
13523 resumedActivity = topRunningActivityLocked(null);
13524 }
13525 }
13526 return resumedActivity;
13527 }
13528
13529 private final boolean updateOomAdjLocked(ProcessRecord app) {
13530 final HistoryRecord TOP_ACT = resumedAppLocked();
13531 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13532 int curAdj = app.curAdj;
13533 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13534 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13535
13536 mAdjSeq++;
13537
13538 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
13539 if (res) {
13540 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
13541 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
13542 if (nowHidden != wasHidden) {
13543 // Changed to/from hidden state, so apps after it in the LRU
13544 // list may also be changed.
13545 updateOomAdjLocked();
13546 }
13547 }
13548 return res;
13549 }
13550
13551 private final boolean updateOomAdjLocked() {
13552 boolean didOomAdj = true;
13553 final HistoryRecord TOP_ACT = resumedAppLocked();
13554 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
13555
13556 if (false) {
13557 RuntimeException e = new RuntimeException();
13558 e.fillInStackTrace();
13559 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
13560 }
13561
13562 mAdjSeq++;
13563
13564 // First try updating the OOM adjustment for each of the
13565 // application processes based on their current state.
13566 int i = mLRUProcesses.size();
13567 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
13568 while (i > 0) {
13569 i--;
13570 ProcessRecord app = mLRUProcesses.get(i);
13571 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
13572 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
13573 && app.curAdj == curHiddenAdj) {
13574 curHiddenAdj++;
13575 }
13576 } else {
13577 didOomAdj = false;
13578 }
13579 }
13580
13581 // todo: for now pretend like OOM ADJ didn't work, because things
13582 // aren't behaving as expected on Linux -- it's not killing processes.
13583 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
13584 }
13585
13586 private final void trimApplications() {
13587 synchronized (this) {
13588 int i;
13589
13590 // First remove any unused application processes whose package
13591 // has been removed.
13592 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
13593 final ProcessRecord app = mRemovedProcesses.get(i);
13594 if (app.activities.size() == 0
13595 && app.curReceiver == null && app.services.size() == 0) {
13596 Log.i(
13597 TAG, "Exiting empty application process "
13598 + app.processName + " ("
13599 + (app.thread != null ? app.thread.asBinder() : null)
13600 + ")\n");
13601 if (app.pid > 0 && app.pid != MY_PID) {
13602 Process.killProcess(app.pid);
13603 } else {
13604 try {
13605 app.thread.scheduleExit();
13606 } catch (Exception e) {
13607 // Ignore exceptions.
13608 }
13609 }
13610 cleanUpApplicationRecordLocked(app, false, -1);
13611 mRemovedProcesses.remove(i);
13612
13613 if (app.persistent) {
13614 if (app.persistent) {
13615 addAppLocked(app.info);
13616 }
13617 }
13618 }
13619 }
13620
13621 // Now try updating the OOM adjustment for each of the
13622 // application processes based on their current state.
13623 // If the setOomAdj() API is not supported, then go with our
13624 // back-up plan...
13625 if (!updateOomAdjLocked()) {
13626
13627 // Count how many processes are running services.
13628 int numServiceProcs = 0;
13629 for (i=mLRUProcesses.size()-1; i>=0; i--) {
13630 final ProcessRecord app = mLRUProcesses.get(i);
13631
13632 if (app.persistent || app.services.size() != 0
13633 || app.curReceiver != null
13634 || app.persistentActivities > 0) {
13635 // Don't count processes holding services against our
13636 // maximum process count.
13637 if (localLOGV) Log.v(
13638 TAG, "Not trimming app " + app + " with services: "
13639 + app.services);
13640 numServiceProcs++;
13641 }
13642 }
13643
13644 int curMaxProcs = mProcessLimit;
13645 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13646 if (mAlwaysFinishActivities) {
13647 curMaxProcs = 1;
13648 }
13649 curMaxProcs += numServiceProcs;
13650
13651 // Quit as many processes as we can to get down to the desired
13652 // process count. First remove any processes that no longer
13653 // have activites running in them.
13654 for ( i=0;
13655 i<mLRUProcesses.size()
13656 && mLRUProcesses.size() > curMaxProcs;
13657 i++) {
13658 final ProcessRecord app = mLRUProcesses.get(i);
13659 // Quit an application only if it is not currently
13660 // running any activities.
13661 if (!app.persistent && app.activities.size() == 0
13662 && app.curReceiver == null && app.services.size() == 0) {
13663 Log.i(
13664 TAG, "Exiting empty application process "
13665 + app.processName + " ("
13666 + (app.thread != null ? app.thread.asBinder() : null)
13667 + ")\n");
13668 if (app.pid > 0 && app.pid != MY_PID) {
13669 Process.killProcess(app.pid);
13670 } else {
13671 try {
13672 app.thread.scheduleExit();
13673 } catch (Exception e) {
13674 // Ignore exceptions.
13675 }
13676 }
13677 // todo: For now we assume the application is not buggy
13678 // or evil, and will quit as a result of our request.
13679 // Eventually we need to drive this off of the death
13680 // notification, and kill the process if it takes too long.
13681 cleanUpApplicationRecordLocked(app, false, i);
13682 i--;
13683 }
13684 }
13685
13686 // If we still have too many processes, now from the least
13687 // recently used process we start finishing activities.
13688 if (Config.LOGV) Log.v(
13689 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
13690 " of " + curMaxProcs + " processes");
13691 for ( i=0;
13692 i<mLRUProcesses.size()
13693 && mLRUProcesses.size() > curMaxProcs;
13694 i++) {
13695 final ProcessRecord app = mLRUProcesses.get(i);
13696 // Quit the application only if we have a state saved for
13697 // all of its activities.
13698 boolean canQuit = !app.persistent && app.curReceiver == null
13699 && app.services.size() == 0
13700 && app.persistentActivities == 0;
13701 int NUMA = app.activities.size();
13702 int j;
13703 if (Config.LOGV) Log.v(
13704 TAG, "Looking to quit " + app.processName);
13705 for (j=0; j<NUMA && canQuit; j++) {
13706 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13707 if (Config.LOGV) Log.v(
13708 TAG, " " + r.intent.getComponent().flattenToShortString()
13709 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13710 canQuit = (r.haveState || !r.stateNotNeeded)
13711 && !r.visible && r.stopped;
13712 }
13713 if (canQuit) {
13714 // Finish all of the activities, and then the app itself.
13715 for (j=0; j<NUMA; j++) {
13716 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13717 if (!r.finishing) {
13718 destroyActivityLocked(r, false);
13719 }
13720 r.resultTo = null;
13721 }
13722 Log.i(TAG, "Exiting application process "
13723 + app.processName + " ("
13724 + (app.thread != null ? app.thread.asBinder() : null)
13725 + ")\n");
13726 if (app.pid > 0 && app.pid != MY_PID) {
13727 Process.killProcess(app.pid);
13728 } else {
13729 try {
13730 app.thread.scheduleExit();
13731 } catch (Exception e) {
13732 // Ignore exceptions.
13733 }
13734 }
13735 // todo: For now we assume the application is not buggy
13736 // or evil, and will quit as a result of our request.
13737 // Eventually we need to drive this off of the death
13738 // notification, and kill the process if it takes too long.
13739 cleanUpApplicationRecordLocked(app, false, i);
13740 i--;
13741 //dump();
13742 }
13743 }
13744
13745 }
13746
13747 int curMaxActivities = MAX_ACTIVITIES;
13748 if (mAlwaysFinishActivities) {
13749 curMaxActivities = 1;
13750 }
13751
13752 // Finally, if there are too many activities now running, try to
13753 // finish as many as we can to get back down to the limit.
13754 for ( i=0;
13755 i<mLRUActivities.size()
13756 && mLRUActivities.size() > curMaxActivities;
13757 i++) {
13758 final HistoryRecord r
13759 = (HistoryRecord)mLRUActivities.get(i);
13760
13761 // We can finish this one if we have its icicle saved and
13762 // it is not persistent.
13763 if ((r.haveState || !r.stateNotNeeded) && !r.visible
13764 && r.stopped && !r.persistent && !r.finishing) {
13765 final int origSize = mLRUActivities.size();
13766 destroyActivityLocked(r, true);
13767
13768 // This will remove it from the LRU list, so keep
13769 // our index at the same value. Note that this check to
13770 // see if the size changes is just paranoia -- if
13771 // something unexpected happens, we don't want to end up
13772 // in an infinite loop.
13773 if (origSize > mLRUActivities.size()) {
13774 i--;
13775 }
13776 }
13777 }
13778 }
13779 }
13780
13781 /** This method sends the specified signal to each of the persistent apps */
13782 public void signalPersistentProcesses(int sig) throws RemoteException {
13783 if (sig != Process.SIGNAL_USR1) {
13784 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13785 }
13786
13787 synchronized (this) {
13788 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13789 != PackageManager.PERMISSION_GRANTED) {
13790 throw new SecurityException("Requires permission "
13791 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13792 }
13793
13794 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
13795 ProcessRecord r = mLRUProcesses.get(i);
13796 if (r.thread != null && r.persistent) {
13797 Process.sendSignal(r.pid, sig);
13798 }
13799 }
13800 }
13801 }
13802
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013803 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013804 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013805
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013806 try {
13807 synchronized (this) {
13808 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13809 // its own permission.
13810 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13811 != PackageManager.PERMISSION_GRANTED) {
13812 throw new SecurityException("Requires permission "
13813 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013814 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013815
13816 if (start && fd == null) {
13817 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013818 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013819
13820 ProcessRecord proc = null;
13821 try {
13822 int pid = Integer.parseInt(process);
13823 synchronized (mPidsSelfLocked) {
13824 proc = mPidsSelfLocked.get(pid);
13825 }
13826 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013827 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013828
13829 if (proc == null) {
13830 HashMap<String, SparseArray<ProcessRecord>> all
13831 = mProcessNames.getMap();
13832 SparseArray<ProcessRecord> procs = all.get(process);
13833 if (procs != null && procs.size() > 0) {
13834 proc = procs.valueAt(0);
13835 }
13836 }
13837
13838 if (proc == null || proc.thread == null) {
13839 throw new IllegalArgumentException("Unknown process: " + process);
13840 }
13841
13842 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
13843 if (isSecure) {
13844 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
13845 throw new SecurityException("Process not debuggable: " + proc);
13846 }
13847 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013848
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013849 proc.thread.profilerControl(start, path, fd);
13850 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013851 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013852 }
13853 } catch (RemoteException e) {
13854 throw new IllegalStateException("Process disappeared");
13855 } finally {
13856 if (fd != null) {
13857 try {
13858 fd.close();
13859 } catch (IOException e) {
13860 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013861 }
13862 }
13863 }
13864
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013865 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13866 public void monitor() {
13867 synchronized (this) { }
13868 }
13869}