blob: 442e9ce3fd1c6177ebe2978f129518b9eefcb79e [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;
42import android.app.PendingIntent;
43import android.app.ResultInfo;
Christopher Tate181fafa2009-05-14 11:12:14 -070044import android.backup.IBackupManager;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020045import android.content.ActivityNotFoundException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.content.ComponentName;
47import android.content.ContentResolver;
48import android.content.Context;
49import android.content.Intent;
50import android.content.IntentFilter;
Suchi Amalapurapu1ccac752009-06-12 10:09:58 -070051import android.content.IIntentReceiver;
52import android.content.IIntentSender;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.content.pm.ActivityInfo;
54import android.content.pm.ApplicationInfo;
55import android.content.pm.ConfigurationInfo;
56import android.content.pm.IPackageDataObserver;
57import android.content.pm.IPackageManager;
58import android.content.pm.InstrumentationInfo;
59import android.content.pm.PackageManager;
Dianne Hackborn2af632f2009-07-08 14:56:37 -070060import android.content.pm.PathPermission;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061import android.content.pm.ProviderInfo;
62import android.content.pm.ResolveInfo;
63import android.content.pm.ServiceInfo;
64import android.content.res.Configuration;
65import android.graphics.Bitmap;
66import android.net.Uri;
67import android.os.Binder;
68import android.os.Bundle;
69import android.os.Environment;
70import android.os.FileUtils;
71import android.os.Handler;
72import android.os.IBinder;
73import android.os.IPermissionController;
74import android.os.Looper;
75import android.os.Message;
76import android.os.Parcel;
77import android.os.ParcelFileDescriptor;
78import android.os.PowerManager;
79import android.os.Process;
Dianne Hackbornb06ea702009-07-13 13:07:51 -070080import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080081import android.os.RemoteException;
82import android.os.ServiceManager;
83import android.os.SystemClock;
84import android.os.SystemProperties;
85import android.provider.Checkin;
86import android.provider.Settings;
Jacek Surazskif5b9c722009-05-18 12:09:59 +020087import android.server.data.CrashData;
88import android.server.data.StackTraceElementData;
89import android.server.data.ThrowableData;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080090import android.text.TextUtils;
91import android.util.Config;
92import android.util.EventLog;
93import android.util.Log;
94import android.util.PrintWriterPrinter;
95import android.util.SparseArray;
96import android.view.Gravity;
97import android.view.LayoutInflater;
98import android.view.View;
99import android.view.WindowManager;
100import android.view.WindowManagerPolicy;
101
102import dalvik.system.Zygote;
103
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200104import java.io.ByteArrayInputStream;
105import java.io.DataInputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800106import java.io.File;
107import java.io.FileDescriptor;
108import java.io.FileInputStream;
109import java.io.FileNotFoundException;
Jacek Surazskif5b9c722009-05-18 12:09:59 +0200110import java.io.IOException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111import java.io.PrintWriter;
112import java.lang.IllegalStateException;
113import java.lang.ref.WeakReference;
114import java.util.ArrayList;
115import java.util.HashMap;
116import java.util.HashSet;
117import java.util.Iterator;
118import java.util.List;
119import java.util.Locale;
120import java.util.Map;
121
122public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor {
123 static final String TAG = "ActivityManager";
124 static final boolean DEBUG = false;
125 static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
126 static final boolean DEBUG_SWITCH = localLOGV || false;
127 static final boolean DEBUG_TASKS = localLOGV || false;
128 static final boolean DEBUG_PAUSE = localLOGV || false;
129 static final boolean DEBUG_OOM_ADJ = localLOGV || false;
130 static final boolean DEBUG_TRANSITION = localLOGV || false;
131 static final boolean DEBUG_BROADCAST = localLOGV || false;
Dianne Hackborn82f3f002009-06-16 18:49:05 -0700132 static final boolean DEBUG_BROADCAST_LIGHT = DEBUG_BROADCAST || false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800133 static final boolean DEBUG_SERVICE = localLOGV || false;
134 static final boolean DEBUG_VISBILITY = localLOGV || false;
135 static final boolean DEBUG_PROCESSES = localLOGV || false;
136 static final boolean DEBUG_USER_LEAVING = localLOGV || false;
The Android Open Source Project10592532009-03-18 17:39:46 -0700137 static final boolean DEBUG_RESULTS = localLOGV || false;
Christopher Tate181fafa2009-05-14 11:12:14 -0700138 static final boolean DEBUG_BACKUP = localLOGV || true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 static final boolean VALIDATE_TOKENS = false;
140 static final boolean SHOW_ACTIVITY_START_TIME = true;
141
142 // Control over CPU and battery monitoring.
143 static final long BATTERY_STATS_TIME = 30*60*1000; // write battery stats every 30 minutes.
144 static final boolean MONITOR_CPU_USAGE = true;
145 static final long MONITOR_CPU_MIN_TIME = 5*1000; // don't sample cpu less than every 5 seconds.
146 static final long MONITOR_CPU_MAX_TIME = 0x0fffffff; // wait possibly forever for next cpu sample.
147 static final boolean MONITOR_THREAD_CPU_USAGE = false;
148
149 // Event log tags
150 static final int LOG_CONFIGURATION_CHANGED = 2719;
151 static final int LOG_CPU = 2721;
152 static final int LOG_AM_FINISH_ACTIVITY = 30001;
153 static final int LOG_TASK_TO_FRONT = 30002;
154 static final int LOG_AM_NEW_INTENT = 30003;
155 static final int LOG_AM_CREATE_TASK = 30004;
156 static final int LOG_AM_CREATE_ACTIVITY = 30005;
157 static final int LOG_AM_RESTART_ACTIVITY = 30006;
158 static final int LOG_AM_RESUME_ACTIVITY = 30007;
159 static final int LOG_ANR = 30008;
160 static final int LOG_ACTIVITY_LAUNCH_TIME = 30009;
161 static final int LOG_AM_PROCESS_BOUND = 30010;
162 static final int LOG_AM_PROCESS_DIED = 30011;
163 static final int LOG_AM_FAILED_TO_PAUSE_ACTIVITY = 30012;
164 static final int LOG_AM_PAUSE_ACTIVITY = 30013;
165 static final int LOG_AM_PROCESS_START = 30014;
166 static final int LOG_AM_PROCESS_BAD = 30015;
167 static final int LOG_AM_PROCESS_GOOD = 30016;
168 static final int LOG_AM_LOW_MEMORY = 30017;
169 static final int LOG_AM_DESTROY_ACTIVITY = 30018;
170 static final int LOG_AM_RELAUNCH_RESUME_ACTIVITY = 30019;
171 static final int LOG_AM_RELAUNCH_ACTIVITY = 30020;
172 static final int LOG_AM_KILL_FOR_MEMORY = 30023;
173 static final int LOG_AM_BROADCAST_DISCARD_FILTER = 30024;
174 static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
175 static final int LOG_AM_CREATE_SERVICE = 30030;
176 static final int LOG_AM_DESTROY_SERVICE = 30031;
177 static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
178 static final int LOG_AM_DROP_PROCESS = 30033;
179 static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
180 static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
181 static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
182
183 static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
184 static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
185
Dianne Hackborn1655be42009-05-08 14:29:01 -0700186 // The flags that are set for all calls we make to the package manager.
187 static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700188 | PackageManager.GET_SUPPORTS_DENSITIES;
Dianne Hackborn1655be42009-05-08 14:29:01 -0700189
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 private static final String SYSTEM_SECURE = "ro.secure";
191
192 // This is the maximum number of application processes we would like
193 // to have running. Due to the asynchronous nature of things, we can
194 // temporarily go beyond this limit.
195 static final int MAX_PROCESSES = 2;
196
197 // Set to false to leave processes running indefinitely, relying on
198 // the kernel killing them as resources are required.
199 static final boolean ENFORCE_PROCESS_LIMIT = false;
200
201 // This is the maximum number of activities that we would like to have
202 // running at a given time.
203 static final int MAX_ACTIVITIES = 20;
204
205 // Maximum number of recent tasks that we can remember.
206 static final int MAX_RECENT_TASKS = 20;
207
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700208 // Amount of time after a call to stopAppSwitches() during which we will
209 // prevent further untrusted switches from happening.
210 static final long APP_SWITCH_DELAY_TIME = 5*1000;
211
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800212 // How long until we reset a task when the user returns to it. Currently
213 // 30 minutes.
214 static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30;
215
216 // Set to true to disable the icon that is shown while a new activity
217 // is being started.
218 static final boolean SHOW_APP_STARTING_ICON = true;
219
220 // How long we wait until giving up on the last activity to pause. This
221 // is short because it directly impacts the responsiveness of starting the
222 // next activity.
223 static final int PAUSE_TIMEOUT = 500;
224
225 /**
226 * How long we can hold the launch wake lock before giving up.
227 */
228 static final int LAUNCH_TIMEOUT = 10*1000;
229
230 // How long we wait for a launched process to attach to the activity manager
231 // before we decide it's never going to come up for real.
232 static final int PROC_START_TIMEOUT = 10*1000;
233
234 // How long we wait until giving up on the last activity telling us it
235 // is idle.
236 static final int IDLE_TIMEOUT = 10*1000;
237
238 // How long to wait after going idle before forcing apps to GC.
239 static final int GC_TIMEOUT = 5*1000;
240
241 // How long we wait until giving up on an activity telling us it has
242 // finished destroying itself.
243 static final int DESTROY_TIMEOUT = 10*1000;
244
245 // How long we allow a receiver to run before giving up on it.
246 static final int BROADCAST_TIMEOUT = 10*1000;
247
248 // How long we wait for a service to finish executing.
249 static final int SERVICE_TIMEOUT = 20*1000;
250
251 // How long a service needs to be running until restarting its process
252 // is no longer considered to be a relaunch of the service.
253 static final int SERVICE_RESTART_DURATION = 5*1000;
254
255 // Maximum amount of time for there to be no activity on a service before
256 // we consider it non-essential and allow its process to go on the
257 // LRU background list.
258 static final int MAX_SERVICE_INACTIVITY = 10*60*1000;
259
260 // How long we wait until we timeout on key dispatching.
261 static final int KEY_DISPATCHING_TIMEOUT = 5*1000;
262
263 // The minimum time we allow between crashes, for us to consider this
264 // application to be bad and stop and its services and reject broadcasts.
265 static final int MIN_CRASH_INTERVAL = 60*1000;
266
267 // How long we wait until we timeout on key dispatching during instrumentation.
268 static final int INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT = 60*1000;
269
270 // OOM adjustments for processes in various states:
271
272 // This is a process without anything currently running in it. Definitely
273 // the first to go! Value set in system/rootdir/init.rc on startup.
274 // This value is initalized in the constructor, careful when refering to
275 // this static variable externally.
276 static int EMPTY_APP_ADJ;
277
278 // This is a process with a content provider that does not have any clients
279 // attached to it. If it did have any clients, its adjustment would be the
280 // one for the highest-priority of those processes.
281 static int CONTENT_PROVIDER_ADJ;
282
283 // This is a process only hosting activities that are not visible,
284 // so it can be killed without any disruption. Value set in
285 // system/rootdir/init.rc on startup.
286 final int HIDDEN_APP_MAX_ADJ;
287 static int HIDDEN_APP_MIN_ADJ;
288
The Android Open Source Project4df24232009-03-05 14:34:35 -0800289 // This is a process holding the home application -- we want to try
290 // avoiding killing it, even if it would normally be in the background,
291 // because the user interacts with it so much.
292 final int HOME_APP_ADJ;
293
Christopher Tate6fa95972009-06-05 18:43:55 -0700294 // This is a process currently hosting a backup operation. Killing it
295 // is not entirely fatal but is generally a bad idea.
296 final int BACKUP_APP_ADJ;
297
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800298 // This is a process holding a secondary server -- killing it will not
299 // have much of an impact as far as the user is concerned. Value set in
300 // system/rootdir/init.rc on startup.
301 final int SECONDARY_SERVER_ADJ;
302
303 // This is a process only hosting activities that are visible to the
304 // user, so we'd prefer they don't disappear. Value set in
305 // system/rootdir/init.rc on startup.
306 final int VISIBLE_APP_ADJ;
307
308 // This is the process running the current foreground app. We'd really
309 // rather not kill it! Value set in system/rootdir/init.rc on startup.
310 final int FOREGROUND_APP_ADJ;
311
312 // This is a process running a core server, such as telephony. Definitely
313 // don't want to kill it, but doing so is not completely fatal.
314 static final int CORE_SERVER_ADJ = -12;
315
316 // The system process runs at the default adjustment.
317 static final int SYSTEM_ADJ = -16;
318
319 // Memory pages are 4K.
320 static final int PAGE_SIZE = 4*1024;
321
322 // Corresponding memory levels for above adjustments.
323 final int EMPTY_APP_MEM;
324 final int HIDDEN_APP_MEM;
The Android Open Source Project4df24232009-03-05 14:34:35 -0800325 final int HOME_APP_MEM;
Christopher Tate6fa95972009-06-05 18:43:55 -0700326 final int BACKUP_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800327 final int SECONDARY_SERVER_MEM;
328 final int VISIBLE_APP_MEM;
329 final int FOREGROUND_APP_MEM;
330
331 final int MY_PID;
332
333 static final String[] EMPTY_STRING_ARRAY = new String[0];
334
335 enum ActivityState {
336 INITIALIZING,
337 RESUMED,
338 PAUSING,
339 PAUSED,
340 STOPPING,
341 STOPPED,
342 FINISHING,
343 DESTROYING,
344 DESTROYED
345 }
346
347 /**
348 * The back history of all previous (and possibly still
349 * running) activities. It contains HistoryRecord objects.
350 */
351 final ArrayList mHistory = new ArrayList();
352
353 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700354 * Description of a request to start a new activity, which has been held
355 * due to app switches being disabled.
356 */
357 class PendingActivityLaunch {
358 HistoryRecord r;
359 HistoryRecord sourceRecord;
360 Uri[] grantedUriPermissions;
361 int grantedMode;
362 boolean onlyIfNeeded;
363 }
364
365 final ArrayList<PendingActivityLaunch> mPendingActivityLaunches
366 = new ArrayList<PendingActivityLaunch>();
367
368 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 * List of all active broadcasts that are to be executed immediately
370 * (without waiting for another broadcast to finish). Currently this only
371 * contains broadcasts to registered receivers, to avoid spinning up
372 * a bunch of processes to execute IntentReceiver components.
373 */
374 final ArrayList<BroadcastRecord> mParallelBroadcasts
375 = new ArrayList<BroadcastRecord>();
376
377 /**
378 * List of all active broadcasts that are to be executed one at a time.
379 * The object at the top of the list is the currently activity broadcasts;
380 * those after it are waiting for the top to finish..
381 */
382 final ArrayList<BroadcastRecord> mOrderedBroadcasts
383 = new ArrayList<BroadcastRecord>();
384
385 /**
386 * Set when we current have a BROADCAST_INTENT_MSG in flight.
387 */
388 boolean mBroadcastsScheduled = false;
389
390 /**
391 * Set to indicate whether to issue an onUserLeaving callback when a
392 * newly launched activity is being brought in front of us.
393 */
394 boolean mUserLeaving = false;
395
396 /**
397 * When we are in the process of pausing an activity, before starting the
398 * next one, this variable holds the activity that is currently being paused.
399 */
400 HistoryRecord mPausingActivity = null;
401
402 /**
403 * Current activity that is resumed, or null if there is none.
404 */
405 HistoryRecord mResumedActivity = null;
406
407 /**
408 * Activity we have told the window manager to have key focus.
409 */
410 HistoryRecord mFocusedActivity = null;
411
412 /**
413 * This is the last activity that we put into the paused state. This is
414 * used to determine if we need to do an activity transition while sleeping,
415 * when we normally hold the top activity paused.
416 */
417 HistoryRecord mLastPausedActivity = null;
418
419 /**
420 * List of activities that are waiting for a new activity
421 * to become visible before completing whatever operation they are
422 * supposed to do.
423 */
424 final ArrayList mWaitingVisibleActivities = new ArrayList();
425
426 /**
427 * List of activities that are ready to be stopped, but waiting
428 * for the next activity to settle down before doing so. It contains
429 * HistoryRecord objects.
430 */
431 final ArrayList<HistoryRecord> mStoppingActivities
432 = new ArrayList<HistoryRecord>();
433
434 /**
435 * List of intents that were used to start the most recent tasks.
436 */
437 final ArrayList<TaskRecord> mRecentTasks
438 = new ArrayList<TaskRecord>();
439
440 /**
441 * List of activities that are ready to be finished, but waiting
442 * for the previous activity to settle down before doing so. It contains
443 * HistoryRecord objects.
444 */
445 final ArrayList mFinishingActivities = new ArrayList();
446
447 /**
448 * All of the applications we currently have running organized by name.
449 * The keys are strings of the application package name (as
450 * returned by the package manager), and the keys are ApplicationRecord
451 * objects.
452 */
453 final ProcessMap<ProcessRecord> mProcessNames
454 = new ProcessMap<ProcessRecord>();
455
456 /**
457 * The last time that various processes have crashed.
458 */
459 final ProcessMap<Long> mProcessCrashTimes = new ProcessMap<Long>();
460
461 /**
462 * Set of applications that we consider to be bad, and will reject
463 * incoming broadcasts from (which the user has no control over).
464 * Processes are added to this set when they have crashed twice within
465 * a minimum amount of time; they are removed from it when they are
466 * later restarted (hopefully due to some user action). The value is the
467 * time it was added to the list.
468 */
469 final ProcessMap<Long> mBadProcesses = new ProcessMap<Long>();
470
471 /**
472 * All of the processes we currently have running organized by pid.
473 * The keys are the pid running the application.
474 *
475 * <p>NOTE: This object is protected by its own lock, NOT the global
476 * activity manager lock!
477 */
478 final SparseArray<ProcessRecord> mPidsSelfLocked
479 = new SparseArray<ProcessRecord>();
480
481 /**
482 * All of the processes that have been forced to be foreground. The key
483 * is the pid of the caller who requested it (we hold a death
484 * link on it).
485 */
486 abstract class ForegroundToken implements IBinder.DeathRecipient {
487 int pid;
488 IBinder token;
489 }
490 final SparseArray<ForegroundToken> mForegroundProcesses
491 = new SparseArray<ForegroundToken>();
492
493 /**
494 * List of records for processes that someone had tried to start before the
495 * system was ready. We don't start them at that point, but ensure they
496 * are started by the time booting is complete.
497 */
498 final ArrayList<ProcessRecord> mProcessesOnHold
499 = new ArrayList<ProcessRecord>();
500
501 /**
502 * List of records for processes that we have started and are waiting
503 * for them to call back. This is really only needed when running in
504 * single processes mode, in which case we do not have a unique pid for
505 * each process.
506 */
507 final ArrayList<ProcessRecord> mStartingProcesses
508 = new ArrayList<ProcessRecord>();
509
510 /**
511 * List of persistent applications that are in the process
512 * of being started.
513 */
514 final ArrayList<ProcessRecord> mPersistentStartingProcesses
515 = new ArrayList<ProcessRecord>();
516
517 /**
518 * Processes that are being forcibly torn down.
519 */
520 final ArrayList<ProcessRecord> mRemovedProcesses
521 = new ArrayList<ProcessRecord>();
522
523 /**
524 * List of running applications, sorted by recent usage.
525 * The first entry in the list is the least recently used.
526 * It contains ApplicationRecord objects. This list does NOT include
527 * any persistent application records (since we never want to exit them).
528 */
529 final ArrayList<ProcessRecord> mLRUProcesses
530 = new ArrayList<ProcessRecord>();
531
532 /**
533 * List of processes that should gc as soon as things are idle.
534 */
535 final ArrayList<ProcessRecord> mProcessesToGc
536 = new ArrayList<ProcessRecord>();
537
538 /**
The Android Open Source Project4df24232009-03-05 14:34:35 -0800539 * This is the process holding what we currently consider to be
540 * the "home" activity.
541 */
542 private ProcessRecord mHomeProcess;
543
544 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800545 * List of running activities, sorted by recent usage.
546 * The first entry in the list is the least recently used.
547 * It contains HistoryRecord objects.
548 */
549 private final ArrayList mLRUActivities = new ArrayList();
550
551 /**
552 * Set of PendingResultRecord objects that are currently active.
553 */
554 final HashSet mPendingResultRecords = new HashSet();
555
556 /**
557 * Set of IntentSenderRecord objects that are currently active.
558 */
559 final HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>> mIntentSenderRecords
560 = new HashMap<PendingIntentRecord.Key, WeakReference<PendingIntentRecord>>();
561
562 /**
563 * Intent broadcast that we have tried to start, but are
564 * waiting for its application's process to be created. We only
565 * need one (instead of a list) because we always process broadcasts
566 * one at a time, so no others can be started while waiting for this
567 * one.
568 */
569 BroadcastRecord mPendingBroadcast = null;
570
571 /**
572 * Keeps track of all IIntentReceivers that have been registered for
573 * broadcasts. Hash keys are the receiver IBinder, hash value is
574 * a ReceiverList.
575 */
576 final HashMap mRegisteredReceivers = new HashMap();
577
578 /**
579 * Resolver for broadcast intents to registered receivers.
580 * Holds BroadcastFilter (subclass of IntentFilter).
581 */
582 final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver
583 = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
584 @Override
585 protected boolean allowFilterResult(
586 BroadcastFilter filter, List<BroadcastFilter> dest) {
587 IBinder target = filter.receiverList.receiver.asBinder();
588 for (int i=dest.size()-1; i>=0; i--) {
589 if (dest.get(i).receiverList.receiver.asBinder() == target) {
590 return false;
591 }
592 }
593 return true;
594 }
595 };
596
597 /**
598 * State of all active sticky broadcasts. Keys are the action of the
599 * sticky Intent, values are an ArrayList of all broadcasted intents with
600 * that action (which should usually be one).
601 */
602 final HashMap<String, ArrayList<Intent>> mStickyBroadcasts =
603 new HashMap<String, ArrayList<Intent>>();
604
605 /**
606 * All currently running services.
607 */
608 final HashMap<ComponentName, ServiceRecord> mServices =
609 new HashMap<ComponentName, ServiceRecord>();
610
611 /**
612 * All currently running services indexed by the Intent used to start them.
613 */
614 final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent =
615 new HashMap<Intent.FilterComparison, ServiceRecord>();
616
617 /**
618 * All currently bound service connections. Keys are the IBinder of
619 * the client's IServiceConnection.
620 */
621 final HashMap<IBinder, ConnectionRecord> mServiceConnections
622 = new HashMap<IBinder, ConnectionRecord>();
623
624 /**
625 * List of services that we have been asked to start,
626 * but haven't yet been able to. It is used to hold start requests
627 * while waiting for their corresponding application thread to get
628 * going.
629 */
630 final ArrayList<ServiceRecord> mPendingServices
631 = new ArrayList<ServiceRecord>();
632
633 /**
634 * List of services that are scheduled to restart following a crash.
635 */
636 final ArrayList<ServiceRecord> mRestartingServices
637 = new ArrayList<ServiceRecord>();
638
639 /**
640 * List of services that are in the process of being stopped.
641 */
642 final ArrayList<ServiceRecord> mStoppingServices
643 = new ArrayList<ServiceRecord>();
644
645 /**
Christopher Tate181fafa2009-05-14 11:12:14 -0700646 * Backup/restore process management
647 */
648 String mBackupAppName = null;
649 BackupRecord mBackupTarget = null;
650
651 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800652 * List of PendingThumbnailsRecord objects of clients who are still
653 * waiting to receive all of the thumbnails for a task.
654 */
655 final ArrayList mPendingThumbnails = new ArrayList();
656
657 /**
658 * List of HistoryRecord objects that have been finished and must
659 * still report back to a pending thumbnail receiver.
660 */
661 final ArrayList mCancelledThumbnails = new ArrayList();
662
663 /**
664 * All of the currently running global content providers. Keys are a
665 * string containing the provider name and values are a
666 * ContentProviderRecord object containing the data about it. Note
667 * that a single provider may be published under multiple names, so
668 * there may be multiple entries here for a single one in mProvidersByClass.
669 */
670 final HashMap mProvidersByName = new HashMap();
671
672 /**
673 * All of the currently running global content providers. Keys are a
674 * string containing the provider's implementation class and values are a
675 * ContentProviderRecord object containing the data about it.
676 */
677 final HashMap mProvidersByClass = new HashMap();
678
679 /**
680 * List of content providers who have clients waiting for them. The
681 * application is currently being launched and the provider will be
682 * removed from this list once it is published.
683 */
684 final ArrayList mLaunchingProviders = new ArrayList();
685
686 /**
687 * Global set of specific Uri permissions that have been granted.
688 */
689 final private SparseArray<HashMap<Uri, UriPermission>> mGrantedUriPermissions
690 = new SparseArray<HashMap<Uri, UriPermission>>();
691
692 /**
693 * Thread-local storage used to carry caller permissions over through
694 * indirect content-provider access.
695 * @see #ActivityManagerService.openContentUri()
696 */
697 private class Identity {
698 public int pid;
699 public int uid;
700
701 Identity(int _pid, int _uid) {
702 pid = _pid;
703 uid = _uid;
704 }
705 }
706 private static ThreadLocal<Identity> sCallerIdentity = new ThreadLocal<Identity>();
707
708 /**
709 * All information we have collected about the runtime performance of
710 * any user id that can impact battery performance.
711 */
712 final BatteryStatsService mBatteryStatsService;
713
714 /**
715 * information about component usage
716 */
717 final UsageStatsService mUsageStatsService;
718
719 /**
720 * Current configuration information. HistoryRecord objects are given
721 * a reference to this object to indicate which configuration they are
722 * currently running in, so this object must be kept immutable.
723 */
724 Configuration mConfiguration = new Configuration();
725
726 /**
727 * List of initialization arguments to pass to all processes when binding applications to them.
728 * For example, references to the commonly used services.
729 */
730 HashMap<String, IBinder> mAppBindArgs;
731
732 /**
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700733 * Temporary to avoid allocations. Protected by main lock.
734 */
735 final StringBuilder mStringBuilder = new StringBuilder(256);
736
737 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800738 * Used to control how we initialize the service.
739 */
740 boolean mStartRunning = false;
741 ComponentName mTopComponent;
742 String mTopAction;
743 String mTopData;
744 boolean mSystemReady = false;
745 boolean mBooting = false;
746
747 Context mContext;
748
749 int mFactoryTest;
750
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -0700751 boolean mCheckedForSetup;
752
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800753 /**
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700754 * The time at which we will allow normal application switches again,
755 * after a call to {@link #stopAppSwitches()}.
756 */
757 long mAppSwitchesAllowedTime;
758
759 /**
760 * This is set to true after the first switch after mAppSwitchesAllowedTime
761 * is set; any switches after that will clear the time.
762 */
763 boolean mDidAppSwitch;
764
765 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766 * Set while we are wanting to sleep, to prevent any
767 * activities from being started/resumed.
768 */
769 boolean mSleeping = false;
770
771 /**
Dianne Hackborn55280a92009-05-07 15:53:46 -0700772 * Set if we are shutting down the system, similar to sleeping.
773 */
774 boolean mShuttingDown = false;
775
776 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800777 * Set when the system is going to sleep, until we have
778 * successfully paused the current activity and released our wake lock.
779 * At that point the system is allowed to actually sleep.
780 */
781 PowerManager.WakeLock mGoingToSleep;
782
783 /**
784 * We don't want to allow the device to go to sleep while in the process
785 * of launching an activity. This is primarily to allow alarm intent
786 * receivers to launch an activity and get that to run before the device
787 * goes back to sleep.
788 */
789 PowerManager.WakeLock mLaunchingActivity;
790
791 /**
792 * Task identifier that activities are currently being started
793 * in. Incremented each time a new task is created.
794 * todo: Replace this with a TokenSpace class that generates non-repeating
795 * integers that won't wrap.
796 */
797 int mCurTask = 1;
798
799 /**
800 * Current sequence id for oom_adj computation traversal.
801 */
802 int mAdjSeq = 0;
803
804 /**
805 * Set to true if the ANDROID_SIMPLE_PROCESS_MANAGEMENT envvar
806 * is set, indicating the user wants processes started in such a way
807 * that they can use ANDROID_PROCESS_WRAPPER and know what will be
808 * running in each process (thus no pre-initialized process, etc).
809 */
810 boolean mSimpleProcessManagement = false;
811
812 /**
813 * System monitoring: number of processes that died since the last
814 * N procs were started.
815 */
816 int[] mProcDeaths = new int[20];
817
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -0700818 /**
819 * This is set if we had to do a delayed dexopt of an app before launching
820 * it, to increasing the ANR timeouts in that case.
821 */
822 boolean mDidDexOpt;
823
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800824 String mDebugApp = null;
825 boolean mWaitForDebugger = false;
826 boolean mDebugTransient = false;
827 String mOrigDebugApp = null;
828 boolean mOrigWaitForDebugger = false;
829 boolean mAlwaysFinishActivities = false;
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700830 IActivityController mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800831
Dianne Hackbornb06ea702009-07-13 13:07:51 -0700832 final RemoteCallbackList<IActivityWatcher> mWatchers
833 = new RemoteCallbackList<IActivityWatcher>();
834
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800835 /**
836 * Callback of last caller to {@link #requestPss}.
837 */
838 Runnable mRequestPssCallback;
839
840 /**
841 * Remaining processes for which we are waiting results from the last
842 * call to {@link #requestPss}.
843 */
844 final ArrayList<ProcessRecord> mRequestPssList
845 = new ArrayList<ProcessRecord>();
846
847 /**
848 * Runtime statistics collection thread. This object's lock is used to
849 * protect all related state.
850 */
851 final Thread mProcessStatsThread;
852
853 /**
854 * Used to collect process stats when showing not responding dialog.
855 * Protected by mProcessStatsThread.
856 */
857 final ProcessStats mProcessStats = new ProcessStats(
858 MONITOR_THREAD_CPU_USAGE);
859 long mLastCpuTime = 0;
860 long mLastWriteTime = 0;
861
Dianne Hackbornf210d6b2009-04-13 18:42:49 -0700862 long mInitialStartTime = 0;
863
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864 /**
865 * Set to true after the system has finished booting.
866 */
867 boolean mBooted = false;
868
869 int mProcessLimit = 0;
870
871 WindowManagerService mWindowManager;
872
873 static ActivityManagerService mSelf;
874 static ActivityThread mSystemThread;
875
876 private final class AppDeathRecipient implements IBinder.DeathRecipient {
877 final ProcessRecord mApp;
878 final int mPid;
879 final IApplicationThread mAppThread;
880
881 AppDeathRecipient(ProcessRecord app, int pid,
882 IApplicationThread thread) {
883 if (localLOGV) Log.v(
884 TAG, "New death recipient " + this
885 + " for thread " + thread.asBinder());
886 mApp = app;
887 mPid = pid;
888 mAppThread = thread;
889 }
890
891 public void binderDied() {
892 if (localLOGV) Log.v(
893 TAG, "Death received in " + this
894 + " for thread " + mAppThread.asBinder());
895 removeRequestedPss(mApp);
896 synchronized(ActivityManagerService.this) {
897 appDiedLocked(mApp, mPid, mAppThread);
898 }
899 }
900 }
901
902 static final int SHOW_ERROR_MSG = 1;
903 static final int SHOW_NOT_RESPONDING_MSG = 2;
904 static final int SHOW_FACTORY_ERROR_MSG = 3;
905 static final int UPDATE_CONFIGURATION_MSG = 4;
906 static final int GC_BACKGROUND_PROCESSES_MSG = 5;
907 static final int WAIT_FOR_DEBUGGER_MSG = 6;
908 static final int BROADCAST_INTENT_MSG = 7;
909 static final int BROADCAST_TIMEOUT_MSG = 8;
910 static final int PAUSE_TIMEOUT_MSG = 9;
911 static final int IDLE_TIMEOUT_MSG = 10;
912 static final int IDLE_NOW_MSG = 11;
913 static final int SERVICE_TIMEOUT_MSG = 12;
914 static final int UPDATE_TIME_ZONE = 13;
915 static final int SHOW_UID_ERROR_MSG = 14;
916 static final int IM_FEELING_LUCKY_MSG = 15;
917 static final int LAUNCH_TIMEOUT_MSG = 16;
918 static final int DESTROY_TIMEOUT_MSG = 17;
919 static final int SERVICE_ERROR_MSG = 18;
920 static final int RESUME_TOP_ACTIVITY_MSG = 19;
921 static final int PROC_START_TIMEOUT_MSG = 20;
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700922 static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800923
924 AlertDialog mUidAlert;
925
926 final Handler mHandler = new Handler() {
927 //public Handler() {
928 // if (localLOGV) Log.v(TAG, "Handler started!");
929 //}
930
931 public void handleMessage(Message msg) {
932 switch (msg.what) {
933 case SHOW_ERROR_MSG: {
934 HashMap data = (HashMap) msg.obj;
935 byte[] crashData = (byte[])data.get("crashData");
936 if (crashData != null) {
937 // This needs to be *un*synchronized to avoid deadlock.
938 ContentResolver resolver = mContext.getContentResolver();
939 Checkin.reportCrash(resolver, crashData);
940 }
941 synchronized (ActivityManagerService.this) {
942 ProcessRecord proc = (ProcessRecord)data.get("app");
943 if (proc != null && proc.crashDialog != null) {
944 Log.e(TAG, "App already has crash dialog: " + proc);
945 return;
946 }
947 AppErrorResult res = (AppErrorResult) data.get("result");
Dianne Hackborn55280a92009-05-07 15:53:46 -0700948 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800949 Dialog d = new AppErrorDialog(
950 mContext, res, proc,
951 (Integer)data.get("flags"),
952 (String)data.get("shortMsg"),
953 (String)data.get("longMsg"));
954 d.show();
955 proc.crashDialog = d;
956 } else {
957 // The device is asleep, so just pretend that the user
958 // saw a crash dialog and hit "force quit".
959 res.set(0);
960 }
961 }
962 } break;
963 case SHOW_NOT_RESPONDING_MSG: {
964 synchronized (ActivityManagerService.this) {
965 HashMap data = (HashMap) msg.obj;
966 ProcessRecord proc = (ProcessRecord)data.get("app");
967 if (proc != null && proc.anrDialog != null) {
968 Log.e(TAG, "App already has anr dialog: " + proc);
969 return;
970 }
The Android Open Source Project4df24232009-03-05 14:34:35 -0800971
972 broadcastIntentLocked(null, null, new Intent("android.intent.action.ANR"),
973 null, null, 0, null, null, null,
974 false, false, MY_PID, Process.SYSTEM_UID);
975
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800976 Dialog d = new AppNotRespondingDialog(ActivityManagerService.this,
977 mContext, proc, (HistoryRecord)data.get("activity"));
978 d.show();
979 proc.anrDialog = d;
980 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -0700981
982 ensureScreenEnabled();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800983 } break;
984 case SHOW_FACTORY_ERROR_MSG: {
985 Dialog d = new FactoryErrorDialog(
986 mContext, msg.getData().getCharSequence("msg"));
987 d.show();
988 enableScreenAfterBoot();
989 } break;
990 case UPDATE_CONFIGURATION_MSG: {
991 final ContentResolver resolver = mContext.getContentResolver();
992 Settings.System.putConfiguration(resolver, (Configuration)msg.obj);
993 } break;
994 case GC_BACKGROUND_PROCESSES_MSG: {
995 synchronized (ActivityManagerService.this) {
996 performAppGcsIfAppropriateLocked();
997 }
998 } break;
999 case WAIT_FOR_DEBUGGER_MSG: {
1000 synchronized (ActivityManagerService.this) {
1001 ProcessRecord app = (ProcessRecord)msg.obj;
1002 if (msg.arg1 != 0) {
1003 if (!app.waitedForDebugger) {
1004 Dialog d = new AppWaitingForDebuggerDialog(
1005 ActivityManagerService.this,
1006 mContext, app);
1007 app.waitDialog = d;
1008 app.waitedForDebugger = true;
1009 d.show();
1010 }
1011 } else {
1012 if (app.waitDialog != null) {
1013 app.waitDialog.dismiss();
1014 app.waitDialog = null;
1015 }
1016 }
1017 }
1018 } break;
1019 case BROADCAST_INTENT_MSG: {
1020 if (DEBUG_BROADCAST) Log.v(
1021 TAG, "Received BROADCAST_INTENT_MSG");
1022 processNextBroadcast(true);
1023 } break;
1024 case BROADCAST_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001025 if (mDidDexOpt) {
1026 mDidDexOpt = false;
1027 Message nmsg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
1028 mHandler.sendMessageDelayed(nmsg, BROADCAST_TIMEOUT);
1029 return;
1030 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001031 broadcastTimeout();
1032 } break;
1033 case PAUSE_TIMEOUT_MSG: {
1034 IBinder token = (IBinder)msg.obj;
1035 // We don't at this point know if the activity is fullscreen,
1036 // so we need to be conservative and assume it isn't.
1037 Log.w(TAG, "Activity pause timeout for " + token);
1038 activityPaused(token, null, true);
1039 } break;
1040 case IDLE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001041 if (mDidDexOpt) {
1042 mDidDexOpt = false;
1043 Message nmsg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
1044 nmsg.obj = msg.obj;
1045 mHandler.sendMessageDelayed(nmsg, IDLE_TIMEOUT);
1046 return;
1047 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048 // We don't at this point know if the activity is fullscreen,
1049 // so we need to be conservative and assume it isn't.
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001050 IBinder token = (IBinder)msg.obj;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 Log.w(TAG, "Activity idle timeout for " + token);
1052 activityIdleInternal(token, true);
1053 } break;
1054 case DESTROY_TIMEOUT_MSG: {
1055 IBinder token = (IBinder)msg.obj;
1056 // We don't at this point know if the activity is fullscreen,
1057 // so we need to be conservative and assume it isn't.
1058 Log.w(TAG, "Activity destroy timeout for " + token);
1059 activityDestroyed(token);
1060 } break;
1061 case IDLE_NOW_MSG: {
1062 IBinder token = (IBinder)msg.obj;
1063 activityIdle(token);
1064 } break;
1065 case SERVICE_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001066 if (mDidDexOpt) {
1067 mDidDexOpt = false;
1068 Message nmsg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
1069 nmsg.obj = msg.obj;
1070 mHandler.sendMessageDelayed(nmsg, SERVICE_TIMEOUT);
1071 return;
1072 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001073 serviceTimeout((ProcessRecord)msg.obj);
1074 } break;
1075 case UPDATE_TIME_ZONE: {
1076 synchronized (ActivityManagerService.this) {
1077 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
1078 ProcessRecord r = mLRUProcesses.get(i);
1079 if (r.thread != null) {
1080 try {
1081 r.thread.updateTimeZone();
1082 } catch (RemoteException ex) {
1083 Log.w(TAG, "Failed to update time zone for: " + r.info.processName);
1084 }
1085 }
1086 }
1087 }
1088 break;
1089 }
1090 case SHOW_UID_ERROR_MSG: {
1091 // XXX This is a temporary dialog, no need to localize.
1092 AlertDialog d = new BaseErrorDialog(mContext);
1093 d.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
1094 d.setCancelable(false);
1095 d.setTitle("System UIDs Inconsistent");
1096 d.setMessage("UIDs on the system are inconsistent, you need to wipe your data partition or your device will be unstable.");
1097 d.setButton("I'm Feeling Lucky",
1098 mHandler.obtainMessage(IM_FEELING_LUCKY_MSG));
1099 mUidAlert = d;
1100 d.show();
1101 } break;
1102 case IM_FEELING_LUCKY_MSG: {
1103 if (mUidAlert != null) {
1104 mUidAlert.dismiss();
1105 mUidAlert = null;
1106 }
1107 } break;
1108 case LAUNCH_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001109 if (mDidDexOpt) {
1110 mDidDexOpt = false;
1111 Message nmsg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
1112 mHandler.sendMessageDelayed(nmsg, LAUNCH_TIMEOUT);
1113 return;
1114 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001115 synchronized (ActivityManagerService.this) {
1116 if (mLaunchingActivity.isHeld()) {
1117 Log.w(TAG, "Launch timeout has expired, giving up wake lock!");
1118 mLaunchingActivity.release();
1119 }
1120 }
1121 } break;
1122 case SERVICE_ERROR_MSG: {
1123 ServiceRecord srv = (ServiceRecord)msg.obj;
1124 // This needs to be *un*synchronized to avoid deadlock.
1125 Checkin.logEvent(mContext.getContentResolver(),
1126 Checkin.Events.Tag.SYSTEM_SERVICE_LOOPING,
1127 srv.name.toShortString());
1128 } break;
1129 case RESUME_TOP_ACTIVITY_MSG: {
1130 synchronized (ActivityManagerService.this) {
1131 resumeTopActivityLocked(null);
1132 }
1133 }
1134 case PROC_START_TIMEOUT_MSG: {
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001135 if (mDidDexOpt) {
1136 mDidDexOpt = false;
1137 Message nmsg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1138 nmsg.obj = msg.obj;
1139 mHandler.sendMessageDelayed(nmsg, PROC_START_TIMEOUT);
1140 return;
1141 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001142 ProcessRecord app = (ProcessRecord)msg.obj;
1143 synchronized (ActivityManagerService.this) {
1144 processStartTimedOutLocked(app);
1145 }
1146 }
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001147 case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
1148 synchronized (ActivityManagerService.this) {
1149 doPendingActivityLaunchesLocked(true);
1150 }
1151 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001152 }
1153 }
1154 };
1155
1156 public static void setSystemProcess() {
1157 try {
1158 ActivityManagerService m = mSelf;
1159
1160 ServiceManager.addService("activity", m);
1161 ServiceManager.addService("meminfo", new MemBinder(m));
1162 if (MONITOR_CPU_USAGE) {
1163 ServiceManager.addService("cpuinfo", new CpuBinder(m));
1164 }
1165 ServiceManager.addService("activity.broadcasts", new BroadcastsBinder(m));
1166 ServiceManager.addService("activity.services", new ServicesBinder(m));
1167 ServiceManager.addService("activity.senders", new SendersBinder(m));
1168 ServiceManager.addService("activity.providers", new ProvidersBinder(m));
1169 ServiceManager.addService("permission", new PermissionController(m));
1170
1171 ApplicationInfo info =
1172 mSelf.mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -07001173 "android", STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001174 synchronized (mSelf) {
1175 ProcessRecord app = mSelf.newProcessRecordLocked(
1176 mSystemThread.getApplicationThread(), info,
1177 info.processName);
1178 app.persistent = true;
1179 app.pid = Process.myPid();
1180 app.maxAdj = SYSTEM_ADJ;
1181 mSelf.mProcessNames.put(app.processName, app.info.uid, app);
1182 synchronized (mSelf.mPidsSelfLocked) {
1183 mSelf.mPidsSelfLocked.put(app.pid, app);
1184 }
1185 mSelf.updateLRUListLocked(app, true);
1186 }
1187 } catch (PackageManager.NameNotFoundException e) {
1188 throw new RuntimeException(
1189 "Unable to find android system package", e);
1190 }
1191 }
1192
1193 public void setWindowManager(WindowManagerService wm) {
1194 mWindowManager = wm;
1195 }
1196
1197 public static final Context main(int factoryTest) {
1198 AThread thr = new AThread();
1199 thr.start();
1200
1201 synchronized (thr) {
1202 while (thr.mService == null) {
1203 try {
1204 thr.wait();
1205 } catch (InterruptedException e) {
1206 }
1207 }
1208 }
1209
1210 ActivityManagerService m = thr.mService;
1211 mSelf = m;
1212 ActivityThread at = ActivityThread.systemMain();
1213 mSystemThread = at;
1214 Context context = at.getSystemContext();
1215 m.mContext = context;
1216 m.mFactoryTest = factoryTest;
1217 PowerManager pm =
1218 (PowerManager)context.getSystemService(Context.POWER_SERVICE);
1219 m.mGoingToSleep = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
1220 m.mLaunchingActivity = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "ActivityManager-Launch");
1221 m.mLaunchingActivity.setReferenceCounted(false);
1222
1223 m.mBatteryStatsService.publish(context);
1224 m.mUsageStatsService.publish(context);
1225
1226 synchronized (thr) {
1227 thr.mReady = true;
1228 thr.notifyAll();
1229 }
1230
1231 m.startRunning(null, null, null, null);
1232
1233 return context;
1234 }
1235
1236 public static ActivityManagerService self() {
1237 return mSelf;
1238 }
1239
1240 static class AThread extends Thread {
1241 ActivityManagerService mService;
1242 boolean mReady = false;
1243
1244 public AThread() {
1245 super("ActivityManager");
1246 }
1247
1248 public void run() {
1249 Looper.prepare();
1250
1251 android.os.Process.setThreadPriority(
1252 android.os.Process.THREAD_PRIORITY_FOREGROUND);
1253
1254 ActivityManagerService m = new ActivityManagerService();
1255
1256 synchronized (this) {
1257 mService = m;
1258 notifyAll();
1259 }
1260
1261 synchronized (this) {
1262 while (!mReady) {
1263 try {
1264 wait();
1265 } catch (InterruptedException e) {
1266 }
1267 }
1268 }
1269
1270 Looper.loop();
1271 }
1272 }
1273
1274 static class BroadcastsBinder extends Binder {
1275 ActivityManagerService mActivityManagerService;
1276 BroadcastsBinder(ActivityManagerService activityManagerService) {
1277 mActivityManagerService = activityManagerService;
1278 }
1279
1280 @Override
1281 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1282 mActivityManagerService.dumpBroadcasts(pw);
1283 }
1284 }
1285
1286 static class ServicesBinder extends Binder {
1287 ActivityManagerService mActivityManagerService;
1288 ServicesBinder(ActivityManagerService activityManagerService) {
1289 mActivityManagerService = activityManagerService;
1290 }
1291
1292 @Override
1293 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1294 mActivityManagerService.dumpServices(pw);
1295 }
1296 }
1297
1298 static class SendersBinder extends Binder {
1299 ActivityManagerService mActivityManagerService;
1300 SendersBinder(ActivityManagerService activityManagerService) {
1301 mActivityManagerService = activityManagerService;
1302 }
1303
1304 @Override
1305 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1306 mActivityManagerService.dumpSenders(pw);
1307 }
1308 }
1309
1310 static class ProvidersBinder extends Binder {
1311 ActivityManagerService mActivityManagerService;
1312 ProvidersBinder(ActivityManagerService activityManagerService) {
1313 mActivityManagerService = activityManagerService;
1314 }
1315
1316 @Override
1317 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1318 mActivityManagerService.dumpProviders(pw);
1319 }
1320 }
1321
1322 static class MemBinder extends Binder {
1323 ActivityManagerService mActivityManagerService;
1324 MemBinder(ActivityManagerService activityManagerService) {
1325 mActivityManagerService = activityManagerService;
1326 }
1327
1328 @Override
1329 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1330 ActivityManagerService service = mActivityManagerService;
1331 ArrayList<ProcessRecord> procs;
1332 synchronized (mActivityManagerService) {
1333 if (args != null && args.length > 0
1334 && args[0].charAt(0) != '-') {
1335 procs = new ArrayList<ProcessRecord>();
1336 int pid = -1;
1337 try {
1338 pid = Integer.parseInt(args[0]);
1339 } catch (NumberFormatException e) {
1340
1341 }
1342 for (int i=0; i<service.mLRUProcesses.size(); i++) {
1343 ProcessRecord proc = service.mLRUProcesses.get(i);
1344 if (proc.pid == pid) {
1345 procs.add(proc);
1346 } else if (proc.processName.equals(args[0])) {
1347 procs.add(proc);
1348 }
1349 }
1350 if (procs.size() <= 0) {
1351 pw.println("No process found for: " + args[0]);
1352 return;
1353 }
1354 } else {
1355 procs = service.mLRUProcesses;
1356 }
1357 }
1358 dumpApplicationMemoryUsage(fd, pw, procs, " ", args);
1359 }
1360 }
1361
1362 static class CpuBinder extends Binder {
1363 ActivityManagerService mActivityManagerService;
1364 CpuBinder(ActivityManagerService activityManagerService) {
1365 mActivityManagerService = activityManagerService;
1366 }
1367
1368 @Override
1369 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1370 synchronized (mActivityManagerService.mProcessStatsThread) {
1371 pw.print(mActivityManagerService.mProcessStats.printCurrentState());
1372 }
1373 }
1374 }
1375
1376 private ActivityManagerService() {
1377 String v = System.getenv("ANDROID_SIMPLE_PROCESS_MANAGEMENT");
1378 if (v != null && Integer.getInteger(v) != 0) {
1379 mSimpleProcessManagement = true;
1380 }
1381 v = System.getenv("ANDROID_DEBUG_APP");
1382 if (v != null) {
1383 mSimpleProcessManagement = true;
1384 }
1385
1386 MY_PID = Process.myPid();
1387
1388 File dataDir = Environment.getDataDirectory();
1389 File systemDir = new File(dataDir, "system");
1390 systemDir.mkdirs();
1391 mBatteryStatsService = new BatteryStatsService(new File(
1392 systemDir, "batterystats.bin").toString());
1393 mBatteryStatsService.getActiveStatistics().readLocked();
1394 mBatteryStatsService.getActiveStatistics().writeLocked();
1395
1396 mUsageStatsService = new UsageStatsService( new File(
Dianne Hackborn6447ca32009-04-07 19:50:08 -07001397 systemDir, "usagestats").toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001398
1399 mConfiguration.makeDefault();
1400 mProcessStats.init();
1401
1402 // Add ourself to the Watchdog monitors.
1403 Watchdog.getInstance().addMonitor(this);
1404
1405 // These values are set in system/rootdir/init.rc on startup.
1406 FOREGROUND_APP_ADJ =
1407 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_ADJ"));
1408 VISIBLE_APP_ADJ =
1409 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_ADJ"));
1410 SECONDARY_SERVER_ADJ =
1411 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_ADJ"));
Christopher Tate6fa95972009-06-05 18:43:55 -07001412 BACKUP_APP_ADJ =
1413 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_ADJ"));
The Android Open Source Project4df24232009-03-05 14:34:35 -08001414 HOME_APP_ADJ =
1415 Integer.valueOf(SystemProperties.get("ro.HOME_APP_ADJ"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001416 HIDDEN_APP_MIN_ADJ =
1417 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MIN_ADJ"));
1418 CONTENT_PROVIDER_ADJ =
1419 Integer.valueOf(SystemProperties.get("ro.CONTENT_PROVIDER_ADJ"));
1420 HIDDEN_APP_MAX_ADJ = CONTENT_PROVIDER_ADJ-1;
1421 EMPTY_APP_ADJ =
1422 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_ADJ"));
1423 FOREGROUND_APP_MEM =
1424 Integer.valueOf(SystemProperties.get("ro.FOREGROUND_APP_MEM"))*PAGE_SIZE;
1425 VISIBLE_APP_MEM =
1426 Integer.valueOf(SystemProperties.get("ro.VISIBLE_APP_MEM"))*PAGE_SIZE;
1427 SECONDARY_SERVER_MEM =
1428 Integer.valueOf(SystemProperties.get("ro.SECONDARY_SERVER_MEM"))*PAGE_SIZE;
Christopher Tate6fa95972009-06-05 18:43:55 -07001429 BACKUP_APP_MEM =
1430 Integer.valueOf(SystemProperties.get("ro.BACKUP_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project4df24232009-03-05 14:34:35 -08001431 HOME_APP_MEM =
1432 Integer.valueOf(SystemProperties.get("ro.HOME_APP_MEM"))*PAGE_SIZE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001433 HIDDEN_APP_MEM =
1434 Integer.valueOf(SystemProperties.get("ro.HIDDEN_APP_MEM"))*PAGE_SIZE;
1435 EMPTY_APP_MEM =
1436 Integer.valueOf(SystemProperties.get("ro.EMPTY_APP_MEM"))*PAGE_SIZE;
1437
1438 mProcessStatsThread = new Thread("ProcessStats") {
1439 public void run() {
1440 while (true) {
1441 try {
1442 try {
1443 synchronized(this) {
1444 final long now = SystemClock.uptimeMillis();
1445 long nextCpuDelay = (mLastCpuTime+MONITOR_CPU_MAX_TIME)-now;
1446 long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
1447 //Log.i(TAG, "Cpu delay=" + nextCpuDelay
1448 // + ", write delay=" + nextWriteDelay);
1449 if (nextWriteDelay < nextCpuDelay) {
1450 nextCpuDelay = nextWriteDelay;
1451 }
1452 if (nextCpuDelay > 0) {
1453 this.wait(nextCpuDelay);
1454 }
1455 }
1456 } catch (InterruptedException e) {
1457 }
1458
1459 updateCpuStatsNow();
1460 } catch (Exception e) {
1461 Log.e(TAG, "Unexpected exception collecting process stats", e);
1462 }
1463 }
1464 }
1465 };
1466 mProcessStatsThread.start();
1467 }
1468
1469 @Override
1470 public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
1471 throws RemoteException {
1472 try {
1473 return super.onTransact(code, data, reply, flags);
1474 } catch (RuntimeException e) {
1475 // The activity manager only throws security exceptions, so let's
1476 // log all others.
1477 if (!(e instanceof SecurityException)) {
1478 Log.e(TAG, "Activity Manager Crash", e);
1479 }
1480 throw e;
1481 }
1482 }
1483
1484 void updateCpuStats() {
1485 synchronized (mProcessStatsThread) {
1486 final long now = SystemClock.uptimeMillis();
1487 if (mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1488 mProcessStatsThread.notify();
1489 }
1490 }
1491 }
1492
1493 void updateCpuStatsNow() {
1494 synchronized (mProcessStatsThread) {
1495 final long now = SystemClock.uptimeMillis();
1496 boolean haveNewCpuStats = false;
Amith Yamasanieaeb6632009-06-03 15:16:10 -07001497
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001498 if (MONITOR_CPU_USAGE &&
1499 mLastCpuTime < (now-MONITOR_CPU_MIN_TIME)) {
1500 mLastCpuTime = now;
1501 haveNewCpuStats = true;
1502 mProcessStats.update();
1503 //Log.i(TAG, mProcessStats.printCurrentState());
1504 //Log.i(TAG, "Total CPU usage: "
1505 // + mProcessStats.getTotalCpuPercent() + "%");
1506
1507 // Log the cpu usage if the property is set.
1508 if ("true".equals(SystemProperties.get("events.cpu"))) {
1509 int user = mProcessStats.getLastUserTime();
1510 int system = mProcessStats.getLastSystemTime();
1511 int iowait = mProcessStats.getLastIoWaitTime();
1512 int irq = mProcessStats.getLastIrqTime();
1513 int softIrq = mProcessStats.getLastSoftIrqTime();
1514 int idle = mProcessStats.getLastIdleTime();
1515
1516 int total = user + system + iowait + irq + softIrq + idle;
1517 if (total == 0) total = 1;
1518
1519 EventLog.writeEvent(LOG_CPU,
1520 ((user+system+iowait+irq+softIrq) * 100) / total,
1521 (user * 100) / total,
1522 (system * 100) / total,
1523 (iowait * 100) / total,
1524 (irq * 100) / total,
1525 (softIrq * 100) / total);
1526 }
1527 }
1528
Amith Yamasani819f9282009-06-24 23:18:15 -07001529 final BatteryStatsImpl bstats = mBatteryStatsService.getActiveStatistics();
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001530 synchronized(bstats) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001531 synchronized(mPidsSelfLocked) {
1532 if (haveNewCpuStats) {
1533 if (mBatteryStatsService.isOnBattery()) {
1534 final int N = mProcessStats.countWorkingStats();
1535 for (int i=0; i<N; i++) {
1536 ProcessStats.Stats st
1537 = mProcessStats.getWorkingStats(i);
1538 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
1539 if (pr != null) {
1540 BatteryStatsImpl.Uid.Proc ps = pr.batteryStats;
1541 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001542 } else {
1543 BatteryStatsImpl.Uid.Proc ps =
Amith Yamasani819f9282009-06-24 23:18:15 -07001544 bstats.getProcessStatsLocked(st.name, st.pid);
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001545 if (ps != null) {
1546 ps.addCpuTimeLocked(st.rel_utime, st.rel_stime);
1547 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001548 }
1549 }
1550 }
1551 }
1552 }
Amith Yamasani32dbefd2009-06-19 09:21:17 -07001553
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001554 if (mLastWriteTime < (now-BATTERY_STATS_TIME)) {
1555 mLastWriteTime = now;
1556 mBatteryStatsService.getActiveStatistics().writeLocked();
1557 }
1558 }
1559 }
1560 }
1561
1562 /**
1563 * Initialize the application bind args. These are passed to each
1564 * process when the bindApplication() IPC is sent to the process. They're
1565 * lazily setup to make sure the services are running when they're asked for.
1566 */
1567 private HashMap<String, IBinder> getCommonServicesLocked() {
1568 if (mAppBindArgs == null) {
1569 mAppBindArgs = new HashMap<String, IBinder>();
1570
1571 // Setup the application init args
1572 mAppBindArgs.put("package", ServiceManager.getService("package"));
1573 mAppBindArgs.put("window", ServiceManager.getService("window"));
1574 mAppBindArgs.put(Context.ALARM_SERVICE,
1575 ServiceManager.getService(Context.ALARM_SERVICE));
1576 }
1577 return mAppBindArgs;
1578 }
1579
1580 private final void setFocusedActivityLocked(HistoryRecord r) {
1581 if (mFocusedActivity != r) {
1582 mFocusedActivity = r;
1583 mWindowManager.setFocusedApp(r, true);
1584 }
1585 }
1586
1587 private final void updateLRUListLocked(ProcessRecord app,
1588 boolean oomAdj) {
1589 // put it on the LRU to keep track of when it should be exited.
1590 int lrui = mLRUProcesses.indexOf(app);
1591 if (lrui >= 0) mLRUProcesses.remove(lrui);
1592 mLRUProcesses.add(app);
1593 //Log.i(TAG, "Putting proc to front: " + app.processName);
1594 if (oomAdj) {
1595 updateOomAdjLocked();
1596 }
1597 }
1598
1599 private final boolean updateLRUListLocked(HistoryRecord r) {
1600 final boolean hadit = mLRUActivities.remove(r);
1601 mLRUActivities.add(r);
1602 return hadit;
1603 }
1604
1605 private final HistoryRecord topRunningActivityLocked(HistoryRecord notTop) {
1606 int i = mHistory.size()-1;
1607 while (i >= 0) {
1608 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1609 if (!r.finishing && r != notTop) {
1610 return r;
1611 }
1612 i--;
1613 }
1614 return null;
1615 }
1616
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07001617 private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) {
1618 int i = mHistory.size()-1;
1619 while (i >= 0) {
1620 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1621 if (!r.finishing && !r.delayedResume && r != notTop) {
1622 return r;
1623 }
1624 i--;
1625 }
1626 return null;
1627 }
1628
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001629 /**
1630 * This is a simplified version of topRunningActivityLocked that provides a number of
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001631 * optional skip-over modes. It is intended for use with the ActivityController hook only.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001632 *
1633 * @param token If non-null, any history records matching this token will be skipped.
1634 * @param taskId If non-zero, we'll attempt to skip over records with the same task ID.
1635 *
1636 * @return Returns the HistoryRecord of the next activity on the stack.
1637 */
1638 private final HistoryRecord topRunningActivityLocked(IBinder token, int taskId) {
1639 int i = mHistory.size()-1;
1640 while (i >= 0) {
1641 HistoryRecord r = (HistoryRecord)mHistory.get(i);
1642 // Note: the taskId check depends on real taskId fields being non-zero
1643 if (!r.finishing && (token != r) && (taskId != r.task.taskId)) {
1644 return r;
1645 }
1646 i--;
1647 }
1648 return null;
1649 }
1650
1651 private final ProcessRecord getProcessRecordLocked(
1652 String processName, int uid) {
1653 if (uid == Process.SYSTEM_UID) {
1654 // The system gets to run in any process. If there are multiple
1655 // processes with the same uid, just pick the first (this
1656 // should never happen).
1657 SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
1658 processName);
1659 return procs != null ? procs.valueAt(0) : null;
1660 }
1661 ProcessRecord proc = mProcessNames.get(processName, uid);
1662 return proc;
1663 }
1664
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001665 private void ensurePackageDexOpt(String packageName) {
1666 IPackageManager pm = ActivityThread.getPackageManager();
1667 try {
1668 if (pm.performDexOpt(packageName)) {
1669 mDidDexOpt = true;
1670 }
1671 } catch (RemoteException e) {
1672 }
1673 }
1674
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001675 private boolean isNextTransitionForward() {
1676 int transit = mWindowManager.getPendingAppTransition();
1677 return transit == WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
1678 || transit == WindowManagerPolicy.TRANSIT_TASK_OPEN
1679 || transit == WindowManagerPolicy.TRANSIT_TASK_TO_FRONT;
1680 }
1681
1682 private final boolean realStartActivityLocked(HistoryRecord r,
1683 ProcessRecord app, boolean andResume, boolean checkConfig)
1684 throws RemoteException {
1685
1686 r.startFreezingScreenLocked(app, 0);
1687 mWindowManager.setAppVisibility(r, true);
1688
1689 // Have the window manager re-evaluate the orientation of
1690 // the screen based on the new activity order. Note that
1691 // as a result of this, it can call back into the activity
1692 // manager with a new orientation. We don't care about that,
1693 // because the activity is not currently running so we are
1694 // just restarting it anyway.
1695 if (checkConfig) {
1696 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07001697 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001698 r.mayFreezeScreenLocked(app) ? r : null);
1699 updateConfigurationLocked(config, r);
1700 }
1701
1702 r.app = app;
1703
1704 if (localLOGV) Log.v(TAG, "Launching: " + r);
1705
1706 int idx = app.activities.indexOf(r);
1707 if (idx < 0) {
1708 app.activities.add(r);
1709 }
1710 updateLRUListLocked(app, true);
1711
1712 try {
1713 if (app.thread == null) {
1714 throw new RemoteException();
1715 }
1716 List<ResultInfo> results = null;
1717 List<Intent> newIntents = null;
1718 if (andResume) {
1719 results = r.results;
1720 newIntents = r.newIntents;
1721 }
1722 if (DEBUG_SWITCH) Log.v(TAG, "Launching: " + r
1723 + " icicle=" + r.icicle
1724 + " with results=" + results + " newIntents=" + newIntents
1725 + " andResume=" + andResume);
1726 if (andResume) {
1727 EventLog.writeEvent(LOG_AM_RESTART_ACTIVITY,
1728 System.identityHashCode(r),
1729 r.task.taskId, r.shortComponentName);
1730 }
The Android Open Source Project4df24232009-03-05 14:34:35 -08001731 if (r.isHomeActivity) {
1732 mHomeProcess = app;
1733 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07001734 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001735 app.thread.scheduleLaunchActivity(new Intent(r.intent), r,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07001736 System.identityHashCode(r),
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001737 r.info, r.icicle, results, newIntents, !andResume,
1738 isNextTransitionForward());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001739 } catch (RemoteException e) {
1740 if (r.launchFailed) {
1741 // This is the second time we failed -- finish activity
1742 // and give up.
1743 Log.e(TAG, "Second failure launching "
1744 + r.intent.getComponent().flattenToShortString()
1745 + ", giving up", e);
1746 appDiedLocked(app, app.pid, app.thread);
1747 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
1748 "2nd-crash");
1749 return false;
1750 }
1751
1752 // This is the first time we failed -- restart process and
1753 // retry.
1754 app.activities.remove(r);
1755 throw e;
1756 }
1757
1758 r.launchFailed = false;
1759 if (updateLRUListLocked(r)) {
1760 Log.w(TAG, "Activity " + r
1761 + " being launched, but already in LRU list");
1762 }
1763
1764 if (andResume) {
1765 // As part of the process of launching, ActivityThread also performs
1766 // a resume.
1767 r.state = ActivityState.RESUMED;
1768 r.icicle = null;
1769 r.haveState = false;
1770 r.stopped = false;
1771 mResumedActivity = r;
1772 r.task.touchActiveTime();
1773 completeResumeLocked(r);
1774 pauseIfSleepingLocked();
1775 } else {
1776 // This activity is not starting in the resumed state... which
1777 // should look like we asked it to pause+stop (but remain visible),
1778 // and it has done so and reported back the current icicle and
1779 // other state.
1780 r.state = ActivityState.STOPPED;
1781 r.stopped = true;
1782 }
1783
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07001784 // Launch the new version setup screen if needed. We do this -after-
1785 // launching the initial activity (that is, home), so that it can have
1786 // a chance to initialize itself while in the background, making the
1787 // switch back to it faster and look better.
1788 startSetupActivityLocked();
1789
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001790 return true;
1791 }
1792
1793 private final void startSpecificActivityLocked(HistoryRecord r,
1794 boolean andResume, boolean checkConfig) {
1795 // Is this activity's application already running?
1796 ProcessRecord app = getProcessRecordLocked(r.processName,
1797 r.info.applicationInfo.uid);
1798
1799 if (r.startTime == 0) {
1800 r.startTime = SystemClock.uptimeMillis();
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001801 if (mInitialStartTime == 0) {
1802 mInitialStartTime = r.startTime;
1803 }
1804 } else if (mInitialStartTime == 0) {
1805 mInitialStartTime = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001806 }
1807
1808 if (app != null && app.thread != null) {
1809 try {
1810 realStartActivityLocked(r, app, andResume, checkConfig);
1811 return;
1812 } catch (RemoteException e) {
1813 Log.w(TAG, "Exception when starting activity "
1814 + r.intent.getComponent().flattenToShortString(), e);
1815 }
1816
1817 // If a dead object exception was thrown -- fall through to
1818 // restart the application.
1819 }
1820
1821 startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
1822 "activity", r.intent.getComponent());
1823 }
1824
1825 private final ProcessRecord startProcessLocked(String processName,
1826 ApplicationInfo info, boolean knownToBeDead, int intentFlags,
1827 String hostingType, ComponentName hostingName) {
1828 ProcessRecord app = getProcessRecordLocked(processName, info.uid);
1829 // We don't have to do anything more if:
1830 // (1) There is an existing application record; and
1831 // (2) The caller doesn't think it is dead, OR there is no thread
1832 // object attached to it so we know it couldn't have crashed; and
1833 // (3) There is a pid assigned to it, so it is either starting or
1834 // already running.
1835 if (DEBUG_PROCESSES) Log.v(TAG, "startProcess: name=" + processName
1836 + " app=" + app + " knownToBeDead=" + knownToBeDead
1837 + " thread=" + (app != null ? app.thread : null)
1838 + " pid=" + (app != null ? app.pid : -1));
1839 if (app != null &&
1840 (!knownToBeDead || app.thread == null) && app.pid > 0) {
1841 return app;
1842 }
1843
1844 String hostingNameStr = hostingName != null
1845 ? hostingName.flattenToShortString() : null;
1846
1847 if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
1848 // If we are in the background, then check to see if this process
1849 // is bad. If so, we will just silently fail.
1850 if (mBadProcesses.get(info.processName, info.uid) != null) {
1851 return null;
1852 }
1853 } else {
1854 // When the user is explicitly starting a process, then clear its
1855 // crash count so that we won't make it bad until they see at
1856 // least one crash dialog again, and make the process good again
1857 // if it had been bad.
1858 mProcessCrashTimes.remove(info.processName, info.uid);
1859 if (mBadProcesses.get(info.processName, info.uid) != null) {
1860 EventLog.writeEvent(LOG_AM_PROCESS_GOOD, info.uid,
1861 info.processName);
1862 mBadProcesses.remove(info.processName, info.uid);
1863 if (app != null) {
1864 app.bad = false;
1865 }
1866 }
1867 }
1868
1869 if (app == null) {
1870 app = newProcessRecordLocked(null, info, processName);
1871 mProcessNames.put(processName, info.uid, app);
1872 } else {
1873 // If this is a new package in the process, add the package to the list
1874 app.addPackage(info.packageName);
1875 }
1876
1877 // If the system is not ready yet, then hold off on starting this
1878 // process until it is.
1879 if (!mSystemReady
1880 && (info.flags&ApplicationInfo.FLAG_PERSISTENT) == 0) {
1881 if (!mProcessesOnHold.contains(app)) {
1882 mProcessesOnHold.add(app);
1883 }
1884 return app;
1885 }
1886
1887 startProcessLocked(app, hostingType, hostingNameStr);
1888 return (app.pid != 0) ? app : null;
1889 }
1890
1891 private final void startProcessLocked(ProcessRecord app,
1892 String hostingType, String hostingNameStr) {
1893 if (app.pid > 0 && app.pid != MY_PID) {
1894 synchronized (mPidsSelfLocked) {
1895 mPidsSelfLocked.remove(app.pid);
1896 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
1897 }
1898 app.pid = 0;
1899 }
1900
1901 mProcessesOnHold.remove(app);
1902
1903 updateCpuStats();
1904
1905 System.arraycopy(mProcDeaths, 0, mProcDeaths, 1, mProcDeaths.length-1);
1906 mProcDeaths[0] = 0;
1907
1908 try {
1909 int uid = app.info.uid;
1910 int[] gids = null;
1911 try {
1912 gids = mContext.getPackageManager().getPackageGids(
1913 app.info.packageName);
1914 } catch (PackageManager.NameNotFoundException e) {
1915 Log.w(TAG, "Unable to retrieve gids", e);
1916 }
1917 if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
1918 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
1919 && mTopComponent != null
1920 && app.processName.equals(mTopComponent.getPackageName())) {
1921 uid = 0;
1922 }
1923 if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
1924 && (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0) {
1925 uid = 0;
1926 }
1927 }
1928 int debugFlags = 0;
1929 if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
1930 debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
1931 }
1932 if ("1".equals(SystemProperties.get("debug.checkjni"))) {
1933 debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
1934 }
1935 if ("1".equals(SystemProperties.get("debug.assert"))) {
1936 debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
1937 }
1938 int pid = Process.start("android.app.ActivityThread",
1939 mSimpleProcessManagement ? app.processName : null, uid, uid,
1940 gids, debugFlags, null);
1941 BatteryStatsImpl bs = app.batteryStats.getBatteryStats();
1942 synchronized (bs) {
1943 if (bs.isOnBattery()) {
1944 app.batteryStats.incStartsLocked();
1945 }
1946 }
1947
1948 EventLog.writeEvent(LOG_AM_PROCESS_START, pid, uid,
1949 app.processName, hostingType,
1950 hostingNameStr != null ? hostingNameStr : "");
1951
1952 if (app.persistent) {
1953 Watchdog.getInstance().processStarted(app, app.processName, pid);
1954 }
1955
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07001956 StringBuilder buf = mStringBuilder;
1957 buf.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001958 buf.append("Start proc ");
1959 buf.append(app.processName);
1960 buf.append(" for ");
1961 buf.append(hostingType);
1962 if (hostingNameStr != null) {
1963 buf.append(" ");
1964 buf.append(hostingNameStr);
1965 }
1966 buf.append(": pid=");
1967 buf.append(pid);
1968 buf.append(" uid=");
1969 buf.append(uid);
1970 buf.append(" gids={");
1971 if (gids != null) {
1972 for (int gi=0; gi<gids.length; gi++) {
1973 if (gi != 0) buf.append(", ");
1974 buf.append(gids[gi]);
1975
1976 }
1977 }
1978 buf.append("}");
1979 Log.i(TAG, buf.toString());
1980 if (pid == 0 || pid == MY_PID) {
1981 // Processes are being emulated with threads.
1982 app.pid = MY_PID;
1983 app.removed = false;
1984 mStartingProcesses.add(app);
1985 } else if (pid > 0) {
1986 app.pid = pid;
1987 app.removed = false;
1988 synchronized (mPidsSelfLocked) {
1989 this.mPidsSelfLocked.put(pid, app);
1990 Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
1991 msg.obj = app;
1992 mHandler.sendMessageDelayed(msg, PROC_START_TIMEOUT);
1993 }
1994 } else {
1995 app.pid = 0;
1996 RuntimeException e = new RuntimeException(
1997 "Failure starting process " + app.processName
1998 + ": returned pid=" + pid);
1999 Log.e(TAG, e.getMessage(), e);
2000 }
2001 } catch (RuntimeException e) {
2002 // XXX do better error recovery.
2003 app.pid = 0;
2004 Log.e(TAG, "Failure starting process " + app.processName, e);
2005 }
2006 }
2007
2008 private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
2009 if (mPausingActivity != null) {
2010 RuntimeException e = new RuntimeException();
2011 Log.e(TAG, "Trying to pause when pause is already pending for "
2012 + mPausingActivity, e);
2013 }
2014 HistoryRecord prev = mResumedActivity;
2015 if (prev == null) {
2016 RuntimeException e = new RuntimeException();
2017 Log.e(TAG, "Trying to pause when nothing is resumed", e);
2018 resumeTopActivityLocked(null);
2019 return;
2020 }
2021 if (DEBUG_PAUSE) Log.v(TAG, "Start pausing: " + prev);
2022 mResumedActivity = null;
2023 mPausingActivity = prev;
2024 mLastPausedActivity = prev;
2025 prev.state = ActivityState.PAUSING;
2026 prev.task.touchActiveTime();
2027
2028 updateCpuStats();
2029
2030 if (prev.app != null && prev.app.thread != null) {
2031 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending pause: " + prev);
2032 try {
2033 EventLog.writeEvent(LOG_AM_PAUSE_ACTIVITY,
2034 System.identityHashCode(prev),
2035 prev.shortComponentName);
2036 prev.app.thread.schedulePauseActivity(prev, prev.finishing, userLeaving,
2037 prev.configChangeFlags);
2038 updateUsageStats(prev, false);
2039 } catch (Exception e) {
2040 // Ignore exception, if process died other code will cleanup.
2041 Log.w(TAG, "Exception thrown during pause", e);
2042 mPausingActivity = null;
2043 mLastPausedActivity = null;
2044 }
2045 } else {
2046 mPausingActivity = null;
2047 mLastPausedActivity = null;
2048 }
2049
2050 // If we are not going to sleep, we want to ensure the device is
2051 // awake until the next activity is started.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002052 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002053 mLaunchingActivity.acquire();
2054 if (!mHandler.hasMessages(LAUNCH_TIMEOUT_MSG)) {
2055 // To be safe, don't allow the wake lock to be held for too long.
2056 Message msg = mHandler.obtainMessage(LAUNCH_TIMEOUT_MSG);
2057 mHandler.sendMessageDelayed(msg, LAUNCH_TIMEOUT);
2058 }
2059 }
2060
2061
2062 if (mPausingActivity != null) {
2063 // Have the window manager pause its key dispatching until the new
2064 // activity has started. If we're pausing the activity just because
2065 // the screen is being turned off and the UI is sleeping, don't interrupt
2066 // key dispatch; the same activity will pick it up again on wakeup.
2067 if (!uiSleeping) {
2068 prev.pauseKeyDispatchingLocked();
2069 } else {
2070 if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
2071 }
2072
2073 // Schedule a pause timeout in case the app doesn't respond.
2074 // We don't give it much time because this directly impacts the
2075 // responsiveness seen by the user.
2076 Message msg = mHandler.obtainMessage(PAUSE_TIMEOUT_MSG);
2077 msg.obj = prev;
2078 mHandler.sendMessageDelayed(msg, PAUSE_TIMEOUT);
2079 if (DEBUG_PAUSE) Log.v(TAG, "Waiting for pause to complete...");
2080 } else {
2081 // This activity failed to schedule the
2082 // pause, so just treat it as being paused now.
2083 if (DEBUG_PAUSE) Log.v(TAG, "Activity not running, resuming next.");
2084 resumeTopActivityLocked(null);
2085 }
2086 }
2087
2088 private final void completePauseLocked() {
2089 HistoryRecord prev = mPausingActivity;
2090 if (DEBUG_PAUSE) Log.v(TAG, "Complete pause: " + prev);
2091
2092 if (prev != null) {
2093 if (prev.finishing) {
2094 if (DEBUG_PAUSE) Log.v(TAG, "Executing finish of activity: " + prev);
2095 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
2096 } else if (prev.app != null) {
2097 if (DEBUG_PAUSE) Log.v(TAG, "Enqueueing pending stop: " + prev);
2098 if (prev.waitingVisible) {
2099 prev.waitingVisible = false;
2100 mWaitingVisibleActivities.remove(prev);
2101 if (DEBUG_SWITCH || DEBUG_PAUSE) Log.v(
2102 TAG, "Complete pause, no longer waiting: " + prev);
2103 }
2104 if (prev.configDestroy) {
2105 // The previous is being paused because the configuration
2106 // is changing, which means it is actually stopping...
2107 // To juggle the fact that we are also starting a new
2108 // instance right now, we need to first completely stop
2109 // the current instance before starting the new one.
2110 if (DEBUG_PAUSE) Log.v(TAG, "Destroying after pause: " + prev);
2111 destroyActivityLocked(prev, true);
2112 } else {
2113 mStoppingActivities.add(prev);
2114 if (mStoppingActivities.size() > 3) {
2115 // If we already have a few activities waiting to stop,
2116 // then give up on things going idle and start clearing
2117 // them out.
2118 if (DEBUG_PAUSE) Log.v(TAG, "To many pending stops, forcing idle");
2119 Message msg = Message.obtain();
2120 msg.what = ActivityManagerService.IDLE_NOW_MSG;
2121 mHandler.sendMessage(msg);
2122 }
2123 }
2124 } else {
2125 if (DEBUG_PAUSE) Log.v(TAG, "App died during pause, not stopping: " + prev);
2126 prev = null;
2127 }
2128 mPausingActivity = null;
2129 }
2130
Dianne Hackborn55280a92009-05-07 15:53:46 -07002131 if (!mSleeping && !mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002132 resumeTopActivityLocked(prev);
2133 } else {
2134 if (mGoingToSleep.isHeld()) {
2135 mGoingToSleep.release();
2136 }
Dianne Hackborn55280a92009-05-07 15:53:46 -07002137 if (mShuttingDown) {
2138 notifyAll();
2139 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002140 }
2141
2142 if (prev != null) {
2143 prev.resumeKeyDispatchingLocked();
2144 }
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002145
2146 if (prev.app != null && prev.cpuTimeAtResume > 0 && mBatteryStatsService.isOnBattery()) {
2147 long diff = 0;
2148 synchronized (mProcessStatsThread) {
2149 diff = mProcessStats.getCpuTimeForPid(prev.app.pid) - prev.cpuTimeAtResume;
2150 }
2151 if (diff > 0) {
2152 BatteryStatsImpl bsi = mBatteryStatsService.getActiveStatistics();
2153 synchronized (bsi) {
2154 BatteryStatsImpl.Uid.Proc ps =
2155 bsi.getProcessStatsLocked(prev.info.applicationInfo.uid,
2156 prev.info.packageName);
2157 if (ps != null) {
2158 ps.addForegroundTimeLocked(diff);
2159 }
2160 }
2161 }
2162 }
2163 prev.cpuTimeAtResume = 0; // reset it
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002164 }
2165
2166 /**
2167 * Once we know that we have asked an application to put an activity in
2168 * the resumed state (either by launching it or explicitly telling it),
2169 * this function updates the rest of our state to match that fact.
2170 */
2171 private final void completeResumeLocked(HistoryRecord next) {
2172 next.idle = false;
2173 next.results = null;
2174 next.newIntents = null;
2175
2176 // schedule an idle timeout in case the app doesn't do it for us.
2177 Message msg = mHandler.obtainMessage(IDLE_TIMEOUT_MSG);
2178 msg.obj = next;
2179 mHandler.sendMessageDelayed(msg, IDLE_TIMEOUT);
2180
2181 if (false) {
2182 // The activity was never told to pause, so just keep
2183 // things going as-is. To maintain our own state,
2184 // we need to emulate it coming back and saying it is
2185 // idle.
2186 msg = mHandler.obtainMessage(IDLE_NOW_MSG);
2187 msg.obj = next;
2188 mHandler.sendMessage(msg);
2189 }
2190
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002191 reportResumedActivity(next);
2192
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002193 next.thumbnail = null;
2194 setFocusedActivityLocked(next);
2195 next.resumeKeyDispatchingLocked();
2196 ensureActivitiesVisibleLocked(null, 0);
2197 mWindowManager.executeAppTransition();
Amith Yamasanieaeb6632009-06-03 15:16:10 -07002198
2199 // Mark the point when the activity is resuming
2200 // TODO: To be more accurate, the mark should be before the onCreate,
2201 // not after the onResume. But for subsequent starts, onResume is fine.
2202 if (next.app != null) {
2203 synchronized (mProcessStatsThread) {
2204 next.cpuTimeAtResume = mProcessStats.getCpuTimeForPid(next.app.pid);
2205 }
2206 } else {
2207 next.cpuTimeAtResume = 0; // Couldn't get the cpu time of process
2208 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002209 }
2210
2211 /**
2212 * Make sure that all activities that need to be visible (that is, they
2213 * currently can be seen by the user) actually are.
2214 */
2215 private final void ensureActivitiesVisibleLocked(HistoryRecord top,
2216 HistoryRecord starting, String onlyThisProcess, int configChanges) {
2217 if (DEBUG_VISBILITY) Log.v(
2218 TAG, "ensureActivitiesVisible behind " + top
2219 + " configChanges=0x" + Integer.toHexString(configChanges));
2220
2221 // If the top activity is not fullscreen, then we need to
2222 // make sure any activities under it are now visible.
2223 final int count = mHistory.size();
2224 int i = count-1;
2225 while (mHistory.get(i) != top) {
2226 i--;
2227 }
2228 HistoryRecord r;
2229 boolean behindFullscreen = false;
2230 for (; i>=0; i--) {
2231 r = (HistoryRecord)mHistory.get(i);
2232 if (DEBUG_VISBILITY) Log.v(
2233 TAG, "Make visible? " + r + " finishing=" + r.finishing
2234 + " state=" + r.state);
2235 if (r.finishing) {
2236 continue;
2237 }
2238
2239 final boolean doThisProcess = onlyThisProcess == null
2240 || onlyThisProcess.equals(r.processName);
2241
2242 // First: if this is not the current activity being started, make
2243 // sure it matches the current configuration.
2244 if (r != starting && doThisProcess) {
2245 ensureActivityConfigurationLocked(r, 0);
2246 }
2247
2248 if (r.app == null || r.app.thread == null) {
2249 if (onlyThisProcess == null
2250 || onlyThisProcess.equals(r.processName)) {
2251 // This activity needs to be visible, but isn't even
2252 // running... get it started, but don't resume it
2253 // at this point.
2254 if (DEBUG_VISBILITY) Log.v(
2255 TAG, "Start and freeze screen for " + r);
2256 if (r != starting) {
2257 r.startFreezingScreenLocked(r.app, configChanges);
2258 }
2259 if (!r.visible) {
2260 if (DEBUG_VISBILITY) Log.v(
2261 TAG, "Starting and making visible: " + r);
2262 mWindowManager.setAppVisibility(r, true);
2263 }
2264 if (r != starting) {
2265 startSpecificActivityLocked(r, false, false);
2266 }
2267 }
2268
2269 } else if (r.visible) {
2270 // If this activity is already visible, then there is nothing
2271 // else to do here.
2272 if (DEBUG_VISBILITY) Log.v(
2273 TAG, "Skipping: already visible at " + r);
2274 r.stopFreezingScreenLocked(false);
2275
2276 } else if (onlyThisProcess == null) {
2277 // This activity is not currently visible, but is running.
2278 // Tell it to become visible.
2279 r.visible = true;
2280 if (r.state != ActivityState.RESUMED && r != starting) {
2281 // If this activity is paused, tell it
2282 // to now show its window.
2283 if (DEBUG_VISBILITY) Log.v(
2284 TAG, "Making visible and scheduling visibility: " + r);
2285 try {
2286 mWindowManager.setAppVisibility(r, true);
2287 r.app.thread.scheduleWindowVisibility(r, true);
2288 r.stopFreezingScreenLocked(false);
2289 } catch (Exception e) {
2290 // Just skip on any failure; we'll make it
2291 // visible when it next restarts.
2292 Log.w(TAG, "Exception thrown making visibile: "
2293 + r.intent.getComponent(), e);
2294 }
2295 }
2296 }
2297
2298 // Aggregate current change flags.
2299 configChanges |= r.configChangeFlags;
2300
2301 if (r.fullscreen) {
2302 // At this point, nothing else needs to be shown
2303 if (DEBUG_VISBILITY) Log.v(
2304 TAG, "Stopping: fullscreen at " + r);
2305 behindFullscreen = true;
2306 i--;
2307 break;
2308 }
2309 }
2310
2311 // Now for any activities that aren't visible to the user, make
2312 // sure they no longer are keeping the screen frozen.
2313 while (i >= 0) {
2314 r = (HistoryRecord)mHistory.get(i);
2315 if (DEBUG_VISBILITY) Log.v(
2316 TAG, "Make invisible? " + r + " finishing=" + r.finishing
2317 + " state=" + r.state
2318 + " behindFullscreen=" + behindFullscreen);
2319 if (!r.finishing) {
2320 if (behindFullscreen) {
2321 if (r.visible) {
2322 if (DEBUG_VISBILITY) Log.v(
2323 TAG, "Making invisible: " + r);
2324 r.visible = false;
2325 try {
2326 mWindowManager.setAppVisibility(r, false);
2327 if ((r.state == ActivityState.STOPPING
2328 || r.state == ActivityState.STOPPED)
2329 && r.app != null && r.app.thread != null) {
2330 if (DEBUG_VISBILITY) Log.v(
2331 TAG, "Scheduling invisibility: " + r);
2332 r.app.thread.scheduleWindowVisibility(r, false);
2333 }
2334 } catch (Exception e) {
2335 // Just skip on any failure; we'll make it
2336 // visible when it next restarts.
2337 Log.w(TAG, "Exception thrown making hidden: "
2338 + r.intent.getComponent(), e);
2339 }
2340 } else {
2341 if (DEBUG_VISBILITY) Log.v(
2342 TAG, "Already invisible: " + r);
2343 }
2344 } else if (r.fullscreen) {
2345 if (DEBUG_VISBILITY) Log.v(
2346 TAG, "Now behindFullscreen: " + r);
2347 behindFullscreen = true;
2348 }
2349 }
2350 i--;
2351 }
2352 }
2353
2354 /**
2355 * Version of ensureActivitiesVisible that can easily be called anywhere.
2356 */
2357 private final void ensureActivitiesVisibleLocked(HistoryRecord starting,
2358 int configChanges) {
2359 HistoryRecord r = topRunningActivityLocked(null);
2360 if (r != null) {
2361 ensureActivitiesVisibleLocked(r, starting, null, configChanges);
2362 }
2363 }
2364
2365 private void updateUsageStats(HistoryRecord resumedComponent, boolean resumed) {
2366 if (resumed) {
2367 mUsageStatsService.noteResumeComponent(resumedComponent.realActivity);
2368 } else {
2369 mUsageStatsService.notePauseComponent(resumedComponent.realActivity);
2370 }
2371 }
2372
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002373 private boolean startHomeActivityLocked() {
2374 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
2375 && mTopAction == null) {
2376 // We are running in factory test mode, but unable to find
2377 // the factory test app, so just sit around displaying the
2378 // error message and don't try to start anything.
2379 return false;
2380 }
2381 Intent intent = new Intent(
2382 mTopAction,
2383 mTopData != null ? Uri.parse(mTopData) : null);
2384 intent.setComponent(mTopComponent);
2385 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
2386 intent.addCategory(Intent.CATEGORY_HOME);
2387 }
2388 ActivityInfo aInfo =
2389 intent.resolveActivityInfo(mContext.getPackageManager(),
2390 STOCK_PM_FLAGS);
2391 if (aInfo != null) {
2392 intent.setComponent(new ComponentName(
2393 aInfo.applicationInfo.packageName, aInfo.name));
2394 // Don't do this if the home app is currently being
2395 // instrumented.
2396 ProcessRecord app = getProcessRecordLocked(aInfo.processName,
2397 aInfo.applicationInfo.uid);
2398 if (app == null || app.instrumentationClass == null) {
2399 intent.setFlags(intent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
2400 startActivityLocked(null, intent, null, null, 0, aInfo,
2401 null, null, 0, 0, 0, false, false);
2402 }
2403 }
2404
2405
2406 return true;
2407 }
2408
2409 /**
2410 * Starts the "new version setup screen" if appropriate.
2411 */
2412 private void startSetupActivityLocked() {
2413 // Only do this once per boot.
2414 if (mCheckedForSetup) {
2415 return;
2416 }
2417
2418 // We will show this screen if the current one is a different
2419 // version than the last one shown, and we are not running in
2420 // low-level factory test mode.
2421 final ContentResolver resolver = mContext.getContentResolver();
2422 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL &&
2423 Settings.Secure.getInt(resolver,
2424 Settings.Secure.DEVICE_PROVISIONED, 0) != 0) {
2425 mCheckedForSetup = true;
2426
2427 // See if we should be showing the platform update setup UI.
2428 Intent intent = new Intent(Intent.ACTION_UPGRADE_SETUP);
2429 List<ResolveInfo> ris = mSelf.mContext.getPackageManager()
2430 .queryIntentActivities(intent, PackageManager.GET_META_DATA);
2431
2432 // We don't allow third party apps to replace this.
2433 ResolveInfo ri = null;
2434 for (int i=0; ris != null && i<ris.size(); i++) {
2435 if ((ris.get(i).activityInfo.applicationInfo.flags
2436 & ApplicationInfo.FLAG_SYSTEM) != 0) {
2437 ri = ris.get(i);
2438 break;
2439 }
2440 }
2441
2442 if (ri != null) {
2443 String vers = ri.activityInfo.metaData != null
2444 ? ri.activityInfo.metaData.getString(Intent.METADATA_SETUP_VERSION)
2445 : null;
2446 if (vers == null && ri.activityInfo.applicationInfo.metaData != null) {
2447 vers = ri.activityInfo.applicationInfo.metaData.getString(
2448 Intent.METADATA_SETUP_VERSION);
2449 }
2450 String lastVers = Settings.Secure.getString(
2451 resolver, Settings.Secure.LAST_SETUP_SHOWN);
2452 if (vers != null && !vers.equals(lastVers)) {
2453 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
2454 intent.setComponent(new ComponentName(
2455 ri.activityInfo.packageName, ri.activityInfo.name));
2456 startActivityLocked(null, intent, null, null, 0, ri.activityInfo,
2457 null, null, 0, 0, 0, false, false);
2458 }
2459 }
2460 }
2461 }
2462
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002463 private void reportResumedActivity(HistoryRecord r) {
2464 //Log.i(TAG, "**** REPORT RESUME: " + r);
2465
2466 final int identHash = System.identityHashCode(r);
2467 updateUsageStats(r, true);
2468
2469 int i = mWatchers.beginBroadcast();
2470 while (i > 0) {
2471 i--;
2472 IActivityWatcher w = mWatchers.getBroadcastItem(i);
2473 if (w != null) {
2474 try {
2475 w.activityResuming(identHash);
2476 } catch (RemoteException e) {
2477 }
2478 }
2479 }
2480 mWatchers.finishBroadcast();
2481 }
2482
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002483 /**
2484 * Ensure that the top activity in the stack is resumed.
2485 *
2486 * @param prev The previously resumed activity, for when in the process
2487 * of pausing; can be null to call from elsewhere.
2488 *
2489 * @return Returns true if something is being resumed, or false if
2490 * nothing happened.
2491 */
2492 private final boolean resumeTopActivityLocked(HistoryRecord prev) {
2493 // Find the first activity that is not finishing.
2494 HistoryRecord next = topRunningActivityLocked(null);
2495
2496 // Remember how we'll process this pause/resume situation, and ensure
2497 // that the state is reset however we wind up proceeding.
2498 final boolean userLeaving = mUserLeaving;
2499 mUserLeaving = false;
2500
2501 if (next == null) {
2502 // There are no more activities! Let's just start up the
2503 // Launcher...
Dianne Hackbornd7cd29d2009-07-01 11:22:45 -07002504 return startHomeActivityLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002505 }
2506
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002507 next.delayedResume = false;
2508
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002509 // If the top activity is the resumed one, nothing to do.
2510 if (mResumedActivity == next && next.state == ActivityState.RESUMED) {
2511 // Make sure we have executed any pending transitions, since there
2512 // should be nothing left to do at this point.
2513 mWindowManager.executeAppTransition();
2514 return false;
2515 }
2516
2517 // If we are sleeping, and there is no resumed activity, and the top
2518 // activity is paused, well that is the state we want.
Dianne Hackborn55280a92009-05-07 15:53:46 -07002519 if ((mSleeping || mShuttingDown)
2520 && mLastPausedActivity == next && next.state == ActivityState.PAUSED) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002521 // Make sure we have executed any pending transitions, since there
2522 // should be nothing left to do at this point.
2523 mWindowManager.executeAppTransition();
2524 return false;
2525 }
2526
2527 // The activity may be waiting for stop, but that is no longer
2528 // appropriate for it.
2529 mStoppingActivities.remove(next);
2530 mWaitingVisibleActivities.remove(next);
2531
2532 if (DEBUG_SWITCH) Log.v(TAG, "Resuming " + next);
2533
2534 // If we are currently pausing an activity, then don't do anything
2535 // until that is done.
2536 if (mPausingActivity != null) {
2537 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: pausing=" + mPausingActivity);
2538 return false;
2539 }
2540
2541 // We need to start pausing the current activity so the top one
2542 // can be resumed...
2543 if (mResumedActivity != null) {
2544 if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
2545 startPausingLocked(userLeaving, false);
2546 return true;
2547 }
2548
2549 if (prev != null && prev != next) {
2550 if (!prev.waitingVisible && next != null && !next.nowVisible) {
2551 prev.waitingVisible = true;
2552 mWaitingVisibleActivities.add(prev);
2553 if (DEBUG_SWITCH) Log.v(
2554 TAG, "Resuming top, waiting visible to hide: " + prev);
2555 } else {
2556 // The next activity is already visible, so hide the previous
2557 // activity's windows right now so we can show the new one ASAP.
2558 // We only do this if the previous is finishing, which should mean
2559 // it is on top of the one being resumed so hiding it quickly
2560 // is good. Otherwise, we want to do the normal route of allowing
2561 // the resumed activity to be shown so we can decide if the
2562 // previous should actually be hidden depending on whether the
2563 // new one is found to be full-screen or not.
2564 if (prev.finishing) {
2565 mWindowManager.setAppVisibility(prev, false);
2566 if (DEBUG_SWITCH) Log.v(TAG, "Not waiting for visible to hide: "
2567 + prev + ", waitingVisible="
2568 + (prev != null ? prev.waitingVisible : null)
2569 + ", nowVisible=" + next.nowVisible);
2570 } else {
2571 if (DEBUG_SWITCH) Log.v(TAG, "Previous already visible but still waiting to hide: "
2572 + prev + ", waitingVisible="
2573 + (prev != null ? prev.waitingVisible : null)
2574 + ", nowVisible=" + next.nowVisible);
2575 }
2576 }
2577 }
2578
2579 // We are starting up the next activity, so tell the window manager
2580 // that the previous one will be hidden soon. This way it can know
2581 // to ignore it when computing the desired screen orientation.
2582 if (prev != null) {
2583 if (prev.finishing) {
2584 if (DEBUG_TRANSITION) Log.v(TAG,
2585 "Prepare close transition: prev=" + prev);
2586 mWindowManager.prepareAppTransition(prev.task == next.task
2587 ? WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE
2588 : WindowManagerPolicy.TRANSIT_TASK_CLOSE);
2589 mWindowManager.setAppWillBeHidden(prev);
2590 mWindowManager.setAppVisibility(prev, false);
2591 } else {
2592 if (DEBUG_TRANSITION) Log.v(TAG,
2593 "Prepare open transition: prev=" + prev);
2594 mWindowManager.prepareAppTransition(prev.task == next.task
2595 ? WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN
2596 : WindowManagerPolicy.TRANSIT_TASK_OPEN);
2597 }
2598 if (false) {
2599 mWindowManager.setAppWillBeHidden(prev);
2600 mWindowManager.setAppVisibility(prev, false);
2601 }
2602 } else if (mHistory.size() > 1) {
2603 if (DEBUG_TRANSITION) Log.v(TAG,
2604 "Prepare open transition: no previous");
2605 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2606 }
2607
2608 if (next.app != null && next.app.thread != null) {
2609 if (DEBUG_SWITCH) Log.v(TAG, "Resume running: " + next);
2610
2611 // This activity is now becoming visible.
2612 mWindowManager.setAppVisibility(next, true);
2613
2614 HistoryRecord lastResumedActivity = mResumedActivity;
2615 ActivityState lastState = next.state;
2616
2617 updateCpuStats();
2618
2619 next.state = ActivityState.RESUMED;
2620 mResumedActivity = next;
2621 next.task.touchActiveTime();
2622 updateLRUListLocked(next.app, true);
2623 updateLRUListLocked(next);
2624
2625 // Have the window manager re-evaluate the orientation of
2626 // the screen based on the new activity order.
2627 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07002628 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002629 next.mayFreezeScreenLocked(next.app) ? next : null);
2630 if (config != null) {
2631 next.frozenBeforeDestroy = true;
2632 }
2633 if (!updateConfigurationLocked(config, next)) {
2634 // The configuration update wasn't able to keep the existing
2635 // instance of the activity, and instead started a new one.
2636 // We should be all done, but let's just make sure our activity
2637 // is still at the top and schedule another run if something
2638 // weird happened.
2639 HistoryRecord nextNext = topRunningActivityLocked(null);
2640 if (DEBUG_SWITCH) Log.i(TAG,
2641 "Activity config changed during resume: " + next
2642 + ", new next: " + nextNext);
2643 if (nextNext != next) {
2644 // Do over!
2645 mHandler.sendEmptyMessage(RESUME_TOP_ACTIVITY_MSG);
2646 }
2647 mWindowManager.executeAppTransition();
2648 return true;
2649 }
2650
2651 try {
2652 // Deliver all pending results.
2653 ArrayList a = next.results;
2654 if (a != null) {
2655 final int N = a.size();
2656 if (!next.finishing && N > 0) {
The Android Open Source Project10592532009-03-18 17:39:46 -07002657 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002658 TAG, "Delivering results to " + next
2659 + ": " + a);
2660 next.app.thread.scheduleSendResult(next, a);
2661 }
2662 }
2663
2664 if (next.newIntents != null) {
2665 next.app.thread.scheduleNewIntent(next.newIntents, next);
2666 }
2667
2668 EventLog.writeEvent(LOG_AM_RESUME_ACTIVITY,
2669 System.identityHashCode(next),
2670 next.task.taskId, next.shortComponentName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002671
2672 next.app.thread.scheduleResumeActivity(next,
2673 isNextTransitionForward());
Dianne Hackbornb06ea702009-07-13 13:07:51 -07002674
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002675 pauseIfSleepingLocked();
2676
2677 } catch (Exception e) {
2678 // Whoops, need to restart this activity!
2679 next.state = lastState;
2680 mResumedActivity = lastResumedActivity;
2681 if (Config.LOGD) Log.d(TAG,
2682 "Restarting because process died: " + next);
2683 if (!next.hasBeenLaunched) {
2684 next.hasBeenLaunched = true;
2685 } else {
2686 if (SHOW_APP_STARTING_ICON) {
2687 mWindowManager.setAppStartingWindow(
2688 next, next.packageName, next.theme,
2689 next.nonLocalizedLabel,
2690 next.labelRes, next.icon, null, true);
2691 }
2692 }
2693 startSpecificActivityLocked(next, true, false);
2694 return true;
2695 }
2696
2697 // From this point on, if something goes wrong there is no way
2698 // to recover the activity.
2699 try {
2700 next.visible = true;
2701 completeResumeLocked(next);
2702 } catch (Exception e) {
2703 // If any exception gets thrown, toss away this
2704 // activity and try the next one.
2705 Log.w(TAG, "Exception thrown during resume of " + next, e);
2706 requestFinishActivityLocked(next, Activity.RESULT_CANCELED, null,
2707 "resume-exception");
2708 return true;
2709 }
2710
2711 // Didn't need to use the icicle, and it is now out of date.
2712 next.icicle = null;
2713 next.haveState = false;
2714 next.stopped = false;
2715
2716 } else {
2717 // Whoops, need to restart this activity!
2718 if (!next.hasBeenLaunched) {
2719 next.hasBeenLaunched = true;
2720 } else {
2721 if (SHOW_APP_STARTING_ICON) {
2722 mWindowManager.setAppStartingWindow(
2723 next, next.packageName, next.theme,
2724 next.nonLocalizedLabel,
2725 next.labelRes, next.icon, null, true);
2726 }
2727 if (DEBUG_SWITCH) Log.v(TAG, "Restarting: " + next);
2728 }
2729 startSpecificActivityLocked(next, true, true);
2730 }
2731
2732 return true;
2733 }
2734
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002735 private final void startActivityLocked(HistoryRecord r, boolean newTask,
2736 boolean doResume) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002737 final int NH = mHistory.size();
2738
2739 int addPos = -1;
2740
2741 if (!newTask) {
2742 // If starting in an existing task, find where that is...
2743 HistoryRecord next = null;
2744 boolean startIt = true;
2745 for (int i = NH-1; i >= 0; i--) {
2746 HistoryRecord p = (HistoryRecord)mHistory.get(i);
2747 if (p.finishing) {
2748 continue;
2749 }
2750 if (p.task == r.task) {
2751 // Here it is! Now, if this is not yet visible to the
2752 // user, then just add it without starting; it will
2753 // get started when the user navigates back to it.
2754 addPos = i+1;
2755 if (!startIt) {
2756 mHistory.add(addPos, r);
2757 r.inHistory = true;
2758 r.task.numActivities++;
2759 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2760 r.info.screenOrientation, r.fullscreen);
2761 if (VALIDATE_TOKENS) {
2762 mWindowManager.validateAppTokens(mHistory);
2763 }
2764 return;
2765 }
2766 break;
2767 }
2768 if (p.fullscreen) {
2769 startIt = false;
2770 }
2771 next = p;
2772 }
2773 }
2774
2775 // Place a new activity at top of stack, so it is next to interact
2776 // with the user.
2777 if (addPos < 0) {
2778 addPos = mHistory.size();
2779 }
2780
2781 // If we are not placing the new activity frontmost, we do not want
2782 // to deliver the onUserLeaving callback to the actual frontmost
2783 // activity
2784 if (addPos < NH) {
2785 mUserLeaving = false;
2786 if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() behind front, mUserLeaving=false");
2787 }
2788
2789 // Slot the activity into the history stack and proceed
2790 mHistory.add(addPos, r);
2791 r.inHistory = true;
2792 r.frontOfTask = newTask;
2793 r.task.numActivities++;
2794 if (NH > 0) {
2795 // We want to show the starting preview window if we are
2796 // switching to a new task, or the next activity's process is
2797 // not currently running.
2798 boolean showStartingIcon = newTask;
2799 ProcessRecord proc = r.app;
2800 if (proc == null) {
2801 proc = mProcessNames.get(r.processName, r.info.applicationInfo.uid);
2802 }
2803 if (proc == null || proc.thread == null) {
2804 showStartingIcon = true;
2805 }
2806 if (DEBUG_TRANSITION) Log.v(TAG,
2807 "Prepare open transition: starting " + r);
2808 mWindowManager.prepareAppTransition(newTask
2809 ? WindowManagerPolicy.TRANSIT_TASK_OPEN
2810 : WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN);
2811 mWindowManager.addAppToken(
2812 addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen);
2813 boolean doShow = true;
2814 if (newTask) {
2815 // Even though this activity is starting fresh, we still need
2816 // to reset it to make sure we apply affinities to move any
2817 // existing activities from other tasks in to it.
2818 // If the caller has requested that the target task be
2819 // reset, then do so.
2820 if ((r.intent.getFlags()
2821 &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
2822 resetTaskIfNeededLocked(r, r);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002823 doShow = topRunningNonDelayedActivityLocked(null) == r;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002824 }
2825 }
2826 if (SHOW_APP_STARTING_ICON && doShow) {
2827 // Figure out if we are transitioning from another activity that is
2828 // "has the same starting icon" as the next one. This allows the
2829 // window manager to keep the previous window it had previously
2830 // created, if it still had one.
2831 HistoryRecord prev = mResumedActivity;
2832 if (prev != null) {
2833 // We don't want to reuse the previous starting preview if:
2834 // (1) The current activity is in a different task.
2835 if (prev.task != r.task) prev = null;
2836 // (2) The current activity is already displayed.
2837 else if (prev.nowVisible) prev = null;
2838 }
2839 mWindowManager.setAppStartingWindow(
2840 r, r.packageName, r.theme, r.nonLocalizedLabel,
2841 r.labelRes, r.icon, prev, showStartingIcon);
2842 }
2843 } else {
2844 // If this is the first activity, don't do any fancy animations,
2845 // because there is nothing for it to animate on top of.
2846 mWindowManager.addAppToken(addPos, r, r.task.taskId,
2847 r.info.screenOrientation, r.fullscreen);
2848 }
2849 if (VALIDATE_TOKENS) {
2850 mWindowManager.validateAppTokens(mHistory);
2851 }
2852
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002853 if (doResume) {
2854 resumeTopActivityLocked(null);
2855 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002856 }
2857
2858 /**
2859 * Perform clear operation as requested by
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002860 * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the
2861 * stack to the given task, then look for
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002862 * an instance of that activity in the stack and, if found, finish all
2863 * activities on top of it and return the instance.
2864 *
2865 * @param newR Description of the new activity being started.
2866 * @return Returns the old activity that should be continue to be used,
2867 * or null if none was found.
2868 */
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002869 private final HistoryRecord performClearTaskLocked(int taskId,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002870 HistoryRecord newR, boolean doClear) {
2871 int i = mHistory.size();
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07002872
2873 // First find the requested task.
2874 while (i > 0) {
2875 i--;
2876 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2877 if (r.task.taskId == taskId) {
2878 i++;
2879 break;
2880 }
2881 }
2882
2883 // Now clear it.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002884 while (i > 0) {
2885 i--;
2886 HistoryRecord r = (HistoryRecord)mHistory.get(i);
2887 if (r.finishing) {
2888 continue;
2889 }
2890 if (r.task.taskId != taskId) {
2891 return null;
2892 }
2893 if (r.realActivity.equals(newR.realActivity)) {
2894 // Here it is! Now finish everything in front...
2895 HistoryRecord ret = r;
2896 if (doClear) {
2897 while (i < (mHistory.size()-1)) {
2898 i++;
2899 r = (HistoryRecord)mHistory.get(i);
2900 if (r.finishing) {
2901 continue;
2902 }
2903 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
2904 null, "clear")) {
2905 i--;
2906 }
2907 }
2908 }
2909
2910 // Finally, if this is a normal launch mode (that is, not
2911 // expecting onNewIntent()), then we will finish the current
2912 // instance of the activity so a new fresh one can be started.
2913 if (ret.launchMode == ActivityInfo.LAUNCH_MULTIPLE) {
2914 if (!ret.finishing) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07002915 int index = indexOfTokenLocked(ret);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002916 if (index >= 0) {
2917 finishActivityLocked(ret, 0, Activity.RESULT_CANCELED,
2918 null, "clear");
2919 }
2920 return null;
2921 }
2922 }
2923
2924 return ret;
2925 }
2926 }
2927
2928 return null;
2929 }
2930
2931 /**
2932 * Find the activity in the history stack within the given task. Returns
2933 * the index within the history at which it's found, or < 0 if not found.
2934 */
2935 private final int findActivityInHistoryLocked(HistoryRecord r, int task) {
2936 int i = mHistory.size();
2937 while (i > 0) {
2938 i--;
2939 HistoryRecord candidate = (HistoryRecord)mHistory.get(i);
2940 if (candidate.task.taskId != task) {
2941 break;
2942 }
2943 if (candidate.realActivity.equals(r.realActivity)) {
2944 return i;
2945 }
2946 }
2947
2948 return -1;
2949 }
2950
2951 /**
2952 * Reorder the history stack so that the activity at the given index is
2953 * brought to the front.
2954 */
2955 private final HistoryRecord moveActivityToFrontLocked(int where) {
2956 HistoryRecord newTop = (HistoryRecord)mHistory.remove(where);
2957 int top = mHistory.size();
2958 HistoryRecord oldTop = (HistoryRecord)mHistory.get(top-1);
2959 mHistory.add(top, newTop);
2960 oldTop.frontOfTask = false;
2961 newTop.frontOfTask = true;
2962 return newTop;
2963 }
2964
2965 /**
2966 * Deliver a new Intent to an existing activity, so that its onNewIntent()
2967 * method will be called at the proper time.
2968 */
2969 private final void deliverNewIntentLocked(HistoryRecord r, Intent intent) {
2970 boolean sent = false;
2971 if (r.state == ActivityState.RESUMED
2972 && r.app != null && r.app.thread != null) {
2973 try {
2974 ArrayList<Intent> ar = new ArrayList<Intent>();
2975 ar.add(new Intent(intent));
2976 r.app.thread.scheduleNewIntent(ar, r);
2977 sent = true;
2978 } catch (Exception e) {
2979 Log.w(TAG, "Exception thrown sending new intent to " + r, e);
2980 }
2981 }
2982 if (!sent) {
2983 r.addNewIntentLocked(new Intent(intent));
2984 }
2985 }
2986
2987 private final void logStartActivity(int tag, HistoryRecord r,
2988 TaskRecord task) {
2989 EventLog.writeEvent(tag,
2990 System.identityHashCode(r), task.taskId,
2991 r.shortComponentName, r.intent.getAction(),
2992 r.intent.getType(), r.intent.getDataString(),
2993 r.intent.getFlags());
2994 }
2995
2996 private final int startActivityLocked(IApplicationThread caller,
2997 Intent intent, String resolvedType,
2998 Uri[] grantedUriPermissions,
2999 int grantedMode, ActivityInfo aInfo, IBinder resultTo,
3000 String resultWho, int requestCode,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003001 int callingPid, int callingUid, boolean onlyIfNeeded,
3002 boolean componentSpecified) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003003 Log.i(TAG, "Starting activity: " + intent);
3004
3005 HistoryRecord sourceRecord = null;
3006 HistoryRecord resultRecord = null;
3007 if (resultTo != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003008 int index = indexOfTokenLocked(resultTo);
The Android Open Source Project10592532009-03-18 17:39:46 -07003009 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003010 TAG, "Sending result to " + resultTo + " (index " + index + ")");
3011 if (index >= 0) {
3012 sourceRecord = (HistoryRecord)mHistory.get(index);
3013 if (requestCode >= 0 && !sourceRecord.finishing) {
3014 resultRecord = sourceRecord;
3015 }
3016 }
3017 }
3018
3019 int launchFlags = intent.getFlags();
3020
3021 if ((launchFlags&Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0
3022 && sourceRecord != null) {
3023 // Transfer the result target from the source activity to the new
3024 // one being started, including any failures.
3025 if (requestCode >= 0) {
3026 return START_FORWARD_AND_REQUEST_CONFLICT;
3027 }
3028 resultRecord = sourceRecord.resultTo;
3029 resultWho = sourceRecord.resultWho;
3030 requestCode = sourceRecord.requestCode;
3031 sourceRecord.resultTo = null;
3032 if (resultRecord != null) {
3033 resultRecord.removeResultsLocked(
3034 sourceRecord, resultWho, requestCode);
3035 }
3036 }
3037
3038 int err = START_SUCCESS;
3039
3040 if (intent.getComponent() == null) {
3041 // We couldn't find a class that can handle the given Intent.
3042 // That's the end of that!
3043 err = START_INTENT_NOT_RESOLVED;
3044 }
3045
3046 if (err == START_SUCCESS && aInfo == null) {
3047 // We couldn't find the specific class specified in the Intent.
3048 // Also the end of the line.
3049 err = START_CLASS_NOT_FOUND;
3050 }
3051
3052 ProcessRecord callerApp = null;
3053 if (err == START_SUCCESS && caller != null) {
3054 callerApp = getRecordForAppLocked(caller);
3055 if (callerApp != null) {
3056 callingPid = callerApp.pid;
3057 callingUid = callerApp.info.uid;
3058 } else {
3059 Log.w(TAG, "Unable to find app for caller " + caller
3060 + " (pid=" + callingPid + ") when starting: "
3061 + intent.toString());
3062 err = START_PERMISSION_DENIED;
3063 }
3064 }
3065
3066 if (err != START_SUCCESS) {
3067 if (resultRecord != null) {
3068 sendActivityResultLocked(-1,
3069 resultRecord, resultWho, requestCode,
3070 Activity.RESULT_CANCELED, null);
3071 }
3072 return err;
3073 }
3074
3075 final int perm = checkComponentPermission(aInfo.permission, callingPid,
3076 callingUid, aInfo.exported ? -1 : aInfo.applicationInfo.uid);
3077 if (perm != PackageManager.PERMISSION_GRANTED) {
3078 if (resultRecord != null) {
3079 sendActivityResultLocked(-1,
3080 resultRecord, resultWho, requestCode,
3081 Activity.RESULT_CANCELED, null);
3082 }
3083 String msg = "Permission Denial: starting " + intent.toString()
3084 + " from " + callerApp + " (pid=" + callingPid
3085 + ", uid=" + callingUid + ")"
3086 + " requires " + aInfo.permission;
3087 Log.w(TAG, msg);
3088 throw new SecurityException(msg);
3089 }
3090
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003091 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003092 boolean abort = false;
3093 try {
3094 // The Intent we give to the watcher has the extra data
3095 // stripped off, since it can contain private information.
3096 Intent watchIntent = intent.cloneFilter();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003097 abort = !mController.activityStarting(watchIntent,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003098 aInfo.applicationInfo.packageName);
3099 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003100 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003101 }
3102
3103 if (abort) {
3104 if (resultRecord != null) {
3105 sendActivityResultLocked(-1,
3106 resultRecord, resultWho, requestCode,
3107 Activity.RESULT_CANCELED, null);
3108 }
3109 // We pretend to the caller that it was really started, but
3110 // they will just get a cancel result.
3111 return START_SUCCESS;
3112 }
3113 }
3114
3115 HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,
3116 intent, resolvedType, aInfo, mConfiguration,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003117 resultRecord, resultWho, requestCode, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003118
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003119 if (mResumedActivity == null
3120 || mResumedActivity.info.applicationInfo.uid != callingUid) {
3121 if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) {
3122 PendingActivityLaunch pal = new PendingActivityLaunch();
3123 pal.r = r;
3124 pal.sourceRecord = sourceRecord;
3125 pal.grantedUriPermissions = grantedUriPermissions;
3126 pal.grantedMode = grantedMode;
3127 pal.onlyIfNeeded = onlyIfNeeded;
3128 mPendingActivityLaunches.add(pal);
3129 return START_SWITCHES_CANCELED;
3130 }
3131 }
3132
3133 if (mDidAppSwitch) {
3134 // This is the second allowed switch since we stopped switches,
3135 // so now just generally allow switches. Use case: user presses
3136 // home (switches disabled, switch to home, mDidAppSwitch now true);
3137 // user taps a home icon (coming from home so allowed, we hit here
3138 // and now allow anyone to switch again).
3139 mAppSwitchesAllowedTime = 0;
3140 } else {
3141 mDidAppSwitch = true;
3142 }
3143
3144 doPendingActivityLaunchesLocked(false);
3145
3146 return startActivityUncheckedLocked(r, sourceRecord,
3147 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
3148 }
3149
3150 private final void doPendingActivityLaunchesLocked(boolean doResume) {
3151 final int N = mPendingActivityLaunches.size();
3152 if (N <= 0) {
3153 return;
3154 }
3155 for (int i=0; i<N; i++) {
3156 PendingActivityLaunch pal = mPendingActivityLaunches.get(i);
3157 startActivityUncheckedLocked(pal.r, pal.sourceRecord,
3158 pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded,
3159 doResume && i == (N-1));
3160 }
3161 mPendingActivityLaunches.clear();
3162 }
3163
3164 private final int startActivityUncheckedLocked(HistoryRecord r,
3165 HistoryRecord sourceRecord, Uri[] grantedUriPermissions,
3166 int grantedMode, boolean onlyIfNeeded, boolean doResume) {
3167 final Intent intent = r.intent;
3168 final int callingUid = r.launchedFromUid;
3169
3170 int launchFlags = intent.getFlags();
3171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003172 // We'll invoke onUserLeaving before onPause only if the launching
3173 // activity did not explicitly state that this is an automated launch.
3174 mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
3175 if (DEBUG_USER_LEAVING) Log.v(TAG,
3176 "startActivity() => mUserLeaving=" + mUserLeaving);
3177
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003178 // If the caller has asked not to resume at this point, we make note
3179 // of this in the record so that we can skip it when trying to find
3180 // the top running activity.
3181 if (!doResume) {
3182 r.delayedResume = true;
3183 }
3184
3185 HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
3186 != 0 ? r : null;
3187
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003188 // If the onlyIfNeeded flag is set, then we can do this if the activity
3189 // being launched is the same as the one making the call... or, as
3190 // a special case, if we do not know the caller then we count the
3191 // current top activity as the caller.
3192 if (onlyIfNeeded) {
3193 HistoryRecord checkedCaller = sourceRecord;
3194 if (checkedCaller == null) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003195 checkedCaller = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003196 }
3197 if (!checkedCaller.realActivity.equals(r.realActivity)) {
3198 // Caller is not the same as launcher, so always needed.
3199 onlyIfNeeded = false;
3200 }
3201 }
3202
3203 if (grantedUriPermissions != null && callingUid > 0) {
3204 for (int i=0; i<grantedUriPermissions.length; i++) {
3205 grantUriPermissionLocked(callingUid, r.packageName,
3206 grantedUriPermissions[i], grantedMode, r);
3207 }
3208 }
3209
3210 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3211 intent, r);
3212
3213 if (sourceRecord == null) {
3214 // This activity is not being started from another... in this
3215 // case we -always- start a new task.
3216 if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
3217 Log.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "
3218 + intent);
3219 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3220 }
3221 } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3222 // The original activity who is starting us is running as a single
3223 // instance... this new activity it is starting must go on its
3224 // own task.
3225 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3226 } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
3227 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3228 // The activity being started is a single instance... it always
3229 // gets launched into its own task.
3230 launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
3231 }
3232
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003233 if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003234 // For whatever reason this activity is being launched into a new
3235 // task... yet the caller has requested a result back. Well, that
3236 // is pretty messed up, so instead immediately send back a cancel
3237 // and let the new task continue launched as normal without a
3238 // dependency on its originator.
3239 Log.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
3240 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003241 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003242 Activity.RESULT_CANCELED, null);
3243 r.resultTo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003244 }
3245
3246 boolean addingToTask = false;
3247 if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
3248 (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
3249 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3250 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3251 // If bring to front is requested, and no result is requested, and
3252 // we can find a task that was started with this same
3253 // component, then instead of launching bring that one to the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003254 if (r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003255 // See if there is a task to bring to the front. If this is
3256 // a SINGLE_INSTANCE activity, there can be one and only one
3257 // instance of it in the history, and it is always in its own
3258 // unique task, so we do a special search.
3259 HistoryRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE
3260 ? findTaskLocked(intent, r.info)
3261 : findActivityLocked(intent, r.info);
3262 if (taskTop != null) {
3263 if (taskTop.task.intent == null) {
3264 // This task was started because of movement of
3265 // the activity based on affinity... now that we
3266 // are actually launching it, we can assign the
3267 // base intent.
3268 taskTop.task.setIntent(intent, r.info);
3269 }
3270 // If the target task is not in the front, then we need
3271 // to bring it to the front... except... well, with
3272 // SINGLE_TASK_LAUNCH it's not entirely clear. We'd like
3273 // to have the same behavior as if a new instance was
3274 // being started, which means not bringing it to the front
3275 // if the caller is not itself in the front.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003276 HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003277 if (curTop.task != taskTop.task) {
3278 r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
3279 boolean callerAtFront = sourceRecord == null
3280 || curTop.task == sourceRecord.task;
3281 if (callerAtFront) {
3282 // We really do want to push this one into the
3283 // user's face, right now.
3284 moveTaskToFrontLocked(taskTop.task);
3285 }
3286 }
3287 // If the caller has requested that the target task be
3288 // reset, then do so.
3289 if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
3290 taskTop = resetTaskIfNeededLocked(taskTop, r);
3291 }
3292 if (onlyIfNeeded) {
3293 // We don't need to start a new activity, and
3294 // the client said not to do anything if that
3295 // is the case, so this is it! And for paranoia, make
3296 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003297 if (doResume) {
3298 resumeTopActivityLocked(null);
3299 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003300 return START_RETURN_INTENT_TO_CALLER;
3301 }
3302 if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
3303 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
3304 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
3305 // In this situation we want to remove all activities
3306 // from the task up to the one being started. In most
3307 // cases this means we are resetting the task to its
3308 // initial state.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003309 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003310 taskTop.task.taskId, r, true);
3311 if (top != null) {
3312 if (top.frontOfTask) {
3313 // Activity aliases may mean we use different
3314 // intents for the top activity, so make sure
3315 // the task now has the identity of the new
3316 // intent.
3317 top.task.setIntent(r.intent, r.info);
3318 }
3319 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3320 deliverNewIntentLocked(top, r.intent);
3321 } else {
3322 // A special case: we need to
3323 // start the activity because it is not currently
3324 // running, and the caller has asked to clear the
3325 // current task to have this activity at the top.
3326 addingToTask = true;
3327 // Now pretend like this activity is being started
3328 // by the top of its task, so it is put in the
3329 // right place.
3330 sourceRecord = taskTop;
3331 }
3332 } else if (r.realActivity.equals(taskTop.task.realActivity)) {
3333 // In this case the top activity on the task is the
3334 // same as the one being launched, so we take that
3335 // as a request to bring the task to the foreground.
3336 // If the top activity in the task is the root
3337 // activity, deliver this new intent to it if it
3338 // desires.
3339 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3340 && taskTop.realActivity.equals(r.realActivity)) {
3341 logStartActivity(LOG_AM_NEW_INTENT, r, taskTop.task);
3342 if (taskTop.frontOfTask) {
3343 taskTop.task.setIntent(r.intent, r.info);
3344 }
3345 deliverNewIntentLocked(taskTop, r.intent);
3346 } else if (!r.intent.filterEquals(taskTop.task.intent)) {
3347 // In this case we are launching the root activity
3348 // of the task, but with a different intent. We
3349 // should start a new instance on top.
3350 addingToTask = true;
3351 sourceRecord = taskTop;
3352 }
3353 } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
3354 // In this case an activity is being launched in to an
3355 // existing task, without resetting that task. This
3356 // is typically the situation of launching an activity
3357 // from a notification or shortcut. We want to place
3358 // the new activity on top of the current task.
3359 addingToTask = true;
3360 sourceRecord = taskTop;
3361 } else if (!taskTop.task.rootWasReset) {
3362 // In this case we are launching in to an existing task
3363 // that has not yet been started from its front door.
3364 // The current task has been brought to the front.
3365 // Ideally, we'd probably like to place this new task
3366 // at the bottom of its stack, but that's a little hard
3367 // to do with the current organization of the code so
3368 // for now we'll just drop it.
3369 taskTop.task.setIntent(r.intent, r.info);
3370 }
3371 if (!addingToTask) {
3372 // We didn't do anything... but it was needed (a.k.a., client
3373 // don't use that intent!) And for paranoia, make
3374 // sure we have correctly resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003375 if (doResume) {
3376 resumeTopActivityLocked(null);
3377 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003378 return START_TASK_TO_FRONT;
3379 }
3380 }
3381 }
3382 }
3383
3384 //String uri = r.intent.toURI();
3385 //Intent intent2 = new Intent(uri);
3386 //Log.i(TAG, "Given intent: " + r.intent);
3387 //Log.i(TAG, "URI is: " + uri);
3388 //Log.i(TAG, "To intent: " + intent2);
3389
3390 if (r.packageName != null) {
3391 // If the activity being launched is the same as the one currently
3392 // at the top, then we need to check if it should only be launched
3393 // once.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003394 HistoryRecord top = topRunningNonDelayedActivityLocked(notTop);
3395 if (top != null && r.resultTo == null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003396 if (top.realActivity.equals(r.realActivity)) {
3397 if (top.app != null && top.app.thread != null) {
3398 if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
3399 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
3400 || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
3401 logStartActivity(LOG_AM_NEW_INTENT, top, top.task);
3402 // For paranoia, make sure we have correctly
3403 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003404 if (doResume) {
3405 resumeTopActivityLocked(null);
3406 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003407 if (onlyIfNeeded) {
3408 // We don't need to start a new activity, and
3409 // the client said not to do anything if that
3410 // is the case, so this is it!
3411 return START_RETURN_INTENT_TO_CALLER;
3412 }
3413 deliverNewIntentLocked(top, r.intent);
3414 return START_DELIVERED_TO_TOP;
3415 }
3416 }
3417 }
3418 }
3419
3420 } else {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003421 if (r.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003422 sendActivityResultLocked(-1,
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003423 r.resultTo, r.resultWho, r.requestCode,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003424 Activity.RESULT_CANCELED, null);
3425 }
3426 return START_CLASS_NOT_FOUND;
3427 }
3428
3429 boolean newTask = false;
3430
3431 // Should this be considered a new task?
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003432 if (r.resultTo == null && !addingToTask
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003433 && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
3434 // todo: should do better management of integers.
3435 mCurTask++;
3436 if (mCurTask <= 0) {
3437 mCurTask = 1;
3438 }
3439 r.task = new TaskRecord(mCurTask, r.info, intent,
3440 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3441 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3442 + " in new task " + r.task);
3443 newTask = true;
3444 addRecentTask(r.task);
3445
3446 } else if (sourceRecord != null) {
3447 if (!addingToTask &&
3448 (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
3449 // In this case, we are adding the activity to an existing
3450 // task, but the caller has asked to clear that task if the
3451 // activity is already running.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003452 HistoryRecord top = performClearTaskLocked(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003453 sourceRecord.task.taskId, r, true);
3454 if (top != null) {
3455 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3456 deliverNewIntentLocked(top, r.intent);
3457 // For paranoia, make sure we have correctly
3458 // resumed the top activity.
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003459 if (doResume) {
3460 resumeTopActivityLocked(null);
3461 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003462 return START_DELIVERED_TO_TOP;
3463 }
3464 } else if (!addingToTask &&
3465 (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
3466 // In this case, we are launching an activity in our own task
3467 // that may already be running somewhere in the history, and
3468 // we want to shuffle it to the front of the stack if so.
3469 int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);
3470 if (where >= 0) {
3471 HistoryRecord top = moveActivityToFrontLocked(where);
3472 logStartActivity(LOG_AM_NEW_INTENT, r, top.task);
3473 deliverNewIntentLocked(top, r.intent);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003474 if (doResume) {
3475 resumeTopActivityLocked(null);
3476 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003477 return START_DELIVERED_TO_TOP;
3478 }
3479 }
3480 // An existing activity is starting this new activity, so we want
3481 // to keep the new one in the same task as the one that is starting
3482 // it.
3483 r.task = sourceRecord.task;
3484 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3485 + " in existing task " + r.task);
3486
3487 } else {
3488 // This not being started from an existing activity, and not part
3489 // of a new task... just put it in the top task, though these days
3490 // this case should never happen.
3491 final int N = mHistory.size();
3492 HistoryRecord prev =
3493 N > 0 ? (HistoryRecord)mHistory.get(N-1) : null;
3494 r.task = prev != null
3495 ? prev.task
3496 : new TaskRecord(mCurTask, r.info, intent,
3497 (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
3498 if (DEBUG_TASKS) Log.v(TAG, "Starting new activity " + r
3499 + " in new guessed " + r.task);
3500 }
3501 if (newTask) {
3502 EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId);
3503 }
3504 logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task);
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07003505 startActivityLocked(r, newTask, doResume);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003506 return START_SUCCESS;
3507 }
3508
3509 public final int startActivity(IApplicationThread caller,
3510 Intent intent, String resolvedType, Uri[] grantedUriPermissions,
3511 int grantedMode, IBinder resultTo,
3512 String resultWho, int requestCode, boolean onlyIfNeeded,
3513 boolean debug) {
3514 // Refuse possible leaked file descriptors
3515 if (intent != null && intent.hasFileDescriptors()) {
3516 throw new IllegalArgumentException("File descriptors passed in Intent");
3517 }
3518
The Android Open Source Project4df24232009-03-05 14:34:35 -08003519 final boolean componentSpecified = intent.getComponent() != null;
3520
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003521 // Don't modify the client's object!
3522 intent = new Intent(intent);
3523
3524 // Collect information about the target of the Intent.
3525 // Must do this before locking, because resolving the intent
3526 // may require launching a process to run its content provider.
3527 ActivityInfo aInfo;
3528 try {
3529 ResolveInfo rInfo =
3530 ActivityThread.getPackageManager().resolveIntent(
3531 intent, resolvedType,
3532 PackageManager.MATCH_DEFAULT_ONLY
Dianne Hackborn1655be42009-05-08 14:29:01 -07003533 | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003534 aInfo = rInfo != null ? rInfo.activityInfo : null;
3535 } catch (RemoteException e) {
3536 aInfo = null;
3537 }
3538
3539 if (aInfo != null) {
3540 // Store the found target back into the intent, because now that
3541 // we have it we never want to do this again. For example, if the
3542 // user navigates back to this point in the history, we should
3543 // always restart the exact same activity.
3544 intent.setComponent(new ComponentName(
3545 aInfo.applicationInfo.packageName, aInfo.name));
3546
3547 // Don't debug things in the system process
3548 if (debug) {
3549 if (!aInfo.processName.equals("system")) {
3550 setDebugApp(aInfo.processName, true, false);
3551 }
3552 }
3553 }
3554
3555 synchronized(this) {
3556 final long origId = Binder.clearCallingIdentity();
3557 int res = startActivityLocked(caller, intent, resolvedType,
3558 grantedUriPermissions, grantedMode, aInfo,
3559 resultTo, resultWho, requestCode, -1, -1,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003560 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003561 Binder.restoreCallingIdentity(origId);
3562 return res;
3563 }
3564 }
3565
3566 public boolean startNextMatchingActivity(IBinder callingActivity,
3567 Intent intent) {
3568 // Refuse possible leaked file descriptors
3569 if (intent != null && intent.hasFileDescriptors() == true) {
3570 throw new IllegalArgumentException("File descriptors passed in Intent");
3571 }
3572
3573 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003574 int index = indexOfTokenLocked(callingActivity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003575 if (index < 0) {
3576 return false;
3577 }
3578 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3579 if (r.app == null || r.app.thread == null) {
3580 // The caller is not running... d'oh!
3581 return false;
3582 }
3583 intent = new Intent(intent);
3584 // The caller is not allowed to change the data.
3585 intent.setDataAndType(r.intent.getData(), r.intent.getType());
3586 // And we are resetting to find the next component...
3587 intent.setComponent(null);
3588
3589 ActivityInfo aInfo = null;
3590 try {
3591 List<ResolveInfo> resolves =
3592 ActivityThread.getPackageManager().queryIntentActivities(
3593 intent, r.resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003594 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003595
3596 // Look for the original activity in the list...
3597 final int N = resolves != null ? resolves.size() : 0;
3598 for (int i=0; i<N; i++) {
3599 ResolveInfo rInfo = resolves.get(i);
3600 if (rInfo.activityInfo.packageName.equals(r.packageName)
3601 && rInfo.activityInfo.name.equals(r.info.name)) {
3602 // We found the current one... the next matching is
3603 // after it.
3604 i++;
3605 if (i<N) {
3606 aInfo = resolves.get(i).activityInfo;
3607 }
3608 break;
3609 }
3610 }
3611 } catch (RemoteException e) {
3612 }
3613
3614 if (aInfo == null) {
3615 // Nobody who is next!
3616 return false;
3617 }
3618
3619 intent.setComponent(new ComponentName(
3620 aInfo.applicationInfo.packageName, aInfo.name));
3621 intent.setFlags(intent.getFlags()&~(
3622 Intent.FLAG_ACTIVITY_FORWARD_RESULT|
3623 Intent.FLAG_ACTIVITY_CLEAR_TOP|
3624 Intent.FLAG_ACTIVITY_MULTIPLE_TASK|
3625 Intent.FLAG_ACTIVITY_NEW_TASK));
3626
3627 // Okay now we need to start the new activity, replacing the
3628 // currently running activity. This is a little tricky because
3629 // we want to start the new one as if the current one is finished,
3630 // but not finish the current one first so that there is no flicker.
3631 // And thus...
3632 final boolean wasFinishing = r.finishing;
3633 r.finishing = true;
3634
3635 // Propagate reply information over to the new activity.
3636 final HistoryRecord resultTo = r.resultTo;
3637 final String resultWho = r.resultWho;
3638 final int requestCode = r.requestCode;
3639 r.resultTo = null;
3640 if (resultTo != null) {
3641 resultTo.removeResultsLocked(r, resultWho, requestCode);
3642 }
3643
3644 final long origId = Binder.clearCallingIdentity();
3645 // XXX we are not dealing with propagating grantedUriPermissions...
3646 // those are not yet exposed to user code, so there is no need.
3647 int res = startActivityLocked(r.app.thread, intent,
3648 r.resolvedType, null, 0, aInfo, resultTo, resultWho,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003649 requestCode, -1, r.launchedFromUid, false, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003650 Binder.restoreCallingIdentity(origId);
3651
3652 r.finishing = wasFinishing;
3653 if (res != START_SUCCESS) {
3654 return false;
3655 }
3656 return true;
3657 }
3658 }
3659
3660 final int startActivityInPackage(int uid,
3661 Intent intent, String resolvedType, IBinder resultTo,
3662 String resultWho, int requestCode, boolean onlyIfNeeded) {
The Android Open Source Project4df24232009-03-05 14:34:35 -08003663 final boolean componentSpecified = intent.getComponent() != null;
3664
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003665 // Don't modify the client's object!
3666 intent = new Intent(intent);
3667
3668 // Collect information about the target of the Intent.
3669 // Must do this before locking, because resolving the intent
3670 // may require launching a process to run its content provider.
3671 ActivityInfo aInfo;
3672 try {
3673 ResolveInfo rInfo =
3674 ActivityThread.getPackageManager().resolveIntent(
3675 intent, resolvedType,
Dianne Hackborn1655be42009-05-08 14:29:01 -07003676 PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003677 aInfo = rInfo != null ? rInfo.activityInfo : null;
3678 } catch (RemoteException e) {
3679 aInfo = null;
3680 }
3681
3682 if (aInfo != null) {
3683 // Store the found target back into the intent, because now that
3684 // we have it we never want to do this again. For example, if the
3685 // user navigates back to this point in the history, we should
3686 // always restart the exact same activity.
3687 intent.setComponent(new ComponentName(
3688 aInfo.applicationInfo.packageName, aInfo.name));
3689 }
3690
3691 synchronized(this) {
3692 return startActivityLocked(null, intent, resolvedType,
3693 null, 0, aInfo, resultTo, resultWho, requestCode, -1, uid,
The Android Open Source Project4df24232009-03-05 14:34:35 -08003694 onlyIfNeeded, componentSpecified);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003695 }
3696 }
3697
3698 private final void addRecentTask(TaskRecord task) {
3699 // Remove any existing entries that are the same kind of task.
3700 int N = mRecentTasks.size();
3701 for (int i=0; i<N; i++) {
3702 TaskRecord tr = mRecentTasks.get(i);
3703 if ((task.affinity != null && task.affinity.equals(tr.affinity))
3704 || (task.intent != null && task.intent.filterEquals(tr.intent))) {
3705 mRecentTasks.remove(i);
3706 i--;
3707 N--;
3708 if (task.intent == null) {
3709 // If the new recent task we are adding is not fully
3710 // specified, then replace it with the existing recent task.
3711 task = tr;
3712 }
3713 }
3714 }
3715 if (N >= MAX_RECENT_TASKS) {
3716 mRecentTasks.remove(N-1);
3717 }
3718 mRecentTasks.add(0, task);
3719 }
3720
3721 public void setRequestedOrientation(IBinder token,
3722 int requestedOrientation) {
3723 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003724 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003725 if (index < 0) {
3726 return;
3727 }
3728 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3729 final long origId = Binder.clearCallingIdentity();
3730 mWindowManager.setAppOrientation(r, requestedOrientation);
3731 Configuration config = mWindowManager.updateOrientationFromAppTokens(
The Android Open Source Project10592532009-03-18 17:39:46 -07003732 mConfiguration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003733 r.mayFreezeScreenLocked(r.app) ? r : null);
3734 if (config != null) {
3735 r.frozenBeforeDestroy = true;
3736 if (!updateConfigurationLocked(config, r)) {
3737 resumeTopActivityLocked(null);
3738 }
3739 }
3740 Binder.restoreCallingIdentity(origId);
3741 }
3742 }
3743
3744 public int getRequestedOrientation(IBinder token) {
3745 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003746 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003747 if (index < 0) {
3748 return ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
3749 }
3750 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3751 return mWindowManager.getAppOrientation(r);
3752 }
3753 }
3754
3755 private final void stopActivityLocked(HistoryRecord r) {
3756 if (DEBUG_SWITCH) Log.d(TAG, "Stopping: " + r);
3757 if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_HISTORY) != 0
3758 || (r.info.flags&ActivityInfo.FLAG_NO_HISTORY) != 0) {
3759 if (!r.finishing) {
3760 requestFinishActivityLocked(r, Activity.RESULT_CANCELED, null,
3761 "no-history");
3762 }
3763 } else if (r.app != null && r.app.thread != null) {
3764 if (mFocusedActivity == r) {
3765 setFocusedActivityLocked(topRunningActivityLocked(null));
3766 }
3767 r.resumeKeyDispatchingLocked();
3768 try {
3769 r.stopped = false;
3770 r.state = ActivityState.STOPPING;
3771 if (DEBUG_VISBILITY) Log.v(
3772 TAG, "Stopping visible=" + r.visible + " for " + r);
3773 if (!r.visible) {
3774 mWindowManager.setAppVisibility(r, false);
3775 }
3776 r.app.thread.scheduleStopActivity(r, r.visible, r.configChangeFlags);
3777 } catch (Exception e) {
3778 // Maybe just ignore exceptions here... if the process
3779 // has crashed, our death notification will clean things
3780 // up.
3781 Log.w(TAG, "Exception thrown during pause", e);
3782 // Just in case, assume it to be stopped.
3783 r.stopped = true;
3784 r.state = ActivityState.STOPPED;
3785 if (r.configDestroy) {
3786 destroyActivityLocked(r, true);
3787 }
3788 }
3789 }
3790 }
3791
3792 /**
3793 * @return Returns true if the activity is being finished, false if for
3794 * some reason it is being left as-is.
3795 */
3796 private final boolean requestFinishActivityLocked(IBinder token, int resultCode,
3797 Intent resultData, String reason) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003798 if (DEBUG_RESULTS) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003799 TAG, "Finishing activity: token=" + token
3800 + ", result=" + resultCode + ", data=" + resultData);
3801
Dianne Hackborn75b03852009-06-12 15:43:26 -07003802 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003803 if (index < 0) {
3804 return false;
3805 }
3806 HistoryRecord r = (HistoryRecord)mHistory.get(index);
3807
3808 // Is this the last activity left?
3809 boolean lastActivity = true;
3810 for (int i=mHistory.size()-1; i>=0; i--) {
3811 HistoryRecord p = (HistoryRecord)mHistory.get(i);
3812 if (!p.finishing && p != r) {
3813 lastActivity = false;
3814 break;
3815 }
3816 }
3817
3818 // If this is the last activity, but it is the home activity, then
3819 // just don't finish it.
3820 if (lastActivity) {
3821 if (r.intent.hasCategory(Intent.CATEGORY_HOME)) {
3822 return false;
3823 }
3824 }
3825
3826 finishActivityLocked(r, index, resultCode, resultData, reason);
3827 return true;
3828 }
3829
3830 /**
3831 * @return Returns true if this activity has been removed from the history
3832 * list, or false if it is still in the list and will be removed later.
3833 */
3834 private final boolean finishActivityLocked(HistoryRecord r, int index,
3835 int resultCode, Intent resultData, String reason) {
3836 if (r.finishing) {
3837 Log.w(TAG, "Duplicate finish request for " + r);
3838 return false;
3839 }
3840
3841 r.finishing = true;
3842 EventLog.writeEvent(LOG_AM_FINISH_ACTIVITY,
3843 System.identityHashCode(r),
3844 r.task.taskId, r.shortComponentName, reason);
3845 r.task.numActivities--;
3846 if (r.frontOfTask && index < (mHistory.size()-1)) {
3847 HistoryRecord next = (HistoryRecord)mHistory.get(index+1);
3848 if (next.task == r.task) {
3849 next.frontOfTask = true;
3850 }
3851 }
3852
3853 r.pauseKeyDispatchingLocked();
3854 if (mFocusedActivity == r) {
3855 setFocusedActivityLocked(topRunningActivityLocked(null));
3856 }
3857
3858 // send the result
3859 HistoryRecord resultTo = r.resultTo;
3860 if (resultTo != null) {
Chris Tate8a7dc172009-03-24 20:11:42 -07003861 if (DEBUG_RESULTS) Log.v(TAG, "Adding result to " + resultTo
3862 + " who=" + r.resultWho + " req=" + r.requestCode
3863 + " res=" + resultCode + " data=" + resultData);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003864 if (r.info.applicationInfo.uid > 0) {
3865 grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3866 r.packageName, resultData, r);
3867 }
3868 resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3869 resultData);
3870 r.resultTo = null;
3871 }
Chris Tate8a7dc172009-03-24 20:11:42 -07003872 else if (DEBUG_RESULTS) Log.v(TAG, "No result destination from " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003873
3874 // Make sure this HistoryRecord is not holding on to other resources,
3875 // because clients have remote IPC references to this object so we
3876 // can't assume that will go away and want to avoid circular IPC refs.
3877 r.results = null;
3878 r.pendingResults = null;
3879 r.newIntents = null;
3880 r.icicle = null;
3881
3882 if (mPendingThumbnails.size() > 0) {
3883 // There are clients waiting to receive thumbnails so, in case
3884 // this is an activity that someone is waiting for, add it
3885 // to the pending list so we can correctly update the clients.
3886 mCancelledThumbnails.add(r);
3887 }
3888
3889 if (mResumedActivity == r) {
3890 boolean endTask = index <= 0
3891 || ((HistoryRecord)mHistory.get(index-1)).task != r.task;
3892 if (DEBUG_TRANSITION) Log.v(TAG,
3893 "Prepare close transition: finishing " + r);
3894 mWindowManager.prepareAppTransition(endTask
3895 ? WindowManagerPolicy.TRANSIT_TASK_CLOSE
3896 : WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE);
3897
3898 // Tell window manager to prepare for this one to be removed.
3899 mWindowManager.setAppVisibility(r, false);
3900
3901 if (mPausingActivity == null) {
3902 if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
3903 if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
3904 startPausingLocked(false, false);
3905 }
3906
3907 } else if (r.state != ActivityState.PAUSING) {
3908 // If the activity is PAUSING, we will complete the finish once
3909 // it is done pausing; else we can just directly finish it here.
3910 if (DEBUG_PAUSE) Log.v(TAG, "Finish not pausing: " + r);
3911 return finishCurrentActivityLocked(r, index,
3912 FINISH_AFTER_PAUSE) == null;
3913 } else {
3914 if (DEBUG_PAUSE) Log.v(TAG, "Finish waiting for pause of: " + r);
3915 }
3916
3917 return false;
3918 }
3919
3920 private static final int FINISH_IMMEDIATELY = 0;
3921 private static final int FINISH_AFTER_PAUSE = 1;
3922 private static final int FINISH_AFTER_VISIBLE = 2;
3923
3924 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3925 int mode) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07003926 final int index = indexOfTokenLocked(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003927 if (index < 0) {
3928 return null;
3929 }
3930
3931 return finishCurrentActivityLocked(r, index, mode);
3932 }
3933
3934 private final HistoryRecord finishCurrentActivityLocked(HistoryRecord r,
3935 int index, int mode) {
3936 // First things first: if this activity is currently visible,
3937 // and the resumed activity is not yet visible, then hold off on
3938 // finishing until the resumed one becomes visible.
3939 if (mode == FINISH_AFTER_VISIBLE && r.nowVisible) {
3940 if (!mStoppingActivities.contains(r)) {
3941 mStoppingActivities.add(r);
3942 if (mStoppingActivities.size() > 3) {
3943 // If we already have a few activities waiting to stop,
3944 // then give up on things going idle and start clearing
3945 // them out.
3946 Message msg = Message.obtain();
3947 msg.what = ActivityManagerService.IDLE_NOW_MSG;
3948 mHandler.sendMessage(msg);
3949 }
3950 }
3951 r.state = ActivityState.STOPPING;
3952 updateOomAdjLocked();
3953 return r;
3954 }
3955
3956 // make sure the record is cleaned out of other places.
3957 mStoppingActivities.remove(r);
3958 mWaitingVisibleActivities.remove(r);
3959 if (mResumedActivity == r) {
3960 mResumedActivity = null;
3961 }
3962 final ActivityState prevState = r.state;
3963 r.state = ActivityState.FINISHING;
3964
3965 if (mode == FINISH_IMMEDIATELY
3966 || prevState == ActivityState.STOPPED
3967 || prevState == ActivityState.INITIALIZING) {
3968 // If this activity is already stopped, we can just finish
3969 // it right now.
3970 return destroyActivityLocked(r, true) ? null : r;
3971 } else {
3972 // Need to go through the full pause cycle to get this
3973 // activity into the stopped state and then finish it.
3974 if (localLOGV) Log.v(TAG, "Enqueueing pending finish: " + r);
3975 mFinishingActivities.add(r);
3976 resumeTopActivityLocked(null);
3977 }
3978 return r;
3979 }
3980
3981 /**
3982 * This is the internal entry point for handling Activity.finish().
3983 *
3984 * @param token The Binder token referencing the Activity we want to finish.
3985 * @param resultCode Result code, if any, from this Activity.
3986 * @param resultData Result data (Intent), if any, from this Activity.
3987 *
3988 * @result Returns true if the activity successfully finished, or false if it is still running.
3989 */
3990 public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
3991 // Refuse possible leaked file descriptors
3992 if (resultData != null && resultData.hasFileDescriptors() == true) {
3993 throw new IllegalArgumentException("File descriptors passed in Intent");
3994 }
3995
3996 synchronized(this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07003997 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003998 // Find the first activity that is not finishing.
3999 HistoryRecord next = topRunningActivityLocked(token, 0);
4000 if (next != null) {
4001 // ask watcher if this is allowed
4002 boolean resumeOK = true;
4003 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004004 resumeOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004005 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004006 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004007 }
4008
4009 if (!resumeOK) {
4010 return false;
4011 }
4012 }
4013 }
4014 final long origId = Binder.clearCallingIdentity();
4015 boolean res = requestFinishActivityLocked(token, resultCode,
4016 resultData, "app-request");
4017 Binder.restoreCallingIdentity(origId);
4018 return res;
4019 }
4020 }
4021
4022 void sendActivityResultLocked(int callingUid, HistoryRecord r,
4023 String resultWho, int requestCode, int resultCode, Intent data) {
4024
4025 if (callingUid > 0) {
4026 grantUriPermissionFromIntentLocked(callingUid, r.packageName,
4027 data, r);
4028 }
4029
The Android Open Source Project10592532009-03-18 17:39:46 -07004030 if (DEBUG_RESULTS) Log.v(TAG, "Send activity result to " + r
4031 + " : who=" + resultWho + " req=" + requestCode
4032 + " res=" + resultCode + " data=" + data);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004033 if (mResumedActivity == r && r.app != null && r.app.thread != null) {
4034 try {
4035 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
4036 list.add(new ResultInfo(resultWho, requestCode,
4037 resultCode, data));
4038 r.app.thread.scheduleSendResult(r, list);
4039 return;
4040 } catch (Exception e) {
4041 Log.w(TAG, "Exception thrown sending result to " + r, e);
4042 }
4043 }
4044
4045 r.addResultLocked(null, resultWho, requestCode, resultCode, data);
4046 }
4047
4048 public final void finishSubActivity(IBinder token, String resultWho,
4049 int requestCode) {
4050 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004051 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004052 if (index < 0) {
4053 return;
4054 }
4055 HistoryRecord self = (HistoryRecord)mHistory.get(index);
4056
4057 final long origId = Binder.clearCallingIdentity();
4058
4059 int i;
4060 for (i=mHistory.size()-1; i>=0; i--) {
4061 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4062 if (r.resultTo == self && r.requestCode == requestCode) {
4063 if ((r.resultWho == null && resultWho == null) ||
4064 (r.resultWho != null && r.resultWho.equals(resultWho))) {
4065 finishActivityLocked(r, i,
4066 Activity.RESULT_CANCELED, null, "request-sub");
4067 }
4068 }
4069 }
4070
4071 Binder.restoreCallingIdentity(origId);
4072 }
4073 }
4074
4075 /**
4076 * Perform clean-up of service connections in an activity record.
4077 */
4078 private final void cleanUpActivityServicesLocked(HistoryRecord r) {
4079 // Throw away any services that have been bound by this activity.
4080 if (r.connections != null) {
4081 Iterator<ConnectionRecord> it = r.connections.iterator();
4082 while (it.hasNext()) {
4083 ConnectionRecord c = it.next();
4084 removeConnectionLocked(c, null, r);
4085 }
4086 r.connections = null;
4087 }
4088 }
4089
4090 /**
4091 * Perform the common clean-up of an activity record. This is called both
4092 * as part of destroyActivityLocked() (when destroying the client-side
4093 * representation) and cleaning things up as a result of its hosting
4094 * processing going away, in which case there is no remaining client-side
4095 * state to destroy so only the cleanup here is needed.
4096 */
4097 private final void cleanUpActivityLocked(HistoryRecord r, boolean cleanServices) {
4098 if (mResumedActivity == r) {
4099 mResumedActivity = null;
4100 }
4101 if (mFocusedActivity == r) {
4102 mFocusedActivity = null;
4103 }
4104
4105 r.configDestroy = false;
4106 r.frozenBeforeDestroy = false;
4107
4108 // Make sure this record is no longer in the pending finishes list.
4109 // This could happen, for example, if we are trimming activities
4110 // down to the max limit while they are still waiting to finish.
4111 mFinishingActivities.remove(r);
4112 mWaitingVisibleActivities.remove(r);
4113
4114 // Remove any pending results.
4115 if (r.finishing && r.pendingResults != null) {
4116 for (WeakReference<PendingIntentRecord> apr : r.pendingResults) {
4117 PendingIntentRecord rec = apr.get();
4118 if (rec != null) {
4119 cancelIntentSenderLocked(rec, false);
4120 }
4121 }
4122 r.pendingResults = null;
4123 }
4124
4125 if (cleanServices) {
4126 cleanUpActivityServicesLocked(r);
4127 }
4128
4129 if (mPendingThumbnails.size() > 0) {
4130 // There are clients waiting to receive thumbnails so, in case
4131 // this is an activity that someone is waiting for, add it
4132 // to the pending list so we can correctly update the clients.
4133 mCancelledThumbnails.add(r);
4134 }
4135
4136 // Get rid of any pending idle timeouts.
4137 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
4138 mHandler.removeMessages(IDLE_TIMEOUT_MSG, r);
4139 }
4140
4141 private final void removeActivityFromHistoryLocked(HistoryRecord r) {
4142 if (r.state != ActivityState.DESTROYED) {
4143 mHistory.remove(r);
4144 r.inHistory = false;
4145 r.state = ActivityState.DESTROYED;
4146 mWindowManager.removeAppToken(r);
4147 if (VALIDATE_TOKENS) {
4148 mWindowManager.validateAppTokens(mHistory);
4149 }
4150 cleanUpActivityServicesLocked(r);
4151 removeActivityUriPermissionsLocked(r);
4152 }
4153 }
4154
4155 /**
4156 * Destroy the current CLIENT SIDE instance of an activity. This may be
4157 * called both when actually finishing an activity, or when performing
4158 * a configuration switch where we destroy the current client-side object
4159 * but then create a new client-side object for this same HistoryRecord.
4160 */
4161 private final boolean destroyActivityLocked(HistoryRecord r,
4162 boolean removeFromApp) {
4163 if (DEBUG_SWITCH) Log.v(
4164 TAG, "Removing activity: token=" + r
4165 + ", app=" + (r.app != null ? r.app.processName : "(null)"));
4166 EventLog.writeEvent(LOG_AM_DESTROY_ACTIVITY,
4167 System.identityHashCode(r),
4168 r.task.taskId, r.shortComponentName);
4169
4170 boolean removedFromHistory = false;
4171
4172 cleanUpActivityLocked(r, false);
4173
4174 if (r.app != null) {
4175 if (removeFromApp) {
4176 int idx = r.app.activities.indexOf(r);
4177 if (idx >= 0) {
4178 r.app.activities.remove(idx);
4179 }
4180 if (r.persistent) {
4181 decPersistentCountLocked(r.app);
4182 }
4183 }
4184
4185 boolean skipDestroy = false;
4186
4187 try {
4188 if (DEBUG_SWITCH) Log.i(TAG, "Destroying: " + r);
4189 r.app.thread.scheduleDestroyActivity(r, r.finishing,
4190 r.configChangeFlags);
4191 } catch (Exception e) {
4192 // We can just ignore exceptions here... if the process
4193 // has crashed, our death notification will clean things
4194 // up.
4195 //Log.w(TAG, "Exception thrown during finish", e);
4196 if (r.finishing) {
4197 removeActivityFromHistoryLocked(r);
4198 removedFromHistory = true;
4199 skipDestroy = true;
4200 }
4201 }
4202
4203 r.app = null;
4204 r.nowVisible = false;
4205
4206 if (r.finishing && !skipDestroy) {
4207 r.state = ActivityState.DESTROYING;
4208 Message msg = mHandler.obtainMessage(DESTROY_TIMEOUT_MSG);
4209 msg.obj = r;
4210 mHandler.sendMessageDelayed(msg, DESTROY_TIMEOUT);
4211 } else {
4212 r.state = ActivityState.DESTROYED;
4213 }
4214 } else {
4215 // remove this record from the history.
4216 if (r.finishing) {
4217 removeActivityFromHistoryLocked(r);
4218 removedFromHistory = true;
4219 } else {
4220 r.state = ActivityState.DESTROYED;
4221 }
4222 }
4223
4224 r.configChangeFlags = 0;
4225
4226 if (!mLRUActivities.remove(r)) {
4227 Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
4228 }
4229
4230 return removedFromHistory;
4231 }
4232
4233 private static void removeHistoryRecordsForAppLocked(ArrayList list,
4234 ProcessRecord app)
4235 {
4236 int i = list.size();
4237 if (localLOGV) Log.v(
4238 TAG, "Removing app " + app + " from list " + list
4239 + " with " + i + " entries");
4240 while (i > 0) {
4241 i--;
4242 HistoryRecord r = (HistoryRecord)list.get(i);
4243 if (localLOGV) Log.v(
4244 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4245 if (r.app == app) {
4246 if (localLOGV) Log.v(TAG, "Removing this entry!");
4247 list.remove(i);
4248 }
4249 }
4250 }
4251
4252 /**
4253 * Main function for removing an existing process from the activity manager
4254 * as a result of that process going away. Clears out all connections
4255 * to the process.
4256 */
4257 private final void handleAppDiedLocked(ProcessRecord app,
4258 boolean restarting) {
4259 cleanUpApplicationRecordLocked(app, restarting, -1);
4260 if (!restarting) {
4261 mLRUProcesses.remove(app);
4262 }
4263
4264 // Just in case...
4265 if (mPausingActivity != null && mPausingActivity.app == app) {
4266 if (DEBUG_PAUSE) Log.v(TAG, "App died while pausing: " + mPausingActivity);
4267 mPausingActivity = null;
4268 }
4269 if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
4270 mLastPausedActivity = null;
4271 }
4272
4273 // Remove this application's activities from active lists.
4274 removeHistoryRecordsForAppLocked(mLRUActivities, app);
4275 removeHistoryRecordsForAppLocked(mStoppingActivities, app);
4276 removeHistoryRecordsForAppLocked(mWaitingVisibleActivities, app);
4277 removeHistoryRecordsForAppLocked(mFinishingActivities, app);
4278
4279 boolean atTop = true;
4280 boolean hasVisibleActivities = false;
4281
4282 // Clean out the history list.
4283 int i = mHistory.size();
4284 if (localLOGV) Log.v(
4285 TAG, "Removing app " + app + " from history with " + i + " entries");
4286 while (i > 0) {
4287 i--;
4288 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4289 if (localLOGV) Log.v(
4290 TAG, "Record #" + i + " " + r + ": app=" + r.app);
4291 if (r.app == app) {
4292 if ((!r.haveState && !r.stateNotNeeded) || r.finishing) {
4293 if (localLOGV) Log.v(
4294 TAG, "Removing this entry! frozen=" + r.haveState
4295 + " finishing=" + r.finishing);
4296 mHistory.remove(i);
4297
4298 r.inHistory = false;
4299 mWindowManager.removeAppToken(r);
4300 if (VALIDATE_TOKENS) {
4301 mWindowManager.validateAppTokens(mHistory);
4302 }
4303 removeActivityUriPermissionsLocked(r);
4304
4305 } else {
4306 // We have the current state for this activity, so
4307 // it can be restarted later when needed.
4308 if (localLOGV) Log.v(
4309 TAG, "Keeping entry, setting app to null");
4310 if (r.visible) {
4311 hasVisibleActivities = true;
4312 }
4313 r.app = null;
4314 r.nowVisible = false;
4315 if (!r.haveState) {
4316 r.icicle = null;
4317 }
4318 }
4319
4320 cleanUpActivityLocked(r, true);
4321 r.state = ActivityState.STOPPED;
4322 }
4323 atTop = false;
4324 }
4325
4326 app.activities.clear();
4327
4328 if (app.instrumentationClass != null) {
4329 Log.w(TAG, "Crash of app " + app.processName
4330 + " running instrumentation " + app.instrumentationClass);
4331 Bundle info = new Bundle();
4332 info.putString("shortMsg", "Process crashed.");
4333 finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
4334 }
4335
4336 if (!restarting) {
4337 if (!resumeTopActivityLocked(null)) {
4338 // If there was nothing to resume, and we are not already
4339 // restarting this process, but there is a visible activity that
4340 // is hosted by the process... then make sure all visible
4341 // activities are running, taking care of restarting this
4342 // process.
4343 if (hasVisibleActivities) {
4344 ensureActivitiesVisibleLocked(null, 0);
4345 }
4346 }
4347 }
4348 }
4349
4350 private final int getLRURecordIndexForAppLocked(IApplicationThread thread) {
4351 IBinder threadBinder = thread.asBinder();
4352
4353 // Find the application record.
4354 int count = mLRUProcesses.size();
4355 int i;
4356 for (i=0; i<count; i++) {
4357 ProcessRecord rec = mLRUProcesses.get(i);
4358 if (rec.thread != null && rec.thread.asBinder() == threadBinder) {
4359 return i;
4360 }
4361 }
4362 return -1;
4363 }
4364
4365 private final ProcessRecord getRecordForAppLocked(
4366 IApplicationThread thread) {
4367 if (thread == null) {
4368 return null;
4369 }
4370
4371 int appIndex = getLRURecordIndexForAppLocked(thread);
4372 return appIndex >= 0 ? mLRUProcesses.get(appIndex) : null;
4373 }
4374
4375 private final void appDiedLocked(ProcessRecord app, int pid,
4376 IApplicationThread thread) {
4377
4378 mProcDeaths[0]++;
4379
4380 if (app.thread != null && app.thread.asBinder() == thread.asBinder()) {
4381 Log.i(TAG, "Process " + app.processName + " (pid " + pid
4382 + ") has died.");
4383 EventLog.writeEvent(LOG_AM_PROCESS_DIED, app.pid, app.processName);
4384 if (localLOGV) Log.v(
4385 TAG, "Dying app: " + app + ", pid: " + pid
4386 + ", thread: " + thread.asBinder());
4387 boolean doLowMem = app.instrumentationClass == null;
4388 handleAppDiedLocked(app, false);
4389
4390 if (doLowMem) {
4391 // If there are no longer any background processes running,
4392 // and the app that died was not running instrumentation,
4393 // then tell everyone we are now low on memory.
4394 boolean haveBg = false;
4395 int count = mLRUProcesses.size();
4396 int i;
4397 for (i=0; i<count; i++) {
4398 ProcessRecord rec = mLRUProcesses.get(i);
4399 if (rec.thread != null && rec.setAdj >= HIDDEN_APP_MIN_ADJ) {
4400 haveBg = true;
4401 break;
4402 }
4403 }
4404
4405 if (!haveBg) {
4406 Log.i(TAG, "Low Memory: No more background processes.");
4407 EventLog.writeEvent(LOG_AM_LOW_MEMORY, mLRUProcesses.size());
4408 for (i=0; i<count; i++) {
4409 ProcessRecord rec = mLRUProcesses.get(i);
4410 if (rec.thread != null) {
4411 rec.lastRequestedGc = SystemClock.uptimeMillis();
4412 try {
4413 rec.thread.scheduleLowMemory();
4414 } catch (RemoteException e) {
4415 // Don't care if the process is gone.
4416 }
4417 }
4418 }
4419 }
4420 }
4421 } else if (Config.LOGD) {
4422 Log.d(TAG, "Received spurious death notification for thread "
4423 + thread.asBinder());
4424 }
4425 }
4426
4427 final String readFile(String filename) {
4428 try {
4429 FileInputStream fs = new FileInputStream(filename);
4430 byte[] inp = new byte[8192];
4431 int size = fs.read(inp);
4432 fs.close();
4433 return new String(inp, 0, 0, size);
4434 } catch (java.io.IOException e) {
4435 }
4436 return "";
4437 }
4438
4439 final void appNotRespondingLocked(ProcessRecord app, HistoryRecord activity,
4440 final String annotation) {
4441 if (app.notResponding || app.crashing) {
4442 return;
4443 }
4444
4445 // Log the ANR to the event log.
4446 EventLog.writeEvent(LOG_ANR, app.pid, app.processName, annotation);
4447
4448 // If we are on a secure build and the application is not interesting to the user (it is
4449 // not visible or in the background), just kill it instead of displaying a dialog.
4450 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
4451 if (isSecure && !app.isInterestingToUserLocked() && Process.myPid() != app.pid) {
4452 Process.killProcess(app.pid);
4453 return;
4454 }
4455
4456 // DeviceMonitor.start();
4457
4458 String processInfo = null;
4459 if (MONITOR_CPU_USAGE) {
4460 updateCpuStatsNow();
4461 synchronized (mProcessStatsThread) {
4462 processInfo = mProcessStats.printCurrentState();
4463 }
4464 }
4465
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004466 StringBuilder info = mStringBuilder;
4467 info.setLength(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004468 info.append("ANR (application not responding) in process: ");
4469 info.append(app.processName);
4470 if (annotation != null) {
4471 info.append("\nAnnotation: ");
4472 info.append(annotation);
4473 }
4474 if (MONITOR_CPU_USAGE) {
4475 info.append("\nCPU usage:\n");
4476 info.append(processInfo);
4477 }
4478 Log.i(TAG, info.toString());
4479
4480 // The application is not responding. Dump as many thread traces as we can.
4481 boolean fileDump = prepareTraceFile(true);
4482 if (!fileDump) {
4483 // Dumping traces to the log, just dump the process that isn't responding so
4484 // we don't overflow the log
4485 Process.sendSignal(app.pid, Process.SIGNAL_QUIT);
4486 } else {
4487 // Dumping traces to a file so dump all active processes we know about
4488 synchronized (this) {
4489 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
4490 ProcessRecord r = mLRUProcesses.get(i);
4491 if (r.thread != null) {
4492 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
4493 }
4494 }
4495 }
4496 }
4497
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004498 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004499 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004500 int res = mController.appNotResponding(app.processName,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004501 app.pid, info.toString());
4502 if (res != 0) {
4503 if (res < 0) {
4504 // wait until the SIGQUIT has had a chance to process before killing the
4505 // process.
4506 try {
4507 wait(2000);
4508 } catch (InterruptedException e) {
4509 }
4510
4511 Process.killProcess(app.pid);
4512 return;
4513 }
4514 }
4515 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07004516 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004517 }
4518 }
4519
4520 makeAppNotRespondingLocked(app,
4521 activity != null ? activity.shortComponentName : null,
4522 annotation != null ? "ANR " + annotation : "ANR",
4523 info.toString(), null);
4524 Message msg = Message.obtain();
4525 HashMap map = new HashMap();
4526 msg.what = SHOW_NOT_RESPONDING_MSG;
4527 msg.obj = map;
4528 map.put("app", app);
4529 if (activity != null) {
4530 map.put("activity", activity);
4531 }
4532
4533 mHandler.sendMessage(msg);
4534 return;
4535 }
4536
4537 /**
4538 * If a stack trace file has been configured, prepare the filesystem
4539 * by creating the directory if it doesn't exist and optionally
4540 * removing the old trace file.
4541 *
4542 * @param removeExisting If set, the existing trace file will be removed.
4543 * @return Returns true if the trace file preparations succeeded
4544 */
4545 public static boolean prepareTraceFile(boolean removeExisting) {
4546 String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
4547 boolean fileReady = false;
4548 if (!TextUtils.isEmpty(tracesPath)) {
4549 File f = new File(tracesPath);
4550 if (!f.exists()) {
4551 // Ensure the enclosing directory exists
4552 File dir = f.getParentFile();
4553 if (!dir.exists()) {
4554 fileReady = dir.mkdirs();
4555 FileUtils.setPermissions(dir.getAbsolutePath(),
4556 FileUtils.S_IRWXU | FileUtils.S_IRWXG | FileUtils.S_IRWXO, -1, -1);
4557 } else if (dir.isDirectory()) {
4558 fileReady = true;
4559 }
4560 } else if (removeExisting) {
4561 // Remove the previous traces file, so we don't fill the disk.
4562 // The VM will recreate it
4563 Log.i(TAG, "Removing old ANR trace file from " + tracesPath);
4564 fileReady = f.delete();
4565 }
4566 }
4567
4568 return fileReady;
4569 }
4570
4571
4572 private final void decPersistentCountLocked(ProcessRecord app)
4573 {
4574 app.persistentActivities--;
4575 if (app.persistentActivities > 0) {
4576 // Still more of 'em...
4577 return;
4578 }
4579 if (app.persistent) {
4580 // Ah, but the application itself is persistent. Whatever!
4581 return;
4582 }
4583
4584 // App is no longer persistent... make sure it and the ones
4585 // following it in the LRU list have the correc oom_adj.
4586 updateOomAdjLocked();
4587 }
4588
4589 public void setPersistent(IBinder token, boolean isPersistent) {
4590 if (checkCallingPermission(android.Manifest.permission.PERSISTENT_ACTIVITY)
4591 != PackageManager.PERMISSION_GRANTED) {
4592 String msg = "Permission Denial: setPersistent() from pid="
4593 + Binder.getCallingPid()
4594 + ", uid=" + Binder.getCallingUid()
4595 + " requires " + android.Manifest.permission.PERSISTENT_ACTIVITY;
4596 Log.w(TAG, msg);
4597 throw new SecurityException(msg);
4598 }
4599
4600 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07004601 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004602 if (index < 0) {
4603 return;
4604 }
4605 HistoryRecord r = (HistoryRecord)mHistory.get(index);
4606 ProcessRecord app = r.app;
4607
4608 if (localLOGV) Log.v(
4609 TAG, "Setting persistence " + isPersistent + ": " + r);
4610
4611 if (isPersistent) {
4612 if (r.persistent) {
4613 // Okay okay, I heard you already!
4614 if (localLOGV) Log.v(TAG, "Already persistent!");
4615 return;
4616 }
4617 r.persistent = true;
4618 app.persistentActivities++;
4619 if (localLOGV) Log.v(TAG, "Num persistent now: " + app.persistentActivities);
4620 if (app.persistentActivities > 1) {
4621 // We aren't the first...
4622 if (localLOGV) Log.v(TAG, "Not the first!");
4623 return;
4624 }
4625 if (app.persistent) {
4626 // This would be redundant.
4627 if (localLOGV) Log.v(TAG, "App is persistent!");
4628 return;
4629 }
4630
4631 // App is now persistent... make sure it and the ones
4632 // following it now have the correct oom_adj.
4633 final long origId = Binder.clearCallingIdentity();
4634 updateOomAdjLocked();
4635 Binder.restoreCallingIdentity(origId);
4636
4637 } else {
4638 if (!r.persistent) {
4639 // Okay okay, I heard you already!
4640 return;
4641 }
4642 r.persistent = false;
4643 final long origId = Binder.clearCallingIdentity();
4644 decPersistentCountLocked(app);
4645 Binder.restoreCallingIdentity(origId);
4646
4647 }
4648 }
4649 }
4650
4651 public boolean clearApplicationUserData(final String packageName,
4652 final IPackageDataObserver observer) {
4653 int uid = Binder.getCallingUid();
4654 int pid = Binder.getCallingPid();
4655 long callingId = Binder.clearCallingIdentity();
4656 try {
4657 IPackageManager pm = ActivityThread.getPackageManager();
4658 int pkgUid = -1;
4659 synchronized(this) {
4660 try {
4661 pkgUid = pm.getPackageUid(packageName);
4662 } catch (RemoteException e) {
4663 }
4664 if (pkgUid == -1) {
4665 Log.w(TAG, "Invalid packageName:" + packageName);
4666 return false;
4667 }
4668 if (uid == pkgUid || checkComponentPermission(
4669 android.Manifest.permission.CLEAR_APP_USER_DATA,
4670 pid, uid, -1)
4671 == PackageManager.PERMISSION_GRANTED) {
4672 restartPackageLocked(packageName, pkgUid);
4673 } else {
4674 throw new SecurityException(pid+" does not have permission:"+
4675 android.Manifest.permission.CLEAR_APP_USER_DATA+" to clear data" +
4676 "for process:"+packageName);
4677 }
4678 }
4679
4680 try {
4681 //clear application user data
4682 pm.clearApplicationUserData(packageName, observer);
4683 Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED,
4684 Uri.fromParts("package", packageName, null));
4685 intent.putExtra(Intent.EXTRA_UID, pkgUid);
4686 broadcastIntentLocked(null, null, intent,
4687 null, null, 0, null, null, null,
4688 false, false, MY_PID, Process.SYSTEM_UID);
4689 } catch (RemoteException e) {
4690 }
4691 } finally {
4692 Binder.restoreCallingIdentity(callingId);
4693 }
4694 return true;
4695 }
4696
4697 public void restartPackage(final String packageName) {
4698 if (checkCallingPermission(android.Manifest.permission.RESTART_PACKAGES)
4699 != PackageManager.PERMISSION_GRANTED) {
4700 String msg = "Permission Denial: restartPackage() from pid="
4701 + Binder.getCallingPid()
4702 + ", uid=" + Binder.getCallingUid()
4703 + " requires " + android.Manifest.permission.RESTART_PACKAGES;
4704 Log.w(TAG, msg);
4705 throw new SecurityException(msg);
4706 }
4707
4708 long callingId = Binder.clearCallingIdentity();
4709 try {
4710 IPackageManager pm = ActivityThread.getPackageManager();
4711 int pkgUid = -1;
4712 synchronized(this) {
4713 try {
4714 pkgUid = pm.getPackageUid(packageName);
4715 } catch (RemoteException e) {
4716 }
4717 if (pkgUid == -1) {
4718 Log.w(TAG, "Invalid packageName: " + packageName);
4719 return;
4720 }
4721 restartPackageLocked(packageName, pkgUid);
4722 }
4723 } finally {
4724 Binder.restoreCallingIdentity(callingId);
4725 }
4726 }
4727
4728 private void restartPackageLocked(final String packageName, int uid) {
4729 uninstallPackageLocked(packageName, uid, false);
4730 Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED,
4731 Uri.fromParts("package", packageName, null));
4732 intent.putExtra(Intent.EXTRA_UID, uid);
4733 broadcastIntentLocked(null, null, intent,
4734 null, null, 0, null, null, null,
4735 false, false, MY_PID, Process.SYSTEM_UID);
4736 }
4737
4738 private final void uninstallPackageLocked(String name, int uid,
4739 boolean callerWillRestart) {
4740 if (Config.LOGD) Log.d(TAG, "Uninstalling process " + name);
4741
4742 int i, N;
4743
4744 final String procNamePrefix = name + ":";
4745 if (uid < 0) {
4746 try {
4747 uid = ActivityThread.getPackageManager().getPackageUid(name);
4748 } catch (RemoteException e) {
4749 }
4750 }
4751
4752 Iterator<SparseArray<Long>> badApps = mProcessCrashTimes.getMap().values().iterator();
4753 while (badApps.hasNext()) {
4754 SparseArray<Long> ba = badApps.next();
4755 if (ba.get(uid) != null) {
4756 badApps.remove();
4757 }
4758 }
4759
4760 ArrayList<ProcessRecord> procs = new ArrayList<ProcessRecord>();
4761
4762 // Remove all processes this package may have touched: all with the
4763 // same UID (except for the system or root user), and all whose name
4764 // matches the package name.
4765 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
4766 final int NA = apps.size();
4767 for (int ia=0; ia<NA; ia++) {
4768 ProcessRecord app = apps.valueAt(ia);
4769 if (app.removed) {
4770 procs.add(app);
4771 } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid)
4772 || app.processName.equals(name)
4773 || app.processName.startsWith(procNamePrefix)) {
4774 app.removed = true;
4775 procs.add(app);
4776 }
4777 }
4778 }
4779
4780 N = procs.size();
4781 for (i=0; i<N; i++) {
4782 removeProcessLocked(procs.get(i), callerWillRestart);
4783 }
4784
4785 for (i=mHistory.size()-1; i>=0; i--) {
4786 HistoryRecord r = (HistoryRecord)mHistory.get(i);
4787 if (r.packageName.equals(name)) {
4788 if (Config.LOGD) Log.d(
4789 TAG, " Force finishing activity "
4790 + r.intent.getComponent().flattenToShortString());
4791 if (r.app != null) {
4792 r.app.removed = true;
4793 }
4794 r.app = null;
4795 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "uninstall");
4796 }
4797 }
4798
4799 ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>();
4800 for (ServiceRecord service : mServices.values()) {
4801 if (service.packageName.equals(name)) {
4802 if (service.app != null) {
4803 service.app.removed = true;
4804 }
4805 service.app = null;
4806 services.add(service);
4807 }
4808 }
4809
4810 N = services.size();
4811 for (i=0; i<N; i++) {
4812 bringDownServiceLocked(services.get(i), true);
4813 }
4814
4815 resumeTopActivityLocked(null);
4816 }
4817
4818 private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) {
4819 final String name = app.processName;
4820 final int uid = app.info.uid;
4821 if (Config.LOGD) Log.d(
4822 TAG, "Force removing process " + app + " (" + name
4823 + "/" + uid + ")");
4824
4825 mProcessNames.remove(name, uid);
4826 boolean needRestart = false;
4827 if (app.pid > 0 && app.pid != MY_PID) {
4828 int pid = app.pid;
4829 synchronized (mPidsSelfLocked) {
4830 mPidsSelfLocked.remove(pid);
4831 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4832 }
4833 handleAppDiedLocked(app, true);
4834 mLRUProcesses.remove(app);
4835 Process.killProcess(pid);
4836
4837 if (app.persistent) {
4838 if (!callerWillRestart) {
4839 addAppLocked(app.info);
4840 } else {
4841 needRestart = true;
4842 }
4843 }
4844 } else {
4845 mRemovedProcesses.add(app);
4846 }
4847
4848 return needRestart;
4849 }
4850
4851 private final void processStartTimedOutLocked(ProcessRecord app) {
4852 final int pid = app.pid;
4853 boolean gone = false;
4854 synchronized (mPidsSelfLocked) {
4855 ProcessRecord knownApp = mPidsSelfLocked.get(pid);
4856 if (knownApp != null && knownApp.thread == null) {
4857 mPidsSelfLocked.remove(pid);
4858 gone = true;
4859 }
4860 }
4861
4862 if (gone) {
4863 Log.w(TAG, "Process " + app + " failed to attach");
4864 mProcessNames.remove(app.processName, app.info.uid);
4865 Process.killProcess(pid);
4866 if (mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid) {
4867 Log.w(TAG, "Unattached app died before broadcast acknowledged, skipping");
4868 mPendingBroadcast = null;
4869 scheduleBroadcastsLocked();
4870 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004871 if (mBackupTarget != null && mBackupTarget.app.pid == pid) {
4872 Log.w(TAG, "Unattached app died before backup, skipping");
4873 try {
4874 IBackupManager bm = IBackupManager.Stub.asInterface(
4875 ServiceManager.getService(Context.BACKUP_SERVICE));
4876 bm.agentDisconnected(app.info.packageName);
4877 } catch (RemoteException e) {
4878 // Can't happen; the backup manager is local
4879 }
4880 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004881 } else {
4882 Log.w(TAG, "Spurious process start timeout - pid not known for " + app);
4883 }
4884 }
4885
4886 private final boolean attachApplicationLocked(IApplicationThread thread,
4887 int pid) {
4888
4889 // Find the application record that is being attached... either via
4890 // the pid if we are running in multiple processes, or just pull the
4891 // next app record if we are emulating process with anonymous threads.
4892 ProcessRecord app;
4893 if (pid != MY_PID && pid >= 0) {
4894 synchronized (mPidsSelfLocked) {
4895 app = mPidsSelfLocked.get(pid);
4896 }
4897 } else if (mStartingProcesses.size() > 0) {
4898 app = mStartingProcesses.remove(0);
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07004899 app.setPid(pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004900 } else {
4901 app = null;
4902 }
4903
4904 if (app == null) {
4905 Log.w(TAG, "No pending application record for pid " + pid
4906 + " (IApplicationThread " + thread + "); dropping process");
4907 EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
4908 if (pid > 0 && pid != MY_PID) {
4909 Process.killProcess(pid);
4910 } else {
4911 try {
4912 thread.scheduleExit();
4913 } catch (Exception e) {
4914 // Ignore exceptions.
4915 }
4916 }
4917 return false;
4918 }
4919
4920 // If this application record is still attached to a previous
4921 // process, clean it up now.
4922 if (app.thread != null) {
4923 handleAppDiedLocked(app, true);
4924 }
4925
4926 // Tell the process all about itself.
4927
4928 if (localLOGV) Log.v(
4929 TAG, "Binding process pid " + pid + " to record " + app);
4930
4931 String processName = app.processName;
4932 try {
4933 thread.asBinder().linkToDeath(new AppDeathRecipient(
4934 app, pid, thread), 0);
4935 } catch (RemoteException e) {
4936 app.resetPackageList();
4937 startProcessLocked(app, "link fail", processName);
4938 return false;
4939 }
4940
4941 EventLog.writeEvent(LOG_AM_PROCESS_BOUND, app.pid, app.processName);
4942
4943 app.thread = thread;
4944 app.curAdj = app.setAdj = -100;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07004945 app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004946 app.forcingToForeground = null;
4947 app.foregroundServices = false;
4948 app.debugging = false;
4949
4950 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
4951
4952 List providers = generateApplicationProvidersLocked(app);
4953
4954 if (localLOGV) Log.v(
4955 TAG, "New app record " + app
4956 + " thread=" + thread.asBinder() + " pid=" + pid);
4957 try {
4958 int testMode = IApplicationThread.DEBUG_OFF;
4959 if (mDebugApp != null && mDebugApp.equals(processName)) {
4960 testMode = mWaitForDebugger
4961 ? IApplicationThread.DEBUG_WAIT
4962 : IApplicationThread.DEBUG_ON;
4963 app.debugging = true;
4964 if (mDebugTransient) {
4965 mDebugApp = mOrigDebugApp;
4966 mWaitForDebugger = mOrigWaitForDebugger;
4967 }
4968 }
Christopher Tate181fafa2009-05-14 11:12:14 -07004969 // If the app is being launched for restore or full backup, set it up specially
4970 boolean isRestrictedBackupMode = false;
4971 if (mBackupTarget != null && mBackupAppName.equals(processName)) {
4972 isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
4973 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
4974 }
Dianne Hackbornd7f6daa2009-06-22 17:06:35 -07004975 ensurePackageDexOpt(app.instrumentationInfo != null
4976 ? app.instrumentationInfo.packageName
4977 : app.info.packageName);
4978 if (app.instrumentationClass != null) {
4979 ensurePackageDexOpt(app.instrumentationClass.getPackageName());
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07004980 }
Dianne Hackborn1655be42009-05-08 14:29:01 -07004981 thread.bindApplication(processName, app.instrumentationInfo != null
4982 ? app.instrumentationInfo : app.info, providers,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004983 app.instrumentationClass, app.instrumentationProfileFile,
4984 app.instrumentationArguments, app.instrumentationWatcher, testMode,
Christopher Tate181fafa2009-05-14 11:12:14 -07004985 isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004986 updateLRUListLocked(app, false);
4987 app.lastRequestedGc = SystemClock.uptimeMillis();
4988 } catch (Exception e) {
4989 // todo: Yikes! What should we do? For now we will try to
4990 // start another process, but that could easily get us in
4991 // an infinite loop of restarting processes...
4992 Log.w(TAG, "Exception thrown during bind!", e);
4993
4994 app.resetPackageList();
4995 startProcessLocked(app, "bind fail", processName);
4996 return false;
4997 }
4998
4999 // Remove this record from the list of starting applications.
5000 mPersistentStartingProcesses.remove(app);
5001 mProcessesOnHold.remove(app);
5002
5003 boolean badApp = false;
5004 boolean didSomething = false;
5005
5006 // See if the top visible activity is waiting to run in this process...
5007 HistoryRecord hr = topRunningActivityLocked(null);
5008 if (hr != null) {
5009 if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid
5010 && processName.equals(hr.processName)) {
5011 try {
5012 if (realStartActivityLocked(hr, app, true, true)) {
5013 didSomething = true;
5014 }
5015 } catch (Exception e) {
5016 Log.w(TAG, "Exception in new application when starting activity "
5017 + hr.intent.getComponent().flattenToShortString(), e);
5018 badApp = true;
5019 }
5020 } else {
5021 ensureActivitiesVisibleLocked(hr, null, processName, 0);
5022 }
5023 }
5024
5025 // Find any services that should be running in this process...
5026 if (!badApp && mPendingServices.size() > 0) {
5027 ServiceRecord sr = null;
5028 try {
5029 for (int i=0; i<mPendingServices.size(); i++) {
5030 sr = mPendingServices.get(i);
5031 if (app.info.uid != sr.appInfo.uid
5032 || !processName.equals(sr.processName)) {
5033 continue;
5034 }
5035
5036 mPendingServices.remove(i);
5037 i--;
5038 realStartServiceLocked(sr, app);
5039 didSomething = true;
5040 }
5041 } catch (Exception e) {
5042 Log.w(TAG, "Exception in new application when starting service "
5043 + sr.shortName, e);
5044 badApp = true;
5045 }
5046 }
5047
5048 // Check if the next broadcast receiver is in this process...
5049 BroadcastRecord br = mPendingBroadcast;
5050 if (!badApp && br != null && br.curApp == app) {
5051 try {
5052 mPendingBroadcast = null;
5053 processCurBroadcastLocked(br, app);
5054 didSomething = true;
5055 } catch (Exception e) {
5056 Log.w(TAG, "Exception in new application when starting receiver "
5057 + br.curComponent.flattenToShortString(), e);
5058 badApp = true;
5059 logBroadcastReceiverDiscard(br);
5060 finishReceiverLocked(br.receiver, br.resultCode, br.resultData,
5061 br.resultExtras, br.resultAbort, true);
5062 scheduleBroadcastsLocked();
5063 }
5064 }
5065
Christopher Tate181fafa2009-05-14 11:12:14 -07005066 // Check whether the next backup agent is in this process...
5067 if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.info.uid) {
5068 if (DEBUG_BACKUP) Log.v(TAG, "New app is backup target, launching agent for " + app);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07005069 ensurePackageDexOpt(mBackupTarget.appInfo.packageName);
Christopher Tate181fafa2009-05-14 11:12:14 -07005070 try {
5071 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, mBackupTarget.backupMode);
5072 } catch (Exception e) {
5073 Log.w(TAG, "Exception scheduling backup agent creation: ");
5074 e.printStackTrace();
5075 }
5076 }
5077
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005078 if (badApp) {
5079 // todo: Also need to kill application to deal with all
5080 // kinds of exceptions.
5081 handleAppDiedLocked(app, false);
5082 return false;
5083 }
5084
5085 if (!didSomething) {
5086 updateOomAdjLocked();
5087 }
5088
5089 return true;
5090 }
5091
5092 public final void attachApplication(IApplicationThread thread) {
5093 synchronized (this) {
5094 int callingPid = Binder.getCallingPid();
5095 final long origId = Binder.clearCallingIdentity();
5096 attachApplicationLocked(thread, callingPid);
5097 Binder.restoreCallingIdentity(origId);
5098 }
5099 }
5100
5101 public final void activityIdle(IBinder token) {
5102 final long origId = Binder.clearCallingIdentity();
5103 activityIdleInternal(token, false);
5104 Binder.restoreCallingIdentity(origId);
5105 }
5106
5107 final ArrayList<HistoryRecord> processStoppingActivitiesLocked(
5108 boolean remove) {
5109 int N = mStoppingActivities.size();
5110 if (N <= 0) return null;
5111
5112 ArrayList<HistoryRecord> stops = null;
5113
5114 final boolean nowVisible = mResumedActivity != null
5115 && mResumedActivity.nowVisible
5116 && !mResumedActivity.waitingVisible;
5117 for (int i=0; i<N; i++) {
5118 HistoryRecord s = mStoppingActivities.get(i);
5119 if (localLOGV) Log.v(TAG, "Stopping " + s + ": nowVisible="
5120 + nowVisible + " waitingVisible=" + s.waitingVisible
5121 + " finishing=" + s.finishing);
5122 if (s.waitingVisible && nowVisible) {
5123 mWaitingVisibleActivities.remove(s);
5124 s.waitingVisible = false;
5125 if (s.finishing) {
5126 // If this activity is finishing, it is sitting on top of
5127 // everyone else but we now know it is no longer needed...
5128 // so get rid of it. Otherwise, we need to go through the
5129 // normal flow and hide it once we determine that it is
5130 // hidden by the activities in front of it.
5131 if (localLOGV) Log.v(TAG, "Before stopping, can hide: " + s);
5132 mWindowManager.setAppVisibility(s, false);
5133 }
5134 }
5135 if (!s.waitingVisible && remove) {
5136 if (localLOGV) Log.v(TAG, "Ready to stop: " + s);
5137 if (stops == null) {
5138 stops = new ArrayList<HistoryRecord>();
5139 }
5140 stops.add(s);
5141 mStoppingActivities.remove(i);
5142 N--;
5143 i--;
5144 }
5145 }
5146
5147 return stops;
5148 }
5149
5150 void enableScreenAfterBoot() {
5151 mWindowManager.enableScreenAfterBoot();
5152 }
5153
5154 final void activityIdleInternal(IBinder token, boolean fromTimeout) {
5155 if (localLOGV) Log.v(TAG, "Activity idle: " + token);
5156
5157 ArrayList<HistoryRecord> stops = null;
5158 ArrayList<HistoryRecord> finishes = null;
5159 ArrayList<HistoryRecord> thumbnails = null;
5160 int NS = 0;
5161 int NF = 0;
5162 int NT = 0;
5163 IApplicationThread sendThumbnail = null;
5164 boolean booting = false;
5165 boolean enableScreen = false;
5166
5167 synchronized (this) {
5168 if (token != null) {
5169 mHandler.removeMessages(IDLE_TIMEOUT_MSG, token);
5170 }
5171
5172 // Get the activity record.
Dianne Hackborn75b03852009-06-12 15:43:26 -07005173 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005174 if (index >= 0) {
5175 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5176
5177 // No longer need to keep the device awake.
5178 if (mResumedActivity == r && mLaunchingActivity.isHeld()) {
5179 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
5180 mLaunchingActivity.release();
5181 }
5182
5183 // We are now idle. If someone is waiting for a thumbnail from
5184 // us, we can now deliver.
5185 r.idle = true;
5186 scheduleAppGcsLocked();
5187 if (r.thumbnailNeeded && r.app != null && r.app.thread != null) {
5188 sendThumbnail = r.app.thread;
5189 r.thumbnailNeeded = false;
5190 }
5191
5192 // If this activity is fullscreen, set up to hide those under it.
5193
5194 if (DEBUG_VISBILITY) Log.v(TAG, "Idle activity for " + r);
5195 ensureActivitiesVisibleLocked(null, 0);
5196
5197 //Log.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
5198 if (!mBooted && !fromTimeout) {
5199 mBooted = true;
5200 enableScreen = true;
5201 }
5202 }
5203
5204 // Atomically retrieve all of the other things to do.
5205 stops = processStoppingActivitiesLocked(true);
5206 NS = stops != null ? stops.size() : 0;
5207 if ((NF=mFinishingActivities.size()) > 0) {
5208 finishes = new ArrayList<HistoryRecord>(mFinishingActivities);
5209 mFinishingActivities.clear();
5210 }
5211 if ((NT=mCancelledThumbnails.size()) > 0) {
5212 thumbnails = new ArrayList<HistoryRecord>(mCancelledThumbnails);
5213 mCancelledThumbnails.clear();
5214 }
5215
5216 booting = mBooting;
5217 mBooting = false;
5218 }
5219
5220 int i;
5221
5222 // Send thumbnail if requested.
5223 if (sendThumbnail != null) {
5224 try {
5225 sendThumbnail.requestThumbnail(token);
5226 } catch (Exception e) {
5227 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
5228 sendPendingThumbnail(null, token, null, null, true);
5229 }
5230 }
5231
5232 // Stop any activities that are scheduled to do so but have been
5233 // waiting for the next one to start.
5234 for (i=0; i<NS; i++) {
5235 HistoryRecord r = (HistoryRecord)stops.get(i);
5236 synchronized (this) {
5237 if (r.finishing) {
5238 finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
5239 } else {
5240 stopActivityLocked(r);
5241 }
5242 }
5243 }
5244
5245 // Finish any activities that are scheduled to do so but have been
5246 // waiting for the next one to start.
5247 for (i=0; i<NF; i++) {
5248 HistoryRecord r = (HistoryRecord)finishes.get(i);
5249 synchronized (this) {
5250 destroyActivityLocked(r, true);
5251 }
5252 }
5253
5254 // Report back to any thumbnail receivers.
5255 for (i=0; i<NT; i++) {
5256 HistoryRecord r = (HistoryRecord)thumbnails.get(i);
5257 sendPendingThumbnail(r, null, null, null, true);
5258 }
5259
5260 if (booting) {
5261 // Ensure that any processes we had put on hold are now started
5262 // up.
5263 final int NP = mProcessesOnHold.size();
5264 if (NP > 0) {
5265 ArrayList<ProcessRecord> procs =
5266 new ArrayList<ProcessRecord>(mProcessesOnHold);
5267 for (int ip=0; ip<NP; ip++) {
5268 this.startProcessLocked(procs.get(ip), "on-hold", null);
5269 }
5270 }
5271 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
5272 // Tell anyone interested that we are done booting!
5273 synchronized (this) {
5274 broadcastIntentLocked(null, null,
5275 new Intent(Intent.ACTION_BOOT_COMPLETED, null),
5276 null, null, 0, null, null,
5277 android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
5278 false, false, MY_PID, Process.SYSTEM_UID);
5279 }
5280 }
5281 }
5282
5283 trimApplications();
5284 //dump();
5285 //mWindowManager.dump();
5286
5287 if (enableScreen) {
5288 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5289 SystemClock.uptimeMillis());
5290 enableScreenAfterBoot();
5291 }
5292 }
5293
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07005294 final void ensureScreenEnabled() {
5295 boolean enableScreen;
5296 synchronized (this) {
5297 enableScreen = !mBooted;
5298 mBooted = true;
5299 }
5300
5301 if (enableScreen) {
5302 EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN,
5303 SystemClock.uptimeMillis());
5304 enableScreenAfterBoot();
5305 }
5306 }
5307
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005308 public final void activityPaused(IBinder token, Bundle icicle) {
5309 // Refuse possible leaked file descriptors
5310 if (icicle != null && icicle.hasFileDescriptors()) {
5311 throw new IllegalArgumentException("File descriptors passed in Bundle");
5312 }
5313
5314 final long origId = Binder.clearCallingIdentity();
5315 activityPaused(token, icicle, false);
5316 Binder.restoreCallingIdentity(origId);
5317 }
5318
5319 final void activityPaused(IBinder token, Bundle icicle, boolean timeout) {
5320 if (DEBUG_PAUSE) Log.v(
5321 TAG, "Activity paused: token=" + token + ", icicle=" + icicle
5322 + ", timeout=" + timeout);
5323
5324 HistoryRecord r = null;
5325
5326 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005327 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005328 if (index >= 0) {
5329 r = (HistoryRecord)mHistory.get(index);
5330 if (!timeout) {
5331 r.icicle = icicle;
5332 r.haveState = true;
5333 }
5334 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
5335 if (mPausingActivity == r) {
5336 r.state = ActivityState.PAUSED;
5337 completePauseLocked();
5338 } else {
5339 EventLog.writeEvent(LOG_AM_FAILED_TO_PAUSE_ACTIVITY,
5340 System.identityHashCode(r), r.shortComponentName,
5341 mPausingActivity != null
5342 ? mPausingActivity.shortComponentName : "(none)");
5343 }
5344 }
5345 }
5346 }
5347
5348 public final void activityStopped(IBinder token, Bitmap thumbnail,
5349 CharSequence description) {
5350 if (localLOGV) Log.v(
5351 TAG, "Activity stopped: token=" + token);
5352
5353 HistoryRecord r = null;
5354
5355 final long origId = Binder.clearCallingIdentity();
5356
5357 synchronized (this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005358 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005359 if (index >= 0) {
5360 r = (HistoryRecord)mHistory.get(index);
5361 r.thumbnail = thumbnail;
5362 r.description = description;
5363 r.stopped = true;
5364 r.state = ActivityState.STOPPED;
5365 if (!r.finishing) {
5366 if (r.configDestroy) {
5367 destroyActivityLocked(r, true);
5368 resumeTopActivityLocked(null);
5369 }
5370 }
5371 }
5372 }
5373
5374 if (r != null) {
5375 sendPendingThumbnail(r, null, null, null, false);
5376 }
5377
5378 trimApplications();
5379
5380 Binder.restoreCallingIdentity(origId);
5381 }
5382
5383 public final void activityDestroyed(IBinder token) {
5384 if (DEBUG_SWITCH) Log.v(TAG, "ACTIVITY DESTROYED: " + token);
5385 synchronized (this) {
5386 mHandler.removeMessages(DESTROY_TIMEOUT_MSG, token);
5387
Dianne Hackborn75b03852009-06-12 15:43:26 -07005388 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005389 if (index >= 0) {
5390 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5391 if (r.state == ActivityState.DESTROYING) {
5392 final long origId = Binder.clearCallingIdentity();
5393 removeActivityFromHistoryLocked(r);
5394 Binder.restoreCallingIdentity(origId);
5395 }
5396 }
5397 }
5398 }
5399
5400 public String getCallingPackage(IBinder token) {
5401 synchronized (this) {
5402 HistoryRecord r = getCallingRecordLocked(token);
5403 return r != null && r.app != null ? r.app.processName : null;
5404 }
5405 }
5406
5407 public ComponentName getCallingActivity(IBinder token) {
5408 synchronized (this) {
5409 HistoryRecord r = getCallingRecordLocked(token);
5410 return r != null ? r.intent.getComponent() : null;
5411 }
5412 }
5413
5414 private HistoryRecord getCallingRecordLocked(IBinder token) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005415 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005416 if (index >= 0) {
5417 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5418 if (r != null) {
5419 return r.resultTo;
5420 }
5421 }
5422 return null;
5423 }
5424
5425 public ComponentName getActivityClassForToken(IBinder token) {
5426 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005427 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005428 if (index >= 0) {
5429 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5430 return r.intent.getComponent();
5431 }
5432 return null;
5433 }
5434 }
5435
5436 public String getPackageForToken(IBinder token) {
5437 synchronized(this) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005438 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005439 if (index >= 0) {
5440 HistoryRecord r = (HistoryRecord)mHistory.get(index);
5441 return r.packageName;
5442 }
5443 return null;
5444 }
5445 }
5446
5447 public IIntentSender getIntentSender(int type,
5448 String packageName, IBinder token, String resultWho,
5449 int requestCode, Intent intent, String resolvedType, int flags) {
5450 // Refuse possible leaked file descriptors
5451 if (intent != null && intent.hasFileDescriptors() == true) {
5452 throw new IllegalArgumentException("File descriptors passed in Intent");
5453 }
5454
5455 synchronized(this) {
5456 int callingUid = Binder.getCallingUid();
5457 try {
5458 if (callingUid != 0 && callingUid != Process.SYSTEM_UID &&
5459 Process.supportsProcesses()) {
5460 int uid = ActivityThread.getPackageManager()
5461 .getPackageUid(packageName);
5462 if (uid != Binder.getCallingUid()) {
5463 String msg = "Permission Denial: getIntentSender() from pid="
5464 + Binder.getCallingPid()
5465 + ", uid=" + Binder.getCallingUid()
5466 + ", (need uid=" + uid + ")"
5467 + " is not allowed to send as package " + packageName;
5468 Log.w(TAG, msg);
5469 throw new SecurityException(msg);
5470 }
5471 }
5472 } catch (RemoteException e) {
5473 throw new SecurityException(e);
5474 }
5475 HistoryRecord activity = null;
5476 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07005477 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005478 if (index < 0) {
5479 return null;
5480 }
5481 activity = (HistoryRecord)mHistory.get(index);
5482 if (activity.finishing) {
5483 return null;
5484 }
5485 }
5486
5487 final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
5488 final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
5489 final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
5490 flags &= ~(PendingIntent.FLAG_NO_CREATE|PendingIntent.FLAG_CANCEL_CURRENT
5491 |PendingIntent.FLAG_UPDATE_CURRENT);
5492
5493 PendingIntentRecord.Key key = new PendingIntentRecord.Key(
5494 type, packageName, activity, resultWho,
5495 requestCode, intent, resolvedType, flags);
5496 WeakReference<PendingIntentRecord> ref;
5497 ref = mIntentSenderRecords.get(key);
5498 PendingIntentRecord rec = ref != null ? ref.get() : null;
5499 if (rec != null) {
5500 if (!cancelCurrent) {
5501 if (updateCurrent) {
5502 rec.key.requestIntent.replaceExtras(intent);
5503 }
5504 return rec;
5505 }
5506 rec.canceled = true;
5507 mIntentSenderRecords.remove(key);
5508 }
5509 if (noCreate) {
5510 return rec;
5511 }
5512 rec = new PendingIntentRecord(this, key, callingUid);
5513 mIntentSenderRecords.put(key, rec.ref);
5514 if (type == INTENT_SENDER_ACTIVITY_RESULT) {
5515 if (activity.pendingResults == null) {
5516 activity.pendingResults
5517 = new HashSet<WeakReference<PendingIntentRecord>>();
5518 }
5519 activity.pendingResults.add(rec.ref);
5520 }
5521 return rec;
5522 }
5523 }
5524
5525 public void cancelIntentSender(IIntentSender sender) {
5526 if (!(sender instanceof PendingIntentRecord)) {
5527 return;
5528 }
5529 synchronized(this) {
5530 PendingIntentRecord rec = (PendingIntentRecord)sender;
5531 try {
5532 int uid = ActivityThread.getPackageManager()
5533 .getPackageUid(rec.key.packageName);
5534 if (uid != Binder.getCallingUid()) {
5535 String msg = "Permission Denial: cancelIntentSender() from pid="
5536 + Binder.getCallingPid()
5537 + ", uid=" + Binder.getCallingUid()
5538 + " is not allowed to cancel packges "
5539 + rec.key.packageName;
5540 Log.w(TAG, msg);
5541 throw new SecurityException(msg);
5542 }
5543 } catch (RemoteException e) {
5544 throw new SecurityException(e);
5545 }
5546 cancelIntentSenderLocked(rec, true);
5547 }
5548 }
5549
5550 void cancelIntentSenderLocked(PendingIntentRecord rec, boolean cleanActivity) {
5551 rec.canceled = true;
5552 mIntentSenderRecords.remove(rec.key);
5553 if (cleanActivity && rec.key.activity != null) {
5554 rec.key.activity.pendingResults.remove(rec.ref);
5555 }
5556 }
5557
5558 public String getPackageForIntentSender(IIntentSender pendingResult) {
5559 if (!(pendingResult instanceof PendingIntentRecord)) {
5560 return null;
5561 }
5562 synchronized(this) {
5563 try {
5564 PendingIntentRecord res = (PendingIntentRecord)pendingResult;
5565 return res.key.packageName;
5566 } catch (ClassCastException e) {
5567 }
5568 }
5569 return null;
5570 }
5571
5572 public void setProcessLimit(int max) {
5573 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5574 "setProcessLimit()");
5575 mProcessLimit = max;
5576 }
5577
5578 public int getProcessLimit() {
5579 return mProcessLimit;
5580 }
5581
5582 void foregroundTokenDied(ForegroundToken token) {
5583 synchronized (ActivityManagerService.this) {
5584 synchronized (mPidsSelfLocked) {
5585 ForegroundToken cur
5586 = mForegroundProcesses.get(token.pid);
5587 if (cur != token) {
5588 return;
5589 }
5590 mForegroundProcesses.remove(token.pid);
5591 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
5592 if (pr == null) {
5593 return;
5594 }
5595 pr.forcingToForeground = null;
5596 pr.foregroundServices = false;
5597 }
5598 updateOomAdjLocked();
5599 }
5600 }
5601
5602 public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
5603 enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
5604 "setProcessForeground()");
5605 synchronized(this) {
5606 boolean changed = false;
5607
5608 synchronized (mPidsSelfLocked) {
5609 ProcessRecord pr = mPidsSelfLocked.get(pid);
5610 if (pr == null) {
5611 Log.w(TAG, "setProcessForeground called on unknown pid: " + pid);
5612 return;
5613 }
5614 ForegroundToken oldToken = mForegroundProcesses.get(pid);
5615 if (oldToken != null) {
5616 oldToken.token.unlinkToDeath(oldToken, 0);
5617 mForegroundProcesses.remove(pid);
5618 pr.forcingToForeground = null;
5619 changed = true;
5620 }
5621 if (isForeground && token != null) {
5622 ForegroundToken newToken = new ForegroundToken() {
5623 public void binderDied() {
5624 foregroundTokenDied(this);
5625 }
5626 };
5627 newToken.pid = pid;
5628 newToken.token = token;
5629 try {
5630 token.linkToDeath(newToken, 0);
5631 mForegroundProcesses.put(pid, newToken);
5632 pr.forcingToForeground = token;
5633 changed = true;
5634 } catch (RemoteException e) {
5635 // If the process died while doing this, we will later
5636 // do the cleanup with the process death link.
5637 }
5638 }
5639 }
5640
5641 if (changed) {
5642 updateOomAdjLocked();
5643 }
5644 }
5645 }
5646
5647 // =========================================================
5648 // PERMISSIONS
5649 // =========================================================
5650
5651 static class PermissionController extends IPermissionController.Stub {
5652 ActivityManagerService mActivityManagerService;
5653 PermissionController(ActivityManagerService activityManagerService) {
5654 mActivityManagerService = activityManagerService;
5655 }
5656
5657 public boolean checkPermission(String permission, int pid, int uid) {
5658 return mActivityManagerService.checkPermission(permission, pid,
5659 uid) == PackageManager.PERMISSION_GRANTED;
5660 }
5661 }
5662
5663 /**
5664 * This can be called with or without the global lock held.
5665 */
5666 int checkComponentPermission(String permission, int pid, int uid,
5667 int reqUid) {
5668 // We might be performing an operation on behalf of an indirect binder
5669 // invocation, e.g. via {@link #openContentUri}. Check and adjust the
5670 // client identity accordingly before proceeding.
5671 Identity tlsIdentity = sCallerIdentity.get();
5672 if (tlsIdentity != null) {
5673 Log.d(TAG, "checkComponentPermission() adjusting {pid,uid} to {"
5674 + tlsIdentity.pid + "," + tlsIdentity.uid + "}");
5675 uid = tlsIdentity.uid;
5676 pid = tlsIdentity.pid;
5677 }
5678
5679 // Root, system server and our own process get to do everything.
5680 if (uid == 0 || uid == Process.SYSTEM_UID || pid == MY_PID ||
5681 !Process.supportsProcesses()) {
5682 return PackageManager.PERMISSION_GRANTED;
5683 }
5684 // If the target requires a specific UID, always fail for others.
5685 if (reqUid >= 0 && uid != reqUid) {
5686 return PackageManager.PERMISSION_DENIED;
5687 }
5688 if (permission == null) {
5689 return PackageManager.PERMISSION_GRANTED;
5690 }
5691 try {
5692 return ActivityThread.getPackageManager()
5693 .checkUidPermission(permission, uid);
5694 } catch (RemoteException e) {
5695 // Should never happen, but if it does... deny!
5696 Log.e(TAG, "PackageManager is dead?!?", e);
5697 }
5698 return PackageManager.PERMISSION_DENIED;
5699 }
5700
5701 /**
5702 * As the only public entry point for permissions checking, this method
5703 * can enforce the semantic that requesting a check on a null global
5704 * permission is automatically denied. (Internally a null permission
5705 * string is used when calling {@link #checkComponentPermission} in cases
5706 * when only uid-based security is needed.)
5707 *
5708 * This can be called with or without the global lock held.
5709 */
5710 public int checkPermission(String permission, int pid, int uid) {
5711 if (permission == null) {
5712 return PackageManager.PERMISSION_DENIED;
5713 }
5714 return checkComponentPermission(permission, pid, uid, -1);
5715 }
5716
5717 /**
5718 * Binder IPC calls go through the public entry point.
5719 * This can be called with or without the global lock held.
5720 */
5721 int checkCallingPermission(String permission) {
5722 return checkPermission(permission,
5723 Binder.getCallingPid(),
5724 Binder.getCallingUid());
5725 }
5726
5727 /**
5728 * This can be called with or without the global lock held.
5729 */
5730 void enforceCallingPermission(String permission, String func) {
5731 if (checkCallingPermission(permission)
5732 == PackageManager.PERMISSION_GRANTED) {
5733 return;
5734 }
5735
5736 String msg = "Permission Denial: " + func + " from pid="
5737 + Binder.getCallingPid()
5738 + ", uid=" + Binder.getCallingUid()
5739 + " requires " + permission;
5740 Log.w(TAG, msg);
5741 throw new SecurityException(msg);
5742 }
5743
5744 private final boolean checkHoldingPermissionsLocked(IPackageManager pm,
5745 ProviderInfo pi, int uid, int modeFlags) {
5746 try {
5747 if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5748 if ((pi.readPermission != null) &&
5749 (pm.checkUidPermission(pi.readPermission, uid)
5750 != PackageManager.PERMISSION_GRANTED)) {
5751 return false;
5752 }
5753 }
5754 if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5755 if ((pi.writePermission != null) &&
5756 (pm.checkUidPermission(pi.writePermission, uid)
5757 != PackageManager.PERMISSION_GRANTED)) {
5758 return false;
5759 }
5760 }
5761 return true;
5762 } catch (RemoteException e) {
5763 return false;
5764 }
5765 }
5766
5767 private final boolean checkUriPermissionLocked(Uri uri, int uid,
5768 int modeFlags) {
5769 // Root gets to do everything.
5770 if (uid == 0 || !Process.supportsProcesses()) {
5771 return true;
5772 }
5773 HashMap<Uri, UriPermission> perms = mGrantedUriPermissions.get(uid);
5774 if (perms == null) return false;
5775 UriPermission perm = perms.get(uri);
5776 if (perm == null) return false;
5777 return (modeFlags&perm.modeFlags) == modeFlags;
5778 }
5779
5780 public int checkUriPermission(Uri uri, int pid, int uid, int modeFlags) {
5781 // Another redirected-binder-call permissions check as in
5782 // {@link checkComponentPermission}.
5783 Identity tlsIdentity = sCallerIdentity.get();
5784 if (tlsIdentity != null) {
5785 uid = tlsIdentity.uid;
5786 pid = tlsIdentity.pid;
5787 }
5788
5789 // Our own process gets to do everything.
5790 if (pid == MY_PID) {
5791 return PackageManager.PERMISSION_GRANTED;
5792 }
5793 synchronized(this) {
5794 return checkUriPermissionLocked(uri, uid, modeFlags)
5795 ? PackageManager.PERMISSION_GRANTED
5796 : PackageManager.PERMISSION_DENIED;
5797 }
5798 }
5799
5800 private void grantUriPermissionLocked(int callingUid,
5801 String targetPkg, Uri uri, int modeFlags, HistoryRecord activity) {
5802 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
5803 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
5804 if (modeFlags == 0) {
5805 return;
5806 }
5807
5808 final IPackageManager pm = ActivityThread.getPackageManager();
5809
5810 // If this is not a content: uri, we can't do anything with it.
5811 if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
5812 return;
5813 }
5814
5815 String name = uri.getAuthority();
5816 ProviderInfo pi = null;
5817 ContentProviderRecord cpr
5818 = (ContentProviderRecord)mProvidersByName.get(name);
5819 if (cpr != null) {
5820 pi = cpr.info;
5821 } else {
5822 try {
5823 pi = pm.resolveContentProvider(name,
5824 PackageManager.GET_URI_PERMISSION_PATTERNS);
5825 } catch (RemoteException ex) {
5826 }
5827 }
5828 if (pi == null) {
5829 Log.w(TAG, "No content provider found for: " + name);
5830 return;
5831 }
5832
5833 int targetUid;
5834 try {
5835 targetUid = pm.getPackageUid(targetPkg);
5836 if (targetUid < 0) {
5837 return;
5838 }
5839 } catch (RemoteException ex) {
5840 return;
5841 }
5842
5843 // First... does the target actually need this permission?
5844 if (checkHoldingPermissionsLocked(pm, pi, targetUid, modeFlags)) {
5845 // No need to grant the target this permission.
5846 return;
5847 }
5848
5849 // Second... maybe someone else has already granted the
5850 // permission?
5851 if (checkUriPermissionLocked(uri, targetUid, modeFlags)) {
5852 // No need to grant the target this permission.
5853 return;
5854 }
5855
5856 // Third... is the provider allowing granting of URI permissions?
5857 if (!pi.grantUriPermissions) {
5858 throw new SecurityException("Provider " + pi.packageName
5859 + "/" + pi.name
5860 + " does not allow granting of Uri permissions (uri "
5861 + uri + ")");
5862 }
5863 if (pi.uriPermissionPatterns != null) {
5864 final int N = pi.uriPermissionPatterns.length;
5865 boolean allowed = false;
5866 for (int i=0; i<N; i++) {
5867 if (pi.uriPermissionPatterns[i] != null
5868 && pi.uriPermissionPatterns[i].match(uri.getPath())) {
5869 allowed = true;
5870 break;
5871 }
5872 }
5873 if (!allowed) {
5874 throw new SecurityException("Provider " + pi.packageName
5875 + "/" + pi.name
5876 + " does not allow granting of permission to path of Uri "
5877 + uri);
5878 }
5879 }
5880
5881 // Fourth... does the caller itself have permission to access
5882 // this uri?
5883 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
5884 if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
5885 throw new SecurityException("Uid " + callingUid
5886 + " does not have permission to uri " + uri);
5887 }
5888 }
5889
5890 // Okay! So here we are: the caller has the assumed permission
5891 // to the uri, and the target doesn't. Let's now give this to
5892 // the target.
5893
5894 HashMap<Uri, UriPermission> targetUris
5895 = mGrantedUriPermissions.get(targetUid);
5896 if (targetUris == null) {
5897 targetUris = new HashMap<Uri, UriPermission>();
5898 mGrantedUriPermissions.put(targetUid, targetUris);
5899 }
5900
5901 UriPermission perm = targetUris.get(uri);
5902 if (perm == null) {
5903 perm = new UriPermission(targetUid, uri);
5904 targetUris.put(uri, perm);
5905
5906 }
5907 perm.modeFlags |= modeFlags;
5908 if (activity == null) {
5909 perm.globalModeFlags |= modeFlags;
5910 } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
5911 perm.readActivities.add(activity);
5912 if (activity.readUriPermissions == null) {
5913 activity.readUriPermissions = new HashSet<UriPermission>();
5914 }
5915 activity.readUriPermissions.add(perm);
5916 } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
5917 perm.writeActivities.add(activity);
5918 if (activity.writeUriPermissions == null) {
5919 activity.writeUriPermissions = new HashSet<UriPermission>();
5920 }
5921 activity.writeUriPermissions.add(perm);
5922 }
5923 }
5924
5925 private void grantUriPermissionFromIntentLocked(int callingUid,
5926 String targetPkg, Intent intent, HistoryRecord activity) {
5927 if (intent == null) {
5928 return;
5929 }
5930 Uri data = intent.getData();
5931 if (data == null) {
5932 return;
5933 }
5934 grantUriPermissionLocked(callingUid, targetPkg, data,
5935 intent.getFlags(), activity);
5936 }
5937
5938 public void grantUriPermission(IApplicationThread caller, String targetPkg,
5939 Uri uri, int modeFlags) {
5940 synchronized(this) {
5941 final ProcessRecord r = getRecordForAppLocked(caller);
5942 if (r == null) {
5943 throw new SecurityException("Unable to find app for caller "
5944 + caller
5945 + " when granting permission to uri " + uri);
5946 }
5947 if (targetPkg == null) {
5948 Log.w(TAG, "grantUriPermission: null target");
5949 return;
5950 }
5951 if (uri == null) {
5952 Log.w(TAG, "grantUriPermission: null uri");
5953 return;
5954 }
5955
5956 grantUriPermissionLocked(r.info.uid, targetPkg, uri, modeFlags,
5957 null);
5958 }
5959 }
5960
5961 private void removeUriPermissionIfNeededLocked(UriPermission perm) {
5962 if ((perm.modeFlags&(Intent.FLAG_GRANT_READ_URI_PERMISSION
5963 |Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) == 0) {
5964 HashMap<Uri, UriPermission> perms
5965 = mGrantedUriPermissions.get(perm.uid);
5966 if (perms != null) {
5967 perms.remove(perm.uri);
5968 if (perms.size() == 0) {
5969 mGrantedUriPermissions.remove(perm.uid);
5970 }
5971 }
5972 }
5973 }
5974
5975 private void removeActivityUriPermissionsLocked(HistoryRecord activity) {
5976 if (activity.readUriPermissions != null) {
5977 for (UriPermission perm : activity.readUriPermissions) {
5978 perm.readActivities.remove(activity);
5979 if (perm.readActivities.size() == 0 && (perm.globalModeFlags
5980 &Intent.FLAG_GRANT_READ_URI_PERMISSION) == 0) {
5981 perm.modeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
5982 removeUriPermissionIfNeededLocked(perm);
5983 }
5984 }
5985 }
5986 if (activity.writeUriPermissions != null) {
5987 for (UriPermission perm : activity.writeUriPermissions) {
5988 perm.writeActivities.remove(activity);
5989 if (perm.writeActivities.size() == 0 && (perm.globalModeFlags
5990 &Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == 0) {
5991 perm.modeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
5992 removeUriPermissionIfNeededLocked(perm);
5993 }
5994 }
5995 }
5996 }
5997
5998 private void revokeUriPermissionLocked(int callingUid, Uri uri,
5999 int modeFlags) {
6000 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6001 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6002 if (modeFlags == 0) {
6003 return;
6004 }
6005
6006 final IPackageManager pm = ActivityThread.getPackageManager();
6007
6008 final String authority = uri.getAuthority();
6009 ProviderInfo pi = null;
6010 ContentProviderRecord cpr
6011 = (ContentProviderRecord)mProvidersByName.get(authority);
6012 if (cpr != null) {
6013 pi = cpr.info;
6014 } else {
6015 try {
6016 pi = pm.resolveContentProvider(authority,
6017 PackageManager.GET_URI_PERMISSION_PATTERNS);
6018 } catch (RemoteException ex) {
6019 }
6020 }
6021 if (pi == null) {
6022 Log.w(TAG, "No content provider found for: " + authority);
6023 return;
6024 }
6025
6026 // Does the caller have this permission on the URI?
6027 if (!checkHoldingPermissionsLocked(pm, pi, callingUid, modeFlags)) {
6028 // Right now, if you are not the original owner of the permission,
6029 // you are not allowed to revoke it.
6030 //if (!checkUriPermissionLocked(uri, callingUid, modeFlags)) {
6031 throw new SecurityException("Uid " + callingUid
6032 + " does not have permission to uri " + uri);
6033 //}
6034 }
6035
6036 // Go through all of the permissions and remove any that match.
6037 final List<String> SEGMENTS = uri.getPathSegments();
6038 if (SEGMENTS != null) {
6039 final int NS = SEGMENTS.size();
6040 int N = mGrantedUriPermissions.size();
6041 for (int i=0; i<N; i++) {
6042 HashMap<Uri, UriPermission> perms
6043 = mGrantedUriPermissions.valueAt(i);
6044 Iterator<UriPermission> it = perms.values().iterator();
6045 toploop:
6046 while (it.hasNext()) {
6047 UriPermission perm = it.next();
6048 Uri targetUri = perm.uri;
6049 if (!authority.equals(targetUri.getAuthority())) {
6050 continue;
6051 }
6052 List<String> targetSegments = targetUri.getPathSegments();
6053 if (targetSegments == null) {
6054 continue;
6055 }
6056 if (targetSegments.size() < NS) {
6057 continue;
6058 }
6059 for (int j=0; j<NS; j++) {
6060 if (!SEGMENTS.get(j).equals(targetSegments.get(j))) {
6061 continue toploop;
6062 }
6063 }
6064 perm.clearModes(modeFlags);
6065 if (perm.modeFlags == 0) {
6066 it.remove();
6067 }
6068 }
6069 if (perms.size() == 0) {
6070 mGrantedUriPermissions.remove(
6071 mGrantedUriPermissions.keyAt(i));
6072 N--;
6073 i--;
6074 }
6075 }
6076 }
6077 }
6078
6079 public void revokeUriPermission(IApplicationThread caller, Uri uri,
6080 int modeFlags) {
6081 synchronized(this) {
6082 final ProcessRecord r = getRecordForAppLocked(caller);
6083 if (r == null) {
6084 throw new SecurityException("Unable to find app for caller "
6085 + caller
6086 + " when revoking permission to uri " + uri);
6087 }
6088 if (uri == null) {
6089 Log.w(TAG, "revokeUriPermission: null uri");
6090 return;
6091 }
6092
6093 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
6094 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
6095 if (modeFlags == 0) {
6096 return;
6097 }
6098
6099 final IPackageManager pm = ActivityThread.getPackageManager();
6100
6101 final String authority = uri.getAuthority();
6102 ProviderInfo pi = null;
6103 ContentProviderRecord cpr
6104 = (ContentProviderRecord)mProvidersByName.get(authority);
6105 if (cpr != null) {
6106 pi = cpr.info;
6107 } else {
6108 try {
6109 pi = pm.resolveContentProvider(authority,
6110 PackageManager.GET_URI_PERMISSION_PATTERNS);
6111 } catch (RemoteException ex) {
6112 }
6113 }
6114 if (pi == null) {
6115 Log.w(TAG, "No content provider found for: " + authority);
6116 return;
6117 }
6118
6119 revokeUriPermissionLocked(r.info.uid, uri, modeFlags);
6120 }
6121 }
6122
6123 public void showWaitingForDebugger(IApplicationThread who, boolean waiting) {
6124 synchronized (this) {
6125 ProcessRecord app =
6126 who != null ? getRecordForAppLocked(who) : null;
6127 if (app == null) return;
6128
6129 Message msg = Message.obtain();
6130 msg.what = WAIT_FOR_DEBUGGER_MSG;
6131 msg.obj = app;
6132 msg.arg1 = waiting ? 1 : 0;
6133 mHandler.sendMessage(msg);
6134 }
6135 }
6136
6137 public void getMemoryInfo(ActivityManager.MemoryInfo outInfo) {
6138 outInfo.availMem = Process.getFreeMemory();
The Android Open Source Project4df24232009-03-05 14:34:35 -08006139 outInfo.threshold = HOME_APP_MEM;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006140 outInfo.lowMemory = outInfo.availMem <
The Android Open Source Project4df24232009-03-05 14:34:35 -08006141 (HOME_APP_MEM + ((HIDDEN_APP_MEM-HOME_APP_MEM)/2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006142 }
6143
6144 // =========================================================
6145 // TASK MANAGEMENT
6146 // =========================================================
6147
6148 public List getTasks(int maxNum, int flags,
6149 IThumbnailReceiver receiver) {
6150 ArrayList list = new ArrayList();
6151
6152 PendingThumbnailsRecord pending = null;
6153 IApplicationThread topThumbnail = null;
6154 HistoryRecord topRecord = null;
6155
6156 synchronized(this) {
6157 if (localLOGV) Log.v(
6158 TAG, "getTasks: max=" + maxNum + ", flags=" + flags
6159 + ", receiver=" + receiver);
6160
6161 if (checkCallingPermission(android.Manifest.permission.GET_TASKS)
6162 != PackageManager.PERMISSION_GRANTED) {
6163 if (receiver != null) {
6164 // If the caller wants to wait for pending thumbnails,
6165 // it ain't gonna get them.
6166 try {
6167 receiver.finished();
6168 } catch (RemoteException ex) {
6169 }
6170 }
6171 String msg = "Permission Denial: getTasks() from pid="
6172 + Binder.getCallingPid()
6173 + ", uid=" + Binder.getCallingUid()
6174 + " requires " + android.Manifest.permission.GET_TASKS;
6175 Log.w(TAG, msg);
6176 throw new SecurityException(msg);
6177 }
6178
6179 int pos = mHistory.size()-1;
6180 HistoryRecord next =
6181 pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6182 HistoryRecord top = null;
6183 CharSequence topDescription = null;
6184 TaskRecord curTask = null;
6185 int numActivities = 0;
6186 int numRunning = 0;
6187 while (pos >= 0 && maxNum > 0) {
6188 final HistoryRecord r = next;
6189 pos--;
6190 next = pos >= 0 ? (HistoryRecord)mHistory.get(pos) : null;
6191
6192 // Initialize state for next task if needed.
6193 if (top == null ||
6194 (top.state == ActivityState.INITIALIZING
6195 && top.task == r.task)) {
6196 top = r;
6197 topDescription = r.description;
6198 curTask = r.task;
6199 numActivities = numRunning = 0;
6200 }
6201
6202 // Add 'r' into the current task.
6203 numActivities++;
6204 if (r.app != null && r.app.thread != null) {
6205 numRunning++;
6206 }
6207 if (topDescription == null) {
6208 topDescription = r.description;
6209 }
6210
6211 if (localLOGV) Log.v(
6212 TAG, r.intent.getComponent().flattenToShortString()
6213 + ": task=" + r.task);
6214
6215 // If the next one is a different task, generate a new
6216 // TaskInfo entry for what we have.
6217 if (next == null || next.task != curTask) {
6218 ActivityManager.RunningTaskInfo ci
6219 = new ActivityManager.RunningTaskInfo();
6220 ci.id = curTask.taskId;
6221 ci.baseActivity = r.intent.getComponent();
6222 ci.topActivity = top.intent.getComponent();
6223 ci.thumbnail = top.thumbnail;
6224 ci.description = topDescription;
6225 ci.numActivities = numActivities;
6226 ci.numRunning = numRunning;
6227 //System.out.println(
6228 // "#" + maxNum + ": " + " descr=" + ci.description);
6229 if (ci.thumbnail == null && receiver != null) {
6230 if (localLOGV) Log.v(
6231 TAG, "State=" + top.state + "Idle=" + top.idle
6232 + " app=" + top.app
6233 + " thr=" + (top.app != null ? top.app.thread : null));
6234 if (top.state == ActivityState.RESUMED
6235 || top.state == ActivityState.PAUSING) {
6236 if (top.idle && top.app != null
6237 && top.app.thread != null) {
6238 topRecord = top;
6239 topThumbnail = top.app.thread;
6240 } else {
6241 top.thumbnailNeeded = true;
6242 }
6243 }
6244 if (pending == null) {
6245 pending = new PendingThumbnailsRecord(receiver);
6246 }
6247 pending.pendingRecords.add(top);
6248 }
6249 list.add(ci);
6250 maxNum--;
6251 top = null;
6252 }
6253 }
6254
6255 if (pending != null) {
6256 mPendingThumbnails.add(pending);
6257 }
6258 }
6259
6260 if (localLOGV) Log.v(TAG, "We have pending thumbnails: " + pending);
6261
6262 if (topThumbnail != null) {
6263 if (localLOGV) Log.v(TAG, "Requesting top thumbnail");
6264 try {
6265 topThumbnail.requestThumbnail(topRecord);
6266 } catch (Exception e) {
6267 Log.w(TAG, "Exception thrown when requesting thumbnail", e);
6268 sendPendingThumbnail(null, topRecord, null, null, true);
6269 }
6270 }
6271
6272 if (pending == null && receiver != null) {
6273 // In this case all thumbnails were available and the client
6274 // is being asked to be told when the remaining ones come in...
6275 // which is unusually, since the top-most currently running
6276 // activity should never have a canned thumbnail! Oh well.
6277 try {
6278 receiver.finished();
6279 } catch (RemoteException ex) {
6280 }
6281 }
6282
6283 return list;
6284 }
6285
6286 public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
6287 int flags) {
6288 synchronized (this) {
6289 enforceCallingPermission(android.Manifest.permission.GET_TASKS,
6290 "getRecentTasks()");
6291
6292 final int N = mRecentTasks.size();
6293 ArrayList<ActivityManager.RecentTaskInfo> res
6294 = new ArrayList<ActivityManager.RecentTaskInfo>(
6295 maxNum < N ? maxNum : N);
6296 for (int i=0; i<N && maxNum > 0; i++) {
6297 TaskRecord tr = mRecentTasks.get(i);
6298 if (((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
6299 || (tr.intent == null)
6300 || ((tr.intent.getFlags()
6301 &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
6302 ActivityManager.RecentTaskInfo rti
6303 = new ActivityManager.RecentTaskInfo();
6304 rti.id = tr.numActivities > 0 ? tr.taskId : -1;
6305 rti.baseIntent = new Intent(
6306 tr.intent != null ? tr.intent : tr.affinityIntent);
6307 rti.origActivity = tr.origActivity;
6308 res.add(rti);
6309 maxNum--;
6310 }
6311 }
6312 return res;
6313 }
6314 }
6315
6316 private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
6317 int j;
6318 TaskRecord startTask = ((HistoryRecord)mHistory.get(startIndex)).task;
6319 TaskRecord jt = startTask;
6320
6321 // First look backwards
6322 for (j=startIndex-1; j>=0; j--) {
6323 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6324 if (r.task != jt) {
6325 jt = r.task;
6326 if (affinity.equals(jt.affinity)) {
6327 return j;
6328 }
6329 }
6330 }
6331
6332 // Now look forwards
6333 final int N = mHistory.size();
6334 jt = startTask;
6335 for (j=startIndex+1; j<N; j++) {
6336 HistoryRecord r = (HistoryRecord)mHistory.get(j);
6337 if (r.task != jt) {
6338 if (affinity.equals(jt.affinity)) {
6339 return j;
6340 }
6341 jt = r.task;
6342 }
6343 }
6344
6345 // Might it be at the top?
6346 if (affinity.equals(((HistoryRecord)mHistory.get(N-1)).task.affinity)) {
6347 return N-1;
6348 }
6349
6350 return -1;
6351 }
6352
6353 /**
6354 * Perform a reset of the given task, if needed as part of launching it.
6355 * Returns the new HistoryRecord at the top of the task.
6356 */
6357 private final HistoryRecord resetTaskIfNeededLocked(HistoryRecord taskTop,
6358 HistoryRecord newActivity) {
6359 boolean forceReset = (newActivity.info.flags
6360 &ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0;
6361 if (taskTop.task.getInactiveDuration() > ACTIVITY_INACTIVE_RESET_TIME) {
6362 if ((newActivity.info.flags
6363 &ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) == 0) {
6364 forceReset = true;
6365 }
6366 }
6367
6368 final TaskRecord task = taskTop.task;
6369
6370 // We are going to move through the history list so that we can look
6371 // at each activity 'target' with 'below' either the interesting
6372 // activity immediately below it in the stack or null.
6373 HistoryRecord target = null;
6374 int targetI = 0;
6375 int taskTopI = -1;
6376 int replyChainEnd = -1;
6377 int lastReparentPos = -1;
6378 for (int i=mHistory.size()-1; i>=-1; i--) {
6379 HistoryRecord below = i >= 0 ? (HistoryRecord)mHistory.get(i) : null;
6380
6381 if (below != null && below.finishing) {
6382 continue;
6383 }
6384 if (target == null) {
6385 target = below;
6386 targetI = i;
6387 // If we were in the middle of a reply chain before this
6388 // task, it doesn't appear like the root of the chain wants
6389 // anything interesting, so drop it.
6390 replyChainEnd = -1;
6391 continue;
6392 }
6393
6394 final int flags = target.info.flags;
6395
6396 final boolean finishOnTaskLaunch =
6397 (flags&ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
6398 final boolean allowTaskReparenting =
6399 (flags&ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0;
6400
6401 if (target.task == task) {
6402 // We are inside of the task being reset... we'll either
6403 // finish this activity, push it out for another task,
6404 // or leave it as-is. We only do this
6405 // for activities that are not the root of the task (since
6406 // if we finish the root, we may no longer have the task!).
6407 if (taskTopI < 0) {
6408 taskTopI = targetI;
6409 }
6410 if (below != null && below.task == task) {
6411 final boolean clearWhenTaskReset =
6412 (target.intent.getFlags()
6413 &Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0;
Ed Heyl73798232009-03-24 21:32:21 -07006414 if (!finishOnTaskLaunch && !clearWhenTaskReset && target.resultTo != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006415 // If this activity is sending a reply to a previous
6416 // activity, we can't do anything with it now until
6417 // we reach the start of the reply chain.
6418 // XXX note that we are assuming the result is always
6419 // to the previous activity, which is almost always
6420 // the case but we really shouldn't count on.
6421 if (replyChainEnd < 0) {
6422 replyChainEnd = targetI;
6423 }
Ed Heyl73798232009-03-24 21:32:21 -07006424 } else if (!finishOnTaskLaunch && !clearWhenTaskReset && allowTaskReparenting
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006425 && target.taskAffinity != null
6426 && !target.taskAffinity.equals(task.affinity)) {
6427 // If this activity has an affinity for another
6428 // task, then we need to move it out of here. We will
6429 // move it as far out of the way as possible, to the
6430 // bottom of the activity stack. This also keeps it
6431 // correctly ordered with any activities we previously
6432 // moved.
6433 HistoryRecord p = (HistoryRecord)mHistory.get(0);
6434 if (target.taskAffinity != null
6435 && target.taskAffinity.equals(p.task.affinity)) {
6436 // If the activity currently at the bottom has the
6437 // same task affinity as the one we are moving,
6438 // then merge it into the same task.
6439 target.task = p.task;
6440 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6441 + " out to bottom task " + p.task);
6442 } else {
6443 mCurTask++;
6444 if (mCurTask <= 0) {
6445 mCurTask = 1;
6446 }
6447 target.task = new TaskRecord(mCurTask, target.info, null,
6448 (target.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);
6449 target.task.affinityIntent = target.intent;
6450 if (DEBUG_TASKS) Log.v(TAG, "Start pushing activity " + target
6451 + " out to new task " + target.task);
6452 }
6453 mWindowManager.setAppGroupId(target, task.taskId);
6454 if (replyChainEnd < 0) {
6455 replyChainEnd = targetI;
6456 }
6457 int dstPos = 0;
6458 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6459 p = (HistoryRecord)mHistory.get(srcPos);
6460 if (p.finishing) {
6461 continue;
6462 }
6463 if (DEBUG_TASKS) Log.v(TAG, "Pushing next activity " + p
6464 + " out to target's task " + target.task);
6465 task.numActivities--;
6466 p.task = target.task;
6467 target.task.numActivities++;
6468 mHistory.remove(srcPos);
6469 mHistory.add(dstPos, p);
6470 mWindowManager.moveAppToken(dstPos, p);
6471 mWindowManager.setAppGroupId(p, p.task.taskId);
6472 dstPos++;
6473 if (VALIDATE_TOKENS) {
6474 mWindowManager.validateAppTokens(mHistory);
6475 }
6476 i++;
6477 }
6478 if (taskTop == p) {
6479 taskTop = below;
6480 }
6481 if (taskTopI == replyChainEnd) {
6482 taskTopI = -1;
6483 }
6484 replyChainEnd = -1;
6485 addRecentTask(target.task);
6486 } else if (forceReset || finishOnTaskLaunch
6487 || clearWhenTaskReset) {
6488 // If the activity should just be removed -- either
6489 // because it asks for it, or the task should be
6490 // cleared -- then finish it and anything that is
6491 // part of its reply chain.
6492 if (clearWhenTaskReset) {
6493 // In this case, we want to finish this activity
6494 // and everything above it, so be sneaky and pretend
6495 // like these are all in the reply chain.
6496 replyChainEnd = targetI+1;
6497 while (replyChainEnd < mHistory.size() &&
6498 ((HistoryRecord)mHistory.get(
6499 replyChainEnd)).task == task) {
6500 replyChainEnd++;
6501 }
6502 replyChainEnd--;
6503 } else if (replyChainEnd < 0) {
6504 replyChainEnd = targetI;
6505 }
6506 HistoryRecord p = null;
6507 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6508 p = (HistoryRecord)mHistory.get(srcPos);
6509 if (p.finishing) {
6510 continue;
6511 }
6512 if (finishActivityLocked(p, srcPos,
6513 Activity.RESULT_CANCELED, null, "reset")) {
6514 replyChainEnd--;
6515 srcPos--;
6516 }
6517 }
6518 if (taskTop == p) {
6519 taskTop = below;
6520 }
6521 if (taskTopI == replyChainEnd) {
6522 taskTopI = -1;
6523 }
6524 replyChainEnd = -1;
6525 } else {
6526 // If we were in the middle of a chain, well the
6527 // activity that started it all doesn't want anything
6528 // special, so leave it all as-is.
6529 replyChainEnd = -1;
6530 }
6531 } else {
6532 // Reached the bottom of the task -- any reply chain
6533 // should be left as-is.
6534 replyChainEnd = -1;
6535 }
6536
6537 } else if (target.resultTo != null) {
6538 // If this activity is sending a reply to a previous
6539 // activity, we can't do anything with it now until
6540 // we reach the start of the reply chain.
6541 // XXX note that we are assuming the result is always
6542 // to the previous activity, which is almost always
6543 // the case but we really shouldn't count on.
6544 if (replyChainEnd < 0) {
6545 replyChainEnd = targetI;
6546 }
6547
6548 } else if (taskTopI >= 0 && allowTaskReparenting
6549 && task.affinity != null
6550 && task.affinity.equals(target.taskAffinity)) {
6551 // We are inside of another task... if this activity has
6552 // an affinity for our task, then either remove it if we are
6553 // clearing or move it over to our task. Note that
6554 // we currently punt on the case where we are resetting a
6555 // task that is not at the top but who has activities above
6556 // with an affinity to it... this is really not a normal
6557 // case, and we will need to later pull that task to the front
6558 // and usually at that point we will do the reset and pick
6559 // up those remaining activities. (This only happens if
6560 // someone starts an activity in a new task from an activity
6561 // in a task that is not currently on top.)
6562 if (forceReset || finishOnTaskLaunch) {
6563 if (replyChainEnd < 0) {
6564 replyChainEnd = targetI;
6565 }
6566 HistoryRecord p = null;
6567 for (int srcPos=targetI; srcPos<=replyChainEnd; srcPos++) {
6568 p = (HistoryRecord)mHistory.get(srcPos);
6569 if (p.finishing) {
6570 continue;
6571 }
6572 if (finishActivityLocked(p, srcPos,
6573 Activity.RESULT_CANCELED, null, "reset")) {
6574 taskTopI--;
6575 lastReparentPos--;
6576 replyChainEnd--;
6577 srcPos--;
6578 }
6579 }
6580 replyChainEnd = -1;
6581 } else {
6582 if (replyChainEnd < 0) {
6583 replyChainEnd = targetI;
6584 }
6585 for (int srcPos=replyChainEnd; srcPos>=targetI; srcPos--) {
6586 HistoryRecord p = (HistoryRecord)mHistory.get(srcPos);
6587 if (p.finishing) {
6588 continue;
6589 }
6590 if (lastReparentPos < 0) {
6591 lastReparentPos = taskTopI;
6592 taskTop = p;
6593 } else {
6594 lastReparentPos--;
6595 }
6596 mHistory.remove(srcPos);
6597 p.task.numActivities--;
6598 p.task = task;
6599 mHistory.add(lastReparentPos, p);
6600 if (DEBUG_TASKS) Log.v(TAG, "Pulling activity " + p
6601 + " in to resetting task " + task);
6602 task.numActivities++;
6603 mWindowManager.moveAppToken(lastReparentPos, p);
6604 mWindowManager.setAppGroupId(p, p.task.taskId);
6605 if (VALIDATE_TOKENS) {
6606 mWindowManager.validateAppTokens(mHistory);
6607 }
6608 }
6609 replyChainEnd = -1;
6610
6611 // Now we've moved it in to place... but what if this is
6612 // a singleTop activity and we have put it on top of another
6613 // instance of the same activity? Then we drop the instance
6614 // below so it remains singleTop.
6615 if (target.info.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP) {
6616 for (int j=lastReparentPos-1; j>=0; j--) {
6617 HistoryRecord p = (HistoryRecord)mHistory.get(j);
6618 if (p.finishing) {
6619 continue;
6620 }
6621 if (p.intent.getComponent().equals(target.intent.getComponent())) {
6622 if (finishActivityLocked(p, j,
6623 Activity.RESULT_CANCELED, null, "replace")) {
6624 taskTopI--;
6625 lastReparentPos--;
6626 }
6627 }
6628 }
6629 }
6630 }
6631 }
6632
6633 target = below;
6634 targetI = i;
6635 }
6636
6637 return taskTop;
6638 }
6639
6640 /**
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006641 * TODO: Add mController hook
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006642 */
6643 public void moveTaskToFront(int task) {
6644 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6645 "moveTaskToFront()");
6646
6647 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006648 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6649 Binder.getCallingUid(), "Task to front")) {
6650 return;
6651 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006652 final long origId = Binder.clearCallingIdentity();
6653 try {
6654 int N = mRecentTasks.size();
6655 for (int i=0; i<N; i++) {
6656 TaskRecord tr = mRecentTasks.get(i);
6657 if (tr.taskId == task) {
6658 moveTaskToFrontLocked(tr);
6659 return;
6660 }
6661 }
6662 for (int i=mHistory.size()-1; i>=0; i--) {
6663 HistoryRecord hr = (HistoryRecord)mHistory.get(i);
6664 if (hr.task.taskId == task) {
6665 moveTaskToFrontLocked(hr.task);
6666 return;
6667 }
6668 }
6669 } finally {
6670 Binder.restoreCallingIdentity(origId);
6671 }
6672 }
6673 }
6674
6675 private final void moveTaskToFrontLocked(TaskRecord tr) {
6676 if (DEBUG_SWITCH) Log.v(TAG, "moveTaskToFront: " + tr);
6677
6678 final int task = tr.taskId;
6679 int top = mHistory.size()-1;
6680
6681 if (top < 0 || ((HistoryRecord)mHistory.get(top)).task.taskId == task) {
6682 // nothing to do!
6683 return;
6684 }
6685
6686 if (DEBUG_TRANSITION) Log.v(TAG,
6687 "Prepare to front transition: task=" + tr);
6688 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_FRONT);
6689
6690 ArrayList moved = new ArrayList();
6691
6692 // Applying the affinities may have removed entries from the history,
6693 // so get the size again.
6694 top = mHistory.size()-1;
6695 int pos = top;
6696
6697 // Shift all activities with this task up to the top
6698 // of the stack, keeping them in the same internal order.
6699 while (pos >= 0) {
6700 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6701 if (localLOGV) Log.v(
6702 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6703 boolean first = true;
6704 if (r.task.taskId == task) {
6705 if (localLOGV) Log.v(TAG, "Removing and adding at " + top);
6706 mHistory.remove(pos);
6707 mHistory.add(top, r);
6708 moved.add(0, r);
6709 top--;
6710 if (first) {
6711 addRecentTask(r.task);
6712 first = false;
6713 }
6714 }
6715 pos--;
6716 }
6717
6718 mWindowManager.moveAppTokensToTop(moved);
6719 if (VALIDATE_TOKENS) {
6720 mWindowManager.validateAppTokens(mHistory);
6721 }
6722
6723 finishTaskMove(task);
6724 EventLog.writeEvent(LOG_TASK_TO_FRONT, task);
6725 }
6726
6727 private final void finishTaskMove(int task) {
6728 resumeTopActivityLocked(null);
6729 }
6730
6731 public void moveTaskToBack(int task) {
6732 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6733 "moveTaskToBack()");
6734
6735 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006736 if (mResumedActivity != null && mResumedActivity.task.taskId == task) {
6737 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6738 Binder.getCallingUid(), "Task to back")) {
6739 return;
6740 }
6741 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006742 final long origId = Binder.clearCallingIdentity();
6743 moveTaskToBackLocked(task);
6744 Binder.restoreCallingIdentity(origId);
6745 }
6746 }
6747
6748 /**
6749 * Moves an activity, and all of the other activities within the same task, to the bottom
6750 * of the history stack. The activity's order within the task is unchanged.
6751 *
6752 * @param token A reference to the activity we wish to move
6753 * @param nonRoot If false then this only works if the activity is the root
6754 * of a task; if true it will work for any activity in a task.
6755 * @return Returns true if the move completed, false if not.
6756 */
6757 public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) {
6758 synchronized(this) {
6759 final long origId = Binder.clearCallingIdentity();
6760 int taskId = getTaskForActivityLocked(token, !nonRoot);
6761 if (taskId >= 0) {
6762 return moveTaskToBackLocked(taskId);
6763 }
6764 Binder.restoreCallingIdentity(origId);
6765 }
6766 return false;
6767 }
6768
6769 /**
6770 * Worker method for rearranging history stack. Implements the function of moving all
6771 * activities for a specific task (gathering them if disjoint) into a single group at the
6772 * bottom of the stack.
6773 *
6774 * If a watcher is installed, the action is preflighted and the watcher has an opportunity
6775 * to premeptively cancel the move.
6776 *
6777 * @param task The taskId to collect and move to the bottom.
6778 * @return Returns true if the move completed, false if not.
6779 */
6780 private final boolean moveTaskToBackLocked(int task) {
6781 Log.i(TAG, "moveTaskToBack: " + task);
6782
6783 // If we have a watcher, preflight the move before committing to it. First check
6784 // for *other* available tasks, but if none are available, then try again allowing the
6785 // current task to be selected.
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006786 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006787 HistoryRecord next = topRunningActivityLocked(null, task);
6788 if (next == null) {
6789 next = topRunningActivityLocked(null, 0);
6790 }
6791 if (next != null) {
6792 // ask watcher if this is allowed
6793 boolean moveOK = true;
6794 try {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006795 moveOK = mController.activityResuming(next.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006796 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07006797 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006798 }
6799 if (!moveOK) {
6800 return false;
6801 }
6802 }
6803 }
6804
6805 ArrayList moved = new ArrayList();
6806
6807 if (DEBUG_TRANSITION) Log.v(TAG,
6808 "Prepare to back transition: task=" + task);
6809 mWindowManager.prepareAppTransition(WindowManagerPolicy.TRANSIT_TASK_TO_BACK);
6810
6811 final int N = mHistory.size();
6812 int bottom = 0;
6813 int pos = 0;
6814
6815 // Shift all activities with this task down to the bottom
6816 // of the stack, keeping them in the same internal order.
6817 while (pos < N) {
6818 HistoryRecord r = (HistoryRecord)mHistory.get(pos);
6819 if (localLOGV) Log.v(
6820 TAG, "At " + pos + " ckp " + r.task + ": " + r);
6821 if (r.task.taskId == task) {
6822 if (localLOGV) Log.v(TAG, "Removing and adding at " + (N-1));
6823 mHistory.remove(pos);
6824 mHistory.add(bottom, r);
6825 moved.add(r);
6826 bottom++;
6827 }
6828 pos++;
6829 }
6830
6831 mWindowManager.moveAppTokensToBottom(moved);
6832 if (VALIDATE_TOKENS) {
6833 mWindowManager.validateAppTokens(mHistory);
6834 }
6835
6836 finishTaskMove(task);
6837 return true;
6838 }
6839
6840 public void moveTaskBackwards(int task) {
6841 enforceCallingPermission(android.Manifest.permission.REORDER_TASKS,
6842 "moveTaskBackwards()");
6843
6844 synchronized(this) {
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07006845 if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(),
6846 Binder.getCallingUid(), "Task backwards")) {
6847 return;
6848 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006849 final long origId = Binder.clearCallingIdentity();
6850 moveTaskBackwardsLocked(task);
6851 Binder.restoreCallingIdentity(origId);
6852 }
6853 }
6854
6855 private final void moveTaskBackwardsLocked(int task) {
6856 Log.e(TAG, "moveTaskBackwards not yet implemented!");
6857 }
6858
6859 public int getTaskForActivity(IBinder token, boolean onlyRoot) {
6860 synchronized(this) {
6861 return getTaskForActivityLocked(token, onlyRoot);
6862 }
6863 }
6864
6865 int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
6866 final int N = mHistory.size();
6867 TaskRecord lastTask = null;
6868 for (int i=0; i<N; i++) {
6869 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6870 if (r == token) {
6871 if (!onlyRoot || lastTask != r.task) {
6872 return r.task.taskId;
6873 }
6874 return -1;
6875 }
6876 lastTask = r.task;
6877 }
6878
6879 return -1;
6880 }
6881
6882 /**
6883 * Returns the top activity in any existing task matching the given
6884 * Intent. Returns null if no such task is found.
6885 */
6886 private HistoryRecord findTaskLocked(Intent intent, ActivityInfo info) {
6887 ComponentName cls = intent.getComponent();
6888 if (info.targetActivity != null) {
6889 cls = new ComponentName(info.packageName, info.targetActivity);
6890 }
6891
6892 TaskRecord cp = null;
6893
6894 final int N = mHistory.size();
6895 for (int i=(N-1); i>=0; i--) {
6896 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6897 if (!r.finishing && r.task != cp
6898 && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
6899 cp = r.task;
6900 //Log.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()
6901 // + "/aff=" + r.task.affinity + " to new cls="
6902 // + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);
6903 if (r.task.affinity != null) {
6904 if (r.task.affinity.equals(info.taskAffinity)) {
6905 //Log.i(TAG, "Found matching affinity!");
6906 return r;
6907 }
6908 } else if (r.task.intent != null
6909 && r.task.intent.getComponent().equals(cls)) {
6910 //Log.i(TAG, "Found matching class!");
6911 //dump();
6912 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6913 return r;
6914 } else if (r.task.affinityIntent != null
6915 && r.task.affinityIntent.getComponent().equals(cls)) {
6916 //Log.i(TAG, "Found matching class!");
6917 //dump();
6918 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6919 return r;
6920 }
6921 }
6922 }
6923
6924 return null;
6925 }
6926
6927 /**
6928 * Returns the first activity (starting from the top of the stack) that
6929 * is the same as the given activity. Returns null if no such activity
6930 * is found.
6931 */
6932 private HistoryRecord findActivityLocked(Intent intent, ActivityInfo info) {
6933 ComponentName cls = intent.getComponent();
6934 if (info.targetActivity != null) {
6935 cls = new ComponentName(info.packageName, info.targetActivity);
6936 }
6937
6938 final int N = mHistory.size();
6939 for (int i=(N-1); i>=0; i--) {
6940 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6941 if (!r.finishing) {
6942 if (r.intent.getComponent().equals(cls)) {
6943 //Log.i(TAG, "Found matching class!");
6944 //dump();
6945 //Log.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
6946 return r;
6947 }
6948 }
6949 }
6950
6951 return null;
6952 }
6953
6954 public void finishOtherInstances(IBinder token, ComponentName className) {
6955 synchronized(this) {
6956 final long origId = Binder.clearCallingIdentity();
6957
6958 int N = mHistory.size();
6959 TaskRecord lastTask = null;
6960 for (int i=0; i<N; i++) {
6961 HistoryRecord r = (HistoryRecord)mHistory.get(i);
6962 if (r.realActivity.equals(className)
6963 && r != token && lastTask != r.task) {
6964 if (finishActivityLocked(r, i, Activity.RESULT_CANCELED,
6965 null, "others")) {
6966 i--;
6967 N--;
6968 }
6969 }
6970 lastTask = r.task;
6971 }
6972
6973 Binder.restoreCallingIdentity(origId);
6974 }
6975 }
6976
6977 // =========================================================
6978 // THUMBNAILS
6979 // =========================================================
6980
6981 public void reportThumbnail(IBinder token,
6982 Bitmap thumbnail, CharSequence description) {
6983 //System.out.println("Report thumbnail for " + token + ": " + thumbnail);
6984 final long origId = Binder.clearCallingIdentity();
6985 sendPendingThumbnail(null, token, thumbnail, description, true);
6986 Binder.restoreCallingIdentity(origId);
6987 }
6988
6989 final void sendPendingThumbnail(HistoryRecord r, IBinder token,
6990 Bitmap thumbnail, CharSequence description, boolean always) {
6991 TaskRecord task = null;
6992 ArrayList receivers = null;
6993
6994 //System.out.println("Send pending thumbnail: " + r);
6995
6996 synchronized(this) {
6997 if (r == null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -07006998 int index = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08006999 if (index < 0) {
7000 return;
7001 }
7002 r = (HistoryRecord)mHistory.get(index);
7003 }
7004 if (thumbnail == null) {
7005 thumbnail = r.thumbnail;
7006 description = r.description;
7007 }
7008 if (thumbnail == null && !always) {
7009 // If there is no thumbnail, and this entry is not actually
7010 // going away, then abort for now and pick up the next
7011 // thumbnail we get.
7012 return;
7013 }
7014 task = r.task;
7015
7016 int N = mPendingThumbnails.size();
7017 int i=0;
7018 while (i<N) {
7019 PendingThumbnailsRecord pr =
7020 (PendingThumbnailsRecord)mPendingThumbnails.get(i);
7021 //System.out.println("Looking in " + pr.pendingRecords);
7022 if (pr.pendingRecords.remove(r)) {
7023 if (receivers == null) {
7024 receivers = new ArrayList();
7025 }
7026 receivers.add(pr);
7027 if (pr.pendingRecords.size() == 0) {
7028 pr.finished = true;
7029 mPendingThumbnails.remove(i);
7030 N--;
7031 continue;
7032 }
7033 }
7034 i++;
7035 }
7036 }
7037
7038 if (receivers != null) {
7039 final int N = receivers.size();
7040 for (int i=0; i<N; i++) {
7041 try {
7042 PendingThumbnailsRecord pr =
7043 (PendingThumbnailsRecord)receivers.get(i);
7044 pr.receiver.newThumbnail(
7045 task != null ? task.taskId : -1, thumbnail, description);
7046 if (pr.finished) {
7047 pr.receiver.finished();
7048 }
7049 } catch (Exception e) {
7050 Log.w(TAG, "Exception thrown when sending thumbnail", e);
7051 }
7052 }
7053 }
7054 }
7055
7056 // =========================================================
7057 // CONTENT PROVIDERS
7058 // =========================================================
7059
7060 private final List generateApplicationProvidersLocked(ProcessRecord app) {
7061 List providers = null;
7062 try {
7063 providers = ActivityThread.getPackageManager().
7064 queryContentProviders(app.processName, app.info.uid,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007065 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007066 } catch (RemoteException ex) {
7067 }
7068 if (providers != null) {
7069 final int N = providers.size();
7070 for (int i=0; i<N; i++) {
7071 ProviderInfo cpi =
7072 (ProviderInfo)providers.get(i);
7073 ContentProviderRecord cpr =
7074 (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7075 if (cpr == null) {
7076 cpr = new ContentProviderRecord(cpi, app.info);
7077 mProvidersByClass.put(cpi.name, cpr);
7078 }
7079 app.pubProviders.put(cpi.name, cpr);
7080 app.addPackage(cpi.applicationInfo.packageName);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07007081 ensurePackageDexOpt(cpi.applicationInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007082 }
7083 }
7084 return providers;
7085 }
7086
7087 private final String checkContentProviderPermissionLocked(
7088 ProviderInfo cpi, ProcessRecord r, int mode) {
7089 final int callingPid = (r != null) ? r.pid : Binder.getCallingPid();
7090 final int callingUid = (r != null) ? r.info.uid : Binder.getCallingUid();
7091 if (checkComponentPermission(cpi.readPermission, callingPid, callingUid,
7092 cpi.exported ? -1 : cpi.applicationInfo.uid)
7093 == PackageManager.PERMISSION_GRANTED
7094 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7095 return null;
7096 }
7097 if (checkComponentPermission(cpi.writePermission, callingPid, callingUid,
7098 cpi.exported ? -1 : cpi.applicationInfo.uid)
7099 == PackageManager.PERMISSION_GRANTED) {
7100 return null;
7101 }
Dianne Hackborn2af632f2009-07-08 14:56:37 -07007102
7103 PathPermission[] pps = cpi.pathPermissions;
7104 if (pps != null) {
7105 int i = pps.length;
7106 while (i > 0) {
7107 i--;
7108 PathPermission pp = pps[i];
7109 if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
7110 cpi.exported ? -1 : cpi.applicationInfo.uid)
7111 == PackageManager.PERMISSION_GRANTED
7112 && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
7113 return null;
7114 }
7115 if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
7116 cpi.exported ? -1 : cpi.applicationInfo.uid)
7117 == PackageManager.PERMISSION_GRANTED) {
7118 return null;
7119 }
7120 }
7121 }
7122
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007123 String msg = "Permission Denial: opening provider " + cpi.name
7124 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
7125 + ", uid=" + callingUid + ") requires "
7126 + cpi.readPermission + " or " + cpi.writePermission;
7127 Log.w(TAG, msg);
7128 return msg;
7129 }
7130
7131 private final ContentProviderHolder getContentProviderImpl(
7132 IApplicationThread caller, String name) {
7133 ContentProviderRecord cpr;
7134 ProviderInfo cpi = null;
7135
7136 synchronized(this) {
7137 ProcessRecord r = null;
7138 if (caller != null) {
7139 r = getRecordForAppLocked(caller);
7140 if (r == null) {
7141 throw new SecurityException(
7142 "Unable to find app for caller " + caller
7143 + " (pid=" + Binder.getCallingPid()
7144 + ") when getting content provider " + name);
7145 }
7146 }
7147
7148 // First check if this content provider has been published...
7149 cpr = (ContentProviderRecord)mProvidersByName.get(name);
7150 if (cpr != null) {
7151 cpi = cpr.info;
7152 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7153 return new ContentProviderHolder(cpi,
7154 cpi.readPermission != null
7155 ? cpi.readPermission : cpi.writePermission);
7156 }
7157
7158 if (r != null && cpr.canRunHere(r)) {
7159 // This provider has been published or is in the process
7160 // of being published... but it is also allowed to run
7161 // in the caller's process, so don't make a connection
7162 // and just let the caller instantiate its own instance.
7163 if (cpr.provider != null) {
7164 // don't give caller the provider object, it needs
7165 // to make its own.
7166 cpr = new ContentProviderRecord(cpr);
7167 }
7168 return cpr;
7169 }
7170
7171 final long origId = Binder.clearCallingIdentity();
7172
7173 // In this case the provider is a single instance, so we can
7174 // return it right away.
7175 if (r != null) {
7176 r.conProviders.add(cpr);
7177 cpr.clients.add(r);
7178 } else {
7179 cpr.externals++;
7180 }
7181
7182 if (cpr.app != null) {
7183 updateOomAdjLocked(cpr.app);
7184 }
7185
7186 Binder.restoreCallingIdentity(origId);
7187
7188 } else {
7189 try {
7190 cpi = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07007191 resolveContentProvider(name,
7192 STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007193 } catch (RemoteException ex) {
7194 }
7195 if (cpi == null) {
7196 return null;
7197 }
7198
7199 if (checkContentProviderPermissionLocked(cpi, r, -1) != null) {
7200 return new ContentProviderHolder(cpi,
7201 cpi.readPermission != null
7202 ? cpi.readPermission : cpi.writePermission);
7203 }
7204
7205 cpr = (ContentProviderRecord)mProvidersByClass.get(cpi.name);
7206 final boolean firstClass = cpr == null;
7207 if (firstClass) {
7208 try {
7209 ApplicationInfo ai =
7210 ActivityThread.getPackageManager().
7211 getApplicationInfo(
7212 cpi.applicationInfo.packageName,
Dianne Hackborn1655be42009-05-08 14:29:01 -07007213 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007214 if (ai == null) {
7215 Log.w(TAG, "No package info for content provider "
7216 + cpi.name);
7217 return null;
7218 }
7219 cpr = new ContentProviderRecord(cpi, ai);
7220 } catch (RemoteException ex) {
7221 // pm is in same process, this will never happen.
7222 }
7223 }
7224
7225 if (r != null && cpr.canRunHere(r)) {
7226 // If this is a multiprocess provider, then just return its
7227 // info and allow the caller to instantiate it. Only do
7228 // this if the provider is the same user as the caller's
7229 // process, or can run as root (so can be in any process).
7230 return cpr;
7231 }
7232
7233 if (false) {
7234 RuntimeException e = new RuntimeException("foo");
7235 //Log.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + r.info.uid
7236 // + " pruid " + ai.uid + "): " + cpi.className, e);
7237 }
7238
7239 // This is single process, and our app is now connecting to it.
7240 // See if we are already in the process of launching this
7241 // provider.
7242 final int N = mLaunchingProviders.size();
7243 int i;
7244 for (i=0; i<N; i++) {
7245 if (mLaunchingProviders.get(i) == cpr) {
7246 break;
7247 }
7248 if (false) {
7249 final ContentProviderRecord rec =
7250 (ContentProviderRecord)mLaunchingProviders.get(i);
7251 if (rec.info.name.equals(cpr.info.name)) {
7252 cpr = rec;
7253 break;
7254 }
7255 }
7256 }
7257
7258 // If the provider is not already being launched, then get it
7259 // started.
7260 if (i >= N) {
7261 final long origId = Binder.clearCallingIdentity();
7262 ProcessRecord proc = startProcessLocked(cpi.processName,
7263 cpr.appInfo, false, 0, "content provider",
7264 new ComponentName(cpi.applicationInfo.packageName,
7265 cpi.name));
7266 if (proc == null) {
7267 Log.w(TAG, "Unable to launch app "
7268 + cpi.applicationInfo.packageName + "/"
7269 + cpi.applicationInfo.uid + " for provider "
7270 + name + ": process is bad");
7271 return null;
7272 }
7273 cpr.launchingApp = proc;
7274 mLaunchingProviders.add(cpr);
7275 Binder.restoreCallingIdentity(origId);
7276 }
7277
7278 // Make sure the provider is published (the same provider class
7279 // may be published under multiple names).
7280 if (firstClass) {
7281 mProvidersByClass.put(cpi.name, cpr);
7282 }
7283 mProvidersByName.put(name, cpr);
7284
7285 if (r != null) {
7286 r.conProviders.add(cpr);
7287 cpr.clients.add(r);
7288 } else {
7289 cpr.externals++;
7290 }
7291 }
7292 }
7293
7294 // Wait for the provider to be published...
7295 synchronized (cpr) {
7296 while (cpr.provider == null) {
7297 if (cpr.launchingApp == null) {
7298 Log.w(TAG, "Unable to launch app "
7299 + cpi.applicationInfo.packageName + "/"
7300 + cpi.applicationInfo.uid + " for provider "
7301 + name + ": launching app became null");
7302 EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
7303 cpi.applicationInfo.packageName,
7304 cpi.applicationInfo.uid, name);
7305 return null;
7306 }
7307 try {
7308 cpr.wait();
7309 } catch (InterruptedException ex) {
7310 }
7311 }
7312 }
7313 return cpr;
7314 }
7315
7316 public final ContentProviderHolder getContentProvider(
7317 IApplicationThread caller, String name) {
7318 if (caller == null) {
7319 String msg = "null IApplicationThread when getting content provider "
7320 + name;
7321 Log.w(TAG, msg);
7322 throw new SecurityException(msg);
7323 }
7324
7325 return getContentProviderImpl(caller, name);
7326 }
7327
7328 private ContentProviderHolder getContentProviderExternal(String name) {
7329 return getContentProviderImpl(null, name);
7330 }
7331
7332 /**
7333 * Drop a content provider from a ProcessRecord's bookkeeping
7334 * @param cpr
7335 */
7336 public void removeContentProvider(IApplicationThread caller, String name) {
7337 synchronized (this) {
7338 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7339 if(cpr == null) {
7340 //remove from mProvidersByClass
7341 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7342 return;
7343 }
7344 final ProcessRecord r = getRecordForAppLocked(caller);
7345 if (r == null) {
7346 throw new SecurityException(
7347 "Unable to find app for caller " + caller +
7348 " when removing content provider " + name);
7349 }
7350 //update content provider record entry info
7351 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7352 if(localLOGV) Log.v(TAG, "Removing content provider requested by "+
7353 r.info.processName+" from process "+localCpr.appInfo.processName);
7354 if(localCpr.appInfo.processName == r.info.processName) {
7355 //should not happen. taken care of as a local provider
7356 if(localLOGV) Log.v(TAG, "local provider doing nothing Ignoring other names");
7357 return;
7358 } else {
7359 localCpr.clients.remove(r);
7360 r.conProviders.remove(localCpr);
7361 }
7362 updateOomAdjLocked();
7363 }
7364 }
7365
7366 private void removeContentProviderExternal(String name) {
7367 synchronized (this) {
7368 ContentProviderRecord cpr = (ContentProviderRecord)mProvidersByName.get(name);
7369 if(cpr == null) {
7370 //remove from mProvidersByClass
7371 if(localLOGV) Log.v(TAG, name+" content provider not found in providers list");
7372 return;
7373 }
7374
7375 //update content provider record entry info
7376 ContentProviderRecord localCpr = (ContentProviderRecord) mProvidersByClass.get(cpr.info.name);
7377 localCpr.externals--;
7378 if (localCpr.externals < 0) {
7379 Log.e(TAG, "Externals < 0 for content provider " + localCpr);
7380 }
7381 updateOomAdjLocked();
7382 }
7383 }
7384
7385 public final void publishContentProviders(IApplicationThread caller,
7386 List<ContentProviderHolder> providers) {
7387 if (providers == null) {
7388 return;
7389 }
7390
7391 synchronized(this) {
7392 final ProcessRecord r = getRecordForAppLocked(caller);
7393 if (r == null) {
7394 throw new SecurityException(
7395 "Unable to find app for caller " + caller
7396 + " (pid=" + Binder.getCallingPid()
7397 + ") when publishing content providers");
7398 }
7399
7400 final long origId = Binder.clearCallingIdentity();
7401
7402 final int N = providers.size();
7403 for (int i=0; i<N; i++) {
7404 ContentProviderHolder src = providers.get(i);
7405 if (src == null || src.info == null || src.provider == null) {
7406 continue;
7407 }
7408 ContentProviderRecord dst =
7409 (ContentProviderRecord)r.pubProviders.get(src.info.name);
7410 if (dst != null) {
7411 mProvidersByClass.put(dst.info.name, dst);
7412 String names[] = dst.info.authority.split(";");
7413 for (int j = 0; j < names.length; j++) {
7414 mProvidersByName.put(names[j], dst);
7415 }
7416
7417 int NL = mLaunchingProviders.size();
7418 int j;
7419 for (j=0; j<NL; j++) {
7420 if (mLaunchingProviders.get(j) == dst) {
7421 mLaunchingProviders.remove(j);
7422 j--;
7423 NL--;
7424 }
7425 }
7426 synchronized (dst) {
7427 dst.provider = src.provider;
7428 dst.app = r;
7429 dst.notifyAll();
7430 }
7431 updateOomAdjLocked(r);
7432 }
7433 }
7434
7435 Binder.restoreCallingIdentity(origId);
7436 }
7437 }
7438
7439 public static final void installSystemProviders() {
7440 ProcessRecord app = mSelf.mProcessNames.get("system", Process.SYSTEM_UID);
7441 List providers = mSelf.generateApplicationProvidersLocked(app);
7442 mSystemThread.installSystemProviders(providers);
7443 }
7444
7445 // =========================================================
7446 // GLOBAL MANAGEMENT
7447 // =========================================================
7448
7449 final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
7450 ApplicationInfo info, String customProcess) {
7451 String proc = customProcess != null ? customProcess : info.processName;
7452 BatteryStatsImpl.Uid.Proc ps = null;
7453 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7454 synchronized (stats) {
7455 ps = stats.getProcessStatsLocked(info.uid, proc);
7456 }
7457 return new ProcessRecord(ps, thread, info, proc);
7458 }
7459
7460 final ProcessRecord addAppLocked(ApplicationInfo info) {
7461 ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
7462
7463 if (app == null) {
7464 app = newProcessRecordLocked(null, info, null);
7465 mProcessNames.put(info.processName, info.uid, app);
7466 updateLRUListLocked(app, true);
7467 }
7468
7469 if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
7470 == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
7471 app.persistent = true;
7472 app.maxAdj = CORE_SERVER_ADJ;
7473 }
7474 if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
7475 mPersistentStartingProcesses.add(app);
7476 startProcessLocked(app, "added application", app.processName);
7477 }
7478
7479 return app;
7480 }
7481
7482 public void unhandledBack() {
7483 enforceCallingPermission(android.Manifest.permission.FORCE_BACK,
7484 "unhandledBack()");
7485
7486 synchronized(this) {
7487 int count = mHistory.size();
7488 if (Config.LOGD) Log.d(
7489 TAG, "Performing unhandledBack(): stack size = " + count);
7490 if (count > 1) {
7491 final long origId = Binder.clearCallingIdentity();
7492 finishActivityLocked((HistoryRecord)mHistory.get(count-1),
7493 count-1, Activity.RESULT_CANCELED, null, "unhandled-back");
7494 Binder.restoreCallingIdentity(origId);
7495 }
7496 }
7497 }
7498
7499 public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
7500 String name = uri.getAuthority();
7501 ContentProviderHolder cph = getContentProviderExternal(name);
7502 ParcelFileDescriptor pfd = null;
7503 if (cph != null) {
7504 // We record the binder invoker's uid in thread-local storage before
7505 // going to the content provider to open the file. Later, in the code
7506 // that handles all permissions checks, we look for this uid and use
7507 // that rather than the Activity Manager's own uid. The effect is that
7508 // we do the check against the caller's permissions even though it looks
7509 // to the content provider like the Activity Manager itself is making
7510 // the request.
7511 sCallerIdentity.set(new Identity(
7512 Binder.getCallingPid(), Binder.getCallingUid()));
7513 try {
7514 pfd = cph.provider.openFile(uri, "r");
7515 } catch (FileNotFoundException e) {
7516 // do nothing; pfd will be returned null
7517 } finally {
7518 // Ensure that whatever happens, we clean up the identity state
7519 sCallerIdentity.remove();
7520 }
7521
7522 // We've got the fd now, so we're done with the provider.
7523 removeContentProviderExternal(name);
7524 } else {
7525 Log.d(TAG, "Failed to get provider for authority '" + name + "'");
7526 }
7527 return pfd;
7528 }
7529
7530 public void goingToSleep() {
7531 synchronized(this) {
7532 mSleeping = true;
7533 mWindowManager.setEventDispatching(false);
7534
7535 if (mResumedActivity != null) {
7536 pauseIfSleepingLocked();
7537 } else {
7538 Log.w(TAG, "goingToSleep with no resumed activity!");
7539 }
7540 }
7541 }
7542
Dianne Hackborn55280a92009-05-07 15:53:46 -07007543 public boolean shutdown(int timeout) {
7544 if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7545 != PackageManager.PERMISSION_GRANTED) {
7546 throw new SecurityException("Requires permission "
7547 + android.Manifest.permission.SHUTDOWN);
7548 }
7549
7550 boolean timedout = false;
7551
7552 synchronized(this) {
7553 mShuttingDown = true;
7554 mWindowManager.setEventDispatching(false);
7555
7556 if (mResumedActivity != null) {
7557 pauseIfSleepingLocked();
7558 final long endTime = System.currentTimeMillis() + timeout;
7559 while (mResumedActivity != null || mPausingActivity != null) {
7560 long delay = endTime - System.currentTimeMillis();
7561 if (delay <= 0) {
7562 Log.w(TAG, "Activity manager shutdown timed out");
7563 timedout = true;
7564 break;
7565 }
7566 try {
7567 this.wait();
7568 } catch (InterruptedException e) {
7569 }
7570 }
7571 }
7572 }
7573
7574 mUsageStatsService.shutdown();
7575 mBatteryStatsService.shutdown();
7576
7577 return timedout;
7578 }
7579
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007580 void pauseIfSleepingLocked() {
Dianne Hackborn55280a92009-05-07 15:53:46 -07007581 if (mSleeping || mShuttingDown) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007582 if (!mGoingToSleep.isHeld()) {
7583 mGoingToSleep.acquire();
7584 if (mLaunchingActivity.isHeld()) {
7585 mLaunchingActivity.release();
7586 mHandler.removeMessages(LAUNCH_TIMEOUT_MSG);
7587 }
7588 }
7589
7590 // If we are not currently pausing an activity, get the current
7591 // one to pause. If we are pausing one, we will just let that stuff
7592 // run and release the wake lock when all done.
7593 if (mPausingActivity == null) {
7594 if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
7595 if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
7596 startPausingLocked(false, true);
7597 }
7598 }
7599 }
7600
7601 public void wakingUp() {
7602 synchronized(this) {
7603 if (mGoingToSleep.isHeld()) {
7604 mGoingToSleep.release();
7605 }
7606 mWindowManager.setEventDispatching(true);
7607 mSleeping = false;
7608 resumeTopActivityLocked(null);
7609 }
7610 }
7611
Dianne Hackborn95fc68f2009-05-19 18:37:45 -07007612 public void stopAppSwitches() {
7613 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7614 != PackageManager.PERMISSION_GRANTED) {
7615 throw new SecurityException("Requires permission "
7616 + android.Manifest.permission.STOP_APP_SWITCHES);
7617 }
7618
7619 synchronized(this) {
7620 mAppSwitchesAllowedTime = SystemClock.uptimeMillis()
7621 + APP_SWITCH_DELAY_TIME;
7622 mDidAppSwitch = false;
7623 mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7624 Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG);
7625 mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME);
7626 }
7627 }
7628
7629 public void resumeAppSwitches() {
7630 if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
7631 != PackageManager.PERMISSION_GRANTED) {
7632 throw new SecurityException("Requires permission "
7633 + android.Manifest.permission.STOP_APP_SWITCHES);
7634 }
7635
7636 synchronized(this) {
7637 // Note that we don't execute any pending app switches... we will
7638 // let those wait until either the timeout, or the next start
7639 // activity request.
7640 mAppSwitchesAllowedTime = 0;
7641 }
7642 }
7643
7644 boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid,
7645 String name) {
7646 if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) {
7647 return true;
7648 }
7649
7650 final int perm = checkComponentPermission(
7651 android.Manifest.permission.STOP_APP_SWITCHES, callingPid,
7652 callingUid, -1);
7653 if (perm == PackageManager.PERMISSION_GRANTED) {
7654 return true;
7655 }
7656
7657 Log.w(TAG, name + " request from " + callingUid + " stopped");
7658 return false;
7659 }
7660
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007661 public void setDebugApp(String packageName, boolean waitForDebugger,
7662 boolean persistent) {
7663 enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP,
7664 "setDebugApp()");
7665
7666 // Note that this is not really thread safe if there are multiple
7667 // callers into it at the same time, but that's not a situation we
7668 // care about.
7669 if (persistent) {
7670 final ContentResolver resolver = mContext.getContentResolver();
7671 Settings.System.putString(
7672 resolver, Settings.System.DEBUG_APP,
7673 packageName);
7674 Settings.System.putInt(
7675 resolver, Settings.System.WAIT_FOR_DEBUGGER,
7676 waitForDebugger ? 1 : 0);
7677 }
7678
7679 synchronized (this) {
7680 if (!persistent) {
7681 mOrigDebugApp = mDebugApp;
7682 mOrigWaitForDebugger = mWaitForDebugger;
7683 }
7684 mDebugApp = packageName;
7685 mWaitForDebugger = waitForDebugger;
7686 mDebugTransient = !persistent;
7687 if (packageName != null) {
7688 final long origId = Binder.clearCallingIdentity();
7689 uninstallPackageLocked(packageName, -1, false);
7690 Binder.restoreCallingIdentity(origId);
7691 }
7692 }
7693 }
7694
7695 public void setAlwaysFinish(boolean enabled) {
7696 enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
7697 "setAlwaysFinish()");
7698
7699 Settings.System.putInt(
7700 mContext.getContentResolver(),
7701 Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
7702
7703 synchronized (this) {
7704 mAlwaysFinishActivities = enabled;
7705 }
7706 }
7707
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007708 public void setActivityController(IActivityController controller) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007709 enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007710 "setActivityController()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007711 synchronized (this) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007712 mController = controller;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007713 }
7714 }
7715
Dianne Hackbornb06ea702009-07-13 13:07:51 -07007716 public void registerActivityWatcher(IActivityWatcher watcher) {
7717 mWatchers.register(watcher);
7718 }
7719
7720 public void unregisterActivityWatcher(IActivityWatcher watcher) {
7721 mWatchers.unregister(watcher);
7722 }
7723
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08007724 public final void enterSafeMode() {
7725 synchronized(this) {
7726 // It only makes sense to do this before the system is ready
7727 // and started launching other packages.
7728 if (!mSystemReady) {
7729 try {
7730 ActivityThread.getPackageManager().enterSafeMode();
7731 } catch (RemoteException e) {
7732 }
7733
7734 View v = LayoutInflater.from(mContext).inflate(
7735 com.android.internal.R.layout.safe_mode, null);
7736 WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
7737 lp.type = WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY;
7738 lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
7739 lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
7740 lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
7741 lp.format = v.getBackground().getOpacity();
7742 lp.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
7743 | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
7744 ((WindowManager)mContext.getSystemService(
7745 Context.WINDOW_SERVICE)).addView(v, lp);
7746 }
7747 }
7748 }
7749
7750 public void noteWakeupAlarm(IIntentSender sender) {
7751 if (!(sender instanceof PendingIntentRecord)) {
7752 return;
7753 }
7754 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
7755 synchronized (stats) {
7756 if (mBatteryStatsService.isOnBattery()) {
7757 mBatteryStatsService.enforceCallingPermission();
7758 PendingIntentRecord rec = (PendingIntentRecord)sender;
7759 int MY_UID = Binder.getCallingUid();
7760 int uid = rec.uid == MY_UID ? Process.SYSTEM_UID : rec.uid;
7761 BatteryStatsImpl.Uid.Pkg pkg =
7762 stats.getPackageStatsLocked(uid, rec.key.packageName);
7763 pkg.incWakeupsLocked();
7764 }
7765 }
7766 }
7767
7768 public boolean killPidsForMemory(int[] pids) {
7769 if (Binder.getCallingUid() != Process.SYSTEM_UID) {
7770 throw new SecurityException("killPidsForMemory only available to the system");
7771 }
7772
7773 // XXX Note: don't acquire main activity lock here, because the window
7774 // manager calls in with its locks held.
7775
7776 boolean killed = false;
7777 synchronized (mPidsSelfLocked) {
7778 int[] types = new int[pids.length];
7779 int worstType = 0;
7780 for (int i=0; i<pids.length; i++) {
7781 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7782 if (proc != null) {
7783 int type = proc.setAdj;
7784 types[i] = type;
7785 if (type > worstType) {
7786 worstType = type;
7787 }
7788 }
7789 }
7790
7791 // If the worse oom_adj is somewhere in the hidden proc LRU range,
7792 // then constrain it so we will kill all hidden procs.
7793 if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
7794 worstType = HIDDEN_APP_MIN_ADJ;
7795 }
7796 Log.w(TAG, "Killing processes for memory at adjustment " + worstType);
7797 for (int i=0; i<pids.length; i++) {
7798 ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
7799 if (proc == null) {
7800 continue;
7801 }
7802 int adj = proc.setAdj;
7803 if (adj >= worstType) {
7804 Log.w(TAG, "Killing for memory: " + proc + " (adj "
7805 + adj + ")");
7806 EventLog.writeEvent(LOG_AM_KILL_FOR_MEMORY, proc.pid,
7807 proc.processName, adj);
7808 killed = true;
7809 Process.killProcess(pids[i]);
7810 }
7811 }
7812 }
7813 return killed;
7814 }
7815
7816 public void reportPss(IApplicationThread caller, int pss) {
7817 Watchdog.PssRequestor req;
7818 String name;
7819 ProcessRecord callerApp;
7820 synchronized (this) {
7821 if (caller == null) {
7822 return;
7823 }
7824 callerApp = getRecordForAppLocked(caller);
7825 if (callerApp == null) {
7826 return;
7827 }
7828 callerApp.lastPss = pss;
7829 req = callerApp;
7830 name = callerApp.processName;
7831 }
7832 Watchdog.getInstance().reportPss(req, name, pss);
7833 if (!callerApp.persistent) {
7834 removeRequestedPss(callerApp);
7835 }
7836 }
7837
7838 public void requestPss(Runnable completeCallback) {
7839 ArrayList<ProcessRecord> procs;
7840 synchronized (this) {
7841 mRequestPssCallback = completeCallback;
7842 mRequestPssList.clear();
7843 for (int i=mLRUProcesses.size()-1; i>=0; i--) {
7844 ProcessRecord proc = mLRUProcesses.get(i);
7845 if (!proc.persistent) {
7846 mRequestPssList.add(proc);
7847 }
7848 }
7849 procs = new ArrayList<ProcessRecord>(mRequestPssList);
7850 }
7851
7852 int oldPri = Process.getThreadPriority(Process.myTid());
7853 Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
7854 for (int i=procs.size()-1; i>=0; i--) {
7855 ProcessRecord proc = procs.get(i);
7856 proc.lastPss = 0;
7857 proc.requestPss();
7858 }
7859 Process.setThreadPriority(oldPri);
7860 }
7861
7862 void removeRequestedPss(ProcessRecord proc) {
7863 Runnable callback = null;
7864 synchronized (this) {
7865 if (mRequestPssList.remove(proc)) {
7866 if (mRequestPssList.size() == 0) {
7867 callback = mRequestPssCallback;
7868 mRequestPssCallback = null;
7869 }
7870 }
7871 }
7872
7873 if (callback != null) {
7874 callback.run();
7875 }
7876 }
7877
7878 public void collectPss(Watchdog.PssStats stats) {
7879 stats.mEmptyPss = 0;
7880 stats.mEmptyCount = 0;
7881 stats.mBackgroundPss = 0;
7882 stats.mBackgroundCount = 0;
7883 stats.mServicePss = 0;
7884 stats.mServiceCount = 0;
7885 stats.mVisiblePss = 0;
7886 stats.mVisibleCount = 0;
7887 stats.mForegroundPss = 0;
7888 stats.mForegroundCount = 0;
7889 stats.mNoPssCount = 0;
7890 synchronized (this) {
7891 int i;
7892 int NPD = mProcDeaths.length < stats.mProcDeaths.length
7893 ? mProcDeaths.length : stats.mProcDeaths.length;
7894 int aggr = 0;
7895 for (i=0; i<NPD; i++) {
7896 aggr += mProcDeaths[i];
7897 stats.mProcDeaths[i] = aggr;
7898 }
7899 while (i<stats.mProcDeaths.length) {
7900 stats.mProcDeaths[i] = 0;
7901 i++;
7902 }
7903
7904 for (i=mLRUProcesses.size()-1; i>=0; i--) {
7905 ProcessRecord proc = mLRUProcesses.get(i);
7906 if (proc.persistent) {
7907 continue;
7908 }
7909 //Log.i(TAG, "Proc " + proc + ": pss=" + proc.lastPss);
7910 if (proc.lastPss == 0) {
7911 stats.mNoPssCount++;
7912 continue;
7913 }
7914 if (proc.setAdj == EMPTY_APP_ADJ) {
7915 stats.mEmptyPss += proc.lastPss;
7916 stats.mEmptyCount++;
7917 } else if (proc.setAdj == CONTENT_PROVIDER_ADJ) {
7918 stats.mEmptyPss += proc.lastPss;
7919 stats.mEmptyCount++;
7920 } else if (proc.setAdj >= HIDDEN_APP_MIN_ADJ) {
7921 stats.mBackgroundPss += proc.lastPss;
7922 stats.mBackgroundCount++;
7923 } else if (proc.setAdj >= VISIBLE_APP_ADJ) {
7924 stats.mVisiblePss += proc.lastPss;
7925 stats.mVisibleCount++;
7926 } else {
7927 stats.mForegroundPss += proc.lastPss;
7928 stats.mForegroundCount++;
7929 }
7930 }
7931 }
7932 }
7933
7934 public final void startRunning(String pkg, String cls, String action,
7935 String data) {
7936 synchronized(this) {
7937 if (mStartRunning) {
7938 return;
7939 }
7940 mStartRunning = true;
7941 mTopComponent = pkg != null && cls != null
7942 ? new ComponentName(pkg, cls) : null;
7943 mTopAction = action != null ? action : Intent.ACTION_MAIN;
7944 mTopData = data;
7945 if (!mSystemReady) {
7946 return;
7947 }
7948 }
7949
7950 systemReady();
7951 }
7952
7953 private void retrieveSettings() {
7954 final ContentResolver resolver = mContext.getContentResolver();
7955 String debugApp = Settings.System.getString(
7956 resolver, Settings.System.DEBUG_APP);
7957 boolean waitForDebugger = Settings.System.getInt(
7958 resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
7959 boolean alwaysFinishActivities = Settings.System.getInt(
7960 resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
7961
7962 Configuration configuration = new Configuration();
7963 Settings.System.getConfiguration(resolver, configuration);
7964
7965 synchronized (this) {
7966 mDebugApp = mOrigDebugApp = debugApp;
7967 mWaitForDebugger = mOrigWaitForDebugger = waitForDebugger;
7968 mAlwaysFinishActivities = alwaysFinishActivities;
7969 // This happens before any activities are started, so we can
7970 // change mConfiguration in-place.
7971 mConfiguration.updateFrom(configuration);
7972 }
7973 }
7974
7975 public boolean testIsSystemReady() {
7976 // no need to synchronize(this) just to read & return the value
7977 return mSystemReady;
7978 }
7979
7980 public void systemReady() {
7981 // In the simulator, startRunning will never have been called, which
7982 // normally sets a few crucial variables. Do it here instead.
7983 if (!Process.supportsProcesses()) {
7984 mStartRunning = true;
7985 mTopAction = Intent.ACTION_MAIN;
7986 }
7987
7988 synchronized(this) {
7989 if (mSystemReady) {
7990 return;
7991 }
7992 mSystemReady = true;
7993 if (!mStartRunning) {
7994 return;
7995 }
7996 }
7997
7998 if (Config.LOGD) Log.d(TAG, "Start running!");
7999 EventLog.writeEvent(LOG_BOOT_PROGRESS_AMS_READY,
8000 SystemClock.uptimeMillis());
8001
8002 synchronized(this) {
8003 if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
8004 ResolveInfo ri = mContext.getPackageManager()
8005 .resolveActivity(new Intent(Intent.ACTION_FACTORY_TEST),
Dianne Hackborn1655be42009-05-08 14:29:01 -07008006 STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008007 CharSequence errorMsg = null;
8008 if (ri != null) {
8009 ActivityInfo ai = ri.activityInfo;
8010 ApplicationInfo app = ai.applicationInfo;
8011 if ((app.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8012 mTopAction = Intent.ACTION_FACTORY_TEST;
8013 mTopData = null;
8014 mTopComponent = new ComponentName(app.packageName,
8015 ai.name);
8016 } else {
8017 errorMsg = mContext.getResources().getText(
8018 com.android.internal.R.string.factorytest_not_system);
8019 }
8020 } else {
8021 errorMsg = mContext.getResources().getText(
8022 com.android.internal.R.string.factorytest_no_action);
8023 }
8024 if (errorMsg != null) {
8025 mTopAction = null;
8026 mTopData = null;
8027 mTopComponent = null;
8028 Message msg = Message.obtain();
8029 msg.what = SHOW_FACTORY_ERROR_MSG;
8030 msg.getData().putCharSequence("msg", errorMsg);
8031 mHandler.sendMessage(msg);
8032 }
8033 }
8034 }
8035
8036 retrieveSettings();
8037
8038 synchronized (this) {
8039 if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
8040 try {
8041 List apps = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -07008042 getPersistentApplications(STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008043 if (apps != null) {
8044 int N = apps.size();
8045 int i;
8046 for (i=0; i<N; i++) {
8047 ApplicationInfo info
8048 = (ApplicationInfo)apps.get(i);
8049 if (info != null &&
8050 !info.packageName.equals("android")) {
8051 addAppLocked(info);
8052 }
8053 }
8054 }
8055 } catch (RemoteException ex) {
8056 // pm is in same process, this will never happen.
8057 }
8058 }
8059
8060 try {
8061 if (ActivityThread.getPackageManager().hasSystemUidErrors()) {
8062 Message msg = Message.obtain();
8063 msg.what = SHOW_UID_ERROR_MSG;
8064 mHandler.sendMessage(msg);
8065 }
8066 } catch (RemoteException e) {
8067 }
8068
8069 // Start up initial activity.
8070 mBooting = true;
8071 resumeTopActivityLocked(null);
8072 }
8073 }
8074
8075 boolean makeAppCrashingLocked(ProcessRecord app,
8076 String tag, String shortMsg, String longMsg, byte[] crashData) {
8077 app.crashing = true;
8078 app.crashingReport = generateProcessError(app,
8079 ActivityManager.ProcessErrorStateInfo.CRASHED, tag, shortMsg, longMsg, crashData);
8080 startAppProblemLocked(app);
8081 app.stopFreezingAllLocked();
8082 return handleAppCrashLocked(app);
8083 }
8084
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008085 private ComponentName getErrorReportReceiver(ProcessRecord app) {
8086 IPackageManager pm = ActivityThread.getPackageManager();
8087 try {
8088 // was an installer package name specified when this app was
8089 // installed?
8090 String installerPackageName = pm.getInstallerPackageName(app.info.packageName);
8091 if (installerPackageName == null) {
8092 return null;
8093 }
8094
8095 // is there an Activity in this package that handles ACTION_APP_ERROR?
8096 Intent intent = new Intent(Intent.ACTION_APP_ERROR);
Dianne Hackbornc14b9cc2009-06-17 18:02:12 -07008097 intent.setPackage(installerPackageName);
8098 ResolveInfo info = pm.resolveIntent(intent, null, 0);
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008099 if (info == null || info.activityInfo == null) {
8100 return null;
8101 }
8102
8103 return new ComponentName(installerPackageName, info.activityInfo.name);
8104 } catch (RemoteException e) {
8105 // will return null and no error report will be delivered
8106 }
8107 return null;
8108 }
8109
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008110 void makeAppNotRespondingLocked(ProcessRecord app,
8111 String tag, String shortMsg, String longMsg, byte[] crashData) {
8112 app.notResponding = true;
8113 app.notRespondingReport = generateProcessError(app,
8114 ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING, tag, shortMsg, longMsg,
8115 crashData);
8116 startAppProblemLocked(app);
8117 app.stopFreezingAllLocked();
8118 }
8119
8120 /**
8121 * Generate a process error record, suitable for attachment to a ProcessRecord.
8122 *
8123 * @param app The ProcessRecord in which the error occurred.
8124 * @param condition Crashing, Application Not Responding, etc. Values are defined in
8125 * ActivityManager.AppErrorStateInfo
8126 * @param tag The tag that was passed into handleApplicationError(). Typically the classname.
8127 * @param shortMsg Short message describing the crash.
8128 * @param longMsg Long message describing the crash.
8129 * @param crashData Raw data passed into handleApplicationError(). Typically a stack trace.
8130 *
8131 * @return Returns a fully-formed AppErrorStateInfo record.
8132 */
8133 private ActivityManager.ProcessErrorStateInfo generateProcessError(ProcessRecord app,
8134 int condition, String tag, String shortMsg, String longMsg, byte[] crashData) {
8135 ActivityManager.ProcessErrorStateInfo report = new ActivityManager.ProcessErrorStateInfo();
8136
8137 report.condition = condition;
8138 report.processName = app.processName;
8139 report.pid = app.pid;
8140 report.uid = app.info.uid;
8141 report.tag = tag;
8142 report.shortMsg = shortMsg;
8143 report.longMsg = longMsg;
8144 report.crashData = crashData;
8145
8146 return report;
8147 }
8148
8149 void killAppAtUsersRequest(ProcessRecord app, Dialog fromDialog,
8150 boolean crashed) {
8151 synchronized (this) {
8152 app.crashing = false;
8153 app.crashingReport = null;
8154 app.notResponding = false;
8155 app.notRespondingReport = null;
8156 if (app.anrDialog == fromDialog) {
8157 app.anrDialog = null;
8158 }
8159 if (app.waitDialog == fromDialog) {
8160 app.waitDialog = null;
8161 }
8162 if (app.pid > 0 && app.pid != MY_PID) {
8163 if (crashed) {
8164 handleAppCrashLocked(app);
8165 }
8166 Log.i(ActivityManagerService.TAG, "Killing process "
8167 + app.processName
8168 + " (pid=" + app.pid + ") at user's request");
8169 Process.killProcess(app.pid);
8170 }
8171
8172 }
8173 }
8174
8175 boolean handleAppCrashLocked(ProcessRecord app) {
8176 long now = SystemClock.uptimeMillis();
8177
8178 Long crashTime = mProcessCrashTimes.get(app.info.processName,
8179 app.info.uid);
8180 if (crashTime != null && now < crashTime+MIN_CRASH_INTERVAL) {
8181 // This process loses!
8182 Log.w(TAG, "Process " + app.info.processName
8183 + " has crashed too many times: killing!");
8184 EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
8185 app.info.processName, app.info.uid);
8186 killServicesLocked(app, false);
8187 for (int i=mHistory.size()-1; i>=0; i--) {
8188 HistoryRecord r = (HistoryRecord)mHistory.get(i);
8189 if (r.app == app) {
8190 if (Config.LOGD) Log.d(
8191 TAG, " Force finishing activity "
8192 + r.intent.getComponent().flattenToShortString());
8193 finishActivityLocked(r, i, Activity.RESULT_CANCELED, null, "crashed");
8194 }
8195 }
8196 if (!app.persistent) {
8197 // We don't want to start this process again until the user
8198 // explicitly does so... but for persistent process, we really
8199 // need to keep it running. If a persistent process is actually
8200 // repeatedly crashing, then badness for everyone.
8201 EventLog.writeEvent(LOG_AM_PROCESS_BAD, app.info.uid,
8202 app.info.processName);
8203 mBadProcesses.put(app.info.processName, app.info.uid, now);
8204 app.bad = true;
8205 mProcessCrashTimes.remove(app.info.processName, app.info.uid);
8206 app.removed = true;
8207 removeProcessLocked(app, false);
8208 return false;
8209 }
8210 }
8211
8212 // Bump up the crash count of any services currently running in the proc.
8213 if (app.services.size() != 0) {
8214 // Any services running in the application need to be placed
8215 // back in the pending list.
8216 Iterator it = app.services.iterator();
8217 while (it.hasNext()) {
8218 ServiceRecord sr = (ServiceRecord)it.next();
8219 sr.crashCount++;
8220 }
8221 }
8222
8223 mProcessCrashTimes.put(app.info.processName, app.info.uid, now);
8224 return true;
8225 }
8226
8227 void startAppProblemLocked(ProcessRecord app) {
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008228 app.errorReportReceiver = getErrorReportReceiver(app);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008229 skipCurrentReceiverLocked(app);
8230 }
8231
8232 void skipCurrentReceiverLocked(ProcessRecord app) {
8233 boolean reschedule = false;
8234 BroadcastRecord r = app.curReceiver;
8235 if (r != null) {
8236 // The current broadcast is waiting for this app's receiver
8237 // to be finished. Looks like that's not going to happen, so
8238 // let the broadcast continue.
8239 logBroadcastReceiverDiscard(r);
8240 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8241 r.resultExtras, r.resultAbort, true);
8242 reschedule = true;
8243 }
8244 r = mPendingBroadcast;
8245 if (r != null && r.curApp == app) {
8246 if (DEBUG_BROADCAST) Log.v(TAG,
8247 "skip & discard pending app " + r);
8248 logBroadcastReceiverDiscard(r);
8249 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
8250 r.resultExtras, r.resultAbort, true);
8251 reschedule = true;
8252 }
8253 if (reschedule) {
8254 scheduleBroadcastsLocked();
8255 }
8256 }
8257
8258 public int handleApplicationError(IBinder app, int flags,
8259 String tag, String shortMsg, String longMsg, byte[] crashData) {
8260 AppErrorResult result = new AppErrorResult();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008261 ProcessRecord r = null;
8262 synchronized (this) {
8263 if (app != null) {
8264 for (SparseArray<ProcessRecord> apps : mProcessNames.getMap().values()) {
8265 final int NA = apps.size();
8266 for (int ia=0; ia<NA; ia++) {
8267 ProcessRecord p = apps.valueAt(ia);
8268 if (p.thread != null && p.thread.asBinder() == app) {
8269 r = p;
8270 break;
8271 }
8272 }
8273 }
8274 }
8275
8276 if (r != null) {
8277 // The application has crashed. Send the SIGQUIT to the process so
8278 // that it can dump its state.
8279 Process.sendSignal(r.pid, Process.SIGNAL_QUIT);
8280 //Log.i(TAG, "Current system threads:");
8281 //Process.sendSignal(MY_PID, Process.SIGNAL_QUIT);
8282 }
8283
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008284 if (mController != null) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008285 try {
8286 String name = r != null ? r.processName : null;
8287 int pid = r != null ? r.pid : Binder.getCallingPid();
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008288 if (!mController.appCrashed(name, pid,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008289 shortMsg, longMsg, crashData)) {
8290 Log.w(TAG, "Force-killing crashed app " + name
8291 + " at watcher's request");
8292 Process.killProcess(pid);
8293 return 0;
8294 }
8295 } catch (RemoteException e) {
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008296 mController = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008297 }
8298 }
8299
8300 final long origId = Binder.clearCallingIdentity();
8301
8302 // If this process is running instrumentation, finish it.
8303 if (r != null && r.instrumentationClass != null) {
8304 Log.w(TAG, "Error in app " + r.processName
8305 + " running instrumentation " + r.instrumentationClass + ":");
8306 if (shortMsg != null) Log.w(TAG, " " + shortMsg);
8307 if (longMsg != null) Log.w(TAG, " " + longMsg);
8308 Bundle info = new Bundle();
8309 info.putString("shortMsg", shortMsg);
8310 info.putString("longMsg", longMsg);
8311 finishInstrumentationLocked(r, Activity.RESULT_CANCELED, info);
8312 Binder.restoreCallingIdentity(origId);
8313 return 0;
8314 }
8315
8316 if (r != null) {
8317 if (!makeAppCrashingLocked(r, tag, shortMsg, longMsg, crashData)) {
8318 return 0;
8319 }
8320 } else {
8321 Log.w(TAG, "Some application object " + app + " tag " + tag
8322 + " has crashed, but I don't know who it is.");
8323 Log.w(TAG, "ShortMsg:" + shortMsg);
8324 Log.w(TAG, "LongMsg:" + longMsg);
8325 Binder.restoreCallingIdentity(origId);
8326 return 0;
8327 }
8328
8329 Message msg = Message.obtain();
8330 msg.what = SHOW_ERROR_MSG;
8331 HashMap data = new HashMap();
8332 data.put("result", result);
8333 data.put("app", r);
8334 data.put("flags", flags);
8335 data.put("shortMsg", shortMsg);
8336 data.put("longMsg", longMsg);
8337 if (r != null && (r.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
8338 // For system processes, submit crash data to the server.
8339 data.put("crashData", crashData);
8340 }
8341 msg.obj = data;
8342 mHandler.sendMessage(msg);
8343
8344 Binder.restoreCallingIdentity(origId);
8345 }
8346
8347 int res = result.get();
8348
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008349 Intent appErrorIntent = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008350 synchronized (this) {
8351 if (r != null) {
8352 mProcessCrashTimes.put(r.info.processName, r.info.uid,
8353 SystemClock.uptimeMillis());
8354 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008355 if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) {
8356 appErrorIntent = createAppErrorIntentLocked(r);
8357 res = AppErrorDialog.FORCE_QUIT;
8358 }
8359 }
8360
8361 if (appErrorIntent != null) {
8362 try {
8363 mContext.startActivity(appErrorIntent);
8364 } catch (ActivityNotFoundException e) {
8365 Log.w(TAG, "bug report receiver dissappeared", e);
8366 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008367 }
8368
8369 return res;
8370 }
8371
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008372 Intent createAppErrorIntentLocked(ProcessRecord r) {
8373 ApplicationErrorReport report = createAppErrorReportLocked(r);
8374 if (report == null) {
8375 return null;
8376 }
8377 Intent result = new Intent(Intent.ACTION_APP_ERROR);
8378 result.setComponent(r.errorReportReceiver);
8379 result.putExtra(Intent.EXTRA_BUG_REPORT, report);
8380 result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
8381 return result;
8382 }
8383
8384 ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) {
8385 if (r.errorReportReceiver == null) {
8386 return null;
8387 }
8388
8389 if (!r.crashing && !r.notResponding) {
8390 return null;
8391 }
8392
8393 try {
8394 ApplicationErrorReport report = new ApplicationErrorReport();
8395 report.packageName = r.info.packageName;
8396 report.installerPackageName = r.errorReportReceiver.getPackageName();
8397 report.processName = r.processName;
8398
8399 if (r.crashing) {
8400 report.type = ApplicationErrorReport.TYPE_CRASH;
8401 report.crashInfo = new ApplicationErrorReport.CrashInfo();
8402
8403 ByteArrayInputStream byteStream = new ByteArrayInputStream(
8404 r.crashingReport.crashData);
8405 DataInputStream dataStream = new DataInputStream(byteStream);
8406 CrashData crashData = new CrashData(dataStream);
8407 ThrowableData throwData = crashData.getThrowableData();
8408
8409 report.time = crashData.getTime();
8410 report.crashInfo.stackTrace = throwData.toString();
8411
Jacek Surazskif829a782009-06-11 22:47:02 +02008412 // Extract the source of the exception, useful for report
8413 // clustering. Also extract the "deepest" non-null exception
8414 // message.
8415 String exceptionMessage = throwData.getMessage();
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008416 while (throwData.getCause() != null) {
8417 throwData = throwData.getCause();
Jacek Surazskif829a782009-06-11 22:47:02 +02008418 String msg = throwData.getMessage();
8419 if (msg != null && msg.length() > 0) {
8420 exceptionMessage = msg;
8421 }
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008422 }
8423 StackTraceElementData trace = throwData.getStackTrace()[0];
Jacek Surazskif829a782009-06-11 22:47:02 +02008424 report.crashInfo.exceptionMessage = exceptionMessage;
Jacek Surazskif5b9c722009-05-18 12:09:59 +02008425 report.crashInfo.exceptionClassName = throwData.getType();
8426 report.crashInfo.throwFileName = trace.getFileName();
8427 report.crashInfo.throwClassName = trace.getClassName();
8428 report.crashInfo.throwMethodName = trace.getMethodName();
8429 } else if (r.notResponding) {
8430 report.type = ApplicationErrorReport.TYPE_ANR;
8431 report.anrInfo = new ApplicationErrorReport.AnrInfo();
8432
8433 report.anrInfo.activity = r.notRespondingReport.tag;
8434 report.anrInfo.cause = r.notRespondingReport.shortMsg;
8435 report.anrInfo.info = r.notRespondingReport.longMsg;
8436 }
8437
8438 return report;
8439 } catch (IOException e) {
8440 // we don't send it
8441 }
8442
8443 return null;
8444 }
8445
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008446 public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() {
8447 // assume our apps are happy - lazy create the list
8448 List<ActivityManager.ProcessErrorStateInfo> errList = null;
8449
8450 synchronized (this) {
8451
8452 // iterate across all processes
8453 final int N = mLRUProcesses.size();
8454 for (int i = 0; i < N; i++) {
8455 ProcessRecord app = mLRUProcesses.get(i);
8456 if ((app.thread != null) && (app.crashing || app.notResponding)) {
8457 // This one's in trouble, so we'll generate a report for it
8458 // crashes are higher priority (in case there's a crash *and* an anr)
8459 ActivityManager.ProcessErrorStateInfo report = null;
8460 if (app.crashing) {
8461 report = app.crashingReport;
8462 } else if (app.notResponding) {
8463 report = app.notRespondingReport;
8464 }
8465
8466 if (report != null) {
8467 if (errList == null) {
8468 errList = new ArrayList<ActivityManager.ProcessErrorStateInfo>(1);
8469 }
8470 errList.add(report);
8471 } else {
8472 Log.w(TAG, "Missing app error report, app = " + app.processName +
8473 " crashing = " + app.crashing +
8474 " notResponding = " + app.notResponding);
8475 }
8476 }
8477 }
8478 }
8479
8480 return errList;
8481 }
8482
8483 public List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {
8484 // Lazy instantiation of list
8485 List<ActivityManager.RunningAppProcessInfo> runList = null;
8486 synchronized (this) {
8487 // Iterate across all processes
8488 final int N = mLRUProcesses.size();
8489 for (int i = 0; i < N; i++) {
8490 ProcessRecord app = mLRUProcesses.get(i);
8491 if ((app.thread != null) && (!app.crashing && !app.notResponding)) {
8492 // Generate process state info for running application
8493 ActivityManager.RunningAppProcessInfo currApp =
8494 new ActivityManager.RunningAppProcessInfo(app.processName,
8495 app.pid, app.getPackageList());
8496 int adj = app.curAdj;
8497 if (adj >= CONTENT_PROVIDER_ADJ) {
8498 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_EMPTY;
8499 } else if (adj >= HIDDEN_APP_MIN_ADJ) {
8500 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
The Android Open Source Project4df24232009-03-05 14:34:35 -08008501 currApp.lru = adj - HIDDEN_APP_MIN_ADJ + 1;
8502 } else if (adj >= HOME_APP_ADJ) {
8503 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_BACKGROUND;
8504 currApp.lru = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008505 } else if (adj >= SECONDARY_SERVER_ADJ) {
8506 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_SERVICE;
8507 } else if (adj >= VISIBLE_APP_ADJ) {
8508 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
8509 } else {
8510 currApp.importance = ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
8511 }
8512 //Log.v(TAG, "Proc " + app.processName + ": imp=" + currApp.importance
8513 // + " lru=" + currApp.lru);
8514 if (runList == null) {
8515 runList = new ArrayList<ActivityManager.RunningAppProcessInfo>();
8516 }
8517 runList.add(currApp);
8518 }
8519 }
8520 }
8521 return runList;
8522 }
8523
8524 @Override
8525 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
8526 synchronized (this) {
8527 if (checkCallingPermission(android.Manifest.permission.DUMP)
8528 != PackageManager.PERMISSION_GRANTED) {
8529 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8530 + Binder.getCallingPid()
8531 + ", uid=" + Binder.getCallingUid()
8532 + " without permission "
8533 + android.Manifest.permission.DUMP);
8534 return;
8535 }
8536 if (args.length != 0 && "service".equals(args[0])) {
8537 dumpService(fd, pw, args);
8538 return;
8539 }
8540 pw.println("Activities in Current Activity Manager State:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008541 dumpHistoryList(pw, mHistory, " ", "Hist", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008542 pw.println(" ");
8543 pw.println(" Running activities (most recent first):");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008544 dumpHistoryList(pw, mLRUActivities, " ", "Run", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008545 if (mWaitingVisibleActivities.size() > 0) {
8546 pw.println(" ");
8547 pw.println(" Activities waiting for another to become visible:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008548 dumpHistoryList(pw, mWaitingVisibleActivities, " ", "Wait", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008549 }
8550 if (mStoppingActivities.size() > 0) {
8551 pw.println(" ");
8552 pw.println(" Activities waiting to stop:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008553 dumpHistoryList(pw, mStoppingActivities, " ", "Stop", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008554 }
8555 if (mFinishingActivities.size() > 0) {
8556 pw.println(" ");
8557 pw.println(" Activities waiting to finish:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008558 dumpHistoryList(pw, mFinishingActivities, " ", "Fin", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008559 }
8560
8561 pw.println(" ");
8562 pw.println(" mPausingActivity: " + mPausingActivity);
8563 pw.println(" mResumedActivity: " + mResumedActivity);
8564 pw.println(" mFocusedActivity: " + mFocusedActivity);
8565 pw.println(" mLastPausedActivity: " + mLastPausedActivity);
8566
8567 if (mRecentTasks.size() > 0) {
8568 pw.println(" ");
8569 pw.println("Recent tasks in Current Activity Manager State:");
8570
8571 final int N = mRecentTasks.size();
8572 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008573 TaskRecord tr = mRecentTasks.get(i);
8574 pw.print(" * Recent #"); pw.print(i); pw.print(": ");
8575 pw.println(tr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008576 mRecentTasks.get(i).dump(pw, " ");
8577 }
8578 }
8579
8580 pw.println(" ");
8581 pw.println(" mCurTask: " + mCurTask);
8582
8583 pw.println(" ");
8584 pw.println("Processes in Current Activity Manager State:");
8585
8586 boolean needSep = false;
8587 int numPers = 0;
8588
8589 for (SparseArray<ProcessRecord> procs : mProcessNames.getMap().values()) {
8590 final int NA = procs.size();
8591 for (int ia=0; ia<NA; ia++) {
8592 if (!needSep) {
8593 pw.println(" All known processes:");
8594 needSep = true;
8595 }
8596 ProcessRecord r = procs.valueAt(ia);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008597 pw.print(r.persistent ? " *PERS*" : " *APP*");
8598 pw.print(" UID "); pw.print(procs.keyAt(ia));
8599 pw.print(" "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008600 r.dump(pw, " ");
8601 if (r.persistent) {
8602 numPers++;
8603 }
8604 }
8605 }
8606
8607 if (mLRUProcesses.size() > 0) {
8608 if (needSep) pw.println(" ");
8609 needSep = true;
8610 pw.println(" Running processes (most recent first):");
8611 dumpProcessList(pw, mLRUProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008612 "App ", "PERS", true);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008613 needSep = true;
8614 }
8615
8616 synchronized (mPidsSelfLocked) {
8617 if (mPidsSelfLocked.size() > 0) {
8618 if (needSep) pw.println(" ");
8619 needSep = true;
8620 pw.println(" PID mappings:");
8621 for (int i=0; i<mPidsSelfLocked.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008622 pw.print(" PID #"); pw.print(mPidsSelfLocked.keyAt(i));
8623 pw.print(": "); pw.println(mPidsSelfLocked.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008624 }
8625 }
8626 }
8627
8628 if (mForegroundProcesses.size() > 0) {
8629 if (needSep) pw.println(" ");
8630 needSep = true;
8631 pw.println(" Foreground Processes:");
8632 for (int i=0; i<mForegroundProcesses.size(); i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008633 pw.print(" PID #"); pw.print(mForegroundProcesses.keyAt(i));
8634 pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008635 }
8636 }
8637
8638 if (mPersistentStartingProcesses.size() > 0) {
8639 if (needSep) pw.println(" ");
8640 needSep = true;
8641 pw.println(" Persisent processes that are starting:");
8642 dumpProcessList(pw, mPersistentStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008643 "Starting Norm", "Restarting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008644 }
8645
8646 if (mStartingProcesses.size() > 0) {
8647 if (needSep) pw.println(" ");
8648 needSep = true;
8649 pw.println(" Processes that are starting:");
8650 dumpProcessList(pw, mStartingProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008651 "Starting Norm", "Starting PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008652 }
8653
8654 if (mRemovedProcesses.size() > 0) {
8655 if (needSep) pw.println(" ");
8656 needSep = true;
8657 pw.println(" Processes that are being removed:");
8658 dumpProcessList(pw, mRemovedProcesses, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008659 "Removed Norm", "Removed PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008660 }
8661
8662 if (mProcessesOnHold.size() > 0) {
8663 if (needSep) pw.println(" ");
8664 needSep = true;
8665 pw.println(" Processes that are on old until the system is ready:");
8666 dumpProcessList(pw, mProcessesOnHold, " ",
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008667 "OnHold Norm", "OnHold PERS", false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008668 }
8669
8670 if (mProcessCrashTimes.getMap().size() > 0) {
8671 if (needSep) pw.println(" ");
8672 needSep = true;
8673 pw.println(" Time since processes crashed:");
8674 long now = SystemClock.uptimeMillis();
8675 for (Map.Entry<String, SparseArray<Long>> procs
8676 : mProcessCrashTimes.getMap().entrySet()) {
8677 SparseArray<Long> uids = procs.getValue();
8678 final int N = uids.size();
8679 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008680 pw.print(" Process "); pw.print(procs.getKey());
8681 pw.print(" uid "); pw.print(uids.keyAt(i));
8682 pw.print(": last crashed ");
8683 pw.print((now-uids.valueAt(i)));
8684 pw.println(" ms ago");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008685 }
8686 }
8687 }
8688
8689 if (mBadProcesses.getMap().size() > 0) {
8690 if (needSep) pw.println(" ");
8691 needSep = true;
8692 pw.println(" Bad processes:");
8693 for (Map.Entry<String, SparseArray<Long>> procs
8694 : mBadProcesses.getMap().entrySet()) {
8695 SparseArray<Long> uids = procs.getValue();
8696 final int N = uids.size();
8697 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008698 pw.print(" Bad process "); pw.print(procs.getKey());
8699 pw.print(" uid "); pw.print(uids.keyAt(i));
8700 pw.print(": crashed at time ");
8701 pw.println(uids.valueAt(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008702 }
8703 }
8704 }
8705
8706 pw.println(" ");
8707 pw.println(" Total persistent processes: " + numPers);
The Android Open Source Project4df24232009-03-05 14:34:35 -08008708 pw.println(" mHomeProcess: " + mHomeProcess);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008709 pw.println(" mConfiguration: " + mConfiguration);
8710 pw.println(" mStartRunning=" + mStartRunning
8711 + " mSystemReady=" + mSystemReady
8712 + " mBooting=" + mBooting
8713 + " mBooted=" + mBooted
8714 + " mFactoryTest=" + mFactoryTest);
Dianne Hackborn55280a92009-05-07 15:53:46 -07008715 pw.println(" mSleeping=" + mSleeping + " mShuttingDown=" + mShuttingDown);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008716 pw.println(" mGoingToSleep=" + mGoingToSleep);
8717 pw.println(" mLaunchingActivity=" + mLaunchingActivity);
8718 pw.println(" mDebugApp=" + mDebugApp + "/orig=" + mOrigDebugApp
8719 + " mDebugTransient=" + mDebugTransient
8720 + " mOrigWaitForDebugger=" + mOrigWaitForDebugger);
8721 pw.println(" mAlwaysFinishActivities=" + mAlwaysFinishActivities
Dianne Hackbornb06ea702009-07-13 13:07:51 -07008722 + " mController=" + mController);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008723 }
8724 }
8725
8726 /**
8727 * There are three ways to call this:
8728 * - no service specified: dump all the services
8729 * - a flattened component name that matched an existing service was specified as the
8730 * first arg: dump that one service
8731 * - the first arg isn't the flattened component name of an existing service:
8732 * dump all services whose component contains the first arg as a substring
8733 */
8734 protected void dumpService(FileDescriptor fd, PrintWriter pw, String[] args) {
8735 String[] newArgs;
8736 String componentNameString;
8737 ServiceRecord r;
8738 if (args.length == 1) {
8739 componentNameString = null;
8740 newArgs = EMPTY_STRING_ARRAY;
8741 r = null;
8742 } else {
8743 componentNameString = args[1];
8744 ComponentName componentName = ComponentName.unflattenFromString(componentNameString);
8745 r = componentName != null ? mServices.get(componentName) : null;
8746 newArgs = new String[args.length - 2];
8747 if (args.length > 2) System.arraycopy(args, 2, newArgs, 0, args.length - 2);
8748 }
8749
8750 if (r != null) {
8751 dumpService(fd, pw, r, newArgs);
8752 } else {
8753 for (ServiceRecord r1 : mServices.values()) {
8754 if (componentNameString == null
8755 || r1.name.flattenToString().contains(componentNameString)) {
8756 dumpService(fd, pw, r1, newArgs);
8757 }
8758 }
8759 }
8760 }
8761
8762 /**
8763 * Invokes IApplicationThread.dumpService() on the thread of the specified service if
8764 * there is a thread associated with the service.
8765 */
8766 private void dumpService(FileDescriptor fd, PrintWriter pw, ServiceRecord r, String[] args) {
8767 pw.println(" Service " + r.name.flattenToString());
8768 if (r.app != null && r.app.thread != null) {
8769 try {
8770 // flush anything that is already in the PrintWriter since the thread is going
8771 // to write to the file descriptor directly
8772 pw.flush();
8773 r.app.thread.dumpService(fd, r, args);
8774 pw.print("\n");
8775 } catch (RemoteException e) {
8776 pw.println("got a RemoteException while dumping the service");
8777 }
8778 }
8779 }
8780
8781 void dumpBroadcasts(PrintWriter pw) {
8782 synchronized (this) {
8783 if (checkCallingPermission(android.Manifest.permission.DUMP)
8784 != PackageManager.PERMISSION_GRANTED) {
8785 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8786 + Binder.getCallingPid()
8787 + ", uid=" + Binder.getCallingUid()
8788 + " without permission "
8789 + android.Manifest.permission.DUMP);
8790 return;
8791 }
8792 pw.println("Broadcasts in Current Activity Manager State:");
8793
8794 if (mRegisteredReceivers.size() > 0) {
8795 pw.println(" ");
8796 pw.println(" Registered Receivers:");
8797 Iterator it = mRegisteredReceivers.values().iterator();
8798 while (it.hasNext()) {
8799 ReceiverList r = (ReceiverList)it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008800 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008801 r.dump(pw, " ");
8802 }
8803 }
8804
8805 pw.println(" ");
8806 pw.println("Receiver Resolver Table:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008807 mReceiverResolver.dump(pw, " ");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008808
8809 if (mParallelBroadcasts.size() > 0 || mOrderedBroadcasts.size() > 0
8810 || mPendingBroadcast != null) {
8811 if (mParallelBroadcasts.size() > 0) {
8812 pw.println(" ");
8813 pw.println(" Active broadcasts:");
8814 }
8815 for (int i=mParallelBroadcasts.size()-1; i>=0; i--) {
8816 pw.println(" Broadcast #" + i + ":");
8817 mParallelBroadcasts.get(i).dump(pw, " ");
8818 }
8819 if (mOrderedBroadcasts.size() > 0) {
8820 pw.println(" ");
8821 pw.println(" Active serialized broadcasts:");
8822 }
8823 for (int i=mOrderedBroadcasts.size()-1; i>=0; i--) {
8824 pw.println(" Serialized Broadcast #" + i + ":");
8825 mOrderedBroadcasts.get(i).dump(pw, " ");
8826 }
8827 pw.println(" ");
8828 pw.println(" Pending broadcast:");
8829 if (mPendingBroadcast != null) {
8830 mPendingBroadcast.dump(pw, " ");
8831 } else {
8832 pw.println(" (null)");
8833 }
8834 }
8835
8836 pw.println(" ");
8837 pw.println(" mBroadcastsScheduled=" + mBroadcastsScheduled);
8838 if (mStickyBroadcasts != null) {
8839 pw.println(" ");
8840 pw.println(" Sticky broadcasts:");
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008841 StringBuilder sb = new StringBuilder(128);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008842 for (Map.Entry<String, ArrayList<Intent>> ent
8843 : mStickyBroadcasts.entrySet()) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008844 pw.print(" * Sticky action "); pw.print(ent.getKey());
8845 pw.println(":");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008846 ArrayList<Intent> intents = ent.getValue();
8847 final int N = intents.size();
8848 for (int i=0; i<N; i++) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008849 sb.setLength(0);
8850 sb.append(" Intent: ");
8851 intents.get(i).toShortString(sb, true, false);
8852 pw.println(sb.toString());
8853 Bundle bundle = intents.get(i).getExtras();
8854 if (bundle != null) {
8855 pw.print(" ");
8856 pw.println(bundle.toString());
8857 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008858 }
8859 }
8860 }
8861
8862 pw.println(" ");
8863 pw.println(" mHandler:");
8864 mHandler.dump(new PrintWriterPrinter(pw), " ");
8865 }
8866 }
8867
8868 void dumpServices(PrintWriter pw) {
8869 synchronized (this) {
8870 if (checkCallingPermission(android.Manifest.permission.DUMP)
8871 != PackageManager.PERMISSION_GRANTED) {
8872 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8873 + Binder.getCallingPid()
8874 + ", uid=" + Binder.getCallingUid()
8875 + " without permission "
8876 + android.Manifest.permission.DUMP);
8877 return;
8878 }
8879 pw.println("Services in Current Activity Manager State:");
8880
8881 boolean needSep = false;
8882
8883 if (mServices.size() > 0) {
8884 pw.println(" Active services:");
8885 Iterator<ServiceRecord> it = mServices.values().iterator();
8886 while (it.hasNext()) {
8887 ServiceRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008888 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008889 r.dump(pw, " ");
8890 }
8891 needSep = true;
8892 }
8893
8894 if (mPendingServices.size() > 0) {
8895 if (needSep) pw.println(" ");
8896 pw.println(" Pending services:");
8897 for (int i=0; i<mPendingServices.size(); i++) {
8898 ServiceRecord r = mPendingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008899 pw.print(" * Pending "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008900 r.dump(pw, " ");
8901 }
8902 needSep = true;
8903 }
8904
8905 if (mRestartingServices.size() > 0) {
8906 if (needSep) pw.println(" ");
8907 pw.println(" Restarting services:");
8908 for (int i=0; i<mRestartingServices.size(); i++) {
8909 ServiceRecord r = mRestartingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008910 pw.print(" * Restarting "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008911 r.dump(pw, " ");
8912 }
8913 needSep = true;
8914 }
8915
8916 if (mStoppingServices.size() > 0) {
8917 if (needSep) pw.println(" ");
8918 pw.println(" Stopping services:");
8919 for (int i=0; i<mStoppingServices.size(); i++) {
8920 ServiceRecord r = mStoppingServices.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008921 pw.print(" * Stopping "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008922 r.dump(pw, " ");
8923 }
8924 needSep = true;
8925 }
8926
8927 if (mServiceConnections.size() > 0) {
8928 if (needSep) pw.println(" ");
8929 pw.println(" Connection bindings to services:");
8930 Iterator<ConnectionRecord> it
8931 = mServiceConnections.values().iterator();
8932 while (it.hasNext()) {
8933 ConnectionRecord r = it.next();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008934 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008935 r.dump(pw, " ");
8936 }
8937 }
8938 }
8939 }
8940
8941 void dumpProviders(PrintWriter pw) {
8942 synchronized (this) {
8943 if (checkCallingPermission(android.Manifest.permission.DUMP)
8944 != PackageManager.PERMISSION_GRANTED) {
8945 pw.println("Permission Denial: can't dump ActivityManager from from pid="
8946 + Binder.getCallingPid()
8947 + ", uid=" + Binder.getCallingUid()
8948 + " without permission "
8949 + android.Manifest.permission.DUMP);
8950 return;
8951 }
8952
8953 pw.println("Content Providers in Current Activity Manager State:");
8954
8955 boolean needSep = false;
8956
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008957 if (mProvidersByClass.size() > 0) {
8958 if (needSep) pw.println(" ");
8959 pw.println(" Published content providers (by class):");
8960 Iterator it = mProvidersByClass.entrySet().iterator();
8961 while (it.hasNext()) {
8962 Map.Entry e = (Map.Entry)it.next();
8963 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008964 pw.print(" * "); pw.println(r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008965 r.dump(pw, " ");
8966 }
8967 needSep = true;
8968 }
8969
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008970 if (mProvidersByName.size() > 0) {
8971 pw.println(" ");
8972 pw.println(" Authority to provider mappings:");
8973 Iterator it = mProvidersByName.entrySet().iterator();
8974 while (it.hasNext()) {
8975 Map.Entry e = (Map.Entry)it.next();
8976 ContentProviderRecord r = (ContentProviderRecord)e.getValue();
8977 pw.print(" "); pw.print(e.getKey()); pw.print(": ");
8978 pw.println(r);
8979 }
8980 needSep = true;
8981 }
8982
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008983 if (mLaunchingProviders.size() > 0) {
8984 if (needSep) pw.println(" ");
8985 pw.println(" Launching content providers:");
8986 for (int i=mLaunchingProviders.size()-1; i>=0; i--) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008987 pw.print(" Launching #"); pw.print(i); pw.print(": ");
8988 pw.println(mLaunchingProviders.get(i));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008989 }
8990 needSep = true;
8991 }
8992
Dianne Hackborn1d442e02009-04-20 18:14:05 -07008993 if (mGrantedUriPermissions.size() > 0) {
8994 pw.println();
8995 pw.println("Granted Uri Permissions:");
8996 for (int i=0; i<mGrantedUriPermissions.size(); i++) {
8997 int uid = mGrantedUriPermissions.keyAt(i);
8998 HashMap<Uri, UriPermission> perms
8999 = mGrantedUriPermissions.valueAt(i);
9000 pw.print(" * UID "); pw.print(uid);
9001 pw.println(" holds:");
9002 for (UriPermission perm : perms.values()) {
9003 pw.print(" "); pw.println(perm);
9004 perm.dump(pw, " ");
9005 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009006 }
9007 }
9008 }
9009 }
9010
9011 void dumpSenders(PrintWriter pw) {
9012 synchronized (this) {
9013 if (checkCallingPermission(android.Manifest.permission.DUMP)
9014 != PackageManager.PERMISSION_GRANTED) {
9015 pw.println("Permission Denial: can't dump ActivityManager from from pid="
9016 + Binder.getCallingPid()
9017 + ", uid=" + Binder.getCallingUid()
9018 + " without permission "
9019 + android.Manifest.permission.DUMP);
9020 return;
9021 }
9022
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009023 pw.println("Pending Intents in Current Activity Manager State:");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009024
9025 if (this.mIntentSenderRecords.size() > 0) {
9026 Iterator<WeakReference<PendingIntentRecord>> it
9027 = mIntentSenderRecords.values().iterator();
9028 while (it.hasNext()) {
9029 WeakReference<PendingIntentRecord> ref = it.next();
9030 PendingIntentRecord rec = ref != null ? ref.get(): null;
9031 if (rec != null) {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009032 pw.print(" * "); pw.println(rec);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009033 rec.dump(pw, " ");
9034 } else {
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009035 pw.print(" * "); pw.print(ref);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009036 }
9037 }
9038 }
9039 }
9040 }
9041
9042 private static final void dumpHistoryList(PrintWriter pw, List list,
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009043 String prefix, String label, boolean complete) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009044 TaskRecord lastTask = null;
9045 for (int i=list.size()-1; i>=0; i--) {
9046 HistoryRecord r = (HistoryRecord)list.get(i);
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009047 final boolean full = complete || !r.inHistory;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009048 if (lastTask != r.task) {
9049 lastTask = r.task;
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009050 pw.print(prefix);
9051 pw.print(full ? "* " : " ");
9052 pw.println(lastTask);
9053 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009054 lastTask.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009055 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009056 }
Dianne Hackborn1d442e02009-04-20 18:14:05 -07009057 pw.print(prefix); pw.print(full ? " * " : " "); pw.print(label);
9058 pw.print(" #"); pw.print(i); pw.print(": ");
9059 pw.println(r);
9060 if (full) {
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009061 r.dump(pw, prefix + " ");
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009062 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009063 }
9064 }
9065
9066 private static final int dumpProcessList(PrintWriter pw, List list,
9067 String prefix, String normalLabel, String persistentLabel,
9068 boolean inclOomAdj) {
9069 int numPers = 0;
9070 for (int i=list.size()-1; i>=0; i--) {
9071 ProcessRecord r = (ProcessRecord)list.get(i);
9072 if (false) {
9073 pw.println(prefix + (r.persistent ? persistentLabel : normalLabel)
9074 + " #" + i + ":");
9075 r.dump(pw, prefix + " ");
9076 } else if (inclOomAdj) {
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07009077 pw.println(String.format("%s%s #%2d: adj=%3d/%d %s",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009078 prefix, (r.persistent ? persistentLabel : normalLabel),
Dianne Hackborn06de2ea2009-05-21 12:56:43 -07009079 i, r.setAdj, r.setSchedGroup, r.toString()));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009080 } else {
9081 pw.println(String.format("%s%s #%2d: %s",
9082 prefix, (r.persistent ? persistentLabel : normalLabel),
9083 i, r.toString()));
9084 }
9085 if (r.persistent) {
9086 numPers++;
9087 }
9088 }
9089 return numPers;
9090 }
9091
9092 private static final void dumpApplicationMemoryUsage(FileDescriptor fd,
9093 PrintWriter pw, List list, String prefix, String[] args) {
Dianne Hackborn6447ca32009-04-07 19:50:08 -07009094 final boolean isCheckinRequest = scanArgs(args, "--checkin");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009095 long uptime = SystemClock.uptimeMillis();
9096 long realtime = SystemClock.elapsedRealtime();
9097
9098 if (isCheckinRequest) {
9099 // short checkin version
9100 pw.println(uptime + "," + realtime);
9101 pw.flush();
9102 } else {
9103 pw.println("Applications Memory Usage (kB):");
9104 pw.println("Uptime: " + uptime + " Realtime: " + realtime);
9105 }
9106 for (int i = list.size() - 1 ; i >= 0 ; i--) {
9107 ProcessRecord r = (ProcessRecord)list.get(i);
9108 if (r.thread != null) {
9109 if (!isCheckinRequest) {
9110 pw.println("\n** MEMINFO in pid " + r.pid + " [" + r.processName + "] **");
9111 pw.flush();
9112 }
9113 try {
9114 r.thread.asBinder().dump(fd, args);
9115 } catch (RemoteException e) {
9116 if (!isCheckinRequest) {
9117 pw.println("Got RemoteException!");
9118 pw.flush();
9119 }
9120 }
9121 }
9122 }
9123 }
9124
9125 /**
9126 * Searches array of arguments for the specified string
9127 * @param args array of argument strings
9128 * @param value value to search for
9129 * @return true if the value is contained in the array
9130 */
9131 private static boolean scanArgs(String[] args, String value) {
9132 if (args != null) {
9133 for (String arg : args) {
9134 if (value.equals(arg)) {
9135 return true;
9136 }
9137 }
9138 }
9139 return false;
9140 }
9141
Dianne Hackborn75b03852009-06-12 15:43:26 -07009142 private final int indexOfTokenLocked(IBinder token) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009143 int count = mHistory.size();
9144
9145 // convert the token to an entry in the history.
9146 HistoryRecord r = null;
9147 int index = -1;
9148 for (int i=count-1; i>=0; i--) {
9149 Object o = mHistory.get(i);
9150 if (o == token) {
9151 r = (HistoryRecord)o;
9152 index = i;
9153 break;
9154 }
9155 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009156
9157 return index;
9158 }
9159
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009160 private final void killServicesLocked(ProcessRecord app,
9161 boolean allowRestart) {
9162 // Report disconnected services.
9163 if (false) {
9164 // XXX we are letting the client link to the service for
9165 // death notifications.
9166 if (app.services.size() > 0) {
9167 Iterator it = app.services.iterator();
9168 while (it.hasNext()) {
9169 ServiceRecord r = (ServiceRecord)it.next();
9170 if (r.connections.size() > 0) {
9171 Iterator<ConnectionRecord> jt
9172 = r.connections.values().iterator();
9173 while (jt.hasNext()) {
9174 ConnectionRecord c = jt.next();
9175 if (c.binding.client != app) {
9176 try {
9177 //c.conn.connected(r.className, null);
9178 } catch (Exception e) {
9179 // todo: this should be asynchronous!
9180 Log.w(TAG, "Exception thrown disconnected servce "
9181 + r.shortName
9182 + " from app " + app.processName, e);
9183 }
9184 }
9185 }
9186 }
9187 }
9188 }
9189 }
9190
9191 // Clean up any connections this application has to other services.
9192 if (app.connections.size() > 0) {
9193 Iterator<ConnectionRecord> it = app.connections.iterator();
9194 while (it.hasNext()) {
9195 ConnectionRecord r = it.next();
9196 removeConnectionLocked(r, app, null);
9197 }
9198 }
9199 app.connections.clear();
9200
9201 if (app.services.size() != 0) {
9202 // Any services running in the application need to be placed
9203 // back in the pending list.
9204 Iterator it = app.services.iterator();
9205 while (it.hasNext()) {
9206 ServiceRecord sr = (ServiceRecord)it.next();
9207 synchronized (sr.stats.getBatteryStats()) {
9208 sr.stats.stopLaunchedLocked();
9209 }
9210 sr.app = null;
9211 sr.executeNesting = 0;
9212 mStoppingServices.remove(sr);
9213 if (sr.bindings.size() > 0) {
9214 Iterator<IntentBindRecord> bindings
9215 = sr.bindings.values().iterator();
9216 while (bindings.hasNext()) {
9217 IntentBindRecord b = bindings.next();
9218 if (DEBUG_SERVICE) Log.v(TAG, "Killing binding " + b
9219 + ": shouldUnbind=" + b.hasBound);
9220 b.binder = null;
9221 b.requested = b.received = b.hasBound = false;
9222 }
9223 }
9224
9225 if (sr.crashCount >= 2) {
9226 Log.w(TAG, "Service crashed " + sr.crashCount
9227 + " times, stopping: " + sr);
9228 EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
9229 sr.crashCount, sr.shortName, app.pid);
9230 bringDownServiceLocked(sr, true);
9231 } else if (!allowRestart) {
9232 bringDownServiceLocked(sr, true);
9233 } else {
9234 scheduleServiceRestartLocked(sr);
9235 }
9236 }
9237
9238 if (!allowRestart) {
9239 app.services.clear();
9240 }
9241 }
9242
9243 app.executingServices.clear();
9244 }
9245
9246 private final void removeDyingProviderLocked(ProcessRecord proc,
9247 ContentProviderRecord cpr) {
9248 synchronized (cpr) {
9249 cpr.launchingApp = null;
9250 cpr.notifyAll();
9251 }
9252
9253 mProvidersByClass.remove(cpr.info.name);
9254 String names[] = cpr.info.authority.split(";");
9255 for (int j = 0; j < names.length; j++) {
9256 mProvidersByName.remove(names[j]);
9257 }
9258
9259 Iterator<ProcessRecord> cit = cpr.clients.iterator();
9260 while (cit.hasNext()) {
9261 ProcessRecord capp = cit.next();
9262 if (!capp.persistent && capp.thread != null
9263 && capp.pid != 0
9264 && capp.pid != MY_PID) {
9265 Log.i(TAG, "Killing app " + capp.processName
9266 + " (pid " + capp.pid
9267 + ") because provider " + cpr.info.name
9268 + " is in dying process " + proc.processName);
9269 Process.killProcess(capp.pid);
9270 }
9271 }
9272
9273 mLaunchingProviders.remove(cpr);
9274 }
9275
9276 /**
9277 * Main code for cleaning up a process when it has gone away. This is
9278 * called both as a result of the process dying, or directly when stopping
9279 * a process when running in single process mode.
9280 */
9281 private final void cleanUpApplicationRecordLocked(ProcessRecord app,
9282 boolean restarting, int index) {
9283 if (index >= 0) {
9284 mLRUProcesses.remove(index);
9285 }
9286
9287 // Dismiss any open dialogs.
9288 if (app.crashDialog != null) {
9289 app.crashDialog.dismiss();
9290 app.crashDialog = null;
9291 }
9292 if (app.anrDialog != null) {
9293 app.anrDialog.dismiss();
9294 app.anrDialog = null;
9295 }
9296 if (app.waitDialog != null) {
9297 app.waitDialog.dismiss();
9298 app.waitDialog = null;
9299 }
9300
9301 app.crashing = false;
9302 app.notResponding = false;
9303
9304 app.resetPackageList();
9305 app.thread = null;
9306 app.forcingToForeground = null;
9307 app.foregroundServices = false;
9308
9309 killServicesLocked(app, true);
9310
9311 boolean restart = false;
9312
9313 int NL = mLaunchingProviders.size();
9314
9315 // Remove published content providers.
9316 if (!app.pubProviders.isEmpty()) {
9317 Iterator it = app.pubProviders.values().iterator();
9318 while (it.hasNext()) {
9319 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9320 cpr.provider = null;
9321 cpr.app = null;
9322
9323 // See if someone is waiting for this provider... in which
9324 // case we don't remove it, but just let it restart.
9325 int i = 0;
9326 if (!app.bad) {
9327 for (; i<NL; i++) {
9328 if (mLaunchingProviders.get(i) == cpr) {
9329 restart = true;
9330 break;
9331 }
9332 }
9333 } else {
9334 i = NL;
9335 }
9336
9337 if (i >= NL) {
9338 removeDyingProviderLocked(app, cpr);
9339 NL = mLaunchingProviders.size();
9340 }
9341 }
9342 app.pubProviders.clear();
9343 }
9344
9345 // Look through the content providers we are waiting to have launched,
9346 // and if any run in this process then either schedule a restart of
9347 // the process or kill the client waiting for it if this process has
9348 // gone bad.
9349 for (int i=0; i<NL; i++) {
9350 ContentProviderRecord cpr = (ContentProviderRecord)
9351 mLaunchingProviders.get(i);
9352 if (cpr.launchingApp == app) {
9353 if (!app.bad) {
9354 restart = true;
9355 } else {
9356 removeDyingProviderLocked(app, cpr);
9357 NL = mLaunchingProviders.size();
9358 }
9359 }
9360 }
9361
9362 // Unregister from connected content providers.
9363 if (!app.conProviders.isEmpty()) {
9364 Iterator it = app.conProviders.iterator();
9365 while (it.hasNext()) {
9366 ContentProviderRecord cpr = (ContentProviderRecord)it.next();
9367 cpr.clients.remove(app);
9368 }
9369 app.conProviders.clear();
9370 }
9371
9372 skipCurrentReceiverLocked(app);
9373
9374 // Unregister any receivers.
9375 if (app.receivers.size() > 0) {
9376 Iterator<ReceiverList> it = app.receivers.iterator();
9377 while (it.hasNext()) {
9378 removeReceiverLocked(it.next());
9379 }
9380 app.receivers.clear();
9381 }
9382
Christopher Tate181fafa2009-05-14 11:12:14 -07009383 // If the app is undergoing backup, tell the backup manager about it
9384 if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) {
9385 if (DEBUG_BACKUP) Log.d(TAG, "App " + mBackupTarget.appInfo + " died during backup");
9386 try {
9387 IBackupManager bm = IBackupManager.Stub.asInterface(
9388 ServiceManager.getService(Context.BACKUP_SERVICE));
9389 bm.agentDisconnected(app.info.packageName);
9390 } catch (RemoteException e) {
9391 // can't happen; backup manager is local
9392 }
9393 }
9394
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009395 // If the caller is restarting this app, then leave it in its
9396 // current lists and let the caller take care of it.
9397 if (restarting) {
9398 return;
9399 }
9400
9401 if (!app.persistent) {
9402 if (DEBUG_PROCESSES) Log.v(TAG,
9403 "Removing non-persistent process during cleanup: " + app);
9404 mProcessNames.remove(app.processName, app.info.uid);
9405 } else if (!app.removed) {
9406 // This app is persistent, so we need to keep its record around.
9407 // If it is not already on the pending app list, add it there
9408 // and start a new process for it.
9409 app.thread = null;
9410 app.forcingToForeground = null;
9411 app.foregroundServices = false;
9412 if (mPersistentStartingProcesses.indexOf(app) < 0) {
9413 mPersistentStartingProcesses.add(app);
9414 restart = true;
9415 }
9416 }
9417 mProcessesOnHold.remove(app);
9418
The Android Open Source Project4df24232009-03-05 14:34:35 -08009419 if (app == mHomeProcess) {
9420 mHomeProcess = null;
9421 }
9422
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009423 if (restart) {
9424 // We have components that still need to be running in the
9425 // process, so re-launch it.
9426 mProcessNames.put(app.processName, app.info.uid, app);
9427 startProcessLocked(app, "restart", app.processName);
9428 } else if (app.pid > 0 && app.pid != MY_PID) {
9429 // Goodbye!
9430 synchronized (mPidsSelfLocked) {
9431 mPidsSelfLocked.remove(app.pid);
9432 mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
9433 }
Dianne Hackbornf210d6b2009-04-13 18:42:49 -07009434 app.setPid(0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009435 }
9436 }
9437
9438 // =========================================================
9439 // SERVICES
9440 // =========================================================
9441
9442 ActivityManager.RunningServiceInfo makeRunningServiceInfoLocked(ServiceRecord r) {
9443 ActivityManager.RunningServiceInfo info =
9444 new ActivityManager.RunningServiceInfo();
9445 info.service = r.name;
9446 if (r.app != null) {
9447 info.pid = r.app.pid;
9448 }
9449 info.process = r.processName;
9450 info.foreground = r.isForeground;
9451 info.activeSince = r.createTime;
9452 info.started = r.startRequested;
9453 info.clientCount = r.connections.size();
9454 info.crashCount = r.crashCount;
9455 info.lastActivityTime = r.lastActivity;
9456 return info;
9457 }
9458
9459 public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
9460 int flags) {
9461 synchronized (this) {
9462 ArrayList<ActivityManager.RunningServiceInfo> res
9463 = new ArrayList<ActivityManager.RunningServiceInfo>();
9464
9465 if (mServices.size() > 0) {
9466 Iterator<ServiceRecord> it = mServices.values().iterator();
9467 while (it.hasNext() && res.size() < maxNum) {
9468 res.add(makeRunningServiceInfoLocked(it.next()));
9469 }
9470 }
9471
9472 for (int i=0; i<mRestartingServices.size() && res.size() < maxNum; i++) {
9473 ServiceRecord r = mRestartingServices.get(i);
9474 ActivityManager.RunningServiceInfo info =
9475 makeRunningServiceInfoLocked(r);
9476 info.restarting = r.nextRestartTime;
9477 res.add(info);
9478 }
9479
9480 return res;
9481 }
9482 }
9483
9484 private final ServiceRecord findServiceLocked(ComponentName name,
9485 IBinder token) {
9486 ServiceRecord r = mServices.get(name);
9487 return r == token ? r : null;
9488 }
9489
9490 private final class ServiceLookupResult {
9491 final ServiceRecord record;
9492 final String permission;
9493
9494 ServiceLookupResult(ServiceRecord _record, String _permission) {
9495 record = _record;
9496 permission = _permission;
9497 }
9498 };
9499
9500 private ServiceLookupResult findServiceLocked(Intent service,
9501 String resolvedType) {
9502 ServiceRecord r = null;
9503 if (service.getComponent() != null) {
9504 r = mServices.get(service.getComponent());
9505 }
9506 if (r == null) {
9507 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9508 r = mServicesByIntent.get(filter);
9509 }
9510
9511 if (r == null) {
9512 try {
9513 ResolveInfo rInfo =
9514 ActivityThread.getPackageManager().resolveService(
9515 service, resolvedType, 0);
9516 ServiceInfo sInfo =
9517 rInfo != null ? rInfo.serviceInfo : null;
9518 if (sInfo == null) {
9519 return null;
9520 }
9521
9522 ComponentName name = new ComponentName(
9523 sInfo.applicationInfo.packageName, sInfo.name);
9524 r = mServices.get(name);
9525 } catch (RemoteException ex) {
9526 // pm is in same process, this will never happen.
9527 }
9528 }
9529 if (r != null) {
9530 int callingPid = Binder.getCallingPid();
9531 int callingUid = Binder.getCallingUid();
9532 if (checkComponentPermission(r.permission,
9533 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9534 != PackageManager.PERMISSION_GRANTED) {
9535 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9536 + " from pid=" + callingPid
9537 + ", uid=" + callingUid
9538 + " requires " + r.permission);
9539 return new ServiceLookupResult(null, r.permission);
9540 }
9541 return new ServiceLookupResult(r, null);
9542 }
9543 return null;
9544 }
9545
9546 private class ServiceRestarter implements Runnable {
9547 private ServiceRecord mService;
9548
9549 void setService(ServiceRecord service) {
9550 mService = service;
9551 }
9552
9553 public void run() {
9554 synchronized(ActivityManagerService.this) {
9555 performServiceRestartLocked(mService);
9556 }
9557 }
9558 }
9559
9560 private ServiceLookupResult retrieveServiceLocked(Intent service,
9561 String resolvedType, int callingPid, int callingUid) {
9562 ServiceRecord r = null;
9563 if (service.getComponent() != null) {
9564 r = mServices.get(service.getComponent());
9565 }
9566 Intent.FilterComparison filter = new Intent.FilterComparison(service);
9567 r = mServicesByIntent.get(filter);
9568 if (r == null) {
9569 try {
9570 ResolveInfo rInfo =
9571 ActivityThread.getPackageManager().resolveService(
Dianne Hackborn1655be42009-05-08 14:29:01 -07009572 service, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009573 ServiceInfo sInfo =
9574 rInfo != null ? rInfo.serviceInfo : null;
9575 if (sInfo == null) {
9576 Log.w(TAG, "Unable to start service " + service +
9577 ": not found");
9578 return null;
9579 }
9580
9581 ComponentName name = new ComponentName(
9582 sInfo.applicationInfo.packageName, sInfo.name);
9583 r = mServices.get(name);
9584 if (r == null) {
9585 filter = new Intent.FilterComparison(service.cloneFilter());
9586 ServiceRestarter res = new ServiceRestarter();
9587 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
9588 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
9589 synchronized (stats) {
9590 ss = stats.getServiceStatsLocked(
9591 sInfo.applicationInfo.uid, sInfo.packageName,
9592 sInfo.name);
9593 }
9594 r = new ServiceRecord(ss, name, filter, sInfo, res);
9595 res.setService(r);
9596 mServices.put(name, r);
9597 mServicesByIntent.put(filter, r);
9598
9599 // Make sure this component isn't in the pending list.
9600 int N = mPendingServices.size();
9601 for (int i=0; i<N; i++) {
9602 ServiceRecord pr = mPendingServices.get(i);
9603 if (pr.name.equals(name)) {
9604 mPendingServices.remove(i);
9605 i--;
9606 N--;
9607 }
9608 }
9609 }
9610 } catch (RemoteException ex) {
9611 // pm is in same process, this will never happen.
9612 }
9613 }
9614 if (r != null) {
9615 if (checkComponentPermission(r.permission,
9616 callingPid, callingUid, r.exported ? -1 : r.appInfo.uid)
9617 != PackageManager.PERMISSION_GRANTED) {
9618 Log.w(TAG, "Permission Denial: Accessing service " + r.name
9619 + " from pid=" + Binder.getCallingPid()
9620 + ", uid=" + Binder.getCallingUid()
9621 + " requires " + r.permission);
9622 return new ServiceLookupResult(null, r.permission);
9623 }
9624 return new ServiceLookupResult(r, null);
9625 }
9626 return null;
9627 }
9628
9629 private final void bumpServiceExecutingLocked(ServiceRecord r) {
9630 long now = SystemClock.uptimeMillis();
9631 if (r.executeNesting == 0 && r.app != null) {
9632 if (r.app.executingServices.size() == 0) {
9633 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
9634 msg.obj = r.app;
9635 mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
9636 }
9637 r.app.executingServices.add(r);
9638 }
9639 r.executeNesting++;
9640 r.executingStart = now;
9641 }
9642
9643 private final void sendServiceArgsLocked(ServiceRecord r,
9644 boolean oomAdjusted) {
9645 final int N = r.startArgs.size();
9646 if (N == 0) {
9647 return;
9648 }
9649
9650 final int BASEID = r.lastStartId - N + 1;
9651 int i = 0;
9652 while (i < N) {
9653 try {
9654 Intent args = r.startArgs.get(i);
9655 if (DEBUG_SERVICE) Log.v(TAG, "Sending arguments to service: "
9656 + r.name + " " + r.intent + " args=" + args);
9657 bumpServiceExecutingLocked(r);
9658 if (!oomAdjusted) {
9659 oomAdjusted = true;
9660 updateOomAdjLocked(r.app);
9661 }
9662 r.app.thread.scheduleServiceArgs(r, BASEID+i, args);
9663 i++;
9664 } catch (Exception e) {
9665 break;
9666 }
9667 }
9668 if (i == N) {
9669 r.startArgs.clear();
9670 } else {
9671 while (i > 0) {
9672 r.startArgs.remove(0);
9673 i--;
9674 }
9675 }
9676 }
9677
9678 private final boolean requestServiceBindingLocked(ServiceRecord r,
9679 IntentBindRecord i, boolean rebind) {
9680 if (r.app == null || r.app.thread == null) {
9681 // If service is not currently running, can't yet bind.
9682 return false;
9683 }
9684 if ((!i.requested || rebind) && i.apps.size() > 0) {
9685 try {
9686 bumpServiceExecutingLocked(r);
9687 if (DEBUG_SERVICE) Log.v(TAG, "Connecting binding " + i
9688 + ": shouldUnbind=" + i.hasBound);
9689 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind);
9690 if (!rebind) {
9691 i.requested = true;
9692 }
9693 i.hasBound = true;
9694 i.doRebind = false;
9695 } catch (RemoteException e) {
9696 return false;
9697 }
9698 }
9699 return true;
9700 }
9701
9702 private final void requestServiceBindingsLocked(ServiceRecord r) {
9703 Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
9704 while (bindings.hasNext()) {
9705 IntentBindRecord i = bindings.next();
9706 if (!requestServiceBindingLocked(r, i, false)) {
9707 break;
9708 }
9709 }
9710 }
9711
9712 private final void realStartServiceLocked(ServiceRecord r,
9713 ProcessRecord app) throws RemoteException {
9714 if (app.thread == null) {
9715 throw new RemoteException();
9716 }
9717
9718 r.app = app;
The Android Open Source Project10592532009-03-18 17:39:46 -07009719 r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009720
9721 app.services.add(r);
9722 bumpServiceExecutingLocked(r);
9723 updateLRUListLocked(app, true);
9724
9725 boolean created = false;
9726 try {
9727 if (DEBUG_SERVICE) Log.v(TAG, "Scheduling start service: "
9728 + r.name + " " + r.intent);
9729 EventLog.writeEvent(LOG_AM_CREATE_SERVICE,
9730 System.identityHashCode(r), r.shortName,
9731 r.intent.getIntent().toString(), r.app.pid);
9732 synchronized (r.stats.getBatteryStats()) {
9733 r.stats.startLaunchedLocked();
9734 }
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -07009735 ensurePackageDexOpt(r.serviceInfo.packageName);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08009736 app.thread.scheduleCreateService(r, r.serviceInfo);
9737 created = true;
9738 } finally {
9739 if (!created) {
9740 app.services.remove(r);
9741 scheduleServiceRestartLocked(r);
9742 }
9743 }
9744
9745 requestServiceBindingsLocked(r);
9746 sendServiceArgsLocked(r, true);
9747 }
9748
9749 private final void scheduleServiceRestartLocked(ServiceRecord r) {
9750 r.totalRestartCount++;
9751 if (r.restartDelay == 0) {
9752 r.restartCount++;
9753 r.restartDelay = SERVICE_RESTART_DURATION;
9754 } else {
9755 // If it has been a "reasonably long time" since the service
9756 // was started, then reset our restart duration back to
9757 // the beginning, so we don't infinitely increase the duration
9758 // on a service that just occasionally gets killed (which is
9759 // a normal case, due to process being killed to reclaim memory).
9760 long now = SystemClock.uptimeMillis();
9761 if (now > (r.restartTime+(SERVICE_RESTART_DURATION*2*2*2))) {
9762 r.restartCount = 1;
9763 r.restartDelay = SERVICE_RESTART_DURATION;
9764 } else {
9765 r.restartDelay *= 2;
9766 }
9767 }
9768 if (!mRestartingServices.contains(r)) {
9769 mRestartingServices.add(r);
9770 }
9771 mHandler.removeCallbacks(r.restarter);
9772 mHandler.postDelayed(r.restarter, r.restartDelay);
9773 r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
9774 Log.w(TAG, "Scheduling restart of crashed service "
9775 + r.shortName + " in " + r.restartDelay + "ms");
9776 EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
9777 r.shortName, r.restartDelay);
9778
9779 Message msg = Message.obtain();
9780 msg.what = SERVICE_ERROR_MSG;
9781 msg.obj = r;
9782 mHandler.sendMessage(msg);
9783 }
9784
9785 final void performServiceRestartLocked(ServiceRecord r) {
9786 if (!mRestartingServices.contains(r)) {
9787 return;
9788 }
9789 bringUpServiceLocked(r, r.intent.getIntent().getFlags(), true);
9790 }
9791
9792 private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
9793 if (r.restartDelay == 0) {
9794 return false;
9795 }
9796 r.resetRestartCounter();
9797 mRestartingServices.remove(r);
9798 mHandler.removeCallbacks(r.restarter);
9799 return true;
9800 }
9801
9802 private final boolean bringUpServiceLocked(ServiceRecord r,
9803 int intentFlags, boolean whileRestarting) {
9804 //Log.i(TAG, "Bring up service:");
9805 //r.dump(" ");
9806
9807 if (r.app != null) {
9808 sendServiceArgsLocked(r, false);
9809 return true;
9810 }
9811
9812 if (!whileRestarting && r.restartDelay > 0) {
9813 // If waiting for a restart, then do nothing.
9814 return true;
9815 }
9816
9817 if (DEBUG_SERVICE) Log.v(TAG, "Bringing up service " + r.name
9818 + " " + r.intent);
9819
9820 final String appName = r.processName;
9821 ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);
9822 if (app != null && app.thread != null) {
9823 try {
9824 realStartServiceLocked(r, app);
9825 return true;
9826 } catch (RemoteException e) {
9827 Log.w(TAG, "Exception when starting service " + r.shortName, e);
9828 }
9829
9830 // If a dead object exception was thrown -- fall through to
9831 // restart the application.
9832 }
9833
9834 if (!mPendingServices.contains(r)) {
9835 // Not running -- get it started, and enqueue this service record
9836 // to be executed when the app comes up.
9837 if (startProcessLocked(appName, r.appInfo, true, intentFlags,
9838 "service", r.name) == null) {
9839 Log.w(TAG, "Unable to launch app "
9840 + r.appInfo.packageName + "/"
9841 + r.appInfo.uid + " for service "
9842 + r.intent.getIntent() + ": process is bad");
9843 bringDownServiceLocked(r, true);
9844 return false;
9845 }
9846 mPendingServices.add(r);
9847 }
9848 return true;
9849 }
9850
9851 private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
9852 //Log.i(TAG, "Bring down service:");
9853 //r.dump(" ");
9854
9855 // Does it still need to run?
9856 if (!force && r.startRequested) {
9857 return;
9858 }
9859 if (r.connections.size() > 0) {
9860 if (!force) {
9861 // XXX should probably keep a count of the number of auto-create
9862 // connections directly in the service.
9863 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9864 while (it.hasNext()) {
9865 ConnectionRecord cr = it.next();
9866 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
9867 return;
9868 }
9869 }
9870 }
9871
9872 // Report to all of the connections that the service is no longer
9873 // available.
9874 Iterator<ConnectionRecord> it = r.connections.values().iterator();
9875 while (it.hasNext()) {
9876 ConnectionRecord c = it.next();
9877 try {
9878 // todo: shouldn't be a synchronous call!
9879 c.conn.connected(r.name, null);
9880 } catch (Exception e) {
9881 Log.w(TAG, "Failure disconnecting service " + r.name +
9882 " to connection " + c.conn.asBinder() +
9883 " (in " + c.binding.client.processName + ")", e);
9884 }
9885 }
9886 }
9887
9888 // Tell the service that it has been unbound.
9889 if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
9890 Iterator<IntentBindRecord> it = r.bindings.values().iterator();
9891 while (it.hasNext()) {
9892 IntentBindRecord ibr = it.next();
9893 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down binding " + ibr
9894 + ": hasBound=" + ibr.hasBound);
9895 if (r.app != null && r.app.thread != null && ibr.hasBound) {
9896 try {
9897 bumpServiceExecutingLocked(r);
9898 updateOomAdjLocked(r.app);
9899 ibr.hasBound = false;
9900 r.app.thread.scheduleUnbindService(r,
9901 ibr.intent.getIntent());
9902 } catch (Exception e) {
9903 Log.w(TAG, "Exception when unbinding service "
9904 + r.shortName, e);
9905 serviceDoneExecutingLocked(r, true);
9906 }
9907 }
9908 }
9909 }
9910
9911 if (DEBUG_SERVICE) Log.v(TAG, "Bringing down service " + r.name
9912 + " " + r.intent);
9913 EventLog.writeEvent(LOG_AM_DESTROY_SERVICE,
9914 System.identityHashCode(r), r.shortName,
9915 (r.app != null) ? r.app.pid : -1);
9916
9917 mServices.remove(r.name);
9918 mServicesByIntent.remove(r.intent);
9919 if (localLOGV) Log.v(TAG, "BRING DOWN SERVICE: " + r.shortName);
9920 r.totalRestartCount = 0;
9921 unscheduleServiceRestartLocked(r);
9922
9923 // Also make sure it is not on the pending list.
9924 int N = mPendingServices.size();
9925 for (int i=0; i<N; i++) {
9926 if (mPendingServices.get(i) == r) {
9927 mPendingServices.remove(i);
9928 if (DEBUG_SERVICE) Log.v(
9929 TAG, "Removed pending service: " + r.shortName);
9930 i--;
9931 N--;
9932 }
9933 }
9934
9935 if (r.app != null) {
9936 synchronized (r.stats.getBatteryStats()) {
9937 r.stats.stopLaunchedLocked();
9938 }
9939 r.app.services.remove(r);
9940 if (r.app.thread != null) {
9941 updateServiceForegroundLocked(r.app, false);
9942 try {
9943 Log.i(TAG, "Stopping service: " + r.shortName);
9944 bumpServiceExecutingLocked(r);
9945 mStoppingServices.add(r);
9946 updateOomAdjLocked(r.app);
9947 r.app.thread.scheduleStopService(r);
9948 } catch (Exception e) {
9949 Log.w(TAG, "Exception when stopping service "
9950 + r.shortName, e);
9951 serviceDoneExecutingLocked(r, true);
9952 }
9953 } else {
9954 if (DEBUG_SERVICE) Log.v(
9955 TAG, "Removed service that has no process: " + r.shortName);
9956 }
9957 } else {
9958 if (DEBUG_SERVICE) Log.v(
9959 TAG, "Removed service that is not running: " + r.shortName);
9960 }
9961 }
9962
9963 ComponentName startServiceLocked(IApplicationThread caller,
9964 Intent service, String resolvedType,
9965 int callingPid, int callingUid) {
9966 synchronized(this) {
9967 if (DEBUG_SERVICE) Log.v(TAG, "startService: " + service
9968 + " type=" + resolvedType + " args=" + service.getExtras());
9969
9970 if (caller != null) {
9971 final ProcessRecord callerApp = getRecordForAppLocked(caller);
9972 if (callerApp == null) {
9973 throw new SecurityException(
9974 "Unable to find app for caller " + caller
9975 + " (pid=" + Binder.getCallingPid()
9976 + ") when starting service " + service);
9977 }
9978 }
9979
9980 ServiceLookupResult res =
9981 retrieveServiceLocked(service, resolvedType,
9982 callingPid, callingUid);
9983 if (res == null) {
9984 return null;
9985 }
9986 if (res.record == null) {
9987 return new ComponentName("!", res.permission != null
9988 ? res.permission : "private to package");
9989 }
9990 ServiceRecord r = res.record;
9991 if (unscheduleServiceRestartLocked(r)) {
9992 if (DEBUG_SERVICE) Log.v(TAG, "START SERVICE WHILE RESTART PENDING: "
9993 + r.shortName);
9994 }
9995 r.startRequested = true;
9996 r.startArgs.add(service);
9997 r.lastStartId++;
9998 if (r.lastStartId < 1) {
9999 r.lastStartId = 1;
10000 }
10001 r.lastActivity = SystemClock.uptimeMillis();
10002 synchronized (r.stats.getBatteryStats()) {
10003 r.stats.startRunningLocked();
10004 }
10005 if (!bringUpServiceLocked(r, service.getFlags(), false)) {
10006 return new ComponentName("!", "Service process is bad");
10007 }
10008 return r.name;
10009 }
10010 }
10011
10012 public ComponentName startService(IApplicationThread caller, Intent service,
10013 String resolvedType) {
10014 // Refuse possible leaked file descriptors
10015 if (service != null && service.hasFileDescriptors() == true) {
10016 throw new IllegalArgumentException("File descriptors passed in Intent");
10017 }
10018
10019 synchronized(this) {
10020 final int callingPid = Binder.getCallingPid();
10021 final int callingUid = Binder.getCallingUid();
10022 final long origId = Binder.clearCallingIdentity();
10023 ComponentName res = startServiceLocked(caller, service,
10024 resolvedType, callingPid, callingUid);
10025 Binder.restoreCallingIdentity(origId);
10026 return res;
10027 }
10028 }
10029
10030 ComponentName startServiceInPackage(int uid,
10031 Intent service, String resolvedType) {
10032 synchronized(this) {
10033 final long origId = Binder.clearCallingIdentity();
10034 ComponentName res = startServiceLocked(null, service,
10035 resolvedType, -1, uid);
10036 Binder.restoreCallingIdentity(origId);
10037 return res;
10038 }
10039 }
10040
10041 public int stopService(IApplicationThread caller, Intent service,
10042 String resolvedType) {
10043 // Refuse possible leaked file descriptors
10044 if (service != null && service.hasFileDescriptors() == true) {
10045 throw new IllegalArgumentException("File descriptors passed in Intent");
10046 }
10047
10048 synchronized(this) {
10049 if (DEBUG_SERVICE) Log.v(TAG, "stopService: " + service
10050 + " type=" + resolvedType);
10051
10052 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10053 if (caller != null && callerApp == null) {
10054 throw new SecurityException(
10055 "Unable to find app for caller " + caller
10056 + " (pid=" + Binder.getCallingPid()
10057 + ") when stopping service " + service);
10058 }
10059
10060 // If this service is active, make sure it is stopped.
10061 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10062 if (r != null) {
10063 if (r.record != null) {
10064 synchronized (r.record.stats.getBatteryStats()) {
10065 r.record.stats.stopRunningLocked();
10066 }
10067 r.record.startRequested = false;
10068 final long origId = Binder.clearCallingIdentity();
10069 bringDownServiceLocked(r.record, false);
10070 Binder.restoreCallingIdentity(origId);
10071 return 1;
10072 }
10073 return -1;
10074 }
10075 }
10076
10077 return 0;
10078 }
10079
10080 public IBinder peekService(Intent service, String resolvedType) {
10081 // Refuse possible leaked file descriptors
10082 if (service != null && service.hasFileDescriptors() == true) {
10083 throw new IllegalArgumentException("File descriptors passed in Intent");
10084 }
10085
10086 IBinder ret = null;
10087
10088 synchronized(this) {
10089 ServiceLookupResult r = findServiceLocked(service, resolvedType);
10090
10091 if (r != null) {
10092 // r.record is null if findServiceLocked() failed the caller permission check
10093 if (r.record == null) {
10094 throw new SecurityException(
10095 "Permission Denial: Accessing service " + r.record.name
10096 + " from pid=" + Binder.getCallingPid()
10097 + ", uid=" + Binder.getCallingUid()
10098 + " requires " + r.permission);
10099 }
10100 IntentBindRecord ib = r.record.bindings.get(r.record.intent);
10101 if (ib != null) {
10102 ret = ib.binder;
10103 }
10104 }
10105 }
10106
10107 return ret;
10108 }
10109
10110 public boolean stopServiceToken(ComponentName className, IBinder token,
10111 int startId) {
10112 synchronized(this) {
10113 if (DEBUG_SERVICE) Log.v(TAG, "stopServiceToken: " + className
10114 + " " + token + " startId=" + startId);
10115 ServiceRecord r = findServiceLocked(className, token);
10116 if (r != null && (startId < 0 || r.lastStartId == startId)) {
10117 synchronized (r.stats.getBatteryStats()) {
10118 r.stats.stopRunningLocked();
10119 r.startRequested = false;
10120 }
10121 final long origId = Binder.clearCallingIdentity();
10122 bringDownServiceLocked(r, false);
10123 Binder.restoreCallingIdentity(origId);
10124 return true;
10125 }
10126 }
10127 return false;
10128 }
10129
10130 public void setServiceForeground(ComponentName className, IBinder token,
10131 boolean isForeground) {
10132 synchronized(this) {
10133 ServiceRecord r = findServiceLocked(className, token);
10134 if (r != null) {
10135 if (r.isForeground != isForeground) {
10136 final long origId = Binder.clearCallingIdentity();
10137 r.isForeground = isForeground;
10138 if (r.app != null) {
10139 updateServiceForegroundLocked(r.app, true);
10140 }
10141 Binder.restoreCallingIdentity(origId);
10142 }
10143 }
10144 }
10145 }
10146
10147 public void updateServiceForegroundLocked(ProcessRecord proc, boolean oomAdj) {
10148 boolean anyForeground = false;
10149 for (ServiceRecord sr : (HashSet<ServiceRecord>)proc.services) {
10150 if (sr.isForeground) {
10151 anyForeground = true;
10152 break;
10153 }
10154 }
10155 if (anyForeground != proc.foregroundServices) {
10156 proc.foregroundServices = anyForeground;
10157 if (oomAdj) {
10158 updateOomAdjLocked();
10159 }
10160 }
10161 }
10162
10163 public int bindService(IApplicationThread caller, IBinder token,
10164 Intent service, String resolvedType,
10165 IServiceConnection connection, int flags) {
10166 // Refuse possible leaked file descriptors
10167 if (service != null && service.hasFileDescriptors() == true) {
10168 throw new IllegalArgumentException("File descriptors passed in Intent");
10169 }
10170
10171 synchronized(this) {
10172 if (DEBUG_SERVICE) Log.v(TAG, "bindService: " + service
10173 + " type=" + resolvedType + " conn=" + connection.asBinder()
10174 + " flags=0x" + Integer.toHexString(flags));
10175 final ProcessRecord callerApp = getRecordForAppLocked(caller);
10176 if (callerApp == null) {
10177 throw new SecurityException(
10178 "Unable to find app for caller " + caller
10179 + " (pid=" + Binder.getCallingPid()
10180 + ") when binding service " + service);
10181 }
10182
10183 HistoryRecord activity = null;
10184 if (token != null) {
Dianne Hackborn75b03852009-06-12 15:43:26 -070010185 int aindex = indexOfTokenLocked(token);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010186 if (aindex < 0) {
10187 Log.w(TAG, "Binding with unknown activity: " + token);
10188 return 0;
10189 }
10190 activity = (HistoryRecord)mHistory.get(aindex);
10191 }
10192
10193 ServiceLookupResult res =
10194 retrieveServiceLocked(service, resolvedType,
10195 Binder.getCallingPid(), Binder.getCallingUid());
10196 if (res == null) {
10197 return 0;
10198 }
10199 if (res.record == null) {
10200 return -1;
10201 }
10202 ServiceRecord s = res.record;
10203
10204 final long origId = Binder.clearCallingIdentity();
10205
10206 if (unscheduleServiceRestartLocked(s)) {
10207 if (DEBUG_SERVICE) Log.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
10208 + s.shortName);
10209 }
10210
10211 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
10212 ConnectionRecord c = new ConnectionRecord(b, activity,
10213 connection, flags);
10214
10215 IBinder binder = connection.asBinder();
10216 s.connections.put(binder, c);
10217 b.connections.add(c);
10218 if (activity != null) {
10219 if (activity.connections == null) {
10220 activity.connections = new HashSet<ConnectionRecord>();
10221 }
10222 activity.connections.add(c);
10223 }
10224 b.client.connections.add(c);
10225 mServiceConnections.put(binder, c);
10226
10227 if ((flags&Context.BIND_AUTO_CREATE) != 0) {
10228 s.lastActivity = SystemClock.uptimeMillis();
10229 if (!bringUpServiceLocked(s, service.getFlags(), false)) {
10230 return 0;
10231 }
10232 }
10233
10234 if (s.app != null) {
10235 // This could have made the service more important.
10236 updateOomAdjLocked(s.app);
10237 }
10238
10239 if (DEBUG_SERVICE) Log.v(TAG, "Bind " + s + " with " + b
10240 + ": received=" + b.intent.received
10241 + " apps=" + b.intent.apps.size()
10242 + " doRebind=" + b.intent.doRebind);
10243
10244 if (s.app != null && b.intent.received) {
10245 // Service is already running, so we can immediately
10246 // publish the connection.
10247 try {
10248 c.conn.connected(s.name, b.intent.binder);
10249 } catch (Exception e) {
10250 Log.w(TAG, "Failure sending service " + s.shortName
10251 + " to connection " + c.conn.asBinder()
10252 + " (in " + c.binding.client.processName + ")", e);
10253 }
10254
10255 // If this is the first app connected back to this binding,
10256 // and the service had previously asked to be told when
10257 // rebound, then do so.
10258 if (b.intent.apps.size() == 1 && b.intent.doRebind) {
10259 requestServiceBindingLocked(s, b.intent, true);
10260 }
10261 } else if (!b.intent.requested) {
10262 requestServiceBindingLocked(s, b.intent, false);
10263 }
10264
10265 Binder.restoreCallingIdentity(origId);
10266 }
10267
10268 return 1;
10269 }
10270
10271 private void removeConnectionLocked(
10272 ConnectionRecord c, ProcessRecord skipApp, HistoryRecord skipAct) {
10273 IBinder binder = c.conn.asBinder();
10274 AppBindRecord b = c.binding;
10275 ServiceRecord s = b.service;
10276 s.connections.remove(binder);
10277 b.connections.remove(c);
10278 if (c.activity != null && c.activity != skipAct) {
10279 if (c.activity.connections != null) {
10280 c.activity.connections.remove(c);
10281 }
10282 }
10283 if (b.client != skipApp) {
10284 b.client.connections.remove(c);
10285 }
10286 mServiceConnections.remove(binder);
10287
10288 if (b.connections.size() == 0) {
10289 b.intent.apps.remove(b.client);
10290 }
10291
10292 if (DEBUG_SERVICE) Log.v(TAG, "Disconnecting binding " + b.intent
10293 + ": shouldUnbind=" + b.intent.hasBound);
10294 if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
10295 && b.intent.hasBound) {
10296 try {
10297 bumpServiceExecutingLocked(s);
10298 updateOomAdjLocked(s.app);
10299 b.intent.hasBound = false;
10300 // Assume the client doesn't want to know about a rebind;
10301 // we will deal with that later if it asks for one.
10302 b.intent.doRebind = false;
10303 s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
10304 } catch (Exception e) {
10305 Log.w(TAG, "Exception when unbinding service " + s.shortName, e);
10306 serviceDoneExecutingLocked(s, true);
10307 }
10308 }
10309
10310 if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
10311 bringDownServiceLocked(s, false);
10312 }
10313 }
10314
10315 public boolean unbindService(IServiceConnection connection) {
10316 synchronized (this) {
10317 IBinder binder = connection.asBinder();
10318 if (DEBUG_SERVICE) Log.v(TAG, "unbindService: conn=" + binder);
10319 ConnectionRecord r = mServiceConnections.get(binder);
10320 if (r == null) {
10321 Log.w(TAG, "Unbind failed: could not find connection for "
10322 + connection.asBinder());
10323 return false;
10324 }
10325
10326 final long origId = Binder.clearCallingIdentity();
10327
10328 removeConnectionLocked(r, null, null);
10329
10330 if (r.binding.service.app != null) {
10331 // This could have made the service less important.
10332 updateOomAdjLocked(r.binding.service.app);
10333 }
10334
10335 Binder.restoreCallingIdentity(origId);
10336 }
10337
10338 return true;
10339 }
10340
10341 public void publishService(IBinder token, Intent intent, IBinder service) {
10342 // Refuse possible leaked file descriptors
10343 if (intent != null && intent.hasFileDescriptors() == true) {
10344 throw new IllegalArgumentException("File descriptors passed in Intent");
10345 }
10346
10347 synchronized(this) {
10348 if (!(token instanceof ServiceRecord)) {
10349 throw new IllegalArgumentException("Invalid service token");
10350 }
10351 ServiceRecord r = (ServiceRecord)token;
10352
10353 final long origId = Binder.clearCallingIdentity();
10354
10355 if (DEBUG_SERVICE) Log.v(TAG, "PUBLISHING SERVICE " + r.name
10356 + " " + intent + ": " + service);
10357 if (r != null) {
10358 Intent.FilterComparison filter
10359 = new Intent.FilterComparison(intent);
10360 IntentBindRecord b = r.bindings.get(filter);
10361 if (b != null && !b.received) {
10362 b.binder = service;
10363 b.requested = true;
10364 b.received = true;
10365 if (r.connections.size() > 0) {
10366 Iterator<ConnectionRecord> it
10367 = r.connections.values().iterator();
10368 while (it.hasNext()) {
10369 ConnectionRecord c = it.next();
10370 if (!filter.equals(c.binding.intent.intent)) {
10371 if (DEBUG_SERVICE) Log.v(
10372 TAG, "Not publishing to: " + c);
10373 if (DEBUG_SERVICE) Log.v(
10374 TAG, "Bound intent: " + c.binding.intent.intent);
10375 if (DEBUG_SERVICE) Log.v(
10376 TAG, "Published intent: " + intent);
10377 continue;
10378 }
10379 if (DEBUG_SERVICE) Log.v(TAG, "Publishing to: " + c);
10380 try {
10381 c.conn.connected(r.name, service);
10382 } catch (Exception e) {
10383 Log.w(TAG, "Failure sending service " + r.name +
10384 " to connection " + c.conn.asBinder() +
10385 " (in " + c.binding.client.processName + ")", e);
10386 }
10387 }
10388 }
10389 }
10390
10391 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10392
10393 Binder.restoreCallingIdentity(origId);
10394 }
10395 }
10396 }
10397
10398 public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
10399 // Refuse possible leaked file descriptors
10400 if (intent != null && intent.hasFileDescriptors() == true) {
10401 throw new IllegalArgumentException("File descriptors passed in Intent");
10402 }
10403
10404 synchronized(this) {
10405 if (!(token instanceof ServiceRecord)) {
10406 throw new IllegalArgumentException("Invalid service token");
10407 }
10408 ServiceRecord r = (ServiceRecord)token;
10409
10410 final long origId = Binder.clearCallingIdentity();
10411
10412 if (r != null) {
10413 Intent.FilterComparison filter
10414 = new Intent.FilterComparison(intent);
10415 IntentBindRecord b = r.bindings.get(filter);
10416 if (DEBUG_SERVICE) Log.v(TAG, "unbindFinished in " + r
10417 + " at " + b + ": apps="
10418 + (b != null ? b.apps.size() : 0));
10419 if (b != null) {
10420 if (b.apps.size() > 0) {
10421 // Applications have already bound since the last
10422 // unbind, so just rebind right here.
10423 requestServiceBindingLocked(r, b, true);
10424 } else {
10425 // Note to tell the service the next time there is
10426 // a new client.
10427 b.doRebind = true;
10428 }
10429 }
10430
10431 serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
10432
10433 Binder.restoreCallingIdentity(origId);
10434 }
10435 }
10436 }
10437
10438 public void serviceDoneExecuting(IBinder token) {
10439 synchronized(this) {
10440 if (!(token instanceof ServiceRecord)) {
10441 throw new IllegalArgumentException("Invalid service token");
10442 }
10443 ServiceRecord r = (ServiceRecord)token;
10444 boolean inStopping = mStoppingServices.contains(token);
10445 if (r != null) {
10446 if (DEBUG_SERVICE) Log.v(TAG, "DONE EXECUTING SERVICE " + r.name
10447 + ": nesting=" + r.executeNesting
10448 + ", inStopping=" + inStopping);
10449 if (r != token) {
10450 Log.w(TAG, "Done executing service " + r.name
10451 + " with incorrect token: given " + token
10452 + ", expected " + r);
10453 return;
10454 }
10455
10456 final long origId = Binder.clearCallingIdentity();
10457 serviceDoneExecutingLocked(r, inStopping);
10458 Binder.restoreCallingIdentity(origId);
10459 } else {
10460 Log.w(TAG, "Done executing unknown service " + r.name
10461 + " with token " + token);
10462 }
10463 }
10464 }
10465
10466 public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
10467 r.executeNesting--;
10468 if (r.executeNesting <= 0 && r.app != null) {
10469 r.app.executingServices.remove(r);
10470 if (r.app.executingServices.size() == 0) {
10471 mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
10472 }
10473 if (inStopping) {
10474 mStoppingServices.remove(r);
10475 }
10476 updateOomAdjLocked(r.app);
10477 }
10478 }
10479
10480 void serviceTimeout(ProcessRecord proc) {
10481 synchronized(this) {
10482 if (proc.executingServices.size() == 0 || proc.thread == null) {
10483 return;
10484 }
10485 long maxTime = SystemClock.uptimeMillis() - SERVICE_TIMEOUT;
10486 Iterator<ServiceRecord> it = proc.executingServices.iterator();
10487 ServiceRecord timeout = null;
10488 long nextTime = 0;
10489 while (it.hasNext()) {
10490 ServiceRecord sr = it.next();
10491 if (sr.executingStart < maxTime) {
10492 timeout = sr;
10493 break;
10494 }
10495 if (sr.executingStart > nextTime) {
10496 nextTime = sr.executingStart;
10497 }
10498 }
10499 if (timeout != null && mLRUProcesses.contains(proc)) {
10500 Log.w(TAG, "Timeout executing service: " + timeout);
10501 appNotRespondingLocked(proc, null, "Executing service "
10502 + timeout.name);
10503 } else {
10504 Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
10505 msg.obj = proc;
10506 mHandler.sendMessageAtTime(msg, nextTime+SERVICE_TIMEOUT);
10507 }
10508 }
10509 }
10510
10511 // =========================================================
Christopher Tate181fafa2009-05-14 11:12:14 -070010512 // BACKUP AND RESTORE
10513 // =========================================================
10514
10515 // Cause the target app to be launched if necessary and its backup agent
10516 // instantiated. The backup agent will invoke backupAgentCreated() on the
10517 // activity manager to announce its creation.
10518 public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
10519 if (DEBUG_BACKUP) Log.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
10520 enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
10521
10522 synchronized(this) {
10523 // !!! TODO: currently no check here that we're already bound
10524 BatteryStatsImpl.Uid.Pkg.Serv ss = null;
10525 BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
10526 synchronized (stats) {
10527 ss = stats.getServiceStatsLocked(app.uid, app.packageName, app.name);
10528 }
10529
10530 BackupRecord r = new BackupRecord(ss, app, backupMode);
10531 ComponentName hostingName = new ComponentName(app.packageName, app.backupAgentName);
10532 // startProcessLocked() returns existing proc's record if it's already running
10533 ProcessRecord proc = startProcessLocked(app.processName, app,
10534 false, 0, "backup", hostingName);
10535 if (proc == null) {
10536 Log.e(TAG, "Unable to start backup agent process " + r);
10537 return false;
10538 }
10539
10540 r.app = proc;
10541 mBackupTarget = r;
10542 mBackupAppName = app.packageName;
10543
Christopher Tate6fa95972009-06-05 18:43:55 -070010544 // Try not to kill the process during backup
10545 updateOomAdjLocked(proc);
10546
Christopher Tate181fafa2009-05-14 11:12:14 -070010547 // If the process is already attached, schedule the creation of the backup agent now.
10548 // If it is not yet live, this will be done when it attaches to the framework.
10549 if (proc.thread != null) {
10550 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc already running: " + proc);
10551 try {
10552 proc.thread.scheduleCreateBackupAgent(app, backupMode);
10553 } catch (RemoteException e) {
10554 // !!! TODO: notify the backup manager that we crashed, or rely on
10555 // death notices, or...?
10556 }
10557 } else {
10558 if (DEBUG_BACKUP) Log.v(TAG, "Agent proc not running, waiting for attach");
10559 }
10560 // Invariants: at this point, the target app process exists and the application
10561 // is either already running or in the process of coming up. mBackupTarget and
10562 // mBackupAppName describe the app, so that when it binds back to the AM we
10563 // know that it's scheduled for a backup-agent operation.
10564 }
10565
10566 return true;
10567 }
10568
10569 // A backup agent has just come up
10570 public void backupAgentCreated(String agentPackageName, IBinder agent) {
10571 if (DEBUG_BACKUP) Log.v(TAG, "backupAgentCreated: " + agentPackageName
10572 + " = " + agent);
10573
10574 synchronized(this) {
10575 if (!agentPackageName.equals(mBackupAppName)) {
10576 Log.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!");
10577 return;
10578 }
10579
Christopher Tate043dadc2009-06-02 16:11:00 -070010580 long oldIdent = Binder.clearCallingIdentity();
Christopher Tate181fafa2009-05-14 11:12:14 -070010581 try {
10582 IBackupManager bm = IBackupManager.Stub.asInterface(
10583 ServiceManager.getService(Context.BACKUP_SERVICE));
10584 bm.agentConnected(agentPackageName, agent);
10585 } catch (RemoteException e) {
10586 // can't happen; the backup manager service is local
10587 } catch (Exception e) {
10588 Log.w(TAG, "Exception trying to deliver BackupAgent binding: ");
10589 e.printStackTrace();
Christopher Tate043dadc2009-06-02 16:11:00 -070010590 } finally {
10591 Binder.restoreCallingIdentity(oldIdent);
Christopher Tate181fafa2009-05-14 11:12:14 -070010592 }
10593 }
10594 }
10595
10596 // done with this agent
10597 public void unbindBackupAgent(ApplicationInfo appInfo) {
10598 if (DEBUG_BACKUP) Log.v(TAG, "unbindBackupAgent: " + appInfo);
Christopher Tate8a27f922009-06-26 11:49:18 -070010599 if (appInfo == null) {
10600 Log.w(TAG, "unbind backup agent for null app");
10601 return;
10602 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010603
10604 synchronized(this) {
Christopher Tate8a27f922009-06-26 11:49:18 -070010605 if (mBackupAppName == null) {
10606 Log.w(TAG, "Unbinding backup agent with no active backup");
10607 return;
10608 }
10609
Christopher Tate181fafa2009-05-14 11:12:14 -070010610 if (!mBackupAppName.equals(appInfo.packageName)) {
10611 Log.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
10612 return;
10613 }
10614
Christopher Tate6fa95972009-06-05 18:43:55 -070010615 ProcessRecord proc = mBackupTarget.app;
10616 mBackupTarget = null;
10617 mBackupAppName = null;
10618
10619 // Not backing this app up any more; reset its OOM adjustment
10620 updateOomAdjLocked(proc);
10621
Christopher Tatec7b31e32009-06-10 15:49:30 -070010622 // If the app crashed during backup, 'thread' will be null here
10623 if (proc.thread != null) {
10624 try {
10625 proc.thread.scheduleDestroyBackupAgent(appInfo);
10626 } catch (Exception e) {
10627 Log.e(TAG, "Exception when unbinding backup agent:");
10628 e.printStackTrace();
10629 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010630 }
Christopher Tate181fafa2009-05-14 11:12:14 -070010631 }
10632 }
10633 // =========================================================
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010634 // BROADCASTS
10635 // =========================================================
10636
10637 private final List getStickies(String action, IntentFilter filter,
10638 List cur) {
10639 final ContentResolver resolver = mContext.getContentResolver();
10640 final ArrayList<Intent> list = mStickyBroadcasts.get(action);
10641 if (list == null) {
10642 return cur;
10643 }
10644 int N = list.size();
10645 for (int i=0; i<N; i++) {
10646 Intent intent = list.get(i);
10647 if (filter.match(resolver, intent, true, TAG) >= 0) {
10648 if (cur == null) {
10649 cur = new ArrayList<Intent>();
10650 }
10651 cur.add(intent);
10652 }
10653 }
10654 return cur;
10655 }
10656
10657 private final void scheduleBroadcastsLocked() {
10658 if (DEBUG_BROADCAST) Log.v(TAG, "Schedule broadcasts: current="
10659 + mBroadcastsScheduled);
10660
10661 if (mBroadcastsScheduled) {
10662 return;
10663 }
10664 mHandler.sendEmptyMessage(BROADCAST_INTENT_MSG);
10665 mBroadcastsScheduled = true;
10666 }
10667
10668 public Intent registerReceiver(IApplicationThread caller,
10669 IIntentReceiver receiver, IntentFilter filter, String permission) {
10670 synchronized(this) {
10671 ProcessRecord callerApp = null;
10672 if (caller != null) {
10673 callerApp = getRecordForAppLocked(caller);
10674 if (callerApp == null) {
10675 throw new SecurityException(
10676 "Unable to find app for caller " + caller
10677 + " (pid=" + Binder.getCallingPid()
10678 + ") when registering receiver " + receiver);
10679 }
10680 }
10681
10682 List allSticky = null;
10683
10684 // Look for any matching sticky broadcasts...
10685 Iterator actions = filter.actionsIterator();
10686 if (actions != null) {
10687 while (actions.hasNext()) {
10688 String action = (String)actions.next();
10689 allSticky = getStickies(action, filter, allSticky);
10690 }
10691 } else {
10692 allSticky = getStickies(null, filter, allSticky);
10693 }
10694
10695 // The first sticky in the list is returned directly back to
10696 // the client.
10697 Intent sticky = allSticky != null ? (Intent)allSticky.get(0) : null;
10698
10699 if (DEBUG_BROADCAST) Log.v(TAG, "Register receiver " + filter
10700 + ": " + sticky);
10701
10702 if (receiver == null) {
10703 return sticky;
10704 }
10705
10706 ReceiverList rl
10707 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10708 if (rl == null) {
10709 rl = new ReceiverList(this, callerApp,
10710 Binder.getCallingPid(),
10711 Binder.getCallingUid(), receiver);
10712 if (rl.app != null) {
10713 rl.app.receivers.add(rl);
10714 } else {
10715 try {
10716 receiver.asBinder().linkToDeath(rl, 0);
10717 } catch (RemoteException e) {
10718 return sticky;
10719 }
10720 rl.linkedToDeath = true;
10721 }
10722 mRegisteredReceivers.put(receiver.asBinder(), rl);
10723 }
10724 BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
10725 rl.add(bf);
10726 if (!bf.debugCheck()) {
10727 Log.w(TAG, "==> For Dynamic broadast");
10728 }
10729 mReceiverResolver.addFilter(bf);
10730
10731 // Enqueue broadcasts for all existing stickies that match
10732 // this filter.
10733 if (allSticky != null) {
10734 ArrayList receivers = new ArrayList();
10735 receivers.add(bf);
10736
10737 int N = allSticky.size();
10738 for (int i=0; i<N; i++) {
10739 Intent intent = (Intent)allSticky.get(i);
10740 BroadcastRecord r = new BroadcastRecord(intent, null,
10741 null, -1, -1, null, receivers, null, 0, null, null,
10742 false);
10743 if (mParallelBroadcasts.size() == 0) {
10744 scheduleBroadcastsLocked();
10745 }
10746 mParallelBroadcasts.add(r);
10747 }
10748 }
10749
10750 return sticky;
10751 }
10752 }
10753
10754 public void unregisterReceiver(IIntentReceiver receiver) {
10755 if (DEBUG_BROADCAST) Log.v(TAG, "Unregister receiver: " + receiver);
10756
10757 boolean doNext = false;
10758
10759 synchronized(this) {
10760 ReceiverList rl
10761 = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
10762 if (rl != null) {
10763 if (rl.curBroadcast != null) {
10764 BroadcastRecord r = rl.curBroadcast;
10765 doNext = finishReceiverLocked(
10766 receiver.asBinder(), r.resultCode, r.resultData,
10767 r.resultExtras, r.resultAbort, true);
10768 }
10769
10770 if (rl.app != null) {
10771 rl.app.receivers.remove(rl);
10772 }
10773 removeReceiverLocked(rl);
10774 if (rl.linkedToDeath) {
10775 rl.linkedToDeath = false;
10776 rl.receiver.asBinder().unlinkToDeath(rl, 0);
10777 }
10778 }
10779 }
10780
10781 if (!doNext) {
10782 return;
10783 }
10784
10785 final long origId = Binder.clearCallingIdentity();
10786 processNextBroadcast(false);
10787 trimApplications();
10788 Binder.restoreCallingIdentity(origId);
10789 }
10790
10791 void removeReceiverLocked(ReceiverList rl) {
10792 mRegisteredReceivers.remove(rl.receiver.asBinder());
10793 int N = rl.size();
10794 for (int i=0; i<N; i++) {
10795 mReceiverResolver.removeFilter(rl.get(i));
10796 }
10797 }
10798
10799 private final int broadcastIntentLocked(ProcessRecord callerApp,
10800 String callerPackage, Intent intent, String resolvedType,
10801 IIntentReceiver resultTo, int resultCode, String resultData,
10802 Bundle map, String requiredPermission,
10803 boolean ordered, boolean sticky, int callingPid, int callingUid) {
10804 intent = new Intent(intent);
10805
Dianne Hackborn82f3f002009-06-16 18:49:05 -070010806 if (DEBUG_BROADCAST_LIGHT) Log.v(
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010807 TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
10808 + " ordered=" + ordered);
10809 if ((resultTo != null) && !ordered) {
10810 Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
10811 }
10812
10813 // Handle special intents: if this broadcast is from the package
10814 // manager about a package being removed, we need to remove all of
10815 // its activities from the history stack.
10816 final boolean uidRemoved = intent.ACTION_UID_REMOVED.equals(
10817 intent.getAction());
10818 if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
10819 || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction())
10820 || uidRemoved) {
10821 if (checkComponentPermission(
10822 android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
10823 callingPid, callingUid, -1)
10824 == PackageManager.PERMISSION_GRANTED) {
10825 if (uidRemoved) {
10826 final Bundle intentExtras = intent.getExtras();
10827 final int uid = intentExtras != null
10828 ? intentExtras.getInt(Intent.EXTRA_UID) : -1;
10829 if (uid >= 0) {
10830 BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
10831 synchronized (bs) {
10832 bs.removeUidStatsLocked(uid);
10833 }
10834 }
10835 } else {
10836 Uri data = intent.getData();
10837 String ssp;
10838 if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
10839 if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
10840 uninstallPackageLocked(ssp,
10841 intent.getIntExtra(Intent.EXTRA_UID, -1), false);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070010842 AttributeCache ac = AttributeCache.instance();
10843 if (ac != null) {
10844 ac.removePackage(ssp);
10845 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010846 }
10847 }
10848 }
10849 } else {
10850 String msg = "Permission Denial: " + intent.getAction()
10851 + " broadcast from " + callerPackage + " (pid=" + callingPid
10852 + ", uid=" + callingUid + ")"
10853 + " requires "
10854 + android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
10855 Log.w(TAG, msg);
10856 throw new SecurityException(msg);
10857 }
10858 }
10859
10860 /*
10861 * If this is the time zone changed action, queue up a message that will reset the timezone
10862 * of all currently running processes. This message will get queued up before the broadcast
10863 * happens.
10864 */
10865 if (intent.ACTION_TIMEZONE_CHANGED.equals(intent.getAction())) {
10866 mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
10867 }
10868
Dianne Hackborn854060af2009-07-09 18:14:31 -070010869 /*
10870 * Prevent non-system code (defined here to be non-persistent
10871 * processes) from sending protected broadcasts.
10872 */
10873 if (callingUid == Process.SYSTEM_UID || callingUid == Process.PHONE_UID
10874 || callingUid == Process.SHELL_UID || callingUid == 0) {
10875 // Always okay.
10876 } else if (callerApp == null || !callerApp.persistent) {
10877 try {
10878 if (ActivityThread.getPackageManager().isProtectedBroadcast(
10879 intent.getAction())) {
10880 String msg = "Permission Denial: not allowed to send broadcast "
10881 + intent.getAction() + " from pid="
10882 + callingPid + ", uid=" + callingUid;
10883 Log.w(TAG, msg);
10884 throw new SecurityException(msg);
10885 }
10886 } catch (RemoteException e) {
10887 Log.w(TAG, "Remote exception", e);
10888 return BROADCAST_SUCCESS;
10889 }
10890 }
10891
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010892 // Add to the sticky list if requested.
10893 if (sticky) {
10894 if (checkPermission(android.Manifest.permission.BROADCAST_STICKY,
10895 callingPid, callingUid)
10896 != PackageManager.PERMISSION_GRANTED) {
10897 String msg = "Permission Denial: broadcastIntent() requesting a sticky broadcast from pid="
10898 + callingPid + ", uid=" + callingUid
10899 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
10900 Log.w(TAG, msg);
10901 throw new SecurityException(msg);
10902 }
10903 if (requiredPermission != null) {
10904 Log.w(TAG, "Can't broadcast sticky intent " + intent
10905 + " and enforce permission " + requiredPermission);
10906 return BROADCAST_STICKY_CANT_HAVE_PERMISSION;
10907 }
10908 if (intent.getComponent() != null) {
10909 throw new SecurityException(
10910 "Sticky broadcasts can't target a specific component");
10911 }
10912 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
10913 if (list == null) {
10914 list = new ArrayList<Intent>();
10915 mStickyBroadcasts.put(intent.getAction(), list);
10916 }
10917 int N = list.size();
10918 int i;
10919 for (i=0; i<N; i++) {
10920 if (intent.filterEquals(list.get(i))) {
10921 // This sticky already exists, replace it.
10922 list.set(i, new Intent(intent));
10923 break;
10924 }
10925 }
10926 if (i >= N) {
10927 list.add(new Intent(intent));
10928 }
10929 }
10930
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010931 // Figure out who all will receive this broadcast.
10932 List receivers = null;
10933 List<BroadcastFilter> registeredReceivers = null;
10934 try {
10935 if (intent.getComponent() != null) {
10936 // Broadcast is going to one specific receiver class...
10937 ActivityInfo ai = ActivityThread.getPackageManager().
Dianne Hackborn1655be42009-05-08 14:29:01 -070010938 getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010939 if (ai != null) {
10940 receivers = new ArrayList();
10941 ResolveInfo ri = new ResolveInfo();
10942 ri.activityInfo = ai;
10943 receivers.add(ri);
10944 }
10945 } else {
10946 // Need to resolve the intent to interested receivers...
10947 if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
10948 == 0) {
10949 receivers =
10950 ActivityThread.getPackageManager().queryIntentReceivers(
Dianne Hackborn1655be42009-05-08 14:29:01 -070010951 intent, resolvedType, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010952 }
Mihai Preda074edef2009-05-18 17:13:31 +020010953 registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010954 }
10955 } catch (RemoteException ex) {
10956 // pm is in same process, this will never happen.
10957 }
10958
10959 int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
10960 if (!ordered && NR > 0) {
10961 // If we are not serializing this broadcast, then send the
10962 // registered receivers separately so they don't wait for the
10963 // components to be launched.
10964 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
10965 callerPackage, callingPid, callingUid, requiredPermission,
10966 registeredReceivers, resultTo, resultCode, resultData, map,
10967 ordered);
10968 if (DEBUG_BROADCAST) Log.v(
10969 TAG, "Enqueueing parallel broadcast " + r
10970 + ": prev had " + mParallelBroadcasts.size());
10971 mParallelBroadcasts.add(r);
10972 scheduleBroadcastsLocked();
10973 registeredReceivers = null;
10974 NR = 0;
10975 }
10976
10977 // Merge into one list.
10978 int ir = 0;
10979 if (receivers != null) {
10980 // A special case for PACKAGE_ADDED: do not allow the package
10981 // being added to see this broadcast. This prevents them from
10982 // using this as a back door to get run as soon as they are
10983 // installed. Maybe in the future we want to have a special install
10984 // broadcast or such for apps, but we'd like to deliberately make
10985 // this decision.
The Android Open Source Project10592532009-03-18 17:39:46 -070010986 boolean skip = false;
10987 if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) {
Dianne Hackbornf63220f2009-03-24 18:38:43 -070010988 skip = true;
The Android Open Source Project10592532009-03-18 17:39:46 -070010989 } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) {
10990 skip = true;
10991 } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) {
10992 skip = true;
10993 }
10994 String skipPackage = (skip && intent.getData() != null)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010995 ? intent.getData().getSchemeSpecificPart()
10996 : null;
10997 if (skipPackage != null && receivers != null) {
10998 int NT = receivers.size();
10999 for (int it=0; it<NT; it++) {
11000 ResolveInfo curt = (ResolveInfo)receivers.get(it);
11001 if (curt.activityInfo.packageName.equals(skipPackage)) {
11002 receivers.remove(it);
11003 it--;
11004 NT--;
11005 }
11006 }
11007 }
11008
11009 int NT = receivers != null ? receivers.size() : 0;
11010 int it = 0;
11011 ResolveInfo curt = null;
11012 BroadcastFilter curr = null;
11013 while (it < NT && ir < NR) {
11014 if (curt == null) {
11015 curt = (ResolveInfo)receivers.get(it);
11016 }
11017 if (curr == null) {
11018 curr = registeredReceivers.get(ir);
11019 }
11020 if (curr.getPriority() >= curt.priority) {
11021 // Insert this broadcast record into the final list.
11022 receivers.add(it, curr);
11023 ir++;
11024 curr = null;
11025 it++;
11026 NT++;
11027 } else {
11028 // Skip to the next ResolveInfo in the final list.
11029 it++;
11030 curt = null;
11031 }
11032 }
11033 }
11034 while (ir < NR) {
11035 if (receivers == null) {
11036 receivers = new ArrayList();
11037 }
11038 receivers.add(registeredReceivers.get(ir));
11039 ir++;
11040 }
11041
11042 if ((receivers != null && receivers.size() > 0)
11043 || resultTo != null) {
11044 BroadcastRecord r = new BroadcastRecord(intent, callerApp,
11045 callerPackage, callingPid, callingUid, requiredPermission,
11046 receivers, resultTo, resultCode, resultData, map, ordered);
11047 if (DEBUG_BROADCAST) Log.v(
11048 TAG, "Enqueueing ordered broadcast " + r
11049 + ": prev had " + mOrderedBroadcasts.size());
11050 if (DEBUG_BROADCAST) {
11051 int seq = r.intent.getIntExtra("seq", -1);
11052 Log.i(TAG, "Enqueueing broadcast " + r.intent.getAction() + " seq=" + seq);
11053 }
11054 mOrderedBroadcasts.add(r);
11055 scheduleBroadcastsLocked();
11056 }
11057
11058 return BROADCAST_SUCCESS;
11059 }
11060
11061 public final int broadcastIntent(IApplicationThread caller,
11062 Intent intent, String resolvedType, IIntentReceiver resultTo,
11063 int resultCode, String resultData, Bundle map,
11064 String requiredPermission, boolean serialized, boolean sticky) {
11065 // Refuse possible leaked file descriptors
11066 if (intent != null && intent.hasFileDescriptors() == true) {
11067 throw new IllegalArgumentException("File descriptors passed in Intent");
11068 }
11069
11070 synchronized(this) {
11071 if (!mSystemReady) {
11072 // if the caller really truly claims to know what they're doing, go
11073 // ahead and allow the broadcast without launching any receivers
11074 int flags = intent.getFlags();
11075 if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT) != 0) {
11076 intent = new Intent(intent);
11077 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
11078 } else if ((flags&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0){
11079 Log.e(TAG, "Attempt to launch receivers of broadcast intent " + intent
11080 + " before boot completion");
11081 throw new IllegalStateException("Cannot broadcast before boot completed");
11082 }
11083 }
11084
11085 final ProcessRecord callerApp = getRecordForAppLocked(caller);
11086 final int callingPid = Binder.getCallingPid();
11087 final int callingUid = Binder.getCallingUid();
11088 final long origId = Binder.clearCallingIdentity();
11089 int res = broadcastIntentLocked(callerApp,
11090 callerApp != null ? callerApp.info.packageName : null,
11091 intent, resolvedType, resultTo,
11092 resultCode, resultData, map, requiredPermission, serialized,
11093 sticky, callingPid, callingUid);
11094 Binder.restoreCallingIdentity(origId);
11095 return res;
11096 }
11097 }
11098
11099 int broadcastIntentInPackage(String packageName, int uid,
11100 Intent intent, String resolvedType, IIntentReceiver resultTo,
11101 int resultCode, String resultData, Bundle map,
11102 String requiredPermission, boolean serialized, boolean sticky) {
11103 synchronized(this) {
11104 final long origId = Binder.clearCallingIdentity();
11105 int res = broadcastIntentLocked(null, packageName, intent, resolvedType,
11106 resultTo, resultCode, resultData, map, requiredPermission,
11107 serialized, sticky, -1, uid);
11108 Binder.restoreCallingIdentity(origId);
11109 return res;
11110 }
11111 }
11112
11113 public final void unbroadcastIntent(IApplicationThread caller,
11114 Intent intent) {
11115 // Refuse possible leaked file descriptors
11116 if (intent != null && intent.hasFileDescriptors() == true) {
11117 throw new IllegalArgumentException("File descriptors passed in Intent");
11118 }
11119
11120 synchronized(this) {
11121 if (checkCallingPermission(android.Manifest.permission.BROADCAST_STICKY)
11122 != PackageManager.PERMISSION_GRANTED) {
11123 String msg = "Permission Denial: unbroadcastIntent() from pid="
11124 + Binder.getCallingPid()
11125 + ", uid=" + Binder.getCallingUid()
11126 + " requires " + android.Manifest.permission.BROADCAST_STICKY;
11127 Log.w(TAG, msg);
11128 throw new SecurityException(msg);
11129 }
11130 ArrayList<Intent> list = mStickyBroadcasts.get(intent.getAction());
11131 if (list != null) {
11132 int N = list.size();
11133 int i;
11134 for (i=0; i<N; i++) {
11135 if (intent.filterEquals(list.get(i))) {
11136 list.remove(i);
11137 break;
11138 }
11139 }
11140 }
11141 }
11142 }
11143
11144 private final boolean finishReceiverLocked(IBinder receiver, int resultCode,
11145 String resultData, Bundle resultExtras, boolean resultAbort,
11146 boolean explicit) {
11147 if (mOrderedBroadcasts.size() == 0) {
11148 if (explicit) {
11149 Log.w(TAG, "finishReceiver called but no pending broadcasts");
11150 }
11151 return false;
11152 }
11153 BroadcastRecord r = mOrderedBroadcasts.get(0);
11154 if (r.receiver == null) {
11155 if (explicit) {
11156 Log.w(TAG, "finishReceiver called but none active");
11157 }
11158 return false;
11159 }
11160 if (r.receiver != receiver) {
11161 Log.w(TAG, "finishReceiver called but active receiver is different");
11162 return false;
11163 }
11164 int state = r.state;
11165 r.state = r.IDLE;
11166 if (state == r.IDLE) {
11167 if (explicit) {
11168 Log.w(TAG, "finishReceiver called but state is IDLE");
11169 }
11170 }
11171 r.receiver = null;
11172 r.intent.setComponent(null);
11173 if (r.curApp != null) {
11174 r.curApp.curReceiver = null;
11175 }
11176 if (r.curFilter != null) {
11177 r.curFilter.receiverList.curBroadcast = null;
11178 }
11179 r.curFilter = null;
11180 r.curApp = null;
11181 r.curComponent = null;
11182 r.curReceiver = null;
11183 mPendingBroadcast = null;
11184
11185 r.resultCode = resultCode;
11186 r.resultData = resultData;
11187 r.resultExtras = resultExtras;
11188 r.resultAbort = resultAbort;
11189
11190 // We will process the next receiver right now if this is finishing
11191 // an app receiver (which is always asynchronous) or after we have
11192 // come back from calling a receiver.
11193 return state == BroadcastRecord.APP_RECEIVE
11194 || state == BroadcastRecord.CALL_DONE_RECEIVE;
11195 }
11196
11197 public void finishReceiver(IBinder who, int resultCode, String resultData,
11198 Bundle resultExtras, boolean resultAbort) {
11199 if (DEBUG_BROADCAST) Log.v(TAG, "Finish receiver: " + who);
11200
11201 // Refuse possible leaked file descriptors
11202 if (resultExtras != null && resultExtras.hasFileDescriptors()) {
11203 throw new IllegalArgumentException("File descriptors passed in Bundle");
11204 }
11205
11206 boolean doNext;
11207
11208 final long origId = Binder.clearCallingIdentity();
11209
11210 synchronized(this) {
11211 doNext = finishReceiverLocked(
11212 who, resultCode, resultData, resultExtras, resultAbort, true);
11213 }
11214
11215 if (doNext) {
11216 processNextBroadcast(false);
11217 }
11218 trimApplications();
11219
11220 Binder.restoreCallingIdentity(origId);
11221 }
11222
11223 private final void logBroadcastReceiverDiscard(BroadcastRecord r) {
11224 if (r.nextReceiver > 0) {
11225 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11226 if (curReceiver instanceof BroadcastFilter) {
11227 BroadcastFilter bf = (BroadcastFilter) curReceiver;
11228 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_FILTER,
11229 System.identityHashCode(r),
11230 r.intent.getAction(),
11231 r.nextReceiver - 1,
11232 System.identityHashCode(bf));
11233 } else {
11234 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11235 System.identityHashCode(r),
11236 r.intent.getAction(),
11237 r.nextReceiver - 1,
11238 ((ResolveInfo)curReceiver).toString());
11239 }
11240 } else {
11241 Log.w(TAG, "Discarding broadcast before first receiver is invoked: "
11242 + r);
11243 EventLog.writeEvent(LOG_AM_BROADCAST_DISCARD_APP,
11244 System.identityHashCode(r),
11245 r.intent.getAction(),
11246 r.nextReceiver,
11247 "NONE");
11248 }
11249 }
11250
11251 private final void broadcastTimeout() {
11252 synchronized (this) {
11253 if (mOrderedBroadcasts.size() == 0) {
11254 return;
11255 }
11256 long now = SystemClock.uptimeMillis();
11257 BroadcastRecord r = mOrderedBroadcasts.get(0);
11258 if ((r.startTime+BROADCAST_TIMEOUT) > now) {
11259 if (DEBUG_BROADCAST) Log.v(TAG,
11260 "Premature timeout @ " + now + ": resetting BROADCAST_TIMEOUT_MSG for "
11261 + (r.startTime + BROADCAST_TIMEOUT));
11262 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11263 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11264 return;
11265 }
11266
11267 Log.w(TAG, "Timeout of broadcast " + r + " - receiver=" + r.receiver);
11268 r.startTime = now;
11269 r.anrCount++;
11270
11271 // Current receiver has passed its expiration date.
11272 if (r.nextReceiver <= 0) {
11273 Log.w(TAG, "Timeout on receiver with nextReceiver <= 0");
11274 return;
11275 }
11276
11277 ProcessRecord app = null;
11278
11279 Object curReceiver = r.receivers.get(r.nextReceiver-1);
11280 Log.w(TAG, "Receiver during timeout: " + curReceiver);
11281 logBroadcastReceiverDiscard(r);
11282 if (curReceiver instanceof BroadcastFilter) {
11283 BroadcastFilter bf = (BroadcastFilter)curReceiver;
11284 if (bf.receiverList.pid != 0
11285 && bf.receiverList.pid != MY_PID) {
11286 synchronized (this.mPidsSelfLocked) {
11287 app = this.mPidsSelfLocked.get(
11288 bf.receiverList.pid);
11289 }
11290 }
11291 } else {
11292 app = r.curApp;
11293 }
11294
11295 if (app != null) {
11296 appNotRespondingLocked(app, null, "Broadcast of " + r.intent.toString());
11297 }
11298
11299 if (mPendingBroadcast == r) {
11300 mPendingBroadcast = null;
11301 }
11302
11303 // Move on to the next receiver.
11304 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11305 r.resultExtras, r.resultAbort, true);
11306 scheduleBroadcastsLocked();
11307 }
11308 }
11309
11310 private final void processCurBroadcastLocked(BroadcastRecord r,
11311 ProcessRecord app) throws RemoteException {
11312 if (app.thread == null) {
11313 throw new RemoteException();
11314 }
11315 r.receiver = app.thread.asBinder();
11316 r.curApp = app;
11317 app.curReceiver = r;
11318 updateLRUListLocked(app, true);
11319
11320 // Tell the application to launch this receiver.
11321 r.intent.setComponent(r.curComponent);
11322
11323 boolean started = false;
11324 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011325 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011326 "Delivering to component " + r.curComponent
11327 + ": " + r);
Dianne Hackborn5c1e00b2009-06-18 17:10:57 -070011328 ensurePackageDexOpt(r.intent.getComponent().getPackageName());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011329 app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
11330 r.resultCode, r.resultData, r.resultExtras, r.ordered);
11331 started = true;
11332 } finally {
11333 if (!started) {
11334 r.receiver = null;
11335 r.curApp = null;
11336 app.curReceiver = null;
11337 }
11338 }
11339
11340 }
11341
11342 static void performReceive(ProcessRecord app, IIntentReceiver receiver,
11343 Intent intent, int resultCode, String data,
11344 Bundle extras, boolean ordered) throws RemoteException {
11345 if (app != null && app.thread != null) {
11346 // If we have an app thread, do the call through that so it is
11347 // correctly ordered with other one-way calls.
11348 app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
11349 data, extras, ordered);
11350 } else {
11351 receiver.performReceive(intent, resultCode, data, extras, ordered);
11352 }
11353 }
11354
11355 private final void deliverToRegisteredReceiver(BroadcastRecord r,
11356 BroadcastFilter filter, boolean ordered) {
11357 boolean skip = false;
11358 if (filter.requiredPermission != null) {
11359 int perm = checkComponentPermission(filter.requiredPermission,
11360 r.callingPid, r.callingUid, -1);
11361 if (perm != PackageManager.PERMISSION_GRANTED) {
11362 Log.w(TAG, "Permission Denial: broadcasting "
11363 + r.intent.toString()
11364 + " from " + r.callerPackage + " (pid="
11365 + r.callingPid + ", uid=" + r.callingUid + ")"
11366 + " requires " + filter.requiredPermission
11367 + " due to registered receiver " + filter);
11368 skip = true;
11369 }
11370 }
11371 if (r.requiredPermission != null) {
11372 int perm = checkComponentPermission(r.requiredPermission,
11373 filter.receiverList.pid, filter.receiverList.uid, -1);
11374 if (perm != PackageManager.PERMISSION_GRANTED) {
11375 Log.w(TAG, "Permission Denial: receiving "
11376 + r.intent.toString()
11377 + " to " + filter.receiverList.app
11378 + " (pid=" + filter.receiverList.pid
11379 + ", uid=" + filter.receiverList.uid + ")"
11380 + " requires " + r.requiredPermission
11381 + " due to sender " + r.callerPackage
11382 + " (uid " + r.callingUid + ")");
11383 skip = true;
11384 }
11385 }
11386
11387 if (!skip) {
11388 // If this is not being sent as an ordered broadcast, then we
11389 // don't want to touch the fields that keep track of the current
11390 // state of ordered broadcasts.
11391 if (ordered) {
11392 r.receiver = filter.receiverList.receiver.asBinder();
11393 r.curFilter = filter;
11394 filter.receiverList.curBroadcast = r;
11395 r.state = BroadcastRecord.CALL_IN_RECEIVE;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011396 if (filter.receiverList.app != null) {
11397 // Bump hosting application to no longer be in background
11398 // scheduling class. Note that we can't do that if there
11399 // isn't an app... but we can only be in that case for
11400 // things that directly call the IActivityManager API, which
11401 // are already core system stuff so don't matter for this.
11402 r.curApp = filter.receiverList.app;
11403 filter.receiverList.app.curReceiver = r;
11404 updateOomAdjLocked();
11405 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011406 }
11407 try {
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011408 if (DEBUG_BROADCAST_LIGHT) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011409 int seq = r.intent.getIntExtra("seq", -1);
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011410 Log.i(TAG, "Delivering to " + filter.receiverList.app
11411 + " (seq=" + seq + "): " + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011412 }
11413 performReceive(filter.receiverList.app, filter.receiverList.receiver,
11414 new Intent(r.intent), r.resultCode,
11415 r.resultData, r.resultExtras, r.ordered);
11416 if (ordered) {
11417 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
11418 }
11419 } catch (RemoteException e) {
11420 Log.w(TAG, "Failure sending broadcast " + r.intent, e);
11421 if (ordered) {
11422 r.receiver = null;
11423 r.curFilter = null;
11424 filter.receiverList.curBroadcast = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011425 if (filter.receiverList.app != null) {
11426 filter.receiverList.app.curReceiver = null;
11427 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011428 }
11429 }
11430 }
11431 }
11432
11433 private final void processNextBroadcast(boolean fromMsg) {
11434 synchronized(this) {
11435 BroadcastRecord r;
11436
11437 if (DEBUG_BROADCAST) Log.v(TAG, "processNextBroadcast: "
11438 + mParallelBroadcasts.size() + " broadcasts, "
11439 + mOrderedBroadcasts.size() + " serialized broadcasts");
11440
11441 updateCpuStats();
11442
11443 if (fromMsg) {
11444 mBroadcastsScheduled = false;
11445 }
11446
11447 // First, deliver any non-serialized broadcasts right away.
11448 while (mParallelBroadcasts.size() > 0) {
11449 r = mParallelBroadcasts.remove(0);
11450 final int N = r.receivers.size();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011451 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing parallel broadcast "
11452 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011453 for (int i=0; i<N; i++) {
11454 Object target = r.receivers.get(i);
11455 if (DEBUG_BROADCAST) Log.v(TAG,
11456 "Delivering non-serialized to registered "
11457 + target + ": " + r);
11458 deliverToRegisteredReceiver(r, (BroadcastFilter)target, false);
11459 }
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011460 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Done with parallel broadcast "
11461 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011462 }
11463
11464 // Now take care of the next serialized one...
11465
11466 // If we are waiting for a process to come up to handle the next
11467 // broadcast, then do nothing at this point. Just in case, we
11468 // check that the process we're waiting for still exists.
11469 if (mPendingBroadcast != null) {
11470 Log.i(TAG, "processNextBroadcast: waiting for "
11471 + mPendingBroadcast.curApp);
11472
11473 boolean isDead;
11474 synchronized (mPidsSelfLocked) {
11475 isDead = (mPidsSelfLocked.get(mPendingBroadcast.curApp.pid) == null);
11476 }
11477 if (!isDead) {
11478 // It's still alive, so keep waiting
11479 return;
11480 } else {
11481 Log.w(TAG, "pending app " + mPendingBroadcast.curApp
11482 + " died before responding to broadcast");
11483 mPendingBroadcast = null;
11484 }
11485 }
11486
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011487 boolean looped = false;
11488
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011489 do {
11490 if (mOrderedBroadcasts.size() == 0) {
11491 // No more broadcasts pending, so all done!
11492 scheduleAppGcsLocked();
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011493 if (looped) {
11494 // If we had finished the last ordered broadcast, then
11495 // make sure all processes have correct oom and sched
11496 // adjustments.
11497 updateOomAdjLocked();
11498 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011499 return;
11500 }
11501 r = mOrderedBroadcasts.get(0);
11502 boolean forceReceive = false;
11503
11504 // Ensure that even if something goes awry with the timeout
11505 // detection, we catch "hung" broadcasts here, discard them,
11506 // and continue to make progress.
11507 int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
11508 long now = SystemClock.uptimeMillis();
11509 if (r.dispatchTime > 0) {
11510 if ((numReceivers > 0) &&
11511 (now > r.dispatchTime + (2*BROADCAST_TIMEOUT*numReceivers))) {
11512 Log.w(TAG, "Hung broadcast discarded after timeout failure:"
11513 + " now=" + now
11514 + " dispatchTime=" + r.dispatchTime
11515 + " startTime=" + r.startTime
11516 + " intent=" + r.intent
11517 + " numReceivers=" + numReceivers
11518 + " nextReceiver=" + r.nextReceiver
11519 + " state=" + r.state);
11520 broadcastTimeout(); // forcibly finish this broadcast
11521 forceReceive = true;
11522 r.state = BroadcastRecord.IDLE;
11523 }
11524 }
11525
11526 if (r.state != BroadcastRecord.IDLE) {
11527 if (DEBUG_BROADCAST) Log.d(TAG,
11528 "processNextBroadcast() called when not idle (state="
11529 + r.state + ")");
11530 return;
11531 }
11532
11533 if (r.receivers == null || r.nextReceiver >= numReceivers
11534 || r.resultAbort || forceReceive) {
11535 // No more receivers for this broadcast! Send the final
11536 // result if requested...
11537 if (r.resultTo != null) {
11538 try {
11539 if (DEBUG_BROADCAST) {
11540 int seq = r.intent.getIntExtra("seq", -1);
11541 Log.i(TAG, "Finishing broadcast " + r.intent.getAction()
11542 + " seq=" + seq + " app=" + r.callerApp);
11543 }
11544 performReceive(r.callerApp, r.resultTo,
11545 new Intent(r.intent), r.resultCode,
11546 r.resultData, r.resultExtras, false);
11547 } catch (RemoteException e) {
11548 Log.w(TAG, "Failure sending broadcast result of " + r.intent, e);
11549 }
11550 }
11551
11552 if (DEBUG_BROADCAST) Log.v(TAG, "Cancelling BROADCAST_TIMEOUT_MSG");
11553 mHandler.removeMessages(BROADCAST_TIMEOUT_MSG);
11554
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011555 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Finished with ordered broadcast "
11556 + r);
11557
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011558 // ... and on to the next...
11559 mOrderedBroadcasts.remove(0);
11560 r = null;
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011561 looped = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011562 continue;
11563 }
11564 } while (r == null);
11565
11566 // Get the next receiver...
11567 int recIdx = r.nextReceiver++;
11568
11569 // Keep track of when this receiver started, and make sure there
11570 // is a timeout message pending to kill it if need be.
11571 r.startTime = SystemClock.uptimeMillis();
11572 if (recIdx == 0) {
11573 r.dispatchTime = r.startTime;
11574
Dianne Hackborn82f3f002009-06-16 18:49:05 -070011575 if (DEBUG_BROADCAST_LIGHT) Log.v(TAG, "Processing ordered broadcast "
11576 + r);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011577 if (DEBUG_BROADCAST) Log.v(TAG,
11578 "Submitting BROADCAST_TIMEOUT_MSG for "
11579 + (r.startTime + BROADCAST_TIMEOUT));
11580 Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG);
11581 mHandler.sendMessageAtTime(msg, r.startTime+BROADCAST_TIMEOUT);
11582 }
11583
11584 Object nextReceiver = r.receivers.get(recIdx);
11585 if (nextReceiver instanceof BroadcastFilter) {
11586 // Simple case: this is a registered receiver who gets
11587 // a direct call.
11588 BroadcastFilter filter = (BroadcastFilter)nextReceiver;
11589 if (DEBUG_BROADCAST) Log.v(TAG,
11590 "Delivering serialized to registered "
11591 + filter + ": " + r);
11592 deliverToRegisteredReceiver(r, filter, r.ordered);
11593 if (r.receiver == null || !r.ordered) {
11594 // The receiver has already finished, so schedule to
11595 // process the next one.
11596 r.state = BroadcastRecord.IDLE;
11597 scheduleBroadcastsLocked();
11598 }
11599 return;
11600 }
11601
11602 // Hard case: need to instantiate the receiver, possibly
11603 // starting its application process to host it.
11604
11605 ResolveInfo info =
11606 (ResolveInfo)nextReceiver;
11607
11608 boolean skip = false;
11609 int perm = checkComponentPermission(info.activityInfo.permission,
11610 r.callingPid, r.callingUid,
11611 info.activityInfo.exported
11612 ? -1 : info.activityInfo.applicationInfo.uid);
11613 if (perm != PackageManager.PERMISSION_GRANTED) {
11614 Log.w(TAG, "Permission Denial: broadcasting "
11615 + r.intent.toString()
11616 + " from " + r.callerPackage + " (pid=" + r.callingPid
11617 + ", uid=" + r.callingUid + ")"
11618 + " requires " + info.activityInfo.permission
11619 + " due to receiver " + info.activityInfo.packageName
11620 + "/" + info.activityInfo.name);
11621 skip = true;
11622 }
11623 if (r.callingUid != Process.SYSTEM_UID &&
11624 r.requiredPermission != null) {
11625 try {
11626 perm = ActivityThread.getPackageManager().
11627 checkPermission(r.requiredPermission,
11628 info.activityInfo.applicationInfo.packageName);
11629 } catch (RemoteException e) {
11630 perm = PackageManager.PERMISSION_DENIED;
11631 }
11632 if (perm != PackageManager.PERMISSION_GRANTED) {
11633 Log.w(TAG, "Permission Denial: receiving "
11634 + r.intent + " to "
11635 + info.activityInfo.applicationInfo.packageName
11636 + " requires " + r.requiredPermission
11637 + " due to sender " + r.callerPackage
11638 + " (uid " + r.callingUid + ")");
11639 skip = true;
11640 }
11641 }
11642 if (r.curApp != null && r.curApp.crashing) {
11643 // If the target process is crashing, just skip it.
11644 skip = true;
11645 }
11646
11647 if (skip) {
11648 r.receiver = null;
11649 r.curFilter = null;
11650 r.state = BroadcastRecord.IDLE;
11651 scheduleBroadcastsLocked();
11652 return;
11653 }
11654
11655 r.state = BroadcastRecord.APP_RECEIVE;
11656 String targetProcess = info.activityInfo.processName;
11657 r.curComponent = new ComponentName(
11658 info.activityInfo.applicationInfo.packageName,
11659 info.activityInfo.name);
11660 r.curReceiver = info.activityInfo;
11661
11662 // Is this receiver's application already running?
11663 ProcessRecord app = getProcessRecordLocked(targetProcess,
11664 info.activityInfo.applicationInfo.uid);
11665 if (app != null && app.thread != null) {
11666 try {
11667 processCurBroadcastLocked(r, app);
11668 return;
11669 } catch (RemoteException e) {
11670 Log.w(TAG, "Exception when sending broadcast to "
11671 + r.curComponent, e);
11672 }
11673
11674 // If a dead object exception was thrown -- fall through to
11675 // restart the application.
11676 }
11677
11678 // Not running -- get it started, and enqueue this history record
11679 // to be executed when the app comes up.
11680 if ((r.curApp=startProcessLocked(targetProcess,
11681 info.activityInfo.applicationInfo, true,
11682 r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
11683 "broadcast", r.curComponent)) == null) {
11684 // Ah, this recipient is unavailable. Finish it if necessary,
11685 // and mark the broadcast record as ready for the next.
11686 Log.w(TAG, "Unable to launch app "
11687 + info.activityInfo.applicationInfo.packageName + "/"
11688 + info.activityInfo.applicationInfo.uid + " for broadcast "
11689 + r.intent + ": process is bad");
11690 logBroadcastReceiverDiscard(r);
11691 finishReceiverLocked(r.receiver, r.resultCode, r.resultData,
11692 r.resultExtras, r.resultAbort, true);
11693 scheduleBroadcastsLocked();
11694 r.state = BroadcastRecord.IDLE;
11695 return;
11696 }
11697
11698 mPendingBroadcast = r;
11699 }
11700 }
11701
11702 // =========================================================
11703 // INSTRUMENTATION
11704 // =========================================================
11705
11706 public boolean startInstrumentation(ComponentName className,
11707 String profileFile, int flags, Bundle arguments,
11708 IInstrumentationWatcher watcher) {
11709 // Refuse possible leaked file descriptors
11710 if (arguments != null && arguments.hasFileDescriptors()) {
11711 throw new IllegalArgumentException("File descriptors passed in Bundle");
11712 }
11713
11714 synchronized(this) {
11715 InstrumentationInfo ii = null;
11716 ApplicationInfo ai = null;
11717 try {
11718 ii = mContext.getPackageManager().getInstrumentationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011719 className, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011720 ai = mContext.getPackageManager().getApplicationInfo(
Dianne Hackborn1655be42009-05-08 14:29:01 -070011721 ii.targetPackage, STOCK_PM_FLAGS);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011722 } catch (PackageManager.NameNotFoundException e) {
11723 }
11724 if (ii == null) {
11725 reportStartInstrumentationFailure(watcher, className,
11726 "Unable to find instrumentation info for: " + className);
11727 return false;
11728 }
11729 if (ai == null) {
11730 reportStartInstrumentationFailure(watcher, className,
11731 "Unable to find instrumentation target package: " + ii.targetPackage);
11732 return false;
11733 }
11734
11735 int match = mContext.getPackageManager().checkSignatures(
11736 ii.targetPackage, ii.packageName);
11737 if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
11738 String msg = "Permission Denial: starting instrumentation "
11739 + className + " from pid="
11740 + Binder.getCallingPid()
11741 + ", uid=" + Binder.getCallingPid()
11742 + " not allowed because package " + ii.packageName
11743 + " does not have a signature matching the target "
11744 + ii.targetPackage;
11745 reportStartInstrumentationFailure(watcher, className, msg);
11746 throw new SecurityException(msg);
11747 }
11748
11749 final long origId = Binder.clearCallingIdentity();
11750 uninstallPackageLocked(ii.targetPackage, -1, true);
11751 ProcessRecord app = addAppLocked(ai);
11752 app.instrumentationClass = className;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011753 app.instrumentationInfo = ai;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011754 app.instrumentationProfileFile = profileFile;
11755 app.instrumentationArguments = arguments;
11756 app.instrumentationWatcher = watcher;
11757 app.instrumentationResultClass = className;
11758 Binder.restoreCallingIdentity(origId);
11759 }
11760
11761 return true;
11762 }
11763
11764 /**
11765 * Report errors that occur while attempting to start Instrumentation. Always writes the
11766 * error to the logs, but if somebody is watching, send the report there too. This enables
11767 * the "am" command to report errors with more information.
11768 *
11769 * @param watcher The IInstrumentationWatcher. Null if there isn't one.
11770 * @param cn The component name of the instrumentation.
11771 * @param report The error report.
11772 */
11773 private void reportStartInstrumentationFailure(IInstrumentationWatcher watcher,
11774 ComponentName cn, String report) {
11775 Log.w(TAG, report);
11776 try {
11777 if (watcher != null) {
11778 Bundle results = new Bundle();
11779 results.putString(Instrumentation.REPORT_KEY_IDENTIFIER, "ActivityManagerService");
11780 results.putString("Error", report);
11781 watcher.instrumentationStatus(cn, -1, results);
11782 }
11783 } catch (RemoteException e) {
11784 Log.w(TAG, e);
11785 }
11786 }
11787
11788 void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
11789 if (app.instrumentationWatcher != null) {
11790 try {
11791 // NOTE: IInstrumentationWatcher *must* be oneway here
11792 app.instrumentationWatcher.instrumentationFinished(
11793 app.instrumentationClass,
11794 resultCode,
11795 results);
11796 } catch (RemoteException e) {
11797 }
11798 }
11799 app.instrumentationWatcher = null;
11800 app.instrumentationClass = null;
Dianne Hackborn1655be42009-05-08 14:29:01 -070011801 app.instrumentationInfo = null;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011802 app.instrumentationProfileFile = null;
11803 app.instrumentationArguments = null;
11804
11805 uninstallPackageLocked(app.processName, -1, false);
11806 }
11807
11808 public void finishInstrumentation(IApplicationThread target,
11809 int resultCode, Bundle results) {
11810 // Refuse possible leaked file descriptors
11811 if (results != null && results.hasFileDescriptors()) {
11812 throw new IllegalArgumentException("File descriptors passed in Intent");
11813 }
11814
11815 synchronized(this) {
11816 ProcessRecord app = getRecordForAppLocked(target);
11817 if (app == null) {
11818 Log.w(TAG, "finishInstrumentation: no app for " + target);
11819 return;
11820 }
11821 final long origId = Binder.clearCallingIdentity();
11822 finishInstrumentationLocked(app, resultCode, results);
11823 Binder.restoreCallingIdentity(origId);
11824 }
11825 }
11826
11827 // =========================================================
11828 // CONFIGURATION
11829 // =========================================================
11830
11831 public ConfigurationInfo getDeviceConfigurationInfo() {
11832 ConfigurationInfo config = new ConfigurationInfo();
11833 synchronized (this) {
11834 config.reqTouchScreen = mConfiguration.touchscreen;
11835 config.reqKeyboardType = mConfiguration.keyboard;
11836 config.reqNavigation = mConfiguration.navigation;
11837 if (mConfiguration.navigation != Configuration.NAVIGATION_NONAV) {
11838 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV;
11839 }
11840 if (mConfiguration.keyboard != Configuration.KEYBOARD_UNDEFINED) {
11841 config.reqInputFeatures |= ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD;
11842 }
11843 }
11844 return config;
11845 }
11846
11847 public Configuration getConfiguration() {
11848 Configuration ci;
11849 synchronized(this) {
11850 ci = new Configuration(mConfiguration);
11851 }
11852 return ci;
11853 }
11854
11855 public void updateConfiguration(Configuration values) {
11856 enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
11857 "updateConfiguration()");
11858
11859 synchronized(this) {
11860 if (values == null && mWindowManager != null) {
11861 // sentinel: fetch the current configuration from the window manager
11862 values = mWindowManager.computeNewConfiguration();
11863 }
11864
11865 final long origId = Binder.clearCallingIdentity();
11866 updateConfigurationLocked(values, null);
11867 Binder.restoreCallingIdentity(origId);
11868 }
11869 }
11870
11871 /**
11872 * Do either or both things: (1) change the current configuration, and (2)
11873 * make sure the given activity is running with the (now) current
11874 * configuration. Returns true if the activity has been left running, or
11875 * false if <var>starting</var> is being destroyed to match the new
11876 * configuration.
11877 */
11878 public boolean updateConfigurationLocked(Configuration values,
11879 HistoryRecord starting) {
11880 int changes = 0;
11881
11882 boolean kept = true;
11883
11884 if (values != null) {
11885 Configuration newConfig = new Configuration(mConfiguration);
11886 changes = newConfig.updateFrom(values);
11887 if (changes != 0) {
11888 if (DEBUG_SWITCH) {
11889 Log.i(TAG, "Updating configuration to: " + values);
11890 }
11891
11892 EventLog.writeEvent(LOG_CONFIGURATION_CHANGED, changes);
11893
11894 if (values.locale != null) {
11895 saveLocaleLocked(values.locale,
11896 !values.locale.equals(mConfiguration.locale),
11897 values.userSetLocale);
11898 }
11899
11900 mConfiguration = newConfig;
11901
11902 Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
11903 msg.obj = new Configuration(mConfiguration);
11904 mHandler.sendMessage(msg);
11905
11906 final int N = mLRUProcesses.size();
11907 for (int i=0; i<N; i++) {
11908 ProcessRecord app = mLRUProcesses.get(i);
11909 try {
11910 if (app.thread != null) {
11911 app.thread.scheduleConfigurationChanged(mConfiguration);
11912 }
11913 } catch (Exception e) {
11914 }
11915 }
11916 Intent intent = new Intent(Intent.ACTION_CONFIGURATION_CHANGED);
11917 broadcastIntentLocked(null, null, intent, null, null, 0, null, null,
11918 null, false, false, MY_PID, Process.SYSTEM_UID);
Dianne Hackbornde7faf62009-06-30 13:27:30 -070011919
11920 AttributeCache ac = AttributeCache.instance();
11921 if (ac != null) {
11922 ac.updateConfiguration(mConfiguration);
11923 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080011924 }
11925 }
11926
11927 if (changes != 0 && starting == null) {
11928 // If the configuration changed, and the caller is not already
11929 // in the process of starting an activity, then find the top
11930 // activity to check if its configuration needs to change.
11931 starting = topRunningActivityLocked(null);
11932 }
11933
11934 if (starting != null) {
11935 kept = ensureActivityConfigurationLocked(starting, changes);
11936 if (kept) {
11937 // If this didn't result in the starting activity being
11938 // destroyed, then we need to make sure at this point that all
11939 // other activities are made visible.
11940 if (DEBUG_SWITCH) Log.i(TAG, "Config didn't destroy " + starting
11941 + ", ensuring others are correct.");
11942 ensureActivitiesVisibleLocked(starting, changes);
11943 }
11944 }
11945
11946 return kept;
11947 }
11948
11949 private final boolean relaunchActivityLocked(HistoryRecord r,
11950 int changes, boolean andResume) {
11951 List<ResultInfo> results = null;
11952 List<Intent> newIntents = null;
11953 if (andResume) {
11954 results = r.results;
11955 newIntents = r.newIntents;
11956 }
11957 if (DEBUG_SWITCH) Log.v(TAG, "Relaunching: " + r
11958 + " with results=" + results + " newIntents=" + newIntents
11959 + " andResume=" + andResume);
11960 EventLog.writeEvent(andResume ? LOG_AM_RELAUNCH_RESUME_ACTIVITY
11961 : LOG_AM_RELAUNCH_ACTIVITY, System.identityHashCode(r),
11962 r.task.taskId, r.shortComponentName);
11963
11964 r.startFreezingScreenLocked(r.app, 0);
11965
11966 try {
11967 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
11968 r.app.thread.scheduleRelaunchActivity(r, results, newIntents,
11969 changes, !andResume);
11970 // Note: don't need to call pauseIfSleepingLocked() here, because
11971 // the caller will only pass in 'andResume' if this activity is
11972 // currently resumed, which implies we aren't sleeping.
11973 } catch (RemoteException e) {
11974 return false;
11975 }
11976
11977 if (andResume) {
11978 r.results = null;
11979 r.newIntents = null;
11980 }
11981
11982 return true;
11983 }
11984
11985 /**
11986 * Make sure the given activity matches the current configuration. Returns
11987 * false if the activity had to be destroyed. Returns true if the
11988 * configuration is the same, or the activity will remain running as-is
11989 * for whatever reason. Ensures the HistoryRecord is updated with the
11990 * correct configuration and all other bookkeeping is handled.
11991 */
11992 private final boolean ensureActivityConfigurationLocked(HistoryRecord r,
11993 int globalChanges) {
11994 if (DEBUG_SWITCH) Log.i(TAG, "Ensuring correct configuration: " + r);
11995
11996 // Short circuit: if the two configurations are the exact same
11997 // object (the common case), then there is nothing to do.
11998 Configuration newConfig = mConfiguration;
11999 if (r.configuration == newConfig) {
12000 if (DEBUG_SWITCH) Log.i(TAG, "Configuration unchanged in " + r);
12001 return true;
12002 }
12003
12004 // We don't worry about activities that are finishing.
12005 if (r.finishing) {
12006 if (DEBUG_SWITCH) Log.i(TAG,
12007 "Configuration doesn't matter in finishing " + r);
12008 r.stopFreezingScreenLocked(false);
12009 return true;
12010 }
12011
12012 // Okay we now are going to make this activity have the new config.
12013 // But then we need to figure out how it needs to deal with that.
12014 Configuration oldConfig = r.configuration;
12015 r.configuration = newConfig;
12016
12017 // If the activity isn't currently running, just leave the new
12018 // configuration and it will pick that up next time it starts.
12019 if (r.app == null || r.app.thread == null) {
12020 if (DEBUG_SWITCH) Log.i(TAG,
12021 "Configuration doesn't matter not running " + r);
12022 r.stopFreezingScreenLocked(false);
12023 return true;
12024 }
12025
12026 // If the activity isn't persistent, there is a chance we will
12027 // need to restart it.
12028 if (!r.persistent) {
12029
12030 // Figure out what has changed between the two configurations.
12031 int changes = oldConfig.diff(newConfig);
12032 if (DEBUG_SWITCH) {
12033 Log.i(TAG, "Checking to restart " + r.info.name + ": changed=0x"
12034 + Integer.toHexString(changes) + ", handles=0x"
12035 + Integer.toHexString(r.info.configChanges));
12036 }
12037 if ((changes&(~r.info.configChanges)) != 0) {
12038 // Aha, the activity isn't handling the change, so DIE DIE DIE.
12039 r.configChangeFlags |= changes;
12040 r.startFreezingScreenLocked(r.app, globalChanges);
12041 if (r.app == null || r.app.thread == null) {
12042 if (DEBUG_SWITCH) Log.i(TAG, "Switch is destroying non-running " + r);
12043 destroyActivityLocked(r, true);
12044 } else if (r.state == ActivityState.PAUSING) {
12045 // A little annoying: we are waiting for this activity to
12046 // finish pausing. Let's not do anything now, but just
12047 // flag that it needs to be restarted when done pausing.
12048 r.configDestroy = true;
12049 return true;
12050 } else if (r.state == ActivityState.RESUMED) {
12051 // Try to optimize this case: the configuration is changing
12052 // and we need to restart the top, resumed activity.
12053 // Instead of doing the normal handshaking, just say
12054 // "restart!".
12055 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting resumed " + r);
12056 relaunchActivityLocked(r, r.configChangeFlags, true);
12057 r.configChangeFlags = 0;
12058 } else {
12059 if (DEBUG_SWITCH) Log.i(TAG, "Switch is restarting non-resumed " + r);
12060 relaunchActivityLocked(r, r.configChangeFlags, false);
12061 r.configChangeFlags = 0;
12062 }
12063
12064 // All done... tell the caller we weren't able to keep this
12065 // activity around.
12066 return false;
12067 }
12068 }
12069
12070 // Default case: the activity can handle this new configuration, so
12071 // hand it over. Note that we don't need to give it the new
12072 // configuration, since we always send configuration changes to all
12073 // process when they happen so it can just use whatever configuration
12074 // it last got.
12075 if (r.app != null && r.app.thread != null) {
12076 try {
12077 r.app.thread.scheduleActivityConfigurationChanged(r);
12078 } catch (RemoteException e) {
12079 // If process died, whatever.
12080 }
12081 }
12082 r.stopFreezingScreenLocked(false);
12083
12084 return true;
12085 }
12086
12087 /**
12088 * Save the locale. You must be inside a synchronized (this) block.
12089 */
12090 private void saveLocaleLocked(Locale l, boolean isDiff, boolean isPersist) {
12091 if(isDiff) {
12092 SystemProperties.set("user.language", l.getLanguage());
12093 SystemProperties.set("user.region", l.getCountry());
12094 }
12095
12096 if(isPersist) {
12097 SystemProperties.set("persist.sys.language", l.getLanguage());
12098 SystemProperties.set("persist.sys.country", l.getCountry());
12099 SystemProperties.set("persist.sys.localevar", l.getVariant());
12100 }
12101 }
12102
12103 // =========================================================
12104 // LIFETIME MANAGEMENT
12105 // =========================================================
12106
12107 private final int computeOomAdjLocked(
12108 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12109 if (mAdjSeq == app.adjSeq) {
12110 // This adjustment has already been computed.
12111 return app.curAdj;
12112 }
12113
12114 if (app.thread == null) {
12115 app.adjSeq = mAdjSeq;
12116 return (app.curAdj=EMPTY_APP_ADJ);
12117 }
12118
12119 app.isForeground = false;
12120
The Android Open Source Project4df24232009-03-05 14:34:35 -080012121 // Determine the importance of the process, starting with most
12122 // important to least, and assign an appropriate OOM adjustment.
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012123 int adj;
12124 int N;
12125 if (app == TOP_APP || app.instrumentationClass != null
12126 || app.persistentActivities > 0) {
12127 // The last app on the list is the foreground app.
12128 adj = FOREGROUND_APP_ADJ;
12129 app.isForeground = true;
12130 } else if (app.curReceiver != null ||
12131 (mPendingBroadcast != null && mPendingBroadcast.curApp == app)) {
12132 // An app that is currently receiving a broadcast also
12133 // counts as being in the foreground.
12134 adj = FOREGROUND_APP_ADJ;
12135 } else if (app.executingServices.size() > 0) {
12136 // An app that is currently executing a service callback also
12137 // counts as being in the foreground.
12138 adj = FOREGROUND_APP_ADJ;
12139 } else if (app.foregroundServices || app.forcingToForeground != null) {
12140 // The user is aware of this app, so make it visible.
12141 adj = VISIBLE_APP_ADJ;
The Android Open Source Project4df24232009-03-05 14:34:35 -080012142 } else if (app == mHomeProcess) {
12143 // This process is hosting what we currently consider to be the
12144 // home app, so we don't want to let it go into the background.
12145 adj = HOME_APP_ADJ;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012146 } else if ((N=app.activities.size()) != 0) {
12147 // This app is in the background with paused activities.
12148 adj = hiddenAdj;
12149 for (int j=0; j<N; j++) {
12150 if (((HistoryRecord)app.activities.get(j)).visible) {
12151 // This app has a visible activity!
12152 adj = VISIBLE_APP_ADJ;
12153 break;
12154 }
12155 }
12156 } else {
12157 // A very not-needed process.
12158 adj = EMPTY_APP_ADJ;
12159 }
12160
The Android Open Source Project4df24232009-03-05 14:34:35 -080012161 // By default, we use the computed adjustment. It may be changed if
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012162 // there are applications dependent on our services or providers, but
12163 // this gives us a baseline and makes sure we don't get into an
12164 // infinite recursion.
12165 app.adjSeq = mAdjSeq;
12166 app.curRawAdj = adj;
12167 app.curAdj = adj <= app.maxAdj ? adj : app.maxAdj;
12168
Christopher Tate6fa95972009-06-05 18:43:55 -070012169 if (mBackupTarget != null && app == mBackupTarget.app) {
12170 // If possible we want to avoid killing apps while they're being backed up
12171 if (adj > BACKUP_APP_ADJ) {
12172 if (DEBUG_BACKUP) Log.v(TAG, "oom BACKUP_APP_ADJ for " + app);
12173 adj = BACKUP_APP_ADJ;
12174 }
12175 }
12176
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012177 if (app.services.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12178 // If this process has active services running in it, we would
12179 // like to avoid killing it unless it would prevent the current
12180 // application from running.
12181 if (adj > hiddenAdj) {
12182 adj = hiddenAdj;
12183 }
12184 final long now = SystemClock.uptimeMillis();
12185 // This process is more important if the top activity is
12186 // bound to the service.
12187 Iterator jt = app.services.iterator();
12188 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12189 ServiceRecord s = (ServiceRecord)jt.next();
12190 if (s.startRequested) {
12191 if (now < (s.lastActivity+MAX_SERVICE_INACTIVITY)) {
12192 // This service has seen some activity within
12193 // recent memory, so we will keep its process ahead
12194 // of the background processes.
12195 if (adj > SECONDARY_SERVER_ADJ) {
12196 adj = SECONDARY_SERVER_ADJ;
12197 }
12198 } else {
12199 // This service has been inactive for too long, just
12200 // put it with the rest of the background processes.
12201 if (adj > hiddenAdj) {
12202 adj = hiddenAdj;
12203 }
12204 }
12205 }
12206 if (s.connections.size() > 0 && adj > FOREGROUND_APP_ADJ) {
12207 Iterator<ConnectionRecord> kt
12208 = s.connections.values().iterator();
12209 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12210 // XXX should compute this based on the max of
12211 // all connected clients.
12212 ConnectionRecord cr = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012213 if (cr.binding.client == app) {
12214 // Binding to ourself is not interesting.
12215 continue;
12216 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012217 if ((cr.flags&Context.BIND_AUTO_CREATE) != 0) {
12218 ProcessRecord client = cr.binding.client;
12219 int myHiddenAdj = hiddenAdj;
12220 if (myHiddenAdj > client.hiddenAdj) {
12221 if (client.hiddenAdj > VISIBLE_APP_ADJ) {
12222 myHiddenAdj = client.hiddenAdj;
12223 } else {
12224 myHiddenAdj = VISIBLE_APP_ADJ;
12225 }
12226 }
12227 int clientAdj = computeOomAdjLocked(
12228 client, myHiddenAdj, TOP_APP);
12229 if (adj > clientAdj) {
12230 adj = clientAdj > VISIBLE_APP_ADJ
12231 ? clientAdj : VISIBLE_APP_ADJ;
12232 }
12233 }
12234 HistoryRecord a = cr.activity;
12235 //if (a != null) {
12236 // Log.i(TAG, "Connection to " + a ": state=" + a.state);
12237 //}
12238 if (a != null && adj > FOREGROUND_APP_ADJ &&
12239 (a.state == ActivityState.RESUMED
12240 || a.state == ActivityState.PAUSING)) {
12241 adj = FOREGROUND_APP_ADJ;
12242 }
12243 }
12244 }
12245 }
12246 }
12247
12248 if (app.pubProviders.size() != 0 && adj > FOREGROUND_APP_ADJ) {
12249 // If this process has published any content providers, then
12250 // its adjustment makes it at least as important as any of the
12251 // processes using those providers, and no less important than
12252 // CONTENT_PROVIDER_ADJ, which is just shy of EMPTY.
12253 if (adj > CONTENT_PROVIDER_ADJ) {
12254 adj = CONTENT_PROVIDER_ADJ;
12255 }
12256 Iterator jt = app.pubProviders.values().iterator();
12257 while (jt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12258 ContentProviderRecord cpr = (ContentProviderRecord)jt.next();
12259 if (cpr.clients.size() != 0) {
12260 Iterator<ProcessRecord> kt = cpr.clients.iterator();
12261 while (kt.hasNext() && adj > FOREGROUND_APP_ADJ) {
12262 ProcessRecord client = kt.next();
The Android Open Source Project10592532009-03-18 17:39:46 -070012263 if (client == app) {
12264 // Being our own client is not interesting.
12265 continue;
12266 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012267 int myHiddenAdj = hiddenAdj;
12268 if (myHiddenAdj > client.hiddenAdj) {
12269 if (client.hiddenAdj > FOREGROUND_APP_ADJ) {
12270 myHiddenAdj = client.hiddenAdj;
12271 } else {
12272 myHiddenAdj = FOREGROUND_APP_ADJ;
12273 }
12274 }
12275 int clientAdj = computeOomAdjLocked(
12276 client, myHiddenAdj, TOP_APP);
12277 if (adj > clientAdj) {
12278 adj = clientAdj > FOREGROUND_APP_ADJ
12279 ? clientAdj : FOREGROUND_APP_ADJ;
12280 }
12281 }
12282 }
12283 // If the provider has external (non-framework) process
12284 // dependencies, ensure that its adjustment is at least
12285 // FOREGROUND_APP_ADJ.
12286 if (cpr.externals != 0) {
12287 if (adj > FOREGROUND_APP_ADJ) {
12288 adj = FOREGROUND_APP_ADJ;
12289 }
12290 }
12291 }
12292 }
12293
12294 app.curRawAdj = adj;
12295
12296 //Log.i(TAG, "OOM ADJ " + app + ": pid=" + app.pid +
12297 // " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
12298 if (adj > app.maxAdj) {
12299 adj = app.maxAdj;
12300 }
12301
12302 app.curAdj = adj;
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012303 app.curSchedGroup = (adj > VISIBLE_APP_ADJ && !app.persistent)
12304 ? Process.THREAD_GROUP_BG_NONINTERACTIVE
12305 : Process.THREAD_GROUP_DEFAULT;
12306
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012307 return adj;
12308 }
12309
12310 /**
12311 * Ask a given process to GC right now.
12312 */
12313 final void performAppGcLocked(ProcessRecord app) {
12314 try {
12315 app.lastRequestedGc = SystemClock.uptimeMillis();
12316 if (app.thread != null) {
12317 app.thread.processInBackground();
12318 }
12319 } catch (Exception e) {
12320 // whatever.
12321 }
12322 }
12323
12324 /**
12325 * Returns true if things are idle enough to perform GCs.
12326 */
12327 private final boolean canGcNow() {
12328 return mParallelBroadcasts.size() == 0
12329 && mOrderedBroadcasts.size() == 0
12330 && (mSleeping || (mResumedActivity != null &&
12331 mResumedActivity.idle));
12332 }
12333
12334 /**
12335 * Perform GCs on all processes that are waiting for it, but only
12336 * if things are idle.
12337 */
12338 final void performAppGcsLocked() {
12339 final int N = mProcessesToGc.size();
12340 if (N <= 0) {
12341 return;
12342 }
12343 if (canGcNow()) {
12344 while (mProcessesToGc.size() > 0) {
12345 ProcessRecord proc = mProcessesToGc.remove(0);
12346 if (proc.curRawAdj > VISIBLE_APP_ADJ) {
12347 // To avoid spamming the system, we will GC processes one
12348 // at a time, waiting a few seconds between each.
12349 performAppGcLocked(proc);
12350 scheduleAppGcsLocked();
12351 return;
12352 }
12353 }
12354 }
12355 }
12356
12357 /**
12358 * If all looks good, perform GCs on all processes waiting for them.
12359 */
12360 final void performAppGcsIfAppropriateLocked() {
12361 if (canGcNow()) {
12362 performAppGcsLocked();
12363 return;
12364 }
12365 // Still not idle, wait some more.
12366 scheduleAppGcsLocked();
12367 }
12368
12369 /**
12370 * Schedule the execution of all pending app GCs.
12371 */
12372 final void scheduleAppGcsLocked() {
12373 mHandler.removeMessages(GC_BACKGROUND_PROCESSES_MSG);
12374 Message msg = mHandler.obtainMessage(GC_BACKGROUND_PROCESSES_MSG);
12375 mHandler.sendMessageDelayed(msg, GC_TIMEOUT);
12376 }
12377
12378 /**
12379 * Set up to ask a process to GC itself. This will either do it
12380 * immediately, or put it on the list of processes to gc the next
12381 * time things are idle.
12382 */
12383 final void scheduleAppGcLocked(ProcessRecord app) {
12384 long now = SystemClock.uptimeMillis();
12385 if ((app.lastRequestedGc+5000) > now) {
12386 return;
12387 }
12388 if (!mProcessesToGc.contains(app)) {
12389 mProcessesToGc.add(app);
12390 scheduleAppGcsLocked();
12391 }
12392 }
12393
12394 private final boolean updateOomAdjLocked(
12395 ProcessRecord app, int hiddenAdj, ProcessRecord TOP_APP) {
12396 app.hiddenAdj = hiddenAdj;
12397
12398 if (app.thread == null) {
12399 return true;
12400 }
12401
12402 int adj = computeOomAdjLocked(app, hiddenAdj, TOP_APP);
12403
12404 //Log.i(TAG, "Computed adj " + adj + " for app " + app.processName);
12405 //Thread priority adjustment is disabled out to see
12406 //how the kernel scheduler performs.
12407 if (false) {
12408 if (app.pid != 0 && app.isForeground != app.setIsForeground) {
12409 app.setIsForeground = app.isForeground;
12410 if (app.pid != MY_PID) {
12411 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG, "Setting priority of " + app
12412 + " to " + (app.isForeground
12413 ? Process.THREAD_PRIORITY_FOREGROUND
12414 : Process.THREAD_PRIORITY_DEFAULT));
12415 try {
12416 Process.setThreadPriority(app.pid, app.isForeground
12417 ? Process.THREAD_PRIORITY_FOREGROUND
12418 : Process.THREAD_PRIORITY_DEFAULT);
12419 } catch (RuntimeException e) {
12420 Log.w(TAG, "Exception trying to set priority of application thread "
12421 + app.pid, e);
12422 }
12423 }
12424 }
12425 }
12426 if (app.pid != 0 && app.pid != MY_PID) {
12427 if (app.curRawAdj != app.setRawAdj) {
12428 if (app.curRawAdj > FOREGROUND_APP_ADJ
12429 && app.setRawAdj <= FOREGROUND_APP_ADJ) {
12430 // If this app is transitioning from foreground to
12431 // non-foreground, have it do a gc.
12432 scheduleAppGcLocked(app);
12433 } else if (app.curRawAdj >= HIDDEN_APP_MIN_ADJ
12434 && app.setRawAdj < HIDDEN_APP_MIN_ADJ) {
12435 // Likewise do a gc when an app is moving in to the
12436 // background (such as a service stopping).
12437 scheduleAppGcLocked(app);
12438 }
12439 app.setRawAdj = app.curRawAdj;
12440 }
12441 if (adj != app.setAdj) {
12442 if (Process.setOomAdj(app.pid, adj)) {
12443 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(
12444 TAG, "Set app " + app.processName +
12445 " oom adj to " + adj);
12446 app.setAdj = adj;
12447 } else {
12448 return false;
12449 }
12450 }
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012451 if (app.setSchedGroup != app.curSchedGroup) {
12452 app.setSchedGroup = app.curSchedGroup;
12453 if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Log.v(TAG,
12454 "Setting process group of " + app.processName
12455 + " to " + app.curSchedGroup);
12456 if (true) {
San Mehat9438de22009-06-10 09:11:28 -070012457 long oldId = Binder.clearCallingIdentity();
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012458 try {
12459 Process.setProcessGroup(app.pid, app.curSchedGroup);
12460 } catch (Exception e) {
12461 Log.w(TAG, "Failed setting process group of " + app.pid
12462 + " to " + app.curSchedGroup);
San Mehat9438de22009-06-10 09:11:28 -070012463 e.printStackTrace();
12464 } finally {
12465 Binder.restoreCallingIdentity(oldId);
Dianne Hackborn06de2ea2009-05-21 12:56:43 -070012466 }
12467 }
12468 if (false) {
12469 if (app.thread != null) {
12470 try {
12471 app.thread.setSchedulingGroup(app.curSchedGroup);
12472 } catch (RemoteException e) {
12473 }
12474 }
12475 }
12476 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012477 }
12478
12479 return true;
12480 }
12481
12482 private final HistoryRecord resumedAppLocked() {
12483 HistoryRecord resumedActivity = mResumedActivity;
12484 if (resumedActivity == null || resumedActivity.app == null) {
12485 resumedActivity = mPausingActivity;
12486 if (resumedActivity == null || resumedActivity.app == null) {
12487 resumedActivity = topRunningActivityLocked(null);
12488 }
12489 }
12490 return resumedActivity;
12491 }
12492
12493 private final boolean updateOomAdjLocked(ProcessRecord app) {
12494 final HistoryRecord TOP_ACT = resumedAppLocked();
12495 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12496 int curAdj = app.curAdj;
12497 final boolean wasHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12498 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12499
12500 mAdjSeq++;
12501
12502 final boolean res = updateOomAdjLocked(app, app.hiddenAdj, TOP_APP);
12503 if (res) {
12504 final boolean nowHidden = app.curAdj >= HIDDEN_APP_MIN_ADJ
12505 && app.curAdj <= HIDDEN_APP_MAX_ADJ;
12506 if (nowHidden != wasHidden) {
12507 // Changed to/from hidden state, so apps after it in the LRU
12508 // list may also be changed.
12509 updateOomAdjLocked();
12510 }
12511 }
12512 return res;
12513 }
12514
12515 private final boolean updateOomAdjLocked() {
12516 boolean didOomAdj = true;
12517 final HistoryRecord TOP_ACT = resumedAppLocked();
12518 final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
12519
12520 if (false) {
12521 RuntimeException e = new RuntimeException();
12522 e.fillInStackTrace();
12523 Log.i(TAG, "updateOomAdj: top=" + TOP_ACT, e);
12524 }
12525
12526 mAdjSeq++;
12527
12528 // First try updating the OOM adjustment for each of the
12529 // application processes based on their current state.
12530 int i = mLRUProcesses.size();
12531 int curHiddenAdj = HIDDEN_APP_MIN_ADJ;
12532 while (i > 0) {
12533 i--;
12534 ProcessRecord app = mLRUProcesses.get(i);
12535 if (updateOomAdjLocked(app, curHiddenAdj, TOP_APP)) {
12536 if (curHiddenAdj < HIDDEN_APP_MAX_ADJ
12537 && app.curAdj == curHiddenAdj) {
12538 curHiddenAdj++;
12539 }
12540 } else {
12541 didOomAdj = false;
12542 }
12543 }
12544
12545 // todo: for now pretend like OOM ADJ didn't work, because things
12546 // aren't behaving as expected on Linux -- it's not killing processes.
12547 return ENFORCE_PROCESS_LIMIT || mProcessLimit > 0 ? false : didOomAdj;
12548 }
12549
12550 private final void trimApplications() {
12551 synchronized (this) {
12552 int i;
12553
12554 // First remove any unused application processes whose package
12555 // has been removed.
12556 for (i=mRemovedProcesses.size()-1; i>=0; i--) {
12557 final ProcessRecord app = mRemovedProcesses.get(i);
12558 if (app.activities.size() == 0
12559 && app.curReceiver == null && app.services.size() == 0) {
12560 Log.i(
12561 TAG, "Exiting empty application process "
12562 + app.processName + " ("
12563 + (app.thread != null ? app.thread.asBinder() : null)
12564 + ")\n");
12565 if (app.pid > 0 && app.pid != MY_PID) {
12566 Process.killProcess(app.pid);
12567 } else {
12568 try {
12569 app.thread.scheduleExit();
12570 } catch (Exception e) {
12571 // Ignore exceptions.
12572 }
12573 }
12574 cleanUpApplicationRecordLocked(app, false, -1);
12575 mRemovedProcesses.remove(i);
12576
12577 if (app.persistent) {
12578 if (app.persistent) {
12579 addAppLocked(app.info);
12580 }
12581 }
12582 }
12583 }
12584
12585 // Now try updating the OOM adjustment for each of the
12586 // application processes based on their current state.
12587 // If the setOomAdj() API is not supported, then go with our
12588 // back-up plan...
12589 if (!updateOomAdjLocked()) {
12590
12591 // Count how many processes are running services.
12592 int numServiceProcs = 0;
12593 for (i=mLRUProcesses.size()-1; i>=0; i--) {
12594 final ProcessRecord app = mLRUProcesses.get(i);
12595
12596 if (app.persistent || app.services.size() != 0
12597 || app.curReceiver != null
12598 || app.persistentActivities > 0) {
12599 // Don't count processes holding services against our
12600 // maximum process count.
12601 if (localLOGV) Log.v(
12602 TAG, "Not trimming app " + app + " with services: "
12603 + app.services);
12604 numServiceProcs++;
12605 }
12606 }
12607
12608 int curMaxProcs = mProcessLimit;
12609 if (curMaxProcs <= 0) curMaxProcs = MAX_PROCESSES;
12610 if (mAlwaysFinishActivities) {
12611 curMaxProcs = 1;
12612 }
12613 curMaxProcs += numServiceProcs;
12614
12615 // Quit as many processes as we can to get down to the desired
12616 // process count. First remove any processes that no longer
12617 // have activites running in them.
12618 for ( i=0;
12619 i<mLRUProcesses.size()
12620 && mLRUProcesses.size() > curMaxProcs;
12621 i++) {
12622 final ProcessRecord app = mLRUProcesses.get(i);
12623 // Quit an application only if it is not currently
12624 // running any activities.
12625 if (!app.persistent && app.activities.size() == 0
12626 && app.curReceiver == null && app.services.size() == 0) {
12627 Log.i(
12628 TAG, "Exiting empty application process "
12629 + app.processName + " ("
12630 + (app.thread != null ? app.thread.asBinder() : null)
12631 + ")\n");
12632 if (app.pid > 0 && app.pid != MY_PID) {
12633 Process.killProcess(app.pid);
12634 } else {
12635 try {
12636 app.thread.scheduleExit();
12637 } catch (Exception e) {
12638 // Ignore exceptions.
12639 }
12640 }
12641 // todo: For now we assume the application is not buggy
12642 // or evil, and will quit as a result of our request.
12643 // Eventually we need to drive this off of the death
12644 // notification, and kill the process if it takes too long.
12645 cleanUpApplicationRecordLocked(app, false, i);
12646 i--;
12647 }
12648 }
12649
12650 // If we still have too many processes, now from the least
12651 // recently used process we start finishing activities.
12652 if (Config.LOGV) Log.v(
12653 TAG, "*** NOW HAVE " + mLRUProcesses.size() +
12654 " of " + curMaxProcs + " processes");
12655 for ( i=0;
12656 i<mLRUProcesses.size()
12657 && mLRUProcesses.size() > curMaxProcs;
12658 i++) {
12659 final ProcessRecord app = mLRUProcesses.get(i);
12660 // Quit the application only if we have a state saved for
12661 // all of its activities.
12662 boolean canQuit = !app.persistent && app.curReceiver == null
12663 && app.services.size() == 0
12664 && app.persistentActivities == 0;
12665 int NUMA = app.activities.size();
12666 int j;
12667 if (Config.LOGV) Log.v(
12668 TAG, "Looking to quit " + app.processName);
12669 for (j=0; j<NUMA && canQuit; j++) {
12670 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12671 if (Config.LOGV) Log.v(
12672 TAG, " " + r.intent.getComponent().flattenToShortString()
12673 + ": frozen=" + r.haveState + ", visible=" + r.visible);
12674 canQuit = (r.haveState || !r.stateNotNeeded)
12675 && !r.visible && r.stopped;
12676 }
12677 if (canQuit) {
12678 // Finish all of the activities, and then the app itself.
12679 for (j=0; j<NUMA; j++) {
12680 HistoryRecord r = (HistoryRecord)app.activities.get(j);
12681 if (!r.finishing) {
12682 destroyActivityLocked(r, false);
12683 }
12684 r.resultTo = null;
12685 }
12686 Log.i(TAG, "Exiting application process "
12687 + app.processName + " ("
12688 + (app.thread != null ? app.thread.asBinder() : null)
12689 + ")\n");
12690 if (app.pid > 0 && app.pid != MY_PID) {
12691 Process.killProcess(app.pid);
12692 } else {
12693 try {
12694 app.thread.scheduleExit();
12695 } catch (Exception e) {
12696 // Ignore exceptions.
12697 }
12698 }
12699 // todo: For now we assume the application is not buggy
12700 // or evil, and will quit as a result of our request.
12701 // Eventually we need to drive this off of the death
12702 // notification, and kill the process if it takes too long.
12703 cleanUpApplicationRecordLocked(app, false, i);
12704 i--;
12705 //dump();
12706 }
12707 }
12708
12709 }
12710
12711 int curMaxActivities = MAX_ACTIVITIES;
12712 if (mAlwaysFinishActivities) {
12713 curMaxActivities = 1;
12714 }
12715
12716 // Finally, if there are too many activities now running, try to
12717 // finish as many as we can to get back down to the limit.
12718 for ( i=0;
12719 i<mLRUActivities.size()
12720 && mLRUActivities.size() > curMaxActivities;
12721 i++) {
12722 final HistoryRecord r
12723 = (HistoryRecord)mLRUActivities.get(i);
12724
12725 // We can finish this one if we have its icicle saved and
12726 // it is not persistent.
12727 if ((r.haveState || !r.stateNotNeeded) && !r.visible
12728 && r.stopped && !r.persistent && !r.finishing) {
12729 final int origSize = mLRUActivities.size();
12730 destroyActivityLocked(r, true);
12731
12732 // This will remove it from the LRU list, so keep
12733 // our index at the same value. Note that this check to
12734 // see if the size changes is just paranoia -- if
12735 // something unexpected happens, we don't want to end up
12736 // in an infinite loop.
12737 if (origSize > mLRUActivities.size()) {
12738 i--;
12739 }
12740 }
12741 }
12742 }
12743 }
12744
12745 /** This method sends the specified signal to each of the persistent apps */
12746 public void signalPersistentProcesses(int sig) throws RemoteException {
12747 if (sig != Process.SIGNAL_USR1) {
12748 throw new SecurityException("Only SIGNAL_USR1 is allowed");
12749 }
12750
12751 synchronized (this) {
12752 if (checkCallingPermission(android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES)
12753 != PackageManager.PERMISSION_GRANTED) {
12754 throw new SecurityException("Requires permission "
12755 + android.Manifest.permission.SIGNAL_PERSISTENT_PROCESSES);
12756 }
12757
12758 for (int i = mLRUProcesses.size() - 1 ; i >= 0 ; i--) {
12759 ProcessRecord r = mLRUProcesses.get(i);
12760 if (r.thread != null && r.persistent) {
12761 Process.sendSignal(r.pid, sig);
12762 }
12763 }
12764 }
12765 }
12766
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012767 public boolean profileControl(String process, boolean start,
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012768 String path, ParcelFileDescriptor fd) throws RemoteException {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012769
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012770 try {
12771 synchronized (this) {
12772 // note: hijacking SET_ACTIVITY_WATCHER, but should be changed to
12773 // its own permission.
12774 if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
12775 != PackageManager.PERMISSION_GRANTED) {
12776 throw new SecurityException("Requires permission "
12777 + android.Manifest.permission.SET_ACTIVITY_WATCHER);
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012778 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012779
12780 if (start && fd == null) {
12781 throw new IllegalArgumentException("null fd");
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012782 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012783
12784 ProcessRecord proc = null;
12785 try {
12786 int pid = Integer.parseInt(process);
12787 synchronized (mPidsSelfLocked) {
12788 proc = mPidsSelfLocked.get(pid);
12789 }
12790 } catch (NumberFormatException e) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012791 }
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012792
12793 if (proc == null) {
12794 HashMap<String, SparseArray<ProcessRecord>> all
12795 = mProcessNames.getMap();
12796 SparseArray<ProcessRecord> procs = all.get(process);
12797 if (procs != null && procs.size() > 0) {
12798 proc = procs.valueAt(0);
12799 }
12800 }
12801
12802 if (proc == null || proc.thread == null) {
12803 throw new IllegalArgumentException("Unknown process: " + process);
12804 }
12805
12806 boolean isSecure = "1".equals(SystemProperties.get(SYSTEM_SECURE, "0"));
12807 if (isSecure) {
12808 if ((proc.info.flags&ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
12809 throw new SecurityException("Process not debuggable: " + proc);
12810 }
12811 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012812
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012813 proc.thread.profilerControl(start, path, fd);
12814 fd = null;
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012815 return true;
Dianne Hackborn9c8dd552009-06-23 19:22:52 -070012816 }
12817 } catch (RemoteException e) {
12818 throw new IllegalStateException("Process disappeared");
12819 } finally {
12820 if (fd != null) {
12821 try {
12822 fd.close();
12823 } catch (IOException e) {
12824 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080012825 }
12826 }
12827 }
12828
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080012829 /** In this method we try to acquire our lock to make sure that we have not deadlocked */
12830 public void monitor() {
12831 synchronized (this) { }
12832 }
12833}