auto import from //branches/cupcake/...@125939
diff --git a/services/java/com/android/server/HeadsetObserver.java b/services/java/com/android/server/HeadsetObserver.java
index cb681e0..2bea731 100644
--- a/services/java/com/android/server/HeadsetObserver.java
+++ b/services/java/com/android/server/HeadsetObserver.java
@@ -88,23 +88,8 @@
mHeadsetName = newName;
mHeadsetState = newState;
AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-
- if (mHeadsetState == 1) {
- audioManager.setRouting(AudioManager.MODE_NORMAL, AudioManager.ROUTE_HEADSET,
- AudioManager.ROUTE_ALL);
- audioManager.setRouting(AudioManager.MODE_RINGTONE,
- AudioManager.ROUTE_HEADSET | AudioManager.ROUTE_SPEAKER,
- AudioManager.ROUTE_ALL);
- audioManager.setRouting(AudioManager.MODE_IN_CALL, AudioManager.ROUTE_HEADSET,
- AudioManager.ROUTE_ALL);
- } else {
- audioManager.setRouting(AudioManager.MODE_NORMAL, AudioManager.ROUTE_SPEAKER,
- AudioManager.ROUTE_ALL);
- audioManager.setRouting(AudioManager.MODE_RINGTONE, AudioManager.ROUTE_SPEAKER,
- AudioManager.ROUTE_ALL);
- audioManager.setRouting(AudioManager.MODE_IN_CALL, AudioManager.ROUTE_EARPIECE,
- AudioManager.ROUTE_ALL);
- }
+
+ audioManager.setWiredHeadsetOn(mHeadsetState == 1);
sendIntent();
}
}
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index c701ca1..63d7c94 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -952,7 +952,15 @@
public void setInputMethod(IBinder token, String id) {
synchronized (mMethodMap) {
- if (mCurToken == null || mCurToken != token) {
+ if (mCurToken == null) {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(
+ "Using null token requires permission "
+ + android.Manifest.permission.WRITE_SECURE_SETTINGS);
+ }
+ } else if (mCurToken != token) {
Log.w(TAG, "Ignoring setInputMethod of token: " + token);
}
@@ -1258,6 +1266,100 @@
}
}
+ // ----------------------------------------------------------------------
+
+ public boolean setInputMethodEnabled(String id, boolean enabled) {
+ synchronized (mMethodMap) {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.WRITE_SECURE_SETTINGS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException(
+ "Requires permission "
+ + android.Manifest.permission.WRITE_SECURE_SETTINGS);
+ }
+
+ // Make sure this is a valid input method.
+ InputMethodInfo imm = mMethodMap.get(id);
+ if (imm == null) {
+ 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;
+ }
+ // 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)) {
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.DEFAULT_INPUT_METHOD,
+ firstId != null ? firstId : "");
+ }
+ // 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;
+ }
+
+ Settings.Secure.putString(mContext.getContentResolver(),
+ Settings.Secure.ENABLED_INPUT_METHODS, enabledStr);
+
+ // Previous state was disabled.
+ return false;
+ }
+ }
+
+ // ----------------------------------------------------------------------
+
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (mContext.checkCallingPermission("android.permission.DUMP")
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 831d1d2..ed9ee79 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -569,7 +569,7 @@
private WifiManager.WifiLock getWifiWakelock() {
if (mWifiLock == null && mWifiManager != null) {
- mWifiLock = mWifiManager.createWifiLock(WIFILOCK_KEY);
+ mWifiLock = mWifiManager.createWifiLock(WifiManager.WIFI_MODE_SCAN_ONLY, WIFILOCK_KEY);
mWifiLock.setReferenceCounted(false);
}
return mWifiLock;
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 03480d1..002ebed 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -137,7 +137,11 @@
* Broadcasts the USB mass storage connected event to all clients.
*/
void notifyUmsConnected() {
- setUsbStorageNotificationVisibility(true);
+ String storageState = Environment.getExternalStorageState();
+ if (!storageState.equals(Environment.MEDIA_REMOVED) &&
+ !storageState.equals(Environment.MEDIA_BAD_REMOVAL)) {
+ setUsbStorageNotificationVisibility(true);
+ }
Intent intent = new Intent(Intent.ACTION_UMS_CONNECTED);
mContext.sendBroadcast(intent);
}
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index e86ff02..f0d5eaf 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -204,7 +204,7 @@
boolean mRestoredSettings;
boolean mReportedUidError;
- // Group-ids that are given to all packages as read from etc/permissions.xml.
+ // Group-ids that are given to all packages as read from etc/permissions/*.xml.
int[] mGlobalGids;
// These are the built-in uid -> permission mappings that were read from the
@@ -534,8 +534,43 @@
}
void readPermissions() {
+ // Read permissions from .../etc/permission directory.
+ File libraryDir = new File(Environment.getRootDirectory(), "etc/permissions");
+ if (!libraryDir.exists() || !libraryDir.isDirectory()) {
+ Log.w(TAG, "No directory " + libraryDir + ", skipping");
+ return;
+ }
+ if (!libraryDir.canRead()) {
+ Log.w(TAG, "Directory " + libraryDir + " cannot be read");
+ return;
+ }
+
+ // Iterate over the files in the directory and scan .xml files
+ for (File f : libraryDir.listFiles()) {
+ // We'll read platform.xml last
+ if (f.getPath().endsWith("etc/permissions/platform.xml")) {
+ continue;
+ }
+
+ if (!f.getPath().endsWith(".xml")) {
+ Log.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
+ continue;
+ }
+ if (!f.canRead()) {
+ Log.w(TAG, "Permissions library file " + f + " cannot be read");
+ continue;
+ }
+
+ readPermissionsFromXml(f);
+ }
+
+ // Read permissions from .../etc/permissions/platform.xml last so it will take precedence
final File permFile = new File(Environment.getRootDirectory(),
- "etc/permissions.xml");
+ "etc/permissions/platform.xml");
+ readPermissionsFromXml(permFile);
+ }
+
+ private void readPermissionsFromXml(File permFile) {
FileReader permReader = null;
try {
permReader = new FileReader(permFile);
@@ -566,9 +601,9 @@
Log.w(TAG, "<group> without gid at "
+ parser.getPositionDescription());
}
+
XmlUtils.skipCurrentTag(parser);
continue;
-
} else if ("permission".equals(name)) {
String perm = parser.getAttributeValue(null, "name");
if (perm == null) {
@@ -622,6 +657,7 @@
Log.w(TAG, "<library> without file at "
+ parser.getPositionDescription());
} else {
+ Log.i(TAG, "Got library " + lname + " in " + lfile);
this.mSharedLibraries.put(lname, lfile);
}
XmlUtils.skipCurrentTag(parser);
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 3fa2087..ca0ad1a 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -158,6 +158,7 @@
private UnsynchronizedWakeLock mBroadcastWakeLock;
private UnsynchronizedWakeLock mStayOnWhilePluggedInScreenDimLock;
private UnsynchronizedWakeLock mStayOnWhilePluggedInPartialLock;
+ private UnsynchronizedWakeLock mPreventScreenOnPartialLock;
private HandlerThread mHandlerThread;
private Handler mHandler;
private TimeoutTask mTimeoutTask = new TimeoutTask();
@@ -180,6 +181,7 @@
private HashMap<IBinder,PokeLock> mPokeLocks = new HashMap<IBinder,PokeLock>();
private long mScreenOnTime;
private long mScreenOnStartTime;
+ private boolean mPreventScreenOn;
// Used when logging number and duration of touch-down cycles
private long mTotalTouchDownTime;
@@ -383,6 +385,8 @@
PowerManager.SCREEN_DIM_WAKE_LOCK, "StayOnWhilePluggedIn Screen Dim", false);
mStayOnWhilePluggedInPartialLock = new UnsynchronizedWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, "StayOnWhilePluggedIn Partial", false);
+ mPreventScreenOnPartialLock = new UnsynchronizedWakeLock(
+ PowerManager.PARTIAL_WAKE_LOCK, "PreventScreenOn Partial", false);
mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
mScreenOnIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -790,6 +794,7 @@
pw.println(" mBroadcastWakeLock=" + mBroadcastWakeLock);
pw.println(" mStayOnWhilePluggedInScreenDimLock=" + mStayOnWhilePluggedInScreenDimLock);
pw.println(" mStayOnWhilePluggedInPartialLock=" + mStayOnWhilePluggedInPartialLock);
+ pw.println(" mPreventScreenOnPartialLock=" + mPreventScreenOnPartialLock);
mScreenBrightness.dump(pw, " mScreenBrightness: ");
mKeyboardBrightness.dump(pw, " mKeyboardBrightness: ");
mButtonBrightness.dump(pw, " mButtonBrightness: ");
@@ -1035,6 +1040,118 @@
}
}
+ /**
+ * Prevents the screen from turning on even if it *should* turn on due
+ * to a subsequent full wake lock being acquired.
+ * <p>
+ * This is a temporary hack that allows an activity to "cover up" any
+ * display glitches that happen during the activity's startup
+ * sequence. (Specifically, this API was added to work around a
+ * cosmetic bug in the "incoming call" sequence, where the lock screen
+ * would flicker briefly before the incoming call UI became visible.)
+ * TODO: There ought to be a more elegant way of doing this,
+ * probably by having the PowerManager and ActivityManager
+ * work together to let apps specify that the screen on/off
+ * state should be synchronized with the Activity lifecycle.
+ * <p>
+ * Note that calling preventScreenOn(true) will NOT turn the screen
+ * off if it's currently on. (This API only affects *future*
+ * acquisitions of full wake locks.)
+ * But calling preventScreenOn(false) WILL turn the screen on if
+ * it's currently off because of a prior preventScreenOn(true) call.
+ * <p>
+ * Any call to preventScreenOn(true) MUST be followed promptly by a call
+ * to preventScreenOn(false). In fact, if the preventScreenOn(false)
+ * call doesn't occur within 5 seconds, we'll turn the screen back on
+ * ourselves (and log a warning about it); this prevents a buggy app
+ * from disabling the screen forever.)
+ * <p>
+ * TODO: this feature should really be controlled by a new type of poke
+ * lock (rather than an IPowerManager call).
+ */
+ public void preventScreenOn(boolean prevent) {
+ // TODO: use a totally new permission (separate from DEVICE_POWER) for this?
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+
+ synchronized (mLocks) {
+ if (prevent) {
+ // First of all, grab a partial wake lock to
+ // make sure the CPU stays on during the entire
+ // preventScreenOn(true) -> preventScreenOn(false) sequence.
+ mPreventScreenOnPartialLock.acquire();
+
+ // Post a forceReenableScreen() call (for 5 seconds in the
+ // future) to make sure the matching preventScreenOn(false) call
+ // has happened by then.
+ mHandler.removeCallbacks(mForceReenableScreenTask);
+ mHandler.postDelayed(mForceReenableScreenTask, 5000);
+
+ // Finally, set the flag that prevents the screen from turning on.
+ // (Below, in setPowerState(), we'll check mPreventScreenOn and
+ // we *won't* call Power.setScreenState(true) if it's set.)
+ mPreventScreenOn = true;
+ } else {
+ // (Re)enable the screen.
+ mPreventScreenOn = false;
+
+ // We're "undoing" a the prior preventScreenOn(true) call, so we
+ // no longer need the 5-second safeguard.
+ mHandler.removeCallbacks(mForceReenableScreenTask);
+
+ // Forcibly turn on the screen if it's supposed to be on. (This
+ // handles the case where the screen is currently off because of
+ // a prior preventScreenOn(true) call.)
+ if ((mPowerState & SCREEN_ON_BIT) != 0) {
+ if (mSpew) {
+ Log.d(TAG,
+ "preventScreenOn: turning on after a prior preventScreenOn(true)!");
+ }
+ int err = Power.setScreenState(true);
+ if (err != 0) {
+ Log.w(TAG, "preventScreenOn: error from Power.setScreenState(): " + err);
+ }
+ }
+
+ // Release the partial wake lock that we held during the
+ // preventScreenOn(true) -> preventScreenOn(false) sequence.
+ mPreventScreenOnPartialLock.release();
+ }
+ }
+ }
+
+ /**
+ * Sanity-check that gets called 5 seconds after any call to
+ * preventScreenOn(true). This ensures that the original call
+ * is followed promptly by a call to preventScreenOn(false).
+ */
+ private void forceReenableScreen() {
+ // We shouldn't get here at all if mPreventScreenOn is false, since
+ // we should have already removed any existing
+ // mForceReenableScreenTask messages...
+ if (!mPreventScreenOn) {
+ Log.w(TAG, "forceReenableScreen: mPreventScreenOn is false, nothing to do");
+ return;
+ }
+
+ // Uh oh. It's been 5 seconds since a call to
+ // preventScreenOn(true) and we haven't re-enabled the screen yet.
+ // This means the app that called preventScreenOn(true) is either
+ // slow (i.e. it took more than 5 seconds to call preventScreenOn(false)),
+ // or buggy (i.e. it forgot to call preventScreenOn(false), or
+ // crashed before doing so.)
+
+ // Log a warning, and forcibly turn the screen back on.
+ Log.w(TAG, "App called preventScreenOn(true) but didn't promptly reenable the screen! "
+ + "Forcing the screen back on...");
+ preventScreenOn(false);
+ }
+
+ private Runnable mForceReenableScreenTask = new Runnable() {
+ public void run() {
+ forceReenableScreen();
+ }
+ };
+
private void setPowerState(int state)
{
setPowerState(state, false, false);
@@ -1096,7 +1213,31 @@
if (oldScreenOn != newScreenOn) {
if (newScreenOn) {
- err = Power.setScreenState(true);
+ // Turn on the screen UNLESS there was a prior
+ // preventScreenOn(true) request. (Note that the lifetime
+ // of a single preventScreenOn() request is limited to 5
+ // seconds to prevent a buggy app from disabling the
+ // screen forever; see forceReenableScreen().)
+ boolean reallyTurnScreenOn = true;
+ if (mSpew) {
+ Log.d(TAG, "- turning screen on... mPreventScreenOn = "
+ + mPreventScreenOn);
+ }
+
+ if (mPreventScreenOn) {
+ if (mSpew) {
+ Log.d(TAG, "- PREVENTING screen from really turning on!");
+ }
+ reallyTurnScreenOn = false;
+ }
+ if (reallyTurnScreenOn) {
+ err = Power.setScreenState(true);
+ } else {
+ Power.setScreenState(false);
+ // But continue as if we really did turn the screen on...
+ err = 0;
+ }
+
mScreenOnStartTime = SystemClock.elapsedRealtime();
mLastTouchDown = 0;
mTotalTouchDownTime = 0;
diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java
index 70c3110..fef3598 100644
--- a/services/java/com/android/server/Watchdog.java
+++ b/services/java/com/android/server/Watchdog.java
@@ -36,6 +36,7 @@
import android.util.EventLog;
import android.util.Log;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
@@ -43,13 +44,13 @@
public class Watchdog extends Thread {
static final String TAG = "Watchdog";
static final boolean localLOGV = false || Config.LOGV;
-
+
// Set this to true to use debug default values.
static final boolean DB = false;
-
+
static final int MONITOR = 2718;
static final int GLOBAL_PSS = 2719;
-
+
static final int TIME_TO_WAIT = DB ? 15*1000 : 60*1000;
static final int EVENT_LOG_TAG = 2802;
static final int EVENT_LOG_PROC_PSS_TAG = 2803;
@@ -61,29 +62,29 @@
static final int EVENT_LOG_MEMINFO_TAG = 2809;
static final int EVENT_LOG_VMSTAT_TAG = 2810;
static final int EVENT_LOG_REQUESTED_REBOOT_TAG = 2811;
-
+
static final int MEMCHECK_DEFAULT_INTERVAL = DB ? 30 : 30*60; // 30 minutes
static final int MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL = DB ? 60 : 2*60*60; // 2 hours
static final int MEMCHECK_DEFAULT_SYSTEM_SOFT_THRESHOLD = (DB ? 10:16)*1024*1024; // 16MB
static final int MEMCHECK_DEFAULT_SYSTEM_HARD_THRESHOLD = (DB ? 14:20)*1024*1024; // 20MB
static final int MEMCHECK_DEFAULT_PHONE_SOFT_THRESHOLD = (DB ? 4:8)*1024*1024; // 8MB
static final int MEMCHECK_DEFAULT_PHONE_HARD_THRESHOLD = (DB ? 8:12)*1024*1024; // 12MB
-
+
static final int MEMCHECK_DEFAULT_EXEC_START_TIME = 1*60*60; // 1:00am
static final int MEMCHECK_DEFAULT_EXEC_END_TIME = 5*60*60; // 5:00am
static final int MEMCHECK_DEFAULT_MIN_SCREEN_OFF = DB ? 1*60 : 5*60; // 5 minutes
static final int MEMCHECK_DEFAULT_MIN_ALARM = DB ? 1*60 : 3*60; // 3 minutes
static final int MEMCHECK_DEFAULT_RECHECK_INTERVAL = DB ? 1*60 : 5*60; // 5 minutes
-
+
static final int REBOOT_DEFAULT_INTERVAL = DB ? 1 : 0; // never force reboot
static final int REBOOT_DEFAULT_START_TIME = 3*60*60; // 3:00am
static final int REBOOT_DEFAULT_WINDOW = 60*60; // within 1 hour
-
+
static final String CHECKUP_ACTION = "com.android.service.Watchdog.CHECKUP";
static final String REBOOT_ACTION = "com.android.service.Watchdog.REBOOT";
-
+
static Watchdog sWatchdog;
-
+
/* This handler will be used to post message back onto the main thread */
final Handler mHandler;
final Runnable mGlobalPssCollected;
@@ -96,11 +97,11 @@
boolean mCompleted;
boolean mForceKillSystem;
Monitor mCurrentMonitor;
-
+
PssRequestor mPhoneReq;
int mPhonePid;
int mPhonePss;
-
+
long mLastMemCheckTime = -(MEMCHECK_DEFAULT_INTERVAL*1000);
boolean mHavePss;
long mLastMemCheckRealtime = -(MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL*1000);
@@ -117,7 +118,7 @@
MEMCHECK_DEFAULT_PHONE_SOFT_THRESHOLD,
Settings.Gservices.MEMCHECK_PHONE_HARD_THRESHOLD,
MEMCHECK_DEFAULT_PHONE_HARD_THRESHOLD);
-
+
final Calendar mCalendar = Calendar.getInstance();
long mMemcheckLastTime;
long mMemcheckExecStartTime;
@@ -127,10 +128,10 @@
boolean mNeedScheduledCheck;
PendingIntent mCheckupIntent;
PendingIntent mRebootIntent;
-
+
long mBootTime;
int mRebootInterval;
-
+
boolean mReqRebootNoWait; // should wait for one interval before reboot?
int mReqRebootInterval = -1; // >= 0 if a reboot has been requested
int mReqRebootStartTime = -1; // >= 0 if a specific start time has been requested
@@ -138,7 +139,7 @@
int mReqMinScreenOff = -1; // >= 0 if a specific screen off time has been requested
int mReqMinNextAlarm = -1; // >= 0 if specific time to next alarm has been requested
int mReqRecheckInterval= -1; // >= 0 if a specific recheck interval has been requested
-
+
/**
* This class monitors the memory in a particular process.
*/
@@ -147,17 +148,17 @@
final String mEnabledSetting;
final String mSoftSetting;
final String mHardSetting;
-
+
int mSoftThreshold;
int mHardThreshold;
boolean mEnabled;
long mLastPss;
-
+
static final int STATE_OK = 0;
static final int STATE_SOFT = 1;
static final int STATE_HARD = 2;
int mState;
-
+
MemMonitor(String processName, String enabledSetting,
String softSetting, int defSoftThreshold,
String hardSetting, int defHardThreshold) {
@@ -168,7 +169,7 @@
mSoftThreshold = defSoftThreshold;
mHardThreshold = defHardThreshold;
}
-
+
void retrieveSettings(ContentResolver resolver) {
mSoftThreshold = Settings.Gservices.getInt(
resolver, mSoftSetting, mSoftThreshold);
@@ -177,7 +178,7 @@
mEnabled = Settings.Gservices.getInt(
resolver, mEnabledSetting, 0) != 0;
}
-
+
boolean checkLocked(long curTime, int pid, int pss) {
mLastPss = pss;
if (mLastPss < mSoftThreshold) {
@@ -188,19 +189,19 @@
mState = STATE_HARD;
}
EventLog.writeEvent(EVENT_LOG_PROC_PSS_TAG, mProcessName, pid, mLastPss);
-
+
if (mState == STATE_OK) {
// Memory is good, don't recover.
return false;
}
-
+
if (mState == STATE_HARD) {
// Memory is really bad, kill right now.
EventLog.writeEvent(EVENT_LOG_HARD_RESET_TAG, mProcessName, pid,
mHardThreshold, mLastPss);
return mEnabled;
}
-
+
// It is time to schedule a reset...
// Check if we are currently within the time to kill processes due
// to memory use.
@@ -219,13 +220,13 @@
}
return mEnabled;
}
-
+
void clear() {
mLastPss = 0;
mState = STATE_OK;
}
}
-
+
/**
* Used for scheduling monitor callbacks and checking memory usage.
*/
@@ -242,7 +243,7 @@
logGlobalMemory();
}
} break;
-
+
case MONITOR: {
if (mHavePss) {
// During the last pass we collected pss information, so
@@ -251,7 +252,7 @@
if (localLOGV) Log.v(TAG, "Have pss, checking memory.");
checkMemory();
}
-
+
if (mHaveGlobalPss) {
// During the last pass we collected pss information, so
// now it is time to report it.
@@ -259,9 +260,9 @@
if (localLOGV) Log.v(TAG, "Have global pss, logging.");
logGlobalMemory();
}
-
+
long now = SystemClock.uptimeMillis();
-
+
// See if we should force a reboot.
int rebootInterval = mReqRebootInterval >= 0
? mReqRebootInterval : Settings.Gservices.getInt(
@@ -273,7 +274,7 @@
// be considered...
checkReboot(false);
}
-
+
// See if we should check memory conditions.
long memCheckInterval = Settings.Gservices.getLong(
mResolver, Settings.Gservices.MEMCHECK_INTERVAL,
@@ -287,7 +288,7 @@
if (localLOGV) Log.v(TAG, "Collecting memory usage.");
collectMemory();
mHavePss = true;
-
+
long memCheckRealtimeInterval = Settings.Gservices.getLong(
mResolver, Settings.Gservices.MEMCHECK_LOG_REALTIME_INTERVAL,
MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL) * 1000;
@@ -299,13 +300,13 @@
mHaveGlobalPss = true;
}
}
-
+
final int size = mMonitors.size();
for (int i = 0 ; i < size ; i++) {
mCurrentMonitor = mMonitors.get(i);
mCurrentMonitor.monitor();
}
-
+
synchronized (Watchdog.this) {
mCompleted = true;
mCurrentMonitor = null;
@@ -320,7 +321,7 @@
mHandler.sendEmptyMessage(GLOBAL_PSS);
}
}
-
+
final class CheckupReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context c, Intent intent) {
@@ -328,7 +329,7 @@
checkMemory();
}
}
-
+
final class RebootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context c, Intent intent) {
@@ -336,7 +337,7 @@
checkReboot(true);
}
}
-
+
final class RebootRequestReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context c, Intent intent) {
@@ -354,15 +355,15 @@
checkReboot(true);
}
}
-
+
public interface Monitor {
void monitor();
}
-
+
public interface PssRequestor {
void requestPss();
}
-
+
public class PssStats {
public int mEmptyPss;
public int mEmptyCount;
@@ -374,20 +375,20 @@
public int mVisibleCount;
public int mForegroundPss;
public int mForegroundCount;
-
+
public int mNoPssCount;
-
+
public int mProcDeaths[] = new int[10];
}
-
+
public static Watchdog getInstance() {
if (sWatchdog == null) {
sWatchdog = new Watchdog();
}
-
+
return sWatchdog;
}
-
+
private Watchdog() {
super("watchdog");
mHandler = new HeartbeatHandler();
@@ -402,24 +403,24 @@
mPower = power;
mAlarm = alarm;
mActivity = activity;
-
+
context.registerReceiver(new CheckupReceiver(),
new IntentFilter(CHECKUP_ACTION));
mCheckupIntent = PendingIntent.getBroadcast(context,
0, new Intent(CHECKUP_ACTION), 0);
-
+
context.registerReceiver(new RebootReceiver(),
new IntentFilter(REBOOT_ACTION));
mRebootIntent = PendingIntent.getBroadcast(context,
0, new Intent(REBOOT_ACTION), 0);
-
+
context.registerReceiver(new RebootRequestReceiver(),
new IntentFilter(Intent.ACTION_REBOOT),
android.Manifest.permission.REBOOT, null);
-
+
mBootTime = System.currentTimeMillis();
}
-
+
public void processStarted(PssRequestor req, String name, int pid) {
synchronized (this) {
if ("com.android.phone".equals(name)) {
@@ -429,7 +430,7 @@
}
}
}
-
+
public void reportPss(PssRequestor req, String name, int pss) {
synchronized (this) {
if (mPhoneReq == req) {
@@ -437,7 +438,7 @@
}
}
}
-
+
public void addMonitor(Monitor monitor) {
synchronized (this) {
if (isAlive()) {
@@ -459,7 +460,7 @@
}
}
}
-
+
/**
* Retrieve memory usage over all application processes. This is an
* async operation, so must be done before doing memory checks.
@@ -467,7 +468,7 @@
void collectGlobalMemory() {
mActivity.requestPss(mGlobalPssCollected);
}
-
+
/**
* Check memory usage in the system, scheduling kills/reboots as needed.
* This always runs on the mHandler thread.
@@ -476,11 +477,11 @@
boolean needScheduledCheck;
long curTime;
long nextTime = 0;
-
+
long recheckInterval = Settings.Gservices.getLong(
mResolver, Settings.Gservices.MEMCHECK_RECHECK_INTERVAL,
MEMCHECK_DEFAULT_RECHECK_INTERVAL) * 1000;
-
+
mSystemMemMonitor.retrieveSettings(mResolver);
mPhoneMemMonitor.retrieveSettings(mResolver);
retrieveBrutalityAmount();
@@ -488,7 +489,7 @@
synchronized (this) {
curTime = System.currentTimeMillis();
mNeedScheduledCheck = false;
-
+
// How is the system doing?
if (mSystemMemMonitor.checkLocked(curTime, Process.myPid(),
(int)Process.getPss(Process.myPid()))) {
@@ -497,7 +498,7 @@
notifyAll();
return;
}
-
+
// How is the phone process doing?
if (mPhoneReq != null) {
if (mPhoneMemMonitor.checkLocked(curTime, mPhonePid,
@@ -508,7 +509,7 @@
} else {
mPhoneMemMonitor.clear();
}
-
+
needScheduledCheck = mNeedScheduledCheck;
if (needScheduledCheck) {
// Something is going bad, but now is not a good time to
@@ -523,14 +524,14 @@
computeMemcheckTimesLocked(nextTime);
nextTime = mMemcheckExecStartTime;
}
-
+
if (localLOGV) {
mCalendar.setTimeInMillis(nextTime);
Log.v(TAG, "Next Alarm Time: " + mCalendar);
}
}
}
-
+
if (needScheduledCheck) {
if (localLOGV) Log.v(TAG, "Scheduling next memcheck alarm for "
+ ((nextTime-curTime)/1000/60) + "m from now");
@@ -555,7 +556,7 @@
final long[] mVMStatSizes = new long[mVMStatFields.length];
final long[] mPrevVMStatSizes = new long[mVMStatFields.length];
long mLastLogGlobalMemoryTime;
-
+
void logGlobalMemory() {
PssStats stats = mPssStats;
mActivity.collectPss(stats);
@@ -591,7 +592,7 @@
(int)mVMStatSizes[0], (int)mVMStatSizes[1], (int)mVMStatSizes[2],
(int)mVMStatSizes[3], (int)mVMStatSizes[4]);
}
-
+
void checkReboot(boolean fromAlarm) {
int rebootInterval = mReqRebootInterval >= 0 ? mReqRebootInterval
: Settings.Gservices.getInt(
@@ -604,7 +605,7 @@
mAlarm.remove(mRebootIntent);
return;
}
-
+
long rebootStartTime = mReqRebootStartTime >= 0 ? mReqRebootStartTime
: Settings.Gservices.getLong(
mResolver, Settings.Gservices.REBOOT_START_TIME,
@@ -617,17 +618,17 @@
: Settings.Gservices.getLong(
mResolver, Settings.Gservices.MEMCHECK_RECHECK_INTERVAL,
MEMCHECK_DEFAULT_RECHECK_INTERVAL)) * 1000;
-
+
retrieveBrutalityAmount();
-
+
long realStartTime;
long now;
-
+
synchronized (this) {
now = System.currentTimeMillis();
realStartTime = computeCalendarTime(mCalendar, now,
rebootStartTime);
-
+
long rebootIntervalMillis = rebootInterval*24*60*60*1000;
if (DB || mReqRebootNoWait ||
(now-mBootTime) >= (rebootIntervalMillis-rebootWindowMillis)) {
@@ -639,7 +640,7 @@
rebootSystem("Checkin scheduled forced");
return;
}
-
+
// Are we within the reboot window?
if (now < realStartTime) {
// Schedule alarm for next check interval.
@@ -654,7 +655,7 @@
rebootSystem("Checked scheduled range");
return;
}
-
+
// Schedule next alarm either within the window or in the
// next interval.
if ((now+recheckInterval) >= (realStartTime+rebootWindowMillis)) {
@@ -670,21 +671,25 @@
}
}
}
-
+
if (localLOGV) Log.v(TAG, "Scheduling next reboot alarm for "
+ ((realStartTime-now)/1000/60) + "m from now");
mAlarm.remove(mRebootIntent);
mAlarm.set(AlarmManager.RTC_WAKEUP, realStartTime, mRebootIntent);
}
-
+
/**
* Perform a full reboot of the system.
*/
void rebootSystem(String reason) {
Log.i(TAG, "Rebooting system because: " + reason);
- android.os.Power.reboot(reason);
+ try {
+ android.os.Power.reboot(reason);
+ } catch (IOException e) {
+ Log.e(TAG, "Reboot failed!", e);
+ }
}
-
+
/**
* Load the current Gservices settings for when
* {@link #shouldWeBeBrutalLocked} will allow the brutality to happen.
@@ -700,12 +705,12 @@
mResolver, Settings.Gservices.MEMCHECK_MIN_ALARM,
MEMCHECK_DEFAULT_MIN_ALARM)) * 1000;
}
-
+
/**
* Determine whether it is a good time to kill, crash, or otherwise
* plunder the current situation for the overall long-term benefit of
* the world.
- *
+ *
* @param curTime The current system time.
* @return Returns null if this is a good time, else a String with the
* text of why it is not a good time.
@@ -714,40 +719,40 @@
if (mBattery == null || !mBattery.isPowered()) {
return "battery";
}
-
+
if (mMinScreenOff >= 0 && (mPower == null ||
mPower.timeSinceScreenOn() < mMinScreenOff)) {
return "screen";
}
-
+
if (mMinAlarm >= 0 && (mAlarm == null ||
mAlarm.timeToNextAlarm() < mMinAlarm)) {
return "alarm";
}
-
+
return null;
}
-
+
/**
* Compute the times during which we next would like to perform process
* restarts.
- *
+ *
* @param curTime The current system time.
*/
void computeMemcheckTimesLocked(long curTime) {
if (mMemcheckLastTime == curTime) {
return;
}
-
+
mMemcheckLastTime = curTime;
-
+
long memcheckExecStartTime = Settings.Gservices.getLong(
mResolver, Settings.Gservices.MEMCHECK_EXEC_START_TIME,
MEMCHECK_DEFAULT_EXEC_START_TIME);
long memcheckExecEndTime = Settings.Gservices.getLong(
mResolver, Settings.Gservices.MEMCHECK_EXEC_END_TIME,
MEMCHECK_DEFAULT_EXEC_END_TIME);
-
+
mMemcheckExecEndTime = computeCalendarTime(mCalendar, curTime,
memcheckExecEndTime);
if (mMemcheckExecEndTime < curTime) {
@@ -758,7 +763,7 @@
}
mMemcheckExecStartTime = computeCalendarTime(mCalendar, curTime,
memcheckExecStartTime);
-
+
if (localLOGV) {
mCalendar.setTimeInMillis(curTime);
Log.v(TAG, "Current Time: " + mCalendar);
@@ -768,7 +773,7 @@
Log.v(TAG, "End Check Time: " + mCalendar);
}
}
-
+
static long computeCalendarTime(Calendar c, long curTime,
long secondsSinceMidnight) {
@@ -782,7 +787,7 @@
c.set(Calendar.MINUTE, val);
c.set(Calendar.SECOND, (int)secondsSinceMidnight - (val*60));
c.set(Calendar.MILLISECOND, 0);
-
+
long newTime = c.getTimeInMillis();
if (newTime < curTime) {
// The given time (in seconds since midnight) has already passed for today, so advance
@@ -790,19 +795,19 @@
c.add(Calendar.DAY_OF_MONTH, 1);
newTime = c.getTimeInMillis();
}
-
+
return newTime;
}
-
+
@Override
public void run() {
while (true) {
mCompleted = false;
mHandler.sendEmptyMessage(MONITOR);
-
+
synchronized (this) {
long timeout = TIME_TO_WAIT;
-
+
// NOTE: We use uptimeMillis() here because we do not want to increment the time we
// wait while asleep. If the device is asleep then the thing that we are waiting
// to timeout on is asleep as well and won't have a chance to run. Causing a false
@@ -827,22 +832,22 @@
continue;
}
}
-
- // If we got here, that means that the system is most likely hung.
- // First send a SIGQUIT so that we can see where it was hung. Then
+
+ // If we got here, that means that the system is most likely hung.
+ // First send a SIGQUIT so that we can see where it was hung. Then
// kill this process so that the system will restart.
String name = (mCurrentMonitor != null) ? mCurrentMonitor.getClass().getName() : "null";
EventLog.writeEvent(EVENT_LOG_TAG, name);
Process.sendSignal(Process.myPid(), Process.SIGNAL_QUIT);
-
+
// Wait a bit longer before killing so we can make sure that the stacks are captured.
try {
Thread.sleep(10*1000);
} catch (InterruptedException e) {
}
-
+
// Only kill the process if the debugger is not attached.
- if (!Debug.isDebuggerConnected()) {
+ if (!Debug.isDebuggerConnected()) {
Process.killProcess(Process.myPid());
}
}
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 7a0deff..f2483ff 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -47,7 +47,6 @@
import android.os.Message;
import android.os.PowerManager;
import android.os.RemoteException;
-import android.os.BatteryManager;
import android.provider.Settings;
import android.util.Log;
import android.text.TextUtils;
@@ -67,7 +66,7 @@
* the IWifiManager interface. It also creates a WifiMonitor to listen
* for Wifi-related events.
*
- * {@hide}
+ * @hide
*/
public class WifiService extends IWifiManager.Stub {
private static final String TAG = "WifiService";
@@ -106,9 +105,9 @@
private static final int DEFAULT_WAKELOCK_TIMEOUT = 8000;
// Wake lock used by driver-stop operation
- private static PowerManager.WakeLock mDriverStopWakeLock;
+ private static PowerManager.WakeLock sDriverStopWakeLock;
// Wake lock used by other operations
- private static PowerManager.WakeLock mWakeLock;
+ private static PowerManager.WakeLock sWakeLock;
private static final int MESSAGE_ENABLE_WIFI = 0;
private static final int MESSAGE_DISABLE_WIFI = 1;
@@ -116,7 +115,7 @@
private static final int MESSAGE_START_WIFI = 3;
private static final int MESSAGE_RELEASE_WAKELOCK = 4;
- private WifiHandler mWifiHandler;
+ private final WifiHandler mWifiHandler;
/*
* Map used to keep track of hidden networks presence, which
@@ -197,17 +196,17 @@
mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0);
PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
- mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
- mDriverStopWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
+ sWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
+ sDriverStopWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
mWifiStateTracker.setReleaseWakeLockCallback(
new Runnable() {
public void run() {
mWifiHandler.removeMessages(MESSAGE_RELEASE_WAKELOCK);
- synchronized (mDriverStopWakeLock) {
- if (mDriverStopWakeLock.isHeld()) {
+ synchronized (sDriverStopWakeLock) {
+ if (sDriverStopWakeLock.isHeld()) {
if (DBG) Log.d(TAG, "Releasing driver-stop wakelock " +
- mDriverStopWakeLock);
- mDriverStopWakeLock.release();
+ sDriverStopWakeLock);
+ sDriverStopWakeLock.release();
}
}
}
@@ -435,7 +434,7 @@
* before adding a new one
*/
synchronized (mWifiHandler) {
- mWakeLock.acquire();
+ sWakeLock.acquire();
sendEnableMessage(enable, true);
}
@@ -679,7 +678,7 @@
if (!TextUtils.isEmpty(value)) {
try {
config.priority = Integer.parseInt(value);
- } catch (NumberFormatException e) {
+ } catch (NumberFormatException ignore) {
}
}
@@ -688,7 +687,7 @@
if (!TextUtils.isEmpty(value)) {
try {
config.hiddenSSID = Integer.parseInt(value) != 0;
- } catch (NumberFormatException e) {
+ } catch (NumberFormatException ignore) {
}
}
@@ -697,7 +696,7 @@
if (!TextUtils.isEmpty(value)) {
try {
config.wepTxKeyIndex = Integer.parseInt(value);
- } catch (NumberFormatException e) {
+ } catch (NumberFormatException ignore) {
}
}
@@ -823,7 +822,7 @@
if (!TextUtils.isEmpty(priorityVal)) {
try {
currentPriority = Integer.parseInt(priorityVal);
- } catch (NumberFormatException e) {
+ } catch (NumberFormatException ignore) {
}
}
doReconfig = currentPriority != config.priority;
@@ -1473,7 +1472,7 @@
/*
* Set a timer to put Wi-Fi to sleep, but only if the screen is off
* AND we are transitioning from a state in which the device was supposed
- * to stay awake and a state in which it is not supposed to stay awake.
+ * to stay awake to a state in which it is not supposed to stay awake.
* If "stay awake" state is not changing, we do nothing, to avoid resetting
* the already-set timer.
*/
@@ -1499,7 +1498,7 @@
* of {@code 0} isn't really a plugged type, but rather an indication that the
* device isn't plugged in at all, there is no bit value corresponding to a
* {@code pluggedType} value of {@code 0}. That is why we shift by
- * {@code pluggedType — 1} instead of by {@code pluggedType}.
+ * {@code pluggedType — 1} instead of by {@code pluggedType}.
* @param stayAwakeConditions a bit string specifying which "plugged types" should
* keep the device (and hence Wi-Fi) awake.
* @param pluggedType the type of plug (USB, AC, or none) for which the check is
@@ -1519,33 +1518,44 @@
msg.sendToTarget();
}
+ private void sendStartMessage(boolean scanOnlyMode) {
+ if (DBG) Log.d(TAG, "sendStartMessage(" + scanOnlyMode + ")");
+ Message.obtain(mWifiHandler, MESSAGE_START_WIFI, scanOnlyMode ? 1 : 0, 0).sendToTarget();
+ }
+
private void updateWifiState() {
boolean wifiEnabled = getPersistedWifiEnabled();
boolean airplaneMode = isAirplaneModeOn();
boolean lockHeld = mLocks.hasLocks();
+ int strongestLockMode;
boolean wifiShouldBeEnabled = wifiEnabled && !airplaneMode;
boolean wifiShouldBeStarted = !mDeviceIdle || lockHeld;
+ if (mDeviceIdle && lockHeld) {
+ strongestLockMode = mLocks.getStrongestLockMode();
+ } else {
+ strongestLockMode = WifiManager.WIFI_MODE_FULL;
+ }
synchronized (mWifiHandler) {
if (wifiShouldBeEnabled) {
if (wifiShouldBeStarted) {
- mWakeLock.acquire();
+ sWakeLock.acquire();
sendEnableMessage(true, false);
- mWakeLock.acquire();
- mWifiHandler.sendEmptyMessage(MESSAGE_START_WIFI);
+ sWakeLock.acquire();
+ sendStartMessage(strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY);
} else {
int wakeLockTimeout =
Settings.Secure.getInt(
mContext.getContentResolver(),
Settings.Secure.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS,
DEFAULT_WAKELOCK_TIMEOUT);
- mDriverStopWakeLock.acquire();
+ sDriverStopWakeLock.acquire();
mWifiHandler.sendEmptyMessage(MESSAGE_STOP_WIFI);
mWifiHandler.sendEmptyMessageDelayed(MESSAGE_RELEASE_WAKELOCK, wakeLockTimeout);
}
} else {
- mWakeLock.acquire();
+ sWakeLock.acquire();
sendEnableMessage(false, false);
}
}
@@ -1590,37 +1600,36 @@
public void handleMessage(Message msg) {
switch (msg.what) {
- case MESSAGE_ENABLE_WIFI: {
+ case MESSAGE_ENABLE_WIFI:
setWifiEnabledBlocking(true, msg.arg1 == 1);
- /* fall through */
- }
-
- case MESSAGE_START_WIFI: {
- mWifiStateTracker.startDriver();
- mWakeLock.release();
+ sWakeLock.release();
break;
- }
- case MESSAGE_DISABLE_WIFI: {
+ case MESSAGE_START_WIFI:
+ mWifiStateTracker.setScanOnlyMode(msg.arg1 != 0);
+ mWifiStateTracker.restart();
+ sWakeLock.release();
+ break;
+
+ case MESSAGE_DISABLE_WIFI:
+ // a non-zero msg.arg1 value means the "enabled" setting
+ // should be persisted
setWifiEnabledBlocking(false, msg.arg1 == 1);
- mWakeLock.release();
+ sWakeLock.release();
break;
- }
- case MESSAGE_STOP_WIFI: {
- mWifiStateTracker.stopDriver();
+ case MESSAGE_STOP_WIFI:
+ mWifiStateTracker.disconnectAndStop();
// don't release wakelock
break;
- }
- case MESSAGE_RELEASE_WAKELOCK: {
- synchronized (mDriverStopWakeLock) {
- if (mDriverStopWakeLock.isHeld()) {
- mDriverStopWakeLock.release();
+ case MESSAGE_RELEASE_WAKELOCK:
+ synchronized (sDriverStopWakeLock) {
+ if (sDriverStopWakeLock.isHeld()) {
+ sDriverStopWakeLock.release();
}
}
break;
- }
}
}
}
@@ -1653,6 +1662,9 @@
r.SSID == null ? "" : r.SSID);
}
}
+ pw.println();
+ pw.println("Locks held:");
+ mLocks.dump(pw);
}
private static String stateName(int wifiState) {
@@ -1674,11 +1686,13 @@
private class WifiLock implements IBinder.DeathRecipient {
String mTag;
+ int mLockMode;
IBinder mBinder;
- WifiLock(String tag, IBinder binder) {
+ WifiLock(int lockMode, String tag, IBinder binder) {
super();
mTag = tag;
+ mLockMode = lockMode;
mBinder = binder;
try {
mBinder.linkToDeath(this, 0);
@@ -1694,30 +1708,40 @@
}
public String toString() {
- return "WifiLock{" + mTag + " binder=" + mBinder + "}";
+ return "WifiLock{" + mTag + " type=" + mLockMode + " binder=" + mBinder + "}";
}
}
private class LockList {
- private ArrayList<WifiLock> mList;
+ private List<WifiLock> mList;
- public LockList() {
+ private LockList() {
mList = new ArrayList<WifiLock>();
}
- public boolean hasLocks() {
+ private synchronized boolean hasLocks() {
return !mList.isEmpty();
}
- public void addLock(WifiLock lock) {
- int index = findLockByBinder(lock.mBinder);
- if (index < 0) {
+ private synchronized int getStrongestLockMode() {
+ if (mList.isEmpty()) {
+ return WifiManager.WIFI_MODE_FULL;
+ }
+ for (WifiLock l : mList) {
+ if (l.mLockMode == WifiManager.WIFI_MODE_FULL) {
+ return WifiManager.WIFI_MODE_FULL;
+ }
+ }
+ return WifiManager.WIFI_MODE_SCAN_ONLY;
+ }
+
+ private void addLock(WifiLock lock) {
+ if (findLockByBinder(lock.mBinder) < 0) {
mList.add(lock);
- } else {
}
}
- public WifiLock removeLock(IBinder binder) {
+ private WifiLock removeLock(IBinder binder) {
int index = findLockByBinder(binder);
if (index >= 0) {
return mList.remove(index);
@@ -1733,11 +1757,28 @@
return i;
return -1;
}
+
+ private synchronized void clear() {
+ if (!mList.isEmpty()) {
+ mList.clear();
+ updateWifiState();
+ }
+ }
+
+ private void dump(PrintWriter pw) {
+ for (WifiLock l : mList) {
+ pw.print(" ");
+ pw.println(l);
+ }
+ }
}
- public boolean acquireWifiLock(IBinder binder, String tag) {
+ public boolean acquireWifiLock(IBinder binder, int lockMode, String tag) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
- WifiLock wifiLock = new WifiLock(tag, binder);
+ if (lockMode != WifiManager.WIFI_MODE_FULL && lockMode != WifiManager.WIFI_MODE_SCAN_ONLY) {
+ return false;
+ }
+ WifiLock wifiLock = new WifiLock(lockMode, tag, binder);
synchronized (mLocks) {
return acquireWifiLockLocked(wifiLock);
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 6c58997f..d2149f1 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -9659,7 +9659,10 @@
if (DEBUG_BROADCAST) Log.v(
TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
+ " ordered=" + ordered);
-
+ if ((resultTo != null) && !ordered) {
+ Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
+ }
+
// Handle special intents: if this broadcast is from the package
// manager about a package being removed, we need to remove all of
// its activities from the history stack.
diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java
index 5de1e4b..b18aaf7 100644
--- a/services/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/java/com/android/server/am/PendingIntentRecord.java
@@ -208,10 +208,12 @@
break;
case IActivityManager.INTENT_SENDER_BROADCAST:
try {
+ // If a completion callback has been requested, require
+ // that the broadcast be delivered synchronously
owner.broadcastIntentInPackage(key.packageName, uid,
finalIntent, resolvedType,
finishedReceiver, code, null, null, null,
- false, false);
+ (finishedReceiver != null), false);
sendFinish = false;
} catch (RuntimeException e) {
Log.w(ActivityManagerService.TAG,