summaryrefslogtreecommitdiffstats
path: root/services/java/com/android/server
diff options
context:
space:
mode:
Diffstat (limited to 'services/java/com/android/server')
-rw-r--r--services/java/com/android/server/GadgetService.java137
-rw-r--r--services/java/com/android/server/InputMethodManagerService.java479
-rw-r--r--services/java/com/android/server/LocationManagerService.java30
-rw-r--r--services/java/com/android/server/PackageManagerService.java7
-rw-r--r--services/java/com/android/server/PowerManagerService.java8
-rw-r--r--services/java/com/android/server/WifiService.java17
-rw-r--r--services/java/com/android/server/WindowManagerService.java232
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java76
-rwxr-xr-xservices/java/com/android/server/am/UsageStatsService.java410
9 files changed, 1018 insertions, 378 deletions
diff --git a/services/java/com/android/server/GadgetService.java b/services/java/com/android/server/GadgetService.java
index 5ef0fb9..ddf3afe 100644
--- a/services/java/com/android/server/GadgetService.java
+++ b/services/java/com/android/server/GadgetService.java
@@ -31,9 +31,10 @@ import android.content.pm.PackageItemInfo;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.gadget.GadgetManager;
-import android.gadget.GadgetInfo;
+import android.gadget.GadgetProviderInfo;
import android.net.Uri;
import android.os.Binder;
+import android.os.Bundle;
import android.os.RemoteException;
import android.os.SystemClock;
import android.util.AttributeSet;
@@ -78,7 +79,7 @@ class GadgetService extends IGadgetService.Stub
static class Provider {
int uid;
- GadgetInfo info;
+ GadgetProviderInfo info;
ArrayList<GadgetId> instances = new ArrayList();
PendingIntent broadcast;
@@ -106,7 +107,7 @@ class GadgetService extends IGadgetService.Stub
PackageManager mPackageManager;
AlarmManager mAlarmManager;
ArrayList<Provider> mInstalledProviders = new ArrayList();
- int mNextGadgetId = 1;
+ int mNextGadgetId = GadgetManager.INVALID_GADGET_ID + 1;
ArrayList<GadgetId> mGadgetIds = new ArrayList();
ArrayList<Host> mHosts = new ArrayList();
@@ -128,7 +129,6 @@ class GadgetService extends IGadgetService.Stub
// update the provider list.
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
mContext.registerReceiver(mBroadcastReceiver, filter);
@@ -148,7 +148,7 @@ class GadgetService extends IGadgetService.Stub
int N = mInstalledProviders.size();
pw.println("Providers: (size=" + N + ")");
for (int i=0; i<N; i++) {
- GadgetInfo info = mInstalledProviders.get(i).info;
+ GadgetProviderInfo info = mInstalledProviders.get(i).info;
pw.println(" [" + i + "] provder=" + info.provider
+ " min=(" + info.minWidth + "x" + info.minHeight + ")"
+ " updatePeriodMillis=" + info.updatePeriodMillis
@@ -265,7 +265,7 @@ class GadgetService extends IGadgetService.Stub
if (p != null) {
p.instances.remove(id);
// send the broacast saying that this gadgetId has been deleted
- Intent intent = new Intent(GadgetManager.GADGET_DELETED_ACTION);
+ Intent intent = new Intent(GadgetManager.ACTION_GADGET_DELETED);
intent.setComponent(p.info.provider);
intent.putExtra(GadgetManager.EXTRA_GADGET_ID, id.gadgetId);
mContext.sendBroadcast(intent);
@@ -274,7 +274,7 @@ class GadgetService extends IGadgetService.Stub
cancelBroadcasts(p);
// send the broacast saying that the provider is not in use any more
- intent = new Intent(GadgetManager.GADGET_DISABLED_ACTION);
+ intent = new Intent(GadgetManager.ACTION_GADGET_DISABLED);
intent.setComponent(p.info.provider);
mContext.sendBroadcast(intent);
}
@@ -331,7 +331,7 @@ class GadgetService extends IGadgetService.Stub
}
}
- public GadgetInfo getGadgetInfo(int gadgetId) {
+ public GadgetProviderInfo getGadgetInfo(int gadgetId) {
synchronized (mGadgetIds) {
GadgetId id = lookupGadgetIdLocked(gadgetId);
if (id != null) {
@@ -351,10 +351,10 @@ class GadgetService extends IGadgetService.Stub
}
}
- public List<GadgetInfo> getInstalledProviders() {
+ public List<GadgetProviderInfo> getInstalledProviders() {
synchronized (mGadgetIds) {
final int N = mInstalledProviders.size();
- ArrayList<GadgetInfo> result = new ArrayList(N);
+ ArrayList<GadgetProviderInfo> result = new ArrayList(N);
for (int i=0; i<N; i++) {
result.add(mInstalledProviders.get(i).info);
}
@@ -364,7 +364,7 @@ class GadgetService extends IGadgetService.Stub
public void updateGadgetIds(int[] gadgetIds, RemoteViews views) {
if (gadgetIds == null) {
- throw new IllegalArgumentException("bad gadgetIds");
+ return;
}
if (gadgetIds.length == 0) {
return;
@@ -408,7 +408,7 @@ class GadgetService extends IGadgetService.Stub
// the lock is held, but this is a oneway call
id.host.callbacks.updateGadget(id.gadgetId, views);
} catch (RemoteException e) {
- // It failed, remove the callback. No need to prune because
+ // It failed; remove the callback. No need to prune because
// we know that this host is still referenced by this instance.
id.host.callbacks = null;
}
@@ -524,10 +524,7 @@ class GadgetService extends IGadgetService.Stub
void getGadgetList() {
PackageManager pm = mPackageManager;
- // TODO: We have these as different actions. I wonder if it makes more sense to
- // have like a GADGET_ACTION, and then subcommands. It's kind of arbitrary that
- // we look for GADGET_UPDATE_ACTION and not any of the other gadget actions.
- Intent intent = new Intent(GadgetManager.GADGET_UPDATE_ACTION);
+ Intent intent = new Intent(GadgetManager.ACTION_GADGET_UPDATE);
List<ResolveInfo> broadcastReceivers = pm.queryBroadcastReceivers(intent,
PackageManager.GET_META_DATA);
@@ -538,11 +535,14 @@ class GadgetService extends IGadgetService.Stub
}
}
- void addProviderLocked(ResolveInfo ri) {
- Provider p = parseGadgetInfoXml(new ComponentName(ri.activityInfo.packageName,
+ boolean addProviderLocked(ResolveInfo ri) {
+ Provider p = parseProviderInfoXml(new ComponentName(ri.activityInfo.packageName,
ri.activityInfo.name), ri);
if (p != null) {
mInstalledProviders.add(p);
+ return true;
+ } else {
+ return false;
}
}
@@ -568,16 +568,18 @@ class GadgetService extends IGadgetService.Stub
}
void sendEnableIntentLocked(Provider p) {
- Intent intent = new Intent(GadgetManager.GADGET_ENABLED_ACTION);
+ Intent intent = new Intent(GadgetManager.ACTION_GADGET_ENABLED);
intent.setComponent(p.info.provider);
mContext.sendBroadcast(intent);
}
void sendUpdateIntentLocked(Provider p, int[] gadgetIds) {
- Intent intent = new Intent(GadgetManager.GADGET_UPDATE_ACTION);
- intent.putExtra(GadgetManager.EXTRA_GADGET_IDS, gadgetIds);
- intent.setComponent(p.info.provider);
- mContext.sendBroadcast(intent);
+ if (gadgetIds != null && gadgetIds.length > 0) {
+ Intent intent = new Intent(GadgetManager.ACTION_GADGET_UPDATE);
+ intent.putExtra(GadgetManager.EXTRA_GADGET_IDS, gadgetIds);
+ intent.setComponent(p.info.provider);
+ mContext.sendBroadcast(intent);
+ }
}
void registerForBroadcastsLocked(Provider p, int[] gadgetIds) {
@@ -587,7 +589,7 @@ class GadgetService extends IGadgetService.Stub
// PendingIntent.getBroadcast will update the extras.
boolean alreadyRegistered = p.broadcast != null;
int instancesSize = p.instances.size();
- Intent intent = new Intent(GadgetManager.GADGET_UPDATE_ACTION);
+ Intent intent = new Intent(GadgetManager.ACTION_GADGET_UPDATE);
intent.putExtra(GadgetManager.EXTRA_GADGET_IDS, gadgetIds);
intent.setComponent(p.info.provider);
long token = Binder.clearCallingIdentity();
@@ -614,16 +616,16 @@ class GadgetService extends IGadgetService.Stub
return gadgetIds;
}
- private Provider parseGadgetInfoXml(ComponentName component, ResolveInfo ri) {
+ private Provider parseProviderInfoXml(ComponentName component, ResolveInfo ri) {
Provider p = null;
ActivityInfo activityInfo = ri.activityInfo;
XmlResourceParser parser = null;
try {
parser = activityInfo.loadXmlMetaData(mPackageManager,
- GadgetManager.GADGET_PROVIDER_META_DATA);
+ GadgetManager.META_DATA_GADGET_PROVIDER);
if (parser == null) {
- Log.w(TAG, "No " + GadgetManager.GADGET_PROVIDER_META_DATA + " meta-data for "
+ Log.w(TAG, "No " + GadgetManager.META_DATA_GADGET_PROVIDER + " meta-data for "
+ "gadget provider '" + component + '\'');
return null;
}
@@ -644,7 +646,7 @@ class GadgetService extends IGadgetService.Stub
}
p = new Provider();
- GadgetInfo info = p.info = new GadgetInfo();
+ GadgetProviderInfo info = p.info = new GadgetProviderInfo();
info.provider = component;
p.uid = activityInfo.applicationInfo.uid;
@@ -672,6 +674,7 @@ class GadgetService extends IGadgetService.Stub
// of what a client process passes to us should not be fatal for the
// system process.
Log.w(TAG, "XML parsing failed for gadget provider '" + component + '\'', e);
+ return null;
} finally {
if (parser != null) parser.close();
}
@@ -979,20 +982,26 @@ class GadgetService extends IGadgetService.Stub
if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
synchronized (mGadgetIds) {
- addProvidersForPackageLocked(pkgName);
- saveStateLocked();
- }
- }
- else if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
- synchronized (mGadgetIds) {
- updateProvidersForPackageLocked(pkgName);
+ Bundle extras = intent.getExtras();
+ if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
+ // The package was just upgraded
+ updateProvidersForPackageLocked(pkgName);
+ } else {
+ // The package was just added
+ addProvidersForPackageLocked(pkgName);
+ }
saveStateLocked();
}
}
else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
- synchronized (mGadgetIds) {
- removeProvidersForPackageLocked(pkgName);
- saveStateLocked();
+ Bundle extras = intent.getExtras();
+ if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) {
+ // The package is being updated. We'll receive a PACKAGE_ADDED shortly.
+ } else {
+ synchronized (mGadgetIds) {
+ removeProvidersForPackageLocked(pkgName);
+ saveStateLocked();
+ }
}
}
}
@@ -1002,7 +1011,7 @@ class GadgetService extends IGadgetService.Stub
// TODO: If there's a better way of matching an intent filter against the
// packages for a given package, use that.
void addProvidersForPackageLocked(String pkgName) {
- Intent intent = new Intent(GadgetManager.GADGET_UPDATE_ACTION);
+ Intent intent = new Intent(GadgetManager.ACTION_GADGET_UPDATE);
List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
PackageManager.GET_META_DATA);
@@ -1021,7 +1030,7 @@ class GadgetService extends IGadgetService.Stub
// packages for a given package, use that.
void updateProvidersForPackageLocked(String pkgName) {
HashSet<String> keep = new HashSet();
- Intent intent = new Intent(GadgetManager.GADGET_UPDATE_ACTION);
+ Intent intent = new Intent(GadgetManager.ACTION_GADGET_UPDATE);
List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent,
PackageManager.GET_META_DATA);
@@ -1031,17 +1040,53 @@ class GadgetService extends IGadgetService.Stub
ResolveInfo ri = broadcastReceivers.get(i);
ActivityInfo ai = ri.activityInfo;
if (pkgName.equals(ai.packageName)) {
- Provider p = lookupProviderLocked(new ComponentName(ai.packageName, ai.name));
+ ComponentName component = new ComponentName(ai.packageName, ai.name);
+ Provider p = lookupProviderLocked(component);
if (p == null) {
- addProviderLocked(ri);
+ if (addProviderLocked(ri)) {
+ keep.add(ai.name);
+ }
+ } else {
+ Provider parsed = parseProviderInfoXml(component, ri);
+ if (parsed != null) {
+ keep.add(ai.name);
+ // Use the new GadgetProviderInfo.
+ GadgetProviderInfo oldInfo = p.info;
+ p.info = parsed.info;
+ // If it's enabled
+ final int M = p.instances.size();
+ if (M > 0) {
+ int[] gadgetIds = getGadgetIds(p);
+ // Reschedule for the new updatePeriodMillis (don't worry about handling
+ // it specially if updatePeriodMillis didn't change because we just sent
+ // an update, and the next one will be updatePeriodMillis from now).
+ cancelBroadcasts(p);
+ registerForBroadcastsLocked(p, gadgetIds);
+ // If it's currently showing, call back with the new GadgetProviderInfo.
+ for (int j=0; j<M; j++) {
+ GadgetId id = p.instances.get(j);
+ if (id.host != null && id.host.callbacks != null) {
+ try {
+ id.host.callbacks.providerChanged(id.gadgetId, p.info);
+ } catch (RemoteException ex) {
+ // It failed; remove the callback. No need to prune because
+ // we know that this host is still referenced by this
+ // instance.
+ id.host.callbacks = null;
+ }
+ }
+ }
+ // Now that we've told the host, push out an update.
+ sendUpdateIntentLocked(p, gadgetIds);
+ }
+ }
}
- keep.add(ai.name);
}
}
// prune the ones we don't want to keep
N = mInstalledProviders.size();
- for (int i=0; i<N; i++) {
+ for (int i=N-1; i>=0; i--) {
Provider p = mInstalledProviders.get(i);
if (pkgName.equals(p.info.provider.getPackageName())
&& !keep.contains(p.info.provider.getClassName())) {
@@ -1052,7 +1097,7 @@ class GadgetService extends IGadgetService.Stub
void removeProvidersForPackageLocked(String pkgName) {
int N = mInstalledProviders.size();
- for (int i=0; i<N; i++) {
+ for (int i=N-1; i>=0; i--) {
Provider p = mInstalledProviders.get(i);
if (pkgName.equals(p.info.provider.getPackageName())) {
removeProviderLocked(i, p);
@@ -1064,7 +1109,7 @@ class GadgetService extends IGadgetService.Stub
// By now, we have removed any gadgets that were in any hosts here,
// so we don't need to worry about sending DISABLE broadcasts to them.
N = mHosts.size();
- for (int i=0; i<N; i++) {
+ for (int i=N-1; i>=0; i--) {
Host host = mHosts.get(i);
if (pkgName.equals(host.packageName)) {
deleteHostLocked(host);
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index ee49365..7588129 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -55,8 +55,10 @@ import android.os.Message;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemClock;
import android.provider.Settings;
import android.text.TextUtils;
+import android.util.EventLog;
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Printer;
@@ -98,6 +100,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
static final int MSG_UNBIND_METHOD = 3000;
static final int MSG_BIND_METHOD = 3010;
+ static final long TIME_TO_RECONNECT = 10*1000;
+
+ static final int LOG_IMF_FORCE_RECONNECT_IME = 32000;
+
final Context mContext;
final Handler mHandler;
final SettingsObserver mSettingsObserver;
@@ -248,6 +254,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
IInputMethod mCurMethod;
/**
+ * Time that we last initiated a bind to the input method, to determine
+ * if we should try to disconnect and reconnect to it.
+ */
+ long mLastBindTime;
+
+ /**
* Have we called mCurMethod.bindInput()?
*/
boolean mBoundToMethod;
@@ -486,7 +498,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
public void systemReady() {
-
}
public List<InputMethodInfo> getInputMethodList() {
@@ -571,7 +582,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
- private int getShowFlags() {
+ private int getImeShowFlags() {
int flags = 0;
if (mShowForced) {
flags |= InputMethod.SHOW_FORCED
@@ -582,6 +593,16 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return flags;
}
+ private int getAppShowFlags() {
+ int flags = 0;
+ if (mShowForced) {
+ flags |= InputMethodManager.SHOW_FORCED;
+ } else if (!mShowExplicitlyRequested) {
+ flags |= InputMethodManager.SHOW_IMPLICIT;
+ }
+ return flags;
+ }
+
InputBindResult attachNewInputLocked(boolean initial, boolean needResult) {
if (!mBoundToMethod) {
executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
@@ -598,7 +619,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
if (mShowRequested) {
if (DEBUG) Log.v(TAG, "Attach new input asks to show input");
- showCurrentInputLocked(getShowFlags());
+ showCurrentInputLocked(getAppShowFlags());
}
return needResult
? new InputBindResult(session.session, mCurId, mCurSeq)
@@ -666,14 +687,31 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
return attachNewInputLocked(initial, needResult);
}
if (mHaveConnection) {
- if (mCurMethod != null && !cs.sessionRequested) {
- cs.sessionRequested = true;
- if (DEBUG) Log.v(TAG, "Creating new session for client " + cs);
- executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
- MSG_CREATE_SESSION, mCurMethod,
- new MethodCallback(mCurMethod)));
+ if (mCurMethod != null) {
+ if (!cs.sessionRequested) {
+ cs.sessionRequested = true;
+ if (DEBUG) Log.v(TAG, "Creating new session for client " + cs);
+ executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO(
+ MSG_CREATE_SESSION, mCurMethod,
+ new MethodCallback(mCurMethod)));
+ }
+ // Return to client, and we will get back with it when
+ // we have had a session made for it.
+ return new InputBindResult(null, mCurId, mCurSeq);
+ } else if (SystemClock.uptimeMillis()
+ < (mLastBindTime+TIME_TO_RECONNECT)) {
+ // In this case we have connected to the service, but
+ // don't yet have its interface. If it hasn't been too
+ // long since we did the connection, we'll return to
+ // the client and wait to get the service interface so
+ // we can report back. If it has been too long, we want
+ // to fall through so we can try a disconnect/reconnect
+ // to see if we can get back in touch with the service.
+ return new InputBindResult(null, mCurId, mCurSeq);
+ } else {
+ EventLog.writeEvent(LOG_IMF_FORCE_RECONNECT_IME, mCurMethodId,
+ SystemClock.uptimeMillis()-mLastBindTime, 0);
}
- return new InputBindResult(null, mCurId, mCurSeq);
}
}
@@ -682,6 +720,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
}
+ if (mHaveConnection) {
+ mContext.unbindService(this);
+ mHaveConnection = false;
+ }
+
if (mCurToken != null) {
try {
if (DEBUG) Log.v(TAG, "Removing window token: " + mCurToken);
@@ -691,16 +734,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
mCurToken = null;
}
- if (mHaveConnection) {
- mContext.unbindService(this);
- mHaveConnection = false;
- }
-
clearCurMethod();
mCurIntent = new Intent(InputMethod.SERVICE_INTERFACE);
mCurIntent.setComponent(info.getComponent());
if (mContext.bindService(mCurIntent, this, Context.BIND_AUTO_CREATE)) {
+ mLastBindTime = SystemClock.uptimeMillis();
mHaveConnection = true;
mCurId = info.getId();
mCurToken = new Binder();
@@ -758,7 +797,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
void onSessionCreated(IInputMethod method, IInputMethodSession session) {
synchronized (mMethodMap) {
- if (mCurMethod == method) {
+ if (mCurMethod != null && method != null
+ && mCurMethod.asBinder() == method.asBinder()) {
if (mCurClient != null) {
mCurClient.curSession = new SessionState(mCurClient,
method, session);
@@ -781,6 +821,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
mCurMethod = null;
}
+ mStatusBar.setIconVisibility(mInputMethodIcon, false);
}
public void onServiceDisconnected(ComponentName name) {
@@ -790,6 +831,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
if (mCurMethod != null && mCurIntent != null
&& name.equals(mCurIntent.getComponent())) {
clearCurMethod();
+ // We consider this to be a new bind attempt, since the system
+ // should now try to restart the service for us.
+ mLastBindTime = SystemClock.uptimeMillis();
mShowRequested = mInputShown;
mInputShown = false;
if (mCurClient != null) {
@@ -800,23 +844,28 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
}
- public void updateStatusIcon(int iconId, String iconPackage) {
- if (iconId == 0) {
- Log.d(TAG, "hide the small icon for the input method");
- mStatusBar.setIconVisibility(mInputMethodIcon, false);
- } else {
- Log.d(TAG, "show a small icon for the input method");
-
- if (iconPackage != null
- && iconPackage
- .equals(InputMethodManager.BUILDIN_INPUTMETHOD_PACKAGE)) {
- iconPackage = null;
+ public void updateStatusIcon(IBinder token, String packageName, int iconId) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ if (token == null || mCurToken != token) {
+ Log.w(TAG, "Ignoring setInputMethod of token: " + token);
+ return;
}
-
- mInputMethodData.iconId = iconId;
- mInputMethodData.iconPackage = iconPackage;
- mStatusBar.updateIcon(mInputMethodIcon, mInputMethodData, null);
- mStatusBar.setIconVisibility(mInputMethodIcon, true);
+
+ synchronized (mMethodMap) {
+ if (iconId == 0) {
+ if (DEBUG) Log.d(TAG, "hide the small icon for the input method");
+ mStatusBar.setIconVisibility(mInputMethodIcon, false);
+ } else if (packageName != null) {
+ if (DEBUG) Log.d(TAG, "show a small icon for the input method");
+ mInputMethodData.iconId = iconId;
+ mInputMethodData.iconPackage = packageName;
+ mStatusBar.updateIcon(mInputMethodIcon, mInputMethodData, null);
+ mStatusBar.setIconVisibility(mInputMethodIcon, true);
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
@@ -860,23 +909,28 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
public void showSoftInput(IInputMethodClient client, int flags) {
- synchronized (mMethodMap) {
- if (mCurClient == null || client == null
- || mCurClient.client.asBinder() != client.asBinder()) {
- try {
- // We need to check if this is the current client with
- // focus in the window manager, to allow this call to
- // be made before input is started in it.
- if (!mIWindowManager.inputMethodClientHasFocus(client)) {
- Log.w(TAG, "Ignoring showSoftInput of: " + client);
- return;
+ long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mMethodMap) {
+ if (mCurClient == null || client == null
+ || mCurClient.client.asBinder() != client.asBinder()) {
+ try {
+ // We need to check if this is the current client with
+ // focus in the window manager, to allow this call to
+ // be made before input is started in it.
+ if (!mIWindowManager.inputMethodClientHasFocus(client)) {
+ Log.w(TAG, "Ignoring showSoftInput of: " + client);
+ return;
+ }
+ } catch (RemoteException e) {
}
- } catch (RemoteException e) {
}
+
+ if (DEBUG) Log.v(TAG, "Client requesting input be shown");
+ showCurrentInputLocked(flags);
}
-
- if (DEBUG) Log.v(TAG, "Client requesting input be shown");
- showCurrentInputLocked(flags);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
@@ -891,29 +945,44 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
if (mCurMethod != null) {
executeOrSendMessage(mCurMethod, mCaller.obtainMessageIO(
- MSG_SHOW_SOFT_INPUT, getShowFlags(), mCurMethod));
+ MSG_SHOW_SOFT_INPUT, getImeShowFlags(), mCurMethod));
mInputShown = true;
+ } else if (mHaveConnection && SystemClock.uptimeMillis()
+ < (mLastBindTime+TIME_TO_RECONNECT)) {
+ // The client has asked to have the input method shown, but
+ // we have been sitting here too long with a connection to the
+ // service and no interface received, so let's disconnect/connect
+ // to try to prod things along.
+ EventLog.writeEvent(LOG_IMF_FORCE_RECONNECT_IME, mCurMethodId,
+ SystemClock.uptimeMillis()-mLastBindTime,1);
+ mContext.unbindService(this);
+ mContext.bindService(mCurIntent, this, Context.BIND_AUTO_CREATE);
}
}
public void hideSoftInput(IInputMethodClient client, int flags) {
- synchronized (mMethodMap) {
- if (mCurClient == null || client == null
- || mCurClient.client.asBinder() != client.asBinder()) {
- try {
- // We need to check if this is the current client with
- // focus in the window manager, to allow this call to
- // be made before input is started in it.
- if (!mIWindowManager.inputMethodClientHasFocus(client)) {
- Log.w(TAG, "Ignoring hideSoftInput of: " + client);
- return;
+ long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mMethodMap) {
+ if (mCurClient == null || client == null
+ || mCurClient.client.asBinder() != client.asBinder()) {
+ try {
+ // We need to check if this is the current client with
+ // focus in the window manager, to allow this call to
+ // be made before input is started in it.
+ if (!mIWindowManager.inputMethodClientHasFocus(client)) {
+ Log.w(TAG, "Ignoring hideSoftInput of: " + client);
+ return;
+ }
+ } catch (RemoteException e) {
}
- } catch (RemoteException e) {
}
+
+ if (DEBUG) Log.v(TAG, "Client requesting input be hidden");
+ hideCurrentInputLocked(flags);
}
-
- if (DEBUG) Log.v(TAG, "Client requesting input be hidden");
- hideCurrentInputLocked(flags);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
@@ -942,70 +1011,75 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
public void windowGainedFocus(IInputMethodClient client,
boolean viewHasFocus, boolean isTextEditor, int softInputMode,
boolean first, int windowFlags) {
- synchronized (mMethodMap) {
- if (DEBUG) Log.v(TAG, "windowGainedFocus: " + client.asBinder()
- + " viewHasFocus=" + viewHasFocus
- + " isTextEditor=" + isTextEditor
- + " softInputMode=#" + Integer.toHexString(softInputMode)
- + " first=" + first + " flags=#"
- + Integer.toHexString(windowFlags));
-
- if (mCurClient == null || client == null
- || mCurClient.client.asBinder() != client.asBinder()) {
- try {
- // We need to check if this is the current client with
- // focus in the window manager, to allow this call to
- // be made before input is started in it.
- if (!mIWindowManager.inputMethodClientHasFocus(client)) {
- Log.w(TAG, "Ignoring focus gain of: " + client);
- return;
+ long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mMethodMap) {
+ if (DEBUG) Log.v(TAG, "windowGainedFocus: " + client.asBinder()
+ + " viewHasFocus=" + viewHasFocus
+ + " isTextEditor=" + isTextEditor
+ + " softInputMode=#" + Integer.toHexString(softInputMode)
+ + " first=" + first + " flags=#"
+ + Integer.toHexString(windowFlags));
+
+ if (mCurClient == null || client == null
+ || mCurClient.client.asBinder() != client.asBinder()) {
+ try {
+ // We need to check if this is the current client with
+ // focus in the window manager, to allow this call to
+ // be made before input is started in it.
+ if (!mIWindowManager.inputMethodClientHasFocus(client)) {
+ Log.w(TAG, "Ignoring focus gain of: " + client);
+ return;
+ }
+ } catch (RemoteException e) {
}
- } catch (RemoteException e) {
}
- }
-
- switch (softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) {
- case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
- if (!isTextEditor || (softInputMode &
- WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
- != WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) {
- if (WindowManager.LayoutParams.mayUseInputMethod(windowFlags)) {
- // There is no focus view, and this window will
- // be behind any soft input window, so hide the
- // soft input window if it is shown.
- if (DEBUG) Log.v(TAG, "Unspecified window will hide input");
- hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS);
+
+ switch (softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) {
+ case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED:
+ if (!isTextEditor || (softInputMode &
+ WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
+ != WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) {
+ if (WindowManager.LayoutParams.mayUseInputMethod(windowFlags)) {
+ // There is no focus view, and this window will
+ // be behind any soft input window, so hide the
+ // soft input window if it is shown.
+ if (DEBUG) Log.v(TAG, "Unspecified window will hide input");
+ hideCurrentInputLocked(InputMethodManager.HIDE_NOT_ALWAYS);
+ }
+ } else if (isTextEditor && (softInputMode &
+ WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
+ == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
+ && (softInputMode &
+ WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
+ // There is a focus view, and we are navigating forward
+ // into the window, so show the input window for the user.
+ if (DEBUG) Log.v(TAG, "Unspecified window will show input");
+ showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT);
}
- } else if (isTextEditor && (softInputMode &
- WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
- == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
- && (softInputMode &
- WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
- // There is a focus view, and we are navigating forward
- // into the window, so show the input window for the user.
- if (DEBUG) Log.v(TAG, "Unspecified window will show input");
- showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT);
- }
- break;
- case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
- // Do nothing.
- break;
- case WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN:
- if (DEBUG) Log.v(TAG, "Window asks to hide input");
- hideCurrentInputLocked(0);
- break;
- case WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE:
- if ((softInputMode &
- WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
- if (DEBUG) Log.v(TAG, "Window asks to show input going forward");
+ break;
+ case WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED:
+ // Do nothing.
+ break;
+ case WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN:
+ if (DEBUG) Log.v(TAG, "Window asks to hide input");
+ hideCurrentInputLocked(0);
+ break;
+ case WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE:
+ if ((softInputMode &
+ WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0) {
+ if (DEBUG) Log.v(TAG, "Window asks to show input going forward");
+ showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT);
+ }
+ break;
+ case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
+ if (DEBUG) Log.v(TAG, "Window asks to always show input");
showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT);
- }
- break;
- case WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE:
- if (DEBUG) Log.v(TAG, "Window asks to always show input");
- showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT);
- break;
+ break;
+ }
}
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
}
@@ -1022,7 +1096,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
public void setInputMethod(IBinder token, String id) {
synchronized (mMethodMap) {
- if (mCurToken == null) {
+ if (token == null) {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.WRITE_SECURE_SETTINGS)
!= PackageManager.PERMISSION_GRANTED) {
@@ -1032,19 +1106,31 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
}
} else if (mCurToken != token) {
Log.w(TAG, "Ignoring setInputMethod of token: " + token);
+ return;
}
- setInputMethodLocked(id);
+ long ident = Binder.clearCallingIdentity();
+ try {
+ setInputMethodLocked(id);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
}
public void hideMySoftInput(IBinder token, int flags) {
synchronized (mMethodMap) {
- if (mCurToken == null || mCurToken != token) {
+ if (token == null || mCurToken != token) {
Log.w(TAG, "Ignoring hideInputMethod of token: " + token);
+ return;
}
- hideCurrentInputLocked(flags);
+ long ident = Binder.clearCallingIdentity();
+ try {
+ hideCurrentInputLocked(flags);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
}
}
@@ -1209,7 +1295,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
// ----------------------------------------------------------------------
- public void showInputMethodMenu() {
+ void showInputMethodMenu() {
if (DEBUG) Log.v(TAG, "Show switching menu");
hideInputMethodMenu();
@@ -1309,83 +1395,88 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
+ android.Manifest.permission.WRITE_SECURE_SETTINGS);
}
- // Make sure this is a valid input method.
- InputMethodInfo imm = mMethodMap.get(id);
- if (imm == null) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ // Make sure this is a valid input method.
+ InputMethodInfo imm = mMethodMap.get(id);
if (imm == null) {
- throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
+ if (imm == null) {
+ throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
+ }
}
- }
-
- StringBuilder builder = new StringBuilder(256);
-
- boolean removed = false;
- String firstId = null;
-
- // Look through the currently enabled input methods.
- String enabledStr = Settings.Secure.getString(mContext.getContentResolver(),
- Settings.Secure.ENABLED_INPUT_METHODS);
- if (enabledStr != null) {
- final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
- splitter.setString(enabledStr);
- while (splitter.hasNext()) {
- String curId = splitter.next();
- if (curId.equals(id)) {
- if (enabled) {
- // We are enabling this input method, but it is
- // already enabled. Nothing to do. The previous
- // state was enabled.
- return true;
+
+ StringBuilder builder = new StringBuilder(256);
+
+ boolean removed = false;
+ String firstId = null;
+
+ // Look through the currently enabled input methods.
+ String enabledStr = Settings.Secure.getString(mContext.getContentResolver(),
+ Settings.Secure.ENABLED_INPUT_METHODS);
+ if (enabledStr != null) {
+ final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
+ splitter.setString(enabledStr);
+ while (splitter.hasNext()) {
+ String curId = splitter.next();
+ if (curId.equals(id)) {
+ if (enabled) {
+ // We are enabling this input method, but it is
+ // already enabled. Nothing to do. The previous
+ // state was enabled.
+ return true;
+ }
+ // We are disabling this input method, and it is
+ // currently enabled. Skip it to remove from the
+ // new list.
+ removed = true;
+ } else if (!enabled) {
+ // We are building a new list of input methods that
+ // doesn't contain the given one.
+ if (firstId == null) firstId = curId;
+ if (builder.length() > 0) builder.append(':');
+ builder.append(curId);
}
- // We are disabling this input method, and it is
- // currently enabled. Skip it to remove from the
- // new list.
- removed = true;
- } else if (!enabled) {
- // We are building a new list of input methods that
- // doesn't contain the given one.
- if (firstId == null) firstId = curId;
- if (builder.length() > 0) builder.append(':');
- builder.append(curId);
}
}
- }
-
- if (!enabled) {
- if (!removed) {
- // We are disabling the input method but it is already
- // disabled. Nothing to do. The previous state was
- // disabled.
- return false;
- }
- // Update the setting with the new list of input methods.
- Settings.Secure.putString(mContext.getContentResolver(),
- Settings.Secure.ENABLED_INPUT_METHODS, builder.toString());
- // We the disabled input method is currently selected, switch
- // to another one.
- String selId = Settings.Secure.getString(mContext.getContentResolver(),
- Settings.Secure.DEFAULT_INPUT_METHOD);
- if (id.equals(selId)) {
+
+ if (!enabled) {
+ if (!removed) {
+ // We are disabling the input method but it is already
+ // disabled. Nothing to do. The previous state was
+ // disabled.
+ return false;
+ }
+ // Update the setting with the new list of input methods.
Settings.Secure.putString(mContext.getContentResolver(),
- Settings.Secure.DEFAULT_INPUT_METHOD,
- firstId != null ? firstId : "");
+ Settings.Secure.ENABLED_INPUT_METHODS, builder.toString());
+ // We the disabled input method is currently selected, switch
+ // to another one.
+ String selId = Settings.Secure.getString(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD);
+ if (id.equals(selId)) {
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD,
+ firstId != null ? firstId : "");
+ }
+ // Previous state was enabled.
+ return true;
}
- // Previous state was enabled.
- return true;
- }
-
- // Add in the newly enabled input method.
- if (enabledStr == null || enabledStr.length() == 0) {
- enabledStr = id;
- } else {
- enabledStr = enabledStr + ':' + id;
+
+ // Add in the newly enabled input method.
+ if (enabledStr == null || enabledStr.length() == 0) {
+ enabledStr = id;
+ } else {
+ enabledStr = enabledStr + ':' + id;
+ }
+
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.ENABLED_INPUT_METHODS, enabledStr);
+
+ // Previous state was disabled.
+ return false;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
-
- Settings.Secure.putString(mContext.getContentResolver(),
- Settings.Secure.ENABLED_INPUT_METHODS, enabledStr);
-
- // Previous state was disabled.
- return false;
}
}
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index bc6fd71..db4daa5 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -132,7 +132,7 @@ public class LocationManagerService extends ILocationManager.Stub
private static final int MESSAGE_HEARTBEAT = 1;
private static final int MESSAGE_ACQUIRE_WAKE_LOCK = 2;
private static final int MESSAGE_RELEASE_WAKE_LOCK = 3;
- private static final int MESSAGE_SET_NETWORK_LOCATION_PROVIDER = 4;
+ private static final int MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER = 4;
// Alarm manager and wakelock variables
private final static String ALARM_INTENT = "com.android.location.ALARM_INTENT";
@@ -565,13 +565,21 @@ public class LocationManagerService extends ILocationManager.Stub
}
}
- public void setNetworkLocationProvider(INetworkLocationProvider provider) {
- mLocationHandler.removeMessages(MESSAGE_SET_NETWORK_LOCATION_PROVIDER);
+ public void setInstallCallback(InstallCallback callback) {
+ mLocationHandler.removeMessages(MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER);
Message m = Message.obtain(mLocationHandler,
- MESSAGE_SET_NETWORK_LOCATION_PROVIDER, provider);
+ MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER, callback);
mLocationHandler.sendMessageAtFrontOfQueue(m);
}
+ public void setNetworkLocationProvider(INetworkLocationProvider provider) {
+ mNetworkLocationInterface = provider;
+ provider.addListener(getPackageNames());
+ mNetworkLocationProvider = (LocationProviderImpl)provider;
+ LocationProviderImpl.addProvider(mNetworkLocationProvider);
+ updateProviders();
+ }
+
public void setLocationCollector(ILocationCollector collector) {
mCollector = collector;
if (mGpsLocationProvider != null) {
@@ -1598,16 +1606,12 @@ public class LocationManagerService extends ILocationManager.Stub
// Update wakelock status so the next alarm is set before releasing wakelock
updateWakelockStatus(mScreenOn);
releaseWakeLock();
- } else if (msg.what == MESSAGE_SET_NETWORK_LOCATION_PROVIDER) {
+ } else if (msg.what == MESSAGE_INSTALL_NETWORK_LOCATION_PROVIDER) {
synchronized (LocationManagerService.class) {
- Log.d(TAG, "adding network location provider");
- mNetworkLocationInterface =
- (INetworkLocationProvider)msg.obj;
- mNetworkLocationInterface.addListener(getPackageNames());
- mNetworkLocationProvider =
- (LocationProviderImpl)mNetworkLocationInterface;
- LocationProviderImpl.addProvider(mNetworkLocationProvider);
- updateProviders();
+ Log.d(TAG, "installing network location provider");
+ INetworkLocationManager.InstallCallback callback =
+ (INetworkLocationManager.InstallCallback)msg.obj;
+ callback.installNetworkLocationProvider(mContext, LocationManagerService.this);
}
}
} catch (Exception e) {
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 221ba46..c490e42 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -3219,12 +3219,15 @@ class PackageManagerService extends IPackageManager.Stub {
Log.i(TAG, "Observer no longer exists.");
}
}
- // There appears to be a subtle deadlock condition if the sendPackageBroadcast call appears
- // in the synchronized block above.
+ // There appears to be a subtle deadlock condition if the sendPackageBroadcast
+ // call appears in the synchronized block above.
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
res.removedInfo.sendBroadcast(false, true);
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, res.uid);
+ if (res.removedInfo.removedPackage != null) {
+ extras.putBoolean(Intent.EXTRA_REPLACING, true);
+ }
sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED,
res.pkg.applicationInfo.packageName,
extras);
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 7c111d3..6974b5e 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -1001,11 +1001,9 @@ class PowerManagerService extends IPowerManager.Stub implements LocalPowerManage
}
}
else {
- synchronized (mLocks) {
- EventLog.writeEvent(LOG_POWER_SCREEN_BROADCAST_STOP, 4,
- mBroadcastWakeLock.mCount);
- mBroadcastWakeLock.release();
- }
+ // If we're in this case, then this handler is running for a previous
+ // paired transaction. mBroadcastWakeLock will already have been released
+ // in sendNotificationLocked.
}
}
};
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index c009fac..eece581 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -87,10 +87,13 @@ public class WifiService extends IWifiManager.Stub {
private final LockList mLocks = new LockList();
/**
- * See {@link Settings.System#WIFI_IDLE_MS}. This is the default value if a
- * Settings.System value is not present.
+ * See {@link Settings.Gservices#WIFI_IDLE_MS}. This is the default value if a
+ * Settings.Gservices value is not present. This timeout value is chosen as
+ * the approximate point at which the battery drain caused by Wi-Fi
+ * being enabled but not active exceeds the battery drain caused by
+ * re-establishing a connection to the mobile data network.
*/
- private static final long DEFAULT_IDLE_MILLIS = 2 * 60 * 1000; /* 2 minutes */
+ private static final long DEFAULT_IDLE_MILLIS = 15 * 60 * 1000; /* 15 minutes */
private static final String WAKELOCK_TAG = "WifiService";
@@ -101,7 +104,7 @@ public class WifiService extends IWifiManager.Stub {
* provides a bit of extra margin.
* <p>
* See {@link android.provider.Settings.Secure#WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS}.
- * This is the default value if a Settings.System value is not present.
+ * This is the default value if a Settings.Secure value is not present.
*/
private static final int DEFAULT_WAKELOCK_TIMEOUT = 8000;
@@ -1364,7 +1367,7 @@ public class WifiService extends IWifiManager.Stub {
* in the current regulatory domain. This method should be used only
* if the correct number of channels cannot be determined automatically
* for some reason. If the operation is successful, the new value is
- * persisted as a System setting.
+ * persisted as a Secure setting.
* @param numChannels the number of allowed channels. Must be greater than 0
* and less than or equal to 16.
* @return {@code true} if the operation succeeds, {@code false} otherwise, e.g.,
@@ -1446,8 +1449,8 @@ public class WifiService extends IWifiManager.Stub {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
- long idleMillis = Settings.System.getLong(mContext.getContentResolver(),
- Settings.System.WIFI_IDLE_MS, DEFAULT_IDLE_MILLIS);
+ long idleMillis = Settings.Gservices.getLong(mContext.getContentResolver(),
+ Settings.Gservices.WIFI_IDLE_MS, DEFAULT_IDLE_MILLIS);
int stayAwakeConditions =
Settings.System.getInt(mContext.getContentResolver(),
Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0);
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 09f5d8f..fed6d12 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -768,27 +768,55 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (willMove && w != null) {
final WindowState curTarget = mInputMethodTarget;
if (curTarget != null && curTarget.mAppToken != null) {
- int curIndex = -1;
- if (DEBUG_INPUT_METHOD) Log.v(TAG, "mNextAppTransition="
- + mNextAppTransition + " curTarget animating="
- + curTarget.isAnimating()
- + " layer=" + curTarget.mAnimLayer
- + " new layer=" + w.mAnimLayer);
- if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
- // If we are currently setting up for an animation,
- // hold everything until we can find out what will happen.
- mInputMethodTargetWaitingAnim = true;
- curIndex = localmWindows.indexOf(curTarget);
- } else if (curTarget.isAnimating() &&
- curTarget.mAnimLayer > w.mAnimLayer) {
- // If the window we are currently targeting is involved
- // with an animation, and it is on top of the next target
- // we will be over, then hold off on moving until
- // that is done.
- curIndex = localmWindows.indexOf(curTarget);
- }
- if (curIndex >= 0) {
- return curIndex + 1;
+
+ // Now some fun for dealing with window animations that
+ // modify the Z order. We need to look at all windows below
+ // the current target that are in this app, finding the highest
+ // visible one in layering.
+ AppWindowToken token = curTarget.mAppToken;
+ WindowState highestTarget = null;
+ int highestPos = 0;
+ if (token.animating || token.animation != null) {
+ int pos = 0;
+ pos = localmWindows.indexOf(curTarget);
+ while (pos >= 0) {
+ WindowState win = (WindowState)localmWindows.get(pos);
+ if (win.mAppToken != token) {
+ break;
+ }
+ if (!win.mRemoved) {
+ if (highestTarget == null || win.mAnimLayer >
+ highestTarget.mAnimLayer) {
+ highestTarget = win;
+ highestPos = pos;
+ }
+ }
+ pos--;
+ }
+ }
+
+ if (highestTarget != null) {
+ if (DEBUG_INPUT_METHOD) Log.v(TAG, "mNextAppTransition="
+ + mNextAppTransition + " " + highestTarget
+ + " animating=" + highestTarget.isAnimating()
+ + " layer=" + highestTarget.mAnimLayer
+ + " new layer=" + w.mAnimLayer);
+
+ if (mNextAppTransition != WindowManagerPolicy.TRANSIT_NONE) {
+ // If we are currently setting up for an animation,
+ // hold everything until we can find out what will happen.
+ mInputMethodTargetWaitingAnim = true;
+ mInputMethodTarget = highestTarget;
+ return highestPos + 1;
+ } else if (highestTarget.isAnimating() &&
+ highestTarget.mAnimLayer > w.mAnimLayer) {
+ // If the window we are currently targeting is involved
+ // with an animation, and it is on top of the next target
+ // we will be over, then hold off on moving until
+ // that is done.
+ mInputMethodTarget = highestTarget;
+ return highestPos + 1;
+ }
}
}
}
@@ -891,12 +919,27 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
+ void logWindowList(String prefix) {
+ int N = mWindows.size();
+ while (N > 0) {
+ N--;
+ Log.v(TAG, prefix + "#" + N + ": " + mWindows.get(N));
+ }
+ }
+
void moveInputMethodDialogsLocked(int pos) {
ArrayList<WindowState> dialogs = mInputMethodDialogs;
+
final int N = dialogs.size();
+ if (DEBUG_INPUT_METHOD) Log.v(TAG, "Removing " + N + " dialogs w/pos=" + pos);
for (int i=0; i<N; i++) {
pos = tmpRemoveWindowLocked(pos, dialogs.get(i));
}
+ if (DEBUG_INPUT_METHOD) {
+ Log.v(TAG, "Window list w/pos=" + pos);
+ logWindowList(" ");
+ }
+
if (pos >= 0) {
final AppWindowToken targetAppToken = mInputMethodTarget.mAppToken;
if (pos < mWindows.size()) {
@@ -905,17 +948,26 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
pos++;
}
}
+ if (DEBUG_INPUT_METHOD) Log.v(TAG, "Adding " + N + " dialogs at pos=" + pos);
for (int i=0; i<N; i++) {
WindowState win = dialogs.get(i);
win.mTargetAppToken = targetAppToken;
pos = reAddWindowLocked(pos, win);
}
+ if (DEBUG_INPUT_METHOD) {
+ Log.v(TAG, "Final window list:");
+ logWindowList(" ");
+ }
return;
}
for (int i=0; i<N; i++) {
WindowState win = dialogs.get(i);
win.mTargetAppToken = null;
reAddWindowToListInOrderLocked(win);
+ if (DEBUG_INPUT_METHOD) {
+ Log.v(TAG, "No IM target, final list:");
+ logWindowList(" ");
+ }
}
}
@@ -971,9 +1023,21 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
if (imWin != null) {
+ if (DEBUG_INPUT_METHOD) {
+ Log.v(TAG, "Moving IM from " + imPos);
+ logWindowList(" ");
+ }
imPos = tmpRemoveWindowLocked(imPos, imWin);
+ if (DEBUG_INPUT_METHOD) {
+ Log.v(TAG, "List after moving with new pos " + imPos + ":");
+ logWindowList(" ");
+ }
imWin.mTargetAppToken = mInputMethodTarget.mAppToken;
reAddWindowLocked(imPos, imWin);
+ if (DEBUG_INPUT_METHOD) {
+ Log.v(TAG, "List after moving IM to " + imPos + ":");
+ logWindowList(" ");
+ }
if (DN > 0) moveInputMethodDialogsLocked(imPos+1);
} else {
moveInputMethodDialogsLocked(imPos);
@@ -984,9 +1048,14 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// because they aren't currently associated with a focus window.
if (imWin != null) {
+ if (DEBUG_INPUT_METHOD) Log.v(TAG, "Moving IM from " + imPos);
tmpRemoveWindowLocked(0, imWin);
imWin.mTargetAppToken = null;
reAddWindowToListInOrderLocked(imWin);
+ if (DEBUG_INPUT_METHOD) {
+ Log.v(TAG, "List with no IM target:");
+ logWindowList(" ");
+ }
if (DN > 0) moveInputMethodDialogsLocked(-1);;
} else {
moveInputMethodDialogsLocked(-1);;
@@ -1233,7 +1302,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (win.mSurface != null && !mDisplayFrozen) {
// If we are not currently running the exit animation, we
// need to see about starting one.
- if (wasVisible=win.isVisibleLw()) {
+ if (wasVisible=win.isWinVisibleLw()) {
int transit = WindowManagerPolicy.TRANSIT_EXIT;
if (win.getAttrs().type == TYPE_APPLICATION_STARTING) {
@@ -1277,6 +1346,12 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mKeyWaiter.releasePendingPointerLocked(win.mSession);
mKeyWaiter.releasePendingTrackballLocked(win.mSession);
+ win.mRemoved = true;
+
+ if (mInputMethodTarget == win) {
+ moveInputMethodWindowsIfNeededLocked(false);
+ }
+
mPolicy.removeWindowLw(win);
win.removeLocked();
@@ -1501,7 +1576,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (win.getAttrs().type == TYPE_APPLICATION_STARTING) {
transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
}
- if (win.isVisibleLw() &&
+ if (win.isWinVisibleLw() &&
applyAnimationLocked(win, transit, false)) {
win.mExiting = true;
mKeyWaiter.finishedKey(session, client, true,
@@ -1511,13 +1586,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// an exit.
win.mExiting = true;
} else {
+ if (mInputMethodWindow == win) {
+ mInputMethodWindow = null;
+ }
win.destroySurfaceLocked();
}
}
}
- if (mInputMethodWindow == win) {
- mInputMethodWindow = null;
- }
outSurface.clear();
}
@@ -1620,7 +1695,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
private boolean applyAnimationLocked(WindowState win,
int transit, boolean isEntrance) {
- if (win.mAnimating && win.mAnimationIsEntrance == isEntrance) {
+ if (win.mLocalAnimating && win.mAnimationIsEntrance == isEntrance) {
// If we are trying to apply an animation, but already running
// an animation of the same type, then just leave that one alone.
return true;
@@ -1666,6 +1741,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
Log.v(TAG, "Loaded animation " + a + " for " + win, e);
}
win.setAnimation(a);
+ win.mAnimationIsEntrance = isEntrance;
}
} else {
win.clearAnimation();
@@ -2724,7 +2800,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
boolean added = false;
for (int j=0; j<NCW; j++) {
WindowState cwin = (WindowState)win.mChildWindows.get(j);
- if (cwin.mSubLayer >= 0) {
+ if (!added && cwin.mSubLayer >= 0) {
mWindows.add(index, win);
index++;
added = true;
@@ -4645,8 +4721,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
KeyQ() {
super(mContext);
PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
- mHoldingScreen = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK
- | PowerManager.ON_AFTER_RELEASE, "KEEP_SCREEN_ON_FLAG");
+ mHoldingScreen = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
+ "KEEP_SCREEN_ON_FLAG");
mHoldingScreen.setReferenceCounted(false);
}
@@ -4769,8 +4845,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (holding) {
mHoldingScreen.acquire();
} else {
- long curTime = SystemClock.uptimeMillis();
- mPowerManager.userActivity(curTime, false, LocalPowerManager.OTHER_EVENT);
+ mPolicy.screenOnStopped();
mHoldingScreen.release();
}
}
@@ -5095,6 +5170,19 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
}
+ public boolean performHapticFeedback(IWindow window, int effectId,
+ boolean always) {
+ synchronized(mWindowMap) {
+ long ident = Binder.clearCallingIdentity();
+ try {
+ return mPolicy.performHapticFeedback(
+ windowForClientLocked(this, window), effectId, always);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
+ }
+
void windowAddedLocked() {
if (mSurfaceSession == null) {
if (localLOGV) Log.v(
@@ -5255,9 +5343,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// Currently running animation.
boolean mAnimating;
+ boolean mLocalAnimating;
Animation mAnimation;
boolean mAnimationIsEntrance;
boolean mHasTransformation;
+ boolean mHasLocalTransformation;
final Transformation mTransformation = new Transformation();
// This is set after IWindowSession.relayout() has been called at
@@ -5297,6 +5387,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// been updated for the new orientation.
boolean mOrientationChanging;
+ // Is this window now (or just being) removed?
+ boolean mRemoved;
+
WindowState(Session s, IWindow c, WindowToken token,
WindowState attachedWindow, WindowManager.LayoutParams a,
int viewVisibility) {
@@ -5516,6 +5609,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (localLOGV) Log.v(
TAG, "Setting animation in " + this + ": " + anim);
mAnimating = false;
+ mLocalAnimating = false;
mAnimation = anim;
mAnimation.restrictDuration(MAX_ANIMATION_DURATION);
mAnimation.scaleCurrentDuration(mWindowAnimationScale);
@@ -5524,6 +5618,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
public void clearAnimation() {
if (mAnimation != null) {
mAnimating = true;
+ mLocalAnimating = false;
mAnimation = null;
}
}
@@ -5752,13 +5847,15 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (!mDrawPending && !mCommitDrawPending && mAnimation != null) {
mHasTransformation = true;
- if (!mAnimating) {
+ mHasLocalTransformation = true;
+ if (!mLocalAnimating) {
if (DEBUG_ANIM) Log.v(
TAG, "Starting animation in " + this +
" @ " + currentTime + ": ww=" + mFrame.width() + " wh=" + mFrame.height() +
" dw=" + dw + " dh=" + dh + " scale=" + mWindowAnimationScale);
mAnimation.initialize(mFrame.width(), mFrame.height(), dw, dh);
mAnimation.setStartTime(currentTime);
+ mLocalAnimating = true;
mAnimating = true;
}
mTransformation.clear();
@@ -5767,9 +5864,6 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (DEBUG_ANIM) Log.v(
TAG, "Stepped animation in " + this +
": more=" + more + ", xform=" + mTransformation);
- if (mAppToken != null && mAppToken.hasTransformation) {
- mTransformation.compose(mAppToken.transformation);
- }
if (more) {
// we're not done!
return true;
@@ -5780,10 +5874,19 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
mAnimation = null;
//WindowManagerService.this.dump();
}
- if (mAppToken != null && mAppToken.hasTransformation) {
+ mHasLocalTransformation = false;
+ if ((!mLocalAnimating || mAnimationIsEntrance) && mAppToken != null
+ && mAppToken.hasTransformation) {
+ // When our app token is animating, we kind-of pretend like
+ // we are as well. Note the mLocalAnimating mAnimationIsEntrance
+ // part of this check means that we will only do this if
+ // our window is not currently exiting, or it is not
+ // locally animating itself. The idea being that one that
+ // is exiting and doing a local animation should be removed
+ // once that animation is done.
mAnimating = true;
mHasTransformation = true;
- mTransformation.set(mAppToken.transformation);
+ mTransformation.clear();
return false;
} else if (mHasTransformation) {
// Little trick to get through the path below to act like
@@ -5796,10 +5899,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
// If the display is frozen, and there is a pending animation,
// clear it and make sure we run the cleanup code.
mAnimating = true;
+ mLocalAnimating = true;
mAnimation = null;
}
- if (!mAnimating) {
+ if (!mAnimating && !mLocalAnimating) {
return false;
}
@@ -5809,6 +5913,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ (mAppToken != null ? mAppToken.reportedVisible : false));
mAnimating = false;
+ mLocalAnimating = false;
mAnimation = null;
mAnimLayer = mLayer;
if (mIsImWindow) {
@@ -5817,6 +5922,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (DEBUG_LAYERS) Log.v(TAG, "Stepping win " + this
+ " anim layer: " + mAnimLayer);
mHasTransformation = false;
+ mHasLocalTransformation = false;
mPolicyVisibility = mPolicyVisibilityAfterAnim;
mTransformation.clear();
if (mHasDrawn
@@ -5891,10 +5997,15 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
void computeShownFrameLocked() {
- final boolean selfTransformation = mHasTransformation;
- final boolean attachedTransformation = (mAttachedWindow != null
- && mAttachedWindow.mHasTransformation);
- if (selfTransformation || attachedTransformation) {
+ final boolean selfTransformation = mHasLocalTransformation;
+ Transformation attachedTransformation =
+ (mAttachedWindow != null && mAttachedWindow.mHasLocalTransformation)
+ ? mAttachedWindow.mTransformation : null;
+ Transformation appTransformation =
+ (mAppToken != null && mAppToken.hasTransformation)
+ ? mAppToken.transformation : null;
+ if (selfTransformation || attachedTransformation != null
+ || appTransformation != null) {
// cache often used attributes locally
final Rect frame = mFrame;
final float tmpFloats[] = mTmpFloats;
@@ -5905,8 +6016,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (selfTransformation) {
tmpMatrix.preConcat(mTransformation.getMatrix());
}
- if (attachedTransformation) {
- tmpMatrix.preConcat(mAttachedWindow.mTransformation.getMatrix());
+ if (attachedTransformation != null) {
+ tmpMatrix.preConcat(attachedTransformation.getMatrix());
+ }
+ if (appTransformation != null) {
+ tmpMatrix.preConcat(appTransformation.getMatrix());
}
// "convert" it into SurfaceFlinger's format
@@ -5940,8 +6054,11 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
if (selfTransformation) {
mShownAlpha *= mTransformation.getAlpha();
}
- if (attachedTransformation) {
- mShownAlpha *= mAttachedWindow.mTransformation.getAlpha();
+ if (attachedTransformation != null) {
+ mShownAlpha *= attachedTransformation.getAlpha();
+ }
+ if (appTransformation != null) {
+ mShownAlpha *= appTransformation.getAlpha();
}
} else {
//Log.i(TAG, "Not applying alpha transform");
@@ -5965,7 +6082,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
/**
* Is this window visible? It is not visible if there is no
* surface, or we are in the process of running an exit animation
- * that will remove the surface.
+ * that will remove the surface, or its app token has been hidden.
*/
public boolean isVisibleLw() {
final AppWindowToken atoken = mAppToken;
@@ -5975,6 +6092,18 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
}
/**
+ * Is this window visible, ignoring its app token? It is not visible
+ * if there is no surface, or we are in the process of running an exit animation
+ * that will remove the surface.
+ */
+ public boolean isWinVisibleLw() {
+ final AppWindowToken atoken = mAppToken;
+ return mSurface != null && mPolicyVisibility && !mAttachedHidden
+ && (atoken == null || !atoken.hiddenRequested || atoken.animating)
+ && !mExiting && !mDestroying;
+ }
+
+ /**
* The same as isVisible(), but follows the current hidden state of
* the associated app token, not the pending requested hidden state.
*/
@@ -6203,6 +6332,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
pw.println(prefix + "mShownAlpha=" + mShownAlpha
+ " mAlpha=" + mAlpha + " mLastAlpha=" + mLastAlpha);
pw.println(prefix + "mAnimating=" + mAnimating
+ + " mLocalAnimating=" + mLocalAnimating
+ " mAnimationIsEntrance=" + mAnimationIsEntrance
+ " mAnimation=" + mAnimation);
pw.println(prefix + "XForm: has=" + mHasTransformation
@@ -6213,7 +6343,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
+ " mHasDrawn=" + mHasDrawn);
pw.println(prefix + "mExiting=" + mExiting
+ " mRemoveOnExit=" + mRemoveOnExit
- + " mDestroying=" + mDestroying);
+ + " mDestroying=" + mDestroying
+ + " mRemoved=" + mRemoved);
pw.println(prefix + "mOrientationChanging=" + mOrientationChanging
+ " mAppFreezing=" + mAppFreezing);
}
@@ -7959,6 +8090,9 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo
i--;
WindowState win = mDestroySurface.get(i);
win.mDestroying = false;
+ if (mInputMethodWindow == win) {
+ mInputMethodWindow = null;
+ }
win.destroySurfaceLocked();
} while (i > 0);
mDestroySurface.clear();
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index f5efe4b..e391da3 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -159,7 +159,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
static final int LOG_AM_BROADCAST_DISCARD_APP = 30025;
static final int LOG_AM_CREATE_SERVICE = 30030;
static final int LOG_AM_DESTROY_SERVICE = 30031;
-
+ static final int LOG_AM_PROCESS_CRASHED_TOO_MUCH = 30032;
+ static final int LOG_AM_DROP_PROCESS = 30033;
+ static final int LOG_AM_SERVICE_CRASHED_TOO_MUCH = 30034;
+ static final int LOG_AM_SCHEDULE_SERVICE_RESTART = 30035;
+ static final int LOG_AM_PROVIDER_LOST_PROCESS = 30036;
+
static final int LOG_BOOT_PROGRESS_AMS_READY = 3040;
static final int LOG_BOOT_PROGRESS_ENABLE_SCREEN = 3050;
@@ -1787,7 +1792,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
- private final void startPausingLocked(boolean userLeaving) {
+ private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
if (mPausingActivity != null) {
RuntimeException e = new RuntimeException();
Log.e(TAG, "Trying to pause when pause is already pending for "
@@ -1840,9 +1845,15 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (mPausingActivity != null) {
// Have the window manager pause its key dispatching until the new
- // activity has started...
- prev.pauseKeyDispatchingLocked();
-
+ // activity has started. If we're pausing the activity just because
+ // the screen is being turned off and the UI is sleeping, don't interrupt
+ // key dispatch; the same activity will pick it up again on wakeup.
+ if (!uiSleeping) {
+ prev.pauseKeyDispatchingLocked();
+ } else {
+ if (DEBUG_PAUSE) Log.v(TAG, "Key dispatch not paused for screen off");
+ }
+
// Schedule a pause timeout in case the app doesn't respond.
// We don't give it much time because this directly impacts the
// responsiveness seen by the user.
@@ -2188,7 +2199,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// can be resumed...
if (mResumedActivity != null) {
if (DEBUG_SWITCH) Log.v(TAG, "Skip resume: need to start pausing");
- startPausingLocked(userLeaving);
+ startPausingLocked(userLeaving, false);
return true;
}
@@ -2605,8 +2616,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.app.thread.scheduleNewIntent(ar, r);
sent = true;
} catch (Exception e) {
- Log.w(TAG,
- "Exception thrown sending new intent to " + r, e);
+ Log.w(TAG, "Exception thrown sending new intent to " + r, e);
}
}
if (!sent) {
@@ -3456,7 +3466,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (mPausingActivity == null) {
if (DEBUG_PAUSE) Log.v(TAG, "Finish needs to pause: " + r);
if (DEBUG_USER_LEAVING) Log.v(TAG, "finish() => pause with userLeaving=false");
- startPausingLocked(false);
+ startPausingLocked(false, false);
}
} else if (r.state != ActivityState.PAUSING) {
@@ -3590,9 +3600,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.app.thread.scheduleSendResult(r, list);
return;
} catch (Exception e) {
- Log.w(TAG,
- "Exception thrown sending result to " + r,
- e);
+ Log.w(TAG, "Exception thrown sending result to " + r, e);
}
}
@@ -3778,8 +3786,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.configChangeFlags = 0;
if (!mLRUActivities.remove(r)) {
- Log.w(TAG, "Activity " + r
- + " being finished, but not in LRU list");
+ Log.w(TAG, "Activity " + r + " being finished, but not in LRU list");
}
return removedFromHistory;
@@ -4217,7 +4224,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} catch (RemoteException e) {
}
if (pkgUid == -1) {
- Log.w(TAG, "Invalid packageName:"+packageName);
+ Log.w(TAG, "Invalid packageName:" + packageName);
return false;
}
if (uid == pkgUid || checkComponentPermission(
@@ -4270,7 +4277,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
} catch (RemoteException e) {
}
if (pkgUid == -1) {
- Log.w(TAG, "Invalid packageName:"+packageName);
+ Log.w(TAG, "Invalid packageName: " + packageName);
return;
}
restartPackageLocked(packageName, pkgUid);
@@ -4423,6 +4430,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (app == null) {
Log.w(TAG, "No pending application record for pid " + pid
+ " (IApplicationThread " + thread + "); dropping process");
+ EventLog.writeEvent(LOG_AM_DROP_PROCESS, pid);
if (pid > 0 && pid != MY_PID) {
Process.killProcess(pid);
} else {
@@ -6579,10 +6587,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (caller != null) {
r = getRecordForAppLocked(caller);
if (r == null) {
- throw new SecurityException(
- "Unable to find app for caller " + caller
- + " (pid=" + Binder.getCallingPid()
- + ") when getting content provider " + name);
+ throw new SecurityException(
+ "Unable to find app for caller " + caller
+ + " (pid=" + Binder.getCallingPid()
+ + ") when getting content provider " + name);
}
}
@@ -6739,6 +6747,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
+ cpi.applicationInfo.packageName + "/"
+ cpi.applicationInfo.uid + " for provider "
+ name + ": launching app became null");
+ EventLog.writeEvent(LOG_AM_PROVIDER_LOST_PROCESS,
+ cpi.applicationInfo.packageName,
+ cpi.applicationInfo.uid, name);
+ return null;
}
try {
cpr.wait();
@@ -6844,9 +6856,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
ContentProviderRecord dst =
(ContentProviderRecord)r.pubProviders.get(src.info.name);
if (dst != null) {
- dst.provider = src.provider;
- dst.app = r;
-
mProvidersByClass.put(dst.info.name, dst);
String names[] = dst.info.authority.split(";");
for (int j = 0; j < names.length; j++) {
@@ -6863,6 +6872,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
}
}
synchronized (dst) {
+ dst.provider = src.provider;
+ dst.app = r;
dst.notifyAll();
}
updateOomAdjLocked(r);
@@ -6993,7 +7004,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (mPausingActivity == null) {
if (DEBUG_PAUSE) Log.v(TAG, "Sleep needs to pause...");
if (DEBUG_USER_LEAVING) Log.v(TAG, "Sleep => pause with userLeaving=false");
- startPausingLocked(false);
+ startPausingLocked(false, true);
}
}
}
@@ -7499,6 +7510,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// This process loses!
Log.w(TAG, "Process " + app.info.processName
+ " has crashed too many times: killing!");
+ EventLog.writeEvent(LOG_AM_PROCESS_CRASHED_TOO_MUCH,
+ app.info.processName, app.info.uid);
killServicesLocked(app, false);
for (int i=mHistory.size()-1; i>=0; i--) {
HistoryRecord r = (HistoryRecord)mHistory.get(i);
@@ -8429,6 +8442,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
if (sr.crashCount >= 2) {
Log.w(TAG, "Service crashed " + sr.crashCount
+ " times, stopping: " + sr);
+ EventLog.writeEvent(LOG_AM_SERVICE_CRASHED_TOO_MUCH,
+ sr.crashCount, sr.shortName, app.pid);
bringDownServiceLocked(sr, true);
} else if (!allowRestart) {
bringDownServiceLocked(sr, true);
@@ -8447,7 +8462,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
private final void removeDyingProviderLocked(ProcessRecord proc,
ContentProviderRecord cpr) {
- cpr.launchingApp = null;
+ synchronized (cpr) {
+ cpr.launchingApp = null;
+ cpr.notifyAll();
+ }
mProvidersByClass.remove(cpr.info.name);
String names[] = cpr.info.authority.split(";");
@@ -8529,6 +8547,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
break;
}
}
+ } else {
+ i = NL;
}
if (i >= NL) {
@@ -8602,7 +8622,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
mProcessesOnHold.remove(app);
if (restart) {
- // We have component that still need to be running in the
+ // We have components that still need to be running in the
// process, so re-launch it.
mProcessNames.put(app.processName, app.info.uid, app);
startProcessLocked(app, "restart", app.processName);
@@ -8952,6 +8972,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
r.nextRestartTime = SystemClock.uptimeMillis() + r.restartDelay;
Log.w(TAG, "Scheduling restart of crashed service "
+ r.shortName + " in " + r.restartDelay + "ms");
+ EventLog.writeEvent(LOG_AM_SCHEDULE_SERVICE_RESTART,
+ r.shortName, r.restartDelay);
Message msg = Message.obtain();
msg.what = SERVICE_ERROR_MSG;
@@ -11660,7 +11682,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen
// We can finish this one if we have its icicle saved and
// it is not persistent.
- if ((r.haveState || !r.stateNotNeeded)
+ if ((r.haveState || !r.stateNotNeeded) && !r.visible
&& r.stopped && !r.persistent && !r.finishing) {
final int origSize = mLRUActivities.size();
destroyActivityLocked(r, true);
diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/java/com/android/server/am/UsageStatsService.java
index 001987f..3922f39 100755
--- a/services/java/com/android/server/am/UsageStatsService.java
+++ b/services/java/com/android/server/am/UsageStatsService.java
@@ -22,13 +22,24 @@ import android.content.Context;
import android.os.Binder;
import android.os.IBinder;
import com.android.internal.os.PkgUsageStats;
+import android.os.Parcel;
import android.os.Process;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.util.Log;
+import java.io.File;
import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Date;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -44,35 +55,257 @@ public final class UsageStatsService extends IUsageStats.Stub {
private static final String TAG = "UsageStats";
static IUsageStats sService;
private Context mContext;
- private String mFileName;
+ // structure used to maintain statistics since the last checkin.
final private Map<String, PkgUsageStatsExtended> mStats;
+ // Lock to update package stats. Methods suffixed by SLOCK should invoked with
+ // this lock held
+ final Object mStatsLock;
+ // Lock to write to file. Methods suffixed by FLOCK should invoked with
+ // this lock held.
+ final Object mFileLock;
+ // Order of locks is mFileLock followed by mStatsLock to avoid deadlocks
private String mResumedPkg;
+ private File mFile;
+ //private File mBackupFile;
+ private long mLastWriteRealTime;
+ private int _FILE_WRITE_INTERVAL = 30*60*1000; //ms
+ private static final String _PREFIX_DELIMIT=".";
+ private String mFilePrefix;
+ private Calendar mCal;
+ private static final int _MAX_NUM_FILES = 10;
+ private long mLastTime;
private class PkgUsageStatsExtended {
int mLaunchCount;
long mUsageTime;
- long mChgTime;
+ long mPausedTime;
+ long mResumedTime;
+
PkgUsageStatsExtended() {
mLaunchCount = 0;
mUsageTime = 0;
- mChgTime = SystemClock.elapsedRealtime();
}
void updateResume() {
mLaunchCount ++;
- mChgTime = SystemClock.elapsedRealtime();
+ mResumedTime = SystemClock.elapsedRealtime();
}
void updatePause() {
- long currTime = SystemClock.elapsedRealtime();
- mUsageTime += (currTime - mChgTime);
- mChgTime = currTime;
+ mPausedTime = SystemClock.elapsedRealtime();
+ mUsageTime += (mPausedTime - mResumedTime);
+ }
+ void clear() {
+ mLaunchCount = 0;
+ mUsageTime = 0;
}
}
- UsageStatsService(String filename) {
- mFileName = filename;
+ UsageStatsService(String fileName) {
mStats = new HashMap<String, PkgUsageStatsExtended>();
+ mStatsLock = new Object();
+ mFileLock = new Object();
+ mFilePrefix = fileName;
+ mCal = Calendar.getInstance();
+ // Update current stats which are binned by date
+ String uFileName = getCurrentDateStr(mFilePrefix);
+ mFile = new File(uFileName);
+ readStatsFromFile();
+ mLastWriteRealTime = SystemClock.elapsedRealtime();
+ mLastTime = new Date().getTime();
+ }
+
+ /*
+ * Utility method to convert date into string.
+ */
+ private String getCurrentDateStr(String prefix) {
+ mCal.setTime(new Date());
+ StringBuilder sb = new StringBuilder();
+ if (prefix != null) {
+ sb.append(prefix);
+ sb.append(".");
+ }
+ int mm = mCal.get(Calendar.MONTH) - Calendar.JANUARY +1;
+ if (mm < 10) {
+ sb.append("0");
+ }
+ sb.append(mm);
+ int dd = mCal.get(Calendar.DAY_OF_MONTH);
+ if (dd < 10) {
+ sb.append("0");
+ }
+ sb.append(dd);
+ sb.append(mCal.get(Calendar.YEAR));
+ return sb.toString();
+ }
+
+ private Parcel getParcelForFile(File file) throws IOException {
+ FileInputStream stream = new FileInputStream(file);
+ byte[] raw = readFully(stream);
+ Parcel in = Parcel.obtain();
+ in.unmarshall(raw, 0, raw.length);
+ in.setDataPosition(0);
+ stream.close();
+ return in;
+ }
+
+ private void readStatsFromFile() {
+ File newFile = mFile;
+ synchronized (mFileLock) {
+ try {
+ if (newFile.exists()) {
+ readStatsFLOCK(newFile);
+ } else {
+ // Check for file limit before creating a new file
+ checkFileLimitFLOCK();
+ newFile.createNewFile();
+ }
+ } catch (IOException e) {
+ Log.w(TAG,"Error : " + e + " reading data from file:" + newFile);
+ }
+ }
+ }
+
+ private void readStatsFLOCK(File file) throws IOException {
+ Parcel in = getParcelForFile(file);
+ while (in.dataAvail() > 0) {
+ String pkgName = in.readString();
+ PkgUsageStatsExtended pus = new PkgUsageStatsExtended();
+ pus.mLaunchCount = in.readInt();
+ pus.mUsageTime = in.readLong();
+ synchronized (mStatsLock) {
+ mStats.put(pkgName, pus);
+ }
+ }
+ }
+
+ private ArrayList<String> getUsageStatsFileListFLOCK() {
+ File dir = getUsageFilesDir();
+ if (dir == null) {
+ Log.w(TAG, "Couldnt find writable directory for usage stats file");
+ return null;
+ }
+ // Check if there are too many files in the system and delete older files
+ String fList[] = dir.list();
+ if (fList == null) {
+ return null;
+ }
+ File pre = new File(mFilePrefix);
+ String filePrefix = pre.getName();
+ // file name followed by dot
+ int prefixLen = filePrefix.length()+1;
+ ArrayList<String> fileList = new ArrayList<String>();
+ for (String file : fList) {
+ int index = file.indexOf(filePrefix);
+ if (index == -1) {
+ continue;
+ }
+ if (file.endsWith(".bak")) {
+ continue;
+ }
+ fileList.add(file);
+ }
+ return fileList;
+ }
+
+ private File getUsageFilesDir() {
+ if (mFilePrefix == null) {
+ return null;
+ }
+ File pre = new File(mFilePrefix);
+ return new File(pre.getParent());
}
+ private void checkFileLimitFLOCK() {
+ File dir = getUsageFilesDir();
+ if (dir == null) {
+ Log.w(TAG, "Couldnt find writable directory for usage stats file");
+ return;
+ }
+ // Get all usage stats output files
+ ArrayList<String> fileList = getUsageStatsFileListFLOCK();
+ if (fileList == null) {
+ // Strange but we dont have to delete any thing
+ return;
+ }
+ int count = fileList.size();
+ if (count <= _MAX_NUM_FILES) {
+ return;
+ }
+ // Sort files
+ Collections.sort(fileList);
+ count -= _MAX_NUM_FILES;
+ // Delete older files
+ for (int i = 0; i < count; i++) {
+ String fileName = fileList.get(i);
+ File file = new File(dir, fileName);
+ Log.i(TAG, "Deleting file : "+fileName);
+ file.delete();
+ }
+ }
+
+ private void writeStatsToFile() {
+ synchronized (mFileLock) {
+ long currTime = new Date().getTime();
+ boolean dayChanged = ((currTime - mLastTime) >= (24*60*60*1000));
+ long currRealTime = SystemClock.elapsedRealtime();
+ if (((currRealTime-mLastWriteRealTime) < _FILE_WRITE_INTERVAL) &&
+ (!dayChanged)) {
+ // wait till the next update
+ return;
+ }
+ // Get the most recent file
+ String todayStr = getCurrentDateStr(mFilePrefix);
+ // Copy current file to back up
+ File backupFile = new File(mFile.getPath() + ".bak");
+ mFile.renameTo(backupFile);
+ try {
+ checkFileLimitFLOCK();
+ mFile.createNewFile();
+ // Write mStats to file
+ writeStatsFLOCK();
+ mLastWriteRealTime = currRealTime;
+ mLastTime = currTime;
+ if (dayChanged) {
+ // clear stats
+ synchronized (mStats) {
+ mStats.clear();
+ }
+ mFile = new File(todayStr);
+ }
+ // Delete the backup file
+ if (backupFile != null) {
+ backupFile.delete();
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "Failed writing stats to file:" + mFile);
+ if (backupFile != null) {
+ backupFile.renameTo(mFile);
+ }
+ }
+ }
+ }
+
+ private void writeStatsFLOCK() throws IOException {
+ FileOutputStream stream = new FileOutputStream(mFile);
+ Parcel out = Parcel.obtain();
+ writeStatsToParcelFLOCK(out);
+ stream.write(out.marshall());
+ out.recycle();
+ stream.flush();
+ stream.close();
+ }
+
+ private void writeStatsToParcelFLOCK(Parcel out) {
+ synchronized (mStatsLock) {
+ Set<String> keys = mStats.keySet();
+ for (String key : keys) {
+ PkgUsageStatsExtended pus = mStats.get(key);
+ out.writeString(key);
+ out.writeInt(pus.mLaunchCount);
+ out.writeLong(pus.mUsageTime);
+ }
+ }
+ }
+
public void publish(Context context) {
mContext = context;
ServiceManager.addService(SERVICE_NAME, asBinder());
@@ -99,12 +332,14 @@ public final class UsageStatsService extends IUsageStats.Stub {
return;
}
if (localLOGV) Log.i(TAG, "started component:"+pkgName);
- PkgUsageStatsExtended pus = mStats.get(pkgName);
- if (pus == null) {
- pus = new PkgUsageStatsExtended();
- mStats.put(pkgName, pus);
+ synchronized (mStatsLock) {
+ PkgUsageStatsExtended pus = mStats.get(pkgName);
+ if (pus == null) {
+ pus = new PkgUsageStatsExtended();
+ mStats.put(pkgName, pus);
+ }
+ pus.updateResume();
}
- pus.updateResume();
mResumedPkg = pkgName;
}
@@ -120,13 +355,17 @@ public final class UsageStatsService extends IUsageStats.Stub {
return;
}
if (localLOGV) Log.i(TAG, "paused component:"+pkgName);
- PkgUsageStatsExtended pus = mStats.get(pkgName);
- if (pus == null) {
- // Weird some error here
- Log.w(TAG, "No package stats for pkg:"+pkgName);
- return;
+ synchronized (mStatsLock) {
+ PkgUsageStatsExtended pus = mStats.get(pkgName);
+ if (pus == null) {
+ // Weird some error here
+ Log.w(TAG, "No package stats for pkg:"+pkgName);
+ return;
+ }
+ pus.updatePause();
}
- pus.updatePause();
+ // Persist data to file
+ writeStatsToFile();
}
public void enforceCallingPermission() {
@@ -145,17 +384,19 @@ public final class UsageStatsService extends IUsageStats.Stub {
((pkgName = componentName.getPackageName()) == null)) {
return null;
}
- PkgUsageStatsExtended pus = mStats.get(pkgName);
- if (pus == null) {
- return null;
+ synchronized (mStatsLock) {
+ PkgUsageStatsExtended pus = mStats.get(pkgName);
+ if (pus == null) {
+ return null;
+ }
+ return new PkgUsageStats(pkgName, pus.mLaunchCount, pus.mUsageTime);
}
- return new PkgUsageStats(pkgName, pus.mLaunchCount, pus.mUsageTime);
}
public PkgUsageStats[] getAllPkgUsageStats() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.PACKAGE_USAGE_STATS, null);
- synchronized (mStats) {
+ synchronized (mStatsLock) {
Set<String> keys = mStats.keySet();
int size = keys.size();
if (size <= 0) {
@@ -172,21 +413,120 @@ public final class UsageStatsService extends IUsageStats.Stub {
}
}
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ static byte[] readFully(FileInputStream stream) throws java.io.IOException {
+ int pos = 0;
+ int avail = stream.available();
+ byte[] data = new byte[avail];
+ while (true) {
+ int amt = stream.read(data, pos, data.length-pos);
+ if (amt <= 0) {
+ return data;
+ }
+ pos += amt;
+ avail = stream.available();
+ if (avail > data.length-pos) {
+ byte[] newData = new byte[pos+avail];
+ System.arraycopy(data, 0, newData, 0, pos);
+ data = newData;
+ }
+ }
+ }
+
+ private void collectDumpInfoFLOCK(PrintWriter pw, String[] args) {
+ List<String> fileList = getUsageStatsFileListFLOCK();
+ if (fileList == null) {
+ return;
+ }
+ final boolean isCheckinRequest = scanArgs(args, "-c");
+ Collections.sort(fileList);
+ File usageFile = new File(mFilePrefix);
+ String dirName = usageFile.getParent();
+ File dir = new File(dirName);
+ String filePrefix = usageFile.getName();
+ // file name followed by dot
+ int prefixLen = filePrefix.length()+1;
+ String todayStr = getCurrentDateStr(null);
+ for (String file : fileList) {
+ File dFile = new File(dir, file);
+ String dateStr = file.substring(prefixLen);
+ try {
+ Parcel in = getParcelForFile(dFile);
+ collectDumpInfoFromParcelFLOCK(in, pw, dateStr, isCheckinRequest);
+ if (isCheckinRequest && !todayStr.equalsIgnoreCase(dateStr)) {
+ // Delete old file after collecting info only for checkin requests
+ dFile.delete();
+ }
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "Failed with "+e+" when collecting dump info from file : " + file);
+ return;
+ } catch (IOException e) {
+ Log.w(TAG, "Failed with "+e+" when collecting dump info from file : "+file);
+ }
+ }
+ }
+
+ private void collectDumpInfoFromParcelFLOCK(Parcel in, PrintWriter pw,
+ String date, boolean isCheckinRequest) {
StringBuilder sb = new StringBuilder();
- synchronized (mStats) {
- Set<String> keys = mStats.keySet();
- for (String key: keys) {
- PkgUsageStatsExtended ps = mStats.get(key);
- sb.append("pkg=");
- sb.append(key);
+ sb.append("Date:");
+ sb.append(date);
+ boolean first = true;
+ while (in.dataAvail() > 0) {
+ String pkgName = in.readString();
+ int launchCount = in.readInt();
+ long usageTime = in.readLong();
+ if (isCheckinRequest) {
+ if (!first) {
+ sb.append(",");
+ }
+ sb.append(pkgName);
+ sb.append(",");
+ sb.append(launchCount);
+ sb.append(",");
+ sb.append(usageTime);
+ sb.append("ms");
+ } else {
+ if (first) {
+ sb.append("\n");
+ }
+ sb.append("pkg=");
+ sb.append(pkgName);
sb.append(", launchCount=");
- sb.append(ps.mLaunchCount);
+ sb.append(launchCount);
sb.append(", usageTime=");
- sb.append(ps.mUsageTime+" ms\n");
+ sb.append(usageTime);
+ sb.append(" ms\n");
}
+ first = false;
}
pw.write(sb.toString());
}
+
+ /**
+ * Searches array of arguments for the specified string
+ * @param args array of argument strings
+ * @param value value to search for
+ * @return true if the value is contained in the array
+ */
+ private static boolean scanArgs(String[] args, String value) {
+ if (args != null) {
+ for (String arg : args) {
+ if (value.equals(arg)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ /*
+ * The data persisted to file is parsed and the stats are computed.
+ */
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ synchronized (mFileLock) {
+ collectDumpInfoFLOCK(pw, args);
+ }
+ }
+
}