blob: a4b0685bb979a54b30e4cda6dc8b537a3951d40e [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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.content.pm.ActivityInfo;
56import android.content.pm.ApplicationInfo;
57import android.content.pm.ConfigurationInfo;
58import android.content.pm.IPackageDataObserver;
59import android.content.pm.IPackageManager;
60import android.content.pm.InstrumentationInfo;
61import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070062import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import android.content.pm.ProviderInfo;
64import android.content.pm.ResolveInfo;
65import android.content.pm.ServiceInfo;
66import android.content.res.Configuration;
67import android.graphics.Bitmap;
68import android.net.Uri;
69import android.os.Binder;
70import android.os.Bundle;
71import android.os.Environment;
72import android.os.FileUtils;
73import android.os.Handler;
74import android.os.IBinder;
75import android.os.IPermissionController;
76import android.os.Looper;
77import android.os.Message;
78import android.os.Parcel;
79import android.os.ParcelFileDescriptor;
80import android.os.PowerManager;
81import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070082import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083import android.os.RemoteException;
84import android.os.ServiceManager;
85import android.os.SystemClock;
86import android.os.SystemProperties;
87import android.provider.Checkin;
88import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020089import android.server.data.CrashData;
90import android.server.data.StackTraceElementData;
91import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092import android.text.TextUtils;
93import android.util.Config;
94import android.util.EventLog;
95import android.util.Log;
96import android.util.PrintWriterPrinter;
97import android.util.SparseArray;
98import android.view.Gravity;
99import android.view.LayoutInflater;
100import android.view.View;
101import android.view.WindowManager;
102import android.view.WindowManagerPolicy;
103
104import dalvik.system.Zygote;
105
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200106import java.io.ByteArrayInputStream;
107import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108import java.io.File;
109import java.io.FileDescriptor;
110import java.io.FileInputStream;
111import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200112import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113import java.io.PrintWriter;
114import java.lang.IllegalStateException;
115import java.lang.ref.WeakReference;
116import java.util.ArrayList;
117import java.util.HashMap;
118import java.util.HashSet;
119import java.util.Iterator;
120import java.util.List;
121import java.util.Locale;
122import java.util.Map;
123
124public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
125 static final String TAG = "ActivityManager";
126 static final boolean DEBUG = false;
127 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
128 static final boolean DEBUG_SWITCH = localLOGV || false;
129 static final boolean DEBUG_TASKS = localLOGV || false;
130 static final boolean DEBUG_PAUSE = localLOGV || false;
131 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
132 static final boolean DEBUG_TRANSITION = localLOGV || false;
133 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700134 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 static final boolean DEBUG_SERVICE = localLOGV || false;
136 static final boolean DEBUG_VISBILITY = localLOGV || false;
137 static final boolean DEBUG_PROCESSES = localLOGV || false;
138 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 Tate181fafa2009-05-14 11:12:14 -0700140 static final boolean DEBUG_BACKUP = localLOGV || true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 static final boolean VALIDATE_TOKENS = false;
142 static final boolean SHOW_ACTIVITY_START_TIME = true;
143
144 // Control over CPU and battery monitoring.
145 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
146 static final boolean MONITOR_CPU_USAGE = true;
147 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
148 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
149 static final boolean MONITOR_THREAD_CPU_USAGE = false;
150
151 // Event log tags
152 static final int LOG_CONFIGURATION_CHANGED = 2719;
153 static final int LOG_CPU = 2721;
154 static final int LOG_AM_FINISH_ACTIVITY = 30001;
155 static final int LOG_TASK_TO_FRONT = 30002;
156 static final int LOG_AM_NEW_INTENT = 30003;
157 static final int LOG_AM_CREATE_TASK = 30004;
158 static final int LOG_AM_CREATE_ACTIVITY = 30005;
159 static final int LOG_AM_RESTART_ACTIVITY = 30006;
160 static final int LOG_AM_RESUME_ACTIVITY = 30007;
161 static final int LOG_ANR = 30008;
162 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
163 static final int LOG_AM_PROCESS_BOUND = 30010;
164 static final int LOG_AM_PROCESS_DIED = 30011;
165 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
166 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
167 static final int LOG_AM_PROCESS_START = 30014;
168 static final int LOG_AM_PROCESS_BAD = 30015;
169 static final int LOG_AM_PROCESS_GOOD = 30016;
170 static final int LOG_AM_LOW_MEMORY = 30017;
171 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
172 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
173 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
174 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
175 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
176 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
177 static final int LOG_AM_CREATE_SERVICE = 30030;
178 static final int LOG_AM_DESTROY_SERVICE = 30031;
179 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
180 static final int LOG_AM_DROP_PROCESS = 30033;
181 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
182 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
183 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
184
185 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
186 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
187
Dianne Hackborn1655be42009-05-08 14:29:01 -0700188 // The flags that are set for all calls we make to the package manager.
Dianne Hackborn11b822d2009-07-21 20:03:02 -0700189 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700190
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 private static final String SYSTEM_SECURE = "ro.secure";
192
193 // This is the maximum number of application processes we would like
194 // to have running. Due to the asynchronous nature of things, we can
195 // temporarily go beyond this limit.
196 static final int MAX_PROCESSES = 2;
197
198 // Set to false to leave processes running indefinitely, relying on
199 // the kernel killing them as resources are required.
200 static final boolean ENFORCE_PROCESS_LIMIT = false;
201
202 // This is the maximum number of activities that we would like to have
203 // running at a given time.
204 static final int MAX_ACTIVITIES = 20;
205
206 // Maximum number of recent tasks that we can remember.
207 static final int MAX_RECENT_TASKS = 20;
208
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700209 // Amount of time after a call to stopAppSwitches() during which we will
210 // prevent further untrusted switches from happening.
211 static final long APP_SWITCH_DELAY_TIME = 5*1000;
212
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800213 // How long until we reset a task when the user returns to it. Currently
214 // 30 minutes.
215 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
216
217 // Set to true to disable the icon that is shown while a new activity
218 // is being started.
219 static final boolean SHOW_APP_STARTING_ICON = true;
220
221 // How long we wait until giving up on the last activity to pause. This
222 // is short because it directly impacts the responsiveness of starting the
223 // next activity.
224 static final int PAUSE_TIMEOUT = 500;
225
226 /**
227 * How long we can hold the launch wake lock before giving up.
228 */
229 static final int LAUNCH_TIMEOUT = 10*1000;
230
231 // How long we wait for a launched process to attach to the activity manager
232 // before we decide it's never going to come up for real.
233 static final int PROC_START_TIMEOUT = 10*1000;
234
235 // How long we wait until giving up on the last activity telling us it
236 // is idle.
237 static final int IDLE_TIMEOUT = 10*1000;
238
239 // How long to wait after going idle before forcing apps to GC.
240 static final int GC_TIMEOUT = 5*1000;
241
242 // How long we wait until giving up on an activity telling us it has
243 // finished destroying itself.
244 static final int DESTROY_TIMEOUT = 10*1000;
245
246 // How long we allow a receiver to run before giving up on it.
247 static final int BROADCAST_TIMEOUT = 10*1000;
248
249 // How long we wait for a service to finish executing.
250 static final int SERVICE_TIMEOUT = 20*1000;
251
252 // How long a service needs to be running until restarting its process
253 // is no longer considered to be a relaunch of the service.
254 static final int SERVICE_RESTART_DURATION = 5*1000;
255
256 // Maximum amount of time for there to be no activity on a service before
257 // we consider it non-essential and allow its process to go on the
258 // LRU background list.
259 static final int MAX_SERVICE_INACTIVITY = 10*60*1000;
260
261 // How long we wait until we timeout on key dispatching.
262 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
263
264 // The minimum time we allow between crashes, for us to consider this
265 // application to be bad and stop and its services and reject broadcasts.
266 static final int MIN_CRASH_INTERVAL = 60*1000;
267
268 // How long we wait until we timeout on key dispatching during instrumentation.
269 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
270
271 // OOM adjustments for processes in various states:
272
273 // This is a process without anything currently running in it. Definitely
274 // the first to go! Value set in system/rootdir/init.rc on startup.
275 // This value is initalized in the constructor, careful when refering to
276 // this static variable externally.
277 static int EMPTY_APP_ADJ;
278
279 // This is a process with a content provider that does not have any clients
280 // attached to it. If it did have any clients, its adjustment would be the
281 // one for the highest-priority of those processes.
282 static int CONTENT_PROVIDER_ADJ;
283
284 // This is a process only hosting activities that are not visible,
285 // so it can be killed without any disruption. Value set in
286 // system/rootdir/init.rc on startup.
287 final int HIDDEN_APP_MAX_ADJ;
288 static int HIDDEN_APP_MIN_ADJ;
289
The Android Open Source Project4df24232009-03-05 14:34:35 -0800290 // This is a process holding the home application -- we want to try
291 // avoiding killing it, even if it would normally be in the background,
292 // because the user interacts with it so much.
293 final int HOME_APP_ADJ;
294
Christopher Tate6fa95972009-06-05 18:43:55 -0700295 // This is a process currently hosting a backup operation. Killing it
296 // is not entirely fatal but is generally a bad idea.
297 final int BACKUP_APP_ADJ;
298
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800299 // This is a process holding a secondary server -- killing it will not
300 // have much of an impact as far as the user is concerned. Value set in
301 // system/rootdir/init.rc on startup.
302 final int SECONDARY_SERVER_ADJ;
303
304 // This is a process only hosting activities that are visible to the
305 // user, so we'd prefer they don't disappear. Value set in
306 // system/rootdir/init.rc on startup.
307 final int VISIBLE_APP_ADJ;
308
309 // This is the process running the current foreground app. We'd really
310 // rather not kill it! Value set in system/rootdir/init.rc on startup.
311 final int FOREGROUND_APP_ADJ;
312
313 // This is a process running a core server, such as telephony. Definitely
314 // don't want to kill it, but doing so is not completely fatal.
315 static final int CORE_SERVER_ADJ = -12;
316
317 // The system process runs at the default adjustment.
318 static final int SYSTEM_ADJ = -16;
319
320 // Memory pages are 4K.
321 static final int PAGE_SIZE = 4*1024;
322
Jacek Surazski82a73df2009-06-17 14:33:18 +0200323 // System property defining error report receiver for system apps
324 static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps";
325
326 // System property defining default error report receiver
327 static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default";
328
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 // Corresponding memory levels for above adjustments.
330 final int EMPTY_APP_MEM;
331 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800332 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700333 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334 final int SECONDARY_SERVER_MEM;
335 final int VISIBLE_APP_MEM;
336 final int FOREGROUND_APP_MEM;
337
338 final int MY_PID;
339
340 static final String[] EMPTY_STRING_ARRAY = new String[0];
341
342 enum ActivityState {
343 INITIALIZING,
344 RESUMED,
345 PAUSING,
346 PAUSED,
347 STOPPING,
348 STOPPED,
349 FINISHING,
350 DESTROYING,
351 DESTROYED
352 }
353
354 /**
355 * The back history of all previous (and possibly still
356 * running) activities. It contains HistoryRecord objects.
357 */
358 final ArrayList mHistory = new ArrayList();
359
360 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700361 * Description of a request to start a new activity, which has been held
362 * due to app switches being disabled.
363 */
364 class PendingActivityLaunch {
365 HistoryRecord r;
366 HistoryRecord sourceRecord;
367 Uri[] grantedUriPermissions;
368 int grantedMode;
369 boolean onlyIfNeeded;
370 }
371
372 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
373 = new ArrayList<PendingActivityLaunch>();
374
375 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376 * List of all active broadcasts that are to be executed immediately
377 * (without waiting for another broadcast to finish). Currently this only
378 * contains broadcasts to registered receivers, to avoid spinning up
379 * a bunch of processes to execute IntentReceiver components.
380 */
381 final ArrayList<BroadcastRecord> mParallelBroadcasts
382 = new ArrayList<BroadcastRecord>();
383
384 /**
385 * List of all active broadcasts that are to be executed one at a time.
386 * The object at the top of the list is the currently activity broadcasts;
387 * those after it are waiting for the top to finish..
388 */
389 final ArrayList<BroadcastRecord> mOrderedBroadcasts
390 = new ArrayList<BroadcastRecord>();
391
392 /**
393 * Set when we current have a BROADCAST_INTENT_MSG in flight.
394 */
395 boolean mBroadcastsScheduled = false;
396
397 /**
398 * Set to indicate whether to issue an onUserLeaving callback when a
399 * newly launched activity is being brought in front of us.
400 */
401 boolean mUserLeaving = false;
402
403 /**
404 * When we are in the process of pausing an activity, before starting the
405 * next one, this variable holds the activity that is currently being paused.
406 */
407 HistoryRecord mPausingActivity = null;
408
409 /**
410 * Current activity that is resumed, or null if there is none.
411 */
412 HistoryRecord mResumedActivity = null;
413
414 /**
415 * Activity we have told the window manager to have key focus.
416 */
417 HistoryRecord mFocusedActivity = null;
418
419 /**
420 * This is the last activity that we put into the paused state. This is
421 * used to determine if we need to do an activity transition while sleeping,
422 * when we normally hold the top activity paused.
423 */
424 HistoryRecord mLastPausedActivity = null;
425
426 /**
427 * List of activities that are waiting for a new activity
428 * to become visible before completing whatever operation they are
429 * supposed to do.
430 */
431 final ArrayList mWaitingVisibleActivities = new ArrayList();
432
433 /**
434 * List of activities that are ready to be stopped, but waiting
435 * for the next activity to settle down before doing so. It contains
436 * HistoryRecord objects.
437 */
438 final ArrayList<HistoryRecord> mStoppingActivities
439 = new ArrayList<HistoryRecord>();
440
441 /**
442 * List of intents that were used to start the most recent tasks.
443 */
444 final ArrayList<TaskRecord> mRecentTasks
445 = new ArrayList<TaskRecord>();
446
447 /**
448 * List of activities that are ready to be finished, but waiting
449 * for the previous activity to settle down before doing so. It contains
450 * HistoryRecord objects.
451 */
452 final ArrayList mFinishingActivities = new ArrayList();
453
454 /**
455 * All of the applications we currently have running organized by name.
456 * The keys are strings of the application package name (as
457 * returned by the package manager), and the keys are ApplicationRecord
458 * objects.
459 */
460 final ProcessMap<ProcessRecord> mProcessNames
461 = new ProcessMap<ProcessRecord>();
462
463 /**
464 * The last time that various processes have crashed.
465 */
466 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
467
468 /**
469 * Set of applications that we consider to be bad, and will reject
470 * incoming broadcasts from (which the user has no control over).
471 * Processes are added to this set when they have crashed twice within
472 * a minimum amount of time; they are removed from it when they are
473 * later restarted (hopefully due to some user action). The value is the
474 * time it was added to the list.
475 */
476 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
477
478 /**
479 * All of the processes we currently have running organized by pid.
480 * The keys are the pid running the application.
481 *
482 * <p>NOTE: This object is protected by its own lock, NOT the global
483 * activity manager lock!
484 */
485 final SparseArray<ProcessRecord> mPidsSelfLocked
486 = new SparseArray<ProcessRecord>();
487
488 /**
489 * All of the processes that have been forced to be foreground. The key
490 * is the pid of the caller who requested it (we hold a death
491 * link on it).
492 */
493 abstract class ForegroundToken implements IBinder.DeathRecipient {
494 int pid;
495 IBinder token;
496 }
497 final SparseArray<ForegroundToken> mForegroundProcesses
498 = new SparseArray<ForegroundToken>();
499
500 /**
501 * List of records for processes that someone had tried to start before the
502 * system was ready. We don't start them at that point, but ensure they
503 * are started by the time booting is complete.
504 */
505 final ArrayList<ProcessRecord> mProcessesOnHold
506 = new ArrayList<ProcessRecord>();
507
508 /**
509 * List of records for processes that we have started and are waiting
510 * for them to call back. This is really only needed when running in
511 * single processes mode, in which case we do not have a unique pid for
512 * each process.
513 */
514 final ArrayList<ProcessRecord> mStartingProcesses
515 = new ArrayList<ProcessRecord>();
516
517 /**
518 * List of persistent applications that are in the process
519 * of being started.
520 */
521 final ArrayList<ProcessRecord> mPersistentStartingProcesses
522 = new ArrayList<ProcessRecord>();
523
524 /**
525 * Processes that are being forcibly torn down.
526 */
527 final ArrayList<ProcessRecord> mRemovedProcesses
528 = new ArrayList<ProcessRecord>();
529
530 /**
531 * List of running applications, sorted by recent usage.
532 * The first entry in the list is the least recently used.
533 * It contains ApplicationRecord objects. This list does NOT include
534 * any persistent application records (since we never want to exit them).
535 */
536 final ArrayList<ProcessRecord> mLRUProcesses
537 = new ArrayList<ProcessRecord>();
538
539 /**
540 * List of processes that should gc as soon as things are idle.
541 */
542 final ArrayList<ProcessRecord> mProcessesToGc
543 = new ArrayList<ProcessRecord>();
544
545 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800546 * This is the process holding what we currently consider to be
547 * the "home" activity.
548 */
549 private ProcessRecord mHomeProcess;
550
551 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800552 * List of running activities, sorted by recent usage.
553 * The first entry in the list is the least recently used.
554 * It contains HistoryRecord objects.
555 */
556 private final ArrayList mLRUActivities = new ArrayList();
557
558 /**
559 * Set of PendingResultRecord objects that are currently active.
560 */
561 final HashSet mPendingResultRecords = new HashSet();
562
563 /**
564 * Set of IntentSenderRecord objects that are currently active.
565 */
566 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
567 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
568
569 /**
570 * Intent broadcast that we have tried to start, but are
571 * waiting for its application's process to be created. We only
572 * need one (instead of a list) because we always process broadcasts
573 * one at a time, so no others can be started while waiting for this
574 * one.
575 */
576 BroadcastRecord mPendingBroadcast = null;
577
578 /**
579 * Keeps track of all IIntentReceivers that have been registered for
580 * broadcasts. Hash keys are the receiver IBinder, hash value is
581 * a ReceiverList.
582 */
583 final HashMap mRegisteredReceivers = new HashMap();
584
585 /**
586 * Resolver for broadcast intents to registered receivers.
587 * Holds BroadcastFilter (subclass of IntentFilter).
588 */
589 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
590 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
591 @Override
592 protected boolean allowFilterResult(
593 BroadcastFilter filter, List<BroadcastFilter> dest) {
594 IBinder target = filter.receiverList.receiver.asBinder();
595 for (int i=dest.size()-1; i>=0; i--) {
596 if (dest.get(i).receiverList.receiver.asBinder() == target) {
597 return false;
598 }
599 }
600 return true;
601 }
602 };
603
604 /**
605 * State of all active sticky broadcasts. Keys are the action of the
606 * sticky Intent, values are an ArrayList of all broadcasted intents with
607 * that action (which should usually be one).
608 */
609 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
610 new HashMap<String, ArrayList<Intent>>();
611
612 /**
613 * All currently running services.
614 */
615 final HashMap<ComponentName, ServiceRecord> mServices =
616 new HashMap<ComponentName, ServiceRecord>();
617
618 /**
619 * All currently running services indexed by the Intent used to start them.
620 */
621 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
622 new HashMap<Intent.FilterComparison, ServiceRecord>();
623
624 /**
625 * All currently bound service connections. Keys are the IBinder of
626 * the client's IServiceConnection.
627 */
628 final HashMap<IBinder, ConnectionRecord> mServiceConnections
629 = new HashMap<IBinder, ConnectionRecord>();
630
631 /**
632 * List of services that we have been asked to start,
633 * but haven't yet been able to. It is used to hold start requests
634 * while waiting for their corresponding application thread to get
635 * going.
636 */
637 final ArrayList<ServiceRecord> mPendingServices
638 = new ArrayList<ServiceRecord>();
639
640 /**
641 * List of services that are scheduled to restart following a crash.
642 */
643 final ArrayList<ServiceRecord> mRestartingServices
644 = new ArrayList<ServiceRecord>();
645
646 /**
647 * List of services that are in the process of being stopped.
648 */
649 final ArrayList<ServiceRecord> mStoppingServices
650 = new ArrayList<ServiceRecord>();
651
652 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700653 * Backup/restore process management
654 */
655 String mBackupAppName = null;
656 BackupRecord mBackupTarget = null;
657
658 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659 * List of PendingThumbnailsRecord objects of clients who are still
660 * waiting to receive all of the thumbnails for a task.
661 */
662 final ArrayList mPendingThumbnails = new ArrayList();
663
664 /**
665 * List of HistoryRecord objects that have been finished and must
666 * still report back to a pending thumbnail receiver.
667 */
668 final ArrayList mCancelledThumbnails = new ArrayList();
669
670 /**
671 * All of the currently running global content providers. Keys are a
672 * string containing the provider name and values are a
673 * ContentProviderRecord object containing the data about it. Note
674 * that a single provider may be published under multiple names, so
675 * there may be multiple entries here for a single one in mProvidersByClass.
676 */
677 final HashMap mProvidersByName = new HashMap();
678
679 /**
680 * All of the currently running global content providers. Keys are a
681 * string containing the provider's implementation class and values are a
682 * ContentProviderRecord object containing the data about it.
683 */
684 final HashMap mProvidersByClass = new HashMap();
685
686 /**
687 * List of content providers who have clients waiting for them. The
688 * application is currently being launched and the provider will be
689 * removed from this list once it is published.
690 */
691 final ArrayList mLaunchingProviders = new ArrayList();
692
693 /**
694 * Global set of specific Uri permissions that have been granted.
695 */
696 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
697 = new SparseArray<HashMap<Uri, UriPermission>>();
698
699 /**
700 * Thread-local storage used to carry caller permissions over through
701 * indirect content-provider access.
702 * @see #ActivityManagerService.openContentUri()
703 */
704 private class Identity {
705 public int pid;
706 public int uid;
707
708 Identity(int _pid, int _uid) {
709 pid = _pid;
710 uid = _uid;
711 }
712 }
713 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
714
715 /**
716 * All information we have collected about the runtime performance of
717 * any user id that can impact battery performance.
718 */
719 final BatteryStatsService mBatteryStatsService;
720
721 /**
722 * information about component usage
723 */
724 final UsageStatsService mUsageStatsService;
725
726 /**
727 * Current configuration information. HistoryRecord objects are given
728 * a reference to this object to indicate which configuration they are
729 * currently running in, so this object must be kept immutable.
730 */
731 Configuration mConfiguration = new Configuration();
732
733 /**
Jack Palevichb90d28c2009-07-22 15:35:24 -0700734 * Hardware-reported OpenGLES version.
735 */
736 final int GL_ES_VERSION;
737
738 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800739 * List of initialization arguments to pass to all processes when binding applications to them.
740 * For example, references to the commonly used services.
741 */
742 HashMap<String, IBinder> mAppBindArgs;
743
744 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700745 * Temporary to avoid allocations. Protected by main lock.
746 */
747 final StringBuilder mStringBuilder = new StringBuilder(256);
748
749 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750 * Used to control how we initialize the service.
751 */
752 boolean mStartRunning = false;
753 ComponentName mTopComponent;
754 String mTopAction;
755 String mTopData;
756 boolean mSystemReady = false;
757 boolean mBooting = false;
758
759 Context mContext;
760
761 int mFactoryTest;
762
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700763 boolean mCheckedForSetup;
764
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800765 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700766 * The time at which we will allow normal application switches again,
767 * after a call to {@link #stopAppSwitches()}.
768 */
769 long mAppSwitchesAllowedTime;
770
771 /**
772 * This is set to true after the first switch after mAppSwitchesAllowedTime
773 * is set; any switches after that will clear the time.
774 */
775 boolean mDidAppSwitch;
776
777 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800778 * Set while we are wanting to sleep, to prevent any
779 * activities from being started/resumed.
780 */
781 boolean mSleeping = false;
782
783 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700784 * Set if we are shutting down the system, similar to sleeping.
785 */
786 boolean mShuttingDown = false;
787
788 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800789 * Set when the system is going to sleep, until we have
790 * successfully paused the current activity and released our wake lock.
791 * At that point the system is allowed to actually sleep.
792 */
793 PowerManager.WakeLock mGoingToSleep;
794
795 /**
796 * We don't want to allow the device to go to sleep while in the process
797 * of launching an activity. This is primarily to allow alarm intent
798 * receivers to launch an activity and get that to run before the device
799 * goes back to sleep.
800 */
801 PowerManager.WakeLock mLaunchingActivity;
802
803 /**
804 * Task identifier that activities are currently being started
805 * in. Incremented each time a new task is created.
806 * todo: Replace this with a TokenSpace class that generates non-repeating
807 * integers that won't wrap.
808 */
809 int mCurTask = 1;
810
811 /**
812 * Current sequence id for oom_adj computation traversal.
813 */
814 int mAdjSeq = 0;
815
816 /**
817 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
818 * is set, indicating the user wants processes started in such a way
819 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
820 * running in each process (thus no pre-initialized process, etc).
821 */
822 boolean mSimpleProcessManagement = false;
823
824 /**
825 * System monitoring: number of processes that died since the last
826 * N procs were started.
827 */
828 int[] mProcDeaths = new int[20];
829
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700830 /**
831 * This is set if we had to do a delayed dexopt of an app before launching
832 * it, to increasing the ANR timeouts in that case.
833 */
834 boolean mDidDexOpt;
835
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800836 String mDebugApp = null;
837 boolean mWaitForDebugger = false;
838 boolean mDebugTransient = false;
839 String mOrigDebugApp = null;
840 boolean mOrigWaitForDebugger = false;
841 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700842 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800843
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700844 final RemoteCallbackList<IActivityWatcher> mWatchers
845 = new RemoteCallbackList<IActivityWatcher>();
846
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800847 /**
848 * Callback of last caller to {@link #requestPss}.
849 */
850 Runnable mRequestPssCallback;
851
852 /**
853 * Remaining processes for which we are waiting results from the last
854 * call to {@link #requestPss}.
855 */
856 final ArrayList<ProcessRecord> mRequestPssList
857 = new ArrayList<ProcessRecord>();
858
859 /**
860 * Runtime statistics collection thread. This object's lock is used to
861 * protect all related state.
862 */
863 final Thread mProcessStatsThread;
864
865 /**
866 * Used to collect process stats when showing not responding dialog.
867 * Protected by mProcessStatsThread.
868 */
869 final ProcessStats mProcessStats = new ProcessStats(
870 MONITOR_THREAD_CPU_USAGE);
871 long mLastCpuTime = 0;
872 long mLastWriteTime = 0;
873
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700874 long mInitialStartTime = 0;
875
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800876 /**
877 * Set to true after the system has finished booting.
878 */
879 boolean mBooted = false;
880
881 int mProcessLimit = 0;
882
883 WindowManagerService mWindowManager;
884
885 static ActivityManagerService mSelf;
886 static ActivityThread mSystemThread;
887
888 private final class AppDeathRecipient implements IBinder.DeathRecipient {
889 final ProcessRecord mApp;
890 final int mPid;
891 final IApplicationThread mAppThread;
892
893 AppDeathRecipient(ProcessRecord app, int pid,
894 IApplicationThread thread) {
895 if (localLOGV) Log.v(
896 TAG, "New death recipient " + this
897 + " for thread " + thread.asBinder());
898 mApp = app;
899 mPid = pid;
900 mAppThread = thread;
901 }
902
903 public void binderDied() {
904 if (localLOGV) Log.v(
905 TAG, "Death received in " + this
906 + " for thread " + mAppThread.asBinder());
907 removeRequestedPss(mApp);
908 synchronized(ActivityManagerService.this) {
909 appDiedLocked(mApp, mPid, mAppThread);
910 }
911 }
912 }
913
914 static final int SHOW_ERROR_MSG = 1;
915 static final int SHOW_NOT_RESPONDING_MSG = 2;
916 static final int SHOW_FACTORY_ERROR_MSG = 3;
917 static final int UPDATE_CONFIGURATION_MSG = 4;
918 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
919 static final int WAIT_FOR_DEBUGGER_MSG = 6;
920 static final int BROADCAST_INTENT_MSG = 7;
921 static final int BROADCAST_TIMEOUT_MSG = 8;
922 static final int PAUSE_TIMEOUT_MSG = 9;
923 static final int IDLE_TIMEOUT_MSG = 10;
924 static final int IDLE_NOW_MSG = 11;
925 static final int SERVICE_TIMEOUT_MSG = 12;
926 static final int UPDATE_TIME_ZONE = 13;
927 static final int SHOW_UID_ERROR_MSG = 14;
928 static final int IM_FEELING_LUCKY_MSG = 15;
929 static final int LAUNCH_TIMEOUT_MSG = 16;
930 static final int DESTROY_TIMEOUT_MSG = 17;
931 static final int SERVICE_ERROR_MSG = 18;
932 static final int RESUME_TOP_ACTIVITY_MSG = 19;
933 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700934 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
Suchi Amalapurapud9d25762009-08-17 16:57:03 -0700935 static final int KILL_APPLICATION_MSG = 22;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800936
937 AlertDialog mUidAlert;
938
939 final Handler mHandler = new Handler() {
940 //public Handler() {
941 // if (localLOGV) Log.v(TAG, "Handler started!");
942 //}
943
944 public void handleMessage(Message msg) {
945 switch (msg.what) {
946 case SHOW_ERROR_MSG: {
947 HashMap data = (HashMap) msg.obj;
948 byte[] crashData = (byte[])data.get("crashData");
949 if (crashData != null) {
950 // This needs to be *un*synchronized to avoid deadlock.
951 ContentResolver resolver = mContext.getContentResolver();
952 Checkin.reportCrash(resolver, crashData);
953 }
954 synchronized (ActivityManagerService.this) {
955 ProcessRecord proc = (ProcessRecord)data.get("app");
956 if (proc != null && proc.crashDialog != null) {
957 Log.e(TAG, "App already has crash dialog: " + proc);
958 return;
959 }
960 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700961 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800962 Dialog d = new AppErrorDialog(
963 mContext, res, proc,
964 (Integer)data.get("flags"),
965 (String)data.get("shortMsg"),
966 (String)data.get("longMsg"));
967 d.show();
968 proc.crashDialog = d;
969 } else {
970 // The device is asleep, so just pretend that the user
971 // saw a crash dialog and hit "force quit".
972 res.set(0);
973 }
974 }
975 } break;
976 case SHOW_NOT_RESPONDING_MSG: {
977 synchronized (ActivityManagerService.this) {
978 HashMap data = (HashMap) msg.obj;
979 ProcessRecord proc = (ProcessRecord)data.get("app");
980 if (proc != null && proc.anrDialog != null) {
981 Log.e(TAG, "App already has anr dialog: " + proc);
982 return;
983 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800984
985 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
986 null, null, 0, null, null, null,
987 false, false, MY_PID, Process.SYSTEM_UID);
988
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800989 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
990 mContext, proc, (HistoryRecord)data.get("activity"));
991 d.show();
992 proc.anrDialog = d;
993 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700994
995 ensureScreenEnabled();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800996 } break;
997 case SHOW_FACTORY_ERROR_MSG: {
998 Dialog d = new FactoryErrorDialog(
999 mContext, msg.getData().getCharSequence("msg"));
1000 d.show();
1001 enableScreenAfterBoot();
1002 } break;
1003 case UPDATE_CONFIGURATION_MSG: {
1004 final ContentResolver resolver = mContext.getContentResolver();
1005 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
1006 } break;
1007 case GC_BACKGROUND_PROCESSES_MSG: {
1008 synchronized (ActivityManagerService.this) {
1009 performAppGcsIfAppropriateLocked();
1010 }
1011 } break;
1012 case WAIT_FOR_DEBUGGER_MSG: {
1013 synchronized (ActivityManagerService.this) {
1014 ProcessRecord app = (ProcessRecord)msg.obj;
1015 if (msg.arg1 != 0) {
1016 if (!app.waitedForDebugger) {
1017 Dialog d = new AppWaitingForDebuggerDialog(
1018 ActivityManagerService.this,
1019 mContext, app);
1020 app.waitDialog = d;
1021 app.waitedForDebugger = true;
1022 d.show();
1023 }
1024 } else {
1025 if (app.waitDialog != null) {
1026 app.waitDialog.dismiss();
1027 app.waitDialog = null;
1028 }
1029 }
1030 }
1031 } break;
1032 case BROADCAST_INTENT_MSG: {
1033 if (DEBUG_BROADCAST) Log.v(
1034 TAG, "Received BROADCAST_INTENT_MSG");
1035 processNextBroadcast(true);
1036 } break;
1037 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001038 if (mDidDexOpt) {
1039 mDidDexOpt = false;
1040 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1041 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1042 return;
1043 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001044 broadcastTimeout();
1045 } break;
1046 case PAUSE_TIMEOUT_MSG: {
1047 IBinder token = (IBinder)msg.obj;
1048 // We don't at this point know if the activity is fullscreen,
1049 // so we need to be conservative and assume it isn't.
1050 Log.w(TAG, "Activity pause timeout for " + token);
1051 activityPaused(token, null, true);
1052 } break;
1053 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001054 if (mDidDexOpt) {
1055 mDidDexOpt = false;
1056 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1057 nmsg.obj = msg.obj;
1058 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1059 return;
1060 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001061 // We don't at this point know if the activity is fullscreen,
1062 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001063 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001064 Log.w(TAG, "Activity idle timeout for " + token);
1065 activityIdleInternal(token, true);
1066 } break;
1067 case DESTROY_TIMEOUT_MSG: {
1068 IBinder token = (IBinder)msg.obj;
1069 // We don't at this point know if the activity is fullscreen,
1070 // so we need to be conservative and assume it isn't.
1071 Log.w(TAG, "Activity destroy timeout for " + token);
1072 activityDestroyed(token);
1073 } break;
1074 case IDLE_NOW_MSG: {
1075 IBinder token = (IBinder)msg.obj;
1076 activityIdle(token);
1077 } break;
1078 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001079 if (mDidDexOpt) {
1080 mDidDexOpt = false;
1081 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1082 nmsg.obj = msg.obj;
1083 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1084 return;
1085 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001086 serviceTimeout((ProcessRecord)msg.obj);
1087 } break;
1088 case UPDATE_TIME_ZONE: {
1089 synchronized (ActivityManagerService.this) {
1090 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1091 ProcessRecord r = mLRUProcesses.get(i);
1092 if (r.thread != null) {
1093 try {
1094 r.thread.updateTimeZone();
1095 } catch (RemoteException ex) {
1096 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1097 }
1098 }
1099 }
1100 }
1101 break;
1102 }
1103 case SHOW_UID_ERROR_MSG: {
1104 // XXX This is a temporary dialog, no need to localize.
1105 AlertDialog d = new BaseErrorDialog(mContext);
1106 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1107 d.setCancelable(false);
1108 d.setTitle("System UIDs Inconsistent");
1109 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1110 d.setButton("I'm Feeling Lucky",
1111 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1112 mUidAlert = d;
1113 d.show();
1114 } break;
1115 case IM_FEELING_LUCKY_MSG: {
1116 if (mUidAlert != null) {
1117 mUidAlert.dismiss();
1118 mUidAlert = null;
1119 }
1120 } break;
1121 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001122 if (mDidDexOpt) {
1123 mDidDexOpt = false;
1124 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1125 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1126 return;
1127 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001128 synchronized (ActivityManagerService.this) {
1129 if (mLaunchingActivity.isHeld()) {
1130 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1131 mLaunchingActivity.release();
1132 }
1133 }
1134 } break;
1135 case SERVICE_ERROR_MSG: {
1136 ServiceRecord srv = (ServiceRecord)msg.obj;
1137 // This needs to be *un*synchronized to avoid deadlock.
1138 Checkin.logEvent(mContext.getContentResolver(),
1139 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1140 srv.name.toShortString());
1141 } break;
1142 case RESUME_TOP_ACTIVITY_MSG: {
1143 synchronized (ActivityManagerService.this) {
1144 resumeTopActivityLocked(null);
1145 }
1146 }
1147 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001148 if (mDidDexOpt) {
1149 mDidDexOpt = false;
1150 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1151 nmsg.obj = msg.obj;
1152 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1153 return;
1154 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001155 ProcessRecord app = (ProcessRecord)msg.obj;
1156 synchronized (ActivityManagerService.this) {
1157 processStartTimedOutLocked(app);
1158 }
1159 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001160 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1161 synchronized (ActivityManagerService.this) {
1162 doPendingActivityLaunchesLocked(true);
1163 }
1164 }
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07001165 case KILL_APPLICATION_MSG: {
1166 synchronized (ActivityManagerService.this) {
1167 int uid = msg.arg1;
1168 boolean restart = (msg.arg2 == 1);
1169 String pkg = (String) msg.obj;
1170 uninstallPackageLocked(pkg, uid, restart);
1171 }
1172 } break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001173 }
1174 }
1175 };
1176
1177 public static void setSystemProcess() {
1178 try {
1179 ActivityManagerService m = mSelf;
1180
1181 ServiceManager.addService("activity", m);
1182 ServiceManager.addService("meminfo", new MemBinder(m));
1183 if (MONITOR_CPU_USAGE) {
1184 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1185 }
1186 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1187 ServiceManager.addService("activity.services", new ServicesBinder(m));
1188 ServiceManager.addService("activity.senders", new SendersBinder(m));
1189 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1190 ServiceManager.addService("permission", new PermissionController(m));
1191
1192 ApplicationInfo info =
1193 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001194 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001195 synchronized (mSelf) {
1196 ProcessRecord app = mSelf.newProcessRecordLocked(
1197 mSystemThread.getApplicationThread(), info,
1198 info.processName);
1199 app.persistent = true;
1200 app.pid = Process.myPid();
1201 app.maxAdj = SYSTEM_ADJ;
1202 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1203 synchronized (mSelf.mPidsSelfLocked) {
1204 mSelf.mPidsSelfLocked.put(app.pid, app);
1205 }
1206 mSelf.updateLRUListLocked(app, true);
1207 }
1208 } catch (PackageManager.NameNotFoundException e) {
1209 throw new RuntimeException(
1210 "Unable to find android system package", e);
1211 }
1212 }
1213
1214 public void setWindowManager(WindowManagerService wm) {
1215 mWindowManager = wm;
1216 }
1217
1218 public static final Context main(int factoryTest) {
1219 AThread thr = new AThread();
1220 thr.start();
1221
1222 synchronized (thr) {
1223 while (thr.mService == null) {
1224 try {
1225 thr.wait();
1226 } catch (InterruptedException e) {
1227 }
1228 }
1229 }
1230
1231 ActivityManagerService m = thr.mService;
1232 mSelf = m;
1233 ActivityThread at = ActivityThread.systemMain();
1234 mSystemThread = at;
1235 Context context = at.getSystemContext();
1236 m.mContext = context;
1237 m.mFactoryTest = factoryTest;
1238 PowerManager pm =
1239 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1240 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1241 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1242 m.mLaunchingActivity.setReferenceCounted(false);
1243
1244 m.mBatteryStatsService.publish(context);
1245 m.mUsageStatsService.publish(context);
1246
1247 synchronized (thr) {
1248 thr.mReady = true;
1249 thr.notifyAll();
1250 }
1251
1252 m.startRunning(null, null, null, null);
1253
1254 return context;
1255 }
1256
1257 public static ActivityManagerService self() {
1258 return mSelf;
1259 }
1260
1261 static class AThread extends Thread {
1262 ActivityManagerService mService;
1263 boolean mReady = false;
1264
1265 public AThread() {
1266 super("ActivityManager");
1267 }
1268
1269 public void run() {
1270 Looper.prepare();
1271
1272 android.os.Process.setThreadPriority(
1273 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1274
1275 ActivityManagerService m = new ActivityManagerService();
1276
1277 synchronized (this) {
1278 mService = m;
1279 notifyAll();
1280 }
1281
1282 synchronized (this) {
1283 while (!mReady) {
1284 try {
1285 wait();
1286 } catch (InterruptedException e) {
1287 }
1288 }
1289 }
1290
1291 Looper.loop();
1292 }
1293 }
1294
1295 static class BroadcastsBinder extends Binder {
1296 ActivityManagerService mActivityManagerService;
1297 BroadcastsBinder(ActivityManagerService activityManagerService) {
1298 mActivityManagerService = activityManagerService;
1299 }
1300
1301 @Override
1302 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1303 mActivityManagerService.dumpBroadcasts(pw);
1304 }
1305 }
1306
1307 static class ServicesBinder extends Binder {
1308 ActivityManagerService mActivityManagerService;
1309 ServicesBinder(ActivityManagerService activityManagerService) {
1310 mActivityManagerService = activityManagerService;
1311 }
1312
1313 @Override
1314 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1315 mActivityManagerService.dumpServices(pw);
1316 }
1317 }
1318
1319 static class SendersBinder extends Binder {
1320 ActivityManagerService mActivityManagerService;
1321 SendersBinder(ActivityManagerService activityManagerService) {
1322 mActivityManagerService = activityManagerService;
1323 }
1324
1325 @Override
1326 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1327 mActivityManagerService.dumpSenders(pw);
1328 }
1329 }
1330
1331 static class ProvidersBinder extends Binder {
1332 ActivityManagerService mActivityManagerService;
1333 ProvidersBinder(ActivityManagerService activityManagerService) {
1334 mActivityManagerService = activityManagerService;
1335 }
1336
1337 @Override
1338 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1339 mActivityManagerService.dumpProviders(pw);
1340 }
1341 }
1342
1343 static class MemBinder extends Binder {
1344 ActivityManagerService mActivityManagerService;
1345 MemBinder(ActivityManagerService activityManagerService) {
1346 mActivityManagerService = activityManagerService;
1347 }
1348
1349 @Override
1350 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1351 ActivityManagerService service = mActivityManagerService;
1352 ArrayList<ProcessRecord> procs;
1353 synchronized (mActivityManagerService) {
1354 if (args != null && args.length > 0
1355 && args[0].charAt(0) != '-') {
1356 procs = new ArrayList<ProcessRecord>();
1357 int pid = -1;
1358 try {
1359 pid = Integer.parseInt(args[0]);
1360 } catch (NumberFormatException e) {
1361
1362 }
1363 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1364 ProcessRecord proc = service.mLRUProcesses.get(i);
1365 if (proc.pid == pid) {
1366 procs.add(proc);
1367 } else if (proc.processName.equals(args[0])) {
1368 procs.add(proc);
1369 }
1370 }
1371 if (procs.size() <= 0) {
1372 pw.println("No process found for: " + args[0]);
1373 return;
1374 }
1375 } else {
1376 procs = service.mLRUProcesses;
1377 }
1378 }
1379 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1380 }
1381 }
1382
1383 static class CpuBinder extends Binder {
1384 ActivityManagerService mActivityManagerService;
1385 CpuBinder(ActivityManagerService activityManagerService) {
1386 mActivityManagerService = activityManagerService;
1387 }
1388
1389 @Override
1390 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1391 synchronized (mActivityManagerService.mProcessStatsThread) {
1392 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1393 }
1394 }
1395 }
1396
1397 private ActivityManagerService() {
1398 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1399 if (v != null && Integer.getInteger(v) != 0) {
1400 mSimpleProcessManagement = true;
1401 }
1402 v = System.getenv("ANDROID_DEBUG_APP");
1403 if (v != null) {
1404 mSimpleProcessManagement = true;
1405 }
1406
1407 MY_PID = Process.myPid();
1408
1409 File dataDir = Environment.getDataDirectory();
1410 File systemDir = new File(dataDir, "system");
1411 systemDir.mkdirs();
1412 mBatteryStatsService = new BatteryStatsService(new File(
1413 systemDir, "batterystats.bin").toString());
1414 mBatteryStatsService.getActiveStatistics().readLocked();
1415 mBatteryStatsService.getActiveStatistics().writeLocked();
1416
1417 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001418 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001419
Jack Palevichb90d28c2009-07-22 15:35:24 -07001420 GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
1421 ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
1422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001423 mConfiguration.makeDefault();
1424 mProcessStats.init();
1425
1426 // Add ourself to the Watchdog monitors.
1427 Watchdog.getInstance().addMonitor(this);
1428
1429 // These values are set in system/rootdir/init.rc on startup.
1430 FOREGROUND_APP_ADJ =
1431 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1432 VISIBLE_APP_ADJ =
1433 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1434 SECONDARY_SERVER_ADJ =
1435 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001436 BACKUP_APP_ADJ =
1437 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001438 HOME_APP_ADJ =
1439 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001440 HIDDEN_APP_MIN_ADJ =
1441 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1442 CONTENT_PROVIDER_ADJ =
1443 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1444 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1445 EMPTY_APP_ADJ =
1446 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1447 FOREGROUND_APP_MEM =
1448 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1449 VISIBLE_APP_MEM =
1450 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1451 SECONDARY_SERVER_MEM =
1452 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001453 BACKUP_APP_MEM =
1454 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001455 HOME_APP_MEM =
1456 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001457 HIDDEN_APP_MEM =
1458 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1459 EMPTY_APP_MEM =
1460 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1461
1462 mProcessStatsThread = new Thread("ProcessStats") {
1463 public void run() {
1464 while (true) {
1465 try {
1466 try {
1467 synchronized(this) {
1468 final long now = SystemClock.uptimeMillis();
1469 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1470 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1471 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1472 // + ", write delay=" + nextWriteDelay);
1473 if (nextWriteDelay < nextCpuDelay) {
1474 nextCpuDelay = nextWriteDelay;
1475 }
1476 if (nextCpuDelay > 0) {
1477 this.wait(nextCpuDelay);
1478 }
1479 }
1480 } catch (InterruptedException e) {
1481 }
1482
1483 updateCpuStatsNow();
1484 } catch (Exception e) {
1485 Log.e(TAG, "Unexpected exception collecting process stats", e);
1486 }
1487 }
1488 }
1489 };
1490 mProcessStatsThread.start();
1491 }
1492
1493 @Override
1494 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1495 throws RemoteException {
1496 try {
1497 return super.onTransact(code, data, reply, flags);
1498 } catch (RuntimeException e) {
1499 // The activity manager only throws security exceptions, so let's
1500 // log all others.
1501 if (!(e instanceof SecurityException)) {
1502 Log.e(TAG, "Activity Manager Crash", e);
1503 }
1504 throw e;
1505 }
1506 }
1507
1508 void updateCpuStats() {
1509 synchronized (mProcessStatsThread) {
1510 final long now = SystemClock.uptimeMillis();
1511 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1512 mProcessStatsThread.notify();
1513 }
1514 }
1515 }
1516
1517 void updateCpuStatsNow() {
1518 synchronized (mProcessStatsThread) {
1519 final long now = SystemClock.uptimeMillis();
1520 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001521
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001522 if (MONITOR_CPU_USAGE &&
1523 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1524 mLastCpuTime = now;
1525 haveNewCpuStats = true;
1526 mProcessStats.update();
1527 //Log.i(TAG, mProcessStats.printCurrentState());
1528 //Log.i(TAG, "Total CPU usage: "
1529 // + mProcessStats.getTotalCpuPercent() + "%");
1530
1531 // Log the cpu usage if the property is set.
1532 if ("true".equals(SystemProperties.get("events.cpu"))) {
1533 int user = mProcessStats.getLastUserTime();
1534 int system = mProcessStats.getLastSystemTime();
1535 int iowait = mProcessStats.getLastIoWaitTime();
1536 int irq = mProcessStats.getLastIrqTime();
1537 int softIrq = mProcessStats.getLastSoftIrqTime();
1538 int idle = mProcessStats.getLastIdleTime();
1539
1540 int total = user + system + iowait + irq + softIrq + idle;
1541 if (total == 0) total = 1;
1542
1543 EventLog.writeEvent(LOG_CPU,
1544 ((user+system+iowait+irq+softIrq) * 100) / total,
1545 (user * 100) / total,
1546 (system * 100) / total,
1547 (iowait * 100) / total,
1548 (irq * 100) / total,
1549 (softIrq * 100) / total);
1550 }
1551 }
1552
Amith Yamasani819f9282009-06-24 23:18:15 -07001553 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001554 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001555 synchronized(mPidsSelfLocked) {
1556 if (haveNewCpuStats) {
1557 if (mBatteryStatsService.isOnBattery()) {
1558 final int N = mProcessStats.countWorkingStats();
1559 for (int i=0; i<N; i++) {
1560 ProcessStats.Stats st
1561 = mProcessStats.getWorkingStats(i);
1562 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1563 if (pr != null) {
1564 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1565 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001566 } else {
1567 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001568 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001569 if (ps != null) {
1570 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1571 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001572 }
1573 }
1574 }
1575 }
1576 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001577
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001578 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1579 mLastWriteTime = now;
1580 mBatteryStatsService.getActiveStatistics().writeLocked();
1581 }
1582 }
1583 }
1584 }
1585
1586 /**
1587 * Initialize the application bind args. These are passed to each
1588 * process when the bindApplication() IPC is sent to the process. They're
1589 * lazily setup to make sure the services are running when they're asked for.
1590 */
1591 private HashMap<String, IBinder> getCommonServicesLocked() {
1592 if (mAppBindArgs == null) {
1593 mAppBindArgs = new HashMap<String, IBinder>();
1594
1595 // Setup the application init args
1596 mAppBindArgs.put("package", ServiceManager.getService("package"));
1597 mAppBindArgs.put("window", ServiceManager.getService("window"));
1598 mAppBindArgs.put(Context.ALARM_SERVICE,
1599 ServiceManager.getService(Context.ALARM_SERVICE));
1600 }
1601 return mAppBindArgs;
1602 }
1603
1604 private final void setFocusedActivityLocked(HistoryRecord r) {
1605 if (mFocusedActivity != r) {
1606 mFocusedActivity = r;
1607 mWindowManager.setFocusedApp(r, true);
1608 }
1609 }
1610
1611 private final void updateLRUListLocked(ProcessRecord app,
1612 boolean oomAdj) {
1613 // put it on the LRU to keep track of when it should be exited.
1614 int lrui = mLRUProcesses.indexOf(app);
1615 if (lrui >= 0) mLRUProcesses.remove(lrui);
1616 mLRUProcesses.add(app);
1617 //Log.i(TAG, "Putting proc to front: " + app.processName);
1618 if (oomAdj) {
1619 updateOomAdjLocked();
1620 }
1621 }
1622
1623 private final boolean updateLRUListLocked(HistoryRecord r) {
1624 final boolean hadit = mLRUActivities.remove(r);
1625 mLRUActivities.add(r);
1626 return hadit;
1627 }
1628
1629 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1630 int i = mHistory.size()-1;
1631 while (i >= 0) {
1632 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1633 if (!r.finishing && r != notTop) {
1634 return r;
1635 }
1636 i--;
1637 }
1638 return null;
1639 }
1640
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001641 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1642 int i = mHistory.size()-1;
1643 while (i >= 0) {
1644 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1645 if (!r.finishing && !r.delayedResume && r != notTop) {
1646 return r;
1647 }
1648 i--;
1649 }
1650 return null;
1651 }
1652
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001653 /**
1654 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001655 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001656 *
1657 * @param token If non-null, any history records matching this token will be skipped.
1658 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1659 *
1660 * @return Returns the HistoryRecord of the next activity on the stack.
1661 */
1662 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1663 int i = mHistory.size()-1;
1664 while (i >= 0) {
1665 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1666 // Note: the taskId check depends on real taskId fields being non-zero
1667 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1668 return r;
1669 }
1670 i--;
1671 }
1672 return null;
1673 }
1674
1675 private final ProcessRecord getProcessRecordLocked(
1676 String processName, int uid) {
1677 if (uid == Process.SYSTEM_UID) {
1678 // The system gets to run in any process. If there are multiple
1679 // processes with the same uid, just pick the first (this
1680 // should never happen).
1681 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1682 processName);
1683 return procs != null ? procs.valueAt(0) : null;
1684 }
1685 ProcessRecord proc = mProcessNames.get(processName, uid);
1686 return proc;
1687 }
1688
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001689 private void ensurePackageDexOpt(String packageName) {
1690 IPackageManager pm = ActivityThread.getPackageManager();
1691 try {
1692 if (pm.performDexOpt(packageName)) {
1693 mDidDexOpt = true;
1694 }
1695 } catch (RemoteException e) {
1696 }
1697 }
1698
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001699 private boolean isNextTransitionForward() {
1700 int transit = mWindowManager.getPendingAppTransition();
1701 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1702 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1703 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1704 }
1705
1706 private final boolean realStartActivityLocked(HistoryRecord r,
1707 ProcessRecord app, boolean andResume, boolean checkConfig)
1708 throws RemoteException {
1709
1710 r.startFreezingScreenLocked(app, 0);
1711 mWindowManager.setAppVisibility(r, true);
1712
1713 // Have the window manager re-evaluate the orientation of
1714 // the screen based on the new activity order. Note that
1715 // as a result of this, it can call back into the activity
1716 // manager with a new orientation. We don't care about that,
1717 // because the activity is not currently running so we are
1718 // just restarting it anyway.
1719 if (checkConfig) {
1720 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001721 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001722 r.mayFreezeScreenLocked(app) ? r : null);
1723 updateConfigurationLocked(config, r);
1724 }
1725
1726 r.app = app;
1727
1728 if (localLOGV) Log.v(TAG, "Launching: " + r);
1729
1730 int idx = app.activities.indexOf(r);
1731 if (idx < 0) {
1732 app.activities.add(r);
1733 }
1734 updateLRUListLocked(app, true);
1735
1736 try {
1737 if (app.thread == null) {
1738 throw new RemoteException();
1739 }
1740 List<ResultInfo> results = null;
1741 List<Intent> newIntents = null;
1742 if (andResume) {
1743 results = r.results;
1744 newIntents = r.newIntents;
1745 }
1746 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1747 + " icicle=" + r.icicle
1748 + " with results=" + results + " newIntents=" + newIntents
1749 + " andResume=" + andResume);
1750 if (andResume) {
1751 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1752 System.identityHashCode(r),
1753 r.task.taskId, r.shortComponentName);
1754 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001755 if (r.isHomeActivity) {
1756 mHomeProcess = app;
1757 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001758 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001759 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001760 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001761 r.info, r.icicle, results, newIntents, !andResume,
1762 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001763 } catch (RemoteException e) {
1764 if (r.launchFailed) {
1765 // This is the second time we failed -- finish activity
1766 // and give up.
1767 Log.e(TAG, "Second failure launching "
1768 + r.intent.getComponent().flattenToShortString()
1769 + ", giving up", e);
1770 appDiedLocked(app, app.pid, app.thread);
1771 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1772 "2nd-crash");
1773 return false;
1774 }
1775
1776 // This is the first time we failed -- restart process and
1777 // retry.
1778 app.activities.remove(r);
1779 throw e;
1780 }
1781
1782 r.launchFailed = false;
1783 if (updateLRUListLocked(r)) {
1784 Log.w(TAG, "Activity " + r
1785 + " being launched, but already in LRU list");
1786 }
1787
1788 if (andResume) {
1789 // As part of the process of launching, ActivityThread also performs
1790 // a resume.
1791 r.state = ActivityState.RESUMED;
1792 r.icicle = null;
1793 r.haveState = false;
1794 r.stopped = false;
1795 mResumedActivity = r;
1796 r.task.touchActiveTime();
1797 completeResumeLocked(r);
1798 pauseIfSleepingLocked();
1799 } else {
1800 // This activity is not starting in the resumed state... which
1801 // should look like we asked it to pause+stop (but remain visible),
1802 // and it has done so and reported back the current icicle and
1803 // other state.
1804 r.state = ActivityState.STOPPED;
1805 r.stopped = true;
1806 }
1807
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001808 // Launch the new version setup screen if needed. We do this -after-
1809 // launching the initial activity (that is, home), so that it can have
1810 // a chance to initialize itself while in the background, making the
1811 // switch back to it faster and look better.
1812 startSetupActivityLocked();
1813
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001814 return true;
1815 }
1816
1817 private final void startSpecificActivityLocked(HistoryRecord r,
1818 boolean andResume, boolean checkConfig) {
1819 // Is this activity's application already running?
1820 ProcessRecord app = getProcessRecordLocked(r.processName,
1821 r.info.applicationInfo.uid);
1822
1823 if (r.startTime == 0) {
1824 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001825 if (mInitialStartTime == 0) {
1826 mInitialStartTime = r.startTime;
1827 }
1828 } else if (mInitialStartTime == 0) {
1829 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001830 }
1831
1832 if (app != null && app.thread != null) {
1833 try {
1834 realStartActivityLocked(r, app, andResume, checkConfig);
1835 return;
1836 } catch (RemoteException e) {
1837 Log.w(TAG, "Exception when starting activity "
1838 + r.intent.getComponent().flattenToShortString(), e);
1839 }
1840
1841 // If a dead object exception was thrown -- fall through to
1842 // restart the application.
1843 }
1844
1845 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
1846 "activity", r.intent.getComponent());
1847 }
1848
1849 private final ProcessRecord startProcessLocked(String processName,
1850 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
1851 String hostingType, ComponentName hostingName) {
1852 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1853 // We don't have to do anything more if:
1854 // (1) There is an existing application record; and
1855 // (2) The caller doesn't think it is dead, OR there is no thread
1856 // object attached to it so we know it couldn't have crashed; and
1857 // (3) There is a pid assigned to it, so it is either starting or
1858 // already running.
1859 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1860 + " app=" + app + " knownToBeDead=" + knownToBeDead
1861 + " thread=" + (app != null ? app.thread : null)
1862 + " pid=" + (app != null ? app.pid : -1));
1863 if (app != null &&
1864 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1865 return app;
1866 }
1867
1868 String hostingNameStr = hostingName != null
1869 ? hostingName.flattenToShortString() : null;
1870
1871 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1872 // If we are in the background, then check to see if this process
1873 // is bad. If so, we will just silently fail.
1874 if (mBadProcesses.get(info.processName, info.uid) != null) {
1875 return null;
1876 }
1877 } else {
1878 // When the user is explicitly starting a process, then clear its
1879 // crash count so that we won't make it bad until they see at
1880 // least one crash dialog again, and make the process good again
1881 // if it had been bad.
1882 mProcessCrashTimes.remove(info.processName, info.uid);
1883 if (mBadProcesses.get(info.processName, info.uid) != null) {
1884 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1885 info.processName);
1886 mBadProcesses.remove(info.processName, info.uid);
1887 if (app != null) {
1888 app.bad = false;
1889 }
1890 }
1891 }
1892
1893 if (app == null) {
1894 app = newProcessRecordLocked(null, info, processName);
1895 mProcessNames.put(processName, info.uid, app);
1896 } else {
1897 // If this is a new package in the process, add the package to the list
1898 app.addPackage(info.packageName);
1899 }
1900
1901 // If the system is not ready yet, then hold off on starting this
1902 // process until it is.
1903 if (!mSystemReady
1904 && (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
1905 if (!mProcessesOnHold.contains(app)) {
1906 mProcessesOnHold.add(app);
1907 }
1908 return app;
1909 }
1910
1911 startProcessLocked(app, hostingType, hostingNameStr);
1912 return (app.pid != 0) ? app : null;
1913 }
1914
1915 private final void startProcessLocked(ProcessRecord app,
1916 String hostingType, String hostingNameStr) {
1917 if (app.pid > 0 && app.pid != MY_PID) {
1918 synchronized (mPidsSelfLocked) {
1919 mPidsSelfLocked.remove(app.pid);
1920 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1921 }
1922 app.pid = 0;
1923 }
1924
1925 mProcessesOnHold.remove(app);
1926
1927 updateCpuStats();
1928
1929 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1930 mProcDeaths[0] = 0;
1931
1932 try {
1933 int uid = app.info.uid;
1934 int[] gids = null;
1935 try {
1936 gids = mContext.getPackageManager().getPackageGids(
1937 app.info.packageName);
1938 } catch (PackageManager.NameNotFoundException e) {
1939 Log.w(TAG, "Unable to retrieve gids", e);
1940 }
1941 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1942 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1943 && mTopComponent != null
1944 && app.processName.equals(mTopComponent.getPackageName())) {
1945 uid = 0;
1946 }
1947 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1948 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1949 uid = 0;
1950 }
1951 }
1952 int debugFlags = 0;
1953 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1954 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1955 }
1956 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1957 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1958 }
1959 if ("1".equals(SystemProperties.get("debug.assert"))) {
1960 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1961 }
1962 int pid = Process.start("android.app.ActivityThread",
1963 mSimpleProcessManagement ? app.processName : null, uid, uid,
1964 gids, debugFlags, null);
1965 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1966 synchronized (bs) {
1967 if (bs.isOnBattery()) {
1968 app.batteryStats.incStartsLocked();
1969 }
1970 }
1971
1972 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
1973 app.processName, hostingType,
1974 hostingNameStr != null ? hostingNameStr : "");
1975
1976 if (app.persistent) {
1977 Watchdog.getInstance().processStarted(app, app.processName, pid);
1978 }
1979
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001980 StringBuilder buf = mStringBuilder;
1981 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001982 buf.append("Start proc ");
1983 buf.append(app.processName);
1984 buf.append(" for ");
1985 buf.append(hostingType);
1986 if (hostingNameStr != null) {
1987 buf.append(" ");
1988 buf.append(hostingNameStr);
1989 }
1990 buf.append(": pid=");
1991 buf.append(pid);
1992 buf.append(" uid=");
1993 buf.append(uid);
1994 buf.append(" gids={");
1995 if (gids != null) {
1996 for (int gi=0; gi<gids.length; gi++) {
1997 if (gi != 0) buf.append(", ");
1998 buf.append(gids[gi]);
1999
2000 }
2001 }
2002 buf.append("}");
2003 Log.i(TAG, buf.toString());
2004 if (pid == 0 || pid == MY_PID) {
2005 // Processes are being emulated with threads.
2006 app.pid = MY_PID;
2007 app.removed = false;
2008 mStartingProcesses.add(app);
2009 } else if (pid > 0) {
2010 app.pid = pid;
2011 app.removed = false;
2012 synchronized (mPidsSelfLocked) {
2013 this.mPidsSelfLocked.put(pid, app);
2014 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
2015 msg.obj = app;
2016 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
2017 }
2018 } else {
2019 app.pid = 0;
2020 RuntimeException e = new RuntimeException(
2021 "Failure starting process " + app.processName
2022 + ": returned pid=" + pid);
2023 Log.e(TAG, e.getMessage(), e);
2024 }
2025 } catch (RuntimeException e) {
2026 // XXX do better error recovery.
2027 app.pid = 0;
2028 Log.e(TAG, "Failure starting process " + app.processName, e);
2029 }
2030 }
2031
2032 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2033 if (mPausingActivity != null) {
2034 RuntimeException e = new RuntimeException();
2035 Log.e(TAG, "Trying to pause when pause is already pending for "
2036 + mPausingActivity, e);
2037 }
2038 HistoryRecord prev = mResumedActivity;
2039 if (prev == null) {
2040 RuntimeException e = new RuntimeException();
2041 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2042 resumeTopActivityLocked(null);
2043 return;
2044 }
2045 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2046 mResumedActivity = null;
2047 mPausingActivity = prev;
2048 mLastPausedActivity = prev;
2049 prev.state = ActivityState.PAUSING;
2050 prev.task.touchActiveTime();
2051
2052 updateCpuStats();
2053
2054 if (prev.app != null && prev.app.thread != null) {
2055 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2056 try {
2057 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2058 System.identityHashCode(prev),
2059 prev.shortComponentName);
2060 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2061 prev.configChangeFlags);
2062 updateUsageStats(prev, false);
2063 } catch (Exception e) {
2064 // Ignore exception, if process died other code will cleanup.
2065 Log.w(TAG, "Exception thrown during pause", e);
2066 mPausingActivity = null;
2067 mLastPausedActivity = null;
2068 }
2069 } else {
2070 mPausingActivity = null;
2071 mLastPausedActivity = null;
2072 }
2073
2074 // If we are not going to sleep, we want to ensure the device is
2075 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002076 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002077 mLaunchingActivity.acquire();
2078 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2079 // To be safe, don't allow the wake lock to be held for too long.
2080 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2081 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2082 }
2083 }
2084
2085
2086 if (mPausingActivity != null) {
2087 // Have the window manager pause its key dispatching until the new
2088 // activity has started. If we're pausing the activity just because
2089 // the screen is being turned off and the UI is sleeping, don't interrupt
2090 // key dispatch; the same activity will pick it up again on wakeup.
2091 if (!uiSleeping) {
2092 prev.pauseKeyDispatchingLocked();
2093 } else {
2094 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2095 }
2096
2097 // Schedule a pause timeout in case the app doesn't respond.
2098 // We don't give it much time because this directly impacts the
2099 // responsiveness seen by the user.
2100 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2101 msg.obj = prev;
2102 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2103 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2104 } else {
2105 // This activity failed to schedule the
2106 // pause, so just treat it as being paused now.
2107 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2108 resumeTopActivityLocked(null);
2109 }
2110 }
2111
2112 private final void completePauseLocked() {
2113 HistoryRecord prev = mPausingActivity;
2114 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2115
2116 if (prev != null) {
2117 if (prev.finishing) {
2118 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2119 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2120 } else if (prev.app != null) {
2121 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2122 if (prev.waitingVisible) {
2123 prev.waitingVisible = false;
2124 mWaitingVisibleActivities.remove(prev);
2125 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2126 TAG, "Complete pause, no longer waiting: " + prev);
2127 }
2128 if (prev.configDestroy) {
2129 // The previous is being paused because the configuration
2130 // is changing, which means it is actually stopping...
2131 // To juggle the fact that we are also starting a new
2132 // instance right now, we need to first completely stop
2133 // the current instance before starting the new one.
2134 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2135 destroyActivityLocked(prev, true);
2136 } else {
2137 mStoppingActivities.add(prev);
2138 if (mStoppingActivities.size() > 3) {
2139 // If we already have a few activities waiting to stop,
2140 // then give up on things going idle and start clearing
2141 // them out.
2142 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2143 Message msg = Message.obtain();
2144 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2145 mHandler.sendMessage(msg);
2146 }
2147 }
2148 } else {
2149 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2150 prev = null;
2151 }
2152 mPausingActivity = null;
2153 }
2154
Dianne Hackborn55280a92009-05-07 15:53:46 -07002155 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002156 resumeTopActivityLocked(prev);
2157 } else {
2158 if (mGoingToSleep.isHeld()) {
2159 mGoingToSleep.release();
2160 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002161 if (mShuttingDown) {
2162 notifyAll();
2163 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002164 }
2165
2166 if (prev != null) {
2167 prev.resumeKeyDispatchingLocked();
2168 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002169
2170 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2171 long diff = 0;
2172 synchronized (mProcessStatsThread) {
2173 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2174 }
2175 if (diff > 0) {
2176 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2177 synchronized (bsi) {
2178 BatteryStatsImpl.Uid.Proc ps =
2179 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2180 prev.info.packageName);
2181 if (ps != null) {
2182 ps.addForegroundTimeLocked(diff);
2183 }
2184 }
2185 }
2186 }
2187 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002188 }
2189
2190 /**
2191 * Once we know that we have asked an application to put an activity in
2192 * the resumed state (either by launching it or explicitly telling it),
2193 * this function updates the rest of our state to match that fact.
2194 */
2195 private final void completeResumeLocked(HistoryRecord next) {
2196 next.idle = false;
2197 next.results = null;
2198 next.newIntents = null;
2199
2200 // schedule an idle timeout in case the app doesn't do it for us.
2201 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2202 msg.obj = next;
2203 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2204
2205 if (false) {
2206 // The activity was never told to pause, so just keep
2207 // things going as-is. To maintain our own state,
2208 // we need to emulate it coming back and saying it is
2209 // idle.
2210 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2211 msg.obj = next;
2212 mHandler.sendMessage(msg);
2213 }
2214
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002215 reportResumedActivity(next);
2216
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002217 next.thumbnail = null;
2218 setFocusedActivityLocked(next);
2219 next.resumeKeyDispatchingLocked();
2220 ensureActivitiesVisibleLocked(null, 0);
2221 mWindowManager.executeAppTransition();
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 Hackbornb06ea702009-07-13 13:07:51 -07002487 private void reportResumedActivity(HistoryRecord r) {
2488 //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();
2538 return false;
2539 }
2540
2541 // If we are sleeping, and there is no resumed activity, and the top
2542 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002543 if ((mSleeping || mShuttingDown)
2544 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002545 // Make sure we have executed any pending transitions, since there
2546 // should be nothing left to do at this point.
2547 mWindowManager.executeAppTransition();
2548 return false;
2549 }
2550
2551 // The activity may be waiting for stop, but that is no longer
2552 // appropriate for it.
2553 mStoppingActivities.remove(next);
2554 mWaitingVisibleActivities.remove(next);
2555
2556 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2557
2558 // If we are currently pausing an activity, then don't do anything
2559 // until that is done.
2560 if (mPausingActivity != null) {
2561 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2562 return false;
2563 }
2564
2565 // We need to start pausing the current activity so the top one
2566 // can be resumed...
2567 if (mResumedActivity != null) {
2568 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2569 startPausingLocked(userLeaving, false);
2570 return true;
2571 }
2572
2573 if (prev != null && prev != next) {
2574 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2575 prev.waitingVisible = true;
2576 mWaitingVisibleActivities.add(prev);
2577 if (DEBUG_SWITCH) Log.v(
2578 TAG, "Resuming top, waiting visible to hide: " + prev);
2579 } else {
2580 // The next activity is already visible, so hide the previous
2581 // activity's windows right now so we can show the new one ASAP.
2582 // We only do this if the previous is finishing, which should mean
2583 // it is on top of the one being resumed so hiding it quickly
2584 // is good. Otherwise, we want to do the normal route of allowing
2585 // the resumed activity to be shown so we can decide if the
2586 // previous should actually be hidden depending on whether the
2587 // new one is found to be full-screen or not.
2588 if (prev.finishing) {
2589 mWindowManager.setAppVisibility(prev, false);
2590 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2591 + prev + ", waitingVisible="
2592 + (prev != null ? prev.waitingVisible : null)
2593 + ", nowVisible=" + next.nowVisible);
2594 } else {
2595 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2596 + prev + ", waitingVisible="
2597 + (prev != null ? prev.waitingVisible : null)
2598 + ", nowVisible=" + next.nowVisible);
2599 }
2600 }
2601 }
2602
2603 // We are starting up the next activity, so tell the window manager
2604 // that the previous one will be hidden soon. This way it can know
2605 // to ignore it when computing the desired screen orientation.
2606 if (prev != null) {
2607 if (prev.finishing) {
2608 if (DEBUG_TRANSITION) Log.v(TAG,
2609 "Prepare close transition: prev=" + prev);
2610 mWindowManager.prepareAppTransition(prev.task == next.task
2611 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2612 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2613 mWindowManager.setAppWillBeHidden(prev);
2614 mWindowManager.setAppVisibility(prev, false);
2615 } else {
2616 if (DEBUG_TRANSITION) Log.v(TAG,
2617 "Prepare open transition: prev=" + prev);
2618 mWindowManager.prepareAppTransition(prev.task == next.task
2619 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2620 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2621 }
2622 if (false) {
2623 mWindowManager.setAppWillBeHidden(prev);
2624 mWindowManager.setAppVisibility(prev, false);
2625 }
2626 } else if (mHistory.size() > 1) {
2627 if (DEBUG_TRANSITION) Log.v(TAG,
2628 "Prepare open transition: no previous");
2629 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2630 }
2631
2632 if (next.app != null && next.app.thread != null) {
2633 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2634
2635 // This activity is now becoming visible.
2636 mWindowManager.setAppVisibility(next, true);
2637
2638 HistoryRecord lastResumedActivity = mResumedActivity;
2639 ActivityState lastState = next.state;
2640
2641 updateCpuStats();
2642
2643 next.state = ActivityState.RESUMED;
2644 mResumedActivity = next;
2645 next.task.touchActiveTime();
2646 updateLRUListLocked(next.app, true);
2647 updateLRUListLocked(next);
2648
2649 // Have the window manager re-evaluate the orientation of
2650 // the screen based on the new activity order.
2651 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002652 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002653 next.mayFreezeScreenLocked(next.app) ? next : null);
2654 if (config != null) {
2655 next.frozenBeforeDestroy = true;
2656 }
2657 if (!updateConfigurationLocked(config, next)) {
2658 // The configuration update wasn't able to keep the existing
2659 // instance of the activity, and instead started a new one.
2660 // We should be all done, but let's just make sure our activity
2661 // is still at the top and schedule another run if something
2662 // weird happened.
2663 HistoryRecord nextNext = topRunningActivityLocked(null);
2664 if (DEBUG_SWITCH) Log.i(TAG,
2665 "Activity config changed during resume: " + next
2666 + ", new next: " + nextNext);
2667 if (nextNext != next) {
2668 // Do over!
2669 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2670 }
2671 mWindowManager.executeAppTransition();
2672 return true;
2673 }
2674
2675 try {
2676 // Deliver all pending results.
2677 ArrayList a = next.results;
2678 if (a != null) {
2679 final int N = a.size();
2680 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002681 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002682 TAG, "Delivering results to " + next
2683 + ": " + a);
2684 next.app.thread.scheduleSendResult(next, a);
2685 }
2686 }
2687
2688 if (next.newIntents != null) {
2689 next.app.thread.scheduleNewIntent(next.newIntents, next);
2690 }
2691
2692 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2693 System.identityHashCode(next),
2694 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002695
2696 next.app.thread.scheduleResumeActivity(next,
2697 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002698
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002699 pauseIfSleepingLocked();
2700
2701 } catch (Exception e) {
2702 // Whoops, need to restart this activity!
2703 next.state = lastState;
2704 mResumedActivity = lastResumedActivity;
2705 if (Config.LOGD) Log.d(TAG,
2706 "Restarting because process died: " + next);
2707 if (!next.hasBeenLaunched) {
2708 next.hasBeenLaunched = true;
2709 } else {
2710 if (SHOW_APP_STARTING_ICON) {
2711 mWindowManager.setAppStartingWindow(
2712 next, next.packageName, next.theme,
2713 next.nonLocalizedLabel,
2714 next.labelRes, next.icon, null, true);
2715 }
2716 }
2717 startSpecificActivityLocked(next, true, false);
2718 return true;
2719 }
2720
2721 // From this point on, if something goes wrong there is no way
2722 // to recover the activity.
2723 try {
2724 next.visible = true;
2725 completeResumeLocked(next);
2726 } catch (Exception e) {
2727 // If any exception gets thrown, toss away this
2728 // activity and try the next one.
2729 Log.w(TAG, "Exception thrown during resume of " + next, e);
2730 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2731 "resume-exception");
2732 return true;
2733 }
2734
2735 // Didn't need to use the icicle, and it is now out of date.
2736 next.icicle = null;
2737 next.haveState = false;
2738 next.stopped = false;
2739
2740 } else {
2741 // Whoops, need to restart this activity!
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 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2752 }
2753 startSpecificActivityLocked(next, true, true);
2754 }
2755
2756 return true;
2757 }
2758
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002759 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2760 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002761 final int NH = mHistory.size();
2762
2763 int addPos = -1;
2764
2765 if (!newTask) {
2766 // If starting in an existing task, find where that is...
2767 HistoryRecord next = null;
2768 boolean startIt = true;
2769 for (int i = NH-1; i >= 0; i--) {
2770 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2771 if (p.finishing) {
2772 continue;
2773 }
2774 if (p.task == r.task) {
2775 // Here it is! Now, if this is not yet visible to the
2776 // user, then just add it without starting; it will
2777 // get started when the user navigates back to it.
2778 addPos = i+1;
2779 if (!startIt) {
2780 mHistory.add(addPos, r);
2781 r.inHistory = true;
2782 r.task.numActivities++;
2783 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2784 r.info.screenOrientation, r.fullscreen);
2785 if (VALIDATE_TOKENS) {
2786 mWindowManager.validateAppTokens(mHistory);
2787 }
2788 return;
2789 }
2790 break;
2791 }
2792 if (p.fullscreen) {
2793 startIt = false;
2794 }
2795 next = p;
2796 }
2797 }
2798
2799 // Place a new activity at top of stack, so it is next to interact
2800 // with the user.
2801 if (addPos < 0) {
2802 addPos = mHistory.size();
2803 }
2804
2805 // If we are not placing the new activity frontmost, we do not want
2806 // to deliver the onUserLeaving callback to the actual frontmost
2807 // activity
2808 if (addPos < NH) {
2809 mUserLeaving = false;
2810 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2811 }
2812
2813 // Slot the activity into the history stack and proceed
2814 mHistory.add(addPos, r);
2815 r.inHistory = true;
2816 r.frontOfTask = newTask;
2817 r.task.numActivities++;
2818 if (NH > 0) {
2819 // We want to show the starting preview window if we are
2820 // switching to a new task, or the next activity's process is
2821 // not currently running.
2822 boolean showStartingIcon = newTask;
2823 ProcessRecord proc = r.app;
2824 if (proc == null) {
2825 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2826 }
2827 if (proc == null || proc.thread == null) {
2828 showStartingIcon = true;
2829 }
2830 if (DEBUG_TRANSITION) Log.v(TAG,
2831 "Prepare open transition: starting " + r);
2832 mWindowManager.prepareAppTransition(newTask
2833 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2834 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2835 mWindowManager.addAppToken(
2836 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2837 boolean doShow = true;
2838 if (newTask) {
2839 // Even though this activity is starting fresh, we still need
2840 // to reset it to make sure we apply affinities to move any
2841 // existing activities from other tasks in to it.
2842 // If the caller has requested that the target task be
2843 // reset, then do so.
2844 if ((r.intent.getFlags()
2845 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2846 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002847 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002848 }
2849 }
2850 if (SHOW_APP_STARTING_ICON && doShow) {
2851 // Figure out if we are transitioning from another activity that is
2852 // "has the same starting icon" as the next one. This allows the
2853 // window manager to keep the previous window it had previously
2854 // created, if it still had one.
2855 HistoryRecord prev = mResumedActivity;
2856 if (prev != null) {
2857 // We don't want to reuse the previous starting preview if:
2858 // (1) The current activity is in a different task.
2859 if (prev.task != r.task) prev = null;
2860 // (2) The current activity is already displayed.
2861 else if (prev.nowVisible) prev = null;
2862 }
2863 mWindowManager.setAppStartingWindow(
2864 r, r.packageName, r.theme, r.nonLocalizedLabel,
2865 r.labelRes, r.icon, prev, showStartingIcon);
2866 }
2867 } else {
2868 // If this is the first activity, don't do any fancy animations,
2869 // because there is nothing for it to animate on top of.
2870 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2871 r.info.screenOrientation, r.fullscreen);
2872 }
2873 if (VALIDATE_TOKENS) {
2874 mWindowManager.validateAppTokens(mHistory);
2875 }
2876
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002877 if (doResume) {
2878 resumeTopActivityLocked(null);
2879 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002880 }
2881
2882 /**
2883 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002884 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2885 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002886 * an instance of that activity in the stack and, if found, finish all
2887 * activities on top of it and return the instance.
2888 *
2889 * @param newR Description of the new activity being started.
2890 * @return Returns the old activity that should be continue to be used,
2891 * or null if none was found.
2892 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002893 private final HistoryRecord performClearTaskLocked(int taskId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002894 HistoryRecord newR, boolean doClear) {
2895 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002896
2897 // First find the requested task.
2898 while (i > 0) {
2899 i--;
2900 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2901 if (r.task.taskId == taskId) {
2902 i++;
2903 break;
2904 }
2905 }
2906
2907 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002908 while (i > 0) {
2909 i--;
2910 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2911 if (r.finishing) {
2912 continue;
2913 }
2914 if (r.task.taskId != taskId) {
2915 return null;
2916 }
2917 if (r.realActivity.equals(newR.realActivity)) {
2918 // Here it is! Now finish everything in front...
2919 HistoryRecord ret = r;
2920 if (doClear) {
2921 while (i < (mHistory.size()-1)) {
2922 i++;
2923 r = (HistoryRecord)mHistory.get(i);
2924 if (r.finishing) {
2925 continue;
2926 }
2927 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2928 null, "clear")) {
2929 i--;
2930 }
2931 }
2932 }
2933
2934 // Finally, if this is a normal launch mode (that is, not
2935 // expecting onNewIntent()), then we will finish the current
2936 // instance of the activity so a new fresh one can be started.
2937 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
2938 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002939 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002940 if (index >= 0) {
2941 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2942 null, "clear");
2943 }
2944 return null;
2945 }
2946 }
2947
2948 return ret;
2949 }
2950 }
2951
2952 return null;
2953 }
2954
2955 /**
2956 * Find the activity in the history stack within the given task. Returns
2957 * the index within the history at which it's found, or < 0 if not found.
2958 */
2959 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2960 int i = mHistory.size();
2961 while (i > 0) {
2962 i--;
2963 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2964 if (candidate.task.taskId != task) {
2965 break;
2966 }
2967 if (candidate.realActivity.equals(r.realActivity)) {
2968 return i;
2969 }
2970 }
2971
2972 return -1;
2973 }
2974
2975 /**
2976 * Reorder the history stack so that the activity at the given index is
2977 * brought to the front.
2978 */
2979 private final HistoryRecord moveActivityToFrontLocked(int where) {
2980 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
2981 int top = mHistory.size();
2982 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
2983 mHistory.add(top, newTop);
2984 oldTop.frontOfTask = false;
2985 newTop.frontOfTask = true;
2986 return newTop;
2987 }
2988
2989 /**
2990 * Deliver a new Intent to an existing activity, so that its onNewIntent()
2991 * method will be called at the proper time.
2992 */
2993 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
2994 boolean sent = false;
2995 if (r.state == ActivityState.RESUMED
2996 && r.app != null && r.app.thread != null) {
2997 try {
2998 ArrayList<Intent> ar = new ArrayList<Intent>();
2999 ar.add(new Intent(intent));
3000 r.app.thread.scheduleNewIntent(ar, r);
3001 sent = true;
3002 } catch (Exception e) {
3003 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
3004 }
3005 }
3006 if (!sent) {
3007 r.addNewIntentLocked(new Intent(intent));
3008 }
3009 }
3010
3011 private final void logStartActivity(int tag, HistoryRecord r,
3012 TaskRecord task) {
3013 EventLog.writeEvent(tag,
3014 System.identityHashCode(r), task.taskId,
3015 r.shortComponentName, r.intent.getAction(),
3016 r.intent.getType(), r.intent.getDataString(),
3017 r.intent.getFlags());
3018 }
3019
3020 private final int startActivityLocked(IApplicationThread caller,
3021 Intent intent, String resolvedType,
3022 Uri[] grantedUriPermissions,
3023 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3024 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003025 int callingPid, int callingUid, boolean onlyIfNeeded,
3026 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003027 Log.i(TAG, "Starting activity: " + intent);
3028
3029 HistoryRecord sourceRecord = null;
3030 HistoryRecord resultRecord = null;
3031 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003032 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003033 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003034 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3035 if (index >= 0) {
3036 sourceRecord = (HistoryRecord)mHistory.get(index);
3037 if (requestCode >= 0 && !sourceRecord.finishing) {
3038 resultRecord = sourceRecord;
3039 }
3040 }
3041 }
3042
3043 int launchFlags = intent.getFlags();
3044
3045 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3046 && sourceRecord != null) {
3047 // Transfer the result target from the source activity to the new
3048 // one being started, including any failures.
3049 if (requestCode >= 0) {
3050 return START_FORWARD_AND_REQUEST_CONFLICT;
3051 }
3052 resultRecord = sourceRecord.resultTo;
3053 resultWho = sourceRecord.resultWho;
3054 requestCode = sourceRecord.requestCode;
3055 sourceRecord.resultTo = null;
3056 if (resultRecord != null) {
3057 resultRecord.removeResultsLocked(
3058 sourceRecord, resultWho, requestCode);
3059 }
3060 }
3061
3062 int err = START_SUCCESS;
3063
3064 if (intent.getComponent() == null) {
3065 // We couldn't find a class that can handle the given Intent.
3066 // That's the end of that!
3067 err = START_INTENT_NOT_RESOLVED;
3068 }
3069
3070 if (err == START_SUCCESS && aInfo == null) {
3071 // We couldn't find the specific class specified in the Intent.
3072 // Also the end of the line.
3073 err = START_CLASS_NOT_FOUND;
3074 }
3075
3076 ProcessRecord callerApp = null;
3077 if (err == START_SUCCESS && caller != null) {
3078 callerApp = getRecordForAppLocked(caller);
3079 if (callerApp != null) {
3080 callingPid = callerApp.pid;
3081 callingUid = callerApp.info.uid;
3082 } else {
3083 Log.w(TAG, "Unable to find app for caller " + caller
3084 + " (pid=" + callingPid + ") when starting: "
3085 + intent.toString());
3086 err = START_PERMISSION_DENIED;
3087 }
3088 }
3089
3090 if (err != START_SUCCESS) {
3091 if (resultRecord != null) {
3092 sendActivityResultLocked(-1,
3093 resultRecord, resultWho, requestCode,
3094 Activity.RESULT_CANCELED, null);
3095 }
3096 return err;
3097 }
3098
3099 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3100 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3101 if (perm != PackageManager.PERMISSION_GRANTED) {
3102 if (resultRecord != null) {
3103 sendActivityResultLocked(-1,
3104 resultRecord, resultWho, requestCode,
3105 Activity.RESULT_CANCELED, null);
3106 }
3107 String msg = "Permission Denial: starting " + intent.toString()
3108 + " from " + callerApp + " (pid=" + callingPid
3109 + ", uid=" + callingUid + ")"
3110 + " requires " + aInfo.permission;
3111 Log.w(TAG, msg);
3112 throw new SecurityException(msg);
3113 }
3114
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003115 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003116 boolean abort = false;
3117 try {
3118 // The Intent we give to the watcher has the extra data
3119 // stripped off, since it can contain private information.
3120 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003121 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003122 aInfo.applicationInfo.packageName);
3123 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003124 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003125 }
3126
3127 if (abort) {
3128 if (resultRecord != null) {
3129 sendActivityResultLocked(-1,
3130 resultRecord, resultWho, requestCode,
3131 Activity.RESULT_CANCELED, null);
3132 }
3133 // We pretend to the caller that it was really started, but
3134 // they will just get a cancel result.
3135 return START_SUCCESS;
3136 }
3137 }
3138
3139 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3140 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003141 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003142
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003143 if (mResumedActivity == null
3144 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3145 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3146 PendingActivityLaunch pal = new PendingActivityLaunch();
3147 pal.r = r;
3148 pal.sourceRecord = sourceRecord;
3149 pal.grantedUriPermissions = grantedUriPermissions;
3150 pal.grantedMode = grantedMode;
3151 pal.onlyIfNeeded = onlyIfNeeded;
3152 mPendingActivityLaunches.add(pal);
3153 return START_SWITCHES_CANCELED;
3154 }
3155 }
3156
3157 if (mDidAppSwitch) {
3158 // This is the second allowed switch since we stopped switches,
3159 // so now just generally allow switches. Use case: user presses
3160 // home (switches disabled, switch to home, mDidAppSwitch now true);
3161 // user taps a home icon (coming from home so allowed, we hit here
3162 // and now allow anyone to switch again).
3163 mAppSwitchesAllowedTime = 0;
3164 } else {
3165 mDidAppSwitch = true;
3166 }
3167
3168 doPendingActivityLaunchesLocked(false);
3169
3170 return startActivityUncheckedLocked(r, sourceRecord,
3171 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3172 }
3173
3174 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3175 final int N = mPendingActivityLaunches.size();
3176 if (N <= 0) {
3177 return;
3178 }
3179 for (int i=0; i<N; i++) {
3180 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3181 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3182 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3183 doResume && i == (N-1));
3184 }
3185 mPendingActivityLaunches.clear();
3186 }
3187
3188 private final int startActivityUncheckedLocked(HistoryRecord r,
3189 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3190 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3191 final Intent intent = r.intent;
3192 final int callingUid = r.launchedFromUid;
3193
3194 int launchFlags = intent.getFlags();
3195
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003196 // We'll invoke onUserLeaving before onPause only if the launching
3197 // activity did not explicitly state that this is an automated launch.
3198 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3199 if (DEBUG_USER_LEAVING) Log.v(TAG,
3200 "startActivity() => mUserLeaving=" + mUserLeaving);
3201
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003202 // If the caller has asked not to resume at this point, we make note
3203 // of this in the record so that we can skip it when trying to find
3204 // the top running activity.
3205 if (!doResume) {
3206 r.delayedResume = true;
3207 }
3208
3209 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3210 != 0 ? r : null;
3211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003212 // If the onlyIfNeeded flag is set, then we can do this if the activity
3213 // being launched is the same as the one making the call... or, as
3214 // a special case, if we do not know the caller then we count the
3215 // current top activity as the caller.
3216 if (onlyIfNeeded) {
3217 HistoryRecord checkedCaller = sourceRecord;
3218 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003219 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003220 }
3221 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3222 // Caller is not the same as launcher, so always needed.
3223 onlyIfNeeded = false;
3224 }
3225 }
3226
3227 if (grantedUriPermissions != null && callingUid > 0) {
3228 for (int i=0; i<grantedUriPermissions.length; i++) {
3229 grantUriPermissionLocked(callingUid, r.packageName,
3230 grantedUriPermissions[i], grantedMode, r);
3231 }
3232 }
3233
3234 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3235 intent, r);
3236
3237 if (sourceRecord == null) {
3238 // This activity is not being started from another... in this
3239 // case we -always- start a new task.
3240 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3241 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3242 + intent);
3243 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3244 }
3245 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3246 // The original activity who is starting us is running as a single
3247 // instance... this new activity it is starting must go on its
3248 // own task.
3249 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3250 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3251 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3252 // The activity being started is a single instance... it always
3253 // gets launched into its own task.
3254 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3255 }
3256
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003257 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003258 // For whatever reason this activity is being launched into a new
3259 // task... yet the caller has requested a result back. Well, that
3260 // is pretty messed up, so instead immediately send back a cancel
3261 // and let the new task continue launched as normal without a
3262 // dependency on its originator.
3263 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3264 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003265 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003266 Activity.RESULT_CANCELED, null);
3267 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003268 }
3269
3270 boolean addingToTask = false;
3271 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3272 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3273 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3274 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3275 // If bring to front is requested, and no result is requested, and
3276 // we can find a task that was started with this same
3277 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003278 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003279 // See if there is a task to bring to the front. If this is
3280 // a SINGLE_INSTANCE activity, there can be one and only one
3281 // instance of it in the history, and it is always in its own
3282 // unique task, so we do a special search.
3283 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3284 ? findTaskLocked(intent, r.info)
3285 : findActivityLocked(intent, r.info);
3286 if (taskTop != null) {
3287 if (taskTop.task.intent == null) {
3288 // This task was started because of movement of
3289 // the activity based on affinity... now that we
3290 // are actually launching it, we can assign the
3291 // base intent.
3292 taskTop.task.setIntent(intent, r.info);
3293 }
3294 // If the target task is not in the front, then we need
3295 // to bring it to the front... except... well, with
3296 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3297 // to have the same behavior as if a new instance was
3298 // being started, which means not bringing it to the front
3299 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003300 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003301 if (curTop.task != taskTop.task) {
3302 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3303 boolean callerAtFront = sourceRecord == null
3304 || curTop.task == sourceRecord.task;
3305 if (callerAtFront) {
3306 // We really do want to push this one into the
3307 // user's face, right now.
3308 moveTaskToFrontLocked(taskTop.task);
3309 }
3310 }
3311 // If the caller has requested that the target task be
3312 // reset, then do so.
3313 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3314 taskTop = resetTaskIfNeededLocked(taskTop, r);
3315 }
3316 if (onlyIfNeeded) {
3317 // We don't need to start a new activity, and
3318 // the client said not to do anything if that
3319 // is the case, so this is it! And for paranoia, make
3320 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003321 if (doResume) {
3322 resumeTopActivityLocked(null);
3323 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003324 return START_RETURN_INTENT_TO_CALLER;
3325 }
3326 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3327 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3328 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3329 // In this situation we want to remove all activities
3330 // from the task up to the one being started. In most
3331 // cases this means we are resetting the task to its
3332 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003333 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003334 taskTop.task.taskId, r, true);
3335 if (top != null) {
3336 if (top.frontOfTask) {
3337 // Activity aliases may mean we use different
3338 // intents for the top activity, so make sure
3339 // the task now has the identity of the new
3340 // intent.
3341 top.task.setIntent(r.intent, r.info);
3342 }
3343 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3344 deliverNewIntentLocked(top, r.intent);
3345 } else {
3346 // A special case: we need to
3347 // start the activity because it is not currently
3348 // running, and the caller has asked to clear the
3349 // current task to have this activity at the top.
3350 addingToTask = true;
3351 // Now pretend like this activity is being started
3352 // by the top of its task, so it is put in the
3353 // right place.
3354 sourceRecord = taskTop;
3355 }
3356 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3357 // In this case the top activity on the task is the
3358 // same as the one being launched, so we take that
3359 // as a request to bring the task to the foreground.
3360 // If the top activity in the task is the root
3361 // activity, deliver this new intent to it if it
3362 // desires.
3363 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3364 && taskTop.realActivity.equals(r.realActivity)) {
3365 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3366 if (taskTop.frontOfTask) {
3367 taskTop.task.setIntent(r.intent, r.info);
3368 }
3369 deliverNewIntentLocked(taskTop, r.intent);
3370 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3371 // In this case we are launching the root activity
3372 // of the task, but with a different intent. We
3373 // should start a new instance on top.
3374 addingToTask = true;
3375 sourceRecord = taskTop;
3376 }
3377 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3378 // In this case an activity is being launched in to an
3379 // existing task, without resetting that task. This
3380 // is typically the situation of launching an activity
3381 // from a notification or shortcut. We want to place
3382 // the new activity on top of the current task.
3383 addingToTask = true;
3384 sourceRecord = taskTop;
3385 } else if (!taskTop.task.rootWasReset) {
3386 // In this case we are launching in to an existing task
3387 // that has not yet been started from its front door.
3388 // The current task has been brought to the front.
3389 // Ideally, we'd probably like to place this new task
3390 // at the bottom of its stack, but that's a little hard
3391 // to do with the current organization of the code so
3392 // for now we'll just drop it.
3393 taskTop.task.setIntent(r.intent, r.info);
3394 }
3395 if (!addingToTask) {
3396 // We didn't do anything... but it was needed (a.k.a., client
3397 // don't use that intent!) And for paranoia, make
3398 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003399 if (doResume) {
3400 resumeTopActivityLocked(null);
3401 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003402 return START_TASK_TO_FRONT;
3403 }
3404 }
3405 }
3406 }
3407
3408 //String uri = r.intent.toURI();
3409 //Intent intent2 = new Intent(uri);
3410 //Log.i(TAG, "Given intent: " + r.intent);
3411 //Log.i(TAG, "URI is: " + uri);
3412 //Log.i(TAG, "To intent: " + intent2);
3413
3414 if (r.packageName != null) {
3415 // If the activity being launched is the same as the one currently
3416 // at the top, then we need to check if it should only be launched
3417 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003418 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3419 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003420 if (top.realActivity.equals(r.realActivity)) {
3421 if (top.app != null && top.app.thread != null) {
3422 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3423 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3424 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3425 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3426 // For paranoia, make sure we have correctly
3427 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003428 if (doResume) {
3429 resumeTopActivityLocked(null);
3430 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003431 if (onlyIfNeeded) {
3432 // We don't need to start a new activity, and
3433 // the client said not to do anything if that
3434 // is the case, so this is it!
3435 return START_RETURN_INTENT_TO_CALLER;
3436 }
3437 deliverNewIntentLocked(top, r.intent);
3438 return START_DELIVERED_TO_TOP;
3439 }
3440 }
3441 }
3442 }
3443
3444 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003445 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003446 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003447 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003448 Activity.RESULT_CANCELED, null);
3449 }
3450 return START_CLASS_NOT_FOUND;
3451 }
3452
3453 boolean newTask = false;
3454
3455 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003456 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003457 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3458 // todo: should do better management of integers.
3459 mCurTask++;
3460 if (mCurTask <= 0) {
3461 mCurTask = 1;
3462 }
3463 r.task = new TaskRecord(mCurTask, r.info, intent,
3464 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3465 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3466 + " in new task " + r.task);
3467 newTask = true;
3468 addRecentTask(r.task);
3469
3470 } else if (sourceRecord != null) {
3471 if (!addingToTask &&
3472 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3473 // In this case, we are adding the activity to an existing
3474 // task, but the caller has asked to clear that task if the
3475 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003476 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003477 sourceRecord.task.taskId, r, true);
3478 if (top != null) {
3479 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3480 deliverNewIntentLocked(top, r.intent);
3481 // For paranoia, make sure we have correctly
3482 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003483 if (doResume) {
3484 resumeTopActivityLocked(null);
3485 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003486 return START_DELIVERED_TO_TOP;
3487 }
3488 } else if (!addingToTask &&
3489 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3490 // In this case, we are launching an activity in our own task
3491 // that may already be running somewhere in the history, and
3492 // we want to shuffle it to the front of the stack if so.
3493 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3494 if (where >= 0) {
3495 HistoryRecord top = moveActivityToFrontLocked(where);
3496 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3497 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003498 if (doResume) {
3499 resumeTopActivityLocked(null);
3500 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003501 return START_DELIVERED_TO_TOP;
3502 }
3503 }
3504 // An existing activity is starting this new activity, so we want
3505 // to keep the new one in the same task as the one that is starting
3506 // it.
3507 r.task = sourceRecord.task;
3508 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3509 + " in existing task " + r.task);
3510
3511 } else {
3512 // This not being started from an existing activity, and not part
3513 // of a new task... just put it in the top task, though these days
3514 // this case should never happen.
3515 final int N = mHistory.size();
3516 HistoryRecord prev =
3517 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3518 r.task = prev != null
3519 ? prev.task
3520 : new TaskRecord(mCurTask, r.info, intent,
3521 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3522 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3523 + " in new guessed " + r.task);
3524 }
3525 if (newTask) {
3526 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3527 }
3528 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003529 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003530 return START_SUCCESS;
3531 }
3532
3533 public final int startActivity(IApplicationThread caller,
3534 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3535 int grantedMode, IBinder resultTo,
3536 String resultWho, int requestCode, boolean onlyIfNeeded,
3537 boolean debug) {
3538 // Refuse possible leaked file descriptors
3539 if (intent != null && intent.hasFileDescriptors()) {
3540 throw new IllegalArgumentException("File descriptors passed in Intent");
3541 }
3542
The Android Open Source Project4df24232009-03-05 14:34:35 -08003543 final boolean componentSpecified = intent.getComponent() != null;
3544
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003545 // Don't modify the client's object!
3546 intent = new Intent(intent);
3547
3548 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003549 ActivityInfo aInfo;
3550 try {
3551 ResolveInfo rInfo =
3552 ActivityThread.getPackageManager().resolveIntent(
3553 intent, resolvedType,
3554 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003555 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003556 aInfo = rInfo != null ? rInfo.activityInfo : null;
3557 } catch (RemoteException e) {
3558 aInfo = null;
3559 }
3560
3561 if (aInfo != null) {
3562 // Store the found target back into the intent, because now that
3563 // we have it we never want to do this again. For example, if the
3564 // user navigates back to this point in the history, we should
3565 // always restart the exact same activity.
3566 intent.setComponent(new ComponentName(
3567 aInfo.applicationInfo.packageName, aInfo.name));
3568
3569 // Don't debug things in the system process
3570 if (debug) {
3571 if (!aInfo.processName.equals("system")) {
3572 setDebugApp(aInfo.processName, true, false);
3573 }
3574 }
3575 }
3576
3577 synchronized(this) {
3578 final long origId = Binder.clearCallingIdentity();
3579 int res = startActivityLocked(caller, intent, resolvedType,
3580 grantedUriPermissions, grantedMode, aInfo,
3581 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003582 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003583 Binder.restoreCallingIdentity(origId);
3584 return res;
3585 }
3586 }
3587
3588 public boolean startNextMatchingActivity(IBinder callingActivity,
3589 Intent intent) {
3590 // Refuse possible leaked file descriptors
3591 if (intent != null && intent.hasFileDescriptors() == true) {
3592 throw new IllegalArgumentException("File descriptors passed in Intent");
3593 }
3594
3595 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003596 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003597 if (index < 0) {
3598 return false;
3599 }
3600 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3601 if (r.app == null || r.app.thread == null) {
3602 // The caller is not running... d'oh!
3603 return false;
3604 }
3605 intent = new Intent(intent);
3606 // The caller is not allowed to change the data.
3607 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3608 // And we are resetting to find the next component...
3609 intent.setComponent(null);
3610
3611 ActivityInfo aInfo = null;
3612 try {
3613 List<ResolveInfo> resolves =
3614 ActivityThread.getPackageManager().queryIntentActivities(
3615 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003616 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003617
3618 // Look for the original activity in the list...
3619 final int N = resolves != null ? resolves.size() : 0;
3620 for (int i=0; i<N; i++) {
3621 ResolveInfo rInfo = resolves.get(i);
3622 if (rInfo.activityInfo.packageName.equals(r.packageName)
3623 && rInfo.activityInfo.name.equals(r.info.name)) {
3624 // We found the current one... the next matching is
3625 // after it.
3626 i++;
3627 if (i<N) {
3628 aInfo = resolves.get(i).activityInfo;
3629 }
3630 break;
3631 }
3632 }
3633 } catch (RemoteException e) {
3634 }
3635
3636 if (aInfo == null) {
3637 // Nobody who is next!
3638 return false;
3639 }
3640
3641 intent.setComponent(new ComponentName(
3642 aInfo.applicationInfo.packageName, aInfo.name));
3643 intent.setFlags(intent.getFlags()&~(
3644 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3645 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3646 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3647 Intent.FLAG_ACTIVITY_NEW_TASK));
3648
3649 // Okay now we need to start the new activity, replacing the
3650 // currently running activity. This is a little tricky because
3651 // we want to start the new one as if the current one is finished,
3652 // but not finish the current one first so that there is no flicker.
3653 // And thus...
3654 final boolean wasFinishing = r.finishing;
3655 r.finishing = true;
3656
3657 // Propagate reply information over to the new activity.
3658 final HistoryRecord resultTo = r.resultTo;
3659 final String resultWho = r.resultWho;
3660 final int requestCode = r.requestCode;
3661 r.resultTo = null;
3662 if (resultTo != null) {
3663 resultTo.removeResultsLocked(r, resultWho, requestCode);
3664 }
3665
3666 final long origId = Binder.clearCallingIdentity();
3667 // XXX we are not dealing with propagating grantedUriPermissions...
3668 // those are not yet exposed to user code, so there is no need.
3669 int res = startActivityLocked(r.app.thread, intent,
3670 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003671 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003672 Binder.restoreCallingIdentity(origId);
3673
3674 r.finishing = wasFinishing;
3675 if (res != START_SUCCESS) {
3676 return false;
3677 }
3678 return true;
3679 }
3680 }
3681
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003682 public final int startActivityInPackage(int uid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003683 Intent intent, String resolvedType, IBinder resultTo,
3684 String resultWho, int requestCode, boolean onlyIfNeeded) {
Dianne Hackborn2d91af02009-07-16 13:34:33 -07003685
3686 // This is so super not safe, that only the system (or okay root)
3687 // can do it.
3688 final int callingUid = Binder.getCallingUid();
3689 if (callingUid != 0 && callingUid != Process.myUid()) {
3690 throw new SecurityException(
3691 "startActivityInPackage only available to the system");
3692 }
3693
The Android Open Source Project4df24232009-03-05 14:34:35 -08003694 final boolean componentSpecified = intent.getComponent() != null;
3695
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003696 // Don't modify the client's object!
3697 intent = new Intent(intent);
3698
3699 // Collect information about the target of the Intent.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003700 ActivityInfo aInfo;
3701 try {
3702 ResolveInfo rInfo =
3703 ActivityThread.getPackageManager().resolveIntent(
3704 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003705 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003706 aInfo = rInfo != null ? rInfo.activityInfo : null;
3707 } catch (RemoteException e) {
3708 aInfo = null;
3709 }
3710
3711 if (aInfo != null) {
3712 // Store the found target back into the intent, because now that
3713 // we have it we never want to do this again. For example, if the
3714 // user navigates back to this point in the history, we should
3715 // always restart the exact same activity.
3716 intent.setComponent(new ComponentName(
3717 aInfo.applicationInfo.packageName, aInfo.name));
3718 }
3719
3720 synchronized(this) {
3721 return startActivityLocked(null, intent, resolvedType,
3722 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003723 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003724 }
3725 }
3726
3727 private final void addRecentTask(TaskRecord task) {
3728 // Remove any existing entries that are the same kind of task.
3729 int N = mRecentTasks.size();
3730 for (int i=0; i<N; i++) {
3731 TaskRecord tr = mRecentTasks.get(i);
3732 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3733 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3734 mRecentTasks.remove(i);
3735 i--;
3736 N--;
3737 if (task.intent == null) {
3738 // If the new recent task we are adding is not fully
3739 // specified, then replace it with the existing recent task.
3740 task = tr;
3741 }
3742 }
3743 }
3744 if (N >= MAX_RECENT_TASKS) {
3745 mRecentTasks.remove(N-1);
3746 }
3747 mRecentTasks.add(0, task);
3748 }
3749
3750 public void setRequestedOrientation(IBinder token,
3751 int requestedOrientation) {
3752 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003753 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003754 if (index < 0) {
3755 return;
3756 }
3757 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3758 final long origId = Binder.clearCallingIdentity();
3759 mWindowManager.setAppOrientation(r, requestedOrientation);
3760 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003761 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003762 r.mayFreezeScreenLocked(r.app) ? r : null);
3763 if (config != null) {
3764 r.frozenBeforeDestroy = true;
3765 if (!updateConfigurationLocked(config, r)) {
3766 resumeTopActivityLocked(null);
3767 }
3768 }
3769 Binder.restoreCallingIdentity(origId);
3770 }
3771 }
3772
3773 public int getRequestedOrientation(IBinder token) {
3774 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003775 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003776 if (index < 0) {
3777 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3778 }
3779 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3780 return mWindowManager.getAppOrientation(r);
3781 }
3782 }
3783
3784 private final void stopActivityLocked(HistoryRecord r) {
3785 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3786 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3787 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3788 if (!r.finishing) {
3789 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3790 "no-history");
3791 }
3792 } else if (r.app != null && r.app.thread != null) {
3793 if (mFocusedActivity == r) {
3794 setFocusedActivityLocked(topRunningActivityLocked(null));
3795 }
3796 r.resumeKeyDispatchingLocked();
3797 try {
3798 r.stopped = false;
3799 r.state = ActivityState.STOPPING;
3800 if (DEBUG_VISBILITY) Log.v(
3801 TAG, "Stopping visible=" + r.visible + " for " + r);
3802 if (!r.visible) {
3803 mWindowManager.setAppVisibility(r, false);
3804 }
3805 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3806 } catch (Exception e) {
3807 // Maybe just ignore exceptions here... if the process
3808 // has crashed, our death notification will clean things
3809 // up.
3810 Log.w(TAG, "Exception thrown during pause", e);
3811 // Just in case, assume it to be stopped.
3812 r.stopped = true;
3813 r.state = ActivityState.STOPPED;
3814 if (r.configDestroy) {
3815 destroyActivityLocked(r, true);
3816 }
3817 }
3818 }
3819 }
3820
3821 /**
3822 * @return Returns true if the activity is being finished, false if for
3823 * some reason it is being left as-is.
3824 */
3825 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3826 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003827 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003828 TAG, "Finishing activity: token=" + token
3829 + ", result=" + resultCode + ", data=" + resultData);
3830
Dianne Hackborn75b03852009-06-12 15:43:26 -07003831 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003832 if (index < 0) {
3833 return false;
3834 }
3835 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3836
3837 // Is this the last activity left?
3838 boolean lastActivity = true;
3839 for (int i=mHistory.size()-1; i>=0; i--) {
3840 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3841 if (!p.finishing && p != r) {
3842 lastActivity = false;
3843 break;
3844 }
3845 }
3846
3847 // If this is the last activity, but it is the home activity, then
3848 // just don't finish it.
3849 if (lastActivity) {
3850 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3851 return false;
3852 }
3853 }
3854
3855 finishActivityLocked(r, index, resultCode, resultData, reason);
3856 return true;
3857 }
3858
3859 /**
3860 * @return Returns true if this activity has been removed from the history
3861 * list, or false if it is still in the list and will be removed later.
3862 */
3863 private final boolean finishActivityLocked(HistoryRecord r, int index,
3864 int resultCode, Intent resultData, String reason) {
3865 if (r.finishing) {
3866 Log.w(TAG, "Duplicate finish request for " + r);
3867 return false;
3868 }
3869
3870 r.finishing = true;
3871 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3872 System.identityHashCode(r),
3873 r.task.taskId, r.shortComponentName, reason);
3874 r.task.numActivities--;
3875 if (r.frontOfTask && index < (mHistory.size()-1)) {
3876 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3877 if (next.task == r.task) {
3878 next.frontOfTask = true;
3879 }
3880 }
3881
3882 r.pauseKeyDispatchingLocked();
3883 if (mFocusedActivity == r) {
3884 setFocusedActivityLocked(topRunningActivityLocked(null));
3885 }
3886
3887 // send the result
3888 HistoryRecord resultTo = r.resultTo;
3889 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003890 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3891 + " who=" + r.resultWho + " req=" + r.requestCode
3892 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003893 if (r.info.applicationInfo.uid > 0) {
3894 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3895 r.packageName, resultData, r);
3896 }
3897 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3898 resultData);
3899 r.resultTo = null;
3900 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003901 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003902
3903 // Make sure this HistoryRecord is not holding on to other resources,
3904 // because clients have remote IPC references to this object so we
3905 // can't assume that will go away and want to avoid circular IPC refs.
3906 r.results = null;
3907 r.pendingResults = null;
3908 r.newIntents = null;
3909 r.icicle = null;
3910
3911 if (mPendingThumbnails.size() > 0) {
3912 // There are clients waiting to receive thumbnails so, in case
3913 // this is an activity that someone is waiting for, add it
3914 // to the pending list so we can correctly update the clients.
3915 mCancelledThumbnails.add(r);
3916 }
3917
3918 if (mResumedActivity == r) {
3919 boolean endTask = index <= 0
3920 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3921 if (DEBUG_TRANSITION) Log.v(TAG,
3922 "Prepare close transition: finishing " + r);
3923 mWindowManager.prepareAppTransition(endTask
3924 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3925 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3926
3927 // Tell window manager to prepare for this one to be removed.
3928 mWindowManager.setAppVisibility(r, false);
3929
3930 if (mPausingActivity == null) {
3931 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3932 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3933 startPausingLocked(false, false);
3934 }
3935
3936 } else if (r.state != ActivityState.PAUSING) {
3937 // If the activity is PAUSING, we will complete the finish once
3938 // it is done pausing; else we can just directly finish it here.
3939 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3940 return finishCurrentActivityLocked(r, index,
3941 FINISH_AFTER_PAUSE) == null;
3942 } else {
3943 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3944 }
3945
3946 return false;
3947 }
3948
3949 private static final int FINISH_IMMEDIATELY = 0;
3950 private static final int FINISH_AFTER_PAUSE = 1;
3951 private static final int FINISH_AFTER_VISIBLE = 2;
3952
3953 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3954 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003955 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003956 if (index < 0) {
3957 return null;
3958 }
3959
3960 return finishCurrentActivityLocked(r, index, mode);
3961 }
3962
3963 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3964 int index, int mode) {
3965 // First things first: if this activity is currently visible,
3966 // and the resumed activity is not yet visible, then hold off on
3967 // finishing until the resumed one becomes visible.
3968 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3969 if (!mStoppingActivities.contains(r)) {
3970 mStoppingActivities.add(r);
3971 if (mStoppingActivities.size() > 3) {
3972 // If we already have a few activities waiting to stop,
3973 // then give up on things going idle and start clearing
3974 // them out.
3975 Message msg = Message.obtain();
3976 msg.what = ActivityManagerService.IDLE_NOW_MSG;
3977 mHandler.sendMessage(msg);
3978 }
3979 }
3980 r.state = ActivityState.STOPPING;
3981 updateOomAdjLocked();
3982 return r;
3983 }
3984
3985 // make sure the record is cleaned out of other places.
3986 mStoppingActivities.remove(r);
3987 mWaitingVisibleActivities.remove(r);
3988 if (mResumedActivity == r) {
3989 mResumedActivity = null;
3990 }
3991 final ActivityState prevState = r.state;
3992 r.state = ActivityState.FINISHING;
3993
3994 if (mode == FINISH_IMMEDIATELY
3995 || prevState == ActivityState.STOPPED
3996 || prevState == ActivityState.INITIALIZING) {
3997 // If this activity is already stopped, we can just finish
3998 // it right now.
3999 return destroyActivityLocked(r, true) ? null : r;
4000 } else {
4001 // Need to go through the full pause cycle to get this
4002 // activity into the stopped state and then finish it.
4003 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
4004 mFinishingActivities.add(r);
4005 resumeTopActivityLocked(null);
4006 }
4007 return r;
4008 }
4009
4010 /**
4011 * This is the internal entry point for handling Activity.finish().
4012 *
4013 * @param token The Binder token referencing the Activity we want to finish.
4014 * @param resultCode Result code, if any, from this Activity.
4015 * @param resultData Result data (Intent), if any, from this Activity.
4016 *
4017 * @result Returns true if the activity successfully finished, or false if it is still running.
4018 */
4019 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
4020 // Refuse possible leaked file descriptors
4021 if (resultData != null && resultData.hasFileDescriptors() == true) {
4022 throw new IllegalArgumentException("File descriptors passed in Intent");
4023 }
4024
4025 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004026 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004027 // Find the first activity that is not finishing.
4028 HistoryRecord next = topRunningActivityLocked(token, 0);
4029 if (next != null) {
4030 // ask watcher if this is allowed
4031 boolean resumeOK = true;
4032 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004033 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004034 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004035 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004036 }
4037
4038 if (!resumeOK) {
4039 return false;
4040 }
4041 }
4042 }
4043 final long origId = Binder.clearCallingIdentity();
4044 boolean res = requestFinishActivityLocked(token, resultCode,
4045 resultData, "app-request");
4046 Binder.restoreCallingIdentity(origId);
4047 return res;
4048 }
4049 }
4050
4051 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4052 String resultWho, int requestCode, int resultCode, Intent data) {
4053
4054 if (callingUid > 0) {
4055 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4056 data, r);
4057 }
4058
The Android Open Source Project10592532009-03-18 17:39:46 -07004059 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4060 + " : who=" + resultWho + " req=" + requestCode
4061 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004062 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4063 try {
4064 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4065 list.add(new ResultInfo(resultWho, requestCode,
4066 resultCode, data));
4067 r.app.thread.scheduleSendResult(r, list);
4068 return;
4069 } catch (Exception e) {
4070 Log.w(TAG, "Exception thrown sending result to " + r, e);
4071 }
4072 }
4073
4074 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4075 }
4076
4077 public final void finishSubActivity(IBinder token, String resultWho,
4078 int requestCode) {
4079 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004080 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004081 if (index < 0) {
4082 return;
4083 }
4084 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4085
4086 final long origId = Binder.clearCallingIdentity();
4087
4088 int i;
4089 for (i=mHistory.size()-1; i>=0; i--) {
4090 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4091 if (r.resultTo == self && r.requestCode == requestCode) {
4092 if ((r.resultWho == null && resultWho == null) ||
4093 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4094 finishActivityLocked(r, i,
4095 Activity.RESULT_CANCELED, null, "request-sub");
4096 }
4097 }
4098 }
4099
4100 Binder.restoreCallingIdentity(origId);
4101 }
4102 }
4103
4104 /**
4105 * Perform clean-up of service connections in an activity record.
4106 */
4107 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4108 // Throw away any services that have been bound by this activity.
4109 if (r.connections != null) {
4110 Iterator<ConnectionRecord> it = r.connections.iterator();
4111 while (it.hasNext()) {
4112 ConnectionRecord c = it.next();
4113 removeConnectionLocked(c, null, r);
4114 }
4115 r.connections = null;
4116 }
4117 }
4118
4119 /**
4120 * Perform the common clean-up of an activity record. This is called both
4121 * as part of destroyActivityLocked() (when destroying the client-side
4122 * representation) and cleaning things up as a result of its hosting
4123 * processing going away, in which case there is no remaining client-side
4124 * state to destroy so only the cleanup here is needed.
4125 */
4126 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4127 if (mResumedActivity == r) {
4128 mResumedActivity = null;
4129 }
4130 if (mFocusedActivity == r) {
4131 mFocusedActivity = null;
4132 }
4133
4134 r.configDestroy = false;
4135 r.frozenBeforeDestroy = false;
4136
4137 // Make sure this record is no longer in the pending finishes list.
4138 // This could happen, for example, if we are trimming activities
4139 // down to the max limit while they are still waiting to finish.
4140 mFinishingActivities.remove(r);
4141 mWaitingVisibleActivities.remove(r);
4142
4143 // Remove any pending results.
4144 if (r.finishing && r.pendingResults != null) {
4145 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4146 PendingIntentRecord rec = apr.get();
4147 if (rec != null) {
4148 cancelIntentSenderLocked(rec, false);
4149 }
4150 }
4151 r.pendingResults = null;
4152 }
4153
4154 if (cleanServices) {
4155 cleanUpActivityServicesLocked(r);
4156 }
4157
4158 if (mPendingThumbnails.size() > 0) {
4159 // There are clients waiting to receive thumbnails so, in case
4160 // this is an activity that someone is waiting for, add it
4161 // to the pending list so we can correctly update the clients.
4162 mCancelledThumbnails.add(r);
4163 }
4164
4165 // Get rid of any pending idle timeouts.
4166 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4167 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4168 }
4169
4170 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4171 if (r.state != ActivityState.DESTROYED) {
4172 mHistory.remove(r);
4173 r.inHistory = false;
4174 r.state = ActivityState.DESTROYED;
4175 mWindowManager.removeAppToken(r);
4176 if (VALIDATE_TOKENS) {
4177 mWindowManager.validateAppTokens(mHistory);
4178 }
4179 cleanUpActivityServicesLocked(r);
4180 removeActivityUriPermissionsLocked(r);
4181 }
4182 }
4183
4184 /**
4185 * Destroy the current CLIENT SIDE instance of an activity. This may be
4186 * called both when actually finishing an activity, or when performing
4187 * a configuration switch where we destroy the current client-side object
4188 * but then create a new client-side object for this same HistoryRecord.
4189 */
4190 private final boolean destroyActivityLocked(HistoryRecord r,
4191 boolean removeFromApp) {
4192 if (DEBUG_SWITCH) Log.v(
4193 TAG, "Removing activity: token=" + r
4194 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4195 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4196 System.identityHashCode(r),
4197 r.task.taskId, r.shortComponentName);
4198
4199 boolean removedFromHistory = false;
4200
4201 cleanUpActivityLocked(r, false);
4202
4203 if (r.app != null) {
4204 if (removeFromApp) {
4205 int idx = r.app.activities.indexOf(r);
4206 if (idx >= 0) {
4207 r.app.activities.remove(idx);
4208 }
4209 if (r.persistent) {
4210 decPersistentCountLocked(r.app);
4211 }
4212 }
4213
4214 boolean skipDestroy = false;
4215
4216 try {
4217 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4218 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4219 r.configChangeFlags);
4220 } catch (Exception e) {
4221 // We can just ignore exceptions here... if the process
4222 // has crashed, our death notification will clean things
4223 // up.
4224 //Log.w(TAG, "Exception thrown during finish", e);
4225 if (r.finishing) {
4226 removeActivityFromHistoryLocked(r);
4227 removedFromHistory = true;
4228 skipDestroy = true;
4229 }
4230 }
4231
4232 r.app = null;
4233 r.nowVisible = false;
4234
4235 if (r.finishing && !skipDestroy) {
4236 r.state = ActivityState.DESTROYING;
4237 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4238 msg.obj = r;
4239 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4240 } else {
4241 r.state = ActivityState.DESTROYED;
4242 }
4243 } else {
4244 // remove this record from the history.
4245 if (r.finishing) {
4246 removeActivityFromHistoryLocked(r);
4247 removedFromHistory = true;
4248 } else {
4249 r.state = ActivityState.DESTROYED;
4250 }
4251 }
4252
4253 r.configChangeFlags = 0;
4254
4255 if (!mLRUActivities.remove(r)) {
4256 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4257 }
4258
4259 return removedFromHistory;
4260 }
4261
4262 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4263 ProcessRecord app)
4264 {
4265 int i = list.size();
4266 if (localLOGV) Log.v(
4267 TAG, "Removing app " + app + " from list " + list
4268 + " with " + i + " entries");
4269 while (i > 0) {
4270 i--;
4271 HistoryRecord r = (HistoryRecord)list.get(i);
4272 if (localLOGV) Log.v(
4273 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4274 if (r.app == app) {
4275 if (localLOGV) Log.v(TAG, "Removing this entry!");
4276 list.remove(i);
4277 }
4278 }
4279 }
4280
4281 /**
4282 * Main function for removing an existing process from the activity manager
4283 * as a result of that process going away. Clears out all connections
4284 * to the process.
4285 */
4286 private final void handleAppDiedLocked(ProcessRecord app,
4287 boolean restarting) {
4288 cleanUpApplicationRecordLocked(app, restarting, -1);
4289 if (!restarting) {
4290 mLRUProcesses.remove(app);
4291 }
4292
4293 // Just in case...
4294 if (mPausingActivity != null && mPausingActivity.app == app) {
4295 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4296 mPausingActivity = null;
4297 }
4298 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4299 mLastPausedActivity = null;
4300 }
4301
4302 // Remove this application's activities from active lists.
4303 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4304 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4305 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4306 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4307
4308 boolean atTop = true;
4309 boolean hasVisibleActivities = false;
4310
4311 // Clean out the history list.
4312 int i = mHistory.size();
4313 if (localLOGV) Log.v(
4314 TAG, "Removing app " + app + " from history with " + i + " entries");
4315 while (i > 0) {
4316 i--;
4317 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4318 if (localLOGV) Log.v(
4319 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4320 if (r.app == app) {
4321 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4322 if (localLOGV) Log.v(
4323 TAG, "Removing this entry! frozen=" + r.haveState
4324 + " finishing=" + r.finishing);
4325 mHistory.remove(i);
4326
4327 r.inHistory = false;
4328 mWindowManager.removeAppToken(r);
4329 if (VALIDATE_TOKENS) {
4330 mWindowManager.validateAppTokens(mHistory);
4331 }
4332 removeActivityUriPermissionsLocked(r);
4333
4334 } else {
4335 // We have the current state for this activity, so
4336 // it can be restarted later when needed.
4337 if (localLOGV) Log.v(
4338 TAG, "Keeping entry, setting app to null");
4339 if (r.visible) {
4340 hasVisibleActivities = true;
4341 }
4342 r.app = null;
4343 r.nowVisible = false;
4344 if (!r.haveState) {
4345 r.icicle = null;
4346 }
4347 }
4348
4349 cleanUpActivityLocked(r, true);
4350 r.state = ActivityState.STOPPED;
4351 }
4352 atTop = false;
4353 }
4354
4355 app.activities.clear();
4356
4357 if (app.instrumentationClass != null) {
4358 Log.w(TAG, "Crash of app " + app.processName
4359 + " running instrumentation " + app.instrumentationClass);
4360 Bundle info = new Bundle();
4361 info.putString("shortMsg", "Process crashed.");
4362 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4363 }
4364
4365 if (!restarting) {
4366 if (!resumeTopActivityLocked(null)) {
4367 // If there was nothing to resume, and we are not already
4368 // restarting this process, but there is a visible activity that
4369 // is hosted by the process... then make sure all visible
4370 // activities are running, taking care of restarting this
4371 // process.
4372 if (hasVisibleActivities) {
4373 ensureActivitiesVisibleLocked(null, 0);
4374 }
4375 }
4376 }
4377 }
4378
4379 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4380 IBinder threadBinder = thread.asBinder();
4381
4382 // Find the application record.
4383 int count = mLRUProcesses.size();
4384 int i;
4385 for (i=0; i<count; i++) {
4386 ProcessRecord rec = mLRUProcesses.get(i);
4387 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4388 return i;
4389 }
4390 }
4391 return -1;
4392 }
4393
4394 private final ProcessRecord getRecordForAppLocked(
4395 IApplicationThread thread) {
4396 if (thread == null) {
4397 return null;
4398 }
4399
4400 int appIndex = getLRURecordIndexForAppLocked(thread);
4401 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4402 }
4403
4404 private final void appDiedLocked(ProcessRecord app, int pid,
4405 IApplicationThread thread) {
4406
4407 mProcDeaths[0]++;
4408
4409 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4410 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4411 + ") has died.");
4412 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4413 if (localLOGV) Log.v(
4414 TAG, "Dying app: " + app + ", pid: " + pid
4415 + ", thread: " + thread.asBinder());
4416 boolean doLowMem = app.instrumentationClass == null;
4417 handleAppDiedLocked(app, false);
4418
4419 if (doLowMem) {
4420 // If there are no longer any background processes running,
4421 // and the app that died was not running instrumentation,
4422 // then tell everyone we are now low on memory.
4423 boolean haveBg = false;
4424 int count = mLRUProcesses.size();
4425 int i;
4426 for (i=0; i<count; i++) {
4427 ProcessRecord rec = mLRUProcesses.get(i);
4428 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4429 haveBg = true;
4430 break;
4431 }
4432 }
4433
4434 if (!haveBg) {
4435 Log.i(TAG, "Low Memory: No more background processes.");
4436 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
4437 for (i=0; i<count; i++) {
4438 ProcessRecord rec = mLRUProcesses.get(i);
4439 if (rec.thread != null) {
4440 rec.lastRequestedGc = SystemClock.uptimeMillis();
4441 try {
4442 rec.thread.scheduleLowMemory();
4443 } catch (RemoteException e) {
4444 // Don't care if the process is gone.
4445 }
4446 }
4447 }
4448 }
4449 }
4450 } else if (Config.LOGD) {
4451 Log.d(TAG, "Received spurious death notification for thread "
4452 + thread.asBinder());
4453 }
4454 }
4455
4456 final String readFile(String filename) {
4457 try {
4458 FileInputStream fs = new FileInputStream(filename);
4459 byte[] inp = new byte[8192];
4460 int size = fs.read(inp);
4461 fs.close();
4462 return new String(inp, 0, 0, size);
4463 } catch (java.io.IOException e) {
4464 }
4465 return "";
4466 }
4467
4468 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004469 HistoryRecord reportedActivity, final String annotation) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004470 if (app.notResponding || app.crashing) {
4471 return;
4472 }
4473
4474 // Log the ANR to the event log.
4475 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4476
4477 // If we are on a secure build and the application is not interesting to the user (it is
4478 // not visible or in the background), just kill it instead of displaying a dialog.
4479 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4480 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4481 Process.killProcess(app.pid);
4482 return;
4483 }
4484
4485 // DeviceMonitor.start();
4486
4487 String processInfo = null;
4488 if (MONITOR_CPU_USAGE) {
4489 updateCpuStatsNow();
4490 synchronized (mProcessStatsThread) {
4491 processInfo = mProcessStats.printCurrentState();
4492 }
4493 }
4494
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004495 StringBuilder info = mStringBuilder;
4496 info.setLength(0);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004497 info.append("ANR in process: ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004498 info.append(app.processName);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004499 if (reportedActivity != null && reportedActivity.app != null) {
4500 info.append(" (last in ");
4501 info.append(reportedActivity.app.processName);
4502 info.append(")");
4503 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004504 if (annotation != null) {
4505 info.append("\nAnnotation: ");
4506 info.append(annotation);
4507 }
4508 if (MONITOR_CPU_USAGE) {
4509 info.append("\nCPU usage:\n");
4510 info.append(processInfo);
4511 }
4512 Log.i(TAG, info.toString());
4513
4514 // The application is not responding. Dump as many thread traces as we can.
4515 boolean fileDump = prepareTraceFile(true);
4516 if (!fileDump) {
4517 // Dumping traces to the log, just dump the process that isn't responding so
4518 // we don't overflow the log
4519 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4520 } else {
4521 // Dumping traces to a file so dump all active processes we know about
4522 synchronized (this) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004523 // First, these are the most important processes.
4524 final int[] imppids = new int[3];
4525 int i=0;
4526 imppids[0] = app.pid;
4527 i++;
4528 if (reportedActivity != null && reportedActivity.app != null
4529 && reportedActivity.app.thread != null
4530 && reportedActivity.app.pid != app.pid) {
4531 imppids[i] = reportedActivity.app.pid;
4532 i++;
4533 }
4534 imppids[i] = Process.myPid();
4535 for (i=0; i<imppids.length && imppids[i] != 0; i++) {
4536 Process.sendSignal(imppids[i], Process.SIGNAL_QUIT);
4537 synchronized (this) {
4538 try {
4539 wait(200);
4540 } catch (InterruptedException e) {
4541 }
4542 }
4543 }
4544 for (i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004545 ProcessRecord r = mLRUProcesses.get(i);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004546 boolean done = false;
4547 for (int j=0; j<imppids.length && imppids[j] != 0; j++) {
4548 if (imppids[j] == r.pid) {
4549 done = true;
4550 break;
4551 }
4552 }
4553 if (!done && r.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004554 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004555 synchronized (this) {
4556 try {
4557 wait(200);
4558 } catch (InterruptedException e) {
4559 }
4560 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004561 }
4562 }
4563 }
4564 }
4565
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004566 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004567 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004568 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004569 app.pid, info.toString());
4570 if (res != 0) {
4571 if (res < 0) {
4572 // wait until the SIGQUIT has had a chance to process before killing the
4573 // process.
4574 try {
4575 wait(2000);
4576 } catch (InterruptedException e) {
4577 }
4578
4579 Process.killProcess(app.pid);
4580 return;
4581 }
4582 }
4583 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004584 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004585 }
4586 }
4587
4588 makeAppNotRespondingLocked(app,
4589 activity != null ? activity.shortComponentName : null,
4590 annotation != null ? "ANR " + annotation : "ANR",
4591 info.toString(), null);
4592 Message msg = Message.obtain();
4593 HashMap map = new HashMap();
4594 msg.what = SHOW_NOT_RESPONDING_MSG;
4595 msg.obj = map;
4596 map.put("app", app);
4597 if (activity != null) {
4598 map.put("activity", activity);
4599 }
4600
4601 mHandler.sendMessage(msg);
4602 return;
4603 }
4604
4605 /**
4606 * If a stack trace file has been configured, prepare the filesystem
4607 * by creating the directory if it doesn't exist and optionally
4608 * removing the old trace file.
4609 *
4610 * @param removeExisting If set, the existing trace file will be removed.
4611 * @return Returns true if the trace file preparations succeeded
4612 */
4613 public static boolean prepareTraceFile(boolean removeExisting) {
4614 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4615 boolean fileReady = false;
4616 if (!TextUtils.isEmpty(tracesPath)) {
4617 File f = new File(tracesPath);
4618 if (!f.exists()) {
4619 // Ensure the enclosing directory exists
4620 File dir = f.getParentFile();
4621 if (!dir.exists()) {
4622 fileReady = dir.mkdirs();
4623 FileUtils.setPermissions(dir.getAbsolutePath(),
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004624 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IXOTH, -1, -1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004625 } else if (dir.isDirectory()) {
4626 fileReady = true;
4627 }
4628 } else if (removeExisting) {
4629 // Remove the previous traces file, so we don't fill the disk.
4630 // The VM will recreate it
4631 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4632 fileReady = f.delete();
4633 }
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07004634
4635 if (removeExisting) {
4636 try {
4637 f.createNewFile();
4638 FileUtils.setPermissions(f.getAbsolutePath(),
4639 FileUtils.S_IRWXU | FileUtils.S_IRWXG
4640 | FileUtils.S_IWOTH | FileUtils.S_IROTH, -1, -1);
4641 fileReady = true;
4642 } catch (IOException e) {
4643 Log.w(TAG, "Unable to make ANR traces file", e);
4644 }
4645 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004646 }
4647
4648 return fileReady;
4649 }
4650
4651
4652 private final void decPersistentCountLocked(ProcessRecord app)
4653 {
4654 app.persistentActivities--;
4655 if (app.persistentActivities > 0) {
4656 // Still more of 'em...
4657 return;
4658 }
4659 if (app.persistent) {
4660 // Ah, but the application itself is persistent. Whatever!
4661 return;
4662 }
4663
4664 // App is no longer persistent... make sure it and the ones
4665 // following it in the LRU list have the correc oom_adj.
4666 updateOomAdjLocked();
4667 }
4668
4669 public void setPersistent(IBinder token, boolean isPersistent) {
4670 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4671 != PackageManager.PERMISSION_GRANTED) {
4672 String msg = "Permission Denial: setPersistent() from pid="
4673 + Binder.getCallingPid()
4674 + ", uid=" + Binder.getCallingUid()
4675 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4676 Log.w(TAG, msg);
4677 throw new SecurityException(msg);
4678 }
4679
4680 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004681 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004682 if (index < 0) {
4683 return;
4684 }
4685 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4686 ProcessRecord app = r.app;
4687
4688 if (localLOGV) Log.v(
4689 TAG, "Setting persistence " + isPersistent + ": " + r);
4690
4691 if (isPersistent) {
4692 if (r.persistent) {
4693 // Okay okay, I heard you already!
4694 if (localLOGV) Log.v(TAG, "Already persistent!");
4695 return;
4696 }
4697 r.persistent = true;
4698 app.persistentActivities++;
4699 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4700 if (app.persistentActivities > 1) {
4701 // We aren't the first...
4702 if (localLOGV) Log.v(TAG, "Not the first!");
4703 return;
4704 }
4705 if (app.persistent) {
4706 // This would be redundant.
4707 if (localLOGV) Log.v(TAG, "App is persistent!");
4708 return;
4709 }
4710
4711 // App is now persistent... make sure it and the ones
4712 // following it now have the correct oom_adj.
4713 final long origId = Binder.clearCallingIdentity();
4714 updateOomAdjLocked();
4715 Binder.restoreCallingIdentity(origId);
4716
4717 } else {
4718 if (!r.persistent) {
4719 // Okay okay, I heard you already!
4720 return;
4721 }
4722 r.persistent = false;
4723 final long origId = Binder.clearCallingIdentity();
4724 decPersistentCountLocked(app);
4725 Binder.restoreCallingIdentity(origId);
4726
4727 }
4728 }
4729 }
4730
4731 public boolean clearApplicationUserData(final String packageName,
4732 final IPackageDataObserver observer) {
4733 int uid = Binder.getCallingUid();
4734 int pid = Binder.getCallingPid();
4735 long callingId = Binder.clearCallingIdentity();
4736 try {
4737 IPackageManager pm = ActivityThread.getPackageManager();
4738 int pkgUid = -1;
4739 synchronized(this) {
4740 try {
4741 pkgUid = pm.getPackageUid(packageName);
4742 } catch (RemoteException e) {
4743 }
4744 if (pkgUid == -1) {
4745 Log.w(TAG, "Invalid packageName:" + packageName);
4746 return false;
4747 }
4748 if (uid == pkgUid || checkComponentPermission(
4749 android.Manifest.permission.CLEAR_APP_USER_DATA,
4750 pid, uid, -1)
4751 == PackageManager.PERMISSION_GRANTED) {
4752 restartPackageLocked(packageName, pkgUid);
4753 } else {
4754 throw new SecurityException(pid+" does not have permission:"+
4755 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4756 "for process:"+packageName);
4757 }
4758 }
4759
4760 try {
4761 //clear application user data
4762 pm.clearApplicationUserData(packageName, observer);
4763 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4764 Uri.fromParts("package", packageName, null));
4765 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4766 broadcastIntentLocked(null, null, intent,
4767 null, null, 0, null, null, null,
4768 false, false, MY_PID, Process.SYSTEM_UID);
4769 } catch (RemoteException e) {
4770 }
4771 } finally {
4772 Binder.restoreCallingIdentity(callingId);
4773 }
4774 return true;
4775 }
4776
4777 public void restartPackage(final String packageName) {
4778 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4779 != PackageManager.PERMISSION_GRANTED) {
4780 String msg = "Permission Denial: restartPackage() from pid="
4781 + Binder.getCallingPid()
4782 + ", uid=" + Binder.getCallingUid()
4783 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4784 Log.w(TAG, msg);
4785 throw new SecurityException(msg);
4786 }
4787
4788 long callingId = Binder.clearCallingIdentity();
4789 try {
4790 IPackageManager pm = ActivityThread.getPackageManager();
4791 int pkgUid = -1;
4792 synchronized(this) {
4793 try {
4794 pkgUid = pm.getPackageUid(packageName);
4795 } catch (RemoteException e) {
4796 }
4797 if (pkgUid == -1) {
4798 Log.w(TAG, "Invalid packageName: " + packageName);
4799 return;
4800 }
4801 restartPackageLocked(packageName, pkgUid);
4802 }
4803 } finally {
4804 Binder.restoreCallingIdentity(callingId);
4805 }
4806 }
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004807
4808 /*
4809 * The pkg name and uid have to be specified.
4810 * @see android.app.IActivityManager#killApplicationWithUid(java.lang.String, int)
4811 */
4812 public void killApplicationWithUid(String pkg, int uid) {
4813 if (pkg == null) {
4814 return;
4815 }
4816 // Make sure the uid is valid.
4817 if (uid < 0) {
4818 Log.w(TAG, "Invalid uid specified for pkg : " + pkg);
4819 return;
4820 }
4821 int callerUid = Binder.getCallingUid();
4822 // Only the system server can kill an application
4823 if (callerUid == Process.SYSTEM_UID) {
Suchi Amalapurapud9d25762009-08-17 16:57:03 -07004824 // Post an aysnc message to kill the application
4825 Message msg = mHandler.obtainMessage(KILL_APPLICATION_MSG);
4826 msg.arg1 = uid;
4827 msg.arg2 = 0;
4828 msg.obj = pkg;
Suchi Amalapurapud50066f2009-08-18 16:57:41 -07004829 mHandler.sendMessage(msg);
Suchi Amalapurapu261e66a2009-07-27 15:21:34 -07004830 } else {
4831 throw new SecurityException(callerUid + " cannot kill pkg: " +
4832 pkg);
4833 }
4834 }
4835
Dianne Hackborna6ddc8a2009-07-28 17:49:55 -07004836 public void closeSystemDialogs(String reason) {
4837 Intent intent = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
4838 if (reason != null) {
4839 intent.putExtra("reason", reason);
4840 }
4841
4842 final int uid = Binder.getCallingUid();
4843 final long origId = Binder.clearCallingIdentity();
4844 synchronized (this) {
4845 int i = mWatchers.beginBroadcast();
4846 while (i > 0) {
4847 i--;
4848 IActivityWatcher w = mWatchers.getBroadcastItem(i);
4849 if (w != null) {
4850 try {
4851 w.closingSystemDialogs(reason);
4852 } catch (RemoteException e) {
4853 }
4854 }
4855 }
4856 mWatchers.finishBroadcast();
4857
4858 broadcastIntentLocked(null, null, intent, null,
4859 null, 0, null, null, null, false, false, -1, uid);
4860 }
4861 Binder.restoreCallingIdentity(origId);
4862 }
4863
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004864 private void restartPackageLocked(final String packageName, int uid) {
4865 uninstallPackageLocked(packageName, uid, false);
4866 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4867 Uri.fromParts("package", packageName, null));
4868 intent.putExtra(Intent.EXTRA_UID, uid);
4869 broadcastIntentLocked(null, null, intent,
4870 null, null, 0, null, null, null,
4871 false, false, MY_PID, Process.SYSTEM_UID);
4872 }
4873
4874 private final void uninstallPackageLocked(String name, int uid,
4875 boolean callerWillRestart) {
4876 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4877
4878 int i, N;
4879
4880 final String procNamePrefix = name + ":";
4881 if (uid < 0) {
4882 try {
4883 uid = ActivityThread.getPackageManager().getPackageUid(name);
4884 } catch (RemoteException e) {
4885 }
4886 }
4887
4888 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4889 while (badApps.hasNext()) {
4890 SparseArray<Long> ba = badApps.next();
4891 if (ba.get(uid) != null) {
4892 badApps.remove();
4893 }
4894 }
4895
4896 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4897
4898 // Remove all processes this package may have touched: all with the
4899 // same UID (except for the system or root user), and all whose name
4900 // matches the package name.
4901 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4902 final int NA = apps.size();
4903 for (int ia=0; ia<NA; ia++) {
4904 ProcessRecord app = apps.valueAt(ia);
4905 if (app.removed) {
4906 procs.add(app);
4907 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4908 || app.processName.equals(name)
4909 || app.processName.startsWith(procNamePrefix)) {
4910 app.removed = true;
4911 procs.add(app);
4912 }
4913 }
4914 }
4915
4916 N = procs.size();
4917 for (i=0; i<N; i++) {
4918 removeProcessLocked(procs.get(i), callerWillRestart);
4919 }
4920
4921 for (i=mHistory.size()-1; i>=0; i--) {
4922 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4923 if (r.packageName.equals(name)) {
4924 if (Config.LOGD) Log.d(
4925 TAG, " Force finishing activity "
4926 + r.intent.getComponent().flattenToShortString());
4927 if (r.app != null) {
4928 r.app.removed = true;
4929 }
4930 r.app = null;
4931 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
4932 }
4933 }
4934
4935 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
4936 for (ServiceRecord service : mServices.values()) {
4937 if (service.packageName.equals(name)) {
4938 if (service.app != null) {
4939 service.app.removed = true;
4940 }
4941 service.app = null;
4942 services.add(service);
4943 }
4944 }
4945
4946 N = services.size();
4947 for (i=0; i<N; i++) {
4948 bringDownServiceLocked(services.get(i), true);
4949 }
4950
4951 resumeTopActivityLocked(null);
4952 }
4953
4954 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
4955 final String name = app.processName;
4956 final int uid = app.info.uid;
4957 if (Config.LOGD) Log.d(
4958 TAG, "Force removing process " + app + " (" + name
4959 + "/" + uid + ")");
4960
4961 mProcessNames.remove(name, uid);
4962 boolean needRestart = false;
4963 if (app.pid > 0 && app.pid != MY_PID) {
4964 int pid = app.pid;
4965 synchronized (mPidsSelfLocked) {
4966 mPidsSelfLocked.remove(pid);
4967 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4968 }
4969 handleAppDiedLocked(app, true);
4970 mLRUProcesses.remove(app);
4971 Process.killProcess(pid);
4972
4973 if (app.persistent) {
4974 if (!callerWillRestart) {
4975 addAppLocked(app.info);
4976 } else {
4977 needRestart = true;
4978 }
4979 }
4980 } else {
4981 mRemovedProcesses.add(app);
4982 }
4983
4984 return needRestart;
4985 }
4986
4987 private final void processStartTimedOutLocked(ProcessRecord app) {
4988 final int pid = app.pid;
4989 boolean gone = false;
4990 synchronized (mPidsSelfLocked) {
4991 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
4992 if (knownApp != null && knownApp.thread == null) {
4993 mPidsSelfLocked.remove(pid);
4994 gone = true;
4995 }
4996 }
4997
4998 if (gone) {
4999 Log.w(TAG, "Process " + app + " failed to attach");
5000 mProcessNames.remove(app.processName, app.info.uid);
5001 Process.killProcess(pid);
5002 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
5003 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
5004 mPendingBroadcast = null;
5005 scheduleBroadcastsLocked();
5006 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005007 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
5008 Log.w(TAG, "Unattached app died before backup, skipping");
5009 try {
5010 IBackupManager bm = IBackupManager.Stub.asInterface(
5011 ServiceManager.getService(Context.BACKUP_SERVICE));
5012 bm.agentDisconnected(app.info.packageName);
5013 } catch (RemoteException e) {
5014 // Can't happen; the backup manager is local
5015 }
5016 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005017 } else {
5018 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
5019 }
5020 }
5021
5022 private final boolean attachApplicationLocked(IApplicationThread thread,
5023 int pid) {
5024
5025 // Find the application record that is being attached... either via
5026 // the pid if we are running in multiple processes, or just pull the
5027 // next app record if we are emulating process with anonymous threads.
5028 ProcessRecord app;
5029 if (pid != MY_PID && pid >= 0) {
5030 synchronized (mPidsSelfLocked) {
5031 app = mPidsSelfLocked.get(pid);
5032 }
5033 } else if (mStartingProcesses.size() > 0) {
5034 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07005035 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005036 } else {
5037 app = null;
5038 }
5039
5040 if (app == null) {
5041 Log.w(TAG, "No pending application record for pid " + pid
5042 + " (IApplicationThread " + thread + "); dropping process");
5043 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
5044 if (pid > 0 && pid != MY_PID) {
5045 Process.killProcess(pid);
5046 } else {
5047 try {
5048 thread.scheduleExit();
5049 } catch (Exception e) {
5050 // Ignore exceptions.
5051 }
5052 }
5053 return false;
5054 }
5055
5056 // If this application record is still attached to a previous
5057 // process, clean it up now.
5058 if (app.thread != null) {
5059 handleAppDiedLocked(app, true);
5060 }
5061
5062 // Tell the process all about itself.
5063
5064 if (localLOGV) Log.v(
5065 TAG, "Binding process pid " + pid + " to record " + app);
5066
5067 String processName = app.processName;
5068 try {
5069 thread.asBinder().linkToDeath(new AppDeathRecipient(
5070 app, pid, thread), 0);
5071 } catch (RemoteException e) {
5072 app.resetPackageList();
5073 startProcessLocked(app, "link fail", processName);
5074 return false;
5075 }
5076
5077 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
5078
5079 app.thread = thread;
5080 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07005081 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005082 app.forcingToForeground = null;
5083 app.foregroundServices = false;
5084 app.debugging = false;
5085
5086 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
5087
5088 List providers = generateApplicationProvidersLocked(app);
5089
5090 if (localLOGV) Log.v(
5091 TAG, "New app record " + app
5092 + " thread=" + thread.asBinder() + " pid=" + pid);
5093 try {
5094 int testMode = IApplicationThread.DEBUG_OFF;
5095 if (mDebugApp != null && mDebugApp.equals(processName)) {
5096 testMode = mWaitForDebugger
5097 ? IApplicationThread.DEBUG_WAIT
5098 : IApplicationThread.DEBUG_ON;
5099 app.debugging = true;
5100 if (mDebugTransient) {
5101 mDebugApp = mOrigDebugApp;
5102 mWaitForDebugger = mOrigWaitForDebugger;
5103 }
5104 }
Christopher Tate181fafa2009-05-14 11:12:14 -07005105 // If the app is being launched for restore or full backup, set it up specially
5106 boolean isRestrictedBackupMode = false;
5107 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
5108 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
5109 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
5110 }
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07005111 ensurePackageDexOpt(app.instrumentationInfo != null
5112 ? app.instrumentationInfo.packageName
5113 : app.info.packageName);
5114 if (app.instrumentationClass != null) {
5115 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005116 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07005117 thread.bindApplication(processName, app.instrumentationInfo != null
5118 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005119 app.instrumentationClass, app.instrumentationProfileFile,
5120 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Christopher Tate181fafa2009-05-14 11:12:14 -07005121 isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005122 updateLRUListLocked(app, false);
5123 app.lastRequestedGc = SystemClock.uptimeMillis();
5124 } catch (Exception e) {
5125 // todo: Yikes! What should we do? For now we will try to
5126 // start another process, but that could easily get us in
5127 // an infinite loop of restarting processes...
5128 Log.w(TAG, "Exception thrown during bind!", e);
5129
5130 app.resetPackageList();
5131 startProcessLocked(app, "bind fail", processName);
5132 return false;
5133 }
5134
5135 // Remove this record from the list of starting applications.
5136 mPersistentStartingProcesses.remove(app);
5137 mProcessesOnHold.remove(app);
5138
5139 boolean badApp = false;
5140 boolean didSomething = false;
5141
5142 // See if the top visible activity is waiting to run in this process...
5143 HistoryRecord hr = topRunningActivityLocked(null);
5144 if (hr != null) {
5145 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5146 && processName.equals(hr.processName)) {
5147 try {
5148 if (realStartActivityLocked(hr, app, true, true)) {
5149 didSomething = true;
5150 }
5151 } catch (Exception e) {
5152 Log.w(TAG, "Exception in new application when starting activity "
5153 + hr.intent.getComponent().flattenToShortString(), e);
5154 badApp = true;
5155 }
5156 } else {
5157 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5158 }
5159 }
5160
5161 // Find any services that should be running in this process...
5162 if (!badApp && mPendingServices.size() > 0) {
5163 ServiceRecord sr = null;
5164 try {
5165 for (int i=0; i<mPendingServices.size(); i++) {
5166 sr = mPendingServices.get(i);
5167 if (app.info.uid != sr.appInfo.uid
5168 || !processName.equals(sr.processName)) {
5169 continue;
5170 }
5171
5172 mPendingServices.remove(i);
5173 i--;
5174 realStartServiceLocked(sr, app);
5175 didSomething = true;
5176 }
5177 } catch (Exception e) {
5178 Log.w(TAG, "Exception in new application when starting service "
5179 + sr.shortName, e);
5180 badApp = true;
5181 }
5182 }
5183
5184 // Check if the next broadcast receiver is in this process...
5185 BroadcastRecord br = mPendingBroadcast;
5186 if (!badApp && br != null && br.curApp == app) {
5187 try {
5188 mPendingBroadcast = null;
5189 processCurBroadcastLocked(br, app);
5190 didSomething = true;
5191 } catch (Exception e) {
5192 Log.w(TAG, "Exception in new application when starting receiver "
5193 + br.curComponent.flattenToShortString(), e);
5194 badApp = true;
5195 logBroadcastReceiverDiscard(br);
5196 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5197 br.resultExtras, br.resultAbort, true);
5198 scheduleBroadcastsLocked();
5199 }
5200 }
5201
Christopher Tate181fafa2009-05-14 11:12:14 -07005202 // Check whether the next backup agent is in this process...
5203 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5204 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005205 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005206 try {
5207 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5208 } catch (Exception e) {
5209 Log.w(TAG, "Exception scheduling backup agent creation: ");
5210 e.printStackTrace();
5211 }
5212 }
5213
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005214 if (badApp) {
5215 // todo: Also need to kill application to deal with all
5216 // kinds of exceptions.
5217 handleAppDiedLocked(app, false);
5218 return false;
5219 }
5220
5221 if (!didSomething) {
5222 updateOomAdjLocked();
5223 }
5224
5225 return true;
5226 }
5227
5228 public final void attachApplication(IApplicationThread thread) {
5229 synchronized (this) {
5230 int callingPid = Binder.getCallingPid();
5231 final long origId = Binder.clearCallingIdentity();
5232 attachApplicationLocked(thread, callingPid);
5233 Binder.restoreCallingIdentity(origId);
5234 }
5235 }
5236
5237 public final void activityIdle(IBinder token) {
5238 final long origId = Binder.clearCallingIdentity();
5239 activityIdleInternal(token, false);
5240 Binder.restoreCallingIdentity(origId);
5241 }
5242
5243 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5244 boolean remove) {
5245 int N = mStoppingActivities.size();
5246 if (N <= 0) return null;
5247
5248 ArrayList<HistoryRecord> stops = null;
5249
5250 final boolean nowVisible = mResumedActivity != null
5251 && mResumedActivity.nowVisible
5252 && !mResumedActivity.waitingVisible;
5253 for (int i=0; i<N; i++) {
5254 HistoryRecord s = mStoppingActivities.get(i);
5255 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5256 + nowVisible + " waitingVisible=" + s.waitingVisible
5257 + " finishing=" + s.finishing);
5258 if (s.waitingVisible && nowVisible) {
5259 mWaitingVisibleActivities.remove(s);
5260 s.waitingVisible = false;
5261 if (s.finishing) {
5262 // If this activity is finishing, it is sitting on top of
5263 // everyone else but we now know it is no longer needed...
5264 // so get rid of it. Otherwise, we need to go through the
5265 // normal flow and hide it once we determine that it is
5266 // hidden by the activities in front of it.
5267 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5268 mWindowManager.setAppVisibility(s, false);
5269 }
5270 }
5271 if (!s.waitingVisible && remove) {
5272 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5273 if (stops == null) {
5274 stops = new ArrayList<HistoryRecord>();
5275 }
5276 stops.add(s);
5277 mStoppingActivities.remove(i);
5278 N--;
5279 i--;
5280 }
5281 }
5282
5283 return stops;
5284 }
5285
5286 void enableScreenAfterBoot() {
5287 mWindowManager.enableScreenAfterBoot();
5288 }
5289
5290 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5291 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5292
5293 ArrayList<HistoryRecord> stops = null;
5294 ArrayList<HistoryRecord> finishes = null;
5295 ArrayList<HistoryRecord> thumbnails = null;
5296 int NS = 0;
5297 int NF = 0;
5298 int NT = 0;
5299 IApplicationThread sendThumbnail = null;
5300 boolean booting = false;
5301 boolean enableScreen = false;
5302
5303 synchronized (this) {
5304 if (token != null) {
5305 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5306 }
5307
5308 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005309 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005310 if (index >= 0) {
5311 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5312
5313 // No longer need to keep the device awake.
5314 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5315 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5316 mLaunchingActivity.release();
5317 }
5318
5319 // We are now idle. If someone is waiting for a thumbnail from
5320 // us, we can now deliver.
5321 r.idle = true;
5322 scheduleAppGcsLocked();
5323 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5324 sendThumbnail = r.app.thread;
5325 r.thumbnailNeeded = false;
5326 }
5327
5328 // If this activity is fullscreen, set up to hide those under it.
5329
5330 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5331 ensureActivitiesVisibleLocked(null, 0);
5332
5333 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5334 if (!mBooted && !fromTimeout) {
5335 mBooted = true;
5336 enableScreen = true;
5337 }
5338 }
5339
5340 // Atomically retrieve all of the other things to do.
5341 stops = processStoppingActivitiesLocked(true);
5342 NS = stops != null ? stops.size() : 0;
5343 if ((NF=mFinishingActivities.size()) > 0) {
5344 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5345 mFinishingActivities.clear();
5346 }
5347 if ((NT=mCancelledThumbnails.size()) > 0) {
5348 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5349 mCancelledThumbnails.clear();
5350 }
5351
5352 booting = mBooting;
5353 mBooting = false;
5354 }
5355
5356 int i;
5357
5358 // Send thumbnail if requested.
5359 if (sendThumbnail != null) {
5360 try {
5361 sendThumbnail.requestThumbnail(token);
5362 } catch (Exception e) {
5363 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5364 sendPendingThumbnail(null, token, null, null, true);
5365 }
5366 }
5367
5368 // Stop any activities that are scheduled to do so but have been
5369 // waiting for the next one to start.
5370 for (i=0; i<NS; i++) {
5371 HistoryRecord r = (HistoryRecord)stops.get(i);
5372 synchronized (this) {
5373 if (r.finishing) {
5374 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5375 } else {
5376 stopActivityLocked(r);
5377 }
5378 }
5379 }
5380
5381 // Finish any activities that are scheduled to do so but have been
5382 // waiting for the next one to start.
5383 for (i=0; i<NF; i++) {
5384 HistoryRecord r = (HistoryRecord)finishes.get(i);
5385 synchronized (this) {
5386 destroyActivityLocked(r, true);
5387 }
5388 }
5389
5390 // Report back to any thumbnail receivers.
5391 for (i=0; i<NT; i++) {
5392 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5393 sendPendingThumbnail(r, null, null, null, true);
5394 }
5395
5396 if (booting) {
5397 // Ensure that any processes we had put on hold are now started
5398 // up.
5399 final int NP = mProcessesOnHold.size();
5400 if (NP > 0) {
5401 ArrayList<ProcessRecord> procs =
5402 new ArrayList<ProcessRecord>(mProcessesOnHold);
5403 for (int ip=0; ip<NP; ip++) {
5404 this.startProcessLocked(procs.get(ip), "on-hold", null);
5405 }
5406 }
5407 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5408 // Tell anyone interested that we are done booting!
5409 synchronized (this) {
5410 broadcastIntentLocked(null, null,
5411 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5412 null, null, 0, null, null,
5413 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5414 false, false, MY_PID, Process.SYSTEM_UID);
5415 }
5416 }
5417 }
5418
5419 trimApplications();
5420 //dump();
5421 //mWindowManager.dump();
5422
5423 if (enableScreen) {
5424 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5425 SystemClock.uptimeMillis());
5426 enableScreenAfterBoot();
5427 }
5428 }
5429
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005430 final void ensureScreenEnabled() {
5431 boolean enableScreen;
5432 synchronized (this) {
5433 enableScreen = !mBooted;
5434 mBooted = true;
5435 }
5436
5437 if (enableScreen) {
5438 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5439 SystemClock.uptimeMillis());
5440 enableScreenAfterBoot();
5441 }
5442 }
5443
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005444 public final void activityPaused(IBinder token, Bundle icicle) {
5445 // Refuse possible leaked file descriptors
5446 if (icicle != null && icicle.hasFileDescriptors()) {
5447 throw new IllegalArgumentException("File descriptors passed in Bundle");
5448 }
5449
5450 final long origId = Binder.clearCallingIdentity();
5451 activityPaused(token, icicle, false);
5452 Binder.restoreCallingIdentity(origId);
5453 }
5454
5455 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5456 if (DEBUG_PAUSE) Log.v(
5457 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5458 + ", timeout=" + timeout);
5459
5460 HistoryRecord r = null;
5461
5462 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005463 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005464 if (index >= 0) {
5465 r = (HistoryRecord)mHistory.get(index);
5466 if (!timeout) {
5467 r.icicle = icicle;
5468 r.haveState = true;
5469 }
5470 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5471 if (mPausingActivity == r) {
5472 r.state = ActivityState.PAUSED;
5473 completePauseLocked();
5474 } else {
5475 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5476 System.identityHashCode(r), r.shortComponentName,
5477 mPausingActivity != null
5478 ? mPausingActivity.shortComponentName : "(none)");
5479 }
5480 }
5481 }
5482 }
5483
5484 public final void activityStopped(IBinder token, Bitmap thumbnail,
5485 CharSequence description) {
5486 if (localLOGV) Log.v(
5487 TAG, "Activity stopped: token=" + token);
5488
5489 HistoryRecord r = null;
5490
5491 final long origId = Binder.clearCallingIdentity();
5492
5493 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005494 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005495 if (index >= 0) {
5496 r = (HistoryRecord)mHistory.get(index);
5497 r.thumbnail = thumbnail;
5498 r.description = description;
5499 r.stopped = true;
5500 r.state = ActivityState.STOPPED;
5501 if (!r.finishing) {
5502 if (r.configDestroy) {
5503 destroyActivityLocked(r, true);
5504 resumeTopActivityLocked(null);
5505 }
5506 }
5507 }
5508 }
5509
5510 if (r != null) {
5511 sendPendingThumbnail(r, null, null, null, false);
5512 }
5513
5514 trimApplications();
5515
5516 Binder.restoreCallingIdentity(origId);
5517 }
5518
5519 public final void activityDestroyed(IBinder token) {
5520 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5521 synchronized (this) {
5522 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5523
Dianne Hackborn75b03852009-06-12 15:43:26 -07005524 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005525 if (index >= 0) {
5526 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5527 if (r.state == ActivityState.DESTROYING) {
5528 final long origId = Binder.clearCallingIdentity();
5529 removeActivityFromHistoryLocked(r);
5530 Binder.restoreCallingIdentity(origId);
5531 }
5532 }
5533 }
5534 }
5535
5536 public String getCallingPackage(IBinder token) {
5537 synchronized (this) {
5538 HistoryRecord r = getCallingRecordLocked(token);
5539 return r != null && r.app != null ? r.app.processName : null;
5540 }
5541 }
5542
5543 public ComponentName getCallingActivity(IBinder token) {
5544 synchronized (this) {
5545 HistoryRecord r = getCallingRecordLocked(token);
5546 return r != null ? r.intent.getComponent() : null;
5547 }
5548 }
5549
5550 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005551 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005552 if (index >= 0) {
5553 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5554 if (r != null) {
5555 return r.resultTo;
5556 }
5557 }
5558 return null;
5559 }
5560
5561 public ComponentName getActivityClassForToken(IBinder token) {
5562 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005563 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005564 if (index >= 0) {
5565 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5566 return r.intent.getComponent();
5567 }
5568 return null;
5569 }
5570 }
5571
5572 public String getPackageForToken(IBinder token) {
5573 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005574 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005575 if (index >= 0) {
5576 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5577 return r.packageName;
5578 }
5579 return null;
5580 }
5581 }
5582
5583 public IIntentSender getIntentSender(int type,
5584 String packageName, IBinder token, String resultWho,
5585 int requestCode, Intent intent, String resolvedType, int flags) {
5586 // Refuse possible leaked file descriptors
5587 if (intent != null && intent.hasFileDescriptors() == true) {
5588 throw new IllegalArgumentException("File descriptors passed in Intent");
5589 }
5590
5591 synchronized(this) {
5592 int callingUid = Binder.getCallingUid();
5593 try {
5594 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5595 Process.supportsProcesses()) {
5596 int uid = ActivityThread.getPackageManager()
5597 .getPackageUid(packageName);
5598 if (uid != Binder.getCallingUid()) {
5599 String msg = "Permission Denial: getIntentSender() from pid="
5600 + Binder.getCallingPid()
5601 + ", uid=" + Binder.getCallingUid()
5602 + ", (need uid=" + uid + ")"
5603 + " is not allowed to send as package " + packageName;
5604 Log.w(TAG, msg);
5605 throw new SecurityException(msg);
5606 }
5607 }
5608 } catch (RemoteException e) {
5609 throw new SecurityException(e);
5610 }
5611 HistoryRecord activity = null;
5612 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005613 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005614 if (index < 0) {
5615 return null;
5616 }
5617 activity = (HistoryRecord)mHistory.get(index);
5618 if (activity.finishing) {
5619 return null;
5620 }
5621 }
5622
5623 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5624 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5625 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5626 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5627 |PendingIntent.FLAG_UPDATE_CURRENT);
5628
5629 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5630 type, packageName, activity, resultWho,
5631 requestCode, intent, resolvedType, flags);
5632 WeakReference<PendingIntentRecord> ref;
5633 ref = mIntentSenderRecords.get(key);
5634 PendingIntentRecord rec = ref != null ? ref.get() : null;
5635 if (rec != null) {
5636 if (!cancelCurrent) {
5637 if (updateCurrent) {
5638 rec.key.requestIntent.replaceExtras(intent);
5639 }
5640 return rec;
5641 }
5642 rec.canceled = true;
5643 mIntentSenderRecords.remove(key);
5644 }
5645 if (noCreate) {
5646 return rec;
5647 }
5648 rec = new PendingIntentRecord(this, key, callingUid);
5649 mIntentSenderRecords.put(key, rec.ref);
5650 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5651 if (activity.pendingResults == null) {
5652 activity.pendingResults
5653 = new HashSet<WeakReference<PendingIntentRecord>>();
5654 }
5655 activity.pendingResults.add(rec.ref);
5656 }
5657 return rec;
5658 }
5659 }
5660
5661 public void cancelIntentSender(IIntentSender sender) {
5662 if (!(sender instanceof PendingIntentRecord)) {
5663 return;
5664 }
5665 synchronized(this) {
5666 PendingIntentRecord rec = (PendingIntentRecord)sender;
5667 try {
5668 int uid = ActivityThread.getPackageManager()
5669 .getPackageUid(rec.key.packageName);
5670 if (uid != Binder.getCallingUid()) {
5671 String msg = "Permission Denial: cancelIntentSender() from pid="
5672 + Binder.getCallingPid()
5673 + ", uid=" + Binder.getCallingUid()
5674 + " is not allowed to cancel packges "
5675 + rec.key.packageName;
5676 Log.w(TAG, msg);
5677 throw new SecurityException(msg);
5678 }
5679 } catch (RemoteException e) {
5680 throw new SecurityException(e);
5681 }
5682 cancelIntentSenderLocked(rec, true);
5683 }
5684 }
5685
5686 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5687 rec.canceled = true;
5688 mIntentSenderRecords.remove(rec.key);
5689 if (cleanActivity && rec.key.activity != null) {
5690 rec.key.activity.pendingResults.remove(rec.ref);
5691 }
5692 }
5693
5694 public String getPackageForIntentSender(IIntentSender pendingResult) {
5695 if (!(pendingResult instanceof PendingIntentRecord)) {
5696 return null;
5697 }
5698 synchronized(this) {
5699 try {
5700 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5701 return res.key.packageName;
5702 } catch (ClassCastException e) {
5703 }
5704 }
5705 return null;
5706 }
5707
5708 public void setProcessLimit(int max) {
5709 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5710 "setProcessLimit()");
5711 mProcessLimit = max;
5712 }
5713
5714 public int getProcessLimit() {
5715 return mProcessLimit;
5716 }
5717
5718 void foregroundTokenDied(ForegroundToken token) {
5719 synchronized (ActivityManagerService.this) {
5720 synchronized (mPidsSelfLocked) {
5721 ForegroundToken cur
5722 = mForegroundProcesses.get(token.pid);
5723 if (cur != token) {
5724 return;
5725 }
5726 mForegroundProcesses.remove(token.pid);
5727 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5728 if (pr == null) {
5729 return;
5730 }
5731 pr.forcingToForeground = null;
5732 pr.foregroundServices = false;
5733 }
5734 updateOomAdjLocked();
5735 }
5736 }
5737
5738 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5739 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5740 "setProcessForeground()");
5741 synchronized(this) {
5742 boolean changed = false;
5743
5744 synchronized (mPidsSelfLocked) {
5745 ProcessRecord pr = mPidsSelfLocked.get(pid);
5746 if (pr == null) {
5747 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5748 return;
5749 }
5750 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5751 if (oldToken != null) {
5752 oldToken.token.unlinkToDeath(oldToken, 0);
5753 mForegroundProcesses.remove(pid);
5754 pr.forcingToForeground = null;
5755 changed = true;
5756 }
5757 if (isForeground && token != null) {
5758 ForegroundToken newToken = new ForegroundToken() {
5759 public void binderDied() {
5760 foregroundTokenDied(this);
5761 }
5762 };
5763 newToken.pid = pid;
5764 newToken.token = token;
5765 try {
5766 token.linkToDeath(newToken, 0);
5767 mForegroundProcesses.put(pid, newToken);
5768 pr.forcingToForeground = token;
5769 changed = true;
5770 } catch (RemoteException e) {
5771 // If the process died while doing this, we will later
5772 // do the cleanup with the process death link.
5773 }
5774 }
5775 }
5776
5777 if (changed) {
5778 updateOomAdjLocked();
5779 }
5780 }
5781 }
5782
5783 // =========================================================
5784 // PERMISSIONS
5785 // =========================================================
5786
5787 static class PermissionController extends IPermissionController.Stub {
5788 ActivityManagerService mActivityManagerService;
5789 PermissionController(ActivityManagerService activityManagerService) {
5790 mActivityManagerService = activityManagerService;
5791 }
5792
5793 public boolean checkPermission(String permission, int pid, int uid) {
5794 return mActivityManagerService.checkPermission(permission, pid,
5795 uid) == PackageManager.PERMISSION_GRANTED;
5796 }
5797 }
5798
5799 /**
5800 * This can be called with or without the global lock held.
5801 */
5802 int checkComponentPermission(String permission, int pid, int uid,
5803 int reqUid) {
5804 // We might be performing an operation on behalf of an indirect binder
5805 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5806 // client identity accordingly before proceeding.
5807 Identity tlsIdentity = sCallerIdentity.get();
5808 if (tlsIdentity != null) {
5809 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5810 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5811 uid = tlsIdentity.uid;
5812 pid = tlsIdentity.pid;
5813 }
5814
5815 // Root, system server and our own process get to do everything.
5816 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5817 !Process.supportsProcesses()) {
5818 return PackageManager.PERMISSION_GRANTED;
5819 }
5820 // If the target requires a specific UID, always fail for others.
5821 if (reqUid >= 0 && uid != reqUid) {
5822 return PackageManager.PERMISSION_DENIED;
5823 }
5824 if (permission == null) {
5825 return PackageManager.PERMISSION_GRANTED;
5826 }
5827 try {
5828 return ActivityThread.getPackageManager()
5829 .checkUidPermission(permission, uid);
5830 } catch (RemoteException e) {
5831 // Should never happen, but if it does... deny!
5832 Log.e(TAG, "PackageManager is dead?!?", e);
5833 }
5834 return PackageManager.PERMISSION_DENIED;
5835 }
5836
5837 /**
5838 * As the only public entry point for permissions checking, this method
5839 * can enforce the semantic that requesting a check on a null global
5840 * permission is automatically denied. (Internally a null permission
5841 * string is used when calling {@link #checkComponentPermission} in cases
5842 * when only uid-based security is needed.)
5843 *
5844 * This can be called with or without the global lock held.
5845 */
5846 public int checkPermission(String permission, int pid, int uid) {
5847 if (permission == null) {
5848 return PackageManager.PERMISSION_DENIED;
5849 }
5850 return checkComponentPermission(permission, pid, uid, -1);
5851 }
5852
5853 /**
5854 * Binder IPC calls go through the public entry point.
5855 * This can be called with or without the global lock held.
5856 */
5857 int checkCallingPermission(String permission) {
5858 return checkPermission(permission,
5859 Binder.getCallingPid(),
5860 Binder.getCallingUid());
5861 }
5862
5863 /**
5864 * This can be called with or without the global lock held.
5865 */
5866 void enforceCallingPermission(String permission, String func) {
5867 if (checkCallingPermission(permission)
5868 == PackageManager.PERMISSION_GRANTED) {
5869 return;
5870 }
5871
5872 String msg = "Permission Denial: " + func + " from pid="
5873 + Binder.getCallingPid()
5874 + ", uid=" + Binder.getCallingUid()
5875 + " requires " + permission;
5876 Log.w(TAG, msg);
5877 throw new SecurityException(msg);
5878 }
5879
5880 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5881 ProviderInfo pi, int uid, int modeFlags) {
5882 try {
5883 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5884 if ((pi.readPermission != null) &&
5885 (pm.checkUidPermission(pi.readPermission, uid)
5886 != PackageManager.PERMISSION_GRANTED)) {
5887 return false;
5888 }
5889 }
5890 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5891 if ((pi.writePermission != null) &&
5892 (pm.checkUidPermission(pi.writePermission, uid)
5893 != PackageManager.PERMISSION_GRANTED)) {
5894 return false;
5895 }
5896 }
5897 return true;
5898 } catch (RemoteException e) {
5899 return false;
5900 }
5901 }
5902
5903 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5904 int modeFlags) {
5905 // Root gets to do everything.
5906 if (uid == 0 || !Process.supportsProcesses()) {
5907 return true;
5908 }
5909 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5910 if (perms == null) return false;
5911 UriPermission perm = perms.get(uri);
5912 if (perm == null) return false;
5913 return (modeFlags&perm.modeFlags) == modeFlags;
5914 }
5915
5916 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5917 // Another redirected-binder-call permissions check as in
5918 // {@link checkComponentPermission}.
5919 Identity tlsIdentity = sCallerIdentity.get();
5920 if (tlsIdentity != null) {
5921 uid = tlsIdentity.uid;
5922 pid = tlsIdentity.pid;
5923 }
5924
5925 // Our own process gets to do everything.
5926 if (pid == MY_PID) {
5927 return PackageManager.PERMISSION_GRANTED;
5928 }
5929 synchronized(this) {
5930 return checkUriPermissionLocked(uri, uid, modeFlags)
5931 ? PackageManager.PERMISSION_GRANTED
5932 : PackageManager.PERMISSION_DENIED;
5933 }
5934 }
5935
5936 private void grantUriPermissionLocked(int callingUid,
5937 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
5938 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5939 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5940 if (modeFlags == 0) {
5941 return;
5942 }
5943
5944 final IPackageManager pm = ActivityThread.getPackageManager();
5945
5946 // If this is not a content: uri, we can't do anything with it.
5947 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
5948 return;
5949 }
5950
5951 String name = uri.getAuthority();
5952 ProviderInfo pi = null;
5953 ContentProviderRecord cpr
5954 = (ContentProviderRecord)mProvidersByName.get(name);
5955 if (cpr != null) {
5956 pi = cpr.info;
5957 } else {
5958 try {
5959 pi = pm.resolveContentProvider(name,
5960 PackageManager.GET_URI_PERMISSION_PATTERNS);
5961 } catch (RemoteException ex) {
5962 }
5963 }
5964 if (pi == null) {
5965 Log.w(TAG, "No content provider found for: " + name);
5966 return;
5967 }
5968
5969 int targetUid;
5970 try {
5971 targetUid = pm.getPackageUid(targetPkg);
5972 if (targetUid < 0) {
5973 return;
5974 }
5975 } catch (RemoteException ex) {
5976 return;
5977 }
5978
5979 // First... does the target actually need this permission?
5980 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
5981 // No need to grant the target this permission.
5982 return;
5983 }
5984
5985 // Second... maybe someone else has already granted the
5986 // permission?
5987 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
5988 // No need to grant the target this permission.
5989 return;
5990 }
5991
5992 // Third... is the provider allowing granting of URI permissions?
5993 if (!pi.grantUriPermissions) {
5994 throw new SecurityException("Provider " + pi.packageName
5995 + "/" + pi.name
5996 + " does not allow granting of Uri permissions (uri "
5997 + uri + ")");
5998 }
5999 if (pi.uriPermissionPatterns != null) {
6000 final int N = pi.uriPermissionPatterns.length;
6001 boolean allowed = false;
6002 for (int i=0; i<N; i++) {
6003 if (pi.uriPermissionPatterns[i] != null
6004 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
6005 allowed = true;
6006 break;
6007 }
6008 }
6009 if (!allowed) {
6010 throw new SecurityException("Provider " + pi.packageName
6011 + "/" + pi.name
6012 + " does not allow granting of permission to path of Uri "
6013 + uri);
6014 }
6015 }
6016
6017 // Fourth... does the caller itself have permission to access
6018 // this uri?
6019 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6020 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6021 throw new SecurityException("Uid " + callingUid
6022 + " does not have permission to uri " + uri);
6023 }
6024 }
6025
6026 // Okay! So here we are: the caller has the assumed permission
6027 // to the uri, and the target doesn't. Let's now give this to
6028 // the target.
6029
6030 HashMap<Uri, UriPermission> targetUris
6031 = mGrantedUriPermissions.get(targetUid);
6032 if (targetUris == null) {
6033 targetUris = new HashMap<Uri, UriPermission>();
6034 mGrantedUriPermissions.put(targetUid, targetUris);
6035 }
6036
6037 UriPermission perm = targetUris.get(uri);
6038 if (perm == null) {
6039 perm = new UriPermission(targetUid, uri);
6040 targetUris.put(uri, perm);
6041
6042 }
6043 perm.modeFlags |= modeFlags;
6044 if (activity == null) {
6045 perm.globalModeFlags |= modeFlags;
6046 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
6047 perm.readActivities.add(activity);
6048 if (activity.readUriPermissions == null) {
6049 activity.readUriPermissions = new HashSet<UriPermission>();
6050 }
6051 activity.readUriPermissions.add(perm);
6052 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
6053 perm.writeActivities.add(activity);
6054 if (activity.writeUriPermissions == null) {
6055 activity.writeUriPermissions = new HashSet<UriPermission>();
6056 }
6057 activity.writeUriPermissions.add(perm);
6058 }
6059 }
6060
6061 private void grantUriPermissionFromIntentLocked(int callingUid,
6062 String targetPkg, Intent intent, HistoryRecord activity) {
6063 if (intent == null) {
6064 return;
6065 }
6066 Uri data = intent.getData();
6067 if (data == null) {
6068 return;
6069 }
6070 grantUriPermissionLocked(callingUid, targetPkg, data,
6071 intent.getFlags(), activity);
6072 }
6073
6074 public void grantUriPermission(IApplicationThread caller, String targetPkg,
6075 Uri uri, int modeFlags) {
6076 synchronized(this) {
6077 final ProcessRecord r = getRecordForAppLocked(caller);
6078 if (r == null) {
6079 throw new SecurityException("Unable to find app for caller "
6080 + caller
6081 + " when granting permission to uri " + uri);
6082 }
6083 if (targetPkg == null) {
6084 Log.w(TAG, "grantUriPermission: null target");
6085 return;
6086 }
6087 if (uri == null) {
6088 Log.w(TAG, "grantUriPermission: null uri");
6089 return;
6090 }
6091
6092 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
6093 null);
6094 }
6095 }
6096
6097 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
6098 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
6099 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
6100 HashMap<Uri, UriPermission> perms
6101 = mGrantedUriPermissions.get(perm.uid);
6102 if (perms != null) {
6103 perms.remove(perm.uri);
6104 if (perms.size() == 0) {
6105 mGrantedUriPermissions.remove(perm.uid);
6106 }
6107 }
6108 }
6109 }
6110
6111 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
6112 if (activity.readUriPermissions != null) {
6113 for (UriPermission perm : activity.readUriPermissions) {
6114 perm.readActivities.remove(activity);
6115 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
6116 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
6117 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
6118 removeUriPermissionIfNeededLocked(perm);
6119 }
6120 }
6121 }
6122 if (activity.writeUriPermissions != null) {
6123 for (UriPermission perm : activity.writeUriPermissions) {
6124 perm.writeActivities.remove(activity);
6125 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
6126 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
6127 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
6128 removeUriPermissionIfNeededLocked(perm);
6129 }
6130 }
6131 }
6132 }
6133
6134 private void revokeUriPermissionLocked(int callingUid, Uri uri,
6135 int modeFlags) {
6136 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6137 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6138 if (modeFlags == 0) {
6139 return;
6140 }
6141
6142 final IPackageManager pm = ActivityThread.getPackageManager();
6143
6144 final String authority = uri.getAuthority();
6145 ProviderInfo pi = null;
6146 ContentProviderRecord cpr
6147 = (ContentProviderRecord)mProvidersByName.get(authority);
6148 if (cpr != null) {
6149 pi = cpr.info;
6150 } else {
6151 try {
6152 pi = pm.resolveContentProvider(authority,
6153 PackageManager.GET_URI_PERMISSION_PATTERNS);
6154 } catch (RemoteException ex) {
6155 }
6156 }
6157 if (pi == null) {
6158 Log.w(TAG, "No content provider found for: " + authority);
6159 return;
6160 }
6161
6162 // Does the caller have this permission on the URI?
6163 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6164 // Right now, if you are not the original owner of the permission,
6165 // you are not allowed to revoke it.
6166 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6167 throw new SecurityException("Uid " + callingUid
6168 + " does not have permission to uri " + uri);
6169 //}
6170 }
6171
6172 // Go through all of the permissions and remove any that match.
6173 final List<String> SEGMENTS = uri.getPathSegments();
6174 if (SEGMENTS != null) {
6175 final int NS = SEGMENTS.size();
6176 int N = mGrantedUriPermissions.size();
6177 for (int i=0; i<N; i++) {
6178 HashMap<Uri, UriPermission> perms
6179 = mGrantedUriPermissions.valueAt(i);
6180 Iterator<UriPermission> it = perms.values().iterator();
6181 toploop:
6182 while (it.hasNext()) {
6183 UriPermission perm = it.next();
6184 Uri targetUri = perm.uri;
6185 if (!authority.equals(targetUri.getAuthority())) {
6186 continue;
6187 }
6188 List<String> targetSegments = targetUri.getPathSegments();
6189 if (targetSegments == null) {
6190 continue;
6191 }
6192 if (targetSegments.size() < NS) {
6193 continue;
6194 }
6195 for (int j=0; j<NS; j++) {
6196 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6197 continue toploop;
6198 }
6199 }
6200 perm.clearModes(modeFlags);
6201 if (perm.modeFlags == 0) {
6202 it.remove();
6203 }
6204 }
6205 if (perms.size() == 0) {
6206 mGrantedUriPermissions.remove(
6207 mGrantedUriPermissions.keyAt(i));
6208 N--;
6209 i--;
6210 }
6211 }
6212 }
6213 }
6214
6215 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6216 int modeFlags) {
6217 synchronized(this) {
6218 final ProcessRecord r = getRecordForAppLocked(caller);
6219 if (r == null) {
6220 throw new SecurityException("Unable to find app for caller "
6221 + caller
6222 + " when revoking permission to uri " + uri);
6223 }
6224 if (uri == null) {
6225 Log.w(TAG, "revokeUriPermission: null uri");
6226 return;
6227 }
6228
6229 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6230 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6231 if (modeFlags == 0) {
6232 return;
6233 }
6234
6235 final IPackageManager pm = ActivityThread.getPackageManager();
6236
6237 final String authority = uri.getAuthority();
6238 ProviderInfo pi = null;
6239 ContentProviderRecord cpr
6240 = (ContentProviderRecord)mProvidersByName.get(authority);
6241 if (cpr != null) {
6242 pi = cpr.info;
6243 } else {
6244 try {
6245 pi = pm.resolveContentProvider(authority,
6246 PackageManager.GET_URI_PERMISSION_PATTERNS);
6247 } catch (RemoteException ex) {
6248 }
6249 }
6250 if (pi == null) {
6251 Log.w(TAG, "No content provider found for: " + authority);
6252 return;
6253 }
6254
6255 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6256 }
6257 }
6258
6259 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6260 synchronized (this) {
6261 ProcessRecord app =
6262 who != null ? getRecordForAppLocked(who) : null;
6263 if (app == null) return;
6264
6265 Message msg = Message.obtain();
6266 msg.what = WAIT_FOR_DEBUGGER_MSG;
6267 msg.obj = app;
6268 msg.arg1 = waiting ? 1 : 0;
6269 mHandler.sendMessage(msg);
6270 }
6271 }
6272
6273 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6274 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006275 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006276 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006277 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006278 }
6279
6280 // =========================================================
6281 // TASK MANAGEMENT
6282 // =========================================================
6283
6284 public List getTasks(int maxNum, int flags,
6285 IThumbnailReceiver receiver) {
6286 ArrayList list = new ArrayList();
6287
6288 PendingThumbnailsRecord pending = null;
6289 IApplicationThread topThumbnail = null;
6290 HistoryRecord topRecord = null;
6291
6292 synchronized(this) {
6293 if (localLOGV) Log.v(
6294 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6295 + ", receiver=" + receiver);
6296
6297 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6298 != PackageManager.PERMISSION_GRANTED) {
6299 if (receiver != null) {
6300 // If the caller wants to wait for pending thumbnails,
6301 // it ain't gonna get them.
6302 try {
6303 receiver.finished();
6304 } catch (RemoteException ex) {
6305 }
6306 }
6307 String msg = "Permission Denial: getTasks() from pid="
6308 + Binder.getCallingPid()
6309 + ", uid=" + Binder.getCallingUid()
6310 + " requires " + android.Manifest.permission.GET_TASKS;
6311 Log.w(TAG, msg);
6312 throw new SecurityException(msg);
6313 }
6314
6315 int pos = mHistory.size()-1;
6316 HistoryRecord next =
6317 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6318 HistoryRecord top = null;
6319 CharSequence topDescription = null;
6320 TaskRecord curTask = null;
6321 int numActivities = 0;
6322 int numRunning = 0;
6323 while (pos >= 0 && maxNum > 0) {
6324 final HistoryRecord r = next;
6325 pos--;
6326 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6327
6328 // Initialize state for next task if needed.
6329 if (top == null ||
6330 (top.state == ActivityState.INITIALIZING
6331 && top.task == r.task)) {
6332 top = r;
6333 topDescription = r.description;
6334 curTask = r.task;
6335 numActivities = numRunning = 0;
6336 }
6337
6338 // Add 'r' into the current task.
6339 numActivities++;
6340 if (r.app != null && r.app.thread != null) {
6341 numRunning++;
6342 }
6343 if (topDescription == null) {
6344 topDescription = r.description;
6345 }
6346
6347 if (localLOGV) Log.v(
6348 TAG, r.intent.getComponent().flattenToShortString()
6349 + ": task=" + r.task);
6350
6351 // If the next one is a different task, generate a new
6352 // TaskInfo entry for what we have.
6353 if (next == null || next.task != curTask) {
6354 ActivityManager.RunningTaskInfo ci
6355 = new ActivityManager.RunningTaskInfo();
6356 ci.id = curTask.taskId;
6357 ci.baseActivity = r.intent.getComponent();
6358 ci.topActivity = top.intent.getComponent();
6359 ci.thumbnail = top.thumbnail;
6360 ci.description = topDescription;
6361 ci.numActivities = numActivities;
6362 ci.numRunning = numRunning;
6363 //System.out.println(
6364 // "#" + maxNum + ": " + " descr=" + ci.description);
6365 if (ci.thumbnail == null && receiver != null) {
6366 if (localLOGV) Log.v(
6367 TAG, "State=" + top.state + "Idle=" + top.idle
6368 + " app=" + top.app
6369 + " thr=" + (top.app != null ? top.app.thread : null));
6370 if (top.state == ActivityState.RESUMED
6371 || top.state == ActivityState.PAUSING) {
6372 if (top.idle && top.app != null
6373 && top.app.thread != null) {
6374 topRecord = top;
6375 topThumbnail = top.app.thread;
6376 } else {
6377 top.thumbnailNeeded = true;
6378 }
6379 }
6380 if (pending == null) {
6381 pending = new PendingThumbnailsRecord(receiver);
6382 }
6383 pending.pendingRecords.add(top);
6384 }
6385 list.add(ci);
6386 maxNum--;
6387 top = null;
6388 }
6389 }
6390
6391 if (pending != null) {
6392 mPendingThumbnails.add(pending);
6393 }
6394 }
6395
6396 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6397
6398 if (topThumbnail != null) {
6399 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6400 try {
6401 topThumbnail.requestThumbnail(topRecord);
6402 } catch (Exception e) {
6403 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6404 sendPendingThumbnail(null, topRecord, null, null, true);
6405 }
6406 }
6407
6408 if (pending == null && receiver != null) {
6409 // In this case all thumbnails were available and the client
6410 // is being asked to be told when the remaining ones come in...
6411 // which is unusually, since the top-most currently running
6412 // activity should never have a canned thumbnail! Oh well.
6413 try {
6414 receiver.finished();
6415 } catch (RemoteException ex) {
6416 }
6417 }
6418
6419 return list;
6420 }
6421
6422 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6423 int flags) {
6424 synchronized (this) {
6425 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6426 "getRecentTasks()");
6427
6428 final int N = mRecentTasks.size();
6429 ArrayList<ActivityManager.RecentTaskInfo> res
6430 = new ArrayList<ActivityManager.RecentTaskInfo>(
6431 maxNum < N ? maxNum : N);
6432 for (int i=0; i<N && maxNum > 0; i++) {
6433 TaskRecord tr = mRecentTasks.get(i);
6434 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6435 || (tr.intent == null)
6436 || ((tr.intent.getFlags()
6437 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6438 ActivityManager.RecentTaskInfo rti
6439 = new ActivityManager.RecentTaskInfo();
6440 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6441 rti.baseIntent = new Intent(
6442 tr.intent != null ? tr.intent : tr.affinityIntent);
6443 rti.origActivity = tr.origActivity;
6444 res.add(rti);
6445 maxNum--;
6446 }
6447 }
6448 return res;
6449 }
6450 }
6451
6452 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6453 int j;
6454 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6455 TaskRecord jt = startTask;
6456
6457 // First look backwards
6458 for (j=startIndex-1; j>=0; j--) {
6459 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6460 if (r.task != jt) {
6461 jt = r.task;
6462 if (affinity.equals(jt.affinity)) {
6463 return j;
6464 }
6465 }
6466 }
6467
6468 // Now look forwards
6469 final int N = mHistory.size();
6470 jt = startTask;
6471 for (j=startIndex+1; j<N; j++) {
6472 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6473 if (r.task != jt) {
6474 if (affinity.equals(jt.affinity)) {
6475 return j;
6476 }
6477 jt = r.task;
6478 }
6479 }
6480
6481 // Might it be at the top?
6482 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6483 return N-1;
6484 }
6485
6486 return -1;
6487 }
6488
6489 /**
6490 * Perform a reset of the given task, if needed as part of launching it.
6491 * Returns the new HistoryRecord at the top of the task.
6492 */
6493 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6494 HistoryRecord newActivity) {
6495 boolean forceReset = (newActivity.info.flags
6496 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6497 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6498 if ((newActivity.info.flags
6499 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6500 forceReset = true;
6501 }
6502 }
6503
6504 final TaskRecord task = taskTop.task;
6505
6506 // We are going to move through the history list so that we can look
6507 // at each activity 'target' with 'below' either the interesting
6508 // activity immediately below it in the stack or null.
6509 HistoryRecord target = null;
6510 int targetI = 0;
6511 int taskTopI = -1;
6512 int replyChainEnd = -1;
6513 int lastReparentPos = -1;
6514 for (int i=mHistory.size()-1; i>=-1; i--) {
6515 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6516
6517 if (below != null && below.finishing) {
6518 continue;
6519 }
6520 if (target == null) {
6521 target = below;
6522 targetI = i;
6523 // If we were in the middle of a reply chain before this
6524 // task, it doesn't appear like the root of the chain wants
6525 // anything interesting, so drop it.
6526 replyChainEnd = -1;
6527 continue;
6528 }
6529
6530 final int flags = target.info.flags;
6531
6532 final boolean finishOnTaskLaunch =
6533 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6534 final boolean allowTaskReparenting =
6535 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6536
6537 if (target.task == task) {
6538 // We are inside of the task being reset... we'll either
6539 // finish this activity, push it out for another task,
6540 // or leave it as-is. We only do this
6541 // for activities that are not the root of the task (since
6542 // if we finish the root, we may no longer have the task!).
6543 if (taskTopI < 0) {
6544 taskTopI = targetI;
6545 }
6546 if (below != null && below.task == task) {
6547 final boolean clearWhenTaskReset =
6548 (target.intent.getFlags()
6549 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006550 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006551 // If this activity is sending a reply to a previous
6552 // activity, we can't do anything with it now until
6553 // we reach the start of the reply chain.
6554 // XXX note that we are assuming the result is always
6555 // to the previous activity, which is almost always
6556 // the case but we really shouldn't count on.
6557 if (replyChainEnd < 0) {
6558 replyChainEnd = targetI;
6559 }
Ed Heyl73798232009-03-24 21:32:21 -07006560 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006561 && target.taskAffinity != null
6562 && !target.taskAffinity.equals(task.affinity)) {
6563 // If this activity has an affinity for another
6564 // task, then we need to move it out of here. We will
6565 // move it as far out of the way as possible, to the
6566 // bottom of the activity stack. This also keeps it
6567 // correctly ordered with any activities we previously
6568 // moved.
6569 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6570 if (target.taskAffinity != null
6571 && target.taskAffinity.equals(p.task.affinity)) {
6572 // If the activity currently at the bottom has the
6573 // same task affinity as the one we are moving,
6574 // then merge it into the same task.
6575 target.task = p.task;
6576 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6577 + " out to bottom task " + p.task);
6578 } else {
6579 mCurTask++;
6580 if (mCurTask <= 0) {
6581 mCurTask = 1;
6582 }
6583 target.task = new TaskRecord(mCurTask, target.info, null,
6584 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6585 target.task.affinityIntent = target.intent;
6586 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6587 + " out to new task " + target.task);
6588 }
6589 mWindowManager.setAppGroupId(target, task.taskId);
6590 if (replyChainEnd < 0) {
6591 replyChainEnd = targetI;
6592 }
6593 int dstPos = 0;
6594 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6595 p = (HistoryRecord)mHistory.get(srcPos);
6596 if (p.finishing) {
6597 continue;
6598 }
6599 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6600 + " out to target's task " + target.task);
6601 task.numActivities--;
6602 p.task = target.task;
6603 target.task.numActivities++;
6604 mHistory.remove(srcPos);
6605 mHistory.add(dstPos, p);
6606 mWindowManager.moveAppToken(dstPos, p);
6607 mWindowManager.setAppGroupId(p, p.task.taskId);
6608 dstPos++;
6609 if (VALIDATE_TOKENS) {
6610 mWindowManager.validateAppTokens(mHistory);
6611 }
6612 i++;
6613 }
6614 if (taskTop == p) {
6615 taskTop = below;
6616 }
6617 if (taskTopI == replyChainEnd) {
6618 taskTopI = -1;
6619 }
6620 replyChainEnd = -1;
6621 addRecentTask(target.task);
6622 } else if (forceReset || finishOnTaskLaunch
6623 || clearWhenTaskReset) {
6624 // If the activity should just be removed -- either
6625 // because it asks for it, or the task should be
6626 // cleared -- then finish it and anything that is
6627 // part of its reply chain.
6628 if (clearWhenTaskReset) {
6629 // In this case, we want to finish this activity
6630 // and everything above it, so be sneaky and pretend
6631 // like these are all in the reply chain.
6632 replyChainEnd = targetI+1;
6633 while (replyChainEnd < mHistory.size() &&
6634 ((HistoryRecord)mHistory.get(
6635 replyChainEnd)).task == task) {
6636 replyChainEnd++;
6637 }
6638 replyChainEnd--;
6639 } else if (replyChainEnd < 0) {
6640 replyChainEnd = targetI;
6641 }
6642 HistoryRecord p = null;
6643 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6644 p = (HistoryRecord)mHistory.get(srcPos);
6645 if (p.finishing) {
6646 continue;
6647 }
6648 if (finishActivityLocked(p, srcPos,
6649 Activity.RESULT_CANCELED, null, "reset")) {
6650 replyChainEnd--;
6651 srcPos--;
6652 }
6653 }
6654 if (taskTop == p) {
6655 taskTop = below;
6656 }
6657 if (taskTopI == replyChainEnd) {
6658 taskTopI = -1;
6659 }
6660 replyChainEnd = -1;
6661 } else {
6662 // If we were in the middle of a chain, well the
6663 // activity that started it all doesn't want anything
6664 // special, so leave it all as-is.
6665 replyChainEnd = -1;
6666 }
6667 } else {
6668 // Reached the bottom of the task -- any reply chain
6669 // should be left as-is.
6670 replyChainEnd = -1;
6671 }
6672
6673 } else if (target.resultTo != null) {
6674 // If this activity is sending a reply to a previous
6675 // activity, we can't do anything with it now until
6676 // we reach the start of the reply chain.
6677 // XXX note that we are assuming the result is always
6678 // to the previous activity, which is almost always
6679 // the case but we really shouldn't count on.
6680 if (replyChainEnd < 0) {
6681 replyChainEnd = targetI;
6682 }
6683
6684 } else if (taskTopI >= 0 && allowTaskReparenting
6685 && task.affinity != null
6686 && task.affinity.equals(target.taskAffinity)) {
6687 // We are inside of another task... if this activity has
6688 // an affinity for our task, then either remove it if we are
6689 // clearing or move it over to our task. Note that
6690 // we currently punt on the case where we are resetting a
6691 // task that is not at the top but who has activities above
6692 // with an affinity to it... this is really not a normal
6693 // case, and we will need to later pull that task to the front
6694 // and usually at that point we will do the reset and pick
6695 // up those remaining activities. (This only happens if
6696 // someone starts an activity in a new task from an activity
6697 // in a task that is not currently on top.)
6698 if (forceReset || finishOnTaskLaunch) {
6699 if (replyChainEnd < 0) {
6700 replyChainEnd = targetI;
6701 }
6702 HistoryRecord p = null;
6703 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6704 p = (HistoryRecord)mHistory.get(srcPos);
6705 if (p.finishing) {
6706 continue;
6707 }
6708 if (finishActivityLocked(p, srcPos,
6709 Activity.RESULT_CANCELED, null, "reset")) {
6710 taskTopI--;
6711 lastReparentPos--;
6712 replyChainEnd--;
6713 srcPos--;
6714 }
6715 }
6716 replyChainEnd = -1;
6717 } else {
6718 if (replyChainEnd < 0) {
6719 replyChainEnd = targetI;
6720 }
6721 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6722 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6723 if (p.finishing) {
6724 continue;
6725 }
6726 if (lastReparentPos < 0) {
6727 lastReparentPos = taskTopI;
6728 taskTop = p;
6729 } else {
6730 lastReparentPos--;
6731 }
6732 mHistory.remove(srcPos);
6733 p.task.numActivities--;
6734 p.task = task;
6735 mHistory.add(lastReparentPos, p);
6736 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6737 + " in to resetting task " + task);
6738 task.numActivities++;
6739 mWindowManager.moveAppToken(lastReparentPos, p);
6740 mWindowManager.setAppGroupId(p, p.task.taskId);
6741 if (VALIDATE_TOKENS) {
6742 mWindowManager.validateAppTokens(mHistory);
6743 }
6744 }
6745 replyChainEnd = -1;
6746
6747 // Now we've moved it in to place... but what if this is
6748 // a singleTop activity and we have put it on top of another
6749 // instance of the same activity? Then we drop the instance
6750 // below so it remains singleTop.
6751 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6752 for (int j=lastReparentPos-1; j>=0; j--) {
6753 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6754 if (p.finishing) {
6755 continue;
6756 }
6757 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6758 if (finishActivityLocked(p, j,
6759 Activity.RESULT_CANCELED, null, "replace")) {
6760 taskTopI--;
6761 lastReparentPos--;
6762 }
6763 }
6764 }
6765 }
6766 }
6767 }
6768
6769 target = below;
6770 targetI = i;
6771 }
6772
6773 return taskTop;
6774 }
6775
6776 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006777 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006778 */
6779 public void moveTaskToFront(int task) {
6780 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6781 "moveTaskToFront()");
6782
6783 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006784 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6785 Binder.getCallingUid(), "Task to front")) {
6786 return;
6787 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006788 final long origId = Binder.clearCallingIdentity();
6789 try {
6790 int N = mRecentTasks.size();
6791 for (int i=0; i<N; i++) {
6792 TaskRecord tr = mRecentTasks.get(i);
6793 if (tr.taskId == task) {
6794 moveTaskToFrontLocked(tr);
6795 return;
6796 }
6797 }
6798 for (int i=mHistory.size()-1; i>=0; i--) {
6799 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6800 if (hr.task.taskId == task) {
6801 moveTaskToFrontLocked(hr.task);
6802 return;
6803 }
6804 }
6805 } finally {
6806 Binder.restoreCallingIdentity(origId);
6807 }
6808 }
6809 }
6810
6811 private final void moveTaskToFrontLocked(TaskRecord tr) {
6812 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6813
6814 final int task = tr.taskId;
6815 int top = mHistory.size()-1;
6816
6817 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6818 // nothing to do!
6819 return;
6820 }
6821
6822 if (DEBUG_TRANSITION) Log.v(TAG,
6823 "Prepare to front transition: task=" + tr);
6824 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6825
6826 ArrayList moved = new ArrayList();
6827
6828 // Applying the affinities may have removed entries from the history,
6829 // so get the size again.
6830 top = mHistory.size()-1;
6831 int pos = top;
6832
6833 // Shift all activities with this task up to the top
6834 // of the stack, keeping them in the same internal order.
6835 while (pos >= 0) {
6836 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6837 if (localLOGV) Log.v(
6838 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6839 boolean first = true;
6840 if (r.task.taskId == task) {
6841 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6842 mHistory.remove(pos);
6843 mHistory.add(top, r);
6844 moved.add(0, r);
6845 top--;
6846 if (first) {
6847 addRecentTask(r.task);
6848 first = false;
6849 }
6850 }
6851 pos--;
6852 }
6853
6854 mWindowManager.moveAppTokensToTop(moved);
6855 if (VALIDATE_TOKENS) {
6856 mWindowManager.validateAppTokens(mHistory);
6857 }
6858
6859 finishTaskMove(task);
6860 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6861 }
6862
6863 private final void finishTaskMove(int task) {
6864 resumeTopActivityLocked(null);
6865 }
6866
6867 public void moveTaskToBack(int task) {
6868 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6869 "moveTaskToBack()");
6870
6871 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006872 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6873 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6874 Binder.getCallingUid(), "Task to back")) {
6875 return;
6876 }
6877 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006878 final long origId = Binder.clearCallingIdentity();
6879 moveTaskToBackLocked(task);
6880 Binder.restoreCallingIdentity(origId);
6881 }
6882 }
6883
6884 /**
6885 * Moves an activity, and all of the other activities within the same task, to the bottom
6886 * of the history stack. The activity's order within the task is unchanged.
6887 *
6888 * @param token A reference to the activity we wish to move
6889 * @param nonRoot If false then this only works if the activity is the root
6890 * of a task; if true it will work for any activity in a task.
6891 * @return Returns true if the move completed, false if not.
6892 */
6893 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6894 synchronized(this) {
6895 final long origId = Binder.clearCallingIdentity();
6896 int taskId = getTaskForActivityLocked(token, !nonRoot);
6897 if (taskId >= 0) {
6898 return moveTaskToBackLocked(taskId);
6899 }
6900 Binder.restoreCallingIdentity(origId);
6901 }
6902 return false;
6903 }
6904
6905 /**
6906 * Worker method for rearranging history stack. Implements the function of moving all
6907 * activities for a specific task (gathering them if disjoint) into a single group at the
6908 * bottom of the stack.
6909 *
6910 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6911 * to premeptively cancel the move.
6912 *
6913 * @param task The taskId to collect and move to the bottom.
6914 * @return Returns true if the move completed, false if not.
6915 */
6916 private final boolean moveTaskToBackLocked(int task) {
6917 Log.i(TAG, "moveTaskToBack: " + task);
6918
6919 // If we have a watcher, preflight the move before committing to it. First check
6920 // for *other* available tasks, but if none are available, then try again allowing the
6921 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006922 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006923 HistoryRecord next = topRunningActivityLocked(null, task);
6924 if (next == null) {
6925 next = topRunningActivityLocked(null, 0);
6926 }
6927 if (next != null) {
6928 // ask watcher if this is allowed
6929 boolean moveOK = true;
6930 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006931 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006932 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006933 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006934 }
6935 if (!moveOK) {
6936 return false;
6937 }
6938 }
6939 }
6940
6941 ArrayList moved = new ArrayList();
6942
6943 if (DEBUG_TRANSITION) Log.v(TAG,
6944 "Prepare to back transition: task=" + task);
6945 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
6946
6947 final int N = mHistory.size();
6948 int bottom = 0;
6949 int pos = 0;
6950
6951 // Shift all activities with this task down to the bottom
6952 // of the stack, keeping them in the same internal order.
6953 while (pos < N) {
6954 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6955 if (localLOGV) Log.v(
6956 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6957 if (r.task.taskId == task) {
6958 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
6959 mHistory.remove(pos);
6960 mHistory.add(bottom, r);
6961 moved.add(r);
6962 bottom++;
6963 }
6964 pos++;
6965 }
6966
6967 mWindowManager.moveAppTokensToBottom(moved);
6968 if (VALIDATE_TOKENS) {
6969 mWindowManager.validateAppTokens(mHistory);
6970 }
6971
6972 finishTaskMove(task);
6973 return true;
6974 }
6975
6976 public void moveTaskBackwards(int task) {
6977 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6978 "moveTaskBackwards()");
6979
6980 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006981 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6982 Binder.getCallingUid(), "Task backwards")) {
6983 return;
6984 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006985 final long origId = Binder.clearCallingIdentity();
6986 moveTaskBackwardsLocked(task);
6987 Binder.restoreCallingIdentity(origId);
6988 }
6989 }
6990
6991 private final void moveTaskBackwardsLocked(int task) {
6992 Log.e(TAG, "moveTaskBackwards not yet implemented!");
6993 }
6994
6995 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
6996 synchronized(this) {
6997 return getTaskForActivityLocked(token, onlyRoot);
6998 }
6999 }
7000
7001 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
7002 final int N = mHistory.size();
7003 TaskRecord lastTask = null;
7004 for (int i=0; i<N; i++) {
7005 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7006 if (r == token) {
7007 if (!onlyRoot || lastTask != r.task) {
7008 return r.task.taskId;
7009 }
7010 return -1;
7011 }
7012 lastTask = r.task;
7013 }
7014
7015 return -1;
7016 }
7017
7018 /**
7019 * Returns the top activity in any existing task matching the given
7020 * Intent. Returns null if no such task is found.
7021 */
7022 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
7023 ComponentName cls = intent.getComponent();
7024 if (info.targetActivity != null) {
7025 cls = new ComponentName(info.packageName, info.targetActivity);
7026 }
7027
7028 TaskRecord cp = null;
7029
7030 final int N = mHistory.size();
7031 for (int i=(N-1); i>=0; i--) {
7032 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7033 if (!r.finishing && r.task != cp
7034 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
7035 cp = r.task;
7036 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
7037 // + "/aff=" + r.task.affinity + " to new cls="
7038 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
7039 if (r.task.affinity != null) {
7040 if (r.task.affinity.equals(info.taskAffinity)) {
7041 //Log.i(TAG, "Found matching affinity!");
7042 return r;
7043 }
7044 } else if (r.task.intent != null
7045 && r.task.intent.getComponent().equals(cls)) {
7046 //Log.i(TAG, "Found matching class!");
7047 //dump();
7048 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7049 return r;
7050 } else if (r.task.affinityIntent != null
7051 && r.task.affinityIntent.getComponent().equals(cls)) {
7052 //Log.i(TAG, "Found matching class!");
7053 //dump();
7054 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7055 return r;
7056 }
7057 }
7058 }
7059
7060 return null;
7061 }
7062
7063 /**
7064 * Returns the first activity (starting from the top of the stack) that
7065 * is the same as the given activity. Returns null if no such activity
7066 * is found.
7067 */
7068 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
7069 ComponentName cls = intent.getComponent();
7070 if (info.targetActivity != null) {
7071 cls = new ComponentName(info.packageName, info.targetActivity);
7072 }
7073
7074 final int N = mHistory.size();
7075 for (int i=(N-1); i>=0; i--) {
7076 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7077 if (!r.finishing) {
7078 if (r.intent.getComponent().equals(cls)) {
7079 //Log.i(TAG, "Found matching class!");
7080 //dump();
7081 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
7082 return r;
7083 }
7084 }
7085 }
7086
7087 return null;
7088 }
7089
7090 public void finishOtherInstances(IBinder token, ComponentName className) {
7091 synchronized(this) {
7092 final long origId = Binder.clearCallingIdentity();
7093
7094 int N = mHistory.size();
7095 TaskRecord lastTask = null;
7096 for (int i=0; i<N; i++) {
7097 HistoryRecord r = (HistoryRecord)mHistory.get(i);
7098 if (r.realActivity.equals(className)
7099 && r != token && lastTask != r.task) {
7100 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
7101 null, "others")) {
7102 i--;
7103 N--;
7104 }
7105 }
7106 lastTask = r.task;
7107 }
7108
7109 Binder.restoreCallingIdentity(origId);
7110 }
7111 }
7112
7113 // =========================================================
7114 // THUMBNAILS
7115 // =========================================================
7116
7117 public void reportThumbnail(IBinder token,
7118 Bitmap thumbnail, CharSequence description) {
7119 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
7120 final long origId = Binder.clearCallingIdentity();
7121 sendPendingThumbnail(null, token, thumbnail, description, true);
7122 Binder.restoreCallingIdentity(origId);
7123 }
7124
7125 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
7126 Bitmap thumbnail, CharSequence description, boolean always) {
7127 TaskRecord task = null;
7128 ArrayList receivers = null;
7129
7130 //System.out.println("Send pending thumbnail: " + r);
7131
7132 synchronized(this) {
7133 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07007134 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007135 if (index < 0) {
7136 return;
7137 }
7138 r = (HistoryRecord)mHistory.get(index);
7139 }
7140 if (thumbnail == null) {
7141 thumbnail = r.thumbnail;
7142 description = r.description;
7143 }
7144 if (thumbnail == null && !always) {
7145 // If there is no thumbnail, and this entry is not actually
7146 // going away, then abort for now and pick up the next
7147 // thumbnail we get.
7148 return;
7149 }
7150 task = r.task;
7151
7152 int N = mPendingThumbnails.size();
7153 int i=0;
7154 while (i<N) {
7155 PendingThumbnailsRecord pr =
7156 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7157 //System.out.println("Looking in " + pr.pendingRecords);
7158 if (pr.pendingRecords.remove(r)) {
7159 if (receivers == null) {
7160 receivers = new ArrayList();
7161 }
7162 receivers.add(pr);
7163 if (pr.pendingRecords.size() == 0) {
7164 pr.finished = true;
7165 mPendingThumbnails.remove(i);
7166 N--;
7167 continue;
7168 }
7169 }
7170 i++;
7171 }
7172 }
7173
7174 if (receivers != null) {
7175 final int N = receivers.size();
7176 for (int i=0; i<N; i++) {
7177 try {
7178 PendingThumbnailsRecord pr =
7179 (PendingThumbnailsRecord)receivers.get(i);
7180 pr.receiver.newThumbnail(
7181 task != null ? task.taskId : -1, thumbnail, description);
7182 if (pr.finished) {
7183 pr.receiver.finished();
7184 }
7185 } catch (Exception e) {
7186 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7187 }
7188 }
7189 }
7190 }
7191
7192 // =========================================================
7193 // CONTENT PROVIDERS
7194 // =========================================================
7195
7196 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7197 List providers = null;
7198 try {
7199 providers = ActivityThread.getPackageManager().
7200 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007201 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007202 } catch (RemoteException ex) {
7203 }
7204 if (providers != null) {
7205 final int N = providers.size();
7206 for (int i=0; i<N; i++) {
7207 ProviderInfo cpi =
7208 (ProviderInfo)providers.get(i);
7209 ContentProviderRecord cpr =
7210 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7211 if (cpr == null) {
7212 cpr = new ContentProviderRecord(cpi, app.info);
7213 mProvidersByClass.put(cpi.name, cpr);
7214 }
7215 app.pubProviders.put(cpi.name, cpr);
7216 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007217 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007218 }
7219 }
7220 return providers;
7221 }
7222
7223 private final String checkContentProviderPermissionLocked(
7224 ProviderInfo cpi, ProcessRecord r, int mode) {
7225 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7226 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7227 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7228 cpi.exported ? -1 : cpi.applicationInfo.uid)
7229 == PackageManager.PERMISSION_GRANTED
7230 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7231 return null;
7232 }
7233 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7234 cpi.exported ? -1 : cpi.applicationInfo.uid)
7235 == PackageManager.PERMISSION_GRANTED) {
7236 return null;
7237 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007238
7239 PathPermission[] pps = cpi.pathPermissions;
7240 if (pps != null) {
7241 int i = pps.length;
7242 while (i > 0) {
7243 i--;
7244 PathPermission pp = pps[i];
7245 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7246 cpi.exported ? -1 : cpi.applicationInfo.uid)
7247 == PackageManager.PERMISSION_GRANTED
7248 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7249 return null;
7250 }
7251 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7252 cpi.exported ? -1 : cpi.applicationInfo.uid)
7253 == PackageManager.PERMISSION_GRANTED) {
7254 return null;
7255 }
7256 }
7257 }
7258
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007259 String msg = "Permission Denial: opening provider " + cpi.name
7260 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7261 + ", uid=" + callingUid + ") requires "
7262 + cpi.readPermission + " or " + cpi.writePermission;
7263 Log.w(TAG, msg);
7264 return msg;
7265 }
7266
7267 private final ContentProviderHolder getContentProviderImpl(
7268 IApplicationThread caller, String name) {
7269 ContentProviderRecord cpr;
7270 ProviderInfo cpi = null;
7271
7272 synchronized(this) {
7273 ProcessRecord r = null;
7274 if (caller != null) {
7275 r = getRecordForAppLocked(caller);
7276 if (r == null) {
7277 throw new SecurityException(
7278 "Unable to find app for caller " + caller
7279 + " (pid=" + Binder.getCallingPid()
7280 + ") when getting content provider " + name);
7281 }
7282 }
7283
7284 // First check if this content provider has been published...
7285 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7286 if (cpr != null) {
7287 cpi = cpr.info;
7288 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7289 return new ContentProviderHolder(cpi,
7290 cpi.readPermission != null
7291 ? cpi.readPermission : cpi.writePermission);
7292 }
7293
7294 if (r != null && cpr.canRunHere(r)) {
7295 // This provider has been published or is in the process
7296 // of being published... but it is also allowed to run
7297 // in the caller's process, so don't make a connection
7298 // and just let the caller instantiate its own instance.
7299 if (cpr.provider != null) {
7300 // don't give caller the provider object, it needs
7301 // to make its own.
7302 cpr = new ContentProviderRecord(cpr);
7303 }
7304 return cpr;
7305 }
7306
7307 final long origId = Binder.clearCallingIdentity();
7308
7309 // In this case the provider is a single instance, so we can
7310 // return it right away.
7311 if (r != null) {
7312 r.conProviders.add(cpr);
7313 cpr.clients.add(r);
7314 } else {
7315 cpr.externals++;
7316 }
7317
7318 if (cpr.app != null) {
7319 updateOomAdjLocked(cpr.app);
7320 }
7321
7322 Binder.restoreCallingIdentity(origId);
7323
7324 } else {
7325 try {
7326 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007327 resolveContentProvider(name,
7328 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007329 } catch (RemoteException ex) {
7330 }
7331 if (cpi == null) {
7332 return null;
7333 }
7334
7335 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7336 return new ContentProviderHolder(cpi,
7337 cpi.readPermission != null
7338 ? cpi.readPermission : cpi.writePermission);
7339 }
7340
7341 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7342 final boolean firstClass = cpr == null;
7343 if (firstClass) {
7344 try {
7345 ApplicationInfo ai =
7346 ActivityThread.getPackageManager().
7347 getApplicationInfo(
7348 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007349 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007350 if (ai == null) {
7351 Log.w(TAG, "No package info for content provider "
7352 + cpi.name);
7353 return null;
7354 }
7355 cpr = new ContentProviderRecord(cpi, ai);
7356 } catch (RemoteException ex) {
7357 // pm is in same process, this will never happen.
7358 }
7359 }
7360
7361 if (r != null && cpr.canRunHere(r)) {
7362 // If this is a multiprocess provider, then just return its
7363 // info and allow the caller to instantiate it. Only do
7364 // this if the provider is the same user as the caller's
7365 // process, or can run as root (so can be in any process).
7366 return cpr;
7367 }
7368
7369 if (false) {
7370 RuntimeException e = new RuntimeException("foo");
7371 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7372 // + " pruid " + ai.uid + "): " + cpi.className, e);
7373 }
7374
7375 // This is single process, and our app is now connecting to it.
7376 // See if we are already in the process of launching this
7377 // provider.
7378 final int N = mLaunchingProviders.size();
7379 int i;
7380 for (i=0; i<N; i++) {
7381 if (mLaunchingProviders.get(i) == cpr) {
7382 break;
7383 }
7384 if (false) {
7385 final ContentProviderRecord rec =
7386 (ContentProviderRecord)mLaunchingProviders.get(i);
7387 if (rec.info.name.equals(cpr.info.name)) {
7388 cpr = rec;
7389 break;
7390 }
7391 }
7392 }
7393
7394 // If the provider is not already being launched, then get it
7395 // started.
7396 if (i >= N) {
7397 final long origId = Binder.clearCallingIdentity();
7398 ProcessRecord proc = startProcessLocked(cpi.processName,
7399 cpr.appInfo, false, 0, "content provider",
7400 new ComponentName(cpi.applicationInfo.packageName,
7401 cpi.name));
7402 if (proc == null) {
7403 Log.w(TAG, "Unable to launch app "
7404 + cpi.applicationInfo.packageName + "/"
7405 + cpi.applicationInfo.uid + " for provider "
7406 + name + ": process is bad");
7407 return null;
7408 }
7409 cpr.launchingApp = proc;
7410 mLaunchingProviders.add(cpr);
7411 Binder.restoreCallingIdentity(origId);
7412 }
7413
7414 // Make sure the provider is published (the same provider class
7415 // may be published under multiple names).
7416 if (firstClass) {
7417 mProvidersByClass.put(cpi.name, cpr);
7418 }
7419 mProvidersByName.put(name, cpr);
7420
7421 if (r != null) {
7422 r.conProviders.add(cpr);
7423 cpr.clients.add(r);
7424 } else {
7425 cpr.externals++;
7426 }
7427 }
7428 }
7429
7430 // Wait for the provider to be published...
7431 synchronized (cpr) {
7432 while (cpr.provider == null) {
7433 if (cpr.launchingApp == null) {
7434 Log.w(TAG, "Unable to launch app "
7435 + cpi.applicationInfo.packageName + "/"
7436 + cpi.applicationInfo.uid + " for provider "
7437 + name + ": launching app became null");
7438 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7439 cpi.applicationInfo.packageName,
7440 cpi.applicationInfo.uid, name);
7441 return null;
7442 }
7443 try {
7444 cpr.wait();
7445 } catch (InterruptedException ex) {
7446 }
7447 }
7448 }
7449 return cpr;
7450 }
7451
7452 public final ContentProviderHolder getContentProvider(
7453 IApplicationThread caller, String name) {
7454 if (caller == null) {
7455 String msg = "null IApplicationThread when getting content provider "
7456 + name;
7457 Log.w(TAG, msg);
7458 throw new SecurityException(msg);
7459 }
7460
7461 return getContentProviderImpl(caller, name);
7462 }
7463
7464 private ContentProviderHolder getContentProviderExternal(String name) {
7465 return getContentProviderImpl(null, name);
7466 }
7467
7468 /**
7469 * Drop a content provider from a ProcessRecord's bookkeeping
7470 * @param cpr
7471 */
7472 public void removeContentProvider(IApplicationThread caller, String name) {
7473 synchronized (this) {
7474 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7475 if(cpr == null) {
7476 //remove from mProvidersByClass
7477 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7478 return;
7479 }
7480 final ProcessRecord r = getRecordForAppLocked(caller);
7481 if (r == null) {
7482 throw new SecurityException(
7483 "Unable to find app for caller " + caller +
7484 " when removing content provider " + name);
7485 }
7486 //update content provider record entry info
7487 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7488 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7489 r.info.processName+" from process "+localCpr.appInfo.processName);
7490 if(localCpr.appInfo.processName == r.info.processName) {
7491 //should not happen. taken care of as a local provider
7492 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7493 return;
7494 } else {
7495 localCpr.clients.remove(r);
7496 r.conProviders.remove(localCpr);
7497 }
7498 updateOomAdjLocked();
7499 }
7500 }
7501
7502 private void removeContentProviderExternal(String name) {
7503 synchronized (this) {
7504 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7505 if(cpr == null) {
7506 //remove from mProvidersByClass
7507 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7508 return;
7509 }
7510
7511 //update content provider record entry info
7512 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7513 localCpr.externals--;
7514 if (localCpr.externals < 0) {
7515 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7516 }
7517 updateOomAdjLocked();
7518 }
7519 }
7520
7521 public final void publishContentProviders(IApplicationThread caller,
7522 List<ContentProviderHolder> providers) {
7523 if (providers == null) {
7524 return;
7525 }
7526
7527 synchronized(this) {
7528 final ProcessRecord r = getRecordForAppLocked(caller);
7529 if (r == null) {
7530 throw new SecurityException(
7531 "Unable to find app for caller " + caller
7532 + " (pid=" + Binder.getCallingPid()
7533 + ") when publishing content providers");
7534 }
7535
7536 final long origId = Binder.clearCallingIdentity();
7537
7538 final int N = providers.size();
7539 for (int i=0; i<N; i++) {
7540 ContentProviderHolder src = providers.get(i);
7541 if (src == null || src.info == null || src.provider == null) {
7542 continue;
7543 }
7544 ContentProviderRecord dst =
7545 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7546 if (dst != null) {
7547 mProvidersByClass.put(dst.info.name, dst);
7548 String names[] = dst.info.authority.split(";");
7549 for (int j = 0; j < names.length; j++) {
7550 mProvidersByName.put(names[j], dst);
7551 }
7552
7553 int NL = mLaunchingProviders.size();
7554 int j;
7555 for (j=0; j<NL; j++) {
7556 if (mLaunchingProviders.get(j) == dst) {
7557 mLaunchingProviders.remove(j);
7558 j--;
7559 NL--;
7560 }
7561 }
7562 synchronized (dst) {
7563 dst.provider = src.provider;
7564 dst.app = r;
7565 dst.notifyAll();
7566 }
7567 updateOomAdjLocked(r);
7568 }
7569 }
7570
7571 Binder.restoreCallingIdentity(origId);
7572 }
7573 }
7574
7575 public static final void installSystemProviders() {
7576 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7577 List providers = mSelf.generateApplicationProvidersLocked(app);
7578 mSystemThread.installSystemProviders(providers);
7579 }
7580
7581 // =========================================================
7582 // GLOBAL MANAGEMENT
7583 // =========================================================
7584
7585 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7586 ApplicationInfo info, String customProcess) {
7587 String proc = customProcess != null ? customProcess : info.processName;
7588 BatteryStatsImpl.Uid.Proc ps = null;
7589 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7590 synchronized (stats) {
7591 ps = stats.getProcessStatsLocked(info.uid, proc);
7592 }
7593 return new ProcessRecord(ps, thread, info, proc);
7594 }
7595
7596 final ProcessRecord addAppLocked(ApplicationInfo info) {
7597 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7598
7599 if (app == null) {
7600 app = newProcessRecordLocked(null, info, null);
7601 mProcessNames.put(info.processName, info.uid, app);
7602 updateLRUListLocked(app, true);
7603 }
7604
7605 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7606 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7607 app.persistent = true;
7608 app.maxAdj = CORE_SERVER_ADJ;
7609 }
7610 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7611 mPersistentStartingProcesses.add(app);
7612 startProcessLocked(app, "added application", app.processName);
7613 }
7614
7615 return app;
7616 }
7617
7618 public void unhandledBack() {
7619 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7620 "unhandledBack()");
7621
7622 synchronized(this) {
7623 int count = mHistory.size();
7624 if (Config.LOGD) Log.d(
7625 TAG, "Performing unhandledBack(): stack size = " + count);
7626 if (count > 1) {
7627 final long origId = Binder.clearCallingIdentity();
7628 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7629 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7630 Binder.restoreCallingIdentity(origId);
7631 }
7632 }
7633 }
7634
7635 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7636 String name = uri.getAuthority();
7637 ContentProviderHolder cph = getContentProviderExternal(name);
7638 ParcelFileDescriptor pfd = null;
7639 if (cph != null) {
7640 // We record the binder invoker's uid in thread-local storage before
7641 // going to the content provider to open the file. Later, in the code
7642 // that handles all permissions checks, we look for this uid and use
7643 // that rather than the Activity Manager's own uid. The effect is that
7644 // we do the check against the caller's permissions even though it looks
7645 // to the content provider like the Activity Manager itself is making
7646 // the request.
7647 sCallerIdentity.set(new Identity(
7648 Binder.getCallingPid(), Binder.getCallingUid()));
7649 try {
7650 pfd = cph.provider.openFile(uri, "r");
7651 } catch (FileNotFoundException e) {
7652 // do nothing; pfd will be returned null
7653 } finally {
7654 // Ensure that whatever happens, we clean up the identity state
7655 sCallerIdentity.remove();
7656 }
7657
7658 // We've got the fd now, so we're done with the provider.
7659 removeContentProviderExternal(name);
7660 } else {
7661 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7662 }
7663 return pfd;
7664 }
7665
7666 public void goingToSleep() {
7667 synchronized(this) {
7668 mSleeping = true;
7669 mWindowManager.setEventDispatching(false);
7670
7671 if (mResumedActivity != null) {
7672 pauseIfSleepingLocked();
7673 } else {
7674 Log.w(TAG, "goingToSleep with no resumed activity!");
7675 }
7676 }
7677 }
7678
Dianne Hackborn55280a92009-05-07 15:53:46 -07007679 public boolean shutdown(int timeout) {
7680 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7681 != PackageManager.PERMISSION_GRANTED) {
7682 throw new SecurityException("Requires permission "
7683 + android.Manifest.permission.SHUTDOWN);
7684 }
7685
7686 boolean timedout = false;
7687
7688 synchronized(this) {
7689 mShuttingDown = true;
7690 mWindowManager.setEventDispatching(false);
7691
7692 if (mResumedActivity != null) {
7693 pauseIfSleepingLocked();
7694 final long endTime = System.currentTimeMillis() + timeout;
7695 while (mResumedActivity != null || mPausingActivity != null) {
7696 long delay = endTime - System.currentTimeMillis();
7697 if (delay <= 0) {
7698 Log.w(TAG, "Activity manager shutdown timed out");
7699 timedout = true;
7700 break;
7701 }
7702 try {
7703 this.wait();
7704 } catch (InterruptedException e) {
7705 }
7706 }
7707 }
7708 }
7709
7710 mUsageStatsService.shutdown();
7711 mBatteryStatsService.shutdown();
7712
7713 return timedout;
7714 }
7715
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007716 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007717 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007718 if (!mGoingToSleep.isHeld()) {
7719 mGoingToSleep.acquire();
7720 if (mLaunchingActivity.isHeld()) {
7721 mLaunchingActivity.release();
7722 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7723 }
7724 }
7725
7726 // If we are not currently pausing an activity, get the current
7727 // one to pause. If we are pausing one, we will just let that stuff
7728 // run and release the wake lock when all done.
7729 if (mPausingActivity == null) {
7730 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7731 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7732 startPausingLocked(false, true);
7733 }
7734 }
7735 }
7736
7737 public void wakingUp() {
7738 synchronized(this) {
7739 if (mGoingToSleep.isHeld()) {
7740 mGoingToSleep.release();
7741 }
7742 mWindowManager.setEventDispatching(true);
7743 mSleeping = false;
7744 resumeTopActivityLocked(null);
7745 }
7746 }
7747
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007748 public void stopAppSwitches() {
7749 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7750 != PackageManager.PERMISSION_GRANTED) {
7751 throw new SecurityException("Requires permission "
7752 + android.Manifest.permission.STOP_APP_SWITCHES);
7753 }
7754
7755 synchronized(this) {
7756 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7757 + APP_SWITCH_DELAY_TIME;
7758 mDidAppSwitch = false;
7759 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7760 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7761 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7762 }
7763 }
7764
7765 public void resumeAppSwitches() {
7766 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7767 != PackageManager.PERMISSION_GRANTED) {
7768 throw new SecurityException("Requires permission "
7769 + android.Manifest.permission.STOP_APP_SWITCHES);
7770 }
7771
7772 synchronized(this) {
7773 // Note that we don't execute any pending app switches... we will
7774 // let those wait until either the timeout, or the next start
7775 // activity request.
7776 mAppSwitchesAllowedTime = 0;
7777 }
7778 }
7779
7780 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7781 String name) {
7782 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7783 return true;
7784 }
7785
7786 final int perm = checkComponentPermission(
7787 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7788 callingUid, -1);
7789 if (perm == PackageManager.PERMISSION_GRANTED) {
7790 return true;
7791 }
7792
7793 Log.w(TAG, name + " request from " + callingUid + " stopped");
7794 return false;
7795 }
7796
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007797 public void setDebugApp(String packageName, boolean waitForDebugger,
7798 boolean persistent) {
7799 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7800 "setDebugApp()");
7801
7802 // Note that this is not really thread safe if there are multiple
7803 // callers into it at the same time, but that's not a situation we
7804 // care about.
7805 if (persistent) {
7806 final ContentResolver resolver = mContext.getContentResolver();
7807 Settings.System.putString(
7808 resolver, Settings.System.DEBUG_APP,
7809 packageName);
7810 Settings.System.putInt(
7811 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7812 waitForDebugger ? 1 : 0);
7813 }
7814
7815 synchronized (this) {
7816 if (!persistent) {
7817 mOrigDebugApp = mDebugApp;
7818 mOrigWaitForDebugger = mWaitForDebugger;
7819 }
7820 mDebugApp = packageName;
7821 mWaitForDebugger = waitForDebugger;
7822 mDebugTransient = !persistent;
7823 if (packageName != null) {
7824 final long origId = Binder.clearCallingIdentity();
7825 uninstallPackageLocked(packageName, -1, false);
7826 Binder.restoreCallingIdentity(origId);
7827 }
7828 }
7829 }
7830
7831 public void setAlwaysFinish(boolean enabled) {
7832 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7833 "setAlwaysFinish()");
7834
7835 Settings.System.putInt(
7836 mContext.getContentResolver(),
7837 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7838
7839 synchronized (this) {
7840 mAlwaysFinishActivities = enabled;
7841 }
7842 }
7843
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007844 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007845 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007846 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007847 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007848 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007849 }
7850 }
7851
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007852 public void registerActivityWatcher(IActivityWatcher watcher) {
7853 mWatchers.register(watcher);
7854 }
7855
7856 public void unregisterActivityWatcher(IActivityWatcher watcher) {
7857 mWatchers.unregister(watcher);
7858 }
7859
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007860 public final void enterSafeMode() {
7861 synchronized(this) {
7862 // It only makes sense to do this before the system is ready
7863 // and started launching other packages.
7864 if (!mSystemReady) {
7865 try {
7866 ActivityThread.getPackageManager().enterSafeMode();
7867 } catch (RemoteException e) {
7868 }
7869
7870 View v = LayoutInflater.from(mContext).inflate(
7871 com.android.internal.R.layout.safe_mode, null);
7872 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7873 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7874 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7875 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7876 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7877 lp.format = v.getBackground().getOpacity();
7878 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7879 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7880 ((WindowManager)mContext.getSystemService(
7881 Context.WINDOW_SERVICE)).addView(v, lp);
7882 }
7883 }
7884 }
7885
7886 public void noteWakeupAlarm(IIntentSender sender) {
7887 if (!(sender instanceof PendingIntentRecord)) {
7888 return;
7889 }
7890 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7891 synchronized (stats) {
7892 if (mBatteryStatsService.isOnBattery()) {
7893 mBatteryStatsService.enforceCallingPermission();
7894 PendingIntentRecord rec = (PendingIntentRecord)sender;
7895 int MY_UID = Binder.getCallingUid();
7896 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7897 BatteryStatsImpl.Uid.Pkg pkg =
7898 stats.getPackageStatsLocked(uid, rec.key.packageName);
7899 pkg.incWakeupsLocked();
7900 }
7901 }
7902 }
7903
7904 public boolean killPidsForMemory(int[] pids) {
7905 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7906 throw new SecurityException("killPidsForMemory only available to the system");
7907 }
7908
7909 // XXX Note: don't acquire main activity lock here, because the window
7910 // manager calls in with its locks held.
7911
7912 boolean killed = false;
7913 synchronized (mPidsSelfLocked) {
7914 int[] types = new int[pids.length];
7915 int worstType = 0;
7916 for (int i=0; i<pids.length; i++) {
7917 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7918 if (proc != null) {
7919 int type = proc.setAdj;
7920 types[i] = type;
7921 if (type > worstType) {
7922 worstType = type;
7923 }
7924 }
7925 }
7926
7927 // If the worse oom_adj is somewhere in the hidden proc LRU range,
7928 // then constrain it so we will kill all hidden procs.
7929 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
7930 worstType = HIDDEN_APP_MIN_ADJ;
7931 }
7932 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
7933 for (int i=0; i<pids.length; i++) {
7934 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7935 if (proc == null) {
7936 continue;
7937 }
7938 int adj = proc.setAdj;
7939 if (adj >= worstType) {
7940 Log.w(TAG, "Killing for memory: " + proc + " (adj "
7941 + adj + ")");
7942 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
7943 proc.processName, adj);
7944 killed = true;
7945 Process.killProcess(pids[i]);
7946 }
7947 }
7948 }
7949 return killed;
7950 }
7951
7952 public void reportPss(IApplicationThread caller, int pss) {
7953 Watchdog.PssRequestor req;
7954 String name;
7955 ProcessRecord callerApp;
7956 synchronized (this) {
7957 if (caller == null) {
7958 return;
7959 }
7960 callerApp = getRecordForAppLocked(caller);
7961 if (callerApp == null) {
7962 return;
7963 }
7964 callerApp.lastPss = pss;
7965 req = callerApp;
7966 name = callerApp.processName;
7967 }
7968 Watchdog.getInstance().reportPss(req, name, pss);
7969 if (!callerApp.persistent) {
7970 removeRequestedPss(callerApp);
7971 }
7972 }
7973
7974 public void requestPss(Runnable completeCallback) {
7975 ArrayList<ProcessRecord> procs;
7976 synchronized (this) {
7977 mRequestPssCallback = completeCallback;
7978 mRequestPssList.clear();
7979 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
7980 ProcessRecord proc = mLRUProcesses.get(i);
7981 if (!proc.persistent) {
7982 mRequestPssList.add(proc);
7983 }
7984 }
7985 procs = new ArrayList<ProcessRecord>(mRequestPssList);
7986 }
7987
7988 int oldPri = Process.getThreadPriority(Process.myTid());
7989 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
7990 for (int i=procs.size()-1; i>=0; i--) {
7991 ProcessRecord proc = procs.get(i);
7992 proc.lastPss = 0;
7993 proc.requestPss();
7994 }
7995 Process.setThreadPriority(oldPri);
7996 }
7997
7998 void removeRequestedPss(ProcessRecord proc) {
7999 Runnable callback = null;
8000 synchronized (this) {
8001 if (mRequestPssList.remove(proc)) {
8002 if (mRequestPssList.size() == 0) {
8003 callback = mRequestPssCallback;
8004 mRequestPssCallback = null;
8005 }
8006 }
8007 }
8008
8009 if (callback != null) {
8010 callback.run();
8011 }
8012 }
8013
8014 public void collectPss(Watchdog.PssStats stats) {
8015 stats.mEmptyPss = 0;
8016 stats.mEmptyCount = 0;
8017 stats.mBackgroundPss = 0;
8018 stats.mBackgroundCount = 0;
8019 stats.mServicePss = 0;
8020 stats.mServiceCount = 0;
8021 stats.mVisiblePss = 0;
8022 stats.mVisibleCount = 0;
8023 stats.mForegroundPss = 0;
8024 stats.mForegroundCount = 0;
8025 stats.mNoPssCount = 0;
8026 synchronized (this) {
8027 int i;
8028 int NPD = mProcDeaths.length < stats.mProcDeaths.length
8029 ? mProcDeaths.length : stats.mProcDeaths.length;
8030 int aggr = 0;
8031 for (i=0; i<NPD; i++) {
8032 aggr += mProcDeaths[i];
8033 stats.mProcDeaths[i] = aggr;
8034 }
8035 while (i<stats.mProcDeaths.length) {
8036 stats.mProcDeaths[i] = 0;
8037 i++;
8038 }
8039
8040 for (i=mLRUProcesses.size()-1; i>=0; i--) {
8041 ProcessRecord proc = mLRUProcesses.get(i);
8042 if (proc.persistent) {
8043 continue;
8044 }
8045 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
8046 if (proc.lastPss == 0) {
8047 stats.mNoPssCount++;
8048 continue;
8049 }
8050 if (proc.setAdj == EMPTY_APP_ADJ) {
8051 stats.mEmptyPss += proc.lastPss;
8052 stats.mEmptyCount++;
8053 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
8054 stats.mEmptyPss += proc.lastPss;
8055 stats.mEmptyCount++;
8056 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
8057 stats.mBackgroundPss += proc.lastPss;
8058 stats.mBackgroundCount++;
8059 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
8060 stats.mVisiblePss += proc.lastPss;
8061 stats.mVisibleCount++;
8062 } else {
8063 stats.mForegroundPss += proc.lastPss;
8064 stats.mForegroundCount++;
8065 }
8066 }
8067 }
8068 }
8069
8070 public final void startRunning(String pkg, String cls, String action,
8071 String data) {
8072 synchronized(this) {
8073 if (mStartRunning) {
8074 return;
8075 }
8076 mStartRunning = true;
8077 mTopComponent = pkg != null && cls != null
8078 ? new ComponentName(pkg, cls) : null;
8079 mTopAction = action != null ? action : Intent.ACTION_MAIN;
8080 mTopData = data;
8081 if (!mSystemReady) {
8082 return;
8083 }
8084 }
8085
8086 systemReady();
8087 }
8088
8089 private void retrieveSettings() {
8090 final ContentResolver resolver = mContext.getContentResolver();
8091 String debugApp = Settings.System.getString(
8092 resolver, Settings.System.DEBUG_APP);
8093 boolean waitForDebugger = Settings.System.getInt(
8094 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
8095 boolean alwaysFinishActivities = Settings.System.getInt(
8096 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
8097
8098 Configuration configuration = new Configuration();
8099 Settings.System.getConfiguration(resolver, configuration);
8100
8101 synchronized (this) {
8102 mDebugApp = mOrigDebugApp = debugApp;
8103 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
8104 mAlwaysFinishActivities = alwaysFinishActivities;
8105 // This happens before any activities are started, so we can
8106 // change mConfiguration in-place.
8107 mConfiguration.updateFrom(configuration);
8108 }
8109 }
8110
8111 public boolean testIsSystemReady() {
8112 // no need to synchronize(this) just to read & return the value
8113 return mSystemReady;
8114 }
8115
8116 public void systemReady() {
8117 // In the simulator, startRunning will never have been called, which
8118 // normally sets a few crucial variables. Do it here instead.
8119 if (!Process.supportsProcesses()) {
8120 mStartRunning = true;
8121 mTopAction = Intent.ACTION_MAIN;
8122 }
8123
8124 synchronized(this) {
8125 if (mSystemReady) {
8126 return;
8127 }
8128 mSystemReady = true;
8129 if (!mStartRunning) {
8130 return;
8131 }
8132 }
8133
8134 if (Config.LOGD) Log.d(TAG, "Start running!");
8135 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8136 SystemClock.uptimeMillis());
8137
8138 synchronized(this) {
8139 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8140 ResolveInfo ri = mContext.getPackageManager()
8141 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008142 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008143 CharSequence errorMsg = null;
8144 if (ri != null) {
8145 ActivityInfo ai = ri.activityInfo;
8146 ApplicationInfo app = ai.applicationInfo;
8147 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8148 mTopAction = Intent.ACTION_FACTORY_TEST;
8149 mTopData = null;
8150 mTopComponent = new ComponentName(app.packageName,
8151 ai.name);
8152 } else {
8153 errorMsg = mContext.getResources().getText(
8154 com.android.internal.R.string.factorytest_not_system);
8155 }
8156 } else {
8157 errorMsg = mContext.getResources().getText(
8158 com.android.internal.R.string.factorytest_no_action);
8159 }
8160 if (errorMsg != null) {
8161 mTopAction = null;
8162 mTopData = null;
8163 mTopComponent = null;
8164 Message msg = Message.obtain();
8165 msg.what = SHOW_FACTORY_ERROR_MSG;
8166 msg.getData().putCharSequence("msg", errorMsg);
8167 mHandler.sendMessage(msg);
8168 }
8169 }
8170 }
8171
8172 retrieveSettings();
8173
8174 synchronized (this) {
8175 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8176 try {
8177 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008178 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008179 if (apps != null) {
8180 int N = apps.size();
8181 int i;
8182 for (i=0; i<N; i++) {
8183 ApplicationInfo info
8184 = (ApplicationInfo)apps.get(i);
8185 if (info != null &&
8186 !info.packageName.equals("android")) {
8187 addAppLocked(info);
8188 }
8189 }
8190 }
8191 } catch (RemoteException ex) {
8192 // pm is in same process, this will never happen.
8193 }
8194 }
8195
8196 try {
8197 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8198 Message msg = Message.obtain();
8199 msg.what = SHOW_UID_ERROR_MSG;
8200 mHandler.sendMessage(msg);
8201 }
8202 } catch (RemoteException e) {
8203 }
8204
8205 // Start up initial activity.
8206 mBooting = true;
8207 resumeTopActivityLocked(null);
8208 }
8209 }
8210
8211 boolean makeAppCrashingLocked(ProcessRecord app,
8212 String tag, String shortMsg, String longMsg, byte[] crashData) {
8213 app.crashing = true;
8214 app.crashingReport = generateProcessError(app,
8215 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8216 startAppProblemLocked(app);
8217 app.stopFreezingAllLocked();
8218 return handleAppCrashLocked(app);
8219 }
8220
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008221 private ComponentName getErrorReportReceiver(ProcessRecord app) {
8222 IPackageManager pm = ActivityThread.getPackageManager();
Jacek Surazski82a73df2009-06-17 14:33:18 +02008223
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008224 try {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008225 // look for receiver in the installer package
8226 String candidate = pm.getInstallerPackageName(app.info.packageName);
8227 ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8228 if (result != null) {
8229 return result;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008230 }
8231
Jacek Surazski82a73df2009-06-17 14:33:18 +02008232 // if the error app is on the system image, look for system apps
8233 // error receiver
8234 if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8235 candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY);
8236 result = getErrorReportReceiver(pm, app.info.packageName, candidate);
8237 if (result != null) {
8238 return result;
8239 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008240 }
8241
Jacek Surazski82a73df2009-06-17 14:33:18 +02008242 // if there is a default receiver, try that
8243 candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY);
8244 return getErrorReportReceiver(pm, app.info.packageName, candidate);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008245 } catch (RemoteException e) {
Jacek Surazski82a73df2009-06-17 14:33:18 +02008246 // should not happen
8247 Log.e(TAG, "error talking to PackageManager", e);
8248 return null;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008249 }
Jacek Surazski82a73df2009-06-17 14:33:18 +02008250 }
8251
8252 /**
8253 * Return activity in receiverPackage that handles ACTION_APP_ERROR.
8254 *
8255 * @param pm PackageManager isntance
8256 * @param errorPackage package which caused the error
8257 * @param receiverPackage candidate package to receive the error
8258 * @return activity component within receiverPackage which handles
8259 * ACTION_APP_ERROR, or null if not found
8260 */
8261 private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage,
8262 String receiverPackage) throws RemoteException {
8263 if (receiverPackage == null || receiverPackage.length() == 0) {
8264 return null;
8265 }
8266
8267 // break the loop if it's the error report receiver package that crashed
8268 if (receiverPackage.equals(errorPackage)) {
8269 return null;
8270 }
8271
8272 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
8273 intent.setPackage(receiverPackage);
8274 ResolveInfo info = pm.resolveIntent(intent, null, 0);
8275 if (info == null || info.activityInfo == null) {
8276 return null;
8277 }
8278 return new ComponentName(receiverPackage, info.activityInfo.name);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008279 }
8280
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008281 void makeAppNotRespondingLocked(ProcessRecord app,
8282 String tag, String shortMsg, String longMsg, byte[] crashData) {
8283 app.notResponding = true;
8284 app.notRespondingReport = generateProcessError(app,
8285 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8286 crashData);
8287 startAppProblemLocked(app);
8288 app.stopFreezingAllLocked();
8289 }
8290
8291 /**
8292 * Generate a process error record, suitable for attachment to a ProcessRecord.
8293 *
8294 * @param app The ProcessRecord in which the error occurred.
8295 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8296 * ActivityManager.AppErrorStateInfo
8297 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8298 * @param shortMsg Short message describing the crash.
8299 * @param longMsg Long message describing the crash.
8300 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8301 *
8302 * @return Returns a fully-formed AppErrorStateInfo record.
8303 */
8304 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8305 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8306 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8307
8308 report.condition = condition;
8309 report.processName = app.processName;
8310 report.pid = app.pid;
8311 report.uid = app.info.uid;
8312 report.tag = tag;
8313 report.shortMsg = shortMsg;
8314 report.longMsg = longMsg;
8315 report.crashData = crashData;
8316
8317 return report;
8318 }
8319
8320 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8321 boolean crashed) {
8322 synchronized (this) {
8323 app.crashing = false;
8324 app.crashingReport = null;
8325 app.notResponding = false;
8326 app.notRespondingReport = null;
8327 if (app.anrDialog == fromDialog) {
8328 app.anrDialog = null;
8329 }
8330 if (app.waitDialog == fromDialog) {
8331 app.waitDialog = null;
8332 }
8333 if (app.pid > 0 && app.pid != MY_PID) {
8334 if (crashed) {
8335 handleAppCrashLocked(app);
8336 }
8337 Log.i(ActivityManagerService.TAG, "Killing process "
8338 + app.processName
8339 + " (pid=" + app.pid + ") at user's request");
8340 Process.killProcess(app.pid);
8341 }
8342
8343 }
8344 }
8345
8346 boolean handleAppCrashLocked(ProcessRecord app) {
8347 long now = SystemClock.uptimeMillis();
8348
8349 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8350 app.info.uid);
8351 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8352 // This process loses!
8353 Log.w(TAG, "Process " + app.info.processName
8354 + " has crashed too many times: killing!");
8355 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8356 app.info.processName, app.info.uid);
8357 killServicesLocked(app, false);
8358 for (int i=mHistory.size()-1; i>=0; i--) {
8359 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8360 if (r.app == app) {
8361 if (Config.LOGD) Log.d(
8362 TAG, " Force finishing activity "
8363 + r.intent.getComponent().flattenToShortString());
8364 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8365 }
8366 }
8367 if (!app.persistent) {
8368 // We don't want to start this process again until the user
8369 // explicitly does so... but for persistent process, we really
8370 // need to keep it running. If a persistent process is actually
8371 // repeatedly crashing, then badness for everyone.
8372 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8373 app.info.processName);
8374 mBadProcesses.put(app.info.processName, app.info.uid, now);
8375 app.bad = true;
8376 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8377 app.removed = true;
8378 removeProcessLocked(app, false);
8379 return false;
8380 }
8381 }
8382
8383 // Bump up the crash count of any services currently running in the proc.
8384 if (app.services.size() != 0) {
8385 // Any services running in the application need to be placed
8386 // back in the pending list.
8387 Iterator it = app.services.iterator();
8388 while (it.hasNext()) {
8389 ServiceRecord sr = (ServiceRecord)it.next();
8390 sr.crashCount++;
8391 }
8392 }
8393
8394 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8395 return true;
8396 }
8397
8398 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008399 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008400 skipCurrentReceiverLocked(app);
8401 }
8402
8403 void skipCurrentReceiverLocked(ProcessRecord app) {
8404 boolean reschedule = false;
8405 BroadcastRecord r = app.curReceiver;
8406 if (r != null) {
8407 // The current broadcast is waiting for this app's receiver
8408 // to be finished. Looks like that's not going to happen, so
8409 // let the broadcast continue.
8410 logBroadcastReceiverDiscard(r);
8411 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8412 r.resultExtras, r.resultAbort, true);
8413 reschedule = true;
8414 }
8415 r = mPendingBroadcast;
8416 if (r != null && r.curApp == app) {
8417 if (DEBUG_BROADCAST) Log.v(TAG,
8418 "skip & discard pending app " + r);
8419 logBroadcastReceiverDiscard(r);
8420 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8421 r.resultExtras, r.resultAbort, true);
8422 reschedule = true;
8423 }
8424 if (reschedule) {
8425 scheduleBroadcastsLocked();
8426 }
8427 }
8428
8429 public int handleApplicationError(IBinder app, int flags,
8430 String tag, String shortMsg, String longMsg, byte[] crashData) {
8431 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008432 ProcessRecord r = null;
8433 synchronized (this) {
8434 if (app != null) {
8435 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8436 final int NA = apps.size();
8437 for (int ia=0; ia<NA; ia++) {
8438 ProcessRecord p = apps.valueAt(ia);
8439 if (p.thread != null && p.thread.asBinder() == app) {
8440 r = p;
8441 break;
8442 }
8443 }
8444 }
8445 }
8446
8447 if (r != null) {
8448 // The application has crashed. Send the SIGQUIT to the process so
8449 // that it can dump its state.
8450 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8451 //Log.i(TAG, "Current system threads:");
8452 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8453 }
8454
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008455 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008456 try {
8457 String name = r != null ? r.processName : null;
8458 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008459 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008460 shortMsg, longMsg, crashData)) {
8461 Log.w(TAG, "Force-killing crashed app " + name
8462 + " at watcher's request");
8463 Process.killProcess(pid);
8464 return 0;
8465 }
8466 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008467 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008468 }
8469 }
8470
8471 final long origId = Binder.clearCallingIdentity();
8472
8473 // If this process is running instrumentation, finish it.
8474 if (r != null && r.instrumentationClass != null) {
8475 Log.w(TAG, "Error in app " + r.processName
8476 + " running instrumentation " + r.instrumentationClass + ":");
8477 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8478 if (longMsg != null) Log.w(TAG, " " + longMsg);
8479 Bundle info = new Bundle();
8480 info.putString("shortMsg", shortMsg);
8481 info.putString("longMsg", longMsg);
8482 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8483 Binder.restoreCallingIdentity(origId);
8484 return 0;
8485 }
8486
8487 if (r != null) {
8488 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8489 return 0;
8490 }
8491 } else {
8492 Log.w(TAG, "Some application object " + app + " tag " + tag
8493 + " has crashed, but I don't know who it is.");
8494 Log.w(TAG, "ShortMsg:" + shortMsg);
8495 Log.w(TAG, "LongMsg:" + longMsg);
8496 Binder.restoreCallingIdentity(origId);
8497 return 0;
8498 }
8499
8500 Message msg = Message.obtain();
8501 msg.what = SHOW_ERROR_MSG;
8502 HashMap data = new HashMap();
8503 data.put("result", result);
8504 data.put("app", r);
8505 data.put("flags", flags);
8506 data.put("shortMsg", shortMsg);
8507 data.put("longMsg", longMsg);
8508 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8509 // For system processes, submit crash data to the server.
8510 data.put("crashData", crashData);
8511 }
8512 msg.obj = data;
8513 mHandler.sendMessage(msg);
8514
8515 Binder.restoreCallingIdentity(origId);
8516 }
8517
8518 int res = result.get();
8519
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008520 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008521 synchronized (this) {
8522 if (r != null) {
8523 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8524 SystemClock.uptimeMillis());
8525 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008526 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8527 appErrorIntent = createAppErrorIntentLocked(r);
8528 res = AppErrorDialog.FORCE_QUIT;
8529 }
8530 }
8531
8532 if (appErrorIntent != null) {
8533 try {
8534 mContext.startActivity(appErrorIntent);
8535 } catch (ActivityNotFoundException e) {
8536 Log.w(TAG, "bug report receiver dissappeared", e);
8537 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008538 }
8539
8540 return res;
8541 }
8542
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008543 Intent createAppErrorIntentLocked(ProcessRecord r) {
8544 ApplicationErrorReport report = createAppErrorReportLocked(r);
8545 if (report == null) {
8546 return null;
8547 }
8548 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8549 result.setComponent(r.errorReportReceiver);
8550 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8551 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8552 return result;
8553 }
8554
8555 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8556 if (r.errorReportReceiver == null) {
8557 return null;
8558 }
8559
8560 if (!r.crashing && !r.notResponding) {
8561 return null;
8562 }
8563
8564 try {
8565 ApplicationErrorReport report = new ApplicationErrorReport();
8566 report.packageName = r.info.packageName;
8567 report.installerPackageName = r.errorReportReceiver.getPackageName();
8568 report.processName = r.processName;
8569
8570 if (r.crashing) {
8571 report.type = ApplicationErrorReport.TYPE_CRASH;
8572 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8573
8574 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8575 r.crashingReport.crashData);
8576 DataInputStream dataStream = new DataInputStream(byteStream);
8577 CrashData crashData = new CrashData(dataStream);
8578 ThrowableData throwData = crashData.getThrowableData();
8579
8580 report.time = crashData.getTime();
8581 report.crashInfo.stackTrace = throwData.toString();
8582
Jacek Surazskif829a782009-06-11 22:47:02 +02008583 // Extract the source of the exception, useful for report
8584 // clustering. Also extract the "deepest" non-null exception
8585 // message.
8586 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008587 while (throwData.getCause() != null) {
8588 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008589 String msg = throwData.getMessage();
8590 if (msg != null && msg.length() > 0) {
8591 exceptionMessage = msg;
8592 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008593 }
8594 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008595 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008596 report.crashInfo.exceptionClassName = throwData.getType();
8597 report.crashInfo.throwFileName = trace.getFileName();
8598 report.crashInfo.throwClassName = trace.getClassName();
8599 report.crashInfo.throwMethodName = trace.getMethodName();
Jacek Surazski5a123732009-06-23 14:57:08 +02008600 report.crashInfo.throwLineNumber = trace.getLineNumber();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008601 } else if (r.notResponding) {
8602 report.type = ApplicationErrorReport.TYPE_ANR;
8603 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8604
8605 report.anrInfo.activity = r.notRespondingReport.tag;
8606 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8607 report.anrInfo.info = r.notRespondingReport.longMsg;
8608 }
8609
8610 return report;
8611 } catch (IOException e) {
8612 // we don't send it
8613 }
8614
8615 return null;
8616 }
8617
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008618 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8619 // assume our apps are happy - lazy create the list
8620 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8621
8622 synchronized (this) {
8623
8624 // iterate across all processes
8625 final int N = mLRUProcesses.size();
8626 for (int i = 0; i < N; i++) {
8627 ProcessRecord app = mLRUProcesses.get(i);
8628 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8629 // This one's in trouble, so we'll generate a report for it
8630 // crashes are higher priority (in case there's a crash *and* an anr)
8631 ActivityManager.ProcessErrorStateInfo report = null;
8632 if (app.crashing) {
8633 report = app.crashingReport;
8634 } else if (app.notResponding) {
8635 report = app.notRespondingReport;
8636 }
8637
8638 if (report != null) {
8639 if (errList == null) {
8640 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8641 }
8642 errList.add(report);
8643 } else {
8644 Log.w(TAG, "Missing app error report, app = " + app.processName +
8645 " crashing = " + app.crashing +
8646 " notResponding = " + app.notResponding);
8647 }
8648 }
8649 }
8650 }
8651
8652 return errList;
8653 }
8654
8655 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8656 // Lazy instantiation of list
8657 List<ActivityManager.RunningAppProcessInfo> runList = null;
8658 synchronized (this) {
8659 // Iterate across all processes
8660 final int N = mLRUProcesses.size();
8661 for (int i = 0; i < N; i++) {
8662 ProcessRecord app = mLRUProcesses.get(i);
8663 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8664 // Generate process state info for running application
8665 ActivityManager.RunningAppProcessInfo currApp =
8666 new ActivityManager.RunningAppProcessInfo(app.processName,
8667 app.pid, app.getPackageList());
8668 int adj = app.curAdj;
8669 if (adj >= CONTENT_PROVIDER_ADJ) {
8670 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8671 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8672 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008673 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8674 } else if (adj >= HOME_APP_ADJ) {
8675 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8676 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008677 } else if (adj >= SECONDARY_SERVER_ADJ) {
8678 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8679 } else if (adj >= VISIBLE_APP_ADJ) {
8680 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8681 } else {
8682 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8683 }
8684 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8685 // + " lru=" + currApp.lru);
8686 if (runList == null) {
8687 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8688 }
8689 runList.add(currApp);
8690 }
8691 }
8692 }
8693 return runList;
8694 }
8695
8696 @Override
8697 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8698 synchronized (this) {
8699 if (checkCallingPermission(android.Manifest.permission.DUMP)
8700 != PackageManager.PERMISSION_GRANTED) {
8701 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8702 + Binder.getCallingPid()
8703 + ", uid=" + Binder.getCallingUid()
8704 + " without permission "
8705 + android.Manifest.permission.DUMP);
8706 return;
8707 }
8708 if (args.length != 0 && "service".equals(args[0])) {
8709 dumpService(fd, pw, args);
8710 return;
8711 }
8712 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008713 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008714 pw.println(" ");
8715 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008716 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008717 if (mWaitingVisibleActivities.size() > 0) {
8718 pw.println(" ");
8719 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008720 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008721 }
8722 if (mStoppingActivities.size() > 0) {
8723 pw.println(" ");
8724 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008725 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008726 }
8727 if (mFinishingActivities.size() > 0) {
8728 pw.println(" ");
8729 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008730 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008731 }
8732
8733 pw.println(" ");
8734 pw.println(" mPausingActivity: " + mPausingActivity);
8735 pw.println(" mResumedActivity: " + mResumedActivity);
8736 pw.println(" mFocusedActivity: " + mFocusedActivity);
8737 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8738
8739 if (mRecentTasks.size() > 0) {
8740 pw.println(" ");
8741 pw.println("Recent tasks in Current Activity Manager State:");
8742
8743 final int N = mRecentTasks.size();
8744 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008745 TaskRecord tr = mRecentTasks.get(i);
8746 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8747 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008748 mRecentTasks.get(i).dump(pw, " ");
8749 }
8750 }
8751
8752 pw.println(" ");
8753 pw.println(" mCurTask: " + mCurTask);
8754
8755 pw.println(" ");
8756 pw.println("Processes in Current Activity Manager State:");
8757
8758 boolean needSep = false;
8759 int numPers = 0;
8760
8761 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8762 final int NA = procs.size();
8763 for (int ia=0; ia<NA; ia++) {
8764 if (!needSep) {
8765 pw.println(" All known processes:");
8766 needSep = true;
8767 }
8768 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008769 pw.print(r.persistent ? " *PERS*" : " *APP*");
8770 pw.print(" UID "); pw.print(procs.keyAt(ia));
8771 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008772 r.dump(pw, " ");
8773 if (r.persistent) {
8774 numPers++;
8775 }
8776 }
8777 }
8778
8779 if (mLRUProcesses.size() > 0) {
8780 if (needSep) pw.println(" ");
8781 needSep = true;
8782 pw.println(" Running processes (most recent first):");
8783 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008784 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008785 needSep = true;
8786 }
8787
8788 synchronized (mPidsSelfLocked) {
8789 if (mPidsSelfLocked.size() > 0) {
8790 if (needSep) pw.println(" ");
8791 needSep = true;
8792 pw.println(" PID mappings:");
8793 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008794 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8795 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008796 }
8797 }
8798 }
8799
8800 if (mForegroundProcesses.size() > 0) {
8801 if (needSep) pw.println(" ");
8802 needSep = true;
8803 pw.println(" Foreground Processes:");
8804 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008805 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8806 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008807 }
8808 }
8809
8810 if (mPersistentStartingProcesses.size() > 0) {
8811 if (needSep) pw.println(" ");
8812 needSep = true;
8813 pw.println(" Persisent processes that are starting:");
8814 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008815 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008816 }
8817
8818 if (mStartingProcesses.size() > 0) {
8819 if (needSep) pw.println(" ");
8820 needSep = true;
8821 pw.println(" Processes that are starting:");
8822 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008823 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008824 }
8825
8826 if (mRemovedProcesses.size() > 0) {
8827 if (needSep) pw.println(" ");
8828 needSep = true;
8829 pw.println(" Processes that are being removed:");
8830 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008831 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008832 }
8833
8834 if (mProcessesOnHold.size() > 0) {
8835 if (needSep) pw.println(" ");
8836 needSep = true;
8837 pw.println(" Processes that are on old until the system is ready:");
8838 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008839 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008840 }
8841
8842 if (mProcessCrashTimes.getMap().size() > 0) {
8843 if (needSep) pw.println(" ");
8844 needSep = true;
8845 pw.println(" Time since processes crashed:");
8846 long now = SystemClock.uptimeMillis();
8847 for (Map.Entry<String, SparseArray<Long>> procs
8848 : mProcessCrashTimes.getMap().entrySet()) {
8849 SparseArray<Long> uids = procs.getValue();
8850 final int N = uids.size();
8851 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008852 pw.print(" Process "); pw.print(procs.getKey());
8853 pw.print(" uid "); pw.print(uids.keyAt(i));
8854 pw.print(": last crashed ");
8855 pw.print((now-uids.valueAt(i)));
8856 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008857 }
8858 }
8859 }
8860
8861 if (mBadProcesses.getMap().size() > 0) {
8862 if (needSep) pw.println(" ");
8863 needSep = true;
8864 pw.println(" Bad processes:");
8865 for (Map.Entry<String, SparseArray<Long>> procs
8866 : mBadProcesses.getMap().entrySet()) {
8867 SparseArray<Long> uids = procs.getValue();
8868 final int N = uids.size();
8869 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008870 pw.print(" Bad process "); pw.print(procs.getKey());
8871 pw.print(" uid "); pw.print(uids.keyAt(i));
8872 pw.print(": crashed at time ");
8873 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008874 }
8875 }
8876 }
8877
8878 pw.println(" ");
8879 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08008880 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008881 pw.println(" mConfiguration: " + mConfiguration);
8882 pw.println(" mStartRunning=" + mStartRunning
8883 + " mSystemReady=" + mSystemReady
8884 + " mBooting=" + mBooting
8885 + " mBooted=" + mBooted
8886 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07008887 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008888 pw.println(" mGoingToSleep=" + mGoingToSleep);
8889 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
8890 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
8891 + " mDebugTransient=" + mDebugTransient
8892 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
8893 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008894 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008895 }
8896 }
8897
8898 /**
8899 * There are three ways to call this:
8900 * - no service specified: dump all the services
8901 * - a flattened component name that matched an existing service was specified as the
8902 * first arg: dump that one service
8903 * - the first arg isn't the flattened component name of an existing service:
8904 * dump all services whose component contains the first arg as a substring
8905 */
8906 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
8907 String[] newArgs;
8908 String componentNameString;
8909 ServiceRecord r;
8910 if (args.length == 1) {
8911 componentNameString = null;
8912 newArgs = EMPTY_STRING_ARRAY;
8913 r = null;
8914 } else {
8915 componentNameString = args[1];
8916 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
8917 r = componentName != null ? mServices.get(componentName) : null;
8918 newArgs = new String[args.length - 2];
8919 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
8920 }
8921
8922 if (r != null) {
8923 dumpService(fd, pw, r, newArgs);
8924 } else {
8925 for (ServiceRecord r1 : mServices.values()) {
8926 if (componentNameString == null
8927 || r1.name.flattenToString().contains(componentNameString)) {
8928 dumpService(fd, pw, r1, newArgs);
8929 }
8930 }
8931 }
8932 }
8933
8934 /**
8935 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
8936 * there is a thread associated with the service.
8937 */
8938 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
8939 pw.println(" Service " + r.name.flattenToString());
8940 if (r.app != null && r.app.thread != null) {
8941 try {
8942 // flush anything that is already in the PrintWriter since the thread is going
8943 // to write to the file descriptor directly
8944 pw.flush();
8945 r.app.thread.dumpService(fd, r, args);
8946 pw.print("\n");
8947 } catch (RemoteException e) {
8948 pw.println("got a RemoteException while dumping the service");
8949 }
8950 }
8951 }
8952
8953 void dumpBroadcasts(PrintWriter pw) {
8954 synchronized (this) {
8955 if (checkCallingPermission(android.Manifest.permission.DUMP)
8956 != PackageManager.PERMISSION_GRANTED) {
8957 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8958 + Binder.getCallingPid()
8959 + ", uid=" + Binder.getCallingUid()
8960 + " without permission "
8961 + android.Manifest.permission.DUMP);
8962 return;
8963 }
8964 pw.println("Broadcasts in Current Activity Manager State:");
8965
8966 if (mRegisteredReceivers.size() > 0) {
8967 pw.println(" ");
8968 pw.println(" Registered Receivers:");
8969 Iterator it = mRegisteredReceivers.values().iterator();
8970 while (it.hasNext()) {
8971 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008972 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008973 r.dump(pw, " ");
8974 }
8975 }
8976
8977 pw.println(" ");
8978 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008979 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008980
8981 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
8982 || mPendingBroadcast != null) {
8983 if (mParallelBroadcasts.size() > 0) {
8984 pw.println(" ");
8985 pw.println(" Active broadcasts:");
8986 }
8987 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
8988 pw.println(" Broadcast #" + i + ":");
8989 mParallelBroadcasts.get(i).dump(pw, " ");
8990 }
8991 if (mOrderedBroadcasts.size() > 0) {
8992 pw.println(" ");
8993 pw.println(" Active serialized broadcasts:");
8994 }
8995 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
8996 pw.println(" Serialized Broadcast #" + i + ":");
8997 mOrderedBroadcasts.get(i).dump(pw, " ");
8998 }
8999 pw.println(" ");
9000 pw.println(" Pending broadcast:");
9001 if (mPendingBroadcast != null) {
9002 mPendingBroadcast.dump(pw, " ");
9003 } else {
9004 pw.println(" (null)");
9005 }
9006 }
9007
9008 pw.println(" ");
9009 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
9010 if (mStickyBroadcasts != null) {
9011 pw.println(" ");
9012 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009013 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009014 for (Map.Entry<String, ArrayList<Intent>> ent
9015 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009016 pw.print(" * Sticky action "); pw.print(ent.getKey());
9017 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009018 ArrayList<Intent> intents = ent.getValue();
9019 final int N = intents.size();
9020 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009021 sb.setLength(0);
9022 sb.append(" Intent: ");
9023 intents.get(i).toShortString(sb, true, false);
9024 pw.println(sb.toString());
9025 Bundle bundle = intents.get(i).getExtras();
9026 if (bundle != null) {
9027 pw.print(" ");
9028 pw.println(bundle.toString());
9029 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009030 }
9031 }
9032 }
9033
9034 pw.println(" ");
9035 pw.println(" mHandler:");
9036 mHandler.dump(new PrintWriterPrinter(pw), " ");
9037 }
9038 }
9039
9040 void dumpServices(PrintWriter pw) {
9041 synchronized (this) {
9042 if (checkCallingPermission(android.Manifest.permission.DUMP)
9043 != PackageManager.PERMISSION_GRANTED) {
9044 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9045 + Binder.getCallingPid()
9046 + ", uid=" + Binder.getCallingUid()
9047 + " without permission "
9048 + android.Manifest.permission.DUMP);
9049 return;
9050 }
9051 pw.println("Services in Current Activity Manager State:");
9052
9053 boolean needSep = false;
9054
9055 if (mServices.size() > 0) {
9056 pw.println(" Active services:");
9057 Iterator<ServiceRecord> it = mServices.values().iterator();
9058 while (it.hasNext()) {
9059 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009060 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009061 r.dump(pw, " ");
9062 }
9063 needSep = true;
9064 }
9065
9066 if (mPendingServices.size() > 0) {
9067 if (needSep) pw.println(" ");
9068 pw.println(" Pending services:");
9069 for (int i=0; i<mPendingServices.size(); i++) {
9070 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009071 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009072 r.dump(pw, " ");
9073 }
9074 needSep = true;
9075 }
9076
9077 if (mRestartingServices.size() > 0) {
9078 if (needSep) pw.println(" ");
9079 pw.println(" Restarting services:");
9080 for (int i=0; i<mRestartingServices.size(); i++) {
9081 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009082 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009083 r.dump(pw, " ");
9084 }
9085 needSep = true;
9086 }
9087
9088 if (mStoppingServices.size() > 0) {
9089 if (needSep) pw.println(" ");
9090 pw.println(" Stopping services:");
9091 for (int i=0; i<mStoppingServices.size(); i++) {
9092 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009093 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009094 r.dump(pw, " ");
9095 }
9096 needSep = true;
9097 }
9098
9099 if (mServiceConnections.size() > 0) {
9100 if (needSep) pw.println(" ");
9101 pw.println(" Connection bindings to services:");
9102 Iterator<ConnectionRecord> it
9103 = mServiceConnections.values().iterator();
9104 while (it.hasNext()) {
9105 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009106 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009107 r.dump(pw, " ");
9108 }
9109 }
9110 }
9111 }
9112
9113 void dumpProviders(PrintWriter pw) {
9114 synchronized (this) {
9115 if (checkCallingPermission(android.Manifest.permission.DUMP)
9116 != PackageManager.PERMISSION_GRANTED) {
9117 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9118 + Binder.getCallingPid()
9119 + ", uid=" + Binder.getCallingUid()
9120 + " without permission "
9121 + android.Manifest.permission.DUMP);
9122 return;
9123 }
9124
9125 pw.println("Content Providers in Current Activity Manager State:");
9126
9127 boolean needSep = false;
9128
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009129 if (mProvidersByClass.size() > 0) {
9130 if (needSep) pw.println(" ");
9131 pw.println(" Published content providers (by class):");
9132 Iterator it = mProvidersByClass.entrySet().iterator();
9133 while (it.hasNext()) {
9134 Map.Entry e = (Map.Entry)it.next();
9135 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009136 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009137 r.dump(pw, " ");
9138 }
9139 needSep = true;
9140 }
9141
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009142 if (mProvidersByName.size() > 0) {
9143 pw.println(" ");
9144 pw.println(" Authority to provider mappings:");
9145 Iterator it = mProvidersByName.entrySet().iterator();
9146 while (it.hasNext()) {
9147 Map.Entry e = (Map.Entry)it.next();
9148 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
9149 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
9150 pw.println(r);
9151 }
9152 needSep = true;
9153 }
9154
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009155 if (mLaunchingProviders.size() > 0) {
9156 if (needSep) pw.println(" ");
9157 pw.println(" Launching content providers:");
9158 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009159 pw.print(" Launching #"); pw.print(i); pw.print(": ");
9160 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009161 }
9162 needSep = true;
9163 }
9164
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009165 if (mGrantedUriPermissions.size() > 0) {
9166 pw.println();
9167 pw.println("Granted Uri Permissions:");
9168 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
9169 int uid = mGrantedUriPermissions.keyAt(i);
9170 HashMap<Uri, UriPermission> perms
9171 = mGrantedUriPermissions.valueAt(i);
9172 pw.print(" * UID "); pw.print(uid);
9173 pw.println(" holds:");
9174 for (UriPermission perm : perms.values()) {
9175 pw.print(" "); pw.println(perm);
9176 perm.dump(pw, " ");
9177 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009178 }
9179 }
9180 }
9181 }
9182
9183 void dumpSenders(PrintWriter pw) {
9184 synchronized (this) {
9185 if (checkCallingPermission(android.Manifest.permission.DUMP)
9186 != PackageManager.PERMISSION_GRANTED) {
9187 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9188 + Binder.getCallingPid()
9189 + ", uid=" + Binder.getCallingUid()
9190 + " without permission "
9191 + android.Manifest.permission.DUMP);
9192 return;
9193 }
9194
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009195 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009196
9197 if (this.mIntentSenderRecords.size() > 0) {
9198 Iterator<WeakReference<PendingIntentRecord>> it
9199 = mIntentSenderRecords.values().iterator();
9200 while (it.hasNext()) {
9201 WeakReference<PendingIntentRecord> ref = it.next();
9202 PendingIntentRecord rec = ref != null ? ref.get(): null;
9203 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009204 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009205 rec.dump(pw, " ");
9206 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009207 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009208 }
9209 }
9210 }
9211 }
9212 }
9213
9214 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009215 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009216 TaskRecord lastTask = null;
9217 for (int i=list.size()-1; i>=0; i--) {
9218 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009219 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009220 if (lastTask != r.task) {
9221 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009222 pw.print(prefix);
9223 pw.print(full ? "* " : " ");
9224 pw.println(lastTask);
9225 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009226 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009227 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009228 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009229 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9230 pw.print(" #"); pw.print(i); pw.print(": ");
9231 pw.println(r);
9232 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009233 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009234 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009235 }
9236 }
9237
9238 private static final int dumpProcessList(PrintWriter pw, List list,
9239 String prefix, String normalLabel, String persistentLabel,
9240 boolean inclOomAdj) {
9241 int numPers = 0;
9242 for (int i=list.size()-1; i>=0; i--) {
9243 ProcessRecord r = (ProcessRecord)list.get(i);
9244 if (false) {
9245 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9246 + " #" + i + ":");
9247 r.dump(pw, prefix + " ");
9248 } else if (inclOomAdj) {
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009249 pw.println(String.format("%s%s #%2d: adj=%4d/%d %s (%s)",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009250 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009251 i, r.setAdj, r.setSchedGroup, r.toString(), r.adjType));
9252 if (r.adjSource != null || r.adjTarget != null) {
9253 pw.println(prefix + " " + r.adjTarget
9254 + " used by " + r.adjSource);
9255 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009256 } else {
9257 pw.println(String.format("%s%s #%2d: %s",
9258 prefix, (r.persistent ? persistentLabel : normalLabel),
9259 i, r.toString()));
9260 }
9261 if (r.persistent) {
9262 numPers++;
9263 }
9264 }
9265 return numPers;
9266 }
9267
9268 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9269 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009270 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009271 long uptime = SystemClock.uptimeMillis();
9272 long realtime = SystemClock.elapsedRealtime();
9273
9274 if (isCheckinRequest) {
9275 // short checkin version
9276 pw.println(uptime + "," + realtime);
9277 pw.flush();
9278 } else {
9279 pw.println("Applications Memory Usage (kB):");
9280 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9281 }
9282 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9283 ProcessRecord r = (ProcessRecord)list.get(i);
9284 if (r.thread != null) {
9285 if (!isCheckinRequest) {
9286 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9287 pw.flush();
9288 }
9289 try {
9290 r.thread.asBinder().dump(fd, args);
9291 } catch (RemoteException e) {
9292 if (!isCheckinRequest) {
9293 pw.println("Got RemoteException!");
9294 pw.flush();
9295 }
9296 }
9297 }
9298 }
9299 }
9300
9301 /**
9302 * Searches array of arguments for the specified string
9303 * @param args array of argument strings
9304 * @param value value to search for
9305 * @return true if the value is contained in the array
9306 */
9307 private static boolean scanArgs(String[] args, String value) {
9308 if (args != null) {
9309 for (String arg : args) {
9310 if (value.equals(arg)) {
9311 return true;
9312 }
9313 }
9314 }
9315 return false;
9316 }
9317
Dianne Hackborn75b03852009-06-12 15:43:26 -07009318 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009319 int count = mHistory.size();
9320
9321 // convert the token to an entry in the history.
9322 HistoryRecord r = null;
9323 int index = -1;
9324 for (int i=count-1; i>=0; i--) {
9325 Object o = mHistory.get(i);
9326 if (o == token) {
9327 r = (HistoryRecord)o;
9328 index = i;
9329 break;
9330 }
9331 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009332
9333 return index;
9334 }
9335
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009336 private final void killServicesLocked(ProcessRecord app,
9337 boolean allowRestart) {
9338 // Report disconnected services.
9339 if (false) {
9340 // XXX we are letting the client link to the service for
9341 // death notifications.
9342 if (app.services.size() > 0) {
9343 Iterator it = app.services.iterator();
9344 while (it.hasNext()) {
9345 ServiceRecord r = (ServiceRecord)it.next();
9346 if (r.connections.size() > 0) {
9347 Iterator<ConnectionRecord> jt
9348 = r.connections.values().iterator();
9349 while (jt.hasNext()) {
9350 ConnectionRecord c = jt.next();
9351 if (c.binding.client != app) {
9352 try {
9353 //c.conn.connected(r.className, null);
9354 } catch (Exception e) {
9355 // todo: this should be asynchronous!
9356 Log.w(TAG, "Exception thrown disconnected servce "
9357 + r.shortName
9358 + " from app " + app.processName, e);
9359 }
9360 }
9361 }
9362 }
9363 }
9364 }
9365 }
9366
9367 // Clean up any connections this application has to other services.
9368 if (app.connections.size() > 0) {
9369 Iterator<ConnectionRecord> it = app.connections.iterator();
9370 while (it.hasNext()) {
9371 ConnectionRecord r = it.next();
9372 removeConnectionLocked(r, app, null);
9373 }
9374 }
9375 app.connections.clear();
9376
9377 if (app.services.size() != 0) {
9378 // Any services running in the application need to be placed
9379 // back in the pending list.
9380 Iterator it = app.services.iterator();
9381 while (it.hasNext()) {
9382 ServiceRecord sr = (ServiceRecord)it.next();
9383 synchronized (sr.stats.getBatteryStats()) {
9384 sr.stats.stopLaunchedLocked();
9385 }
9386 sr.app = null;
9387 sr.executeNesting = 0;
9388 mStoppingServices.remove(sr);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009389
9390 boolean hasClients = sr.bindings.size() > 0;
9391 if (hasClients) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009392 Iterator<IntentBindRecord> bindings
9393 = sr.bindings.values().iterator();
9394 while (bindings.hasNext()) {
9395 IntentBindRecord b = bindings.next();
9396 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9397 + ": shouldUnbind=" + b.hasBound);
9398 b.binder = null;
9399 b.requested = b.received = b.hasBound = false;
9400 }
9401 }
9402
9403 if (sr.crashCount >= 2) {
9404 Log.w(TAG, "Service crashed " + sr.crashCount
9405 + " times, stopping: " + sr);
9406 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9407 sr.crashCount, sr.shortName, app.pid);
9408 bringDownServiceLocked(sr, true);
9409 } else if (!allowRestart) {
9410 bringDownServiceLocked(sr, true);
9411 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009412 boolean canceled = scheduleServiceRestartLocked(sr, true);
9413
9414 // Should the service remain running? Note that in the
9415 // extreme case of so many attempts to deliver a command
9416 // that it failed, that we also will stop it here.
9417 if (sr.startRequested && (sr.stopIfKilled || canceled)) {
9418 if (sr.pendingStarts.size() == 0) {
9419 sr.startRequested = false;
9420 if (!hasClients) {
9421 // Whoops, no reason to restart!
9422 bringDownServiceLocked(sr, true);
9423 }
9424 }
9425 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009426 }
9427 }
9428
9429 if (!allowRestart) {
9430 app.services.clear();
9431 }
9432 }
9433
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009434 // Make sure we have no more records on the stopping list.
9435 int i = mStoppingServices.size();
9436 while (i > 0) {
9437 i--;
9438 ServiceRecord sr = mStoppingServices.get(i);
9439 if (sr.app == app) {
9440 mStoppingServices.remove(i);
9441 }
9442 }
9443
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009444 app.executingServices.clear();
9445 }
9446
9447 private final void removeDyingProviderLocked(ProcessRecord proc,
9448 ContentProviderRecord cpr) {
9449 synchronized (cpr) {
9450 cpr.launchingApp = null;
9451 cpr.notifyAll();
9452 }
9453
9454 mProvidersByClass.remove(cpr.info.name);
9455 String names[] = cpr.info.authority.split(";");
9456 for (int j = 0; j < names.length; j++) {
9457 mProvidersByName.remove(names[j]);
9458 }
9459
9460 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9461 while (cit.hasNext()) {
9462 ProcessRecord capp = cit.next();
9463 if (!capp.persistent && capp.thread != null
9464 && capp.pid != 0
9465 && capp.pid != MY_PID) {
9466 Log.i(TAG, "Killing app " + capp.processName
9467 + " (pid " + capp.pid
9468 + ") because provider " + cpr.info.name
9469 + " is in dying process " + proc.processName);
9470 Process.killProcess(capp.pid);
9471 }
9472 }
9473
9474 mLaunchingProviders.remove(cpr);
9475 }
9476
9477 /**
9478 * Main code for cleaning up a process when it has gone away. This is
9479 * called both as a result of the process dying, or directly when stopping
9480 * a process when running in single process mode.
9481 */
9482 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9483 boolean restarting, int index) {
9484 if (index >= 0) {
9485 mLRUProcesses.remove(index);
9486 }
9487
9488 // Dismiss any open dialogs.
9489 if (app.crashDialog != null) {
9490 app.crashDialog.dismiss();
9491 app.crashDialog = null;
9492 }
9493 if (app.anrDialog != null) {
9494 app.anrDialog.dismiss();
9495 app.anrDialog = null;
9496 }
9497 if (app.waitDialog != null) {
9498 app.waitDialog.dismiss();
9499 app.waitDialog = null;
9500 }
9501
9502 app.crashing = false;
9503 app.notResponding = false;
9504
9505 app.resetPackageList();
9506 app.thread = null;
9507 app.forcingToForeground = null;
9508 app.foregroundServices = false;
9509
9510 killServicesLocked(app, true);
9511
9512 boolean restart = false;
9513
9514 int NL = mLaunchingProviders.size();
9515
9516 // Remove published content providers.
9517 if (!app.pubProviders.isEmpty()) {
9518 Iterator it = app.pubProviders.values().iterator();
9519 while (it.hasNext()) {
9520 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9521 cpr.provider = null;
9522 cpr.app = null;
9523
9524 // See if someone is waiting for this provider... in which
9525 // case we don't remove it, but just let it restart.
9526 int i = 0;
9527 if (!app.bad) {
9528 for (; i<NL; i++) {
9529 if (mLaunchingProviders.get(i) == cpr) {
9530 restart = true;
9531 break;
9532 }
9533 }
9534 } else {
9535 i = NL;
9536 }
9537
9538 if (i >= NL) {
9539 removeDyingProviderLocked(app, cpr);
9540 NL = mLaunchingProviders.size();
9541 }
9542 }
9543 app.pubProviders.clear();
9544 }
9545
9546 // Look through the content providers we are waiting to have launched,
9547 // and if any run in this process then either schedule a restart of
9548 // the process or kill the client waiting for it if this process has
9549 // gone bad.
9550 for (int i=0; i<NL; i++) {
9551 ContentProviderRecord cpr = (ContentProviderRecord)
9552 mLaunchingProviders.get(i);
9553 if (cpr.launchingApp == app) {
9554 if (!app.bad) {
9555 restart = true;
9556 } else {
9557 removeDyingProviderLocked(app, cpr);
9558 NL = mLaunchingProviders.size();
9559 }
9560 }
9561 }
9562
9563 // Unregister from connected content providers.
9564 if (!app.conProviders.isEmpty()) {
9565 Iterator it = app.conProviders.iterator();
9566 while (it.hasNext()) {
9567 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9568 cpr.clients.remove(app);
9569 }
9570 app.conProviders.clear();
9571 }
9572
Dianne Hackbornde42bb62009-08-05 12:26:15 -07009573 // At this point there may be remaining entries in mLaunchingProviders
9574 // where we were the only one waiting, so they are no longer of use.
9575 // Look for these and clean up if found.
9576 // XXX Commented out for now. Trying to figure out a way to reproduce
9577 // the actual situation to identify what is actually going on.
9578 if (false) {
9579 for (int i=0; i<NL; i++) {
9580 ContentProviderRecord cpr = (ContentProviderRecord)
9581 mLaunchingProviders.get(i);
9582 if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
9583 synchronized (cpr) {
9584 cpr.launchingApp = null;
9585 cpr.notifyAll();
9586 }
9587 }
9588 }
9589 }
9590
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009591 skipCurrentReceiverLocked(app);
9592
9593 // Unregister any receivers.
9594 if (app.receivers.size() > 0) {
9595 Iterator<ReceiverList> it = app.receivers.iterator();
9596 while (it.hasNext()) {
9597 removeReceiverLocked(it.next());
9598 }
9599 app.receivers.clear();
9600 }
9601
Christopher Tate181fafa2009-05-14 11:12:14 -07009602 // If the app is undergoing backup, tell the backup manager about it
9603 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9604 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9605 try {
9606 IBackupManager bm = IBackupManager.Stub.asInterface(
9607 ServiceManager.getService(Context.BACKUP_SERVICE));
9608 bm.agentDisconnected(app.info.packageName);
9609 } catch (RemoteException e) {
9610 // can't happen; backup manager is local
9611 }
9612 }
9613
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009614 // If the caller is restarting this app, then leave it in its
9615 // current lists and let the caller take care of it.
9616 if (restarting) {
9617 return;
9618 }
9619
9620 if (!app.persistent) {
9621 if (DEBUG_PROCESSES) Log.v(TAG,
9622 "Removing non-persistent process during cleanup: " + app);
9623 mProcessNames.remove(app.processName, app.info.uid);
9624 } else if (!app.removed) {
9625 // This app is persistent, so we need to keep its record around.
9626 // If it is not already on the pending app list, add it there
9627 // and start a new process for it.
9628 app.thread = null;
9629 app.forcingToForeground = null;
9630 app.foregroundServices = false;
9631 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9632 mPersistentStartingProcesses.add(app);
9633 restart = true;
9634 }
9635 }
9636 mProcessesOnHold.remove(app);
9637
The Android Open Source Project4df24232009-03-05 14:34:35 -08009638 if (app == mHomeProcess) {
9639 mHomeProcess = null;
9640 }
9641
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009642 if (restart) {
9643 // We have components that still need to be running in the
9644 // process, so re-launch it.
9645 mProcessNames.put(app.processName, app.info.uid, app);
9646 startProcessLocked(app, "restart", app.processName);
9647 } else if (app.pid > 0 && app.pid != MY_PID) {
9648 // Goodbye!
9649 synchronized (mPidsSelfLocked) {
9650 mPidsSelfLocked.remove(app.pid);
9651 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9652 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009653 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009654 }
9655 }
9656
9657 // =========================================================
9658 // SERVICES
9659 // =========================================================
9660
9661 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9662 ActivityManager.RunningServiceInfo info =
9663 new ActivityManager.RunningServiceInfo();
9664 info.service = r.name;
9665 if (r.app != null) {
9666 info.pid = r.app.pid;
9667 }
9668 info.process = r.processName;
9669 info.foreground = r.isForeground;
9670 info.activeSince = r.createTime;
9671 info.started = r.startRequested;
9672 info.clientCount = r.connections.size();
9673 info.crashCount = r.crashCount;
9674 info.lastActivityTime = r.lastActivity;
9675 return info;
9676 }
9677
9678 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9679 int flags) {
9680 synchronized (this) {
9681 ArrayList<ActivityManager.RunningServiceInfo> res
9682 = new ArrayList<ActivityManager.RunningServiceInfo>();
9683
9684 if (mServices.size() > 0) {
9685 Iterator<ServiceRecord> it = mServices.values().iterator();
9686 while (it.hasNext() && res.size() < maxNum) {
9687 res.add(makeRunningServiceInfoLocked(it.next()));
9688 }
9689 }
9690
9691 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9692 ServiceRecord r = mRestartingServices.get(i);
9693 ActivityManager.RunningServiceInfo info =
9694 makeRunningServiceInfoLocked(r);
9695 info.restarting = r.nextRestartTime;
9696 res.add(info);
9697 }
9698
9699 return res;
9700 }
9701 }
9702
9703 private final ServiceRecord findServiceLocked(ComponentName name,
9704 IBinder token) {
9705 ServiceRecord r = mServices.get(name);
9706 return r == token ? r : null;
9707 }
9708
9709 private final class ServiceLookupResult {
9710 final ServiceRecord record;
9711 final String permission;
9712
9713 ServiceLookupResult(ServiceRecord _record, String _permission) {
9714 record = _record;
9715 permission = _permission;
9716 }
9717 };
9718
9719 private ServiceLookupResult findServiceLocked(Intent service,
9720 String resolvedType) {
9721 ServiceRecord r = null;
9722 if (service.getComponent() != null) {
9723 r = mServices.get(service.getComponent());
9724 }
9725 if (r == null) {
9726 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9727 r = mServicesByIntent.get(filter);
9728 }
9729
9730 if (r == null) {
9731 try {
9732 ResolveInfo rInfo =
9733 ActivityThread.getPackageManager().resolveService(
9734 service, resolvedType, 0);
9735 ServiceInfo sInfo =
9736 rInfo != null ? rInfo.serviceInfo : null;
9737 if (sInfo == null) {
9738 return null;
9739 }
9740
9741 ComponentName name = new ComponentName(
9742 sInfo.applicationInfo.packageName, sInfo.name);
9743 r = mServices.get(name);
9744 } catch (RemoteException ex) {
9745 // pm is in same process, this will never happen.
9746 }
9747 }
9748 if (r != null) {
9749 int callingPid = Binder.getCallingPid();
9750 int callingUid = Binder.getCallingUid();
9751 if (checkComponentPermission(r.permission,
9752 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9753 != PackageManager.PERMISSION_GRANTED) {
9754 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9755 + " from pid=" + callingPid
9756 + ", uid=" + callingUid
9757 + " requires " + r.permission);
9758 return new ServiceLookupResult(null, r.permission);
9759 }
9760 return new ServiceLookupResult(r, null);
9761 }
9762 return null;
9763 }
9764
9765 private class ServiceRestarter implements Runnable {
9766 private ServiceRecord mService;
9767
9768 void setService(ServiceRecord service) {
9769 mService = service;
9770 }
9771
9772 public void run() {
9773 synchronized(ActivityManagerService.this) {
9774 performServiceRestartLocked(mService);
9775 }
9776 }
9777 }
9778
9779 private ServiceLookupResult retrieveServiceLocked(Intent service,
9780 String resolvedType, int callingPid, int callingUid) {
9781 ServiceRecord r = null;
9782 if (service.getComponent() != null) {
9783 r = mServices.get(service.getComponent());
9784 }
9785 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9786 r = mServicesByIntent.get(filter);
9787 if (r == null) {
9788 try {
9789 ResolveInfo rInfo =
9790 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009791 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009792 ServiceInfo sInfo =
9793 rInfo != null ? rInfo.serviceInfo : null;
9794 if (sInfo == null) {
9795 Log.w(TAG, "Unable to start service " + service +
9796 ": not found");
9797 return null;
9798 }
9799
9800 ComponentName name = new ComponentName(
9801 sInfo.applicationInfo.packageName, sInfo.name);
9802 r = mServices.get(name);
9803 if (r == null) {
9804 filter = new Intent.FilterComparison(service.cloneFilter());
9805 ServiceRestarter res = new ServiceRestarter();
9806 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9807 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9808 synchronized (stats) {
9809 ss = stats.getServiceStatsLocked(
9810 sInfo.applicationInfo.uid, sInfo.packageName,
9811 sInfo.name);
9812 }
9813 r = new ServiceRecord(ss, name, filter, sInfo, res);
9814 res.setService(r);
9815 mServices.put(name, r);
9816 mServicesByIntent.put(filter, r);
9817
9818 // Make sure this component isn't in the pending list.
9819 int N = mPendingServices.size();
9820 for (int i=0; i<N; i++) {
9821 ServiceRecord pr = mPendingServices.get(i);
9822 if (pr.name.equals(name)) {
9823 mPendingServices.remove(i);
9824 i--;
9825 N--;
9826 }
9827 }
9828 }
9829 } catch (RemoteException ex) {
9830 // pm is in same process, this will never happen.
9831 }
9832 }
9833 if (r != null) {
9834 if (checkComponentPermission(r.permission,
9835 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9836 != PackageManager.PERMISSION_GRANTED) {
9837 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9838 + " from pid=" + Binder.getCallingPid()
9839 + ", uid=" + Binder.getCallingUid()
9840 + " requires " + r.permission);
9841 return new ServiceLookupResult(null, r.permission);
9842 }
9843 return new ServiceLookupResult(r, null);
9844 }
9845 return null;
9846 }
9847
9848 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9849 long now = SystemClock.uptimeMillis();
9850 if (r.executeNesting == 0 && r.app != null) {
9851 if (r.app.executingServices.size() == 0) {
9852 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9853 msg.obj = r.app;
9854 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9855 }
9856 r.app.executingServices.add(r);
9857 }
9858 r.executeNesting++;
9859 r.executingStart = now;
9860 }
9861
9862 private final void sendServiceArgsLocked(ServiceRecord r,
9863 boolean oomAdjusted) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009864 final int N = r.pendingStarts.size();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009865 if (N == 0) {
9866 return;
9867 }
9868
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009869 int i = 0;
9870 while (i < N) {
9871 try {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009872 ServiceRecord.StartItem si = r.pendingStarts.get(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009873 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009874 + r.name + " " + r.intent + " args=" + si.intent);
9875 if (si.intent == null && N > 0) {
9876 // If somehow we got a dummy start at the front, then
9877 // just drop it here.
9878 i++;
9879 continue;
9880 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009881 bumpServiceExecutingLocked(r);
9882 if (!oomAdjusted) {
9883 oomAdjusted = true;
9884 updateOomAdjLocked(r.app);
9885 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009886 int flags = 0;
9887 if (si.deliveryCount > 0) {
9888 flags |= Service.START_FLAG_RETRY;
9889 }
9890 if (si.doneExecutingCount > 0) {
9891 flags |= Service.START_FLAG_REDELIVERY;
9892 }
9893 r.app.thread.scheduleServiceArgs(r, si.id, flags, si.intent);
9894 si.deliveredTime = SystemClock.uptimeMillis();
9895 r.deliveredStarts.add(si);
9896 si.deliveryCount++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009897 i++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009898 } catch (RemoteException e) {
9899 // Remote process gone... we'll let the normal cleanup take
9900 // care of this.
9901 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009902 } catch (Exception e) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009903 Log.w(TAG, "Unexpected exception", e);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009904 break;
9905 }
9906 }
9907 if (i == N) {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009908 r.pendingStarts.clear();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009909 } else {
9910 while (i > 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009911 i--;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009912 r.pendingStarts.remove(i);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009913 }
9914 }
9915 }
9916
9917 private final boolean requestServiceBindingLocked(ServiceRecord r,
9918 IntentBindRecord i, boolean rebind) {
9919 if (r.app == null || r.app.thread == null) {
9920 // If service is not currently running, can't yet bind.
9921 return false;
9922 }
9923 if ((!i.requested || rebind) && i.apps.size() > 0) {
9924 try {
9925 bumpServiceExecutingLocked(r);
9926 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
9927 + ": shouldUnbind=" + i.hasBound);
9928 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
9929 if (!rebind) {
9930 i.requested = true;
9931 }
9932 i.hasBound = true;
9933 i.doRebind = false;
9934 } catch (RemoteException e) {
9935 return false;
9936 }
9937 }
9938 return true;
9939 }
9940
9941 private final void requestServiceBindingsLocked(ServiceRecord r) {
9942 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
9943 while (bindings.hasNext()) {
9944 IntentBindRecord i = bindings.next();
9945 if (!requestServiceBindingLocked(r, i, false)) {
9946 break;
9947 }
9948 }
9949 }
9950
9951 private final void realStartServiceLocked(ServiceRecord r,
9952 ProcessRecord app) throws RemoteException {
9953 if (app.thread == null) {
9954 throw new RemoteException();
9955 }
9956
9957 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -07009958 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009959
9960 app.services.add(r);
9961 bumpServiceExecutingLocked(r);
9962 updateLRUListLocked(app, true);
9963
9964 boolean created = false;
9965 try {
9966 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
9967 + r.name + " " + r.intent);
9968 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
9969 System.identityHashCode(r), r.shortName,
9970 r.intent.getIntent().toString(), r.app.pid);
9971 synchronized (r.stats.getBatteryStats()) {
9972 r.stats.startLaunchedLocked();
9973 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07009974 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009975 app.thread.scheduleCreateService(r, r.serviceInfo);
Dianne Hackbornd8a43f62009-08-17 23:33:56 -07009976 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009977 created = true;
9978 } finally {
9979 if (!created) {
9980 app.services.remove(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009981 scheduleServiceRestartLocked(r, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009982 }
9983 }
9984
9985 requestServiceBindingsLocked(r);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -07009986
9987 // If the service is in the started state, and there are no
9988 // pending arguments, then fake up one so its onStartCommand() will
9989 // be called.
9990 if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
9991 r.lastStartId++;
9992 if (r.lastStartId < 1) {
9993 r.lastStartId = 1;
9994 }
9995 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, null));
9996 }
9997
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009998 sendServiceArgsLocked(r, true);
9999 }
10000
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010001 private final boolean scheduleServiceRestartLocked(ServiceRecord r,
10002 boolean allowCancel) {
10003 boolean canceled = false;
10004
10005 long minDuration = SERVICE_RESTART_DURATION;
10006 long resetTime = minDuration*2*2*2;
10007
10008 // Any delivered but not yet finished starts should be put back
10009 // on the pending list.
10010 final int N = r.deliveredStarts.size();
10011 if (N > 0) {
10012 for (int i=N-1; i>=0; i--) {
10013 ServiceRecord.StartItem si = r.deliveredStarts.get(i);
10014 if (si.intent == null) {
10015 // We'll generate this again if needed.
10016 } else if (!allowCancel || (si.deliveryCount < ServiceRecord.MAX_DELIVERY_COUNT
10017 && si.doneExecutingCount < ServiceRecord.MAX_DONE_EXECUTING_COUNT)) {
10018 r.pendingStarts.add(0, si);
10019 long dur = SystemClock.uptimeMillis() - si.deliveredTime;
10020 dur *= 2;
10021 if (minDuration < dur) minDuration = dur;
10022 if (resetTime < dur) resetTime = dur;
10023 } else {
10024 Log.w(TAG, "Canceling start item " + si.intent + " in service "
10025 + r.name);
10026 canceled = true;
10027 }
10028 }
10029 r.deliveredStarts.clear();
10030 }
10031
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010032 r.totalRestartCount++;
10033 if (r.restartDelay == 0) {
10034 r.restartCount++;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010035 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010036 } else {
10037 // If it has been a "reasonably long time" since the service
10038 // was started, then reset our restart duration back to
10039 // the beginning, so we don't infinitely increase the duration
10040 // on a service that just occasionally gets killed (which is
10041 // a normal case, due to process being killed to reclaim memory).
10042 long now = SystemClock.uptimeMillis();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010043 if (now > (r.restartTime+resetTime)) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010044 r.restartCount = 1;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010045 r.restartDelay = minDuration;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010046 } else {
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010047 r.restartDelay *= 4;
10048 if (r.restartDelay < minDuration) {
10049 r.restartDelay = minDuration;
10050 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010051 }
10052 }
10053 if (!mRestartingServices.contains(r)) {
10054 mRestartingServices.add(r);
10055 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010056 r.cancelNotification();
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010057
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010058 mHandler.removeCallbacks(r.restarter);
10059 mHandler.postDelayed(r.restarter, r.restartDelay);
10060 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
10061 Log.w(TAG, "Scheduling restart of crashed service "
10062 + r.shortName + " in " + r.restartDelay + "ms");
10063 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
10064 r.shortName, r.restartDelay);
10065
10066 Message msg = Message.obtain();
10067 msg.what = SERVICE_ERROR_MSG;
10068 msg.obj = r;
10069 mHandler.sendMessage(msg);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010070
10071 return canceled;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010072 }
10073
10074 final void performServiceRestartLocked(ServiceRecord r) {
10075 if (!mRestartingServices.contains(r)) {
10076 return;
10077 }
10078 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
10079 }
10080
10081 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
10082 if (r.restartDelay == 0) {
10083 return false;
10084 }
10085 r.resetRestartCounter();
10086 mRestartingServices.remove(r);
10087 mHandler.removeCallbacks(r.restarter);
10088 return true;
10089 }
10090
10091 private final boolean bringUpServiceLocked(ServiceRecord r,
10092 int intentFlags, boolean whileRestarting) {
10093 //Log.i(TAG, "Bring up service:");
10094 //r.dump(" ");
10095
10096 if (r.app != null) {
10097 sendServiceArgsLocked(r, false);
10098 return true;
10099 }
10100
10101 if (!whileRestarting && r.restartDelay > 0) {
10102 // If waiting for a restart, then do nothing.
10103 return true;
10104 }
10105
10106 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
10107 + " " + r.intent);
10108
Dianne Hackbornde42bb62009-08-05 12:26:15 -070010109 // We are now bringing the service up, so no longer in the
10110 // restarting state.
10111 mRestartingServices.remove(r);
10112
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010113 final String appName = r.processName;
10114 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
10115 if (app != null && app.thread != null) {
10116 try {
10117 realStartServiceLocked(r, app);
10118 return true;
10119 } catch (RemoteException e) {
10120 Log.w(TAG, "Exception when starting service " + r.shortName, e);
10121 }
10122
10123 // If a dead object exception was thrown -- fall through to
10124 // restart the application.
10125 }
10126
10127 if (!mPendingServices.contains(r)) {
10128 // Not running -- get it started, and enqueue this service record
10129 // to be executed when the app comes up.
10130 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
10131 "service", r.name) == null) {
10132 Log.w(TAG, "Unable to launch app "
10133 + r.appInfo.packageName + "/"
10134 + r.appInfo.uid + " for service "
10135 + r.intent.getIntent() + ": process is bad");
10136 bringDownServiceLocked(r, true);
10137 return false;
10138 }
10139 mPendingServices.add(r);
10140 }
10141 return true;
10142 }
10143
10144 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
10145 //Log.i(TAG, "Bring down service:");
10146 //r.dump(" ");
10147
10148 // Does it still need to run?
10149 if (!force && r.startRequested) {
10150 return;
10151 }
10152 if (r.connections.size() > 0) {
10153 if (!force) {
10154 // XXX should probably keep a count of the number of auto-create
10155 // connections directly in the service.
10156 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10157 while (it.hasNext()) {
10158 ConnectionRecord cr = it.next();
10159 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
10160 return;
10161 }
10162 }
10163 }
10164
10165 // Report to all of the connections that the service is no longer
10166 // available.
10167 Iterator<ConnectionRecord> it = r.connections.values().iterator();
10168 while (it.hasNext()) {
10169 ConnectionRecord c = it.next();
10170 try {
10171 // todo: shouldn't be a synchronous call!
10172 c.conn.connected(r.name, null);
10173 } catch (Exception e) {
10174 Log.w(TAG, "Failure disconnecting service " + r.name +
10175 " to connection " + c.conn.asBinder() +
10176 " (in " + c.binding.client.processName + ")", e);
10177 }
10178 }
10179 }
10180
10181 // Tell the service that it has been unbound.
10182 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
10183 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
10184 while (it.hasNext()) {
10185 IntentBindRecord ibr = it.next();
10186 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
10187 + ": hasBound=" + ibr.hasBound);
10188 if (r.app != null && r.app.thread != null && ibr.hasBound) {
10189 try {
10190 bumpServiceExecutingLocked(r);
10191 updateOomAdjLocked(r.app);
10192 ibr.hasBound = false;
10193 r.app.thread.scheduleUnbindService(r,
10194 ibr.intent.getIntent());
10195 } catch (Exception e) {
10196 Log.w(TAG, "Exception when unbinding service "
10197 + r.shortName, e);
10198 serviceDoneExecutingLocked(r, true);
10199 }
10200 }
10201 }
10202 }
10203
10204 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
10205 + " " + r.intent);
10206 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
10207 System.identityHashCode(r), r.shortName,
10208 (r.app != null) ? r.app.pid : -1);
10209
10210 mServices.remove(r.name);
10211 mServicesByIntent.remove(r.intent);
10212 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
10213 r.totalRestartCount = 0;
10214 unscheduleServiceRestartLocked(r);
10215
10216 // Also make sure it is not on the pending list.
10217 int N = mPendingServices.size();
10218 for (int i=0; i<N; i++) {
10219 if (mPendingServices.get(i) == r) {
10220 mPendingServices.remove(i);
10221 if (DEBUG_SERVICE) Log.v(
10222 TAG, "Removed pending service: " + r.shortName);
10223 i--;
10224 N--;
10225 }
10226 }
10227
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010228 r.cancelNotification();
10229 r.isForeground = false;
10230 r.foregroundId = 0;
10231 r.foregroundNoti = null;
10232
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010233 // Clear start entries.
10234 r.deliveredStarts.clear();
10235 r.pendingStarts.clear();
10236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010237 if (r.app != null) {
10238 synchronized (r.stats.getBatteryStats()) {
10239 r.stats.stopLaunchedLocked();
10240 }
10241 r.app.services.remove(r);
10242 if (r.app.thread != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010243 try {
10244 Log.i(TAG, "Stopping service: " + r.shortName);
10245 bumpServiceExecutingLocked(r);
10246 mStoppingServices.add(r);
10247 updateOomAdjLocked(r.app);
10248 r.app.thread.scheduleStopService(r);
10249 } catch (Exception e) {
10250 Log.w(TAG, "Exception when stopping service "
10251 + r.shortName, e);
10252 serviceDoneExecutingLocked(r, true);
10253 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010254 updateServiceForegroundLocked(r.app, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010255 } else {
10256 if (DEBUG_SERVICE) Log.v(
10257 TAG, "Removed service that has no process: " + r.shortName);
10258 }
10259 } else {
10260 if (DEBUG_SERVICE) Log.v(
10261 TAG, "Removed service that is not running: " + r.shortName);
10262 }
10263 }
10264
10265 ComponentName startServiceLocked(IApplicationThread caller,
10266 Intent service, String resolvedType,
10267 int callingPid, int callingUid) {
10268 synchronized(this) {
10269 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
10270 + " type=" + resolvedType + " args=" + service.getExtras());
10271
10272 if (caller != null) {
10273 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10274 if (callerApp == null) {
10275 throw new SecurityException(
10276 "Unable to find app for caller " + caller
10277 + " (pid=" + Binder.getCallingPid()
10278 + ") when starting service " + service);
10279 }
10280 }
10281
10282 ServiceLookupResult res =
10283 retrieveServiceLocked(service, resolvedType,
10284 callingPid, callingUid);
10285 if (res == null) {
10286 return null;
10287 }
10288 if (res.record == null) {
10289 return new ComponentName("!", res.permission != null
10290 ? res.permission : "private to package");
10291 }
10292 ServiceRecord r = res.record;
10293 if (unscheduleServiceRestartLocked(r)) {
10294 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
10295 + r.shortName);
10296 }
10297 r.startRequested = true;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010298 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010299 r.lastStartId++;
10300 if (r.lastStartId < 1) {
10301 r.lastStartId = 1;
10302 }
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010303 r.pendingStarts.add(new ServiceRecord.StartItem(r.lastStartId, service));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010304 r.lastActivity = SystemClock.uptimeMillis();
10305 synchronized (r.stats.getBatteryStats()) {
10306 r.stats.startRunningLocked();
10307 }
10308 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10309 return new ComponentName("!", "Service process is bad");
10310 }
10311 return r.name;
10312 }
10313 }
10314
10315 public ComponentName startService(IApplicationThread caller, Intent service,
10316 String resolvedType) {
10317 // Refuse possible leaked file descriptors
10318 if (service != null && service.hasFileDescriptors() == true) {
10319 throw new IllegalArgumentException("File descriptors passed in Intent");
10320 }
10321
10322 synchronized(this) {
10323 final int callingPid = Binder.getCallingPid();
10324 final int callingUid = Binder.getCallingUid();
10325 final long origId = Binder.clearCallingIdentity();
10326 ComponentName res = startServiceLocked(caller, service,
10327 resolvedType, callingPid, callingUid);
10328 Binder.restoreCallingIdentity(origId);
10329 return res;
10330 }
10331 }
10332
10333 ComponentName startServiceInPackage(int uid,
10334 Intent service, String resolvedType) {
10335 synchronized(this) {
10336 final long origId = Binder.clearCallingIdentity();
10337 ComponentName res = startServiceLocked(null, service,
10338 resolvedType, -1, uid);
10339 Binder.restoreCallingIdentity(origId);
10340 return res;
10341 }
10342 }
10343
10344 public int stopService(IApplicationThread caller, Intent service,
10345 String resolvedType) {
10346 // Refuse possible leaked file descriptors
10347 if (service != null && service.hasFileDescriptors() == true) {
10348 throw new IllegalArgumentException("File descriptors passed in Intent");
10349 }
10350
10351 synchronized(this) {
10352 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10353 + " type=" + resolvedType);
10354
10355 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10356 if (caller != null && callerApp == null) {
10357 throw new SecurityException(
10358 "Unable to find app for caller " + caller
10359 + " (pid=" + Binder.getCallingPid()
10360 + ") when stopping service " + service);
10361 }
10362
10363 // If this service is active, make sure it is stopped.
10364 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10365 if (r != null) {
10366 if (r.record != null) {
10367 synchronized (r.record.stats.getBatteryStats()) {
10368 r.record.stats.stopRunningLocked();
10369 }
10370 r.record.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010371 r.record.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010372 final long origId = Binder.clearCallingIdentity();
10373 bringDownServiceLocked(r.record, false);
10374 Binder.restoreCallingIdentity(origId);
10375 return 1;
10376 }
10377 return -1;
10378 }
10379 }
10380
10381 return 0;
10382 }
10383
10384 public IBinder peekService(Intent service, String resolvedType) {
10385 // Refuse possible leaked file descriptors
10386 if (service != null && service.hasFileDescriptors() == true) {
10387 throw new IllegalArgumentException("File descriptors passed in Intent");
10388 }
10389
10390 IBinder ret = null;
10391
10392 synchronized(this) {
10393 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10394
10395 if (r != null) {
10396 // r.record is null if findServiceLocked() failed the caller permission check
10397 if (r.record == null) {
10398 throw new SecurityException(
10399 "Permission Denial: Accessing service " + r.record.name
10400 + " from pid=" + Binder.getCallingPid()
10401 + ", uid=" + Binder.getCallingUid()
10402 + " requires " + r.permission);
10403 }
10404 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10405 if (ib != null) {
10406 ret = ib.binder;
10407 }
10408 }
10409 }
10410
10411 return ret;
10412 }
10413
10414 public boolean stopServiceToken(ComponentName className, IBinder token,
10415 int startId) {
10416 synchronized(this) {
10417 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10418 + " " + token + " startId=" + startId);
10419 ServiceRecord r = findServiceLocked(className, token);
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010420 if (r != null) {
10421 if (startId >= 0) {
10422 // Asked to only stop if done with all work. Note that
10423 // to avoid leaks, we will take this as dropping all
10424 // start items up to and including this one.
10425 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
10426 if (si != null) {
10427 while (r.deliveredStarts.size() > 0) {
10428 if (r.deliveredStarts.remove(0) == si) {
10429 break;
10430 }
10431 }
10432 }
10433
10434 if (r.lastStartId != startId) {
10435 return false;
10436 }
10437
10438 if (r.deliveredStarts.size() > 0) {
10439 Log.w(TAG, "stopServiceToken startId " + startId
10440 + " is last, but have " + r.deliveredStarts.size()
10441 + " remaining args");
10442 }
10443 }
10444
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010445 synchronized (r.stats.getBatteryStats()) {
10446 r.stats.stopRunningLocked();
10447 r.startRequested = false;
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010448 r.callStart = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010449 }
10450 final long origId = Binder.clearCallingIdentity();
10451 bringDownServiceLocked(r, false);
10452 Binder.restoreCallingIdentity(origId);
10453 return true;
10454 }
10455 }
10456 return false;
10457 }
10458
10459 public void setServiceForeground(ComponentName className, IBinder token,
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010460 int id, Notification notification, boolean removeNotification) {
10461 final long origId = Binder.clearCallingIdentity();
10462 try {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010463 synchronized(this) {
10464 ServiceRecord r = findServiceLocked(className, token);
10465 if (r != null) {
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010466 if (id != 0) {
10467 if (notification == null) {
10468 throw new IllegalArgumentException("null notification");
10469 }
10470 if (r.foregroundId != id) {
10471 r.cancelNotification();
10472 r.foregroundId = id;
10473 }
10474 notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
10475 r.foregroundNoti = notification;
10476 r.isForeground = true;
10477 r.postNotification();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010478 if (r.app != null) {
10479 updateServiceForegroundLocked(r.app, true);
10480 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010481 } else {
10482 if (r.isForeground) {
10483 r.isForeground = false;
10484 if (r.app != null) {
10485 updateServiceForegroundLocked(r.app, true);
10486 }
10487 }
10488 if (removeNotification) {
10489 r.cancelNotification();
10490 r.foregroundId = 0;
10491 r.foregroundNoti = null;
10492 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010493 }
10494 }
10495 }
Dianne Hackbornd8a43f62009-08-17 23:33:56 -070010496 } finally {
10497 Binder.restoreCallingIdentity(origId);
10498 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010499 }
10500
10501 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10502 boolean anyForeground = false;
10503 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10504 if (sr.isForeground) {
10505 anyForeground = true;
10506 break;
10507 }
10508 }
10509 if (anyForeground != proc.foregroundServices) {
10510 proc.foregroundServices = anyForeground;
10511 if (oomAdj) {
10512 updateOomAdjLocked();
10513 }
10514 }
10515 }
10516
10517 public int bindService(IApplicationThread caller, IBinder token,
10518 Intent service, String resolvedType,
10519 IServiceConnection connection, int flags) {
10520 // Refuse possible leaked file descriptors
10521 if (service != null && service.hasFileDescriptors() == true) {
10522 throw new IllegalArgumentException("File descriptors passed in Intent");
10523 }
10524
10525 synchronized(this) {
10526 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10527 + " type=" + resolvedType + " conn=" + connection.asBinder()
10528 + " flags=0x" + Integer.toHexString(flags));
10529 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10530 if (callerApp == null) {
10531 throw new SecurityException(
10532 "Unable to find app for caller " + caller
10533 + " (pid=" + Binder.getCallingPid()
10534 + ") when binding service " + service);
10535 }
10536
10537 HistoryRecord activity = null;
10538 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010539 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010540 if (aindex < 0) {
10541 Log.w(TAG, "Binding with unknown activity: " + token);
10542 return 0;
10543 }
10544 activity = (HistoryRecord)mHistory.get(aindex);
10545 }
10546
10547 ServiceLookupResult res =
10548 retrieveServiceLocked(service, resolvedType,
10549 Binder.getCallingPid(), Binder.getCallingUid());
10550 if (res == null) {
10551 return 0;
10552 }
10553 if (res.record == null) {
10554 return -1;
10555 }
10556 ServiceRecord s = res.record;
10557
10558 final long origId = Binder.clearCallingIdentity();
10559
10560 if (unscheduleServiceRestartLocked(s)) {
10561 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10562 + s.shortName);
10563 }
10564
10565 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10566 ConnectionRecord c = new ConnectionRecord(b, activity,
10567 connection, flags);
10568
10569 IBinder binder = connection.asBinder();
10570 s.connections.put(binder, c);
10571 b.connections.add(c);
10572 if (activity != null) {
10573 if (activity.connections == null) {
10574 activity.connections = new HashSet<ConnectionRecord>();
10575 }
10576 activity.connections.add(c);
10577 }
10578 b.client.connections.add(c);
10579 mServiceConnections.put(binder, c);
10580
10581 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10582 s.lastActivity = SystemClock.uptimeMillis();
10583 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10584 return 0;
10585 }
10586 }
10587
10588 if (s.app != null) {
10589 // This could have made the service more important.
10590 updateOomAdjLocked(s.app);
10591 }
10592
10593 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10594 + ": received=" + b.intent.received
10595 + " apps=" + b.intent.apps.size()
10596 + " doRebind=" + b.intent.doRebind);
10597
10598 if (s.app != null && b.intent.received) {
10599 // Service is already running, so we can immediately
10600 // publish the connection.
10601 try {
10602 c.conn.connected(s.name, b.intent.binder);
10603 } catch (Exception e) {
10604 Log.w(TAG, "Failure sending service " + s.shortName
10605 + " to connection " + c.conn.asBinder()
10606 + " (in " + c.binding.client.processName + ")", e);
10607 }
10608
10609 // If this is the first app connected back to this binding,
10610 // and the service had previously asked to be told when
10611 // rebound, then do so.
10612 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10613 requestServiceBindingLocked(s, b.intent, true);
10614 }
10615 } else if (!b.intent.requested) {
10616 requestServiceBindingLocked(s, b.intent, false);
10617 }
10618
10619 Binder.restoreCallingIdentity(origId);
10620 }
10621
10622 return 1;
10623 }
10624
10625 private void removeConnectionLocked(
10626 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10627 IBinder binder = c.conn.asBinder();
10628 AppBindRecord b = c.binding;
10629 ServiceRecord s = b.service;
10630 s.connections.remove(binder);
10631 b.connections.remove(c);
10632 if (c.activity != null && c.activity != skipAct) {
10633 if (c.activity.connections != null) {
10634 c.activity.connections.remove(c);
10635 }
10636 }
10637 if (b.client != skipApp) {
10638 b.client.connections.remove(c);
10639 }
10640 mServiceConnections.remove(binder);
10641
10642 if (b.connections.size() == 0) {
10643 b.intent.apps.remove(b.client);
10644 }
10645
10646 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10647 + ": shouldUnbind=" + b.intent.hasBound);
10648 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10649 && b.intent.hasBound) {
10650 try {
10651 bumpServiceExecutingLocked(s);
10652 updateOomAdjLocked(s.app);
10653 b.intent.hasBound = false;
10654 // Assume the client doesn't want to know about a rebind;
10655 // we will deal with that later if it asks for one.
10656 b.intent.doRebind = false;
10657 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10658 } catch (Exception e) {
10659 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10660 serviceDoneExecutingLocked(s, true);
10661 }
10662 }
10663
10664 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10665 bringDownServiceLocked(s, false);
10666 }
10667 }
10668
10669 public boolean unbindService(IServiceConnection connection) {
10670 synchronized (this) {
10671 IBinder binder = connection.asBinder();
10672 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10673 ConnectionRecord r = mServiceConnections.get(binder);
10674 if (r == null) {
10675 Log.w(TAG, "Unbind failed: could not find connection for "
10676 + connection.asBinder());
10677 return false;
10678 }
10679
10680 final long origId = Binder.clearCallingIdentity();
10681
10682 removeConnectionLocked(r, null, null);
10683
10684 if (r.binding.service.app != null) {
10685 // This could have made the service less important.
10686 updateOomAdjLocked(r.binding.service.app);
10687 }
10688
10689 Binder.restoreCallingIdentity(origId);
10690 }
10691
10692 return true;
10693 }
10694
10695 public void publishService(IBinder token, Intent intent, IBinder service) {
10696 // Refuse possible leaked file descriptors
10697 if (intent != null && intent.hasFileDescriptors() == true) {
10698 throw new IllegalArgumentException("File descriptors passed in Intent");
10699 }
10700
10701 synchronized(this) {
10702 if (!(token instanceof ServiceRecord)) {
10703 throw new IllegalArgumentException("Invalid service token");
10704 }
10705 ServiceRecord r = (ServiceRecord)token;
10706
10707 final long origId = Binder.clearCallingIdentity();
10708
10709 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10710 + " " + intent + ": " + service);
10711 if (r != null) {
10712 Intent.FilterComparison filter
10713 = new Intent.FilterComparison(intent);
10714 IntentBindRecord b = r.bindings.get(filter);
10715 if (b != null && !b.received) {
10716 b.binder = service;
10717 b.requested = true;
10718 b.received = true;
10719 if (r.connections.size() > 0) {
10720 Iterator<ConnectionRecord> it
10721 = r.connections.values().iterator();
10722 while (it.hasNext()) {
10723 ConnectionRecord c = it.next();
10724 if (!filter.equals(c.binding.intent.intent)) {
10725 if (DEBUG_SERVICE) Log.v(
10726 TAG, "Not publishing to: " + c);
10727 if (DEBUG_SERVICE) Log.v(
10728 TAG, "Bound intent: " + c.binding.intent.intent);
10729 if (DEBUG_SERVICE) Log.v(
10730 TAG, "Published intent: " + intent);
10731 continue;
10732 }
10733 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10734 try {
10735 c.conn.connected(r.name, service);
10736 } catch (Exception e) {
10737 Log.w(TAG, "Failure sending service " + r.name +
10738 " to connection " + c.conn.asBinder() +
10739 " (in " + c.binding.client.processName + ")", e);
10740 }
10741 }
10742 }
10743 }
10744
10745 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10746
10747 Binder.restoreCallingIdentity(origId);
10748 }
10749 }
10750 }
10751
10752 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10753 // Refuse possible leaked file descriptors
10754 if (intent != null && intent.hasFileDescriptors() == true) {
10755 throw new IllegalArgumentException("File descriptors passed in Intent");
10756 }
10757
10758 synchronized(this) {
10759 if (!(token instanceof ServiceRecord)) {
10760 throw new IllegalArgumentException("Invalid service token");
10761 }
10762 ServiceRecord r = (ServiceRecord)token;
10763
10764 final long origId = Binder.clearCallingIdentity();
10765
10766 if (r != null) {
10767 Intent.FilterComparison filter
10768 = new Intent.FilterComparison(intent);
10769 IntentBindRecord b = r.bindings.get(filter);
10770 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10771 + " at " + b + ": apps="
10772 + (b != null ? b.apps.size() : 0));
10773 if (b != null) {
10774 if (b.apps.size() > 0) {
10775 // Applications have already bound since the last
10776 // unbind, so just rebind right here.
10777 requestServiceBindingLocked(r, b, true);
10778 } else {
10779 // Note to tell the service the next time there is
10780 // a new client.
10781 b.doRebind = true;
10782 }
10783 }
10784
10785 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10786
10787 Binder.restoreCallingIdentity(origId);
10788 }
10789 }
10790 }
10791
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010792 public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010793 synchronized(this) {
10794 if (!(token instanceof ServiceRecord)) {
10795 throw new IllegalArgumentException("Invalid service token");
10796 }
10797 ServiceRecord r = (ServiceRecord)token;
10798 boolean inStopping = mStoppingServices.contains(token);
10799 if (r != null) {
10800 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10801 + ": nesting=" + r.executeNesting
10802 + ", inStopping=" + inStopping);
10803 if (r != token) {
10804 Log.w(TAG, "Done executing service " + r.name
10805 + " with incorrect token: given " + token
10806 + ", expected " + r);
10807 return;
10808 }
10809
Dianne Hackbornf6f9f2d2009-08-21 16:26:03 -070010810 if (type == 1) {
10811 // This is a call from a service start... take care of
10812 // book-keeping.
10813 r.callStart = true;
10814 switch (res) {
10815 case Service.START_STICKY_COMPATIBILITY:
10816 case Service.START_STICKY: {
10817 // We are done with the associated start arguments.
10818 r.findDeliveredStart(startId, true);
10819 // Don't stop if killed.
10820 r.stopIfKilled = false;
10821 break;
10822 }
10823 case Service.START_NOT_STICKY: {
10824 // We are done with the associated start arguments.
10825 r.findDeliveredStart(startId, true);
10826 if (r.lastStartId == startId) {
10827 // There is no more work, and this service
10828 // doesn't want to hang around if killed.
10829 r.stopIfKilled = true;
10830 }
10831 break;
10832 }
10833 case Service.START_REDELIVER_INTENT: {
10834 // We'll keep this item until they explicitly
10835 // call stop for it, but keep track of the fact
10836 // that it was delivered.
10837 ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
10838 if (si != null) {
10839 si.deliveryCount = 0;
10840 si.doneExecutingCount++;
10841 // Don't stop if killed.
10842 r.stopIfKilled = true;
10843 }
10844 break;
10845 }
10846 default:
10847 throw new IllegalArgumentException(
10848 "Unknown service start result: " + res);
10849 }
10850 if (res == Service.START_STICKY_COMPATIBILITY) {
10851 r.callStart = false;
10852 }
10853 }
10854
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010855 final long origId = Binder.clearCallingIdentity();
10856 serviceDoneExecutingLocked(r, inStopping);
10857 Binder.restoreCallingIdentity(origId);
10858 } else {
10859 Log.w(TAG, "Done executing unknown service " + r.name
10860 + " with token " + token);
10861 }
10862 }
10863 }
10864
10865 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10866 r.executeNesting--;
10867 if (r.executeNesting <= 0 && r.app != null) {
10868 r.app.executingServices.remove(r);
10869 if (r.app.executingServices.size() == 0) {
10870 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10871 }
10872 if (inStopping) {
10873 mStoppingServices.remove(r);
10874 }
10875 updateOomAdjLocked(r.app);
10876 }
10877 }
10878
10879 void serviceTimeout(ProcessRecord proc) {
10880 synchronized(this) {
10881 if (proc.executingServices.size() == 0 || proc.thread == null) {
10882 return;
10883 }
10884 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10885 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10886 ServiceRecord timeout = null;
10887 long nextTime = 0;
10888 while (it.hasNext()) {
10889 ServiceRecord sr = it.next();
10890 if (sr.executingStart < maxTime) {
10891 timeout = sr;
10892 break;
10893 }
10894 if (sr.executingStart > nextTime) {
10895 nextTime = sr.executingStart;
10896 }
10897 }
10898 if (timeout != null && mLRUProcesses.contains(proc)) {
10899 Log.w(TAG, "Timeout executing service: " + timeout);
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070010900 appNotRespondingLocked(proc, null, null, "Executing service "
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010901 + timeout.name);
10902 } else {
10903 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10904 msg.obj = proc;
10905 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
10906 }
10907 }
10908 }
10909
10910 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070010911 // BACKUP AND RESTORE
10912 // =========================================================
10913
10914 // Cause the target app to be launched if necessary and its backup agent
10915 // instantiated. The backup agent will invoke backupAgentCreated() on the
10916 // activity manager to announce its creation.
10917 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
10918 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
10919 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
10920
10921 synchronized(this) {
10922 // !!! TODO: currently no check here that we're already bound
10923 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10924 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10925 synchronized (stats) {
10926 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
10927 }
10928
10929 BackupRecord r = new BackupRecord(ss, app, backupMode);
10930 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
10931 // startProcessLocked() returns existing proc's record if it's already running
10932 ProcessRecord proc = startProcessLocked(app.processName, app,
10933 false, 0, "backup", hostingName);
10934 if (proc == null) {
10935 Log.e(TAG, "Unable to start backup agent process " + r);
10936 return false;
10937 }
10938
10939 r.app = proc;
10940 mBackupTarget = r;
10941 mBackupAppName = app.packageName;
10942
Christopher Tate6fa95972009-06-05 18:43:55 -070010943 // Try not to kill the process during backup
10944 updateOomAdjLocked(proc);
10945
Christopher Tate181fafa2009-05-14 11:12:14 -070010946 // If the process is already attached, schedule the creation of the backup agent now.
10947 // If it is not yet live, this will be done when it attaches to the framework.
10948 if (proc.thread != null) {
10949 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
10950 try {
10951 proc.thread.scheduleCreateBackupAgent(app, backupMode);
10952 } catch (RemoteException e) {
10953 // !!! TODO: notify the backup manager that we crashed, or rely on
10954 // death notices, or...?
10955 }
10956 } else {
10957 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
10958 }
10959 // Invariants: at this point, the target app process exists and the application
10960 // is either already running or in the process of coming up. mBackupTarget and
10961 // mBackupAppName describe the app, so that when it binds back to the AM we
10962 // know that it's scheduled for a backup-agent operation.
10963 }
10964
10965 return true;
10966 }
10967
10968 // A backup agent has just come up
10969 public void backupAgentCreated(String agentPackageName, IBinder agent) {
10970 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
10971 + " = " + agent);
10972
10973 synchronized(this) {
10974 if (!agentPackageName.equals(mBackupAppName)) {
10975 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
10976 return;
10977 }
10978
Christopher Tate043dadc2009-06-02 16:11:00 -070010979 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070010980 try {
10981 IBackupManager bm = IBackupManager.Stub.asInterface(
10982 ServiceManager.getService(Context.BACKUP_SERVICE));
10983 bm.agentConnected(agentPackageName, agent);
10984 } catch (RemoteException e) {
10985 // can't happen; the backup manager service is local
10986 } catch (Exception e) {
10987 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
10988 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070010989 } finally {
10990 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070010991 }
10992 }
10993 }
10994
10995 // done with this agent
10996 public void unbindBackupAgent(ApplicationInfo appInfo) {
10997 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070010998 if (appInfo == null) {
10999 Log.w(TAG, "unbind backup agent for null app");
11000 return;
11001 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011002
11003 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070011004 if (mBackupAppName == null) {
11005 Log.w(TAG, "Unbinding backup agent with no active backup");
11006 return;
11007 }
11008
Christopher Tate181fafa2009-05-14 11:12:14 -070011009 if (!mBackupAppName.equals(appInfo.packageName)) {
11010 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
11011 return;
11012 }
11013
Christopher Tate6fa95972009-06-05 18:43:55 -070011014 ProcessRecord proc = mBackupTarget.app;
11015 mBackupTarget = null;
11016 mBackupAppName = null;
11017
11018 // Not backing this app up any more; reset its OOM adjustment
11019 updateOomAdjLocked(proc);
11020
Christopher Tatec7b31e32009-06-10 15:49:30 -070011021 // If the app crashed during backup, 'thread' will be null here
11022 if (proc.thread != null) {
11023 try {
11024 proc.thread.scheduleDestroyBackupAgent(appInfo);
11025 } catch (Exception e) {
11026 Log.e(TAG, "Exception when unbinding backup agent:");
11027 e.printStackTrace();
11028 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011029 }
Christopher Tate181fafa2009-05-14 11:12:14 -070011030 }
11031 }
11032 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011033 // BROADCASTS
11034 // =========================================================
11035
11036 private final List getStickies(String action, IntentFilter filter,
11037 List cur) {
11038 final ContentResolver resolver = mContext.getContentResolver();
11039 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
11040 if (list == null) {
11041 return cur;
11042 }
11043 int N = list.size();
11044 for (int i=0; i<N; i++) {
11045 Intent intent = list.get(i);
11046 if (filter.match(resolver, intent, true, TAG) >= 0) {
11047 if (cur == null) {
11048 cur = new ArrayList<Intent>();
11049 }
11050 cur.add(intent);
11051 }
11052 }
11053 return cur;
11054 }
11055
11056 private final void scheduleBroadcastsLocked() {
11057 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
11058 + mBroadcastsScheduled);
11059
11060 if (mBroadcastsScheduled) {
11061 return;
11062 }
11063 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
11064 mBroadcastsScheduled = true;
11065 }
11066
11067 public Intent registerReceiver(IApplicationThread caller,
11068 IIntentReceiver receiver, IntentFilter filter, String permission) {
11069 synchronized(this) {
11070 ProcessRecord callerApp = null;
11071 if (caller != null) {
11072 callerApp = getRecordForAppLocked(caller);
11073 if (callerApp == null) {
11074 throw new SecurityException(
11075 "Unable to find app for caller " + caller
11076 + " (pid=" + Binder.getCallingPid()
11077 + ") when registering receiver " + receiver);
11078 }
11079 }
11080
11081 List allSticky = null;
11082
11083 // Look for any matching sticky broadcasts...
11084 Iterator actions = filter.actionsIterator();
11085 if (actions != null) {
11086 while (actions.hasNext()) {
11087 String action = (String)actions.next();
11088 allSticky = getStickies(action, filter, allSticky);
11089 }
11090 } else {
11091 allSticky = getStickies(null, filter, allSticky);
11092 }
11093
11094 // The first sticky in the list is returned directly back to
11095 // the client.
11096 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
11097
11098 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
11099 + ": " + sticky);
11100
11101 if (receiver == null) {
11102 return sticky;
11103 }
11104
11105 ReceiverList rl
11106 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11107 if (rl == null) {
11108 rl = new ReceiverList(this, callerApp,
11109 Binder.getCallingPid(),
11110 Binder.getCallingUid(), receiver);
11111 if (rl.app != null) {
11112 rl.app.receivers.add(rl);
11113 } else {
11114 try {
11115 receiver.asBinder().linkToDeath(rl, 0);
11116 } catch (RemoteException e) {
11117 return sticky;
11118 }
11119 rl.linkedToDeath = true;
11120 }
11121 mRegisteredReceivers.put(receiver.asBinder(), rl);
11122 }
11123 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
11124 rl.add(bf);
11125 if (!bf.debugCheck()) {
11126 Log.w(TAG, "==> For Dynamic broadast");
11127 }
11128 mReceiverResolver.addFilter(bf);
11129
11130 // Enqueue broadcasts for all existing stickies that match
11131 // this filter.
11132 if (allSticky != null) {
11133 ArrayList receivers = new ArrayList();
11134 receivers.add(bf);
11135
11136 int N = allSticky.size();
11137 for (int i=0; i<N; i++) {
11138 Intent intent = (Intent)allSticky.get(i);
11139 BroadcastRecord r = new BroadcastRecord(intent, null,
11140 null, -1, -1, null, receivers, null, 0, null, null,
11141 false);
11142 if (mParallelBroadcasts.size() == 0) {
11143 scheduleBroadcastsLocked();
11144 }
11145 mParallelBroadcasts.add(r);
11146 }
11147 }
11148
11149 return sticky;
11150 }
11151 }
11152
11153 public void unregisterReceiver(IIntentReceiver receiver) {
11154 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
11155
11156 boolean doNext = false;
11157
11158 synchronized(this) {
11159 ReceiverList rl
11160 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
11161 if (rl != null) {
11162 if (rl.curBroadcast != null) {
11163 BroadcastRecord r = rl.curBroadcast;
11164 doNext = finishReceiverLocked(
11165 receiver.asBinder(), r.resultCode, r.resultData,
11166 r.resultExtras, r.resultAbort, true);
11167 }
11168
11169 if (rl.app != null) {
11170 rl.app.receivers.remove(rl);
11171 }
11172 removeReceiverLocked(rl);
11173 if (rl.linkedToDeath) {
11174 rl.linkedToDeath = false;
11175 rl.receiver.asBinder().unlinkToDeath(rl, 0);
11176 }
11177 }
11178 }
11179
11180 if (!doNext) {
11181 return;
11182 }
11183
11184 final long origId = Binder.clearCallingIdentity();
11185 processNextBroadcast(false);
11186 trimApplications();
11187 Binder.restoreCallingIdentity(origId);
11188 }
11189
11190 void removeReceiverLocked(ReceiverList rl) {
11191 mRegisteredReceivers.remove(rl.receiver.asBinder());
11192 int N = rl.size();
11193 for (int i=0; i<N; i++) {
11194 mReceiverResolver.removeFilter(rl.get(i));
11195 }
11196 }
11197
11198 private final int broadcastIntentLocked(ProcessRecord callerApp,
11199 String callerPackage, Intent intent, String resolvedType,
11200 IIntentReceiver resultTo, int resultCode, String resultData,
11201 Bundle map, String requiredPermission,
11202 boolean ordered, boolean sticky, int callingPid, int callingUid) {
11203 intent = new Intent(intent);
11204
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011205 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011206 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
11207 + " ordered=" + ordered);
11208 if ((resultTo != null) && !ordered) {
11209 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
11210 }
11211
11212 // Handle special intents: if this broadcast is from the package
11213 // manager about a package being removed, we need to remove all of
11214 // its activities from the history stack.
11215 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
11216 intent.getAction());
11217 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
11218 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
11219 || uidRemoved) {
11220 if (checkComponentPermission(
11221 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
11222 callingPid, callingUid, -1)
11223 == PackageManager.PERMISSION_GRANTED) {
11224 if (uidRemoved) {
11225 final Bundle intentExtras = intent.getExtras();
11226 final int uid = intentExtras != null
11227 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
11228 if (uid >= 0) {
11229 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
11230 synchronized (bs) {
11231 bs.removeUidStatsLocked(uid);
11232 }
11233 }
11234 } else {
11235 Uri data = intent.getData();
11236 String ssp;
11237 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
11238 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
11239 uninstallPackageLocked(ssp,
11240 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011241 AttributeCache ac = AttributeCache.instance();
11242 if (ac != null) {
11243 ac.removePackage(ssp);
11244 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011245 }
11246 }
11247 }
11248 } else {
11249 String msg = "Permission Denial: " + intent.getAction()
11250 + " broadcast from " + callerPackage + " (pid=" + callingPid
11251 + ", uid=" + callingUid + ")"
11252 + " requires "
11253 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
11254 Log.w(TAG, msg);
11255 throw new SecurityException(msg);
11256 }
11257 }
11258
11259 /*
11260 * If this is the time zone changed action, queue up a message that will reset the timezone
11261 * of all currently running processes. This message will get queued up before the broadcast
11262 * happens.
11263 */
11264 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
11265 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
11266 }
11267
Dianne Hackborn854060af2009-07-09 18:14:31 -070011268 /*
11269 * Prevent non-system code (defined here to be non-persistent
11270 * processes) from sending protected broadcasts.
11271 */
11272 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
11273 || callingUid == Process.SHELL_UID || callingUid == 0) {
11274 // Always okay.
11275 } else if (callerApp == null || !callerApp.persistent) {
11276 try {
11277 if (ActivityThread.getPackageManager().isProtectedBroadcast(
11278 intent.getAction())) {
11279 String msg = "Permission Denial: not allowed to send broadcast "
11280 + intent.getAction() + " from pid="
11281 + callingPid + ", uid=" + callingUid;
11282 Log.w(TAG, msg);
11283 throw new SecurityException(msg);
11284 }
11285 } catch (RemoteException e) {
11286 Log.w(TAG, "Remote exception", e);
11287 return BROADCAST_SUCCESS;
11288 }
11289 }
11290
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011291 // Add to the sticky list if requested.
11292 if (sticky) {
11293 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
11294 callingPid, callingUid)
11295 != PackageManager.PERMISSION_GRANTED) {
11296 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
11297 + callingPid + ", uid=" + callingUid
11298 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11299 Log.w(TAG, msg);
11300 throw new SecurityException(msg);
11301 }
11302 if (requiredPermission != null) {
11303 Log.w(TAG, "Can't broadcast sticky intent " + intent
11304 + " and enforce permission " + requiredPermission);
11305 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
11306 }
11307 if (intent.getComponent() != null) {
11308 throw new SecurityException(
11309 "Sticky broadcasts can't target a specific component");
11310 }
11311 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11312 if (list == null) {
11313 list = new ArrayList<Intent>();
11314 mStickyBroadcasts.put(intent.getAction(), list);
11315 }
11316 int N = list.size();
11317 int i;
11318 for (i=0; i<N; i++) {
11319 if (intent.filterEquals(list.get(i))) {
11320 // This sticky already exists, replace it.
11321 list.set(i, new Intent(intent));
11322 break;
11323 }
11324 }
11325 if (i >= N) {
11326 list.add(new Intent(intent));
11327 }
11328 }
11329
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011330 // Figure out who all will receive this broadcast.
11331 List receivers = null;
11332 List<BroadcastFilter> registeredReceivers = null;
11333 try {
11334 if (intent.getComponent() != null) {
11335 // Broadcast is going to one specific receiver class...
11336 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070011337 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011338 if (ai != null) {
11339 receivers = new ArrayList();
11340 ResolveInfo ri = new ResolveInfo();
11341 ri.activityInfo = ai;
11342 receivers.add(ri);
11343 }
11344 } else {
11345 // Need to resolve the intent to interested receivers...
11346 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
11347 == 0) {
11348 receivers =
11349 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011350 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011351 }
Mihai Preda074edef2009-05-18 17:13:31 +020011352 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011353 }
11354 } catch (RemoteException ex) {
11355 // pm is in same process, this will never happen.
11356 }
11357
11358 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
11359 if (!ordered && NR > 0) {
11360 // If we are not serializing this broadcast, then send the
11361 // registered receivers separately so they don't wait for the
11362 // components to be launched.
11363 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11364 callerPackage, callingPid, callingUid, requiredPermission,
11365 registeredReceivers, resultTo, resultCode, resultData, map,
11366 ordered);
11367 if (DEBUG_BROADCAST) Log.v(
11368 TAG, "Enqueueing parallel broadcast " + r
11369 + ": prev had " + mParallelBroadcasts.size());
11370 mParallelBroadcasts.add(r);
11371 scheduleBroadcastsLocked();
11372 registeredReceivers = null;
11373 NR = 0;
11374 }
11375
11376 // Merge into one list.
11377 int ir = 0;
11378 if (receivers != null) {
11379 // A special case for PACKAGE_ADDED: do not allow the package
11380 // being added to see this broadcast. This prevents them from
11381 // using this as a back door to get run as soon as they are
11382 // installed. Maybe in the future we want to have a special install
11383 // broadcast or such for apps, but we'd like to deliberately make
11384 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070011385 boolean skip = false;
11386 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070011387 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070011388 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
11389 skip = true;
11390 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
11391 skip = true;
11392 }
11393 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011394 ? intent.getData().getSchemeSpecificPart()
11395 : null;
11396 if (skipPackage != null && receivers != null) {
11397 int NT = receivers.size();
11398 for (int it=0; it<NT; it++) {
11399 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11400 if (curt.activityInfo.packageName.equals(skipPackage)) {
11401 receivers.remove(it);
11402 it--;
11403 NT--;
11404 }
11405 }
11406 }
11407
11408 int NT = receivers != null ? receivers.size() : 0;
11409 int it = 0;
11410 ResolveInfo curt = null;
11411 BroadcastFilter curr = null;
11412 while (it < NT && ir < NR) {
11413 if (curt == null) {
11414 curt = (ResolveInfo)receivers.get(it);
11415 }
11416 if (curr == null) {
11417 curr = registeredReceivers.get(ir);
11418 }
11419 if (curr.getPriority() >= curt.priority) {
11420 // Insert this broadcast record into the final list.
11421 receivers.add(it, curr);
11422 ir++;
11423 curr = null;
11424 it++;
11425 NT++;
11426 } else {
11427 // Skip to the next ResolveInfo in the final list.
11428 it++;
11429 curt = null;
11430 }
11431 }
11432 }
11433 while (ir < NR) {
11434 if (receivers == null) {
11435 receivers = new ArrayList();
11436 }
11437 receivers.add(registeredReceivers.get(ir));
11438 ir++;
11439 }
11440
11441 if ((receivers != null && receivers.size() > 0)
11442 || resultTo != null) {
11443 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11444 callerPackage, callingPid, callingUid, requiredPermission,
11445 receivers, resultTo, resultCode, resultData, map, ordered);
11446 if (DEBUG_BROADCAST) Log.v(
11447 TAG, "Enqueueing ordered broadcast " + r
11448 + ": prev had " + mOrderedBroadcasts.size());
11449 if (DEBUG_BROADCAST) {
11450 int seq = r.intent.getIntExtra("seq", -1);
11451 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11452 }
11453 mOrderedBroadcasts.add(r);
11454 scheduleBroadcastsLocked();
11455 }
11456
11457 return BROADCAST_SUCCESS;
11458 }
11459
11460 public final int broadcastIntent(IApplicationThread caller,
11461 Intent intent, String resolvedType, IIntentReceiver resultTo,
11462 int resultCode, String resultData, Bundle map,
11463 String requiredPermission, boolean serialized, boolean sticky) {
11464 // Refuse possible leaked file descriptors
11465 if (intent != null && intent.hasFileDescriptors() == true) {
11466 throw new IllegalArgumentException("File descriptors passed in Intent");
11467 }
11468
11469 synchronized(this) {
11470 if (!mSystemReady) {
11471 // if the caller really truly claims to know what they're doing, go
11472 // ahead and allow the broadcast without launching any receivers
11473 int flags = intent.getFlags();
11474 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11475 intent = new Intent(intent);
11476 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11477 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11478 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11479 + " before boot completion");
11480 throw new IllegalStateException("Cannot broadcast before boot completed");
11481 }
11482 }
11483
11484 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11485 final int callingPid = Binder.getCallingPid();
11486 final int callingUid = Binder.getCallingUid();
11487 final long origId = Binder.clearCallingIdentity();
11488 int res = broadcastIntentLocked(callerApp,
11489 callerApp != null ? callerApp.info.packageName : null,
11490 intent, resolvedType, resultTo,
11491 resultCode, resultData, map, requiredPermission, serialized,
11492 sticky, callingPid, callingUid);
11493 Binder.restoreCallingIdentity(origId);
11494 return res;
11495 }
11496 }
11497
11498 int broadcastIntentInPackage(String packageName, int uid,
11499 Intent intent, String resolvedType, IIntentReceiver resultTo,
11500 int resultCode, String resultData, Bundle map,
11501 String requiredPermission, boolean serialized, boolean sticky) {
11502 synchronized(this) {
11503 final long origId = Binder.clearCallingIdentity();
11504 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11505 resultTo, resultCode, resultData, map, requiredPermission,
11506 serialized, sticky, -1, uid);
11507 Binder.restoreCallingIdentity(origId);
11508 return res;
11509 }
11510 }
11511
11512 public final void unbroadcastIntent(IApplicationThread caller,
11513 Intent intent) {
11514 // Refuse possible leaked file descriptors
11515 if (intent != null && intent.hasFileDescriptors() == true) {
11516 throw new IllegalArgumentException("File descriptors passed in Intent");
11517 }
11518
11519 synchronized(this) {
11520 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11521 != PackageManager.PERMISSION_GRANTED) {
11522 String msg = "Permission Denial: unbroadcastIntent() from pid="
11523 + Binder.getCallingPid()
11524 + ", uid=" + Binder.getCallingUid()
11525 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11526 Log.w(TAG, msg);
11527 throw new SecurityException(msg);
11528 }
11529 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11530 if (list != null) {
11531 int N = list.size();
11532 int i;
11533 for (i=0; i<N; i++) {
11534 if (intent.filterEquals(list.get(i))) {
11535 list.remove(i);
11536 break;
11537 }
11538 }
11539 }
11540 }
11541 }
11542
11543 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11544 String resultData, Bundle resultExtras, boolean resultAbort,
11545 boolean explicit) {
11546 if (mOrderedBroadcasts.size() == 0) {
11547 if (explicit) {
11548 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11549 }
11550 return false;
11551 }
11552 BroadcastRecord r = mOrderedBroadcasts.get(0);
11553 if (r.receiver == null) {
11554 if (explicit) {
11555 Log.w(TAG, "finishReceiver called but none active");
11556 }
11557 return false;
11558 }
11559 if (r.receiver != receiver) {
11560 Log.w(TAG, "finishReceiver called but active receiver is different");
11561 return false;
11562 }
11563 int state = r.state;
11564 r.state = r.IDLE;
11565 if (state == r.IDLE) {
11566 if (explicit) {
11567 Log.w(TAG, "finishReceiver called but state is IDLE");
11568 }
11569 }
11570 r.receiver = null;
11571 r.intent.setComponent(null);
11572 if (r.curApp != null) {
11573 r.curApp.curReceiver = null;
11574 }
11575 if (r.curFilter != null) {
11576 r.curFilter.receiverList.curBroadcast = null;
11577 }
11578 r.curFilter = null;
11579 r.curApp = null;
11580 r.curComponent = null;
11581 r.curReceiver = null;
11582 mPendingBroadcast = null;
11583
11584 r.resultCode = resultCode;
11585 r.resultData = resultData;
11586 r.resultExtras = resultExtras;
11587 r.resultAbort = resultAbort;
11588
11589 // We will process the next receiver right now if this is finishing
11590 // an app receiver (which is always asynchronous) or after we have
11591 // come back from calling a receiver.
11592 return state == BroadcastRecord.APP_RECEIVE
11593 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11594 }
11595
11596 public void finishReceiver(IBinder who, int resultCode, String resultData,
11597 Bundle resultExtras, boolean resultAbort) {
11598 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11599
11600 // Refuse possible leaked file descriptors
11601 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11602 throw new IllegalArgumentException("File descriptors passed in Bundle");
11603 }
11604
11605 boolean doNext;
11606
11607 final long origId = Binder.clearCallingIdentity();
11608
11609 synchronized(this) {
11610 doNext = finishReceiverLocked(
11611 who, resultCode, resultData, resultExtras, resultAbort, true);
11612 }
11613
11614 if (doNext) {
11615 processNextBroadcast(false);
11616 }
11617 trimApplications();
11618
11619 Binder.restoreCallingIdentity(origId);
11620 }
11621
11622 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11623 if (r.nextReceiver > 0) {
11624 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11625 if (curReceiver instanceof BroadcastFilter) {
11626 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11627 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11628 System.identityHashCode(r),
11629 r.intent.getAction(),
11630 r.nextReceiver - 1,
11631 System.identityHashCode(bf));
11632 } else {
11633 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11634 System.identityHashCode(r),
11635 r.intent.getAction(),
11636 r.nextReceiver - 1,
11637 ((ResolveInfo)curReceiver).toString());
11638 }
11639 } else {
11640 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11641 + r);
11642 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11643 System.identityHashCode(r),
11644 r.intent.getAction(),
11645 r.nextReceiver,
11646 "NONE");
11647 }
11648 }
11649
11650 private final void broadcastTimeout() {
11651 synchronized (this) {
11652 if (mOrderedBroadcasts.size() == 0) {
11653 return;
11654 }
11655 long now = SystemClock.uptimeMillis();
11656 BroadcastRecord r = mOrderedBroadcasts.get(0);
11657 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11658 if (DEBUG_BROADCAST) Log.v(TAG,
11659 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11660 + (r.startTime + BROADCAST_TIMEOUT));
11661 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11662 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11663 return;
11664 }
11665
11666 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11667 r.startTime = now;
11668 r.anrCount++;
11669
11670 // Current receiver has passed its expiration date.
11671 if (r.nextReceiver <= 0) {
11672 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11673 return;
11674 }
11675
11676 ProcessRecord app = null;
11677
11678 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11679 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11680 logBroadcastReceiverDiscard(r);
11681 if (curReceiver instanceof BroadcastFilter) {
11682 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11683 if (bf.receiverList.pid != 0
11684 && bf.receiverList.pid != MY_PID) {
11685 synchronized (this.mPidsSelfLocked) {
11686 app = this.mPidsSelfLocked.get(
11687 bf.receiverList.pid);
11688 }
11689 }
11690 } else {
11691 app = r.curApp;
11692 }
11693
11694 if (app != null) {
Dianne Hackborn82e1ee92009-08-11 18:56:41 -070011695 appNotRespondingLocked(app, null, null,
11696 "Broadcast of " + r.intent.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011697 }
11698
11699 if (mPendingBroadcast == r) {
11700 mPendingBroadcast = null;
11701 }
11702
11703 // Move on to the next receiver.
11704 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11705 r.resultExtras, r.resultAbort, true);
11706 scheduleBroadcastsLocked();
11707 }
11708 }
11709
11710 private final void processCurBroadcastLocked(BroadcastRecord r,
11711 ProcessRecord app) throws RemoteException {
11712 if (app.thread == null) {
11713 throw new RemoteException();
11714 }
11715 r.receiver = app.thread.asBinder();
11716 r.curApp = app;
11717 app.curReceiver = r;
11718 updateLRUListLocked(app, true);
11719
11720 // Tell the application to launch this receiver.
11721 r.intent.setComponent(r.curComponent);
11722
11723 boolean started = false;
11724 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011725 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011726 "Delivering to component " + r.curComponent
11727 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070011728 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011729 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
11730 r.resultCode, r.resultData, r.resultExtras, r.ordered);
11731 started = true;
11732 } finally {
11733 if (!started) {
11734 r.receiver = null;
11735 r.curApp = null;
11736 app.curReceiver = null;
11737 }
11738 }
11739
11740 }
11741
11742 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
11743 Intent intent, int resultCode, String data,
11744 Bundle extras, boolean ordered) throws RemoteException {
11745 if (app != null && app.thread != null) {
11746 // If we have an app thread, do the call through that so it is
11747 // correctly ordered with other one-way calls.
11748 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
11749 data, extras, ordered);
11750 } else {
11751 receiver.performReceive(intent, resultCode, data, extras, ordered);
11752 }
11753 }
11754
11755 private final void deliverToRegisteredReceiver(BroadcastRecord r,
11756 BroadcastFilter filter, boolean ordered) {
11757 boolean skip = false;
11758 if (filter.requiredPermission != null) {
11759 int perm = checkComponentPermission(filter.requiredPermission,
11760 r.callingPid, r.callingUid, -1);
11761 if (perm != PackageManager.PERMISSION_GRANTED) {
11762 Log.w(TAG, "Permission Denial: broadcasting "
11763 + r.intent.toString()
11764 + " from " + r.callerPackage + " (pid="
11765 + r.callingPid + ", uid=" + r.callingUid + ")"
11766 + " requires " + filter.requiredPermission
11767 + " due to registered receiver " + filter);
11768 skip = true;
11769 }
11770 }
11771 if (r.requiredPermission != null) {
11772 int perm = checkComponentPermission(r.requiredPermission,
11773 filter.receiverList.pid, filter.receiverList.uid, -1);
11774 if (perm != PackageManager.PERMISSION_GRANTED) {
11775 Log.w(TAG, "Permission Denial: receiving "
11776 + r.intent.toString()
11777 + " to " + filter.receiverList.app
11778 + " (pid=" + filter.receiverList.pid
11779 + ", uid=" + filter.receiverList.uid + ")"
11780 + " requires " + r.requiredPermission
11781 + " due to sender " + r.callerPackage
11782 + " (uid " + r.callingUid + ")");
11783 skip = true;
11784 }
11785 }
11786
11787 if (!skip) {
11788 // If this is not being sent as an ordered broadcast, then we
11789 // don't want to touch the fields that keep track of the current
11790 // state of ordered broadcasts.
11791 if (ordered) {
11792 r.receiver = filter.receiverList.receiver.asBinder();
11793 r.curFilter = filter;
11794 filter.receiverList.curBroadcast = r;
11795 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011796 if (filter.receiverList.app != null) {
11797 // Bump hosting application to no longer be in background
11798 // scheduling class. Note that we can't do that if there
11799 // isn't an app... but we can only be in that case for
11800 // things that directly call the IActivityManager API, which
11801 // are already core system stuff so don't matter for this.
11802 r.curApp = filter.receiverList.app;
11803 filter.receiverList.app.curReceiver = r;
11804 updateOomAdjLocked();
11805 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011806 }
11807 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011808 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011809 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011810 Log.i(TAG, "Delivering to " + filter.receiverList.app
11811 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011812 }
11813 performReceive(filter.receiverList.app, filter.receiverList.receiver,
11814 new Intent(r.intent), r.resultCode,
11815 r.resultData, r.resultExtras, r.ordered);
11816 if (ordered) {
11817 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
11818 }
11819 } catch (RemoteException e) {
11820 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
11821 if (ordered) {
11822 r.receiver = null;
11823 r.curFilter = null;
11824 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011825 if (filter.receiverList.app != null) {
11826 filter.receiverList.app.curReceiver = null;
11827 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011828 }
11829 }
11830 }
11831 }
11832
11833 private final void processNextBroadcast(boolean fromMsg) {
11834 synchronized(this) {
11835 BroadcastRecord r;
11836
11837 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
11838 + mParallelBroadcasts.size() + " broadcasts, "
11839 + mOrderedBroadcasts.size() + " serialized broadcasts");
11840
11841 updateCpuStats();
11842
11843 if (fromMsg) {
11844 mBroadcastsScheduled = false;
11845 }
11846
11847 // First, deliver any non-serialized broadcasts right away.
11848 while (mParallelBroadcasts.size() > 0) {
11849 r = mParallelBroadcasts.remove(0);
11850 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011851 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
11852 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011853 for (int i=0; i<N; i++) {
11854 Object target = r.receivers.get(i);
11855 if (DEBUG_BROADCAST) Log.v(TAG,
11856 "Delivering non-serialized to registered "
11857 + target + ": " + r);
11858 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
11859 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011860 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
11861 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011862 }
11863
11864 // Now take care of the next serialized one...
11865
11866 // If we are waiting for a process to come up to handle the next
11867 // broadcast, then do nothing at this point. Just in case, we
11868 // check that the process we're waiting for still exists.
11869 if (mPendingBroadcast != null) {
11870 Log.i(TAG, "processNextBroadcast: waiting for "
11871 + mPendingBroadcast.curApp);
11872
11873 boolean isDead;
11874 synchronized (mPidsSelfLocked) {
11875 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
11876 }
11877 if (!isDead) {
11878 // It's still alive, so keep waiting
11879 return;
11880 } else {
11881 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
11882 + " died before responding to broadcast");
11883 mPendingBroadcast = null;
11884 }
11885 }
11886
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011887 boolean looped = false;
11888
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011889 do {
11890 if (mOrderedBroadcasts.size() == 0) {
11891 // No more broadcasts pending, so all done!
11892 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011893 if (looped) {
11894 // If we had finished the last ordered broadcast, then
11895 // make sure all processes have correct oom and sched
11896 // adjustments.
11897 updateOomAdjLocked();
11898 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011899 return;
11900 }
11901 r = mOrderedBroadcasts.get(0);
11902 boolean forceReceive = false;
11903
11904 // Ensure that even if something goes awry with the timeout
11905 // detection, we catch "hung" broadcasts here, discard them,
11906 // and continue to make progress.
11907 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
11908 long now = SystemClock.uptimeMillis();
11909 if (r.dispatchTime > 0) {
11910 if ((numReceivers > 0) &&
11911 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
11912 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
11913 + " now=" + now
11914 + " dispatchTime=" + r.dispatchTime
11915 + " startTime=" + r.startTime
11916 + " intent=" + r.intent
11917 + " numReceivers=" + numReceivers
11918 + " nextReceiver=" + r.nextReceiver
11919 + " state=" + r.state);
11920 broadcastTimeout(); // forcibly finish this broadcast
11921 forceReceive = true;
11922 r.state = BroadcastRecord.IDLE;
11923 }
11924 }
11925
11926 if (r.state != BroadcastRecord.IDLE) {
11927 if (DEBUG_BROADCAST) Log.d(TAG,
11928 "processNextBroadcast() called when not idle (state="
11929 + r.state + ")");
11930 return;
11931 }
11932
11933 if (r.receivers == null || r.nextReceiver >= numReceivers
11934 || r.resultAbort || forceReceive) {
11935 // No more receivers for this broadcast! Send the final
11936 // result if requested...
11937 if (r.resultTo != null) {
11938 try {
11939 if (DEBUG_BROADCAST) {
11940 int seq = r.intent.getIntExtra("seq", -1);
11941 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
11942 + " seq=" + seq + " app=" + r.callerApp);
11943 }
11944 performReceive(r.callerApp, r.resultTo,
11945 new Intent(r.intent), r.resultCode,
11946 r.resultData, r.resultExtras, false);
11947 } catch (RemoteException e) {
11948 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
11949 }
11950 }
11951
11952 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
11953 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
11954
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011955 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
11956 + r);
11957
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011958 // ... and on to the next...
11959 mOrderedBroadcasts.remove(0);
11960 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011961 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011962 continue;
11963 }
11964 } while (r == null);
11965
11966 // Get the next receiver...
11967 int recIdx = r.nextReceiver++;
11968
11969 // Keep track of when this receiver started, and make sure there
11970 // is a timeout message pending to kill it if need be.
11971 r.startTime = SystemClock.uptimeMillis();
11972 if (recIdx == 0) {
11973 r.dispatchTime = r.startTime;
11974
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011975 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
11976 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011977 if (DEBUG_BROADCAST) Log.v(TAG,
11978 "Submitting BROADCAST_TIMEOUT_MSG for "
11979 + (r.startTime + BROADCAST_TIMEOUT));
11980 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11981 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11982 }
11983
11984 Object nextReceiver = r.receivers.get(recIdx);
11985 if (nextReceiver instanceof BroadcastFilter) {
11986 // Simple case: this is a registered receiver who gets
11987 // a direct call.
11988 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
11989 if (DEBUG_BROADCAST) Log.v(TAG,
11990 "Delivering serialized to registered "
11991 + filter + ": " + r);
11992 deliverToRegisteredReceiver(r, filter, r.ordered);
11993 if (r.receiver == null || !r.ordered) {
11994 // The receiver has already finished, so schedule to
11995 // process the next one.
11996 r.state = BroadcastRecord.IDLE;
11997 scheduleBroadcastsLocked();
11998 }
11999 return;
12000 }
12001
12002 // Hard case: need to instantiate the receiver, possibly
12003 // starting its application process to host it.
12004
12005 ResolveInfo info =
12006 (ResolveInfo)nextReceiver;
12007
12008 boolean skip = false;
12009 int perm = checkComponentPermission(info.activityInfo.permission,
12010 r.callingPid, r.callingUid,
12011 info.activityInfo.exported
12012 ? -1 : info.activityInfo.applicationInfo.uid);
12013 if (perm != PackageManager.PERMISSION_GRANTED) {
12014 Log.w(TAG, "Permission Denial: broadcasting "
12015 + r.intent.toString()
12016 + " from " + r.callerPackage + " (pid=" + r.callingPid
12017 + ", uid=" + r.callingUid + ")"
12018 + " requires " + info.activityInfo.permission
12019 + " due to receiver " + info.activityInfo.packageName
12020 + "/" + info.activityInfo.name);
12021 skip = true;
12022 }
12023 if (r.callingUid != Process.SYSTEM_UID &&
12024 r.requiredPermission != null) {
12025 try {
12026 perm = ActivityThread.getPackageManager().
12027 checkPermission(r.requiredPermission,
12028 info.activityInfo.applicationInfo.packageName);
12029 } catch (RemoteException e) {
12030 perm = PackageManager.PERMISSION_DENIED;
12031 }
12032 if (perm != PackageManager.PERMISSION_GRANTED) {
12033 Log.w(TAG, "Permission Denial: receiving "
12034 + r.intent + " to "
12035 + info.activityInfo.applicationInfo.packageName
12036 + " requires " + r.requiredPermission
12037 + " due to sender " + r.callerPackage
12038 + " (uid " + r.callingUid + ")");
12039 skip = true;
12040 }
12041 }
12042 if (r.curApp != null && r.curApp.crashing) {
12043 // If the target process is crashing, just skip it.
12044 skip = true;
12045 }
12046
12047 if (skip) {
12048 r.receiver = null;
12049 r.curFilter = null;
12050 r.state = BroadcastRecord.IDLE;
12051 scheduleBroadcastsLocked();
12052 return;
12053 }
12054
12055 r.state = BroadcastRecord.APP_RECEIVE;
12056 String targetProcess = info.activityInfo.processName;
12057 r.curComponent = new ComponentName(
12058 info.activityInfo.applicationInfo.packageName,
12059 info.activityInfo.name);
12060 r.curReceiver = info.activityInfo;
12061
12062 // Is this receiver's application already running?
12063 ProcessRecord app = getProcessRecordLocked(targetProcess,
12064 info.activityInfo.applicationInfo.uid);
12065 if (app != null && app.thread != null) {
12066 try {
12067 processCurBroadcastLocked(r, app);
12068 return;
12069 } catch (RemoteException e) {
12070 Log.w(TAG, "Exception when sending broadcast to "
12071 + r.curComponent, e);
12072 }
12073
12074 // If a dead object exception was thrown -- fall through to
12075 // restart the application.
12076 }
12077
12078 // Not running -- get it started, and enqueue this history record
12079 // to be executed when the app comes up.
12080 if ((r.curApp=startProcessLocked(targetProcess,
12081 info.activityInfo.applicationInfo, true,
12082 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
12083 "broadcast", r.curComponent)) == null) {
12084 // Ah, this recipient is unavailable. Finish it if necessary,
12085 // and mark the broadcast record as ready for the next.
12086 Log.w(TAG, "Unable to launch app "
12087 + info.activityInfo.applicationInfo.packageName + "/"
12088 + info.activityInfo.applicationInfo.uid + " for broadcast "
12089 + r.intent + ": process is bad");
12090 logBroadcastReceiverDiscard(r);
12091 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
12092 r.resultExtras, r.resultAbort, true);
12093 scheduleBroadcastsLocked();
12094 r.state = BroadcastRecord.IDLE;
12095 return;
12096 }
12097
12098 mPendingBroadcast = r;
12099 }
12100 }
12101
12102 // =========================================================
12103 // INSTRUMENTATION
12104 // =========================================================
12105
12106 public boolean startInstrumentation(ComponentName className,
12107 String profileFile, int flags, Bundle arguments,
12108 IInstrumentationWatcher watcher) {
12109 // Refuse possible leaked file descriptors
12110 if (arguments != null && arguments.hasFileDescriptors()) {
12111 throw new IllegalArgumentException("File descriptors passed in Bundle");
12112 }
12113
12114 synchronized(this) {
12115 InstrumentationInfo ii = null;
12116 ApplicationInfo ai = null;
12117 try {
12118 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012119 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012120 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070012121 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012122 } catch (PackageManager.NameNotFoundException e) {
12123 }
12124 if (ii == null) {
12125 reportStartInstrumentationFailure(watcher, className,
12126 "Unable to find instrumentation info for: " + className);
12127 return false;
12128 }
12129 if (ai == null) {
12130 reportStartInstrumentationFailure(watcher, className,
12131 "Unable to find instrumentation target package: " + ii.targetPackage);
12132 return false;
12133 }
12134
12135 int match = mContext.getPackageManager().checkSignatures(
12136 ii.targetPackage, ii.packageName);
12137 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
12138 String msg = "Permission Denial: starting instrumentation "
12139 + className + " from pid="
12140 + Binder.getCallingPid()
12141 + ", uid=" + Binder.getCallingPid()
12142 + " not allowed because package " + ii.packageName
12143 + " does not have a signature matching the target "
12144 + ii.targetPackage;
12145 reportStartInstrumentationFailure(watcher, className, msg);
12146 throw new SecurityException(msg);
12147 }
12148
12149 final long origId = Binder.clearCallingIdentity();
12150 uninstallPackageLocked(ii.targetPackage, -1, true);
12151 ProcessRecord app = addAppLocked(ai);
12152 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012153 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012154 app.instrumentationProfileFile = profileFile;
12155 app.instrumentationArguments = arguments;
12156 app.instrumentationWatcher = watcher;
12157 app.instrumentationResultClass = className;
12158 Binder.restoreCallingIdentity(origId);
12159 }
12160
12161 return true;
12162 }
12163
12164 /**
12165 * Report errors that occur while attempting to start Instrumentation. Always writes the
12166 * error to the logs, but if somebody is watching, send the report there too. This enables
12167 * the "am" command to report errors with more information.
12168 *
12169 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
12170 * @param cn The component name of the instrumentation.
12171 * @param report The error report.
12172 */
12173 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
12174 ComponentName cn, String report) {
12175 Log.w(TAG, report);
12176 try {
12177 if (watcher != null) {
12178 Bundle results = new Bundle();
12179 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
12180 results.putString("Error", report);
12181 watcher.instrumentationStatus(cn, -1, results);
12182 }
12183 } catch (RemoteException e) {
12184 Log.w(TAG, e);
12185 }
12186 }
12187
12188 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
12189 if (app.instrumentationWatcher != null) {
12190 try {
12191 // NOTE: IInstrumentationWatcher *must* be oneway here
12192 app.instrumentationWatcher.instrumentationFinished(
12193 app.instrumentationClass,
12194 resultCode,
12195 results);
12196 } catch (RemoteException e) {
12197 }
12198 }
12199 app.instrumentationWatcher = null;
12200 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070012201 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012202 app.instrumentationProfileFile = null;
12203 app.instrumentationArguments = null;
12204
12205 uninstallPackageLocked(app.processName, -1, false);
12206 }
12207
12208 public void finishInstrumentation(IApplicationThread target,
12209 int resultCode, Bundle results) {
12210 // Refuse possible leaked file descriptors
12211 if (results != null && results.hasFileDescriptors()) {
12212 throw new IllegalArgumentException("File descriptors passed in Intent");
12213 }
12214
12215 synchronized(this) {
12216 ProcessRecord app = getRecordForAppLocked(target);
12217 if (app == null) {
12218 Log.w(TAG, "finishInstrumentation: no app for " + target);
12219 return;
12220 }
12221 final long origId = Binder.clearCallingIdentity();
12222 finishInstrumentationLocked(app, resultCode, results);
12223 Binder.restoreCallingIdentity(origId);
12224 }
12225 }
12226
12227 // =========================================================
12228 // CONFIGURATION
12229 // =========================================================
12230
12231 public ConfigurationInfo getDeviceConfigurationInfo() {
12232 ConfigurationInfo config = new ConfigurationInfo();
12233 synchronized (this) {
12234 config.reqTouchScreen = mConfiguration.touchscreen;
12235 config.reqKeyboardType = mConfiguration.keyboard;
12236 config.reqNavigation = mConfiguration.navigation;
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012237 if (mConfiguration.navigation == Configuration.NAVIGATION_DPAD
12238 || mConfiguration.navigation == Configuration.NAVIGATION_TRACKBALL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012239 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
12240 }
Dianne Hackbornfae76f52009-07-16 13:41:23 -070012241 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED
12242 && mConfiguration.keyboard != Configuration.KEYBOARD_NOKEYS) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012243 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
12244 }
Jack Palevichb90d28c2009-07-22 15:35:24 -070012245 config.reqGlEsVersion = GL_ES_VERSION;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012246 }
12247 return config;
12248 }
12249
12250 public Configuration getConfiguration() {
12251 Configuration ci;
12252 synchronized(this) {
12253 ci = new Configuration(mConfiguration);
12254 }
12255 return ci;
12256 }
12257
12258 public void updateConfiguration(Configuration values) {
12259 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
12260 "updateConfiguration()");
12261
12262 synchronized(this) {
12263 if (values == null && mWindowManager != null) {
12264 // sentinel: fetch the current configuration from the window manager
12265 values = mWindowManager.computeNewConfiguration();
12266 }
12267
12268 final long origId = Binder.clearCallingIdentity();
12269 updateConfigurationLocked(values, null);
12270 Binder.restoreCallingIdentity(origId);
12271 }
12272 }
12273
12274 /**
12275 * Do either or both things: (1) change the current configuration, and (2)
12276 * make sure the given activity is running with the (now) current
12277 * configuration. Returns true if the activity has been left running, or
12278 * false if <var>starting</var> is being destroyed to match the new
12279 * configuration.
12280 */
12281 public boolean updateConfigurationLocked(Configuration values,
12282 HistoryRecord starting) {
12283 int changes = 0;
12284
12285 boolean kept = true;
12286
12287 if (values != null) {
12288 Configuration newConfig = new Configuration(mConfiguration);
12289 changes = newConfig.updateFrom(values);
12290 if (changes != 0) {
12291 if (DEBUG_SWITCH) {
12292 Log.i(TAG, "Updating configuration to: " + values);
12293 }
12294
12295 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
12296
12297 if (values.locale != null) {
12298 saveLocaleLocked(values.locale,
12299 !values.locale.equals(mConfiguration.locale),
12300 values.userSetLocale);
12301 }
12302
12303 mConfiguration = newConfig;
12304
12305 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
12306 msg.obj = new Configuration(mConfiguration);
12307 mHandler.sendMessage(msg);
12308
12309 final int N = mLRUProcesses.size();
12310 for (int i=0; i<N; i++) {
12311 ProcessRecord app = mLRUProcesses.get(i);
12312 try {
12313 if (app.thread != null) {
12314 app.thread.scheduleConfigurationChanged(mConfiguration);
12315 }
12316 } catch (Exception e) {
12317 }
12318 }
12319 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
12320 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
12321 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070012322
12323 AttributeCache ac = AttributeCache.instance();
12324 if (ac != null) {
12325 ac.updateConfiguration(mConfiguration);
12326 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012327 }
12328 }
12329
12330 if (changes != 0 && starting == null) {
12331 // If the configuration changed, and the caller is not already
12332 // in the process of starting an activity, then find the top
12333 // activity to check if its configuration needs to change.
12334 starting = topRunningActivityLocked(null);
12335 }
12336
12337 if (starting != null) {
12338 kept = ensureActivityConfigurationLocked(starting, changes);
12339 if (kept) {
12340 // If this didn't result in the starting activity being
12341 // destroyed, then we need to make sure at this point that all
12342 // other activities are made visible.
12343 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
12344 + ", ensuring others are correct.");
12345 ensureActivitiesVisibleLocked(starting, changes);
12346 }
12347 }
12348
12349 return kept;
12350 }
12351
12352 private final boolean relaunchActivityLocked(HistoryRecord r,
12353 int changes, boolean andResume) {
12354 List<ResultInfo> results = null;
12355 List<Intent> newIntents = null;
12356 if (andResume) {
12357 results = r.results;
12358 newIntents = r.newIntents;
12359 }
12360 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
12361 + " with results=" + results + " newIntents=" + newIntents
12362 + " andResume=" + andResume);
12363 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
12364 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
12365 r.task.taskId, r.shortComponentName);
12366
12367 r.startFreezingScreenLocked(r.app, 0);
12368
12369 try {
12370 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12371 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
12372 changes, !andResume);
12373 // Note: don't need to call pauseIfSleepingLocked() here, because
12374 // the caller will only pass in 'andResume' if this activity is
12375 // currently resumed, which implies we aren't sleeping.
12376 } catch (RemoteException e) {
12377 return false;
12378 }
12379
12380 if (andResume) {
12381 r.results = null;
12382 r.newIntents = null;
12383 }
12384
12385 return true;
12386 }
12387
12388 /**
12389 * Make sure the given activity matches the current configuration. Returns
12390 * false if the activity had to be destroyed. Returns true if the
12391 * configuration is the same, or the activity will remain running as-is
12392 * for whatever reason. Ensures the HistoryRecord is updated with the
12393 * correct configuration and all other bookkeeping is handled.
12394 */
12395 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
12396 int globalChanges) {
12397 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
12398
12399 // Short circuit: if the two configurations are the exact same
12400 // object (the common case), then there is nothing to do.
12401 Configuration newConfig = mConfiguration;
12402 if (r.configuration == newConfig) {
12403 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
12404 return true;
12405 }
12406
12407 // We don't worry about activities that are finishing.
12408 if (r.finishing) {
12409 if (DEBUG_SWITCH) Log.i(TAG,
12410 "Configuration doesn't matter in finishing " + r);
12411 r.stopFreezingScreenLocked(false);
12412 return true;
12413 }
12414
12415 // Okay we now are going to make this activity have the new config.
12416 // But then we need to figure out how it needs to deal with that.
12417 Configuration oldConfig = r.configuration;
12418 r.configuration = newConfig;
12419
12420 // If the activity isn't currently running, just leave the new
12421 // configuration and it will pick that up next time it starts.
12422 if (r.app == null || r.app.thread == null) {
12423 if (DEBUG_SWITCH) Log.i(TAG,
12424 "Configuration doesn't matter not running " + r);
12425 r.stopFreezingScreenLocked(false);
12426 return true;
12427 }
12428
12429 // If the activity isn't persistent, there is a chance we will
12430 // need to restart it.
12431 if (!r.persistent) {
12432
12433 // Figure out what has changed between the two configurations.
12434 int changes = oldConfig.diff(newConfig);
12435 if (DEBUG_SWITCH) {
12436 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
12437 + Integer.toHexString(changes) + ", handles=0x"
12438 + Integer.toHexString(r.info.configChanges));
12439 }
12440 if ((changes&(~r.info.configChanges)) != 0) {
12441 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12442 r.configChangeFlags |= changes;
12443 r.startFreezingScreenLocked(r.app, globalChanges);
12444 if (r.app == null || r.app.thread == null) {
12445 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
12446 destroyActivityLocked(r, true);
12447 } else if (r.state == ActivityState.PAUSING) {
12448 // A little annoying: we are waiting for this activity to
12449 // finish pausing. Let's not do anything now, but just
12450 // flag that it needs to be restarted when done pausing.
12451 r.configDestroy = true;
12452 return true;
12453 } else if (r.state == ActivityState.RESUMED) {
12454 // Try to optimize this case: the configuration is changing
12455 // and we need to restart the top, resumed activity.
12456 // Instead of doing the normal handshaking, just say
12457 // "restart!".
12458 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12459 relaunchActivityLocked(r, r.configChangeFlags, true);
12460 r.configChangeFlags = 0;
12461 } else {
12462 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
12463 relaunchActivityLocked(r, r.configChangeFlags, false);
12464 r.configChangeFlags = 0;
12465 }
12466
12467 // All done... tell the caller we weren't able to keep this
12468 // activity around.
12469 return false;
12470 }
12471 }
12472
12473 // Default case: the activity can handle this new configuration, so
12474 // hand it over. Note that we don't need to give it the new
12475 // configuration, since we always send configuration changes to all
12476 // process when they happen so it can just use whatever configuration
12477 // it last got.
12478 if (r.app != null && r.app.thread != null) {
12479 try {
12480 r.app.thread.scheduleActivityConfigurationChanged(r);
12481 } catch (RemoteException e) {
12482 // If process died, whatever.
12483 }
12484 }
12485 r.stopFreezingScreenLocked(false);
12486
12487 return true;
12488 }
12489
12490 /**
12491 * Save the locale. You must be inside a synchronized (this) block.
12492 */
12493 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12494 if(isDiff) {
12495 SystemProperties.set("user.language", l.getLanguage());
12496 SystemProperties.set("user.region", l.getCountry());
12497 }
12498
12499 if(isPersist) {
12500 SystemProperties.set("persist.sys.language", l.getLanguage());
12501 SystemProperties.set("persist.sys.country", l.getCountry());
12502 SystemProperties.set("persist.sys.localevar", l.getVariant());
12503 }
12504 }
12505
12506 // =========================================================
12507 // LIFETIME MANAGEMENT
12508 // =========================================================
12509
12510 private final int computeOomAdjLocked(
12511 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12512 if (mAdjSeq == app.adjSeq) {
12513 // This adjustment has already been computed.
12514 return app.curAdj;
12515 }
12516
12517 if (app.thread == null) {
12518 app.adjSeq = mAdjSeq;
12519 return (app.curAdj=EMPTY_APP_ADJ);
12520 }
12521
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012522 if (app.maxAdj <= FOREGROUND_APP_ADJ) {
12523 // The max adjustment doesn't allow this app to be anything
12524 // below foreground, so it is not worth doing work for it.
12525 app.adjType = "fixed";
12526 app.adjSeq = mAdjSeq;
12527 app.curRawAdj = app.maxAdj;
12528 app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
12529 return (app.curAdj=app.maxAdj);
12530 }
12531
12532 app.adjSource = null;
12533 app.adjTarget = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012534
The Android Open Source Project4df24232009-03-05 14:34:35 -080012535 // Determine the importance of the process, starting with most
12536 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012537 int adj;
12538 int N;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012539 if (app == TOP_APP) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012540 // The last app on the list is the foreground app.
12541 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012542 app.adjType = "top";
12543 } else if (app.instrumentationClass != null) {
12544 // Don't want to kill running instrumentation.
12545 adj = FOREGROUND_APP_ADJ;
12546 app.adjType = "instr";
12547 } else if (app.persistentActivities > 0) {
12548 // Special persistent activities... shouldn't be used these days.
12549 adj = FOREGROUND_APP_ADJ;
12550 app.adjType = "pers";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012551 } else if (app.curReceiver != null ||
12552 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12553 // An app that is currently receiving a broadcast also
12554 // counts as being in the foreground.
12555 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012556 app.adjType = "broadcast";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012557 } else if (app.executingServices.size() > 0) {
12558 // An app that is currently executing a service callback also
12559 // counts as being in the foreground.
12560 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012561 app.adjType = "exec-service";
12562 } else if (app.foregroundServices) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012563 // The user is aware of this app, so make it visible.
12564 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012565 app.adjType = "foreground-service";
12566 } else if (app.forcingToForeground != null) {
12567 // The user is aware of this app, so make it visible.
12568 adj = VISIBLE_APP_ADJ;
12569 app.adjType = "force-foreground";
12570 app.adjSource = app.forcingToForeground;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012571 } else if (app == mHomeProcess) {
12572 // This process is hosting what we currently consider to be the
12573 // home app, so we don't want to let it go into the background.
12574 adj = HOME_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012575 app.adjType = "home";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012576 } else if ((N=app.activities.size()) != 0) {
12577 // This app is in the background with paused activities.
12578 adj = hiddenAdj;
12579 for (int j=0; j<N; j++) {
12580 if (((HistoryRecord)app.activities.get(j)).visible) {
12581 // This app has a visible activity!
12582 adj = VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012583 app.adjType = "visible";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012584 break;
12585 }
12586 }
12587 } else {
12588 // A very not-needed process.
12589 adj = EMPTY_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012590 app.adjType = "empty";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012591 }
12592
The Android Open Source Project4df24232009-03-05 14:34:35 -080012593 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012594 // there are applications dependent on our services or providers, but
12595 // this gives us a baseline and makes sure we don't get into an
12596 // infinite recursion.
12597 app.adjSeq = mAdjSeq;
12598 app.curRawAdj = adj;
12599 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12600
Christopher Tate6fa95972009-06-05 18:43:55 -070012601 if (mBackupTarget != null && app == mBackupTarget.app) {
12602 // If possible we want to avoid killing apps while they're being backed up
12603 if (adj > BACKUP_APP_ADJ) {
12604 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12605 adj = BACKUP_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012606 app.adjType = "backup";
Christopher Tate6fa95972009-06-05 18:43:55 -070012607 }
12608 }
12609
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012610 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12611 // If this process has active services running in it, we would
12612 // like to avoid killing it unless it would prevent the current
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012613 // application from running. By default we put the process in
12614 // with the rest of the background processes; as we scan through
12615 // its services we may bump it up from there.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012616 if (adj > hiddenAdj) {
12617 adj = hiddenAdj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012618 app.adjType = "services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012619 }
12620 final long now = SystemClock.uptimeMillis();
12621 // This process is more important if the top activity is
12622 // bound to the service.
12623 Iterator jt = app.services.iterator();
12624 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12625 ServiceRecord s = (ServiceRecord)jt.next();
12626 if (s.startRequested) {
12627 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12628 // This service has seen some activity within
12629 // recent memory, so we will keep its process ahead
12630 // of the background processes.
12631 if (adj > SECONDARY_SERVER_ADJ) {
12632 adj = SECONDARY_SERVER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012633 app.adjType = "started-services";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012634 }
12635 }
12636 }
12637 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12638 Iterator<ConnectionRecord> kt
12639 = s.connections.values().iterator();
12640 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12641 // XXX should compute this based on the max of
12642 // all connected clients.
12643 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012644 if (cr.binding.client == app) {
12645 // Binding to ourself is not interesting.
12646 continue;
12647 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012648 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12649 ProcessRecord client = cr.binding.client;
12650 int myHiddenAdj = hiddenAdj;
12651 if (myHiddenAdj > client.hiddenAdj) {
12652 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12653 myHiddenAdj = client.hiddenAdj;
12654 } else {
12655 myHiddenAdj = VISIBLE_APP_ADJ;
12656 }
12657 }
12658 int clientAdj = computeOomAdjLocked(
12659 client, myHiddenAdj, TOP_APP);
12660 if (adj > clientAdj) {
12661 adj = clientAdj > VISIBLE_APP_ADJ
12662 ? clientAdj : VISIBLE_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012663 app.adjType = "service";
12664 app.adjSource = cr.binding.client;
12665 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012666 }
12667 }
12668 HistoryRecord a = cr.activity;
12669 //if (a != null) {
12670 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
12671 //}
12672 if (a != null && adj > FOREGROUND_APP_ADJ &&
12673 (a.state == ActivityState.RESUMED
12674 || a.state == ActivityState.PAUSING)) {
12675 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012676 app.adjType = "service";
12677 app.adjSource = a;
12678 app.adjTarget = s.serviceInfo.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012679 }
12680 }
12681 }
12682 }
12683 }
12684
12685 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12686 // If this process has published any content providers, then
12687 // its adjustment makes it at least as important as any of the
12688 // processes using those providers, and no less important than
12689 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
12690 if (adj > CONTENT_PROVIDER_ADJ) {
12691 adj = CONTENT_PROVIDER_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012692 app.adjType = "pub-providers";
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012693 }
12694 Iterator jt = app.pubProviders.values().iterator();
12695 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12696 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
12697 if (cpr.clients.size() != 0) {
12698 Iterator<ProcessRecord> kt = cpr.clients.iterator();
12699 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12700 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012701 if (client == app) {
12702 // Being our own client is not interesting.
12703 continue;
12704 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012705 int myHiddenAdj = hiddenAdj;
12706 if (myHiddenAdj > client.hiddenAdj) {
12707 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
12708 myHiddenAdj = client.hiddenAdj;
12709 } else {
12710 myHiddenAdj = FOREGROUND_APP_ADJ;
12711 }
12712 }
12713 int clientAdj = computeOomAdjLocked(
12714 client, myHiddenAdj, TOP_APP);
12715 if (adj > clientAdj) {
12716 adj = clientAdj > FOREGROUND_APP_ADJ
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012717 ? clientAdj : FOREGROUND_APP_ADJ;
12718 app.adjType = "provider";
12719 app.adjSource = client;
12720 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012721 }
12722 }
12723 }
12724 // If the provider has external (non-framework) process
12725 // dependencies, ensure that its adjustment is at least
12726 // FOREGROUND_APP_ADJ.
12727 if (cpr.externals != 0) {
12728 if (adj > FOREGROUND_APP_ADJ) {
12729 adj = FOREGROUND_APP_ADJ;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012730 app.adjType = "provider";
12731 app.adjTarget = cpr.info.name;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012732 }
12733 }
12734 }
12735 }
12736
12737 app.curRawAdj = adj;
12738
12739 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
12740 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
12741 if (adj > app.maxAdj) {
12742 adj = app.maxAdj;
12743 }
12744
12745 app.curAdj = adj;
Dianne Hackbornde42bb62009-08-05 12:26:15 -070012746 app.curSchedGroup = adj > VISIBLE_APP_ADJ
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012747 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
12748 : Process.THREAD_GROUP_DEFAULT;
12749
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012750 return adj;
12751 }
12752
12753 /**
12754 * Ask a given process to GC right now.
12755 */
12756 final void performAppGcLocked(ProcessRecord app) {
12757 try {
12758 app.lastRequestedGc = SystemClock.uptimeMillis();
12759 if (app.thread != null) {
12760 app.thread.processInBackground();
12761 }
12762 } catch (Exception e) {
12763 // whatever.
12764 }
12765 }
12766
12767 /**
12768 * Returns true if things are idle enough to perform GCs.
12769 */
12770 private final boolean canGcNow() {
12771 return mParallelBroadcasts.size() == 0
12772 && mOrderedBroadcasts.size() == 0
12773 && (mSleeping || (mResumedActivity != null &&
12774 mResumedActivity.idle));
12775 }
12776
12777 /**
12778 * Perform GCs on all processes that are waiting for it, but only
12779 * if things are idle.
12780 */
12781 final void performAppGcsLocked() {
12782 final int N = mProcessesToGc.size();
12783 if (N <= 0) {
12784 return;
12785 }
12786 if (canGcNow()) {
12787 while (mProcessesToGc.size() > 0) {
12788 ProcessRecord proc = mProcessesToGc.remove(0);
12789 if (proc.curRawAdj > VISIBLE_APP_ADJ) {
12790 // To avoid spamming the system, we will GC processes one
12791 // at a time, waiting a few seconds between each.
12792 performAppGcLocked(proc);
12793 scheduleAppGcsLocked();
12794 return;
12795 }
12796 }
12797 }
12798 }
12799
12800 /**
12801 * If all looks good, perform GCs on all processes waiting for them.
12802 */
12803 final void performAppGcsIfAppropriateLocked() {
12804 if (canGcNow()) {
12805 performAppGcsLocked();
12806 return;
12807 }
12808 // Still not idle, wait some more.
12809 scheduleAppGcsLocked();
12810 }
12811
12812 /**
12813 * Schedule the execution of all pending app GCs.
12814 */
12815 final void scheduleAppGcsLocked() {
12816 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
12817 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
12818 mHandler.sendMessageDelayed(msg, GC_TIMEOUT);
12819 }
12820
12821 /**
12822 * Set up to ask a process to GC itself. This will either do it
12823 * immediately, or put it on the list of processes to gc the next
12824 * time things are idle.
12825 */
12826 final void scheduleAppGcLocked(ProcessRecord app) {
12827 long now = SystemClock.uptimeMillis();
12828 if ((app.lastRequestedGc+5000) > now) {
12829 return;
12830 }
12831 if (!mProcessesToGc.contains(app)) {
12832 mProcessesToGc.add(app);
12833 scheduleAppGcsLocked();
12834 }
12835 }
12836
12837 private final boolean updateOomAdjLocked(
12838 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12839 app.hiddenAdj = hiddenAdj;
12840
12841 if (app.thread == null) {
12842 return true;
12843 }
12844
12845 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
12846
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012847 if (app.pid != 0 && app.pid != MY_PID) {
12848 if (app.curRawAdj != app.setRawAdj) {
12849 if (app.curRawAdj > FOREGROUND_APP_ADJ
12850 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
12851 // If this app is transitioning from foreground to
12852 // non-foreground, have it do a gc.
12853 scheduleAppGcLocked(app);
12854 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
12855 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
12856 // Likewise do a gc when an app is moving in to the
12857 // background (such as a service stopping).
12858 scheduleAppGcLocked(app);
12859 }
12860 app.setRawAdj = app.curRawAdj;
12861 }
12862 if (adj != app.setAdj) {
12863 if (Process.setOomAdj(app.pid, adj)) {
12864 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
12865 TAG, "Set app " + app.processName +
12866 " oom adj to " + adj);
12867 app.setAdj = adj;
12868 } else {
12869 return false;
12870 }
12871 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012872 if (app.setSchedGroup != app.curSchedGroup) {
12873 app.setSchedGroup = app.curSchedGroup;
12874 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
12875 "Setting process group of " + app.processName
12876 + " to " + app.curSchedGroup);
12877 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070012878 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012879 try {
12880 Process.setProcessGroup(app.pid, app.curSchedGroup);
12881 } catch (Exception e) {
12882 Log.w(TAG, "Failed setting process group of " + app.pid
12883 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070012884 e.printStackTrace();
12885 } finally {
12886 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012887 }
12888 }
12889 if (false) {
12890 if (app.thread != null) {
12891 try {
12892 app.thread.setSchedulingGroup(app.curSchedGroup);
12893 } catch (RemoteException e) {
12894 }
12895 }
12896 }
12897 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012898 }
12899
12900 return true;
12901 }
12902
12903 private final HistoryRecord resumedAppLocked() {
12904 HistoryRecord resumedActivity = mResumedActivity;
12905 if (resumedActivity == null || resumedActivity.app == null) {
12906 resumedActivity = mPausingActivity;
12907 if (resumedActivity == null || resumedActivity.app == null) {
12908 resumedActivity = topRunningActivityLocked(null);
12909 }
12910 }
12911 return resumedActivity;
12912 }
12913
12914 private final boolean updateOomAdjLocked(ProcessRecord app) {
12915 final HistoryRecord TOP_ACT = resumedAppLocked();
12916 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12917 int curAdj = app.curAdj;
12918 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12919 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12920
12921 mAdjSeq++;
12922
12923 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
12924 if (res) {
12925 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12926 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12927 if (nowHidden != wasHidden) {
12928 // Changed to/from hidden state, so apps after it in the LRU
12929 // list may also be changed.
12930 updateOomAdjLocked();
12931 }
12932 }
12933 return res;
12934 }
12935
12936 private final boolean updateOomAdjLocked() {
12937 boolean didOomAdj = true;
12938 final HistoryRecord TOP_ACT = resumedAppLocked();
12939 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12940
12941 if (false) {
12942 RuntimeException e = new RuntimeException();
12943 e.fillInStackTrace();
12944 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
12945 }
12946
12947 mAdjSeq++;
12948
12949 // First try updating the OOM adjustment for each of the
12950 // application processes based on their current state.
12951 int i = mLRUProcesses.size();
12952 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
12953 while (i > 0) {
12954 i--;
12955 ProcessRecord app = mLRUProcesses.get(i);
12956 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
12957 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
12958 && app.curAdj == curHiddenAdj) {
12959 curHiddenAdj++;
12960 }
12961 } else {
12962 didOomAdj = false;
12963 }
12964 }
12965
12966 // todo: for now pretend like OOM ADJ didn't work, because things
12967 // aren't behaving as expected on Linux -- it's not killing processes.
12968 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
12969 }
12970
12971 private final void trimApplications() {
12972 synchronized (this) {
12973 int i;
12974
12975 // First remove any unused application processes whose package
12976 // has been removed.
12977 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
12978 final ProcessRecord app = mRemovedProcesses.get(i);
12979 if (app.activities.size() == 0
12980 && app.curReceiver == null && app.services.size() == 0) {
12981 Log.i(
12982 TAG, "Exiting empty application process "
12983 + app.processName + " ("
12984 + (app.thread != null ? app.thread.asBinder() : null)
12985 + ")\n");
12986 if (app.pid > 0 && app.pid != MY_PID) {
12987 Process.killProcess(app.pid);
12988 } else {
12989 try {
12990 app.thread.scheduleExit();
12991 } catch (Exception e) {
12992 // Ignore exceptions.
12993 }
12994 }
12995 cleanUpApplicationRecordLocked(app, false, -1);
12996 mRemovedProcesses.remove(i);
12997
12998 if (app.persistent) {
12999 if (app.persistent) {
13000 addAppLocked(app.info);
13001 }
13002 }
13003 }
13004 }
13005
13006 // Now try updating the OOM adjustment for each of the
13007 // application processes based on their current state.
13008 // If the setOomAdj() API is not supported, then go with our
13009 // back-up plan...
13010 if (!updateOomAdjLocked()) {
13011
13012 // Count how many processes are running services.
13013 int numServiceProcs = 0;
13014 for (i=mLRUProcesses.size()-1; i>=0; i--) {
13015 final ProcessRecord app = mLRUProcesses.get(i);
13016
13017 if (app.persistent || app.services.size() != 0
13018 || app.curReceiver != null
13019 || app.persistentActivities > 0) {
13020 // Don't count processes holding services against our
13021 // maximum process count.
13022 if (localLOGV) Log.v(
13023 TAG, "Not trimming app " + app + " with services: "
13024 + app.services);
13025 numServiceProcs++;
13026 }
13027 }
13028
13029 int curMaxProcs = mProcessLimit;
13030 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
13031 if (mAlwaysFinishActivities) {
13032 curMaxProcs = 1;
13033 }
13034 curMaxProcs += numServiceProcs;
13035
13036 // Quit as many processes as we can to get down to the desired
13037 // process count. First remove any processes that no longer
13038 // have activites running in them.
13039 for ( i=0;
13040 i<mLRUProcesses.size()
13041 && mLRUProcesses.size() > curMaxProcs;
13042 i++) {
13043 final ProcessRecord app = mLRUProcesses.get(i);
13044 // Quit an application only if it is not currently
13045 // running any activities.
13046 if (!app.persistent && app.activities.size() == 0
13047 && app.curReceiver == null && app.services.size() == 0) {
13048 Log.i(
13049 TAG, "Exiting empty application process "
13050 + app.processName + " ("
13051 + (app.thread != null ? app.thread.asBinder() : null)
13052 + ")\n");
13053 if (app.pid > 0 && app.pid != MY_PID) {
13054 Process.killProcess(app.pid);
13055 } else {
13056 try {
13057 app.thread.scheduleExit();
13058 } catch (Exception e) {
13059 // Ignore exceptions.
13060 }
13061 }
13062 // todo: For now we assume the application is not buggy
13063 // or evil, and will quit as a result of our request.
13064 // Eventually we need to drive this off of the death
13065 // notification, and kill the process if it takes too long.
13066 cleanUpApplicationRecordLocked(app, false, i);
13067 i--;
13068 }
13069 }
13070
13071 // If we still have too many processes, now from the least
13072 // recently used process we start finishing activities.
13073 if (Config.LOGV) Log.v(
13074 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
13075 " of " + curMaxProcs + " processes");
13076 for ( i=0;
13077 i<mLRUProcesses.size()
13078 && mLRUProcesses.size() > curMaxProcs;
13079 i++) {
13080 final ProcessRecord app = mLRUProcesses.get(i);
13081 // Quit the application only if we have a state saved for
13082 // all of its activities.
13083 boolean canQuit = !app.persistent && app.curReceiver == null
13084 && app.services.size() == 0
13085 && app.persistentActivities == 0;
13086 int NUMA = app.activities.size();
13087 int j;
13088 if (Config.LOGV) Log.v(
13089 TAG, "Looking to quit " + app.processName);
13090 for (j=0; j<NUMA && canQuit; j++) {
13091 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13092 if (Config.LOGV) Log.v(
13093 TAG, " " + r.intent.getComponent().flattenToShortString()
13094 + ": frozen=" + r.haveState + ", visible=" + r.visible);
13095 canQuit = (r.haveState || !r.stateNotNeeded)
13096 && !r.visible && r.stopped;
13097 }
13098 if (canQuit) {
13099 // Finish all of the activities, and then the app itself.
13100 for (j=0; j<NUMA; j++) {
13101 HistoryRecord r = (HistoryRecord)app.activities.get(j);
13102 if (!r.finishing) {
13103 destroyActivityLocked(r, false);
13104 }
13105 r.resultTo = null;
13106 }
13107 Log.i(TAG, "Exiting application process "
13108 + app.processName + " ("
13109 + (app.thread != null ? app.thread.asBinder() : null)
13110 + ")\n");
13111 if (app.pid > 0 && app.pid != MY_PID) {
13112 Process.killProcess(app.pid);
13113 } else {
13114 try {
13115 app.thread.scheduleExit();
13116 } catch (Exception e) {
13117 // Ignore exceptions.
13118 }
13119 }
13120 // todo: For now we assume the application is not buggy
13121 // or evil, and will quit as a result of our request.
13122 // Eventually we need to drive this off of the death
13123 // notification, and kill the process if it takes too long.
13124 cleanUpApplicationRecordLocked(app, false, i);
13125 i--;
13126 //dump();
13127 }
13128 }
13129
13130 }
13131
13132 int curMaxActivities = MAX_ACTIVITIES;
13133 if (mAlwaysFinishActivities) {
13134 curMaxActivities = 1;
13135 }
13136
13137 // Finally, if there are too many activities now running, try to
13138 // finish as many as we can to get back down to the limit.
13139 for ( i=0;
13140 i<mLRUActivities.size()
13141 && mLRUActivities.size() > curMaxActivities;
13142 i++) {
13143 final HistoryRecord r
13144 = (HistoryRecord)mLRUActivities.get(i);
13145
13146 // We can finish this one if we have its icicle saved and
13147 // it is not persistent.
13148 if ((r.haveState || !r.stateNotNeeded) && !r.visible
13149 && r.stopped && !r.persistent && !r.finishing) {
13150 final int origSize = mLRUActivities.size();
13151 destroyActivityLocked(r, true);
13152
13153 // This will remove it from the LRU list, so keep
13154 // our index at the same value. Note that this check to
13155 // see if the size changes is just paranoia -- if
13156 // something unexpected happens, we don't want to end up
13157 // in an infinite loop.
13158 if (origSize > mLRUActivities.size()) {
13159 i--;
13160 }
13161 }
13162 }
13163 }
13164 }
13165
13166 /** This method sends the specified signal to each of the persistent apps */
13167 public void signalPersistentProcesses(int sig) throws RemoteException {
13168 if (sig != Process.SIGNAL_USR1) {
13169 throw new SecurityException("Only SIGNAL_USR1 is allowed");
13170 }
13171
13172 synchronized (this) {
13173 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
13174 != PackageManager.PERMISSION_GRANTED) {
13175 throw new SecurityException("Requires permission "
13176 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
13177 }
13178
13179 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
13180 ProcessRecord r = mLRUProcesses.get(i);
13181 if (r.thread != null && r.persistent) {
13182 Process.sendSignal(r.pid, sig);
13183 }
13184 }
13185 }
13186 }
13187
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013188 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013189 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013190
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013191 try {
13192 synchronized (this) {
13193 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
13194 // its own permission.
13195 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
13196 != PackageManager.PERMISSION_GRANTED) {
13197 throw new SecurityException("Requires permission "
13198 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013199 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013200
13201 if (start && fd == null) {
13202 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013203 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013204
13205 ProcessRecord proc = null;
13206 try {
13207 int pid = Integer.parseInt(process);
13208 synchronized (mPidsSelfLocked) {
13209 proc = mPidsSelfLocked.get(pid);
13210 }
13211 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013212 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013213
13214 if (proc == null) {
13215 HashMap<String, SparseArray<ProcessRecord>> all
13216 = mProcessNames.getMap();
13217 SparseArray<ProcessRecord> procs = all.get(process);
13218 if (procs != null && procs.size() > 0) {
13219 proc = procs.valueAt(0);
13220 }
13221 }
13222
13223 if (proc == null || proc.thread == null) {
13224 throw new IllegalArgumentException("Unknown process: " + process);
13225 }
13226
13227 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
13228 if (isSecure) {
13229 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
13230 throw new SecurityException("Process not debuggable: " + proc);
13231 }
13232 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013233
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013234 proc.thread.profilerControl(start, path, fd);
13235 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013236 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070013237 }
13238 } catch (RemoteException e) {
13239 throw new IllegalStateException("Process disappeared");
13240 } finally {
13241 if (fd != null) {
13242 try {
13243 fd.close();
13244 } catch (IOException e) {
13245 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080013246 }
13247 }
13248 }
13249
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080013250 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
13251 public void monitor() {
13252 synchronized (this) { }
13253 }
13254}