package android.app;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import com.intel.mpt.annotation.MayloonStubAnnotation;
import android.app.ActivityStack.ActivityState;
import android.content.BroadcastFilter;
import android.content.BroadcastReceiver;
import android.content.BroadcastRecord;
import android.content.ComponentName;
import android.content.ContentProvider;
import android.content.ContentProviderRecord;
import android.content.ContentService;
import android.content.Context;
import android.content.IIntentReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ReceiverList;
import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.ConfigurationInfo;
import android.content.pm.InstrumentationInfo;
import android.content.pm.IntentResolver;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
import android.util.Log;
import android.util.Slog;
public class ActivityManager {
public static final String LAUNCHER = "com.intel.jsdroid.sudoku";
private static boolean DEBUG_PROVIDER = true;
/**
* Returned by startActivity() if the start request was canceled because app
* switches are temporarily canceled to ensure the user's last request (such
* as pressing home) is performed.
*/
public static final int START_SWITCHES_CANCELED = 4;
/**
* Returned by startActivity() if an activity wasn't really started, but the
* given Intent was given to the existing top activity.
*/
public static final int START_DELIVERED_TO_TOP = 3;
/**
* Returned by startActivity() if an activity wasn't really started, but a
* task was simply brought to the foreground.
*/
public static final int START_TASK_TO_FRONT = 2;
/**
* Returned by startActivity() if the caller asked that the Intent not be
* executed if it is the recipient, and that is indeed the case.
*/
public static final int START_RETURN_INTENT_TO_CALLER = 1;
/**
* Activity was started successfully as normal.
*/
public static final int START_SUCCESS = 0;
public static final int START_INTENT_NOT_RESOLVED = -1;
public static final int START_CLASS_NOT_FOUND = -2;
public static final int START_FORWARD_AND_REQUEST_CONFLICT = -3;
public static final int START_PERMISSION_DENIED = -4;
public static final int START_NOT_ACTIVITY = -5;
public static final int START_CANCELED = -6;
// This is a process running a core server, such as telephony. Definitely
// don't want to kill it, but doing so is not completely fatal.
static final int CORE_SERVER_ADJ = -12;
public static final String TAG = "ActivityManager>>>";
private final Context mContext;
public Activity mCurActivity = null;
// How long we wait for a service to finish executing.
static final int SERVICE_TIMEOUT = 20 * 1000;
static final boolean DEBUG_SERVICE = true;
/**
* List of persistent applications that are in the process
* of being started.
*/
final ArrayList<ProcessRecord> mPersistentStartingProcesses
= new ArrayList<ProcessRecord>();
/**
* Task identifier that activities are currently being started in.
* Incremented each time a new task is created. todo: Replace this with a
* TokenSpace class that generates non-repeating integers that won't wrap.
*/
int mCurTask = 0;
public ActivityManager(Context context) {
mContext = context;
}
public void main() {
Looper.prepare();
mMainStack = new ActivityStack(this, mContext, true);
startRunning(null, null, null, null);
}
public ActivityStack mMainStack;
boolean mStartRunning;
String mTopAction;
String mTopData;
boolean mSystemReady;
ComponentName mTopComponent;
public int startActivity(IApplicationThread caller, Intent intent,
String resolvedType, Uri[] grantedUriPermissions, int grantedMode,
IBinder resultTo, String resultWho, int requestCode,
boolean onlyIfNeeded, boolean debug) {
// System.out.println("in startActivity");
return mMainStack.startActivityMayWait(caller, intent, resolvedType,
grantedUriPermissions, grantedMode, resultTo, resultWho,
requestCode, onlyIfNeeded, debug);
}
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType)
{
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
synchronized(this) {
// final int callingPid = Binder.getCallingPid();
// final int callingUid = Binder.getCallingUid();
// final long origId = Binder.clearCallingIdentity();
ComponentName res = startServiceLocked(caller, service,
resolvedType);
// Binder.restoreCallingIdentity(origId);
return res;
}
}
private static final HashMap<ServiceRecord, ArrayList<ConnectionRecord>> mServiceConnection = new HashMap<ServiceRecord, ArrayList<ConnectionRecord>>();
private class ConnectionInfo {
IBinder binder;
// IBinder.DeathRecipient deathMonitor;
}
private final HashMap<ComponentName, ConnectionInfo> mActiveConnections
= new HashMap<ComponentName, ConnectionInfo>();
public int bindService(IApplicationThread caller,
Intent service, String resolvedType,
ServiceConnection connection, int flags) {
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
final ProcessRecord callerApp = getRecordForAppLocked(caller);
Log.i(TAG, "bindService:");
int clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
// PendingIntent clientIntent = null;
//
//
// try {
// clientIntent = (PendingIntent)service.getParcelableExtra(
// Intent.EXTRA_CLIENT_INTENT);
// } catch (RuntimeException e) {
// }
// if (clientIntent != null) {
// clientLabel = service.getIntExtra(Intent.EXTRA_CLIENT_LABEL, 0);
// if (clientLabel != 0) {
// // There are no useful extras in the intent, trash them.
// // System code calling with this stuff just needs to know
// // this will happen.
// service = service.cloneFilter();
// }
// }
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType);
if (res == null) {
return 0;
}
if (res.record == null) {
return -1;
}
ServiceRecord s = res.record;
// final long origId = Binder.clearCallingIdentity();
// if (unscheduleServiceRestartLocked(s)) {
// if (DEBUG_SERVICE) Slog.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
// + s);
// }
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
ConnectionRecord c = new ConnectionRecord(b,
connection, flags, clientLabel);
// IBinder binder = connection.asBinder();
ArrayList<ConnectionRecord> clist = mServiceConnection.get(s);
if (clist == null) {
clist = new ArrayList<ConnectionRecord>();
mServiceConnection.put(s, clist);
}
clist.add(c);
// b.connections.add(c);
// if (activity != null) {
// if (activity.connections == null) {
// activity.connections = new HashSet<ConnectionRecord>();
// }
// activity.connections.add(c);
// }
// b.client.connections.add(c);
// if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
// b.client.hasAboveClient = true;
// }
// clist = mServiceConnections.get(binder);
// if (clist == null) {
// clist = new ArrayList<ConnectionRecord>();
// mServiceConnections.put(binder, clist);
// }
// clist.add(c);
if ((flags&Context.BIND_AUTO_CREATE) != 0) {
s.lastActivity = SystemClock.uptimeMillis();
if (!bringUpServiceLocked(s, service.getFlags(), false)) {
return 0;
}
}
// if (s.app != null) {
// // This could have made the service more important.
// updateOomAdjLocked(s.app);
// }
//
// if (DEBUG_SERVICE) Slog.v(TAG, "Bind " + s + " with " + b
// + ": received=" + b.intent.received
// + " apps=" + b.intent.apps.size()
// + " doRebind=" + b.intent.doRebind);
//
// if (s.app != null && b.intent.received) {
// // Service is already running, so we can immediately
// // publish the connection.
// try {
// c.conn.connected(s.name, b.intent.binder);
// } catch (Exception e) {
// Slog.w(TAG, "Failure sending service " + s.shortName
// + " to connection " + c.conn.asBinder()
// + " (in " + c.binding.client.processName + ")", e);
// }
//
// // If this is the first app connected back to this binding,
// // and the service had previously asked to be told when
// // rebound, then do so.
// if (b.intent.apps.size() == 1 && b.intent.doRebind) {
// requestServiceBindingLocked(s, b.intent, true);
// }
// } else if (!b.intent.requested) {
// requestServiceBindingLocked(s, b.intent, false);
// }
//
// Binder.restoreCallingIdentity(origId);
return 1;
}
private ComponentName startServiceLocked(IApplicationThread caller,
Intent service, String resolvedType) {
synchronized(this) {
// if (DEBUG_SERVICE) Slog.v(TAG, "startService: " + service
// + " type=" + resolvedType + " args=" + service.getExtras());
// if (caller != null) {
// final ProcessRecord callerApp = getRecordForAppLocked(caller);
// if (callerApp == null) {
// throw new SecurityException(
// "Unable to find app for caller " + caller
// + ") when starting service " + service);
// }
// }
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType);
if (res == null) {
return null;
}
if (res.record == null) {
return new ComponentName("!", res.permission != null
? res.permission : "private to package");
}
ServiceRecord r = res.record;
// int targetPermissionUid = checkGrantUriPermissionFromIntentLocked(
// callingUid, r.packageName, service);
// if (unscheduleServiceRestartLocked(r)) {
// if (DEBUG_SERVICE) Slog.v(TAG, "START SERVICE WHILE RESTART PENDING: " + r);
// }
r.startRequested = true;
r.callStart = false;
r.pendingStarts.add(new ServiceRecord.StartItem(r, 1, service, -1));
r.lastActivity = SystemClock.uptimeMillis();
// synchronized (r.stats.getBatteryStats()) {
// r.stats.startRunningLocked();
// }
if (!bringUpServiceLocked(r, service.getFlags(), false)) {
return new ComponentName("!", "Service process is bad");
}
return r.name;
}
}
private final boolean bringUpServiceLocked(ServiceRecord r,
int intentFlags, boolean whileRestarting) {
//Slog.i(TAG, "Bring up service:");
//r.dump(" ");
Log.i(TAG, "bringUpServiceLocked:");
if (r.app != null && r.app.thread != null) {
//sendServiceArgsLocked(r, false);
return true;
}
// if (!whileRestarting && r.restartDelay > 0) {
// // If waiting for a restart, then do nothing.
// return true;
// }
// if (DEBUG_SERVICE) Slog.v(TAG, "Bringing up " + r + " " + r.intent);
// We are now bringing the service up, so no longer in the
// restarting state.
// mRestartingServices.remove(r);
// Service is now being launched, its package can't be stopped.
// try {
// AppGlobals.getPackageManager().setPackageStoppedState(
// r.packageName, false);
// } catch (RemoteException e) {
// } catch (IllegalArgumentException e) {
// Slog.w(TAG, "Failed trying to unstop package "
// + r.packageName + ": " + e);
// }
final String appName = r.processName;
// ProcessRecord app = mProcessNames.get(appName);
ProcessRecord app = newProcessRecordLocked(null, r.appInfo, appName);
// app.thread = mContext.getActivityThread().getApplicationThread();
// ProcessRecord app = getProcessRecordLocked(appName, r.appInfo.uid);;
if (app != null ) {
try {
app.addPackage(r.appInfo.packageName);
realStartServiceLocked(r, app);
return true;
} catch (Exception e) {
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
// Not running -- get it started, and enqueue this service record
// // to be executed when the app comes up.
// if (startProcessLocked(appName, r.appInfo, true, intentFlags,
// "service", r.name, false) == null) {
// Slog.w(TAG, "Unable to launch app "
// + r.appInfo.packageName + "/"
// + r.appInfo.uid + " for service "
// + r.intent.getIntent() + ": process is bad");
// bringDownServiceLocked(r, true);
// return false;
// }
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
return true;
}
private final class ServiceLookupResult {
final ServiceRecord record;
final String permission;
ServiceLookupResult(ServiceRecord _record, String _permission) {
record = _record;
permission = _permission;
}
};
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app) {
Log.i(TAG, "realStartServiceLocked:");
r.app = app;
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
app.services.add(r);
// bumpServiceExecutingLocked(r, "create");
// updateLruProcessLocked(app, true, true);
// boolean created = false;
// try {
// mStringBuilder.setLength(0);
// r.intent.getIntent().toShortString(mStringBuilder, true, false, true);
// EventLog.writeEvent(EventLogTags.AM_CREATE_SERVICE,
// System.identityHashCode(r), r.shortName,
// mStringBuilder.toString(), r.app.pid);
// synchronized (r.stats.getBatteryStats()) {
// r.stats.startLaunchedLocked();
// }
// ensurePackageDexOpt(r.serviceInfo.packageName);
mContext.getActivityThread().getApplicationThread().scheduleCreateService(r, r.serviceInfo);
// compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo));
// r.postNotification();
// created = true;
// } finally {
// if (!created) {
// app.services.remove(r);
// scheduleServiceRestartLocked(r, false);
// }
// }
//
requestServiceBindingsLocked(r);
//
// // If the service is in the started state, and there are no
// // pending arguments, then fake up one so its onStartCommand() will
// // be called.
if (r.startRequested && r.callStart && r.pendingStarts.size() == 0) {
r.pendingStarts.add(new ServiceRecord.StartItem(r, 1, null, -1));
}
//
sendServiceArgsLocked(r, true);
}
private void sendServiceArgsLocked(ServiceRecord r, boolean b) {
final int N = r.pendingStarts.size();
if (N == 0) {
return;
}
while (r.pendingStarts.size() > 0) {
ServiceRecord.StartItem si = r.pendingStarts.remove(0);
if (si.intent == null && N > 1) {
// If somehow we got a dummy null intent in the middle,
// then skip it. DO NOT skip a null intent when it is
// the only one in the list -- this is to support the
// onStartCommand(null) case.
continue;
}
si.deliveredTime = SystemClock.uptimeMillis();
r.deliveredStarts.add(si);
si.deliveryCount++;
// if (si.targetPermissionUid >= 0 && si.intent != null) {
// grantUriPermissionUncheckedFromIntentLocked(si.targetPermissionUid,
// r.packageName, si.intent, si.getUriPermissionsLocked());
// }
// bumpServiceExecutingLocked(r, "start");
// if (!oomAdjusted) {
// oomAdjusted = true;
// updateOomAdjLocked(r.app);
// }
int flags = 0;
if (si.deliveryCount > 0) {
flags |= Service.START_FLAG_RETRY;
}
if (si.doneExecutingCount > 0) {
flags |= Service.START_FLAG_REDELIVERY;
}
mContext.getActivityThread().getApplicationThread().scheduleServiceArgs(r, si.id, flags, si.intent);
}
}
private void requestServiceBindingsLocked(ServiceRecord r) {
Log.i(TAG, "requestServiceBindingsLocked:");
// TODO Auto-generated method stub
Iterator<IntentBindRecord> bindings = r.bindings.values().iterator();
while (bindings.hasNext()) {
IntentBindRecord i = bindings.next();
if (!requestServiceBindingLocked(r, i, false)) {
break;
}
}
}
private boolean requestServiceBindingLocked(ServiceRecord r,
IntentBindRecord i, boolean rebind) {
Log.i(TAG, "requestServiceBindingsLocked2:");
if (r.app == null ) {
// If service is not currently running, can't yet bind.
return false;
}
if ((!i.requested || rebind) && i.apps.size() > 0) {
// bumpServiceExecutingLocked(r, "bind");
mContext.getActivityThread().getApplicationThread().scheduleBindService(r, i.intent.getIntent(), rebind);
if (!rebind) {
i.requested = true;
}
i.hasBound = true;
i.doRebind = false;
}
return true;
}
private ServiceLookupResult retrieveServiceLocked(Intent service,
String resolvedType) {
ServiceRecord r = null;
if (service.getComponent() != null) {
r = mServices.get(service.getComponent());
}
Intent.FilterComparison filter = new Intent.FilterComparison(service);
r = mServicesByIntent.get(filter);
if (r == null) {
ResolveInfo rInfo = Context.getSystemContext().getPackageManager().resolveService(
service,resolvedType,STOCK_PM_FLAGS);
ServiceInfo sInfo = rInfo != null ? rInfo.serviceInfo : null;
ComponentName name = service.getComponent();
r = mServices.get(name);
if (r == null) {
filter = new Intent.FilterComparison(service.cloneFilter());
ServiceRestarter res = new ServiceRestarter();
// BatteryStatsImpl.Uid.Pkg.Serv ss = null;
// BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
// synchronized (stats) {
// ss = stats.getServiceStatsLocked(
// sInfo.applicationInfo.uid, sInfo.packageName,
// sInfo.name);
// }
r = new ServiceRecord(this, name, filter, sInfo, res);
res.setService(r);
mServices.put(name, r);
mServicesByIntent.put(filter, r);
// Make sure this component isn't in the pending list.
int N = mPendingServices.size();
for (int i=0; i<N; i++) {
ServiceRecord pr = mPendingServices.get(i);
if (pr.name.equals(name)) {
mPendingServices.remove(i);
i--;
N--;
}
}
}
}
if (r != null) {
// if (checkComponentPermission(r.permission,
// callingPid, callingUid, r.appInfo.uid, r.exported)
// != PackageManager.PERMISSION_GRANTED) {
// if (!r.exported) {
// Slog.w(TAG, "Permission Denial: Accessing service " + r.name
// + " from pid=" + callingPid
// + ", uid=" + callingUid
// + " that is not exported from uid " + r.appInfo.uid);
// return new ServiceLookupResult(null, "not exported from uid "
// + r.appInfo.uid);
// }
// Slog.w(TAG, "Permission Denial: Accessing service " + r.name
// + " from pid=" + callingPid
// + ", uid=" + callingUid
// + " requires " + r.permission);
// return new ServiceLookupResult(null, r.permission);
// }
return new ServiceLookupResult(r, null);
}
return null;
}
public void publishService(IBinder token, Intent intent, IBinder service) {
// Refuse possible leaked file descriptors
if (intent != null && intent.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
Log.i(TAG, "publishService:");
if (!(token instanceof ServiceRecord)) {
throw new IllegalArgumentException("Invalid service token");
}
ServiceRecord r = (ServiceRecord)token;
// final long origId = Binder.clearCallingIdentity();
// if (DEBUG_SERVICE) Slog.v(TAG, "PUBLISHING " + r
// + " " + intent + ": " + service);
if (r != null) {
Intent.FilterComparison filter
= new Intent.FilterComparison(intent);
IntentBindRecord b = r.bindings.get(filter);
if(mServiceConnection.get(r) == null)
Log.i(TAG, "service connection = null:");
if (mServiceConnection.get(r) != null) {
Iterator<ArrayList<ConnectionRecord>> it
= mServiceConnection.values().iterator();
while (it.hasNext()) {
ArrayList<ConnectionRecord> clist = it.next();
for (int i=0; i<clist.size(); i++) {
ConnectionRecord c = clist.get(i);
Log.i(TAG, "c.conn:");
mContext.getActivityThread().getApplicationThread().getHandler().post(new RunConnection(r.name,service,0,c.conn));
}
}
}
// serviceDoneExecutingLocked(r, mStoppingServices.contains(r));
//
// Binder.restoreCallingIdentity(origId);
}
}
final class RunConnection implements Runnable{
RunConnection(ComponentName name, IBinder service, int command,ServiceConnection connection) {
Log.i(TAG, "new RunConnection:");
mName = name;
mService = service;
mCommand = command;
mConnection = connection;
}
@Override
public void run() {
// TODO Auto-generated method stub
Log.i(TAG, "RunConnection.run:");
if (mCommand == 0) {
ConnectionInfo old;
ConnectionInfo info;
old = mActiveConnections.get(mName);
if (old != null && old.binder == mService) {
// Huh, already have this one. Oh well!
return;
}
if (mService != null) {
// A new service is being connected... set it all up.
info = new ConnectionInfo();
info.binder = mService;
// info.deathMonitor = new IBinder.DeathRecipient();
// mService.linkToDeath(info.deathMonitor, 0);
mActiveConnections.put(mName, info);
} else {
// The named service is being disconnected... clean up.
mActiveConnections.remove(mName);
}
// if (old != null) {
// old.binder.unlinkToDeath(old.deathMonitor, 0);
// }
//
// If there was an old service, it is not disconnected.
if (old != null) {
mConnection.onServiceDisconnected(mName);
}
// If there is a new service, it is now connected.
if (mService != null) {
Log.i(TAG, "RunConnection:");
mConnection.onServiceConnected(mName, mService);
}
} else if (mCommand == 1) {
// doDeath(mName, mService);
mConnection.onServiceDisconnected(mName);
}
}
final ComponentName mName;
final IBinder mService;
final int mCommand;
final ServiceConnection mConnection;
}
private class ServiceRestarter implements Runnable {
private ServiceRecord mService;
void setService(ServiceRecord service) {
mService = service;
}
public void run() {
// synchronized(ActivityManager.this) {
// performServiceRestartLocked(mService);
// }
}
}
public final void startRunning(String pkg, String cls, String action,
String data) {
if (mStartRunning) {
return;
}
mStartRunning = true;
mTopComponent = pkg != null && cls != null ? new ComponentName(pkg, cls)
: null;
mTopAction = action != null ? action : Intent.ACTION_MAIN;
mTopData = data;
// if (!mSystemReady) {
// return;
// }
systemReady();
}
// The flags that are set for all calls we make to the package manager.
static final int STOCK_PM_FLAGS = PackageManager.GET_SHARED_LIBRARY_FILES;
boolean startHomeActivityLocked() {
// System.out.println("in startHomeActivityLocked");
Intent intent = new Intent(mTopAction,
mTopData != null ? Uri.parse(mTopData) : null);
intent.addCategory(Intent.CATEGORY_HOME);
ActivityInfo aInfo = intent.resolveActivityInfo(mContext.getPackageManager(),
STOCK_PM_FLAGS);
if (aInfo == null) {
/*
* No Home activity is found. Find a main activity to Launch.
*/
PackageManager manager = mContext.getPackageManager();
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
final List<ResolveInfo> apps = manager.queryIntentActivities(mainIntent, 0);
aInfo = apps.get(0).activityInfo;
}
if (aInfo == null) {
Log.i(TAG, "Cannot find intent " + intent);
} else {
intent.setComponent(new ComponentName(
aInfo.applicationInfo.packageName, aInfo.name));
// Don't do this if the home app is currently being
// instrumented.
ProcessRecord app = getProcessRecordLocked(aInfo.processName);
if (app == null || app.instrumentationClass == null) {
intent.setFlags(intent.getFlags()
| Intent.FLAG_ACTIVITY_NEW_TASK);
mMainStack.startActivityLocked(null, intent, null, null, 0,
aInfo, null, null, 0, 0, 0, false, false);
}
}
/**
* @j2sNative
* try {
* // Removing startup screen
* if (document.getElementById('mayloonstartup')) {
* document.getElementById('mayloonstartup').style.display = 'none';
* }
* } catch ( e ) {
* // Just ignore any exception occurred
* }
*/ { }
// System.out.println("startHomeActivityLocked Over");
return true;
}
final HashMap<String, ProcessRecord> mProcessNames = new HashMap<String, ProcessRecord>();
final ProcessRecord getProcessRecordLocked(String processName) {
// System.out.println("processName: " + processName);
ProcessRecord proc = mProcessNames.get(processName);
return proc;
}
public void systemReady() {
// System.out.println("in systemReady");
// initialize Content service
ContentService.main(mContext);
mMainStack.resumeTopActivityLocked(null);
}
// Maximum number of recent tasks that we can remember.
static final int MAX_RECENT_TASKS = 20;
private static final boolean DEBUG_BROADCAST = true;
private static final boolean DEBUG_BROADCAST_LIGHT = false;
private static final int BROADCAST_SUCCESS = 0;
final ArrayList<TaskRecord> mRecentTasks = new ArrayList<TaskRecord>();
public ActivityRecord mFocusedActivity;
final void addRecentTaskLocked(TaskRecord task) {
// Remove any existing entries that are the same kind of task.
int N = mRecentTasks.size();
for (int i = 0; i < N; i++) {
TaskRecord tr = mRecentTasks.get(i);
if ((task.affinity != null && task.affinity.equals(tr.affinity))
|| (task.intent != null && task.intent
.filterEquals(tr.intent))) {
mRecentTasks.remove(i);
i--;
N--;
if (task.intent == null) {
// If the new recent task we are adding is not fully
// specified, then replace it with the existing recent task.
task = tr;
}
}
}
if (N >= MAX_RECENT_TASKS) {
mRecentTasks.remove(N - 1);
}
mRecentTasks.add(0, task);
}
public final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver = new IntentResolver<BroadcastFilter, BroadcastFilter>() {
@Override
protected boolean allowFilterResult(BroadcastFilter filter,
List<BroadcastFilter> dest) {
IIntentReceiver target = filter.receiverList.receiver;
for (int i = dest.size() - 1; i >= 0; i--) {
if (dest.get(i).receiverList.receiver == target) {
return false;
}
}
return true;
}
};
final HashMap mRegisteredReceivers = new HashMap();
public final Intent registerReceiver(IApplicationThread caller,
IIntentReceiver receiver, IntentFilter filter, String permission) {
synchronized (this) {
ProcessRecord callerApp = null;
if (caller != null) {
callerApp = getRecordForAppLocked(caller);
}
List allSticky = null;
// Look for any matching sticky broadcasts...
Iterator actions = filter.actionsIterator();
if(DEBUG_BROADCAST)
Log.i(TAG, "this is register in activitymanager");
if (actions != null) {
while (actions.hasNext()) {
String action = (String) actions.next();
// allSticky = getStickiesLocked(action, filter, allSticky);
if(DEBUG_BROADCAST)
Log.i(TAG, "action:"+action);
}
} else {
// allSticky = getStickiesLocked(null, filter, allSticky);
}
// The first sticky in the list is returned directly back to
// the client.
Intent sticky = allSticky != null ? (Intent) allSticky.get(0)
: null;
if (receiver == null) {
return sticky;
}
ReceiverList rl = (ReceiverList) mRegisteredReceivers.get(receiver);
if (rl == null) {
rl = new ReceiverList(this, callerApp, 0, 0, receiver);
mRegisteredReceivers.put(receiver, rl);
}
BroadcastFilter bf = new BroadcastFilter(filter, rl, permission);
rl.add(bf);
mReceiverResolver.addFilter(bf);
if (!bf.debugCheck()) {
Slog.w(TAG, "==> For Dynamic broadast");
}
// Enqueue broadcasts for all existing stickies that match
// this filter.
if (allSticky != null) {
/*
* ArrayList receivers = new ArrayList(); receivers.add(bf);
*
* int N = allSticky.size(); for (int i=0; i<N; i++) { Intent
* intent = (Intent)allSticky.get(i); BroadcastRecord r = new
* BroadcastRecord(intent, null, null, -1, -1, null, receivers,
* null, 0, null, null, false, true, true); if
* (mParallelBroadcasts.size() == 0) {
* scheduleBroadcastsLocked(); } mParallelBroadcasts.add(r); }
*/
}
// return sticky;
return null;
}
}
public void unregisterReceiver(IIntentReceiver receiver) {
ReceiverList rl = (ReceiverList) mRegisteredReceivers.get(receiver);
if(rl!=null){
removeReceiverLocked(rl);
}
}
void removeReceiverLocked(ReceiverList rl) {
mRegisteredReceivers.remove(rl.receiver);
int N = rl.size();
for (int i=0; i<N; i++) {
mReceiverResolver.removeFilter(rl.get(i));
}
}
private final void deliverToRegisteredReceiverLocked(BroadcastRecord r,
BroadcastFilter filter, boolean ordered) {
Context context=filter.receiverList.receiver.mOuterContext;
Intent intent=r.intent;
filter.receiverList.receiver.receiver.onReceive(context, intent);
}
private final void processNextBroadcast(Intent intent) {
// First, deliver any non-serialized broadcasts right away.
if (mParallelBroadcasts.size() > 0) {
BroadcastRecord r=mParallelBroadcasts.remove(0);
r.dispatchTime = SystemClock.uptimeMillis();
final int N = r.receivers.size();
for (int i = 0; i < N; i++) {
Object target = r.receivers.get(i);
if (DEBUG_BROADCAST)
Log.i(TAG, "receivers size:" + N);
deliverToRegisteredReceiverLocked(r, (BroadcastFilter) target,
false);
}
}
if (mOrderedBroadcasts.size() > 0) {
BroadcastRecord r=mOrderedBroadcasts.remove(0);
r.dispatchTime = SystemClock.uptimeMillis();
final int N = r.receivers.size();
for (int i = 0; i < N; i++) {
ResolveInfo target = (ResolveInfo)r.receivers.get(i);
if (DEBUG_BROADCAST)
Log.i(TAG, "package receivers size:" + N);
BroadcastReceiver receiver = null;
try {
receiver = (BroadcastReceiver)Class.forName(target.activityInfo.name).newInstance();
} catch (Exception e) {
Log.i(TAG, "Create broadrecerver error");
}
receiver.onReceive(Context.mOuterContext, intent);
}
}
}
private final void scheduleBroadcastsLocked(Intent intent) {
processNextBroadcast(intent);
}
final ArrayList<BroadcastRecord> mParallelBroadcasts
= new ArrayList<BroadcastRecord>();
final ArrayList<BroadcastRecord> mOrderedBroadcasts
= new ArrayList<BroadcastRecord>();
public final int broadcastIntent(IApplicationThread caller, Intent intent,
String resolvedType, IIntentReceiver resultTo, int resultCode,
String resultData, Bundle map, String requiredPermission,
boolean ordered, boolean sticky) {
final ProcessRecord callerApp = getRecordForAppLocked(caller);
if (DEBUG_BROADCAST_LIGHT)
Slog.v(TAG, (sticky ? "Broadcast sticky: " : "Broadcast: ")
+ intent + " ordered=" + ordered);
if ((resultTo != null) && !ordered) {
Slog.w(TAG, "Broadcast " + intent
+ " not ordered but result callback requested!");
}
// Add to the sticky list if requested.
// Figure out who all will receive this broadcast.
List receivers = null;
List<BroadcastFilter> registeredReceivers = null;
registeredReceivers = mReceiverResolver.queryIntent(intent,
resolvedType, false);
final boolean replacePending = (intent.getFlags() & Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;
Log.i(TAG, "ComponentNamename:"+intent.getComponent());
if (intent.getComponent() != null) {
// Broadcast is going to one specific receiver class...
ActivityInfo ai = Context.getSystemContext().getPackageManager()
.getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS);
if (ai != null) {
receivers = new ArrayList();
ResolveInfo ri = new ResolveInfo();
ri.activityInfo = ai;
receivers.add(ri);
}
} else {
// Need to resolve the intent to interested receivers...
Log.i(TAG, "if:"+String.valueOf(intent.getFlags() & Intent.FLAG_RECEIVER_REGISTERED_ONLY));
if ((intent.getFlags() & Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
receivers = Context
.getSystemContext()
.getPackageManager()
.queryIntentReceivers(intent, resolvedType,
STOCK_PM_FLAGS);
}
}
Log.i(TAG, "package receiver size is:"+String.valueOf(receivers.size()));
int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
if (!ordered && NR > 0) {
// If we are not serializing this broadcast, then send the
// registered receivers separately so they don't wait for the
// components to be launched.
BroadcastRecord r = new BroadcastRecord(intent, callerApp,
null, 0, 0, requiredPermission,
registeredReceivers, resultCode, resultData, map, ordered,
sticky, false);
mParallelBroadcasts.add(r);
registeredReceivers = null;
NR = 0;
}
BroadcastRecord s = new BroadcastRecord(intent, callerApp,
null, 0, 0, requiredPermission,
receivers, resultCode, resultData, map, ordered,
sticky, false);
mOrderedBroadcasts.add(s);
scheduleBroadcastsLocked(intent);
return BROADCAST_SUCCESS;
}
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
String hostingType, ComponentName hostingName,
boolean allowWhileBooting) {
// System.out.println(TAG + "in package startProcessLocked");
// System.out.println(TAG + "processName: " + processName + ", info: "
// + info.name);
/**/
ProcessRecord app = getProcessRecordLocked(processName);
// We don't have to do anything more if:
// (1) There is an existing application record; and
// (2) The caller doesn't think it is dead, OR there is no thread
// object attached to it so we know it couldn't have crashed; and
// (3) There is a pid assigned to it, so it is either starting or
// already running.
// if (DEBUG_PROCESSES)
// Slog.v(TAG, "startProcess: name=" + processName + " app=" + app
// + " knownToBeDead=" + knownToBeDead + " thread="
// + (app != null ? app.thread : null) + " pid="
// + (app != null ? app.pid : -1));
if (app != null && app.pid > 0) {
Log.i(TAG, "impossible here");
if (!knownToBeDead || app.thread == null) {
// We already have the app running, or are waiting for it to
// come up (we have a pid but not yet its thread), so keep it.
// if (DEBUG_PROCESSES)
// Slog.v(TAG, "App already running: " + app);
return app;
} else {
// An application record is attached to a previous process,
// clean it up now.
// if (DEBUG_PROCESSES)
// Slog.v(TAG, "App died: " + app);
// handleAppDiedLocked(app, true);
}
}
String hostingNameStr = hostingName != null ? hostingName
.flattenToShortString() : null;
// System.out.println(TAG + "hostingNameStr: " + hostingNameStr);
if ((intentFlags & Intent.FLAG_FROM_BACKGROUND) != 0) {
Log.i(TAG, "impossible here");
// If we are in the background, then check to see if this process
// is bad. If so, we will just silently fail.
// if (mBadProcesses.get(info.processName, info.uid) != null) {
// if (DEBUG_PROCESSES)
// Slog.v(TAG, "Bad process: " + info.uid + "/"
// + info.processName);
// return null;
// }
} else {
// When the user is explicitly starting a process, then clear its
// crash count so that we won't make it bad until they see at
// least one crash dialog again, and make the process good again
// if it had been bad.
// if (DEBUG_PROCESSES)
// Slog.v(TAG, "Clearing bad process: " + info.uid + "/"
// + info.processName);
// mProcessCrashTimes.remove(info.processName, info.uid);
// if (mBadProcesses.get(info.processName, info.uid) != null) {
// EventLog.writeEvent(EventLogTags.AM_PROC_GOOD, info.uid,
// info.processName);
// mBadProcesses.remove(info.processName, info.uid);
// if (app != null) {
// app.bad = false;
// }
// }
}
if (app == null) {
app = newProcessRecordLocked(null, info, processName);
// app.processName = processName = app.info.packageName;
// System.out.println("processName: " + processName + ", app.PN: "
// + app.processName);
mProcessNames.put(processName, app);
// System.out.print("processName: " + processName);
} else {
// If this is a new package in the process, add the package to the
// list
app.addPackage(info.packageName);
}
/**
* // If the system is not ready yet, then hold off on starting this //
* process until it is. if (!mProcessesReady &&
* !isAllowedWhileBooting(info) && !allowWhileBooting) { if
* (!mProcessesOnHold.contains(app)) { mProcessesOnHold.add(app); } if
* (DEBUG_PROCESSES) Slog.v(TAG, "System not ready, putting on hold: " +
* app); return app; }
*
* /
**/
startProcessLocked(app, hostingType, hostingNameStr);
return (app.pid != 0) ? app : null;
}
final ProcessRecord newProcessRecordLocked(IApplicationThread thread,
ApplicationInfo info, String customProcess) {
String proc = customProcess != null ? customProcess : info.processName;
// System.out.println(TAG + "proc: " + proc);
return new ProcessRecord(thread, info, proc);
}
private final void startProcessLocked(ProcessRecord app,
String hostingType, String hostingNameStr) {
// System.out.println(TAG + "in private startProcessLocked");
// int pid = Process.start("android.app.ActivityThread",
// mSimpleProcessManagement ? app.processName : null, uid, uid,
// gids, debugFlags, new String[] { targetPackage });
try {
ActivityThread acT = (ActivityThread) Class.forName(
"android.app.ActivityThread").newInstance();
// if (app.processName == null)
// app.processName = app.info.packageName;
acT.main(app.processName);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public final void attachApplication(IApplicationThread thread,
String processName) {
// System.out.println(TAG + "in attachApplication, starting "
// + processName);
// Find the application record that is being attached... either via
// the pid if we are running in multiple processes, or just pull the
// next app record if we are emulating process with anonymous threads.
ProcessRecord app = null;
app = mProcessNames.get(processName);
if (app == null) {
Log.e(TAG, "process get fail");
return;
}
// System.out.println(TAG + "get process: " + app.processName);
app.thread = thread;
app.curAdj = app.setAdj = -100;
app.forcingToForeground = null;
app.foregroundServices = false;
app.debugging = false;
boolean normalMode = true;
thread.bindApplication(processName,
app.instrumentationInfo != null ? app.instrumentationInfo
: app.info, app.instrumentationClass,
app.instrumentationProfileFile, app.instrumentationArguments,
IApplicationThread.DEBUG_OFF, false || !normalMode);
// System.out.println("after bindApplication");
// See if the top visible activity is waiting to run in this process...
ActivityRecord hr = mMainStack.topRunningActivityLocked(null);
if (hr != null && normalMode) {
// System.out.println("processName: " + processName
// + ", hr.processName: " + hr.processName);
if (hr.app == null && processName.equals(hr.processName)) {
try {
mMainStack.realStartActivityLocked(hr, app, true, true);
} catch (Exception e) {
Log.i(TAG, e.getMessage());
Log.i(TAG, "Exception in new application when starting activity "
+ hr.intent.getComponent()
.flattenToShortString());
}
} else {
Log.i(TAG, "impossible here lalala");
// mMainStack.ensureActivitiesVisibleLocked(hr, null,
// processName,
// 0);
}
}
}
public final boolean finishActivity(IBinder token, int resultCode,
Intent resultData) {
// System.out.println(TAG + "in finishActivity");
boolean res = mMainStack.requestFinishActivityLocked(token, resultCode,
resultData, "app-request");
// System.out.println(TAG + "finishActivity Over! res: " + res);
//mCurActivity.setVisible(true);
return res;
}
final ProcessRecord getRecordForAppLocked(IApplicationThread thread) {
if (thread == null) {
return null;
}
Iterator<Entry<String, ProcessRecord>> entrySetIterator = mProcessNames
.entrySet().iterator();
while (entrySetIterator.hasNext()) {
Entry<String, ProcessRecord> entry = entrySetIterator.next();
// System.out.println("Entry, Key: " + entry.getKey());
if (entry.getValue().thread == thread) {
return entry.getValue();
}
}
return null;
}
final void setFocusedActivityLocked(ActivityRecord r) {
// TODO
if (mFocusedActivity != r) {
mFocusedActivity = r;
// mWindowManager.setFocusedApp(r, true);
}
}
public final void activityPaused(IBinder token, Bundle icicle) {
mMainStack.activityPaused(token, icicle, false);
}
public final void activityDestroyed(IBinder token) {
mMainStack.activityDestroyed(token);
}
public final void activityIdle(IBinder token, Configuration config) {
final long origId = Binder.clearCallingIdentity();
mMainStack.activityIdleInternal(token, false, config);
Binder.restoreCallingIdentity(origId);
}
public final void activityStopped(IBinder token) {
ActivityRecord r = null;
int index = mMainStack.indexOfTokenLocked(token);
if (index >= 0) {
r = (ActivityRecord)mMainStack.mHistory.get(index);
r.stopped = true;
r.state = ActivityState.STOPPED;
if (!r.finishing) {
if (r.configDestroy) {
r.stack.destroyActivityLocked(r, true);
r.stack.resumeTopActivityLocked(null);
}
}
}
// trimApplications();
}
/**
* All currently running services.
*/
final HashMap<ComponentName, ServiceRecord> mServices = new HashMap<ComponentName, ServiceRecord>();
/**
* All currently running services indexed by the Intent used to start them.
*/
final HashMap<Intent.FilterComparison, ServiceRecord> mServicesByIntent = new HashMap<Intent.FilterComparison, ServiceRecord>();
/**
* List of services that we have been asked to start, but haven't yet been
* able to. It is used to hold start requests while waiting for their
* corresponding application thread to get going.
*/
final ArrayList<ServiceRecord> mPendingServices = new ArrayList<ServiceRecord>();
/**
* List of services that are scheduled to restart following a crash.
*/
final ArrayList<ServiceRecord> mRestartingServices = new ArrayList<ServiceRecord>();
/**
* List of services that are in the process of being stopped.
*/
final ArrayList<ServiceRecord> mStoppingServices = new ArrayList<ServiceRecord>();
private final ServiceRecord findServiceLocked(ComponentName name,
IBinder token) {
ServiceRecord r = mServices.get(name);
return r == token ? r : null;
}
public boolean stopServiceToken(ComponentName className, IBinder token,
int startId) {
synchronized (this) {
if (DEBUG_SERVICE)
Log.i(TAG, "stopServiceToken: " + className + " "
+ token + " startId=" + startId);
ServiceRecord r = findServiceLocked(className, token);
if (r != null) {
if (startId >= 0) {
// Asked to only stop if done with all work. Note that
// to avoid leaks, we will take this as dropping all
// start items up to and including this one.
ServiceRecord.StartItem si = r.findDeliveredStart(startId,
false);
if (si != null) {
while (r.deliveredStarts.size() > 0) {
ServiceRecord.StartItem cur = r.deliveredStarts
.remove(0);
// cur.removeUriPermissionsLocked();
if (cur == si) {
break;
}
}
}
if (r.lastStartId != startId) {
return false;
}
if (r.deliveredStarts.size() > 0) {
Log.i(TAG, "stopServiceToken startId "
+ startId + " is last, but have "
+ r.deliveredStarts.size() + " remaining args");
}
}
{
r.startRequested = false;
r.callStart = false;
}
// final long origId = Binder.clearCallingIdentity();
bringDownServiceLocked(r, false);
// Binder.restoreCallingIdentity(origId);
return true;
}
}
return false;
}
public void serviceDoneExecutingLocked(ServiceRecord r, boolean inStopping) {
if (DEBUG_SERVICE)
Log.i(TAG, "<<< DONE EXECUTING " + r + ": nesting="
+ r.executeNesting + ", inStopping=" + inStopping
+ ", app=" + r.app);
else if (DEBUG_SERVICE)
System.out.println(TAG + "<<< DONE EXECUTING " + r.shortName);
r.executeNesting--;
if (r.executeNesting <= 0 && r.app != null) {
if (DEBUG_SERVICE)
Log.i(TAG, "Nesting at 0 of " + r.shortName);
r.app.executingServices.remove(r);
if (r.app.executingServices.size() == 0) {
if (DEBUG_SERVICE)
Log.i(TAG, "No more executingServices of "
+ r.shortName);
/**
* FIXME: implement message handler
*/
// mHandler.removeMessages(SERVICE_TIMEOUT_MSG, r.app);
}
if (inStopping) {
if (DEBUG_SERVICE)
Log.i(TAG, "doneExecuting remove stopping "
+ r);
mStoppingServices.remove(r);
}
}
}
private final boolean unscheduleServiceRestartLocked(ServiceRecord r) {
if (r.restartDelay == 0) {
return false;
}
r.resetRestartCounter();
mRestartingServices.remove(r);
/**
* FIXME: implement message handler
*/
// mHandler.removeCallbacks(r.restarter);
return true;
}
private final void bringDownServiceLocked(ServiceRecord r, boolean force) {
// Slog.i(TAG, "Bring down service:");
// r.dump(" ");
// Does it still need to run?
if (!force && r.startRequested) {
return;
}
if (r.connections.size() > 0) {
if (!force) {
// XXX should probably keep a count of the number of auto-create
// connections directly in the service.
Iterator<ArrayList<ConnectionRecord>> it = r.connections
.values().iterator();
while (it.hasNext()) {
ArrayList<ConnectionRecord> cr = it.next();
for (int i = 0; i < cr.size(); i++) {
if ((cr.get(i).flags & Context.BIND_AUTO_CREATE) != 0) {
return;
}
}
}
}
// Report to all of the connections that the service is no longer
// available.
Iterator<ArrayList<ConnectionRecord>> it = r.connections.values()
.iterator();
while (it.hasNext()) {
ArrayList<ConnectionRecord> c = it.next();
for (int i = 0; i < c.size(); i++) {
try {
/**
* FIXME: What to do with service connection?
*/
// c.get(i).conn.connected(r.name, null);
} catch (Exception e) {
Log.i(TAG, "Failure disconnecting service " + r.name
+ " to connection " + " (in "
+ c.get(i).binding.client.processName + ")");
}
}
}
}
// Tell the service that it has been unbound.
if (r.bindings.size() > 0 && r.app != null && r.app.thread != null) {
Iterator<IntentBindRecord> it = r.bindings.values().iterator();
while (it.hasNext()) {
IntentBindRecord ibr = it.next();
if (DEBUG_SERVICE)
Log.i(TAG, "Bringing down binding " + ibr
+ ": hasBound=" + ibr.hasBound);
if (r.app != null && r.app.thread != null && ibr.hasBound) {
try {
bumpServiceExecutingLocked(r, "bring down unbind");
ibr.hasBound = false;
/**
* FIXME: How do we unbind service?
*/
// r.app.thread.scheduleUnbindService(r,
// ibr.intent.getIntent());
} catch (Exception e) {
Log.i(TAG, "Exception when unbinding service "
+ r.shortName);
serviceDoneExecutingLocked(r, true);
}
}
}
}
if (DEBUG_SERVICE)
Log.i(TAG, "Bringing down " + r + " " + r.intent);
/*
* EventLog.writeEvent(EventLogTags.AM_DESTROY_SERVICE,
* System.identityHashCode(r), r.shortName, (r.app != null) ? r.app.pid
* : -1);
*/
mServices.remove(r.name);
mServicesByIntent.remove(r.intent);
r.totalRestartCount = 0;
unscheduleServiceRestartLocked(r);
// Also make sure it is not on the pending list.
int N = mPendingServices.size();
for (int i = 0; i < N; i++) {
if (mPendingServices.get(i) == r) {
mPendingServices.remove(i);
if (DEBUG_SERVICE)
Log.i(TAG, "Removed pending: " + r);
i--;
N--;
}
}
r.cancelNotification();
r.isForeground = false;
r.foregroundId = 0;
// Clear start entries.
r.clearDeliveredStartsLocked();
r.pendingStarts.clear();
if (r.app != null) {
r.app.services.remove(r);
if (r.app.thread != null) {
try {
bumpServiceExecutingLocked(r, "stop");
mStoppingServices.add(r);
/**
* FIXME: How do we implement stopService?
*/
// r.app.thread.scheduleStopService(r);
} catch (Exception e) {
Log.i(TAG, "Exception when stopping service "
+ r.shortName);
serviceDoneExecutingLocked(r, true);
}
// updateServiceForegroundLocked(r.app, false);
} else {
if (DEBUG_SERVICE)
Log.i(TAG, "Removed service that has no process: " + r);
}
} else {
if (DEBUG_SERVICE)
Log.i(TAG, "Removed service that is not running: " + r);
}
}
static final int SHOW_ERROR_MSG = 1;
static final int SHOW_NOT_RESPONDING_MSG = 2;
static final int SHOW_FACTORY_ERROR_MSG = 3;
static final int UPDATE_CONFIGURATION_MSG = 4;
static final int GC_BACKGROUND_PROCESSES_MSG = 5;
static final int WAIT_FOR_DEBUGGER_MSG = 6;
static final int BROADCAST_INTENT_MSG = 7;
static final int BROADCAST_TIMEOUT_MSG = 8;
static final int SERVICE_TIMEOUT_MSG = 12;
static final int UPDATE_TIME_ZONE = 13;
static final int SHOW_UID_ERROR_MSG = 14;
static final int IM_FEELING_LUCKY_MSG = 15;
static final int PROC_START_TIMEOUT_MSG = 20;
static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21;
static final int KILL_APPLICATION_MSG = 22;
static final int FINALIZE_PENDING_INTENT_MSG = 23;
static final int POST_HEAVY_NOTIFICATION_MSG = 24;
static final int CANCEL_HEAVY_NOTIFICATION_MSG = 25;
static final int SHOW_STRICT_MODE_VIOLATION_MSG = 26;
static final int CHECK_EXCESSIVE_WAKE_LOCKS_MSG = 27;
/**
* final Handler mHandler = new Handler() { //public Handler() { // if
* (localLOGV) Slog.v(TAG, "Handler started!"); //}
*
* public void handleMessage(Message msg) { switch (msg.what) { case
* SHOW_ERROR_MSG: {
*
* } break; case SHOW_NOT_RESPONDING_MSG: { synchronized
* (ActivityManager.this) {
*
* }
*
* } break; case SHOW_STRICT_MODE_VIOLATION_MSG: {
*
* } break; case SHOW_FACTORY_ERROR_MSG: {
*
* } break; case UPDATE_CONFIGURATION_MSG: {
*
* } break; case GC_BACKGROUND_PROCESSES_MSG: {
*
* } break; case WAIT_FOR_DEBUGGER_MSG: {
*
* } break; case BROADCAST_INTENT_MSG: {
*
* } break; case BROADCAST_TIMEOUT_MSG: {
*
* } break; case SERVICE_TIMEOUT_MSG: {
*
* } break; case UPDATE_TIME_ZONE: {
*
* } break; case SHOW_UID_ERROR_MSG: {
*
* } break; case IM_FEELING_LUCKY_MSG: {
*
* } break; case PROC_START_TIMEOUT_MSG: {
*
* } break; case DO_PENDING_ACTIVITY_LAUNCHES_MSG: {
*
* } break; case KILL_APPLICATION_MSG: {
*
* } break; case FINALIZE_PENDING_INTENT_MSG: {
*
* } break; case POST_HEAVY_NOTIFICATION_MSG: {
*
* } break; case CANCEL_HEAVY_NOTIFICATION_MSG: {
*
* } break; case CHECK_EXCESSIVE_WAKE_LOCKS_MSG: {
*
* } break; } } };
*/
private final void bumpServiceExecutingLocked(ServiceRecord r, String why) {
if (DEBUG_SERVICE)
Log.i(TAG, ">>> EXECUTING " + why + " of " + r
+ " in app " + r.app);
else if (DEBUG_SERVICE)
Log.i(TAG, ">>> EXECUTING " + why + " of "
+ r.shortName);
long now = SystemClock.uptimeMillis();
if (r.executeNesting == 0 && r.app != null) {
if (r.app.executingServices.size() == 0) {
/**
* FIXME: implement message handler
*/
// Message msg = mHandler.obtainMessage(SERVICE_TIMEOUT_MSG);
// msg.obj = r.app;
// mHandler.sendMessageAtTime(msg, now+SERVICE_TIMEOUT);
}
r.app.executingServices.add(r);
}
r.executeNesting++;
r.executingStart = now;
}
public void setServiceForeground(ComponentName className, IBinder token,
int id, boolean removeNotification) {
// final long origId = Binder.clearCallingIdentity();
try {
synchronized (this) {
ServiceRecord r = findServiceLocked(className, token);
if (r != null) {
if (id != 0) {
if (r.foregroundId != id) {
r.cancelNotification();
r.foregroundId = id;
}
r.isForeground = true;
r.postNotification();
} else {
if (r.isForeground) {
r.isForeground = false;
}
if (removeNotification) {
r.cancelNotification();
r.foregroundId = 0;
}
}
}
}
} finally {
// Binder.restoreCallingIdentity(origId);
}
}
// Content Provider
/**
* All of the currently running global content providers. Keys are a string
* containing the provider name and values are a ContentProviderRecord
* object containing the data about it. Note that a single provider may be
* published under multiple names, so there may be multiple entries here for
* a single one in mProvidersByClass.
*/
final HashMap<String, ContentProviderRecord> mProvidersByName = new HashMap<String, ContentProviderRecord>();
/**
* All of the currently running global content providers. Keys are a string
* containing the provider's implementation class and values are a
* ContentProviderRecord object containing the data about it.
*/
final HashMap<String, ContentProviderRecord> mProvidersByClass = new HashMap<String, ContentProviderRecord>();
/** Information you can retrieve about a particular application. */
public static class ContentProviderHolder implements Parcelable {
public final ProviderInfo info;
public ContentProvider provider;
public boolean noReleaseNeeded;
public ContentProviderHolder(ProviderInfo _info) {
info = _info;
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
info.writeToParcel(dest, 0);
if (provider != null) {
dest.writeStrongBinder(/*provider.asBinder()*/null);
} else {
dest.writeStrongBinder(null);
}
dest.writeInt(noReleaseNeeded ? 1 : 0);
}
public static final Creator<ContentProviderHolder> CREATOR = new Creator<ContentProviderHolder>() {
public ContentProviderHolder createFromParcel(Parcel source) {
return new ContentProviderHolder(source);
}
public ContentProviderHolder[] newArray(int size) {
return new ContentProviderHolder[size];
}
};
private ContentProviderHolder(Parcel source) {
info = null;
// info = ProviderInfo.CREATOR.createFromParcel(source);
// provider = ContentProviderNative.asInterface(
// source.readStrongBinder());
// noReleaseNeeded = source.readInt() != 0;
}
};
public ContentProviderHolder getContentProvider(IApplicationThread caller,
String name) {
if (caller == null) {
String msg = "null IApplicationThread when getting content provider "
+ name;
Log.w(TAG, msg);
}
return getContentProviderImpl(caller, name);
}
private ContentProviderHolder getContentProviderExternal(String name) {
return getContentProviderImpl(null, name);
}
public String getProviderMimeType(Uri uri) {
final String name = uri.getAuthority();
ContentProviderHolder holder = null;
try {
holder = getContentProviderExternal(name);
if(DEBUG_PROVIDER)Log.i(TAG, "getProviderMimeType:"+holder);
if (holder != null) {
return holder.provider.getType(uri);
}
} catch (Exception e) {
Log.w(TAG, "Content provider dead retrieving " + uri, e);
return null;
} finally {
if (holder != null) {
removeContentProviderExternal(name);
}
}
return null;
}
private void removeContentProviderExternal(String name) {
ContentProviderRecord cpr = mProvidersByName.get(name);
if(cpr == null) {
//remove from mProvidersByClass
if(DEBUG_PROVIDER) Slog.v(TAG, name+" content provider not found in providers list");
return;
}
//update content provider record entry info
ContentProviderRecord localCpr = mProvidersByClass.get(cpr.info.name);
localCpr.externals--;
if (localCpr.externals < 0) {
Slog.e(TAG, "Externals < 0 for content provider " + localCpr);
}
}
private final ContentProviderHolder getContentProviderImpl(
IApplicationThread caller, String name) {
ContentProviderRecord cpr;
ProviderInfo cpi = null;
if (DEBUG_PROVIDER)
Log.i(TAG, "ActivityManager:getContentProviderImpl");
ProcessRecord r = null;
if (caller != null) {
// TODO AND FIXME: I don't know when to add the process record
r = getRecordForAppLocked(caller);
if (r == null) {
throw new SecurityException("Unable to find app for caller "
+ caller + ") when getting content provider " + name);
}
}
if (DEBUG_PROVIDER)
Log.i(TAG, "ActivityManager:getContentProviderImpl");
// First check if this content provider has been published...
cpr = mProvidersByName.get(name);
if (cpr != null) {
cpi = cpr.info;
if (r != null && cpr.canRunHere(r)) {
// This provider has been published or is in the process
// of being published... but it is also allowed to run
// in the caller's process, so don't make a connection
// and just let the caller instantiate its own instance.
if (cpr.provider != null) {
// don't give caller the provider object, it needs
// to make its own.
cpr = new ContentProviderRecord(cpr);
}
return cpr;
}
// // In this case the provider instance already exists, so we can
// // return it right away.
// if (r != null) {
// if (DEBUG) Log.v(TAG,
// "Adding provider requested by "
// + r.processName + " from process "
// + cpr.info.processName);
// Integer cnt = r.conProviders.get(cpr);
// if (cnt == null) {
// r.conProviders.put(cpr, new Integer(1));
// } else {
// r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
// }
// cpr.clients.add(r);
// if (cpr.app != null && r.setAdj <= PERCEPTIBLE_APP_ADJ) {
// // If this is a perceptible app accessing the provider,
// // make sure to count it as being accessed and thus
// // back up on the LRU list. This is good because
// // content providers are often expensive to start.
// updateLruProcessLocked(cpr.app, false, true);
// }
// } else {
// cpr.externals++;
// }
//
// if (cpr.app != null) {
// //updateOomAdjLocked(cpr.app);
// }
//
// //Binder.restoreCallingIdentity(origId);
} else {
if (DEBUG_PROVIDER)
Log.i(TAG, "ActivityManager:getContentProviderImpl:AppGlobals.getPackageManager().resolveContentProvider");
cpi = Context
.getSystemContext()
.getPackageManager()
.resolveContentProvider(
name,
STOCK_PM_FLAGS
| PackageManager.GET_URI_PERMISSION_PATTERNS);
if (cpi == null) {
Log.d(TAG, "cpi(ProviderInfo is null.)");
return null;
}
if (DEBUG_PROVIDER)
Log.i(TAG, "ActivityManager:ProviderInfo is got!");
cpr = mProvidersByClass.get(cpi.name);
final boolean firstClass = cpr == null;
if (firstClass) {
try {
ApplicationInfo ai = Context
.getSystemContext()
.getPackageManager()
.getApplicationInfo(
cpi.applicationInfo.packageName,
STOCK_PM_FLAGS);
if (ai == null) {
Log.w(TAG, "No package info for content provider "
+ cpi.name);
return null;
}
cpr = new ContentProviderRecord(cpi, ai);
// Make sure the provider is published (the same provider class
// may be published under multiple names).
mProvidersByClass.put(cpi.name, cpr);
mProvidersByName.put(name, cpr);
} catch (Exception ex) {
}
}
if (/*r != null &&*/ cpr.canRunHere(r)) {
// If this is a multiprocess provider, then just return its
// info and allow the caller to instantiate it. Only do
// this if the provider is the same user as the caller's
// process, or can run as root (so can be in any process).
return cpr;
}
// FIXME: i ignore the case that the content provider should run
// on the caller's single process
// This is single process, and our app is now connecting to it.
// See if we are already in the process of launching this
// provider.
// final int N = mLaunchingProviders.size();
// int i;
// for (i=0; i<N; i++) {
// if (mLaunchingProviders.get(i) == cpr) {
// break;
// }
// }
// If the provider is not already being launched, then get it
// started.
// if (i >= N) {
// final long origId = Binder.clearCallingIdentity();
// ProcessRecord proc = startProcessLocked(cpi.processName,
// cpr.appInfo, false, 0, "content provider",
// new ComponentName(cpi.applicationInfo.packageName,
// cpi.name), false);
// if (proc == null) {
// Slog.w(TAG, "Unable to launch app "
// + cpi.applicationInfo.packageName + "/"
// + cpi.applicationInfo.uid + " for provider "
// + name + ": process is bad");
// return null;
// }
// cpr.launchingApp = proc;
// mLaunchingProviders.add(cpr);
// Binder.restoreCallingIdentity(origId);
// }
// Make sure the provider is published (the same provider class
// may be published under multiple names).
// if (firstClass) {
// mProvidersByClass.put(cpi.name, cpr);
// }
// mProvidersByName.put(name, cpr);
//
// if (r != null) {
// if (DEBUG) Log.v(TAG,
// "Adding provider requested by "
// + r.processName + " from process "
// + cpr.info.processName);
// Integer cnt = r.conProviders.get(cpr);
// if (cnt == null) {
// r.conProviders.put(cpr, new Integer(1));
// } else {
// r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
// }
// cpr.clients.add(r);
// } else {
// cpr.externals++;
// }
}
// Wait for the provider to be published...
while (cpr.provider == null) {
if (cpr.launchingApp == null) {
Log.w(TAG, "Unable to launch app "
+ cpi.applicationInfo.packageName + "/"
+ cpi.applicationInfo.uid + " for provider " + name
+ ": launching app became null");
return null;
}
try {
cpr.wait();
} catch (InterruptedException ex) {
}
}
return cpr;
}
public void unbindService(ServiceConnection conn) {
// TODO Auto-generated method stub
}
/**
* Get the device configuration attributes.
*/
public ConfigurationInfo getDeviceConfigurationInfo() {
// try {
// return ActivityManagerNative.getDefault().getDeviceConfigurationInfo();
// } catch (RemoteException e) {
// }
ConfigurationInfo info = new ConfigurationInfo();
info.reqGlEsVersion = 0x00020000; // We support OpenGLES 2.0
return info;
}
/**
* Information you can retrieve about any processes that are in an error condition.
*/
public static class ProcessErrorStateInfo implements Parcelable {
/**
* Condition codes
*/
public static final int NO_ERROR = 0;
public static final int CRASHED = 1;
public static final int NOT_RESPONDING = 2;
/**
* The condition that the process is in.
*/
public int condition;
/**
* The process name in which the crash or error occurred.
*/
public String processName;
/**
* The pid of this process; 0 if none
*/
public int pid;
/**
* The kernel user-ID that has been assigned to this process;
* currently this is not a unique ID (multiple applications can have
* the same uid).
*/
public int uid;
/**
* The activity name associated with the error, if known. May be null.
*/
public String tag;
/**
* A short message describing the error condition.
*/
public String shortMsg;
/**
* A long message describing the error condition.
*/
public String longMsg;
/**
* The stack trace where the error originated. May be null.
*/
public String stackTrace;
/**
* to be deprecated: This value will always be null.
*/
public byte[] crashData = null;
public ProcessErrorStateInfo() {
}
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(condition);
dest.writeString(processName);
dest.writeInt(pid);
dest.writeInt(uid);
dest.writeString(tag);
dest.writeString(shortMsg);
dest.writeString(longMsg);
dest.writeString(stackTrace);
}
public void readFromParcel(Parcel source) {
condition = source.readInt();
processName = source.readString();
pid = source.readInt();
uid = source.readInt();
tag = source.readString();
shortMsg = source.readString();
longMsg = source.readString();
stackTrace = source.readString();
}
public static final Creator<ProcessErrorStateInfo> CREATOR =
new Creator<ProcessErrorStateInfo>() {
public ProcessErrorStateInfo createFromParcel(Parcel source) {
return new ProcessErrorStateInfo(source);
}
public ProcessErrorStateInfo[] newArray(int size) {
return new ProcessErrorStateInfo[size];
}
};
private ProcessErrorStateInfo(Parcel source) {
readFromParcel(source);
}
}
/**
* Returns a list of any processes that are currently in an error condition. The result
* will be null if all processes are running properly at this time.
*
* @return Returns a list of ProcessErrorStateInfo records, or null if there are no
* current error conditions (it will not return an empty list). This list ordering is not
* specified.
*/
public List<ProcessErrorStateInfo> getProcessesInErrorState() {
/*
try {
return ActivityManagerNative.getDefault().getProcessesInErrorState();
} catch (RemoteException e) {
return null;
}
*/
return null;
}
void finishInstrumentationLocked(ProcessRecord app, int resultCode, Bundle results) {
/*
if (app.instrumentationWatcher != null) {
try {
// NOTE: IInstrumentationWatcher *must* be oneway here
app.instrumentationWatcher.instrumentationFinished(
app.instrumentationClass,
resultCode,
results);
} catch (RemoteException e) {
}
}
*/
//app.instrumentationWatcher = null;
/**
* @Mayloon update
* Implement finishInstrumentationLocked here
* In android source code
* finishInstrumentationLocked is implemented in ActivityManagerService
*/
String pretty = null;
if (results != null) {
pretty = results.getString(Instrumentation.REPORT_KEY_STREAMRESULT);
}
if (pretty != null) {
Log.i(TAG, pretty);
} else {
if (results != null) {
for (String key : results.keySet()) {
Log.i(TAG, "Instrumentation_RESULT: " + key + "=" + results.getByte(key));
}
}
Log.i(TAG, "Instrumentation_code: " + resultCode);
}
app.instrumentationClass = null;
app.instrumentationInfo = null;
app.instrumentationProfileFile = null;
app.instrumentationArguments = null;
//forceStopPackageLocked(app.processName, -1, false, false, true);
}
public void finishInstrumentation(IApplicationThread target,
int resultCode, Bundle results) {
// Refuse possible leaked file descriptors
if (results != null && results.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
synchronized(this) {
ProcessRecord app = getRecordForAppLocked(target);
if (app == null) {
Slog.w(TAG, "finishInstrumentation: no app for " + target);
return;
}
//final long origId = Binder.clearCallingIdentity();
finishInstrumentationLocked(app, resultCode, results);
//Binder.restoreCallingIdentity(origId);
}
}
final ProcessRecord getProcessRecordLocked(
String processName, int uid) {
/**
/*@Mayloon update
*/
/*
if (uid == Process.SYSTEM_UID) {
// The system gets to run in any process. If there are multiple
// processes with the same uid, just pick the first (this
// should never happen).
SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(
processName);
return procs != null ? procs.valueAt(0) : null;
}
*/
ProcessRecord proc = mProcessNames.get(processName);
return proc;
}
final ProcessRecord addAppLocked(ApplicationInfo info) {
ProcessRecord app = getProcessRecordLocked(info.processName, info.uid);
if (app == null) {
app = newProcessRecordLocked(null, info, null);
mProcessNames.put(info.processName, app);
/**
/*@Mayloon update
*/
//updateLruProcessLocked(app, true, true);
}
if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
== (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) {
app.persistent = true;
app.maxAdj = CORE_SERVER_ADJ;
}
/*
if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
mPersistentStartingProcesses.add(app);
startProcessLocked(app, "added application", app.processName);
Log.i(TAG,"start process locked");
}
*/
return app;
}
// =========================================================
// INSTRUMENTATION
// =========================================================
public boolean startInstrumentation(ComponentName className,
String profileFile, int flags, Bundle arguments,
IInstrumentationWatcher watcher) {
Log.i(TAG,"start instrumentation");
// Refuse possible leaked file descriptors
if (arguments != null && arguments.hasFileDescriptors()) {
throw new IllegalArgumentException("File descriptors passed in Bundle");
}
InstrumentationInfo ii = null;
ApplicationInfo ai = null;
try {
ii = Context.getSystemContext().getPackageManager().getInstrumentationInfo(
className, STOCK_PM_FLAGS);
ai = Context.getSystemContext().getPackageManager().getApplicationInfo(
ii.targetPackage, STOCK_PM_FLAGS);
} catch (PackageManager.NameNotFoundException e) {
}
if (ii == null) {
/**
/*@Mayloon update
*/
//reportStartInstrumentationFailure(watcher, className,
//"Unable to find instrumentation info for: " + className);
Log.e(TAG,"Unable to find instrumentation info for: " + className);
return false;
}
if (ai == null) {
/**
/*@Mayloon update
*/
//reportStartInstrumentationFailure(watcher, className,
//"Unable to find instrumentation target package: " + ii.targetPackage);
Log.e(TAG,"Unable to find instrumentation target package: " + ii.targetPackage);
return false;
}
/**
/*@Mayloon update
*/
/*
int match = mContext.getPackageManager().checkSignatures(
ii.targetPackage, ii.packageName);
if (match < 0 && match != PackageManager.SIGNATURE_FIRST_NOT_SIGNED) {
String msg = "Permission Denial: starting instrumentation "
+ className + " from pid="
+ Binder.getCallingPid()
+ ", uid=" + Binder.getCallingPid()
+ " not allowed because package " + ii.packageName
+ " does not have a signature matching the target "
+ ii.targetPackage;
reportStartInstrumentationFailure(watcher, className, msg);
throw new SecurityException(msg);
}
*/
/**
/*@Mayloon update
*/
//final long origId = Binder.clearCallingIdentity();
//forceStopPackageLocked(ii.targetPackage, -1, true, false, true);
ProcessRecord app = addAppLocked(ai);
app.instrumentationClass = className;
app.instrumentationInfo = ai;
app.instrumentationProfileFile = profileFile;
app.instrumentationArguments = arguments;
/**
/*@Mayloon update
*/
//app.instrumentationWatcher = watcher;
app.instrumentationResultClass = className;
/**
/*@Mayloon update
*/
//Binder.restoreCallingIdentity(origId);
/**
* @Mayloon update
* Comment this for bug 808
*/
//if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) {
mPersistentStartingProcesses.add(app);
startProcessLocked(app, "added application", app.processName);
Log.i(TAG, "start process locked");
//}
return true;
}
/**
* @j2sNative
* console.log("Missing method: getProcessMemoryInfo");
*/
@MayloonStubAnnotation()
public Object[] getProcessMemoryInfo(int[] pids) {
System.out.println("Stub" + " Function : getProcessMemoryInfo");
return null;
}
/**
* @j2sNative
* console.log("Missing method: killBackgroundProcesses");
*/
@MayloonStubAnnotation()
public void killBackgroundProcesses(String packageName) {
System.out.println("Stub" + " Function : killBackgroundProcesses");
return;
}
/**
* @j2sNative
* console.log("Missing method: getMemoryInfo");
*/
@MayloonStubAnnotation()
public void getMemoryInfo(Object outInfo) {
System.out.println("Stub" + " Function : getMemoryInfo");
return;
}
/**
* @j2sNative
* console.log("Missing method: getRunningServices");
*/
@MayloonStubAnnotation()
public List getRunningServices(int maxNum) {
System.out.println("Stub" + " Function : getRunningServices");
return null;
}
/**
* @j2sNative
* console.log("Missing method: getRunningAppProcesses");
*/
@MayloonStubAnnotation()
public List getRunningAppProcesses() {
System.out.println("Stub" + " Function : getRunningAppProcesses");
return null;
}
/**
* @j2sNative
* console.log("Missing method: getMemoryClass");
*/
@MayloonStubAnnotation()
public int getMemoryClass() {
System.out.println("Stub" + " Function : getMemoryClass");
return 0;
}
/**
* @j2sNative
* console.log("Missing method: restartPackage");
*/
@MayloonStubAnnotation()
public void restartPackage(String packageName) {
System.out.println("Stub" + " Function : restartPackage");
return;
}
/**
* @j2sNative
* console.log("Missing method: isUserAMonkey");
*/
@MayloonStubAnnotation()
public static boolean isUserAMonkey() {
System.out.println("Stub" + " Function : isUserAMonkey");
return true;
}
/**
* @j2sNative
* console.log("Missing method: getRunningTasks");
*/
@MayloonStubAnnotation()
public List getRunningTasks(int maxNum) {
System.out.println("Stub" + " Function : getRunningTasks");
return null;
}
/**
* @j2sNative
* console.log("Missing method: MemoryInfo");
*/
@MayloonStubAnnotation()
public void MemoryInfo() {
System.out.println("Stub" + " Function : MemoryInfo");
return;
}
}