diff options
Diffstat (limited to 'services/java')
13 files changed, 755 insertions, 507 deletions
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java index 131e156..78db6f9 100644 --- a/services/java/com/android/server/AppWidgetService.java +++ b/services/java/com/android/server/AppWidgetService.java @@ -68,6 +68,7 @@ class AppWidgetService extends IAppWidgetService.Stub private static final String SETTINGS_FILENAME = "appwidgets.xml"; private static final String SETTINGS_TMP_FILENAME = SETTINGS_FILENAME + ".tmp"; + private static final int MIN_UPDATE_PERIOD = 30 * 60 * 1000; // 30 minutes /* * When identifying a Host or Provider based on the calling process, use the uid field. @@ -629,9 +630,12 @@ class AppWidgetService extends IAppWidgetService.Stub Binder.restoreCallingIdentity(token); } if (!alreadyRegistered) { + long period = p.info.updatePeriodMillis; + if (period < MIN_UPDATE_PERIOD) { + period = MIN_UPDATE_PERIOD; + } mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, - SystemClock.elapsedRealtime() + p.info.updatePeriodMillis, - p.info.updatePeriodMillis, p.broadcast); + SystemClock.elapsedRealtime() + period, period, p.broadcast); } } } diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java index 6e28515..20f0750 100644 --- a/services/java/com/android/server/BackupManagerService.java +++ b/services/java/com/android/server/BackupManagerService.java @@ -1490,7 +1490,9 @@ class BackupManagerService extends IBackupManager.Stub { try { synchronized(this) { - if (mRestoreSets == null) { + if (mRestoreTransport == null) { + Log.w(TAG, "Null transport getting restore sets"); + } else if (mRestoreSets == null) { // valid transport; do the one-time fetch mRestoreSets = mRestoreTransport.getAvailableRestoreSets(); } return mRestoreSets; @@ -1546,8 +1548,6 @@ class BackupManagerService extends IBackupManager.Stub { @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { synchronized (mQueueLock) { - long oldId = Binder.clearCallingIdentity(); - pw.println("Backup Manager is " + (mEnabled ? "enabled" : "disabled") + " / " + (!mProvisioned ? "not " : "") + "provisioned"); pw.println("Available transports:"); @@ -1570,8 +1570,6 @@ class BackupManagerService extends IBackupManager.Stub { for (BackupRequest req : mPendingBackups.values()) { pw.println(" " + req); } - - Binder.restoreCallingIdentity(oldId); } } } diff --git a/services/java/com/android/server/BatteryService.java b/services/java/com/android/server/BatteryService.java index 90d8c9d..5cdce5b 100644 --- a/services/java/com/android/server/BatteryService.java +++ b/services/java/com/android/server/BatteryService.java @@ -92,6 +92,9 @@ class BatteryService extends Binder { // This should probably be exposed in the API, though it's not critical private static final int BATTERY_PLUGGED_NONE = 0; + private static final int BATTERY_LEVEL_CLOSE_WARNING = 20; + private static final int BATTERY_LEVEL_WARNING = 15; + private final Context mContext; private final IBatteryStats mBatteryStats; @@ -120,6 +123,7 @@ class BatteryService extends Binder { private long mDischargeStartTime; private int mDischargeStartLevel; + private boolean mSentLowBatteryBroadcast = false; public BatteryService(Context context) { mContext = context; @@ -260,6 +264,18 @@ class BatteryService extends Binder { intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); mContext.sendBroadcast(intent); } + + final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE; + final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE; + + /* The ACTION_BATTERY_LOW broadcast is sent in these situations: + * - is just un-plugged (previously was plugged) and battery level is under WARNING, or + * - is not plugged and battery level crosses the WARNING boundary (becomes < 15). + */ + final boolean sendBatteryLow = !plugged + && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN + && mBatteryLevel < BATTERY_LEVEL_WARNING + && (oldPlugged || mLastBatteryLevel >= BATTERY_LEVEL_WARNING); mLastBatteryStatus = mBatteryStatus; mLastBatteryHealth = mBatteryHealth; @@ -269,8 +285,15 @@ class BatteryService extends Binder { mLastBatteryVoltage = mBatteryVoltage; mLastBatteryTemperature = mBatteryTemperature; mLastBatteryLevelCritical = mBatteryLevelCritical; - + sendIntent(); + if (sendBatteryLow) { + mSentLowBatteryBroadcast = true; + mContext.sendBroadcast(new Intent(Intent.ACTION_BATTERY_LOW)); + } else if (mSentLowBatteryBroadcast && mLastBatteryLevel >= BATTERY_LEVEL_CLOSE_WARNING) { + mSentLowBatteryBroadcast = false; + mContext.sendBroadcast(new Intent(Intent.ACTION_BATTERY_OKAY)); + } // This needs to be done after sendIntent() so that we get the lastest battery stats. if (logOutlier && dischargeDuration != 0) { diff --git a/services/java/com/android/server/HardwareService.java b/services/java/com/android/server/HardwareService.java index 5bc9b5f..7597f85 100755 --- a/services/java/com/android/server/HardwareService.java +++ b/services/java/com/android/server/HardwareService.java @@ -37,6 +37,9 @@ import android.os.Binder; import android.os.SystemClock; import android.util.Log; +import java.util.LinkedList; +import java.util.ListIterator; + public class HardwareService extends IHardwareService.Stub { private static final String TAG = "HardwareService"; @@ -50,9 +53,62 @@ public class HardwareService extends IHardwareService.Stub { static final int LIGHT_FLASH_NONE = 0; static final int LIGHT_FLASH_TIMED = 1; + private final LinkedList<Vibration> mVibrations; + private Vibration mCurrentVibration; + private boolean mAttentionLightOn; private boolean mPulsing; + private class Vibration implements IBinder.DeathRecipient { + private final IBinder mToken; + private final long mTimeout; + private final long mStartTime; + private final long[] mPattern; + private final int mRepeat; + + Vibration(IBinder token, long millis) { + this(token, millis, null, 0); + } + + Vibration(IBinder token, long[] pattern, int repeat) { + this(token, 0, pattern, repeat); + } + + private Vibration(IBinder token, long millis, long[] pattern, + int repeat) { + mToken = token; + mTimeout = millis; + mStartTime = SystemClock.uptimeMillis(); + mPattern = pattern; + mRepeat = repeat; + } + + public void binderDied() { + synchronized (mVibrations) { + mVibrations.remove(this); + if (this == mCurrentVibration) { + doCancelVibrateLocked(); + startNextVibrationLocked(); + } + } + } + + public boolean hasLongerTimeout(long millis) { + if (mTimeout == 0) { + // This is a pattern, return false to play the simple + // vibration. + return false; + } + if ((mStartTime + mTimeout) + < (SystemClock.uptimeMillis() + millis)) { + // If this vibration will end before the time passed in, let + // the new vibration play. + return false; + } + return true; + } + } + HardwareService(Context context) { // Reset the hardware to a default state, in case this is a runtime // restart instead of a fresh boot. @@ -66,6 +122,8 @@ public class HardwareService extends IHardwareService.Stub { mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); mWakeLock.setReferenceCounted(true); + mVibrations = new LinkedList<Vibration>(); + mBatteryStats = BatteryStatsService.getService(); IntentFilter filter = new IntentFilter(); @@ -78,13 +136,24 @@ public class HardwareService extends IHardwareService.Stub { super.finalize(); } - public void vibrate(long milliseconds) { + public void vibrate(long milliseconds, IBinder token) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.VIBRATE) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires VIBRATE permission"); } - doCancelVibrate(); - vibratorOn(milliseconds); + if (mCurrentVibration != null + && mCurrentVibration.hasLongerTimeout(milliseconds)) { + // Ignore this vibration since the current vibration will play for + // longer than milliseconds. + return; + } + Vibration vib = new Vibration(token, milliseconds); + synchronized (mVibrations) { + removeVibrationLocked(token); + doCancelVibrateLocked(); + mCurrentVibration = vib; + startVibrationLocked(vib); + } } private boolean isAll0(long[] pattern) { @@ -121,34 +190,25 @@ public class HardwareService extends IHardwareService.Stub { return; } - synchronized (this) { - Death death = new Death(token); - try { - token.linkToDeath(death, 0); - } catch (RemoteException e) { - return; - } - - Thread oldThread = mThread; - - if (oldThread != null) { - // stop the old one - synchronized (mThread) { - mThread.mDone = true; - mThread.notify(); - } - } + Vibration vib = new Vibration(token, pattern, repeat); + try { + token.linkToDeath(vib, 0); + } catch (RemoteException e) { + return; + } - if (mDeath != null) { - mToken.unlinkToDeath(mDeath, 0); + synchronized (mVibrations) { + removeVibrationLocked(token); + doCancelVibrateLocked(); + if (repeat >= 0) { + mVibrations.addFirst(vib); + startNextVibrationLocked(); + } else { + // A negative repeat means that this pattern is not meant + // to repeat. Treat it like a simple vibration. + mCurrentVibration = vib; + startVibrationLocked(vib); } - - mDeath = death; - mToken = token; - - // start the new thread - mThread = new VibrateThread(pattern, repeat); - mThread.start(); } } finally { @@ -156,7 +216,7 @@ public class HardwareService extends IHardwareService.Stub { } } - public void cancelVibrate() { + public void cancelVibrate(IBinder token) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.VIBRATE, "cancelVibrate"); @@ -164,7 +224,13 @@ public class HardwareService extends IHardwareService.Stub { // so wakelock calls will succeed long identity = Binder.clearCallingIdentity(); try { - doCancelVibrate(); + synchronized (mVibrations) { + final Vibration vib = removeVibrationLocked(token); + if (vib == mCurrentVibration) { + doCancelVibrateLocked(); + startNextVibrationLocked(); + } + } } finally { Binder.restoreCallingIdentity(identity); @@ -277,27 +343,74 @@ public class HardwareService extends IHardwareService.Stub { } }; - private void doCancelVibrate() { - synchronized (this) { - if (mThread != null) { - synchronized (mThread) { - mThread.mDone = true; - mThread.notify(); - } - mThread = null; + private final Runnable mVibrationRunnable = new Runnable() { + public void run() { + synchronized (mVibrations) { + doCancelVibrateLocked(); + startNextVibrationLocked(); + } + } + }; + + // Lock held on mVibrations + private void doCancelVibrateLocked() { + if (mThread != null) { + synchronized (mThread) { + mThread.mDone = true; + mThread.notify(); } - vibratorOff(); + mThread = null; } + vibratorOff(); + mH.removeCallbacks(mVibrationRunnable); + } + + // Lock held on mVibrations + private void startNextVibrationLocked() { + if (mVibrations.size() <= 0) { + return; + } + mCurrentVibration = mVibrations.getFirst(); + startVibrationLocked(mCurrentVibration); + } + + // Lock held on mVibrations + private void startVibrationLocked(final Vibration vib) { + if (vib.mTimeout != 0) { + vibratorOn(vib.mTimeout); + mH.postDelayed(mVibrationRunnable, vib.mTimeout); + } else { + // mThread better be null here. doCancelVibrate should always be + // called before startNextVibrationLocked or startVibrationLocked. + mThread = new VibrateThread(vib); + mThread.start(); + } + } + + // Lock held on mVibrations + private Vibration removeVibrationLocked(IBinder token) { + ListIterator<Vibration> iter = mVibrations.listIterator(0); + while (iter.hasNext()) { + Vibration vib = iter.next(); + if (vib.mToken == token) { + iter.remove(); + return vib; + } + } + // We might be looking for a simple vibration which is only stored in + // mCurrentVibration. + if (mCurrentVibration != null && mCurrentVibration.mToken == token) { + return mCurrentVibration; + } + return null; } private class VibrateThread extends Thread { - long[] mPattern; - int mRepeat; + final Vibration mVibration; boolean mDone; - VibrateThread(long[] pattern, int repeat) { - mPattern = pattern; - mRepeat = repeat; + VibrateThread(Vibration vib) { + mVibration = vib; mWakeLock.acquire(); } @@ -323,8 +436,9 @@ public class HardwareService extends IHardwareService.Stub { Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY); synchronized (this) { int index = 0; - long[] pattern = mPattern; + long[] pattern = mVibration.mPattern; int len = pattern.length; + int repeat = mVibration.mRepeat; long duration = 0; while (!mDone) { @@ -347,50 +461,37 @@ public class HardwareService extends IHardwareService.Stub { HardwareService.this.vibratorOn(duration); } } else { - if (mRepeat < 0) { + if (repeat < 0) { break; } else { - index = mRepeat; + index = repeat; duration = 0; } } } - if (mDone) { - // make sure vibrator is off if we were cancelled. - // otherwise, it will turn off automatically - // when the last timeout expires. - HardwareService.this.vibratorOff(); - } mWakeLock.release(); } - synchronized (HardwareService.this) { + synchronized (mVibrations) { if (mThread == this) { mThread = null; } - } - } - }; - - private class Death implements IBinder.DeathRecipient { - IBinder mMe; - - Death(IBinder me) { - mMe = me; - } - - public void binderDied() { - synchronized (HardwareService.this) { - if (mMe == mToken) { - doCancelVibrate(); + if (!mDone) { + // If this vibration finished naturally, start the next + // vibration. + mVibrations.remove(mVibration); + startNextVibrationLocked(); } } } - } + }; BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) { - doCancelVibrate(); + synchronized (mVibrations) { + doCancelVibrateLocked(); + mVibrations.clear(); + } } } }; @@ -407,8 +508,6 @@ public class HardwareService extends IHardwareService.Stub { private final IBatteryStats mBatteryStats; volatile VibrateThread mThread; - volatile Death mDeath; - volatile IBinder mToken; private int mNativePointer; diff --git a/services/java/com/android/server/InputDevice.java b/services/java/com/android/server/InputDevice.java index 7b8a2a4..a71c39a 100644 --- a/services/java/com/android/server/InputDevice.java +++ b/services/java/com/android/server/InputDevice.java @@ -63,22 +63,59 @@ public class InputDevice { yMoveScale = my != 0 ? (1.0f/my) : 1.0f; } - MotionEvent generateMotion(InputDevice device, long curTime, + MotionEvent generateMotion(InputDevice device, long curTime, long curTimeNano, boolean isAbs, Display display, int orientation, int metaState) { - if (!changed) { - return null; - } - float scaledX = x; float scaledY = y; float temp; float scaledPressure = 1.0f; float scaledSize = 0; int edgeFlags = 0; + + int action; + if (down != lastDown) { + if (isAbs) { + final AbsoluteInfo absX = device.absX; + final AbsoluteInfo absY = device.absY; + if (down && absX != null && absY != null) { + // We don't let downs start unless we are + // inside of the screen. There are two reasons for + // this: to avoid spurious touches when holding + // the edges of the device near the touchscreen, + // and to avoid reporting events if there are virtual + // keys on the touchscreen outside of the display + // area. + if (scaledX < absX.minValue || scaledX > absX.maxValue + || scaledY < absY.minValue || scaledY > absY.maxValue) { + if (false) Log.v("InputDevice", "Rejecting (" + scaledX + "," + + scaledY + "): outside of (" + + absX.minValue + "," + absY.minValue + + ")-(" + absX.maxValue + "," + + absY.maxValue + ")"); + return null; + } + } + } else { + x = y = 0; + } + lastDown = down; + if (down) { + action = MotionEvent.ACTION_DOWN; + downTime = curTime; + } else { + action = MotionEvent.ACTION_UP; + } + currentMove = null; + } else { + action = MotionEvent.ACTION_MOVE; + } + if (isAbs) { - int w = display.getWidth()-1; - int h = display.getHeight()-1; + final int dispW = display.getWidth()-1; + final int dispH = display.getHeight()-1; + int w = dispW; + int h = dispH; if (orientation == Surface.ROTATION_90 || orientation == Surface.ROTATION_270) { int tmp = w; @@ -120,16 +157,17 @@ public class InputDevice { break; } - if (scaledX == 0) { - edgeFlags += MotionEvent.EDGE_LEFT; - } else if (scaledX == display.getWidth() - 1.0f) { - edgeFlags += MotionEvent.EDGE_RIGHT; - } - - if (scaledY == 0) { - edgeFlags += MotionEvent.EDGE_TOP; - } else if (scaledY == display.getHeight() - 1.0f) { - edgeFlags += MotionEvent.EDGE_BOTTOM; + if (action != MotionEvent.ACTION_DOWN) { + if (scaledX <= 0) { + edgeFlags += MotionEvent.EDGE_LEFT; + } else if (scaledX >= dispW) { + edgeFlags += MotionEvent.EDGE_RIGHT; + } + if (scaledY <= 0) { + edgeFlags += MotionEvent.EDGE_TOP; + } else if (scaledY >= dispH) { + edgeFlags += MotionEvent.EDGE_BOTTOM; + } } } else { @@ -153,41 +191,25 @@ public class InputDevice { } } - changed = false; - if (down != lastDown) { - int action; - lastDown = down; - if (down) { - action = MotionEvent.ACTION_DOWN; - downTime = curTime; - } else { - action = MotionEvent.ACTION_UP; - } - currentMove = null; - if (!isAbs) { - x = y = 0; - } - return MotionEvent.obtain(downTime, curTime, action, - scaledX, scaledY, scaledPressure, scaledSize, metaState, - xPrecision, yPrecision, device.id, edgeFlags); - } else { - if (currentMove != null) { - if (false) Log.i("InputDevice", "Adding batch x=" + scaledX - + " y=" + scaledY + " to " + currentMove); - currentMove.addBatch(curTime, scaledX, scaledY, - scaledPressure, scaledSize, metaState); - if (WindowManagerPolicy.WATCH_POINTER) { - Log.i("KeyInputQueue", "Updating: " + currentMove); - } - return null; + if (currentMove != null) { + if (false) Log.i("InputDevice", "Adding batch x=" + scaledX + + " y=" + scaledY + " to " + currentMove); + currentMove.addBatch(curTime, scaledX, scaledY, + scaledPressure, scaledSize, metaState); + if (WindowManagerPolicy.WATCH_POINTER) { + Log.i("KeyInputQueue", "Updating: " + currentMove); } - MotionEvent me = MotionEvent.obtain(downTime, curTime, - MotionEvent.ACTION_MOVE, scaledX, scaledY, - scaledPressure, scaledSize, metaState, - xPrecision, yPrecision, device.id, edgeFlags); + return null; + } + + MotionEvent me = MotionEvent.obtainNano(downTime, curTime, + curTimeNano, action, scaledX, scaledY, + scaledPressure, scaledSize, metaState, + xPrecision, yPrecision, device.id, edgeFlags); + if (action == MotionEvent.ACTION_MOVE) { currentMove = me; - return me; } + return me; } } diff --git a/services/java/com/android/server/KeyInputQueue.java b/services/java/com/android/server/KeyInputQueue.java index 411cd6b..fd6b813 100644 --- a/services/java/com/android/server/KeyInputQueue.java +++ b/services/java/com/android/server/KeyInputQueue.java @@ -18,8 +18,9 @@ package com.android.server; import android.content.Context; import android.content.res.Configuration; -import android.os.SystemClock; +import android.os.LatencyTimer; import android.os.PowerManager; +import android.os.SystemClock; import android.util.Log; import android.util.SparseArray; import android.view.Display; @@ -29,10 +30,20 @@ import android.view.RawInputEvent; import android.view.Surface; import android.view.WindowManagerPolicy; +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; + public abstract class KeyInputQueue { static final String TAG = "KeyInputQueue"; - SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>(); + static final boolean DEBUG_VIRTUAL_KEYS = false; + + final SparseArray<InputDevice> mDevices = new SparseArray<InputDevice>(); + final ArrayList<VirtualKey> mVirtualKeys = new ArrayList<VirtualKey>(); int mGlobalMetaState = 0; boolean mHaveGlobalMetaState = false; @@ -43,10 +54,14 @@ public abstract class KeyInputQueue { int mCacheCount; Display mDisplay = null; + int mDisplayWidth; + int mDisplayHeight; int mOrientation = Surface.ROTATION_0; int[] mKeyRotationMap = null; + VirtualKey mPressedVirtualKey = null; + PowerManager.WakeLock mWakeLock; static final int[] KEY_90_MAP = new int[] { @@ -73,14 +88,17 @@ public abstract class KeyInputQueue { public static final int FILTER_REMOVE = 0; public static final int FILTER_KEEP = 1; public static final int FILTER_ABORT = -1; - + + private static final boolean MEASURE_LATENCY = false; + private LatencyTimer lt; + public interface FilterCallback { int filterEvent(QueuedEvent ev); } static class QueuedEvent { InputDevice inputDevice; - long when; + long whenNano; int flags; // From the raw event int classType; // One of the class constants in InputEvent Object event; @@ -88,7 +106,7 @@ public abstract class KeyInputQueue { void copyFrom(QueuedEvent that) { this.inputDevice = that.inputDevice; - this.when = that.when; + this.whenNano = that.whenNano; this.flags = that.flags; this.classType = that.classType; this.event = that.event; @@ -106,7 +124,106 @@ public abstract class KeyInputQueue { QueuedEvent next; } + /** + * A key that exists as a part of the touch-screen, outside of the normal + * display area of the screen. + */ + static class VirtualKey { + int scancode; + int centerx; + int centery; + int width; + int height; + + int hitLeft; + int hitTop; + int hitRight; + int hitBottom; + + InputDevice lastDevice; + int lastKeycode; + + boolean checkHit(int x, int y) { + return (x >= hitLeft && x <= hitRight + && y >= hitTop && y <= hitBottom); + } + + void computeHitRect(InputDevice dev, int dw, int dh) { + if (dev == lastDevice) { + return; + } + + if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "computeHitRect for " + scancode + + ": dev=" + dev + " absX=" + dev.absX + " absY=" + dev.absY); + + lastDevice = dev; + + int minx = dev.absX.minValue; + int maxx = dev.absX.maxValue; + + int halfw = width/2; + int left = centerx - halfw; + int right = centerx + halfw; + hitLeft = minx + ((left*maxx-minx)/dw); + hitRight = minx + ((right*maxx-minx)/dw); + + int miny = dev.absY.minValue; + int maxy = dev.absY.maxValue; + + int halfh = height/2; + int top = centery - halfh; + int bottom = centery + halfh; + hitTop = miny + ((top*maxy-miny)/dh); + hitBottom = miny + ((bottom*maxy-miny)/dh); + } + } + KeyInputQueue(Context context) { + if (MEASURE_LATENCY) { + lt = new LatencyTimer(100, 1000); + } + + try { + FileInputStream fis = new FileInputStream( + "/sys/board_properties/virtualkeys.synaptics-rmi-touchscreen"); + InputStreamReader isr = new InputStreamReader(fis); + BufferedReader br = new BufferedReader(isr); + String str = br.readLine(); + if (str != null) { + String[] it = str.split(":"); + if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "***** VIRTUAL KEYS: " + it); + final int N = it.length-6; + for (int i=0; i<=N; i+=6) { + if (!"0x01".equals(it[i])) { + Log.w(TAG, "Unknown virtual key type at elem #" + i + + ": " + it[i]); + continue; + } + try { + VirtualKey sb = new VirtualKey(); + sb.scancode = Integer.parseInt(it[i+1]); + sb.centerx = Integer.parseInt(it[i+2]); + sb.centery = Integer.parseInt(it[i+3]); + sb.width = Integer.parseInt(it[i+4]); + sb.height = Integer.parseInt(it[i+5]); + if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Virtual key " + + sb.scancode + ": center=" + sb.centerx + "," + + sb.centery + " size=" + sb.width + "x" + + sb.height); + mVirtualKeys.add(sb); + } catch (NumberFormatException e) { + Log.w(TAG, "Bad number at region " + i + " in: " + + str, e); + } + } + } + br.close(); + } catch (FileNotFoundException e) { + Log.i(TAG, "No virtual keys found"); + } catch (IOException e) { + Log.w(TAG, "Error reading virtual keys", e); + } + PowerManager pm = (PowerManager)context.getSystemService( Context.POWER_SERVICE); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, @@ -123,6 +240,12 @@ public abstract class KeyInputQueue { public void setDisplay(Display display) { mDisplay = display; + + // We assume at this point that the display dimensions reflect the + // natural, unrotated display. We will perform hit tests for soft + // buttons based on that display. + mDisplayWidth = display.getWidth(); + mDisplayHeight = display.getHeight(); } public void getInputConfiguration(Configuration config) { @@ -165,6 +288,7 @@ public abstract class KeyInputQueue { public static native int getScancodeState(int deviceId, int sw); public static native int getKeycodeState(int sw); public static native int getKeycodeState(int deviceId, int sw); + public static native int scancodeToKeycode(int deviceId, int scancode); public static native boolean hasKeys(int[] keycodes, boolean[] keyExists); public static KeyEvent newKeyEvent(InputDevice device, long downTime, @@ -241,7 +365,7 @@ public abstract class KeyInputQueue { if (configChanged) { synchronized (mFirst) { - addLocked(di, SystemClock.uptimeMillis(), 0, + addLocked(di, System.nanoTime(), 0, RawInputEvent.CLASS_CONFIGURATION_CHANGED, null); } @@ -256,6 +380,7 @@ public abstract class KeyInputQueue { // timebase as SystemClock.uptimeMillis(). //curTime = gotOne ? ev.when : SystemClock.uptimeMillis(); final long curTime = SystemClock.uptimeMillis(); + final long curTimeNano = System.nanoTime(); //Log.i(TAG, "curTime=" + curTime + ", systemClock=" + SystemClock.uptimeMillis()); final int classes = di.classes; @@ -276,7 +401,7 @@ public abstract class KeyInputQueue { down = false; } int keycode = rotateKeyCodeLocked(ev.keycode); - addLocked(di, curTime, ev.flags, + addLocked(di, curTimeNano, ev.flags, RawInputEvent.CLASS_KEYBOARD, newKeyEvent(di, di.mDownTime, curTime, down, keycode, 0, scancode, @@ -330,36 +455,127 @@ public abstract class KeyInputQueue { } MotionEvent me; - me = di.mAbs.generateMotion(di, curTime, true, - mDisplay, mOrientation, mGlobalMetaState); - if (false) Log.v(TAG, "Absolute: x=" + di.mAbs.x - + " y=" + di.mAbs.y + " ev=" + me); - if (me != null) { - if (WindowManagerPolicy.WATCH_POINTER) { - Log.i(TAG, "Enqueueing: " + me); + + InputDevice.MotionState ms = di.mAbs; + if (ms.changed) { + ms.changed = false; + + boolean doMotion = true; + + // Look for virtual buttons. + VirtualKey vk = mPressedVirtualKey; + if (vk != null) { + doMotion = false; + if (!ms.down) { + mPressedVirtualKey = null; + ms.lastDown = ms.down; + if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, + "Generate key up for: " + vk.scancode); + addLocked(di, curTimeNano, ev.flags, + RawInputEvent.CLASS_KEYBOARD, + newKeyEvent(di, di.mDownTime, + curTime, false, + vk.lastKeycode, + 0, vk.scancode, 0)); + } + } else if (ms.down && !ms.lastDown) { + vk = findSoftButton(di); + if (vk != null) { + doMotion = false; + mPressedVirtualKey = vk; + vk.lastKeycode = scancodeToKeycode( + di.id, vk.scancode); + ms.lastDown = ms.down; + di.mDownTime = curTime; + if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, + "Generate key down for: " + vk.scancode + + " (keycode=" + vk.lastKeycode + ")"); + addLocked(di, curTimeNano, ev.flags, + RawInputEvent.CLASS_KEYBOARD, + newKeyEvent(di, di.mDownTime, + curTime, true, + vk.lastKeycode, 0, + vk.scancode, 0)); + } + } + + if (doMotion) { + me = ms.generateMotion(di, curTime, + curTimeNano, true, mDisplay, + mOrientation, mGlobalMetaState); + if (false) Log.v(TAG, "Absolute: x=" + di.mAbs.x + + " y=" + di.mAbs.y + " ev=" + me); + if (me != null) { + if (WindowManagerPolicy.WATCH_POINTER) { + Log.i(TAG, "Enqueueing: " + me); + } + addLocked(di, curTimeNano, ev.flags, + RawInputEvent.CLASS_TOUCHSCREEN, me); + } } - addLocked(di, curTime, ev.flags, - RawInputEvent.CLASS_TOUCHSCREEN, me); } - me = di.mRel.generateMotion(di, curTime, false, - mDisplay, mOrientation, mGlobalMetaState); - if (false) Log.v(TAG, "Relative: x=" + di.mRel.x - + " y=" + di.mRel.y + " ev=" + me); - if (me != null) { - addLocked(di, curTime, ev.flags, - RawInputEvent.CLASS_TRACKBALL, me); + + ms = di.mRel; + if (ms.changed) { + ms.changed = false; + + me = ms.generateMotion(di, curTime, + curTimeNano, false, mDisplay, + mOrientation, mGlobalMetaState); + if (false) Log.v(TAG, "Relative: x=" + di.mRel.x + + " y=" + di.mRel.y + " ev=" + me); + if (me != null) { + addLocked(di, curTimeNano, ev.flags, + RawInputEvent.CLASS_TRACKBALL, me); + } } } } } } - } - catch (RuntimeException exc) { + + } catch (RuntimeException exc) { Log.e(TAG, "InputReaderThread uncaught exception", exc); } } }; + private VirtualKey findSoftButton(InputDevice dev) { + final int N = mVirtualKeys.size(); + if (N <= 0) { + return null; + } + + final InputDevice.AbsoluteInfo absx = dev.absX; + final InputDevice.AbsoluteInfo absy = dev.absY; + final InputDevice.MotionState absm = dev.mAbs; + if (absx == null || absy == null || absm == null) { + return null; + } + + if (absm.x >= absx.minValue && absm.x <= absx.maxValue + && absm.y >= absy.minValue && absm.y <= absy.maxValue) { + if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Input (" + absm.x + + "," + absm.y + ") inside of display"); + return null; + } + + for (int i=0; i<N; i++) { + VirtualKey sb = mVirtualKeys.get(i); + sb.computeHitRect(dev, mDisplayWidth, mDisplayHeight); + if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Hit test (" + absm.x + "," + + absm.y + ") in code " + sb.scancode + " - (" + sb.hitLeft + + "," + sb.hitTop + ")-(" + sb.hitRight + "," + + sb.hitBottom + ")"); + if (sb.checkHit(absm.x, absm.y)) { + if (DEBUG_VIRTUAL_KEYS) Log.v(TAG, "Hit!"); + return sb; + } + } + + return null; + } + /** * Returns a new meta state for the given keys and old state. */ @@ -530,7 +746,7 @@ public abstract class KeyInputQueue { } } - private QueuedEvent obtainLocked(InputDevice device, long when, + private QueuedEvent obtainLocked(InputDevice device, long whenNano, int flags, int classType, Object event) { QueuedEvent ev; if (mCacheCount == 0) { @@ -542,7 +758,7 @@ public abstract class KeyInputQueue { mCacheCount--; } ev.inputDevice = device; - ev.when = when; + ev.whenNano = whenNano; ev.flags = flags; ev.classType = classType; ev.event = event; @@ -561,13 +777,13 @@ public abstract class KeyInputQueue { } } - private void addLocked(InputDevice device, long when, int flags, + private void addLocked(InputDevice device, long whenNano, int flags, int classType, Object event) { boolean poke = mFirst.next == mLast; - QueuedEvent ev = obtainLocked(device, when, flags, classType, event); + QueuedEvent ev = obtainLocked(device, whenNano, flags, classType, event); QueuedEvent p = mLast.prev; - while (p != mFirst && ev.when < p.when) { + while (p != mFirst && ev.whenNano < p.whenNano) { p = p.prev; } @@ -578,8 +794,15 @@ public abstract class KeyInputQueue { ev.inQueue = true; if (poke) { + long time; + if (MEASURE_LATENCY) { + time = System.nanoTime(); + } mFirst.notify(); mWakeLock.acquire(); + if (MEASURE_LATENCY) { + lt.sample("1 addLocked-queued event ", System.nanoTime() - time); + } } } diff --git a/services/java/com/android/server/MasterClearReceiver.java b/services/java/com/android/server/MasterClearReceiver.java index 5a42e76..3c366da 100644 --- a/services/java/com/android/server/MasterClearReceiver.java +++ b/services/java/com/android/server/MasterClearReceiver.java @@ -30,8 +30,8 @@ public class MasterClearReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals("android.intent.action.GTALK_DATA_MESSAGE_RECEIVED")) { - if (!intent.getBooleanExtra("from_trusted_server", false)) { + if (intent.getAction().equals(Intent.ACTION_REMOTE_INTENT)) { + if (!intent.getBooleanExtra("android.intent.extra.from_trusted_server", false)) { Log.w(TAG, "Ignoring master clear request -- not from trusted server."); return; } diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index b85cf2c..682eaa7 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -1683,6 +1683,9 @@ class PackageManagerService extends IPackageManager.Stub { } } + /** + * @deprecated + */ public void querySyncProviders(List outNames, List outInfo) { synchronized (mPackages) { Iterator<Map.Entry<String, PackageParser.Provider>> i diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index b038a64..48d97ec 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -32,12 +32,7 @@ import android.content.pm.IPackageManager; import android.database.ContentObserver; import android.database.Cursor; import android.media.AudioService; -import android.os.IBinder; -import android.os.Looper; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.SystemClock; -import android.os.SystemProperties; +import android.os.*; import android.provider.Contacts.People; import android.provider.Settings; import android.server.BluetoothA2dpService; @@ -45,6 +40,7 @@ import android.server.BluetoothDeviceService; import android.server.search.SearchManagerService; import android.util.EventLog; import android.util.Log; +import android.accounts.AccountManagerService; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; @@ -120,6 +116,14 @@ class ServerThread extends Thread { mContentResolver = context.getContentResolver(); + try { + Log.i(TAG, "Starting Account Manager."); + ServiceManager.addService(Context.ACCOUNT_SERVICE, + new AccountManagerService(context)); + } catch (Throwable e) { + Log.e(TAG, "Failure starting Account Manager", e); + } + Log.i(TAG, "Starting Content Manager."); ContentService.main(context, factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL); @@ -172,7 +176,7 @@ class ServerThread extends Thread { bluetooth = new BluetoothDeviceService(context); bluetooth.init(); ServiceManager.addService(Context.BLUETOOTH_SERVICE, bluetooth); - bluetoothA2dp = new BluetoothA2dpService(context); + bluetoothA2dp = new BluetoothA2dpService(context, bluetooth); ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE, bluetoothA2dp); @@ -419,19 +423,19 @@ public class SystemServer public static final int FACTORY_TEST_OFF = 0; public static final int FACTORY_TEST_LOW_LEVEL = 1; public static final int FACTORY_TEST_HIGH_LEVEL = 2; - - /** - * This method is called from Zygote to initialize the system. This will cause the native + + /** + * This method is called from Zygote to initialize the system. This will cause the native * services (SurfaceFlinger, AudioFlinger, etc..) to be started. After that it will call back * up into init2() to start the Android services. - */ + */ native public static void init1(String[] args); public static void main(String[] args) { // The system server has to run all of the time, so it needs to be // as efficient as possible with its memory usage. VMRuntime.getRuntime().setTargetHeapUtilization(0.8f); - + System.loadLibrary("android_servers"); init1(args); } diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java index b4754b6..67e8cf3 100644 --- a/services/java/com/android/server/WifiService.java +++ b/services/java/com/android/server/WifiService.java @@ -41,6 +41,7 @@ import android.net.wifi.WifiConfiguration; import android.net.wifi.SupplicantState; import android.net.NetworkStateTracker; import android.net.DhcpInfo; +import android.net.NetworkUtils; import android.os.Binder; import android.os.Handler; import android.os.HandlerThread; @@ -142,28 +143,6 @@ public class WifiService extends IWifiManager.Stub { private final WifiHandler mWifiHandler; /* - * Map used to keep track of hidden networks presence, which - * is needed to switch between active and passive scan modes. - * If there is at least one hidden network that is currently - * present (enabled), we want to do active scans instead of - * passive. - */ - private final Map<Integer, Boolean> mIsHiddenNetworkPresent; - /* - * The number of currently present hidden networks. When this - * counter goes from 0 to 1 or from 1 to 0, we change the - * scan mode to active or passive respectively. Initially, we - * set the counter to 0 and we increment it every time we add - * a new present (enabled) hidden network. - */ - private int mNumHiddenNetworkPresent; - /* - * Whether we change the scan mode is due to a hidden network - * (in this class, this is always the case) - */ - private final static boolean SET_DUE_TO_A_HIDDEN_NETWORK = true; - - /* * Cache of scan results objects (size is somewhat arbitrary) */ private static final int SCAN_RESULT_CACHE_SIZE = 80; @@ -195,12 +174,6 @@ public class WifiService extends IWifiManager.Stub { mWifiStateTracker.enableRssiPolling(true); mBatteryStats = BatteryStatsService.getService(); - /* - * Initialize the hidden-networks state - */ - mIsHiddenNetworkPresent = new HashMap<Integer, Boolean>(); - mNumHiddenNetworkPresent = 0; - mScanResultCache = new LinkedHashMap<String, ScanResult>( SCAN_RESULT_CACHE_SIZE, 0.75f, true) { /* @@ -254,155 +227,6 @@ public class WifiService extends IWifiManager.Stub { setWifiEnabledBlocking(wifiEnabled, false, Process.myUid()); } - /** - * Initializes the hidden networks state. Must be called when we - * enable Wi-Fi. - */ - private synchronized void initializeHiddenNetworksState() { - // First, reset the state - resetHiddenNetworksState(); - - // ... then add networks that are marked as hidden - List<WifiConfiguration> networks = getConfiguredNetworks(); - if (!networks.isEmpty()) { - for (WifiConfiguration config : networks) { - if (config != null && config.hiddenSSID) { - addOrUpdateHiddenNetwork( - config.networkId, - config.status != WifiConfiguration.Status.DISABLED); - } - } - - } - } - - /** - * Resets the hidden networks state. - */ - private synchronized void resetHiddenNetworksState() { - mNumHiddenNetworkPresent = 0; - mIsHiddenNetworkPresent.clear(); - } - - /** - * Marks all but netId network as not present. - */ - private synchronized void markAllHiddenNetworksButOneAsNotPresent(int netId) { - for (Map.Entry<Integer, Boolean> entry : mIsHiddenNetworkPresent.entrySet()) { - if (entry != null) { - Integer networkId = entry.getKey(); - if (networkId != netId) { - updateNetworkIfHidden( - networkId, false); - } - } - } - } - - /** - * Updates the netId network presence status if netId is an existing - * hidden network. - */ - private synchronized void updateNetworkIfHidden(int netId, boolean present) { - if (isHiddenNetwork(netId)) { - addOrUpdateHiddenNetwork(netId, present); - } - } - - /** - * Updates the netId network presence status if netId is an existing - * hidden network. If the network does not exist, adds the network. - */ - private synchronized void addOrUpdateHiddenNetwork(int netId, boolean present) { - if (0 <= netId) { - - // If we are adding a new entry or modifying an existing one - Boolean isPresent = mIsHiddenNetworkPresent.get(netId); - if (isPresent == null || isPresent != present) { - if (present) { - incrementHiddentNetworkPresentCounter(); - } else { - // If we add a new hidden network, no need to change - // the counter (it must be 0) - if (isPresent != null) { - decrementHiddentNetworkPresentCounter(); - } - } - mIsHiddenNetworkPresent.put(netId, present); - } - } else { - Log.e(TAG, "addOrUpdateHiddenNetwork(): Invalid (negative) network id!"); - } - } - - /** - * Removes the netId network if it is hidden (being kept track of). - */ - private synchronized void removeNetworkIfHidden(int netId) { - if (isHiddenNetwork(netId)) { - removeHiddenNetwork(netId); - } - } - - /** - * Removes the netId network. For the call to be successful, the network - * must be hidden. - */ - private synchronized void removeHiddenNetwork(int netId) { - if (0 <= netId) { - Boolean isPresent = - mIsHiddenNetworkPresent.remove(netId); - if (isPresent != null) { - // If we remove an existing hidden network that is not - // present, no need to change the counter - if (isPresent) { - decrementHiddentNetworkPresentCounter(); - } - } else { - if (DBG) { - Log.d(TAG, "removeHiddenNetwork(): Removing a non-existent network!"); - } - } - } else { - Log.e(TAG, "removeHiddenNetwork(): Invalid (negative) network id!"); - } - } - - /** - * Returns true if netId is an existing hidden network. - */ - private synchronized boolean isHiddenNetwork(int netId) { - return mIsHiddenNetworkPresent.containsKey(netId); - } - - /** - * Increments the present (enabled) hidden networks counter. If the - * counter value goes from 0 to 1, changes the scan mode to active. - */ - private void incrementHiddentNetworkPresentCounter() { - ++mNumHiddenNetworkPresent; - if (1 == mNumHiddenNetworkPresent) { - // Switch the scan mode to "active" - mWifiStateTracker.setScanMode(true, SET_DUE_TO_A_HIDDEN_NETWORK); - } - } - - /** - * Decrements the present (enabled) hidden networks counter. If the - * counter goes from 1 to 0, changes the scan mode back to passive. - */ - private void decrementHiddentNetworkPresentCounter() { - if (0 < mNumHiddenNetworkPresent) { - --mNumHiddenNetworkPresent; - if (0 == mNumHiddenNetworkPresent) { - // Switch the scan mode to "passive" - mWifiStateTracker.setScanMode(false, SET_DUE_TO_A_HIDDEN_NETWORK); - } - } else { - Log.e(TAG, "Hidden-network counter invariant violation!"); - } - } - private boolean getPersistedWifiEnabled() { final ContentResolver cr = mContext.getContentResolver(); try { @@ -522,7 +346,7 @@ public class WifiService extends IWifiManager.Stub { } // We must reset the interface before we unload the driver - mWifiStateTracker.resetInterface(); + mWifiStateTracker.resetInterface(false); if (!WifiNative.unloadDriver()) { Log.e(TAG, "Failed to unload Wi-Fi driver."); @@ -544,12 +368,10 @@ public class WifiService extends IWifiManager.Stub { setWifiEnabledState(eventualWifiState, uid); /* - * Initialize the hidden networks state and the number of allowed - * radio channels if Wi-Fi is being turned on. + * Initialize the number of allowed radio channels if Wi-Fi is being turned on. */ if (enable) { mWifiStateTracker.setNumAllowedChannels(); - initializeHiddenNetworksState(); } return true; @@ -884,15 +706,6 @@ public class WifiService extends IWifiManager.Stub { } mNeedReconfig = mNeedReconfig || doReconfig; - /* - * If we have hidden networks, we may have to change the scan mode - */ - if (config.hiddenSSID) { - // Mark the network as present unless it is disabled - addOrUpdateHiddenNetwork( - netId, config.status != WifiConfiguration.Status.DISABLED); - } - setVariables: { /* * Note that if a networkId for a non-existent network @@ -1220,11 +1033,6 @@ public class WifiService extends IWifiManager.Stub { public boolean removeNetwork(int netId) { enforceChangePermission(); - /* - * If we have hidden networks, we may have to change the scan mode - */ - removeNetworkIfHidden(netId); - return mWifiStateTracker.removeNetwork(netId); } @@ -1238,18 +1046,14 @@ public class WifiService extends IWifiManager.Stub { public boolean enableNetwork(int netId, boolean disableOthers) { enforceChangePermission(); - /* - * If we have hidden networks, we may have to change the scan mode - */ - synchronized(this) { - if (disableOthers) { - markAllHiddenNetworksButOneAsNotPresent(netId); - } - updateNetworkIfHidden(netId, true); - } - synchronized (mWifiStateTracker) { - return WifiNative.enableNetworkCommand(netId, disableOthers); + String ifname = mWifiStateTracker.getInterfaceName(); + NetworkUtils.enableInterface(ifname); + boolean result = WifiNative.enableNetworkCommand(netId, disableOthers); + if (!result) { + NetworkUtils.disableInterface(ifname); + } + return result; } } @@ -1262,11 +1066,6 @@ public class WifiService extends IWifiManager.Stub { public boolean disableNetwork(int netId) { enforceChangePermission(); - /* - * If we have hidden networks, we may have to change the scan mode - */ - updateNetworkIfHidden(netId, false); - synchronized (mWifiStateTracker) { return WifiNative.disableNetworkCommand(netId); } @@ -1364,39 +1163,42 @@ public class WifiService extends IWifiManager.Stub { level = 0; } - // bssid is the hash key - scanResult = mScanResultCache.get(bssid); - if (scanResult != null) { - scanResult.level = level; - } else { - /* - * The formatting of the results returned by - * wpa_supplicant is intended to make the fields - * line up nicely when printed, - * not to make them easy to parse. So we have to - * apply some heuristics to figure out which field - * is the SSID and which field is the flags. - */ - String ssid; - String flags; - if (result.length == 4) { - if (result[3].charAt(0) == '[') { - flags = result[3]; - ssid = ""; - } else { - flags = ""; - ssid = result[3]; - } - } else if (result.length == 5) { + /* + * The formatting of the results returned by + * wpa_supplicant is intended to make the fields + * line up nicely when printed, + * not to make them easy to parse. So we have to + * apply some heuristics to figure out which field + * is the SSID and which field is the flags. + */ + String ssid; + String flags; + if (result.length == 4) { + if (result[3].charAt(0) == '[') { flags = result[3]; - ssid = result[4]; + ssid = ""; } else { - // Here, we must have 3 fields: no flags and ssid - // set flags = ""; - ssid = ""; + ssid = result[3]; } + } else if (result.length == 5) { + flags = result[3]; + ssid = result[4]; + } else { + // Here, we must have 3 fields: no flags and ssid + // set + flags = ""; + ssid = ""; + } + // bssid is the hash key + scanResult = mScanResultCache.get(bssid); + if (scanResult != null) { + scanResult.level = level; + scanResult.SSID = ssid; + scanResult.capabilities = flags; + scanResult.frequency = frequency; + } else { // Do not add scan results that have no SSID set if (0 < ssid.trim().length()) { scanResult = @@ -1468,14 +1270,17 @@ public class WifiService extends IWifiManager.Stub { * Set the number of radio frequency channels that are allowed to be used * 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 + * for some reason. If the operation is successful, the new value may be * persisted as a Secure setting. * @param numChannels the number of allowed channels. Must be greater than 0 * and less than or equal to 16. + * @param persist {@code true} if the setting should be remembered. * @return {@code true} if the operation succeeds, {@code false} otherwise, e.g., * {@code numChannels} is outside the valid range. */ - public boolean setNumAllowedChannels(int numChannels) { + public boolean setNumAllowedChannels(int numChannels, boolean persist) { + Log.i(TAG, "WifiService trying to setNumAllowed to "+numChannels+ + " with persist set to "+persist); enforceChangePermission(); /* * Validate the argument. We'd like to let the Wi-Fi driver do this, @@ -1494,9 +1299,11 @@ public class WifiService extends IWifiManager.Stub { return false; } - Settings.Secure.putInt(mContext.getContentResolver(), - Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS, - numChannels); + if (persist) { + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.WIFI_NUM_ALLOWED_CHANNELS, + numChannels); + } mWifiStateTracker.setNumAllowedChannels(numChannels); return true; } diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java index ad882a9..25aff5c 100644 --- a/services/java/com/android/server/WindowManagerService.java +++ b/services/java/com/android/server/WindowManagerService.java @@ -64,6 +64,7 @@ import android.os.Binder; import android.os.Debug; import android.os.Handler; import android.os.IBinder; +import android.os.LatencyTimer; import android.os.LocalPowerManager; import android.os.Looper; import android.os.Message; @@ -135,6 +136,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo static final boolean DEBUG_STARTING_WINDOW = false; static final boolean DEBUG_REORDER = false; static final boolean SHOW_TRANSACTIONS = false; + static final boolean MEASURE_LATENCY = false; + static private LatencyTimer lt; static final boolean PROFILE_ORIENTATION = false; static final boolean BLUR = true; @@ -509,6 +512,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo private WindowManagerService(Context context, PowerManagerService pm, boolean haveInputMethods) { + if (MEASURE_LATENCY) { + lt = new LatencyTimer(100, 1000); + } + mContext = context; mHaveInputMethods = haveInputMethods; mLimitedAlphaCompositing = context.getResources().getBoolean( @@ -3793,7 +3800,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo private final void wakeupIfNeeded(WindowState targetWin, int eventType) { long curTime = SystemClock.uptimeMillis(); - if (eventType == LONG_TOUCH_EVENT || eventType == CHEEK_EVENT) { + if (eventType == TOUCH_EVENT || eventType == LONG_TOUCH_EVENT || eventType == CHEEK_EVENT) { if (mLastTouchEventType == eventType && (curTime - mLastUserActivityCallTime) < MIN_TIME_BETWEEN_USERACTIVITIES) { return; @@ -3853,8 +3860,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo if (DEBUG_INPUT || WindowManagerPolicy.WATCH_POINTER) Log.v(TAG, "dispatchPointer " + ev); + if (MEASURE_LATENCY) { + lt.sample("3 Wait for last dispatch ", System.nanoTime() - qev.whenNano); + } + Object targetObj = mKeyWaiter.waitForNextEventTarget(null, qev, ev, true, false, pid, uid); + + if (MEASURE_LATENCY) { + lt.sample("3 Last dispatch finished ", System.nanoTime() - qev.whenNano); + } int action = ev.getAction(); @@ -3892,7 +3907,8 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo WindowState target = (WindowState)targetObj; final long eventTime = ev.getEventTime(); - + final long eventTimeNano = ev.getEventTimeNano(); + //Log.i(TAG, "Sending " + ev + " to " + target); if (uid != 0 && uid != target.mSession.mUid) { @@ -3909,6 +3925,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo return INJECT_NO_PERMISSION; } } + + if (MEASURE_LATENCY) { + lt.sample("4 in dispatchPointer ", System.nanoTime() - eventTimeNano); + } if ((target.mAttrs.flags & WindowManager.LayoutParams.FLAG_IGNORE_CHEEK_PRESSES) != 0) { @@ -3992,6 +4012,10 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } } + if (MEASURE_LATENCY) { + lt.sample("5 in dispatchPointer ", System.nanoTime() - eventTimeNano); + } + synchronized(mWindowMap) { if (qev != null && action == MotionEvent.ACTION_MOVE) { mKeyWaiter.bindTargetWindowLocked(target, @@ -4029,7 +4053,16 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo if (DEBUG_INPUT || DEBUG_FOCUS || WindowManagerPolicy.WATCH_POINTER) { Log.v(TAG, "Delivering pointer " + qev + " to " + target); } + + if (MEASURE_LATENCY) { + lt.sample("6 before svr->client ipc ", System.nanoTime() - eventTimeNano); + } + target.mClient.dispatchPointer(ev, eventTime); + + if (MEASURE_LATENCY) { + lt.sample("7 after svr->client ipc ", System.nanoTime() - eventTimeNano); + } return INJECT_SUCCEEDED; } catch (android.os.RemoteException e) { Log.i(TAG, "WINDOW DIED during motion dispatch: " + target); @@ -5198,7 +5231,7 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo } } } - }; + } public boolean detectSafeMode() { mSafeMode = mPolicy.detectSafeMode(); @@ -5263,9 +5296,13 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo if (DEBUG_INPUT && ev != null) Log.v( TAG, "Event: type=" + ev.classType + " data=" + ev.event); + if (MEASURE_LATENCY) { + lt.sample("2 got event ", System.nanoTime() - ev.whenNano); + } + try { if (ev != null) { - curTime = ev.when; + curTime = SystemClock.uptimeMillis(); int eventType; if (ev.classType == RawInputEvent.CLASS_TOUCHSCREEN) { eventType = eventType((MotionEvent)ev.event); @@ -5276,17 +5313,29 @@ public class WindowManagerService extends IWindowManager.Stub implements Watchdo eventType = LocalPowerManager.OTHER_EVENT; } try { - long now = SystemClock.uptimeMillis(); - - if ((now - mLastBatteryStatsCallTime) + if ((curTime - mLastBatteryStatsCallTime) >= MIN_TIME_BETWEEN_USERACTIVITIES) { - mLastBatteryStatsCallTime = now; + mLastBatteryStatsCallTime = curTime; mBatteryStats.noteInputEvent(); } } catch (RemoteException e) { // Ignore } - mPowerManager.userActivity(curTime, false, eventType, false); + + if (eventType != TOUCH_EVENT + && eventType != LONG_TOUCH_EVENT + && eventType != CHEEK_EVENT) { + mPowerManager.userActivity(curTime, false, + eventType, false); + } else if (mLastTouchEventType != eventType + || (curTime - mLastUserActivityCallTime) + >= MIN_TIME_BETWEEN_USERACTIVITIES) { + mLastUserActivityCallTime = curTime; + mLastTouchEventType = eventType; + mPowerManager.userActivity(curTime, false, + eventType, false); + } + switch (ev.classType) { case RawInputEvent.CLASS_KEYBOARD: KeyEvent ke = (KeyEvent)ev.event; diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 442e9ce..25991f2 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -319,6 +319,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // Memory pages are 4K. static final int PAGE_SIZE = 4*1024; + // System property defining error report receiver for system apps + static final String SYSTEM_APPS_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.system.apps"; + + // System property defining default error report receiver + static final String DEFAULT_ERROR_RECEIVER_PROPERTY = "ro.error.receiver.default"; + // Corresponding memory levels for above adjustments. final int EMPTY_APP_MEM; final int HIDDEN_APP_MEM; @@ -8084,27 +8090,62 @@ public final class ActivityManagerService extends ActivityManagerNative implemen private ComponentName getErrorReportReceiver(ProcessRecord app) { IPackageManager pm = ActivityThread.getPackageManager(); + try { - // was an installer package name specified when this app was - // installed? - String installerPackageName = pm.getInstallerPackageName(app.info.packageName); - if (installerPackageName == null) { - return null; + // look for receiver in the installer package + String candidate = pm.getInstallerPackageName(app.info.packageName); + ComponentName result = getErrorReportReceiver(pm, app.info.packageName, candidate); + if (result != null) { + return result; } - // is there an Activity in this package that handles ACTION_APP_ERROR? - Intent intent = new Intent(Intent.ACTION_APP_ERROR); - intent.setPackage(installerPackageName); - ResolveInfo info = pm.resolveIntent(intent, null, 0); - if (info == null || info.activityInfo == null) { - return null; + // if the error app is on the system image, look for system apps + // error receiver + if ((app.info.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { + candidate = SystemProperties.get(SYSTEM_APPS_ERROR_RECEIVER_PROPERTY); + result = getErrorReportReceiver(pm, app.info.packageName, candidate); + if (result != null) { + return result; + } } - return new ComponentName(installerPackageName, info.activityInfo.name); + // if there is a default receiver, try that + candidate = SystemProperties.get(DEFAULT_ERROR_RECEIVER_PROPERTY); + return getErrorReportReceiver(pm, app.info.packageName, candidate); } catch (RemoteException e) { - // will return null and no error report will be delivered + // should not happen + Log.e(TAG, "error talking to PackageManager", e); + return null; } - return null; + } + + /** + * Return activity in receiverPackage that handles ACTION_APP_ERROR. + * + * @param pm PackageManager isntance + * @param errorPackage package which caused the error + * @param receiverPackage candidate package to receive the error + * @return activity component within receiverPackage which handles + * ACTION_APP_ERROR, or null if not found + */ + private ComponentName getErrorReportReceiver(IPackageManager pm, String errorPackage, + String receiverPackage) throws RemoteException { + if (receiverPackage == null || receiverPackage.length() == 0) { + return null; + } + + // break the loop if it's the error report receiver package that crashed + if (receiverPackage.equals(errorPackage)) { + return null; + } + + Intent intent = new Intent(Intent.ACTION_APP_ERROR); + intent.setPackage(receiverPackage); + ResolveInfo info = pm.resolveIntent(intent, null, 0); + if (info == null || info.activityInfo == null) { + return null; + } + return new ComponentName(receiverPackage, info.activityInfo.name); } void makeAppNotRespondingLocked(ProcessRecord app, @@ -8426,6 +8467,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen report.crashInfo.throwFileName = trace.getFileName(); report.crashInfo.throwClassName = trace.getClassName(); report.crashInfo.throwMethodName = trace.getMethodName(); + report.crashInfo.throwLineNumber = trace.getLineNumber(); } else if (r.notResponding) { report.type = ApplicationErrorReport.TYPE_ANR; report.anrInfo = new ApplicationErrorReport.AnrInfo(); diff --git a/services/java/com/android/server/status/StatusBarPolicy.java b/services/java/com/android/server/status/StatusBarPolicy.java index 7a8d4e5..c8db95b 100644 --- a/services/java/com/android/server/status/StatusBarPolicy.java +++ b/services/java/com/android/server/status/StatusBarPolicy.java @@ -76,15 +76,8 @@ public class StatusBarPolicy { private static StatusBarPolicy sInstance; // message codes for the handler - private static final int EVENT_DATA_CONN_STATE_CHANGED = 2; - private static final int EVENT_DATA_ACTIVITY = 3; private static final int EVENT_BATTERY_CLOSE = 4; - // indices into mBatteryThresholds - private static final int BATTERY_THRESHOLD_CLOSE_WARNING = 0; - private static final int BATTERY_THRESHOLD_WARNING = 1; - private static final int BATTERY_THRESHOLD_EMPTY = 2; - private final Context mContext; private final StatusBarService mService; private final Handler mHandler = new StatusBarHandler(); @@ -99,16 +92,13 @@ public class StatusBarPolicy { private IBinder mBatteryIcon; private IconData mBatteryData; private boolean mBatteryFirst = true; - private int mBatteryPlugged; + private boolean mBatteryPlugged; private int mBatteryLevel; - private int mBatteryThreshold = 0; // index into mBatteryThresholds - private int[] mBatteryThresholds = new int[] { 20, 15, -1 }; private AlertDialog mLowBatteryDialog; private TextView mBatteryLevelTextView; private View mBatteryView; private int mBatteryViewSequence; private boolean mBatteryShowLowOnEndCall = false; - private boolean mSentLowBatteryBroadcast = false; private static final boolean SHOW_LOW_BATTERY_WARNING = true; // phone @@ -363,6 +353,9 @@ public class StatusBarPolicy { else if (action.equals(Intent.ACTION_TIME_CHANGED)) { updateClock(); } + else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { + updateBattery(intent); + } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) { updateClock(); } @@ -377,8 +370,11 @@ public class StatusBarPolicy { else if (action.equals(Intent.ACTION_SYNC_STATE_CHANGED)) { updateSyncState(intent); } - else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { - updateBattery(intent); + else if (action.equals(Intent.ACTION_BATTERY_LOW)) { + onBatteryLow(intent); + } + else if (action.equals(Intent.ACTION_BATTERY_OKAY)) { + onBatteryOkay(intent); } else if (action.equals(BluetoothIntent.BLUETOOTH_STATE_CHANGED_ACTION) || action.equals(BluetoothIntent.HEADSET_STATE_CHANGED_ACTION) || @@ -521,6 +517,8 @@ public class StatusBarPolicy { filter.addAction(Intent.ACTION_TIME_CHANGED); filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); filter.addAction(Intent.ACTION_BATTERY_CHANGED); + filter.addAction(Intent.ACTION_BATTERY_LOW); + filter.addAction(Intent.ACTION_BATTERY_OKAY); filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); filter.addAction(Intent.ACTION_ALARM_CHANGED); filter.addAction(Intent.ACTION_SYNC_STATE_CHANGED); @@ -564,38 +562,22 @@ public class StatusBarPolicy { //mService.setIconVisibility(mSyncFailingIcon, isFailing && !isActive); } - private void pickNextBatteryLevel(int level) { - final int N = mBatteryThresholds.length; - for (int i=0; i<N; i++) { - if (level >= mBatteryThresholds[i]) { - mBatteryThreshold = i; - break; - } - } - if (mBatteryThreshold >= N) { - mBatteryThreshold = N-1; - } - } - private final void updateBattery(Intent intent) { mBatteryData.iconId = intent.getIntExtra("icon-small", 0); mBatteryData.iconLevel = intent.getIntExtra("level", 0); mService.updateIcon(mBatteryIcon, mBatteryData, null); - int plugged = intent.getIntExtra("plugged", 0); + boolean plugged = intent.getIntExtra("plugged", 0) != 0; int level = intent.getIntExtra("level", -1); if (false) { Log.d(TAG, "updateBattery level=" + level + " plugged=" + plugged + " mBatteryPlugged=" + mBatteryPlugged + " mBatteryLevel=" + mBatteryLevel - + " mBatteryThreshold=" + mBatteryThreshold + " mBatteryFirst=" + mBatteryFirst); } - int oldPlugged = mBatteryPlugged; - int oldThreshold = mBatteryThreshold; - pickNextBatteryLevel(level); + boolean oldPlugged = mBatteryPlugged; mBatteryPlugged = plugged; mBatteryLevel = level; @@ -617,44 +599,34 @@ public class StatusBarPolicy { } */ if (false) { - Log.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level - + " mBatteryThreshold=" + mBatteryThreshold + " oldThreshold=" + oldThreshold); + Log.d(TAG, "plugged=" + plugged + " oldPlugged=" + oldPlugged + " level=" + level); } - if (plugged == 0 - && ((oldPlugged != 0 && level < mBatteryThresholds[BATTERY_THRESHOLD_WARNING]) - || (mBatteryThreshold > oldThreshold - && mBatteryThreshold > BATTERY_THRESHOLD_WARNING))) { - // Broadcast the low battery warning - mSentLowBatteryBroadcast = true; - mContext.sendBroadcast(new Intent(Intent.ACTION_BATTERY_LOW)); - - if (SHOW_LOW_BATTERY_WARNING) { - if (false) { - Log.d(TAG, "mPhoneState=" + mPhoneState - + " mLowBatteryDialog=" + mLowBatteryDialog - + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall); - } + } - if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) { - showLowBatteryWarning(); - } else { - mBatteryShowLowOnEndCall = true; - } + private void onBatteryLow(Intent intent) { + if (SHOW_LOW_BATTERY_WARNING) { + if (false) { + Log.d(TAG, "mPhoneState=" + mPhoneState + + " mLowBatteryDialog=" + mLowBatteryDialog + + " mBatteryShowLowOnEndCall=" + mBatteryShowLowOnEndCall); } - } else if (mBatteryThreshold < BATTERY_THRESHOLD_WARNING) { - if (mSentLowBatteryBroadcast == true) { - mSentLowBatteryBroadcast = false; - mContext.sendBroadcast(new Intent(Intent.ACTION_BATTERY_OKAY)); - } - if (SHOW_LOW_BATTERY_WARNING) { - if (mLowBatteryDialog != null) { - mLowBatteryDialog.dismiss(); - mBatteryShowLowOnEndCall = false; - } + + if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) { + showLowBatteryWarning(); + } else { + mBatteryShowLowOnEndCall = true; } } } + private void onBatteryOkay(Intent intent) { + if (mLowBatteryDialog != null + && SHOW_LOW_BATTERY_WARNING) { + mLowBatteryDialog.dismiss(); + mBatteryShowLowOnEndCall = false; + } + } + private void showBatteryView() { closeLastBatteryView(); if (mLowBatteryDialog != null) { @@ -716,9 +688,11 @@ public class StatusBarPolicy { private void showLowBatteryWarning() { closeLastBatteryView(); - int level = mBatteryThresholds[mBatteryThreshold > 1 ? mBatteryThreshold - 1 : 0]; + /* Show exact battery level. + * Add 1 because the text says "less than X%". + */ CharSequence levelText = mContext.getString( - com.android.internal.R.string.battery_low_percent_format, level); + com.android.internal.R.string.battery_low_percent_format, mBatteryLevel + 1); if (mBatteryLevelTextView != null) { mBatteryLevelTextView.setText(levelText); @@ -769,7 +743,7 @@ public class StatusBarPolicy { } if (mPhoneState == TelephonyManager.CALL_STATE_IDLE) { if (mBatteryShowLowOnEndCall) { - if (mBatteryPlugged == 0) { + if (!mBatteryPlugged) { showLowBatteryWarning(); } mBatteryShowLowOnEndCall = false; |