diff options
Diffstat (limited to 'services')
32 files changed, 1237 insertions, 865 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 941c9c8..744fa50 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -522,6 +522,11 @@ uint32_t AudioFlinger::latency(int output) const status_t AudioFlinger::setMasterVolume(float value) { + status_t ret = initCheck(); + if (ret != NO_ERROR) { + return ret; + } + // check calling permissions if (!settingsAllowed()) { return PERMISSION_DENIED; @@ -547,7 +552,10 @@ status_t AudioFlinger::setMasterVolume(float value) status_t AudioFlinger::setMode(int mode) { - status_t ret; + status_t ret = initCheck(); + if (ret != NO_ERROR) { + return ret; + } // check calling permissions if (!settingsAllowed()) { @@ -577,6 +585,11 @@ status_t AudioFlinger::setMode(int mode) status_t AudioFlinger::setMicMute(bool state) { + status_t ret = initCheck(); + if (ret != NO_ERROR) { + return ret; + } + // check calling permissions if (!settingsAllowed()) { return PERMISSION_DENIED; @@ -584,13 +597,18 @@ status_t AudioFlinger::setMicMute(bool state) AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_HW_SET_MIC_MUTE; - status_t ret = mPrimaryHardwareDev->set_mic_mute(mPrimaryHardwareDev, state); + ret = mPrimaryHardwareDev->set_mic_mute(mPrimaryHardwareDev, state); mHardwareStatus = AUDIO_HW_IDLE; return ret; } bool AudioFlinger::getMicMute() const { + status_t ret = initCheck(); + if (ret != NO_ERROR) { + return false; + } + bool state = AUDIO_MODE_INVALID; mHardwareStatus = AUDIO_HW_GET_MIC_MUTE; mPrimaryHardwareDev->get_mic_mute(mPrimaryHardwareDev, &state); @@ -814,6 +832,11 @@ String8 AudioFlinger::getParameters(int ioHandle, const String8& keys) size_t AudioFlinger::getInputBufferSize(uint32_t sampleRate, int format, int channelCount) { + status_t ret = initCheck(); + if (ret != NO_ERROR) { + return 0; + } + return mPrimaryHardwareDev->get_input_buffer_size(mPrimaryHardwareDev, sampleRate, format, channelCount); } @@ -834,6 +857,11 @@ unsigned int AudioFlinger::getInputFramesLost(int ioHandle) status_t AudioFlinger::setVoiceVolume(float value) { + status_t ret = initCheck(); + if (ret != NO_ERROR) { + return ret; + } + // check calling permissions if (!settingsAllowed()) { return PERMISSION_DENIED; @@ -841,7 +869,7 @@ status_t AudioFlinger::setVoiceVolume(float value) AutoMutex lock(mHardwareLock); mHardwareStatus = AUDIO_SET_VOICE_VOLUME; - status_t ret = mPrimaryHardwareDev->set_voice_volume(mPrimaryHardwareDev, value); + ret = mPrimaryHardwareDev->set_voice_volume(mPrimaryHardwareDev, value); mHardwareStatus = AUDIO_HW_IDLE; return ret; diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp index f6ce44c..cf167ae 100644 --- a/services/input/InputDispatcher.cpp +++ b/services/input/InputDispatcher.cpp @@ -1831,8 +1831,8 @@ void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget, bool resumeWithAppendedMotionSample) { #if DEBUG_DISPATCH_CYCLE - LOGD("channel '%s' ~ prepareDispatchCycle - flags=%d, " - "xOffset=%f, yOffset=%f, scaleFactor=%f" + LOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, " + "xOffset=%f, yOffset=%f, scaleFactor=%f, " "pointerIds=0x%x, " "resumeWithAppendedMotionSample=%s", connection->getInputChannelName(), inputTarget->flags, diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp index 40c85fc..bfcf8e0 100644 --- a/services/input/InputReader.cpp +++ b/services/input/InputReader.cpp @@ -1220,6 +1220,9 @@ void TouchButtonAccumulator::reset(InputDevice* device) { mBtnToolAirbrush = device->isKeyPressed(BTN_TOOL_AIRBRUSH); mBtnToolMouse = device->isKeyPressed(BTN_TOOL_MOUSE); mBtnToolLens = device->isKeyPressed(BTN_TOOL_LENS); + mBtnToolDoubleTap = device->isKeyPressed(BTN_TOOL_DOUBLETAP); + mBtnToolTripleTap = device->isKeyPressed(BTN_TOOL_TRIPLETAP); + mBtnToolQuadTap = device->isKeyPressed(BTN_TOOL_QUADTAP); } void TouchButtonAccumulator::clearButtons() { @@ -1234,6 +1237,9 @@ void TouchButtonAccumulator::clearButtons() { mBtnToolAirbrush = 0; mBtnToolMouse = 0; mBtnToolLens = 0; + mBtnToolDoubleTap = 0; + mBtnToolTripleTap = 0; + mBtnToolQuadTap = 0; } void TouchButtonAccumulator::process(const RawEvent* rawEvent) { @@ -1272,6 +1278,15 @@ void TouchButtonAccumulator::process(const RawEvent* rawEvent) { case BTN_TOOL_LENS: mBtnToolLens = rawEvent->value; break; + case BTN_TOOL_DOUBLETAP: + mBtnToolDoubleTap = rawEvent->value; + break; + case BTN_TOOL_TRIPLETAP: + mBtnToolTripleTap = rawEvent->value; + break; + case BTN_TOOL_QUADTAP: + mBtnToolQuadTap = rawEvent->value; + break; } } } @@ -1297,7 +1312,7 @@ int32_t TouchButtonAccumulator::getToolType() const { if (mBtnToolPen || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush) { return AMOTION_EVENT_TOOL_TYPE_STYLUS; } - if (mBtnToolFinger) { + if (mBtnToolFinger || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap) { return AMOTION_EVENT_TOOL_TYPE_FINGER; } return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; @@ -1306,7 +1321,8 @@ int32_t TouchButtonAccumulator::getToolType() const { bool TouchButtonAccumulator::isToolActive() const { return mBtnTouch || mBtnToolFinger || mBtnToolPen || mBtnToolRubber || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush - || mBtnToolMouse || mBtnToolLens; + || mBtnToolMouse || mBtnToolLens + || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap; } bool TouchButtonAccumulator::isHovering() const { @@ -2172,6 +2188,7 @@ void CursorInputMapper::sync(nsecs_t when) { } nsecs_t downTime = mDownTime; bool buttonsChanged = currentButtonState != lastButtonState; + bool buttonsPressed = currentButtonState & ~lastButtonState; float deltaX = mCursorMotionAccumulator.getRelativeX() * mXScale; float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale; @@ -2233,7 +2250,7 @@ void CursorInputMapper::sync(nsecs_t when) { // the device in your pocket. // TODO: Use the input device configuration to control this behavior more finely. uint32_t policyFlags = 0; - if (getDevice()->isExternal()) { + if ((buttonsPressed || moved || scrolled) && getDevice()->isExternal()) { policyFlags |= POLICY_FLAG_WAKE_DROPPED; } @@ -3329,9 +3346,12 @@ void TouchInputMapper::sync(nsecs_t when) { // Handle policy on initial down or hover events. uint32_t policyFlags = 0; - if (mLastRawPointerData.pointerCount == 0 && mCurrentRawPointerData.pointerCount != 0) { + bool initialDown = mLastRawPointerData.pointerCount == 0 + && mCurrentRawPointerData.pointerCount != 0; + bool buttonsPressed = mCurrentButtonState & ~mLastButtonState; + if (initialDown || buttonsPressed) { + // If this is a touch screen, hide the pointer on an initial down. if (mDeviceMode == DEVICE_MODE_DIRECT) { - // If this is a touch screen, hide the pointer on an initial down. getContext()->fadePointer(); } diff --git a/services/input/InputReader.h b/services/input/InputReader.h index 76d77f1..bad96df 100644 --- a/services/input/InputReader.h +++ b/services/input/InputReader.h @@ -596,6 +596,9 @@ private: bool mBtnToolAirbrush; bool mBtnToolMouse; bool mBtnToolLens; + bool mBtnToolDoubleTap; + bool mBtnToolTripleTap; + bool mBtnToolQuadTap; void clearButtons(); }; diff --git a/services/input/tests/InputReader_test.cpp b/services/input/tests/InputReader_test.cpp index 4796958..32f948b 100644 --- a/services/input/tests/InputReader_test.cpp +++ b/services/input/tests/InputReader_test.cpp @@ -3377,8 +3377,32 @@ TEST_F(SingleTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); - // finger + // double-tap processKey(mapper, BTN_TOOL_LENS, 0); + processKey(mapper, BTN_TOOL_DOUBLETAP, 1); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + + // triple-tap + processKey(mapper, BTN_TOOL_DOUBLETAP, 0); + processKey(mapper, BTN_TOOL_TRIPLETAP, 1); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + + // quad-tap + processKey(mapper, BTN_TOOL_TRIPLETAP, 0); + processKey(mapper, BTN_TOOL_QUADTAP, 1); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + + // finger + processKey(mapper, BTN_TOOL_QUADTAP, 0); processKey(mapper, BTN_TOOL_FINGER, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); @@ -4766,8 +4790,32 @@ TEST_F(MultiTouchInputMapperTest, Process_ShouldHandleAllToolTypes) { ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_MOUSE, motionArgs.pointerProperties[0].toolType); - // finger + // double-tap processKey(mapper, BTN_TOOL_LENS, 0); + processKey(mapper, BTN_TOOL_DOUBLETAP, 1); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + + // triple-tap + processKey(mapper, BTN_TOOL_DOUBLETAP, 0); + processKey(mapper, BTN_TOOL_TRIPLETAP, 1); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + + // quad-tap + processKey(mapper, BTN_TOOL_TRIPLETAP, 0); + processKey(mapper, BTN_TOOL_QUADTAP, 1); + processSync(mapper); + ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); + ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, motionArgs.action); + ASSERT_EQ(AMOTION_EVENT_TOOL_TYPE_FINGER, motionArgs.pointerProperties[0].toolType); + + // finger + processKey(mapper, BTN_TOOL_QUADTAP, 0); processKey(mapper, BTN_TOOL_FINGER, 1); processSync(mapper); ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyMotionWasCalled(&motionArgs)); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 1341dd4..bfca851 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -72,7 +72,6 @@ import com.android.internal.net.VpnConfig; import com.android.internal.telephony.Phone; import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Vpn; - import com.google.android.collect.Lists; import com.google.android.collect.Sets; @@ -89,7 +88,6 @@ import java.util.Collection; import java.util.GregorianCalendar; import java.util.HashSet; import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; /** * @hide @@ -251,6 +249,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final int EVENT_SEND_STICKY_BROADCAST_INTENT = MAX_NETWORK_STATE_TRACKER_EVENT + 12; + /** + * Used internally to + * {@link NetworkStateTracker#setPolicyDataEnable(boolean)}. + */ + private static final int EVENT_SET_POLICY_DATA_ENABLE = MAX_NETWORK_STATE_TRACKER_EVENT + 13; + private Handler mHandler; // list of DeathRecipients used to make sure features are turned off when @@ -1282,7 +1286,25 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (VDBG) { log(mNetTrackers[ConnectivityManager.TYPE_MOBILE].toString() + enabled); } - mNetTrackers[ConnectivityManager.TYPE_MOBILE].setDataEnable(enabled); + mNetTrackers[ConnectivityManager.TYPE_MOBILE].setUserDataEnable(enabled); + } + } + + @Override + public void setPolicyDataEnable(int networkType, boolean enabled) { + // only someone like NPMS should only be calling us + mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); + + mHandler.sendMessage(mHandler.obtainMessage( + EVENT_SET_POLICY_DATA_ENABLE, networkType, (enabled ? ENABLED : DISABLED))); + } + + private void handleSetPolicyDataEnable(int networkType, boolean enabled) { + if (isNetworkTypeValid(networkType)) { + final NetworkStateTracker tracker = mNetTrackers[networkType]; + if (tracker != null) { + tracker.setPolicyDataEnable(enabled); + } } } @@ -2263,6 +2285,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { sendStickyBroadcast(intent); break; } + case EVENT_SET_POLICY_DATA_ENABLE: { + final int networkType = msg.arg1; + final boolean enabled = msg.arg2 == ENABLED; + handleSetPolicyDataEnable(networkType, enabled); + } } } } diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java index d549308..f1b8bae 100644 --- a/services/java/com/android/server/DevicePolicyManagerService.java +++ b/services/java/com/android/server/DevicePolicyManagerService.java @@ -1556,13 +1556,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return false; } } - - LockPatternUtils utils = new LockPatternUtils(mContext); - if(utils.checkPasswordHistory(password)) { - Slog.w(TAG, "resetPassword: password is the same as one of the last " - + getPasswordHistoryLength(null) + " passwords"); - return false; - } } int callingUid = Binder.getCallingUid(); diff --git a/services/java/com/android/server/DropBoxManagerService.java b/services/java/com/android/server/DropBoxManagerService.java index 5c878c9..d37c9ab 100644 --- a/services/java/com/android/server/DropBoxManagerService.java +++ b/services/java/com/android/server/DropBoxManagerService.java @@ -28,7 +28,6 @@ import android.os.Debug; import android.os.DropBoxManager; import android.os.FileUtils; import android.os.Handler; -import android.os.ParcelFileDescriptor; import android.os.StatFs; import android.os.SystemClock; import android.provider.Settings; @@ -45,14 +44,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; -import java.io.OutputStreamWriter; import java.io.PrintWriter; -import java.io.UnsupportedEncodingException; import java.util.ArrayList; -import java.util.Comparator; import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; import java.util.SortedSet; import java.util.TreeSet; import java.util.zip.GZIPOutputStream; diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index 73d790a..c11755b 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -1,5 +1,4 @@ /* - * Copyright (C) 2006-2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of @@ -48,7 +47,6 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; @@ -57,7 +55,6 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.database.ContentObserver; -import android.graphics.BitmapFactory; import android.inputmethodservice.InputMethodService; import android.os.Binder; import android.os.Environment; @@ -98,12 +95,10 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Set; import java.util.TreeMap; /** @@ -147,7 +142,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub final Handler mHandler; final InputMethodSettings mSettings; final SettingsObserver mSettingsObserver; - final StatusBarManagerService mStatusBar; final IWindowManager mIWindowManager; final HandlerCaller mCaller; private final InputMethodFileManager mFileManager; @@ -162,10 +156,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub new LruCache<SuggestionSpan, InputMethodInfo>(SECURE_SUGGESTION_SPANS_MAX_SIZE); // Ongoing notification - private final NotificationManager mNotificationManager; - private final KeyguardManager mKeyguardManager; - private final Notification mImeSwitcherNotification; - private final PendingIntent mImeSwitchPendingIntent; + private NotificationManager mNotificationManager; + private KeyguardManager mKeyguardManager; + private StatusBarManagerService mStatusBar; + private Notification mImeSwitcherNotification; + private PendingIntent mImeSwitchPendingIntent; private boolean mShowOngoingImeSwitcherForPhones; private boolean mNotificationShown; @@ -469,8 +464,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // Pick another one... Slog.i(TAG, "Current input method removed: " + curInputMethodId); mImeWindowVis = 0; - mStatusBar.setImeWindowStatus(mCurToken, mImeWindowVis, - mBackDisposition); + updateImeWindowStatusLocked(); if (!chooseNewDefaultIMELocked()) { changed = true; curIm = null; @@ -511,7 +505,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } - public InputMethodManagerService(Context context, StatusBarManagerService statusBar) { + public InputMethodManagerService(Context context) { mContext = context; mRes = context.getResources(); mHandler = new Handler(this); @@ -524,10 +518,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } }); - mKeyguardManager = (KeyguardManager) - mContext.getSystemService(Context.KEYGUARD_SERVICE); - mNotificationManager = (NotificationManager) - mContext.getSystemService(Context.NOTIFICATION_SERVICE); mImeSwitcherNotification = new Notification(); mImeSwitcherNotification.icon = com.android.internal.R.drawable.ic_notification_ime_default; mImeSwitcherNotification.when = 0; @@ -553,8 +543,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub screenOnOffFilt.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); mContext.registerReceiver(new ScreenOnOffReceiver(), screenOnOffFilt); - mStatusBar = statusBar; - statusBar.setIconVisibility("ime", false); mNotificationShown = false; // mSettings should be created before buildInputMethodListLocked @@ -608,10 +596,17 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } - public void systemReady() { + public void systemReady(StatusBarManagerService statusBar) { synchronized (mMethodMap) { if (!mSystemReady) { mSystemReady = true; + mKeyguardManager = (KeyguardManager) + mContext.getSystemService(Context.KEYGUARD_SERVICE); + mNotificationManager = (NotificationManager) + mContext.getSystemService(Context.NOTIFICATION_SERVICE); + mStatusBar = statusBar; + statusBar.setIconVisibility("ime", false); + updateImeWindowStatusLocked(); mShowOngoingImeSwitcherForPhones = mRes.getBoolean( com.android.internal.R.bool.show_ongoing_ime_switcher); try { @@ -623,6 +618,10 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } + void updateImeWindowStatusLocked() { + setImeWindowStatus(mCurToken, mImeWindowVis, mBackDisposition); + } + @Override public List<InputMethodInfo> getInputMethodList() { synchronized (mMethodMap) { @@ -993,6 +992,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub sessionState.session.finishSession(); } catch (RemoteException e) { Slog.w(TAG, "Session failed to close due to remote exception", e); + mImeWindowVis = 0; + updateImeWindowStatusLocked(); } } } @@ -1009,7 +1010,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mEnabledSession = null; mCurMethod = null; } - mStatusBar.setIconVisibility("ime", false); + if (mStatusBar != null) { + mStatusBar.setIconVisibility("ime", false); + } } @Override @@ -1046,7 +1049,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub synchronized (mMethodMap) { if (iconId == 0) { if (DEBUG) Slog.d(TAG, "hide the small icon for the input method"); - mStatusBar.setIconVisibility("ime", false); + if (mStatusBar != null) { + mStatusBar.setIconVisibility("ime", false); + } } else if (packageName != null) { if (DEBUG) Slog.d(TAG, "show a small icon for the input method"); CharSequence contentDescription = null; @@ -1057,9 +1062,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } catch (NameNotFoundException nnfe) { /* ignore */ } - mStatusBar.setIcon("ime", packageName, iconId, 0, - contentDescription != null ? contentDescription.toString() : null); - mStatusBar.setIconVisibility("ime", true); + if (mStatusBar != null) { + mStatusBar.setIcon("ime", packageName, iconId, 0, + contentDescription != null + ? contentDescription.toString() : null); + mStatusBar.setIconVisibility("ime", true); + } } } } finally { @@ -1112,6 +1120,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } } + @SuppressWarnings("deprecation") @Override public void setImeWindowStatus(IBinder token, int vis, int backDisposition) { int uid = Binder.getCallingUid(); @@ -1125,7 +1134,9 @@ public class InputMethodManagerService extends IInputMethodManager.Stub synchronized (mMethodMap) { mImeWindowVis = vis; mBackDisposition = backDisposition; - mStatusBar.setImeWindowStatus(token, vis, backDisposition); + if (mStatusBar != null) { + mStatusBar.setImeWindowStatus(token, vis, backDisposition); + } final boolean iconVisibility = (vis & InputMethodService.IME_ACTIVE) != 0; final InputMethodInfo imi = mMethodMap.get(mCurMethodId); if (imi != null && iconVisibility && needsToShowImeSwitchOngoingNotification()) { @@ -1142,12 +1153,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mImeSwitcherNotification.setLatestEventInfo( mContext, title, summary, mImeSwitchPendingIntent); - mNotificationManager.notify( - com.android.internal.R.string.select_input_method, - mImeSwitcherNotification); - mNotificationShown = true; + if (mNotificationManager != null) { + mNotificationManager.notify( + com.android.internal.R.string.select_input_method, + mImeSwitcherNotification); + mNotificationShown = true; + } } else { - if (mNotificationShown) { + if (mNotificationShown && mNotificationManager != null) { mNotificationManager.cancel( com.android.internal.R.string.select_input_method); mNotificationShown = false; @@ -1252,8 +1265,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mImeWindowVis = (mInputShown || hardKeyShown) ? ( InputMethodService.IME_ACTIVE | InputMethodService.IME_VISIBLE) : 0; - mStatusBar.setImeWindowStatus(mCurToken, mImeWindowVis, - mBackDisposition); + updateImeWindowStatusLocked(); // If subtype is null, try to find the most applicable one from // getCurrentInputMethodSubtype. if (subtype == null) { @@ -1374,13 +1386,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (DEBUG) Slog.w(TAG, "Ignoring hideSoftInput of uid " + uid + ": " + client); mImeWindowVis = 0; - mStatusBar.setImeWindowStatus(mCurToken, mImeWindowVis, - mBackDisposition); + updateImeWindowStatusLocked(); return false; } } catch (RemoteException e) { mImeWindowVis = 0; - mStatusBar.setImeWindowStatus(mCurToken, mImeWindowVis, mBackDisposition); + updateImeWindowStatusLocked(); return false; } } @@ -2151,7 +2162,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } }); - if (showSubtypes && !(mKeyguardManager.isKeyguardLocked() + if (showSubtypes && mKeyguardManager != null && !(mKeyguardManager.isKeyguardLocked() && mKeyguardManager.isKeyguardSecure())) { mDialogBuilder.setPositiveButton( com.android.internal.R.string.configure_input_methods, @@ -2580,6 +2591,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } // TODO: We should change the return type from List to List<Parcelable> + @SuppressWarnings("rawtypes") @Override public List getShortcutInputMethodsAndSubtypes() { synchronized (mMethodMap) { diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index 6edb132..7a3a344 100755 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -101,13 +101,8 @@ public class NotificationManagerService extends INotificationManager.Stub private Vibrator mVibrator = new Vibrator(); // for enabling and disabling notification pulse behavior - private boolean mScreenOn = true; private boolean mInCall = false; private boolean mNotificationPulseEnabled; - // This is true if we have received a new notification while the screen is off - // (that is, if mLedNotification was set while the screen was off) - // This is reset to false when the screen is turned on. - private boolean mPendingPulseNotification; private final ArrayList<NotificationRecord> mNotificationList = new ArrayList<NotificationRecord>(); @@ -349,12 +344,6 @@ public class NotificationManagerService extends INotificationManager.Stub cancelAllNotificationsInt(pkgName, 0, 0, !queryRestart); } } - } else if (action.equals(Intent.ACTION_SCREEN_ON)) { - mScreenOn = true; - updateNotificationPulse(); - } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { - mScreenOn = false; - updateNotificationPulse(); } else if (action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) { mInCall = (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_OFFHOOK)); updateNotificationPulse(); @@ -1059,11 +1048,6 @@ public class NotificationManagerService extends INotificationManager.Stub // lock on mNotificationList private void updateLightsLocked() { - // clear pending pulse notification if screen is on - if (mScreenOn || mLedNotification == null) { - mPendingPulseNotification = false; - } - // handle notification lights if (mLedNotification == null) { // get next notification, if any @@ -1071,14 +1055,10 @@ public class NotificationManagerService extends INotificationManager.Stub if (n > 0) { mLedNotification = mLights.get(n-1); } - if (mLedNotification != null && !mScreenOn) { - mPendingPulseNotification = true; - } } - // we only flash if screen is off and persistent pulsing is enabled - // and we are not currently in a call - if (!mPendingPulseNotification || mScreenOn || mInCall) { + // Don't flash while we are in a call + if (mLedNotification == null || mInCall) { mNotificationLight.turnOff(); } else { int ledARGB = mLedNotification.notification.ledARGB; diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java index d80a2cd..cbd986f 100644 --- a/services/java/com/android/server/PowerManagerService.java +++ b/services/java/com/android/server/PowerManagerService.java @@ -161,6 +161,7 @@ public class PowerManagerService extends IPowerManager.Stub private int mStayOnConditions = 0; private final int[] mBroadcastQueue = new int[] { -1, -1, -1 }; private final int[] mBroadcastWhy = new int[3]; + private boolean mBroadcastingScreenOff = false; private int mPartialCount = 0; private int mPowerState; // mScreenOffReason can be WindowManagerPolicy.OFF_BECAUSE_OF_USER, @@ -1342,6 +1343,10 @@ public class PowerManagerService extends IPowerManager.Stub mBroadcastWakeLock.release(); } + // The broadcast queue has changed; make sure the screen is on if it + // is now possible for it to be. + updateNativePowerStateLocked(); + // Now send the message. if (index >= 0) { // Acquire the broadcast wake lock before changing the power @@ -1370,6 +1375,9 @@ public class PowerManagerService extends IPowerManager.Stub mBroadcastWhy[i] = mBroadcastWhy[i+1]; } policy = getPolicyLocked(); + if (value == 0) { + mBroadcastingScreenOff = true; + } } if (value == 1) { mScreenOnStart = SystemClock.uptimeMillis(); @@ -1412,6 +1420,8 @@ public class PowerManagerService extends IPowerManager.Stub synchronized (mLocks) { EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, mBroadcastWakeLock.mCount); + mBroadcastingScreenOff = false; + updateNativePowerStateLocked(); mBroadcastWakeLock.release(); } } @@ -1442,6 +1452,10 @@ public class PowerManagerService extends IPowerManager.Stub synchronized (mLocks) { EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_DONE, 0, SystemClock.uptimeMillis() - mScreenOffStart, mBroadcastWakeLock.mCount); + synchronized (mLocks) { + mBroadcastingScreenOff = false; + updateNativePowerStateLocked(); + } mBroadcastWakeLock.release(); } } @@ -1768,6 +1782,22 @@ public class PowerManagerService extends IPowerManager.Stub } private void updateNativePowerStateLocked() { + if ((mPowerState & SCREEN_ON_BIT) != 0) { + // Don't turn screen on if we are currently reporting a screen off. + // This is to avoid letting the screen go on before things like the + // lock screen have been displayed due to it going off. + if (mBroadcastingScreenOff) { + // Currently broadcasting that the screen is off. Don't + // allow screen to go on until that is done. + return; + } + for (int i=0; i<mBroadcastQueue.length; i++) { + if (mBroadcastQueue[i] == 0) { + // A screen off is currently enqueued. + return; + } + } + } nativeSetPowerState( (mPowerState & SCREEN_ON_BIT) != 0, (mPowerState & SCREEN_BRIGHT) == SCREEN_BRIGHT); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 5dd3c5b..e6f92a5 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -40,6 +40,7 @@ import android.server.BluetoothService; import android.server.search.SearchManagerService; import android.util.DisplayMetrics; import android.util.EventLog; +import android.util.Log; import android.util.Slog; import android.view.WindowManager; @@ -66,6 +67,11 @@ class ServerThread extends Thread { ContentResolver mContentResolver; + void reportWtf(String msg, Throwable e) { + Slog.w(TAG, "***********************************************"); + Log.wtf(TAG, "BOOT FAILURE " + msg, e); + } + @Override public void run() { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, @@ -116,7 +122,6 @@ class ServerThread extends Thread { WindowManagerService wm = null; BluetoothService bluetooth = null; BluetoothA2dpService bluetoothA2dp = null; - WiredAccessoryObserver wiredAccessory = null; DockObserver dock = null; UsbService usb = null; UiModeManagerService uiMode = null; @@ -222,7 +227,8 @@ class ServerThread extends Thread { } } catch (RuntimeException e) { - Slog.e("System", "Failure starting core service", e); + Slog.e("System", "******************************************"); + Slog.e("System", "************ Failure starting core service", e); } DevicePolicyManagerService devicePolicy = null; @@ -235,13 +241,52 @@ class ServerThread extends Thread { CountryDetectorService countryDetector = null; TextServicesManagerService tsms = null; + // Bring up services needed for UI. + if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { + try { + Slog.i(TAG, "Input Method Service"); + imm = new InputMethodManagerService(context); + ServiceManager.addService(Context.INPUT_METHOD_SERVICE, imm); + } catch (Throwable e) { + reportWtf("starting Input Manager Service", e); + } + + try { + Slog.i(TAG, "Accessibility Manager"); + ServiceManager.addService(Context.ACCESSIBILITY_SERVICE, + new AccessibilityManagerService(context)); + } catch (Throwable e) { + reportWtf("starting Accessibility Manager", e); + } + } + + try { + wm.displayReady(); + } catch (Throwable e) { + reportWtf("making display ready", e); + } + + try { + pm.performBootDexOpt(); + } catch (Throwable e) { + reportWtf("performing boot dexopt", e); + } + + try { + ActivityManagerNative.getDefault().showBootMessage( + context.getResources().getText( + com.android.internal.R.string.android_upgrading_starting_apps), + false); + } catch (RemoteException e) { + } + if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) { try { Slog.i(TAG, "Device Policy"); devicePolicy = new DevicePolicyManagerService(context); ServiceManager.addService(Context.DEVICE_POLICY_SERVICE, devicePolicy); } catch (Throwable e) { - Slog.e(TAG, "Failure starting DevicePolicyService", e); + reportWtf("starting DevicePolicyService", e); } try { @@ -249,7 +294,7 @@ class ServerThread extends Thread { statusBar = new StatusBarManagerService(context, wm); ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar); } catch (Throwable e) { - Slog.e(TAG, "Failure starting StatusBarManagerService", e); + reportWtf("starting StatusBarManagerService", e); } try { @@ -257,15 +302,7 @@ class ServerThread extends Thread { ServiceManager.addService(Context.CLIPBOARD_SERVICE, new ClipboardService(context)); } catch (Throwable e) { - Slog.e(TAG, "Failure starting Clipboard Service", e); - } - - try { - Slog.i(TAG, "Input Method Service"); - imm = new InputMethodManagerService(context, statusBar); - ServiceManager.addService(Context.INPUT_METHOD_SERVICE, imm); - } catch (Throwable e) { - Slog.e(TAG, "Failure starting Input Manager Service", e); + reportWtf("starting Clipboard Service", e); } try { @@ -273,7 +310,7 @@ class ServerThread extends Thread { networkManagement = NetworkManagementService.create(context); ServiceManager.addService(Context.NETWORKMANAGEMENT_SERVICE, networkManagement); } catch (Throwable e) { - Slog.e(TAG, "Failure starting NetworkManagement Service", e); + reportWtf("starting NetworkManagement Service", e); } try { @@ -281,7 +318,7 @@ class ServerThread extends Thread { tsms = new TextServicesManagerService(context); ServiceManager.addService(Context.TEXT_SERVICES_MANAGER_SERVICE, tsms); } catch (Throwable e) { - Slog.e(TAG, "Failure starting Text Service Manager Service", e); + reportWtf("starting Text Service Manager Service", e); } try { @@ -289,7 +326,7 @@ class ServerThread extends Thread { networkStats = new NetworkStatsService(context, networkManagement, alarm); ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats); } catch (Throwable e) { - Slog.e(TAG, "Failure starting NetworkStats Service", e); + reportWtf("starting NetworkStats Service", e); } try { @@ -299,7 +336,7 @@ class ServerThread extends Thread { networkStats, networkManagement); ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy); } catch (Throwable e) { - Slog.e(TAG, "Failure starting NetworkPolicy Service", e); + reportWtf("starting NetworkPolicy Service", e); } try { @@ -307,7 +344,7 @@ class ServerThread extends Thread { wifiP2p = new WifiP2pService(context); ServiceManager.addService(Context.WIFI_P2P_SERVICE, wifiP2p); } catch (Throwable e) { - Slog.e(TAG, "Failure starting Wi-Fi P2pService", e); + reportWtf("starting Wi-Fi P2pService", e); } try { @@ -316,7 +353,7 @@ class ServerThread extends Thread { ServiceManager.addService(Context.WIFI_SERVICE, wifi); wifi.checkAndStartWifi(); } catch (Throwable e) { - Slog.e(TAG, "Failure starting Wi-Fi Service", e); + reportWtf("starting Wi-Fi Service", e); } try { @@ -327,7 +364,7 @@ class ServerThread extends Thread { networkPolicy.bindConnectivityManager(connectivity); wifiP2p.connectivityServiceReady(); } catch (Throwable e) { - Slog.e(TAG, "Failure starting Connectivity Service", e); + reportWtf("starting Connectivity Service", e); } try { @@ -336,15 +373,7 @@ class ServerThread extends Thread { ServiceManager.addService( Context.THROTTLE_SERVICE, throttle); } catch (Throwable e) { - Slog.e(TAG, "Failure starting ThrottleService", e); - } - - try { - Slog.i(TAG, "Accessibility Manager"); - ServiceManager.addService(Context.ACCESSIBILITY_SERVICE, - new AccessibilityManagerService(context)); - } catch (Throwable e) { - Slog.e(TAG, "Failure starting Accessibility Manager", e); + reportWtf("starting ThrottleService", e); } try { @@ -355,7 +384,7 @@ class ServerThread extends Thread { Slog.i(TAG, "Mount Service"); ServiceManager.addService("mount", new MountService(context)); } catch (Throwable e) { - Slog.e(TAG, "Failure starting Mount Service", e); + reportWtf("starting Mount Service", e); } try { @@ -364,7 +393,7 @@ class ServerThread extends Thread { ServiceManager.addService(Context.NOTIFICATION_SERVICE, notification); networkPolicy.bindNotificationManager(notification); } catch (Throwable e) { - Slog.e(TAG, "Failure starting Notification Manager", e); + reportWtf("starting Notification Manager", e); } try { @@ -372,7 +401,7 @@ class ServerThread extends Thread { ServiceManager.addService(DeviceStorageMonitorService.SERVICE, new DeviceStorageMonitorService(context)); } catch (Throwable e) { - Slog.e(TAG, "Failure starting DeviceStorageMonitor service", e); + reportWtf("starting DeviceStorageMonitor service", e); } try { @@ -380,7 +409,7 @@ class ServerThread extends Thread { location = new LocationManagerService(context); ServiceManager.addService(Context.LOCATION_SERVICE, location); } catch (Throwable e) { - Slog.e(TAG, "Failure starting Location Manager", e); + reportWtf("starting Location Manager", e); } try { @@ -388,7 +417,7 @@ class ServerThread extends Thread { countryDetector = new CountryDetectorService(context); ServiceManager.addService(Context.COUNTRY_DETECTOR, countryDetector); } catch (Throwable e) { - Slog.e(TAG, "Failure starting Country Detector", e); + reportWtf("starting Country Detector", e); } try { @@ -396,7 +425,7 @@ class ServerThread extends Thread { ServiceManager.addService(Context.SEARCH_SERVICE, new SearchManagerService(context)); } catch (Throwable e) { - Slog.e(TAG, "Failure starting Search Service", e); + reportWtf("starting Search Service", e); } try { @@ -404,7 +433,7 @@ class ServerThread extends Thread { ServiceManager.addService(Context.DROPBOX_SERVICE, new DropBoxManagerService(context, new File("/data/system/dropbox"))); } catch (Throwable e) { - Slog.e(TAG, "Failure starting DropBoxManagerService", e); + reportWtf("starting DropBoxManagerService", e); } try { @@ -412,14 +441,14 @@ class ServerThread extends Thread { wallpaper = new WallpaperManagerService(context); ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper); } catch (Throwable e) { - Slog.e(TAG, "Failure starting Wallpaper Service", e); + reportWtf("starting Wallpaper Service", e); } try { Slog.i(TAG, "Audio Service"); ServiceManager.addService(Context.AUDIO_SERVICE, new AudioService(context)); } catch (Throwable e) { - Slog.e(TAG, "Failure starting Audio Service", e); + reportWtf("starting Audio Service", e); } try { @@ -427,15 +456,15 @@ class ServerThread extends Thread { // Listen for dock station changes dock = new DockObserver(context, power); } catch (Throwable e) { - Slog.e(TAG, "Failure starting DockObserver", e); + reportWtf("starting DockObserver", e); } try { Slog.i(TAG, "Wired Accessory Observer"); // Listen for wired headset changes - wiredAccessory = new WiredAccessoryObserver(context); + new WiredAccessoryObserver(context); } catch (Throwable e) { - Slog.e(TAG, "Failure starting WiredAccessoryObserver", e); + reportWtf("starting WiredAccessoryObserver", e); } try { @@ -444,7 +473,7 @@ class ServerThread extends Thread { usb = new UsbService(context); ServiceManager.addService(Context.USB_SERVICE, usb); } catch (Throwable e) { - Slog.e(TAG, "Failure starting UsbService", e); + reportWtf("starting UsbService", e); } try { @@ -452,7 +481,7 @@ class ServerThread extends Thread { // Listen for UI mode changes uiMode = new UiModeManagerService(context); } catch (Throwable e) { - Slog.e(TAG, "Failure starting UiModeManagerService", e); + reportWtf("starting UiModeManagerService", e); } try { @@ -468,21 +497,21 @@ class ServerThread extends Thread { appWidget = new AppWidgetService(context); ServiceManager.addService(Context.APPWIDGET_SERVICE, appWidget); } catch (Throwable e) { - Slog.e(TAG, "Failure starting AppWidget Service", e); + reportWtf("starting AppWidget Service", e); } try { Slog.i(TAG, "Recognition Service"); recognition = new RecognitionManagerService(context); } catch (Throwable e) { - Slog.e(TAG, "Failure starting Recognition Service", e); + reportWtf("starting Recognition Service", e); } try { Slog.i(TAG, "DiskStats Service"); ServiceManager.addService("diskstats", new DiskStatsService(context)); } catch (Throwable e) { - Slog.e(TAG, "Failure starting DiskStats Service", e); + reportWtf("starting DiskStats Service", e); } try { @@ -494,14 +523,14 @@ class ServerThread extends Thread { ServiceManager.addService("samplingprofiler", new SamplingProfilerService(context)); } catch (Throwable e) { - Slog.e(TAG, "Failure starting SamplingProfiler Service", e); + reportWtf("starting SamplingProfiler Service", e); } try { Slog.i(TAG, "NetworkTimeUpdateService"); networkTimeUpdater = new NetworkTimeUpdateService(context); } catch (Throwable e) { - Slog.e(TAG, "Failure starting NetworkTimeUpdate service"); + reportWtf("starting NetworkTimeUpdate service", e); } } @@ -522,14 +551,26 @@ class ServerThread extends Thread { // It is now time to start up the app processes... if (devicePolicy != null) { - devicePolicy.systemReady(); + try { + devicePolicy.systemReady(); + } catch (Throwable e) { + reportWtf("making Device Policy Service ready", e); + } } if (notification != null) { - notification.systemReady(); + try { + notification.systemReady(); + } catch (Throwable e) { + reportWtf("making Notification Service ready", e); + } } - wm.systemReady(); + try { + wm.systemReady(); + } catch (Throwable e) { + reportWtf("making Window Manager Service ready", e); + } if (safeMode) { ActivityManagerService.self().showSafeModeOverlay(); @@ -547,7 +588,8 @@ class ServerThread extends Thread { power.systemReady(); try { pm.systemReady(); - } catch (RemoteException e) { + } catch (Throwable e) { + reportWtf("making Package Manager Service ready", e); } // These are needed to propagate to the runnable below. @@ -569,6 +611,7 @@ class ServerThread extends Thread { final CountryDetectorService countryDetectorF = countryDetector; final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater; final TextServicesManagerService textServiceManagerServiceF = tsms; + final StatusBarManagerService statusBarF = statusBar; // We now tell the activity manager it is okay to run third party // code. It will call back into us once it has gotten to the state @@ -581,28 +624,96 @@ class ServerThread extends Thread { Slog.i(TAG, "Making services ready"); startSystemUi(contextF); - if (batteryF != null) batteryF.systemReady(); - if (networkManagementF != null) networkManagementF.systemReady(); - if (networkStatsF != null) networkStatsF.systemReady(); - if (networkPolicyF != null) networkPolicyF.systemReady(); - if (connectivityF != null) connectivityF.systemReady(); - if (dockF != null) dockF.systemReady(); - if (usbF != null) usbF.systemReady(); - if (uiModeF != null) uiModeF.systemReady(); - if (recognitionF != null) recognitionF.systemReady(); + try { + if (batteryF != null) batteryF.systemReady(); + } catch (Throwable e) { + reportWtf("making Battery Service ready", e); + } + try { + if (networkManagementF != null) networkManagementF.systemReady(); + } catch (Throwable e) { + reportWtf("making Network Managment Service ready", e); + } + try { + if (networkStatsF != null) networkStatsF.systemReady(); + } catch (Throwable e) { + reportWtf("making Network Stats Service ready", e); + } + try { + if (networkPolicyF != null) networkPolicyF.systemReady(); + } catch (Throwable e) { + reportWtf("making Network Policy Service ready", e); + } + try { + if (connectivityF != null) connectivityF.systemReady(); + } catch (Throwable e) { + reportWtf("making Connectivity Service ready", e); + } + try { + if (dockF != null) dockF.systemReady(); + } catch (Throwable e) { + reportWtf("making Dock Service ready", e); + } + try { + if (usbF != null) usbF.systemReady(); + } catch (Throwable e) { + reportWtf("making USB Service ready", e); + } + try { + if (uiModeF != null) uiModeF.systemReady(); + } catch (Throwable e) { + reportWtf("making UI Mode Service ready", e); + } + try { + if (recognitionF != null) recognitionF.systemReady(); + } catch (Throwable e) { + reportWtf("making Recognition Service ready", e); + } Watchdog.getInstance().start(); // It is now okay to let the various system services start their // third party code... - if (appWidgetF != null) appWidgetF.systemReady(safeMode); - if (wallpaperF != null) wallpaperF.systemReady(); - if (immF != null) immF.systemReady(); - if (locationF != null) locationF.systemReady(); - if (countryDetectorF != null) countryDetectorF.systemReady(); - if (throttleF != null) throttleF.systemReady(); - if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemReady(); - if (textServiceManagerServiceF != null) textServiceManagerServiceF.systemReady(); + try { + if (appWidgetF != null) appWidgetF.systemReady(safeMode); + } catch (Throwable e) { + reportWtf("making App Widget Service ready", e); + } + try { + if (wallpaperF != null) wallpaperF.systemReady(); + } catch (Throwable e) { + reportWtf("making Wallpaper Service ready", e); + } + try { + if (immF != null) immF.systemReady(statusBarF); + } catch (Throwable e) { + reportWtf("making Input Method Service ready", e); + } + try { + if (locationF != null) locationF.systemReady(); + } catch (Throwable e) { + reportWtf("making Location Service ready", e); + } + try { + if (countryDetectorF != null) countryDetectorF.systemReady(); + } catch (Throwable e) { + reportWtf("making Country Detector Service ready", e); + } + try { + if (throttleF != null) throttleF.systemReady(); + } catch (Throwable e) { + reportWtf("making Throttle Service ready", e); + } + try { + if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemReady(); + } catch (Throwable e) { + reportWtf("making Network Time Service ready", e); + } + try { + if (textServiceManagerServiceF != null) textServiceManagerServiceF.systemReady(); + } catch (Throwable e) { + reportWtf("making Text Services Manager Service ready", e); + } } }); diff --git a/services/java/com/android/server/TextServicesManagerService.java b/services/java/com/android/server/TextServicesManagerService.java index 90824a6..321274f 100644 --- a/services/java/com/android/server/TextServicesManagerService.java +++ b/services/java/com/android/server/TextServicesManagerService.java @@ -41,6 +41,7 @@ import android.service.textservice.SpellCheckerService; import android.text.TextUtils; import android.util.Slog; import android.view.textservice.SpellCheckerInfo; +import android.view.textservice.SpellCheckerSubtype; import java.io.IOException; import java.util.ArrayList; @@ -172,9 +173,9 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { @Override public SpellCheckerInfo getCurrentSpellChecker(String locale) { synchronized (mSpellCheckerMap) { - String curSpellCheckerId = + final String curSpellCheckerId = Settings.Secure.getString(mContext.getContentResolver(), - Settings.Secure.SPELL_CHECKER_SERVICE); + Settings.Secure.SELECTED_SPELL_CHECKER); if (DBG) { Slog.w(TAG, "getCurrentSpellChecker: " + curSpellCheckerId); } @@ -185,6 +186,47 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { } } + // TODO: Save SpellCheckerSubtype by supported languages. + @Override + public SpellCheckerSubtype getCurrentSpellCheckerSubtype(String locale) { + synchronized (mSpellCheckerMap) { + final String subtypeHashCodeStr = + Settings.Secure.getString(mContext.getContentResolver(), + Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE); + if (DBG) { + Slog.w(TAG, "getCurrentSpellChecker: " + subtypeHashCodeStr); + } + final SpellCheckerInfo sci = getCurrentSpellChecker(null); + if (sci == null || sci.getSubtypeCount() == 0) { + if (DBG) { + Slog.w(TAG, "Subtype not found."); + } + return null; + } + if (TextUtils.isEmpty(subtypeHashCodeStr)) { + if (DBG) { + Slog.w(TAG, "Return first subtype in " + sci.getId()); + } + // Return the first Subtype if there is no settings for the current subtype. + return sci.getSubtypeAt(0); + } + final int hashCode = Integer.valueOf(subtypeHashCodeStr); + for (int i = 0; i < sci.getSubtypeCount(); ++i) { + final SpellCheckerSubtype scs = sci.getSubtypeAt(i); + if (scs.hashCode() == hashCode) { + if (DBG) { + Slog.w(TAG, "Return subtype " + scs.hashCode()); + } + return scs; + } + } + if (DBG) { + Slog.w(TAG, "Return first subtype in " + sci.getId()); + } + return sci.getSubtypeAt(0); + } + } + @Override public void getSpellCheckerService(String sciId, String locale, ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener, @@ -253,6 +295,13 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { return; } + @Override + public boolean isSpellCheckerEnabled() { + synchronized(mSpellCheckerMap) { + return isSpellCheckerEnabledLocked(); + } + } + private void startSpellCheckerServiceInnerLocked(SpellCheckerInfo info, String locale, ITextServicesSessionListener tsListener, ISpellCheckerSessionListener scListener, int uid, Bundle bundle) { @@ -301,7 +350,7 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { } @Override - public void setCurrentSpellChecker(String sciId) { + public void setCurrentSpellChecker(String locale, String sciId) { synchronized(mSpellCheckerMap) { if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.WRITE_SECURE_SETTINGS) @@ -314,6 +363,34 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { } } + @Override + public void setCurrentSpellCheckerSubtype(String locale, int hashCode) { + synchronized(mSpellCheckerMap) { + if (mContext.checkCallingOrSelfPermission( + android.Manifest.permission.WRITE_SECURE_SETTINGS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException( + "Requires permission " + + android.Manifest.permission.WRITE_SECURE_SETTINGS); + } + setCurrentSpellCheckerSubtypeLocked(hashCode); + } + } + + @Override + public void setSpellCheckerEnabled(boolean enabled) { + synchronized(mSpellCheckerMap) { + if (mContext.checkCallingOrSelfPermission( + android.Manifest.permission.WRITE_SECURE_SETTINGS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException( + "Requires permission " + + android.Manifest.permission.WRITE_SECURE_SETTINGS); + } + setSpellCheckerEnabledLocked(enabled); + } + } + private void setCurrentSpellCheckerLocked(String sciId) { if (DBG) { Slog.w(TAG, "setCurrentSpellChecker: " + sciId); @@ -322,7 +399,59 @@ public class TextServicesManagerService extends ITextServicesManager.Stub { final long ident = Binder.clearCallingIdentity(); try { Settings.Secure.putString(mContext.getContentResolver(), - Settings.Secure.SPELL_CHECKER_SERVICE, sciId); + Settings.Secure.SELECTED_SPELL_CHECKER, sciId); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + private void setCurrentSpellCheckerSubtypeLocked(int hashCode) { + if (DBG) { + Slog.w(TAG, "setCurrentSpellCheckerSubtype: " + hashCode); + } + final SpellCheckerInfo sci = getCurrentSpellChecker(null); + if (sci == null) return; + boolean found = false; + for (int i = 0; i < sci.getSubtypeCount(); ++i) { + if(sci.getSubtypeAt(i).hashCode() == hashCode) { + found = true; + break; + } + } + if (!found) { + return; + } + final long ident = Binder.clearCallingIdentity(); + try { + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, String.valueOf(hashCode)); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + private void setSpellCheckerEnabledLocked(boolean enabled) { + if (DBG) { + Slog.w(TAG, "setSpellCheckerEnabled: " + enabled); + } + final long ident = Binder.clearCallingIdentity(); + try { + Settings.Secure.putInt(mContext.getContentResolver(), + Settings.Secure.SPELL_CHECKER_ENABLED, enabled ? 1 : 0); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + + private boolean isSpellCheckerEnabledLocked() { + final long ident = Binder.clearCallingIdentity(); + try { + final boolean retval = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.SPELL_CHECKER_ENABLED, 1) == 1; + if (DBG) { + Slog.w(TAG, "getSpellCheckerEnabled: " + retval); + } + return retval; } finally { Binder.restoreCallingIdentity(ident); } diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java index 9765f2a..6ceccaf 100644 --- a/services/java/com/android/server/WallpaperManagerService.java +++ b/services/java/com/android/server/WallpaperManagerService.java @@ -75,7 +75,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub { static final String TAG = "WallpaperService"; static final boolean DEBUG = false; - Object mLock = new Object(); + final Object mLock = new Object[0]; /** * Minimum time between crashes of a wallpaper service for us to consider @@ -118,9 +118,10 @@ class WallpaperManagerService extends IWallpaperManager.Stub { File changedFile = new File(WALLPAPER_DIR, path); if (WALLPAPER_FILE.equals(changedFile)) { notifyCallbacksLocked(); - if (mWallpaperComponent == null || - mWallpaperComponent.equals(mImageWallpaperComponent)) { - bindWallpaperComponentLocked(mWallpaperComponent, true); + if (mWallpaperComponent == null || mImageWallpaperPending) { + mImageWallpaperPending = false; + bindWallpaperComponentLocked(mImageWallpaperComponent, true); + saveSettingsLocked(); } } } @@ -133,7 +134,12 @@ class WallpaperManagerService extends IWallpaperManager.Stub { int mWidth = -1; int mHeight = -1; - + + /** + * Client is currently writing a new image wallpaper. + */ + boolean mImageWallpaperPending; + /** * Resource name if using a picture from the wallpaper gallery */ @@ -343,6 +349,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub { } final long ident = Binder.clearCallingIdentity(); try { + mImageWallpaperPending = false; bindWallpaperComponentLocked(null, false); } catch (IllegalArgumentException e) { // This can happen if the default wallpaper component doesn't @@ -433,9 +440,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub { try { ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name); if (pfd != null) { - // Bind the wallpaper to an ImageWallpaper - bindWallpaperComponentLocked(mImageWallpaperComponent, false); - saveSettingsLocked(); + mImageWallpaperPending = true; } return pfd; } finally { @@ -463,6 +468,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub { synchronized (mLock) { final long ident = Binder.clearCallingIdentity(); try { + mImageWallpaperPending = false; bindWallpaperComponentLocked(name, false); } finally { Binder.restoreCallingIdentity(ident); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 800c4fc..7232a94 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -91,6 +91,7 @@ import android.os.Environment; import android.os.FileObserver; import android.os.FileUtils; import android.os.Handler; +import android.os.HandlerThread; import android.os.IBinder; import android.os.IPermissionController; import android.os.Looper; @@ -3748,6 +3749,10 @@ public final class ActivityManagerService extends ActivityManagerNative mWindowManager.enableScreenAfterBoot(); } + public void showBootMessage(final CharSequence msg, final boolean always) { + mWindowManager.showBootMessage(msg, always); + } + final void finishBooting() { IntentFilter pkgFilter = new IntentFilter(); pkgFilter.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART); @@ -6446,7 +6451,9 @@ public final class ActivityManagerService extends ActivityManagerNative File fname = new File(systemDir, "called_pre_boots.dat"); return fname; } - + + static final int LAST_DONE_VERSION = 10000; + private static ArrayList<ComponentName> readLastDonePreBootReceivers() { ArrayList<ComponentName> lastDoneReceivers = new ArrayList<ComponentName>(); File file = getCalledPreBootReceiversFile(); @@ -6454,16 +6461,21 @@ public final class ActivityManagerService extends ActivityManagerNative try { fis = new FileInputStream(file); DataInputStream dis = new DataInputStream(new BufferedInputStream(fis, 2048)); - int vers = dis.readInt(); - String codename = dis.readUTF(); - if (vers == android.os.Build.VERSION.SDK_INT - && codename.equals(android.os.Build.VERSION.CODENAME)) { - int num = dis.readInt(); - while (num > 0) { - num--; - String pkg = dis.readUTF(); - String cls = dis.readUTF(); - lastDoneReceivers.add(new ComponentName(pkg, cls)); + int fvers = dis.readInt(); + if (fvers == LAST_DONE_VERSION) { + String vers = dis.readUTF(); + String codename = dis.readUTF(); + String build = dis.readUTF(); + if (android.os.Build.VERSION.RELEASE.equals(vers) + && android.os.Build.VERSION.CODENAME.equals(codename) + && android.os.Build.VERSION.INCREMENTAL.equals(build)) { + int num = dis.readInt(); + while (num > 0) { + num--; + String pkg = dis.readUTF(); + String cls = dis.readUTF(); + lastDoneReceivers.add(new ComponentName(pkg, cls)); + } } } } catch (FileNotFoundException e) { @@ -6488,8 +6500,10 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.i(TAG, "Writing new set of last done pre-boot receivers..."); fos = new FileOutputStream(file); dos = new DataOutputStream(new BufferedOutputStream(fos, 2048)); - dos.writeInt(android.os.Build.VERSION.SDK_INT); + dos.writeInt(LAST_DONE_VERSION); + dos.writeUTF(android.os.Build.VERSION.RELEASE); dos.writeUTF(android.os.Build.VERSION.CODENAME); + dos.writeUTF(android.os.Build.VERSION.INCREMENTAL); dos.writeInt(list.size()); for (int i=0; i<list.size(); i++) { dos.writeUTF(list.get(i).getPackageName()); @@ -6550,7 +6564,7 @@ public final class ActivityManagerService extends ActivityManagerNative i--; } } - + for (int i=0; i<ris.size(); i++) { ActivityInfo ai = ris.get(i).activityInfo; ComponentName comp = new ComponentName(ai.packageName, ai.name); @@ -6571,6 +6585,9 @@ public final class ActivityManagerService extends ActivityManagerNative mDidUpdate = true; } writeLastDonePreBootReceivers(doneReceivers); + showBootMessage(mContext.getText( + R.string.android_upgrading_complete), + false); systemReady(goingCallback); } }); @@ -9009,6 +9026,7 @@ public final class ActivityManagerService extends ActivityManagerNative final static class MemItem { final String label; final long pss; + ArrayList<MemItem> subitems; public MemItem(String _label, long _pss) { label = _label; @@ -9034,7 +9052,10 @@ public final class ActivityManagerService extends ActivityManagerNative for (int i=0; i<items.size(); i++) { MemItem mi = items.get(i); - pw.print(prefix); pw.printf("%8d Kb: ", mi.pss); pw.println(mi.label); + pw.print(prefix); pw.printf("%7d Kb: ", mi.pss); pw.println(mi.label); + if (mi.subitems != null) { + dumpMemItems(pw, prefix + " ", mi.subitems, true); + } } } @@ -9102,6 +9123,7 @@ public final class ActivityManagerService extends ActivityManagerNative "Backup", "Services", "Home", "Background" }; long oomPss[] = new long[oomLabel.length]; + ArrayList<MemItem>[] oomProcs = (ArrayList<MemItem>[])new ArrayList[oomLabel.length]; long totalPss = 0; @@ -9130,7 +9152,9 @@ public final class ActivityManagerService extends ActivityManagerNative if (!isCheckinRequest && mi != null) { long myTotalPss = mi.getTotalPss(); totalPss += myTotalPss; - procMems.add(new MemItem(r.processName + " (pid " + r.pid + ")", myTotalPss)); + MemItem pssItem = new MemItem(r.processName + " (pid " + r.pid + ")", + myTotalPss); + procMems.add(pssItem); nativePss += mi.nativePss; dalvikPss += mi.dalvikPss; @@ -9144,6 +9168,10 @@ public final class ActivityManagerService extends ActivityManagerNative for (int oomIndex=0; oomIndex<oomPss.length; oomIndex++) { if (r.setAdj <= oomAdj[oomIndex] || oomIndex == (oomPss.length-1)) { oomPss[oomIndex] += myTotalPss; + if (oomProcs[oomIndex] == null) { + oomProcs[oomIndex] = new ArrayList<MemItem>(); + } + oomProcs[oomIndex].add(pssItem); break; } } @@ -9164,7 +9192,9 @@ public final class ActivityManagerService extends ActivityManagerNative ArrayList<MemItem> oomMems = new ArrayList<MemItem>(); for (int j=0; j<oomPss.length; j++) { if (oomPss[j] != 0) { - oomMems.add(new MemItem(oomLabel[j], oomPss[j])); + MemItem item = new MemItem(oomLabel[j], oomPss[j]); + item.subitems = oomProcs[j]; + oomMems.add(item); } } diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index 6f0779f..4ad0f45 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -3163,7 +3163,7 @@ final class ActivityStack { //Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout); if (mMainStack) { - if (!mService.mBooted && !fromTimeout) { + if (!mService.mBooted) { mService.mBooted = true; enableScreen = true; } diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java index e61a7f4..87129ea 100644 --- a/services/java/com/android/server/am/TaskRecord.java +++ b/services/java/com/android/server/am/TaskRecord.java @@ -116,6 +116,8 @@ class TaskRecord extends ThumbnailHolder { if (!askedCompatMode) { pw.print(prefix); pw.print("askedCompatMode="); pw.println(askedCompatMode); } + pw.print(prefix); pw.print("lastThumbnail="); pw.print(lastThumbnail); + pw.print(" lastDescription="); pw.println(lastDescription); pw.print(prefix); pw.print("lastActiveTime="); pw.print(lastActiveTime); pw.print(" (inactive for "); pw.print((getInactiveDuration()/1000)); pw.println("s)"); diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java index 6b65e07..55e0678 100644 --- a/services/java/com/android/server/connectivity/Vpn.java +++ b/services/java/com/android/server/connectivity/Vpn.java @@ -388,6 +388,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub { private final VpnConfig mConfig; private final String[] mDaemons; private final String[][] mArguments; + private final LocalSocket[] mSockets; private final String mOuterInterface; private final LegacyVpnInfo mInfo; @@ -398,6 +399,7 @@ public class Vpn extends INetworkManagementEventObserver.Stub { mConfig = config; mDaemons = new String[] {"racoon", "mtpd"}; mArguments = new String[][] {racoon, mtpd}; + mSockets = new LocalSocket[mDaemons.length]; mInfo = new LegacyVpnInfo(); // This is the interface which VPN is running on. @@ -416,10 +418,14 @@ public class Vpn extends INetworkManagementEventObserver.Stub { } public void exit() { - // We assume that everything is reset after the daemons die. + // We assume that everything is reset after stopping the daemons. interrupt(); - for (String daemon : mDaemons) { - SystemProperties.set("ctl.stop", daemon); + for (LocalSocket socket : mSockets) { + try { + socket.close(); + } catch (Exception e) { + // ignore + } } } @@ -462,15 +468,10 @@ public class Vpn extends INetworkManagementEventObserver.Stub { checkpoint(false); mInfo.state = LegacyVpnInfo.STATE_INITIALIZING; - // First stop the daemons. - for (String daemon : mDaemons) { - SystemProperties.set("ctl.stop", daemon); - } - // Wait for the daemons to stop. for (String daemon : mDaemons) { String key = "init.svc." + daemon; - while (!"stopped".equals(SystemProperties.get(key))) { + while (!"stopped".equals(SystemProperties.get(key, "stopped"))) { checkpoint(true); } } @@ -511,27 +512,27 @@ public class Vpn extends INetworkManagementEventObserver.Stub { } // Create the control socket. - LocalSocket socket = new LocalSocket(); + mSockets[i] = new LocalSocket(); LocalSocketAddress address = new LocalSocketAddress( daemon, LocalSocketAddress.Namespace.RESERVED); // Wait for the socket to connect. while (true) { try { - socket.connect(address); + mSockets[i].connect(address); break; } catch (Exception e) { // ignore } checkpoint(true); } - socket.setSoTimeout(500); + mSockets[i].setSoTimeout(500); // Send over the arguments. - OutputStream out = socket.getOutputStream(); + OutputStream out = mSockets[i].getOutputStream(); for (String argument : arguments) { byte[] bytes = argument.getBytes(Charsets.UTF_8); - if (bytes.length > 0xFFFF) { + if (bytes.length >= 0xFFFF) { throw new IllegalArgumentException("Argument is too large"); } out.write(bytes.length >> 8); @@ -539,11 +540,12 @@ public class Vpn extends INetworkManagementEventObserver.Stub { out.write(bytes); checkpoint(false); } + out.write(0xFF); + out.write(0xFF); out.flush(); - socket.shutdownOutput(); // Wait for End-of-File. - InputStream in = socket.getInputStream(); + InputStream in = mSockets[i].getInputStream(); while (true) { try { if (in.read() == -1) { @@ -554,7 +556,6 @@ public class Vpn extends INetworkManagementEventObserver.Stub { } checkpoint(true); } - socket.close(); } // Wait for the daemons to create the new state. @@ -631,6 +632,13 @@ public class Vpn extends INetworkManagementEventObserver.Stub { Log.i(TAG, "Aborting", e); exit(); } finally { + // Kill the daemons if they fail to stop. + if (mInfo.state == LegacyVpnInfo.STATE_INITIALIZING) { + for (String daemon : mDaemons) { + SystemProperties.set("ctl.stop", daemon); + } + } + // Do not leave an unstable state. if (mInfo.state == LegacyVpnInfo.STATE_INITIALIZING || mInfo.state == LegacyVpnInfo.STATE_CONNECTING) { diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java index 14d9665..84880f9 100644 --- a/services/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java @@ -27,7 +27,10 @@ import static android.content.Intent.ACTION_PACKAGE_ADDED; import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; +import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_MOBILE; +import static android.net.ConnectivityManager.TYPE_WIFI; +import static android.net.ConnectivityManager.TYPE_WIMAX; import static android.net.NetworkPolicy.LIMIT_DISABLED; import static android.net.NetworkPolicy.SNOOZE_NEVER; import static android.net.NetworkPolicy.WARNING_DISABLED; @@ -40,8 +43,11 @@ import static android.net.NetworkPolicyManager.computeLastCycleBoundary; import static android.net.NetworkPolicyManager.dumpPolicy; import static android.net.NetworkPolicyManager.dumpRules; import static android.net.NetworkPolicyManager.isUidValidForPolicy; +import static android.net.NetworkTemplate.MATCH_ETHERNET; import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER; import static android.net.NetworkTemplate.MATCH_MOBILE_4G; +import static android.net.NetworkTemplate.MATCH_MOBILE_ALL; +import static android.net.NetworkTemplate.MATCH_WIFI; import static android.net.NetworkTemplate.buildTemplateMobileAll; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static com.android.internal.util.Preconditions.checkNotNull; @@ -104,6 +110,7 @@ import android.util.Xml; import com.android.internal.R; import com.android.internal.os.AtomicFile; import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.Objects; import com.google.android.collect.Lists; import com.google.android.collect.Maps; import com.google.android.collect.Sets; @@ -129,8 +136,8 @@ import java.util.List; import libcore.io.IoUtils; /** - * Service that maintains low-level network policy rules and collects usage - * statistics to drive those rules. + * Service that maintains low-level network policy rules, using + * {@link NetworkStatsService} statistics to drive those rules. * <p> * Derives active rules by combining a given policy with other system status, * and delivers to listeners, such as {@link ConnectivityManager}, for @@ -195,6 +202,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private volatile boolean mScreenOn; private volatile boolean mRestrictBackground; + private final boolean mSuppressDefaultPolicy; + /** Defined network policies. */ private HashMap<NetworkTemplate, NetworkPolicy> mNetworkPolicy = Maps.newHashMap(); /** Currently active network rules for ifaces. */ @@ -210,6 +219,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { /** Set of over-limit templates that have been notified. */ private HashSet<NetworkTemplate> mOverLimitNotified = Sets.newHashSet(); + /** Set of currently active {@link Notification} tags. */ + private HashSet<String> mActiveNotifs = Sets.newHashSet(); + /** Current values from {@link #setPolicyDataEnable(int, boolean)}. */ + private SparseBooleanArray mActiveNetworkEnabled = new SparseBooleanArray(); + /** Foreground at both UID and PID granularity. */ private SparseBooleanArray mUidForeground = new SparseBooleanArray(); private SparseArray<SparseBooleanArray> mUidPidForeground = new SparseArray< @@ -232,7 +246,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { IPowerManager powerManager, INetworkStatsService networkStats, INetworkManagementService networkManagement) { this(context, activityManager, powerManager, networkStats, networkManagement, - NtpTrustedTime.getInstance(context), getSystemDir()); + NtpTrustedTime.getInstance(context), getSystemDir(), false); } private static File getSystemDir() { @@ -241,8 +255,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { public NetworkPolicyManagerService(Context context, IActivityManager activityManager, IPowerManager powerManager, INetworkStatsService networkStats, - INetworkManagementService networkManagement, - TrustedTime time, File systemDir) { + INetworkManagementService networkManagement, TrustedTime time, File systemDir, + boolean suppressDefaultPolicy) { mContext = checkNotNull(context, "missing context"); mActivityManager = checkNotNull(activityManager, "missing activityManager"); mPowerManager = checkNotNull(powerManager, "missing powerManager"); @@ -254,6 +268,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mHandlerThread.start(); mHandler = new Handler(mHandlerThread.getLooper(), mHandlerCallback); + mSuppressDefaultPolicy = suppressDefaultPolicy; + mPolicyFile = new AtomicFile(new File(systemDir, "netpolicy.xml")); } @@ -408,6 +424,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // READ_NETWORK_USAGE_HISTORY permission above. synchronized (mRulesLock) { + updateNetworkEnabledLocked(); updateNotificationsLocked(); } } @@ -446,6 +463,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { Slog.w(TAG, "problem updating network stats"); } + updateNetworkEnabledLocked(); updateNotificationsLocked(); } } @@ -459,74 +477,70 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private void updateNotificationsLocked() { if (LOGV) Slog.v(TAG, "updateNotificationsLocked()"); - // try refreshing time source when stale - if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) { - mTime.forceRefresh(); - } - - final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() - : System.currentTimeMillis(); + // keep track of previously active notifications + final HashSet<String> beforeNotifs = Sets.newHashSet(); + beforeNotifs.addAll(mActiveNotifs); + mActiveNotifs.clear(); // TODO: when switching to kernel notifications, compute next future // cycle boundary to recompute notifications. // examine stats for each active policy - for (NetworkPolicy policy : mNetworkRules.keySet()) { + final long currentTime = currentTimeMillis(true); + for (NetworkPolicy policy : mNetworkPolicy.values()) { + // ignore policies that aren't relevant to user + if (!isTemplateRelevant(policy.template)) continue; + final long start = computeLastCycleBoundary(currentTime, policy); final long end = currentTime; - final long totalBytes; - try { - final NetworkStats stats = mNetworkStats.getSummaryForNetwork( - policy.template, start, end); - final NetworkStats.Entry entry = stats.getValues(0, null); - totalBytes = entry.rxBytes + entry.txBytes; - } catch (RemoteException e) { - Slog.w(TAG, "problem reading summary for template " + policy.template); - continue; - } + final long totalBytes = getTotalBytes(policy.template, start, end); + if (totalBytes == UNKNOWN_BYTES) continue; if (policy.limitBytes != LIMIT_DISABLED && totalBytes >= policy.limitBytes) { - cancelNotification(policy, TYPE_WARNING); - if (policy.lastSnooze >= start) { - cancelNotification(policy, TYPE_LIMIT); enqueueNotification(policy, TYPE_LIMIT_SNOOZED, totalBytes); } else { - cancelNotification(policy, TYPE_LIMIT_SNOOZED); enqueueNotification(policy, TYPE_LIMIT, totalBytes); notifyOverLimitLocked(policy.template); } } else { - cancelNotification(policy, TYPE_LIMIT); - cancelNotification(policy, TYPE_LIMIT_SNOOZED); notifyUnderLimitLocked(policy.template); if (policy.warningBytes != WARNING_DISABLED && totalBytes >= policy.warningBytes) { enqueueNotification(policy, TYPE_WARNING, totalBytes); - } else { - cancelNotification(policy, TYPE_WARNING); } } } - // clear notifications for non-active policies - for (NetworkPolicy policy : mNetworkPolicy.values()) { - if (!mNetworkRules.containsKey(policy)) { - cancelNotification(policy, TYPE_WARNING); - cancelNotification(policy, TYPE_LIMIT); - cancelNotification(policy, TYPE_LIMIT_SNOOZED); - notifyUnderLimitLocked(policy.template); - } - } - // ongoing notification when restricting background data if (mRestrictBackground) { enqueueRestrictedNotification(TAG_ALLOW_BACKGROUND); - } else { - cancelNotification(TAG_ALLOW_BACKGROUND); } + + // cancel stale notifications that we didn't renew above + for (String tag : beforeNotifs) { + if (!mActiveNotifs.contains(tag)) { + cancelNotification(tag); + } + } + } + + /** + * Test if given {@link NetworkTemplate} is relevant to user based on + * current device state, such as when {@link #getActiveSubscriberId()} + * matches. This is regardless of data connection status. + */ + private boolean isTemplateRelevant(NetworkTemplate template) { + switch (template.getMatchRule()) { + case MATCH_MOBILE_3G_LOWER: + case MATCH_MOBILE_4G: + case MATCH_MOBILE_ALL: + // mobile templates are relevant when subscriberid is active + return Objects.equal(getActiveSubscriberId(), template.getSubscriberId()); + } + return true; } /** @@ -590,9 +604,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { case MATCH_MOBILE_4G: title = res.getText(R.string.data_usage_4g_limit_title); break; - default: + case MATCH_MOBILE_ALL: title = res.getText(R.string.data_usage_mobile_limit_title); break; + case MATCH_WIFI: + title = res.getText(R.string.data_usage_wifi_limit_title); + break; + default: + title = null; + break; } builder.setSmallIcon(com.android.internal.R.drawable.ic_menu_block); @@ -618,9 +638,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { case MATCH_MOBILE_4G: title = res.getText(R.string.data_usage_4g_limit_snoozed_title); break; - default: + case MATCH_MOBILE_ALL: title = res.getText(R.string.data_usage_mobile_limit_snoozed_title); break; + case MATCH_WIFI: + title = res.getText(R.string.data_usage_wifi_limit_snoozed_title); + break; + default: + title = null; + break; } builder.setSmallIcon(R.drawable.ic_menu_info_details); @@ -641,6 +667,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final int[] idReceived = new int[1]; mNotifManager.enqueueNotificationWithTag( packageName, tag, 0x0, builder.getNotification(), idReceived); + mActiveNotifs.add(tag); } catch (RemoteException e) { Slog.w(TAG, "problem during enqueueNotification: " + e); } @@ -674,19 +701,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final int[] idReceived = new int[1]; mNotifManager.enqueueNotificationWithTag(packageName, tag, 0x0, builder.getNotification(), idReceived); + mActiveNotifs.add(tag); } catch (RemoteException e) { Slog.w(TAG, "problem during enqueueNotification: " + e); } } - /** - * Cancel any notification for combined {@link NetworkPolicy} and specific - * type, like {@link #TYPE_LIMIT}. - */ - private void cancelNotification(NetworkPolicy policy, int type) { - cancelNotification(buildNotificationTag(policy, type)); - } - private void cancelNotification(String tag) { // TODO: move to NotificationManager once we can mock it try { @@ -709,6 +729,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // permission above. synchronized (mRulesLock) { ensureActiveMobilePolicyLocked(); + updateNetworkEnabledLocked(); updateNetworkRulesLocked(); updateNotificationsLocked(); } @@ -716,6 +737,65 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { }; /** + * Proactively control network data connections when they exceed + * {@link NetworkPolicy#limitBytes}. + */ + private void updateNetworkEnabledLocked() { + if (LOGV) Slog.v(TAG, "updateNetworkEnabledLocked()"); + + // TODO: reset any policy-disabled networks when any policy is removed + // completely, which is currently rare case. + + final long currentTime = currentTimeMillis(true); + for (NetworkPolicy policy : mNetworkPolicy.values()) { + // shortcut when policy has no limit + if (policy.limitBytes == LIMIT_DISABLED) { + setNetworkTemplateEnabled(policy.template, true); + continue; + } + + final long start = computeLastCycleBoundary(currentTime, policy); + final long end = currentTime; + + final long totalBytes = getTotalBytes(policy.template, start, end); + if (totalBytes == UNKNOWN_BYTES) continue; + + // disable data connection when over limit and not snoozed + final boolean overLimit = policy.limitBytes != LIMIT_DISABLED + && totalBytes > policy.limitBytes && policy.lastSnooze < start; + setNetworkTemplateEnabled(policy.template, !overLimit); + } + } + + /** + * Control {@link IConnectivityManager#setPolicyDataEnable(int, boolean)} + * for the given {@link NetworkTemplate}. + */ + private void setNetworkTemplateEnabled(NetworkTemplate template, boolean enabled) { + if (LOGD) Slog.d(TAG, "setting template=" + template + " enabled=" + enabled); + switch (template.getMatchRule()) { + case MATCH_MOBILE_3G_LOWER: + case MATCH_MOBILE_4G: + case MATCH_MOBILE_ALL: + // TODO: offer more granular control over radio states once + // 4965893 is available. + if (Objects.equal(getActiveSubscriberId(), template.getSubscriberId())) { + setPolicyDataEnable(TYPE_MOBILE, enabled); + setPolicyDataEnable(TYPE_WIMAX, enabled); + } + break; + case MATCH_WIFI: + setPolicyDataEnable(TYPE_WIFI, enabled); + break; + case MATCH_ETHERNET: + setPolicyDataEnable(TYPE_ETHERNET, enabled); + break; + default: + throw new IllegalArgumentException("unexpected template"); + } + } + + /** * Examine all connected {@link NetworkState}, looking for * {@link NetworkPolicy} that need to be enforced. When matches found, set * remaining quota based on usage cycle and historical stats. @@ -763,34 +843,19 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } - // try refreshing time source when stale - if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) { - mTime.forceRefresh(); - } - - final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() - : System.currentTimeMillis(); - final HashSet<String> newMeteredIfaces = Sets.newHashSet(); // apply each policy that we found ifaces for; compute remaining data // based on current cycle and historical stats, and push to kernel. + final long currentTime = currentTimeMillis(true); for (NetworkPolicy policy : mNetworkRules.keySet()) { final String[] ifaces = mNetworkRules.get(policy); final long start = computeLastCycleBoundary(currentTime, policy); final long end = currentTime; - final NetworkStats stats; - final long total; - try { - stats = mNetworkStats.getSummaryForNetwork(policy.template, start, end); - final NetworkStats.Entry entry = stats.getValues(0, null); - total = entry.rxBytes + entry.txBytes; - } catch (RemoteException e) { - Slog.w(TAG, "problem reading summary for template " + policy.template); - continue; - } + final long totalBytes = getTotalBytes(policy.template, start, end); + if (totalBytes == UNKNOWN_BYTES) continue; if (LOGD) { Slog.d(TAG, "applying policy " + policy.toString() + " to ifaces " @@ -798,11 +863,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } final boolean hasLimit = policy.limitBytes != LIMIT_DISABLED; - final boolean hasWarning = policy.warningBytes != WARNING_DISABLED; - if (hasLimit) { - // remaining "quota" is based on usage in current cycle - final long quotaBytes = Math.max(0, policy.limitBytes - total); + final long quotaBytes; + if (policy.lastSnooze >= start) { + // snoozing past quota, but we still need to restrict apps, + // so push really high quota. + quotaBytes = Long.MAX_VALUE; + } else { + // remaining "quota" bytes are based on total usage in + // current cycle. kernel doesn't like 0-byte rules, so we + // set 1-byte quota and disable the radio later. + quotaBytes = Math.max(1, policy.limitBytes - totalBytes); + } if (ifaces.length > 1) { // TODO: switch to shared quota once NMS supports @@ -811,10 +883,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { for (String iface : ifaces) { removeInterfaceQuota(iface); - if (quotaBytes > 0) { - setInterfaceQuota(iface, quotaBytes); - newMeteredIfaces.add(iface); - } + setInterfaceQuota(iface, quotaBytes); + newMeteredIfaces.add(iface); } } } @@ -837,6 +907,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { */ private void ensureActiveMobilePolicyLocked() { if (LOGV) Slog.v(TAG, "ensureActiveMobilePolicyLocked()"); + if (mSuppressDefaultPolicy) return; + final String subscriberId = getActiveSubscriberId(); final NetworkIdentity probeIdent = new NetworkIdentity( TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UNKNOWN, subscriberId, false); @@ -1073,6 +1145,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mNetworkPolicy.put(policy.template, policy); } + updateNetworkEnabledLocked(); updateNetworkRulesLocked(); updateNotificationsLocked(); writePolicyLocked(); @@ -1093,14 +1166,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { public void snoozePolicy(NetworkTemplate template) { mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); - // try refreshing time source when stale - if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) { - mTime.forceRefresh(); - } - - final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() - : System.currentTimeMillis(); - + final long currentTime = currentTimeMillis(true); synchronized (mRulesLock) { // find and snooze local policy that matches final NetworkPolicy policy = mNetworkPolicy.get(template); @@ -1110,6 +1176,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { policy.lastSnooze = currentTime; + updateNetworkEnabledLocked(); updateNetworkRulesLocked(); updateNotificationsLocked(); writePolicyLocked(); @@ -1173,22 +1240,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { return null; } - final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() - : System.currentTimeMillis(); + final long currentTime = currentTimeMillis(false); final long start = computeLastCycleBoundary(currentTime, policy); final long end = currentTime; // find total bytes used under policy - long totalBytes = 0; - try { - final NetworkStats stats = mNetworkStats.getSummaryForNetwork( - policy.template, start, end); - final NetworkStats.Entry entry = stats.getValues(0, null); - totalBytes = entry.rxBytes + entry.txBytes; - } catch (RemoteException e) { - Slog.w(TAG, "problem reading summary for template " + policy.template); - } + final long totalBytes = getTotalBytes(policy.template, start, end); + if (totalBytes == UNKNOWN_BYTES) return null; // report soft and hard limits under policy final long softLimitBytes = policy.warningBytes != WARNING_DISABLED ? policy.warningBytes @@ -1481,12 +1540,54 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } + /** + * Control {@link IConnectivityManager#setPolicyDataEnable(int, boolean)}, + * dispatching only when actually changed. + */ + private void setPolicyDataEnable(int networkType, boolean enabled) { + synchronized (mActiveNetworkEnabled) { + final boolean prevEnabled = mActiveNetworkEnabled.get(networkType, true); + if (prevEnabled == enabled) return; + + try { + mConnManager.setPolicyDataEnable(networkType, enabled); + } catch (RemoteException e) { + Slog.e(TAG, "problem setting network enabled", e); + } + + mActiveNetworkEnabled.put(networkType, enabled); + } + } + private String getActiveSubscriberId() { final TelephonyManager telephony = (TelephonyManager) mContext.getSystemService( Context.TELEPHONY_SERVICE); return telephony.getSubscriberId(); } + private static final long UNKNOWN_BYTES = -1; + + private long getTotalBytes(NetworkTemplate template, long start, long end) { + try { + final NetworkStats stats = mNetworkStats.getSummaryForNetwork( + template, start, end); + final NetworkStats.Entry entry = stats.getValues(0, null); + return entry.rxBytes + entry.txBytes; + } catch (RemoteException e) { + Slog.w(TAG, "problem reading summary for template " + template); + return UNKNOWN_BYTES; + } + } + + private long currentTimeMillis(boolean allowRefresh) { + // try refreshing time source when stale + if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE && allowRefresh) { + mTime.forceRefresh(); + } + + return mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); + } + private static Intent buildAllowBackgroundDataIntent() { return new Intent(ACTION_ALLOW_BACKGROUND); } diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index dbb8164..b8797d1 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -187,13 +187,15 @@ public class PackageManagerService extends IPackageManager.Stub { static final int SCAN_NEW_INSTALL = 1<<4; static final int SCAN_NO_PATHS = 1<<5; static final int SCAN_UPDATE_TIME = 1<<6; + static final int SCAN_DEFER_DEX = 1<<7; static final int REMOVE_CHATTY = 1<<16; /** * Whether verification is enabled by default. */ - private static final boolean DEFAULT_VERIFY_ENABLE = true; + // STOPSHIP: change this to true + private static final boolean DEFAULT_VERIFY_ENABLE = false; /** * The default maximum time to wait for the verification agent to return in @@ -349,6 +351,9 @@ public class PackageManagerService extends IPackageManager.Stub { /** List of packages waiting for verification. */ final SparseArray<InstallArgs> mPendingVerification = new SparseArray<InstallArgs>(); + final ArrayList<PackageParser.Package> mDeferredDexOpt = + new ArrayList<PackageParser.Package>(); + /** Token for keys in mPendingVerification. */ private int mPendingVerificationToken = 0; @@ -907,7 +912,7 @@ public class PackageManagerService extends IPackageManager.Stub { // Set flag to monitor and not change apk file paths when // scanning install directories. - int scanMode = SCAN_MONITOR | SCAN_NO_PATHS; + int scanMode = SCAN_MONITOR | SCAN_NO_PATHS | SCAN_DEFER_DEX; if (mNoDexOpt) { Slog.w(TAG, "Running ENG build: no pre-dexopt!"); scanMode |= SCAN_NO_DEX; @@ -2899,6 +2904,33 @@ public class PackageManagerService extends IPackageManager.Stub { } } + public void performBootDexOpt() { + ArrayList<PackageParser.Package> pkgs = null; + synchronized (mPackages) { + if (mDeferredDexOpt.size() > 0) { + pkgs = new ArrayList<PackageParser.Package>(mDeferredDexOpt); + mDeferredDexOpt.clear(); + } + } + if (pkgs != null) { + for (int i=0; i<pkgs.size(); i++) { + try { + ActivityManagerNative.getDefault().showBootMessage( + mContext.getResources().getString( + com.android.internal.R.string.android_upgrading_apk, + i+1, pkgs.size()), true); + } catch (RemoteException e) { + } + PackageParser.Package p = pkgs.get(i); + synchronized (mInstallLock) { + if (!p.mDidDexOpt) { + performDexOptLI(p, false, false); + } + } + } + } + } + public boolean performDexOpt(String packageName) { enforceSystemOrRoot("Only the system can request dexopt be performed"); @@ -2914,25 +2946,32 @@ public class PackageManagerService extends IPackageManager.Stub { } } synchronized (mInstallLock) { - return performDexOptLI(p, false) == DEX_OPT_PERFORMED; + return performDexOptLI(p, false, false) == DEX_OPT_PERFORMED; } } static final int DEX_OPT_SKIPPED = 0; static final int DEX_OPT_PERFORMED = 1; + static final int DEX_OPT_DEFERRED = 2; static final int DEX_OPT_FAILED = -1; - private int performDexOptLI(PackageParser.Package pkg, boolean forceDex) { + private int performDexOptLI(PackageParser.Package pkg, boolean forceDex, boolean defer) { boolean performed = false; if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) { String path = pkg.mScanPath; int ret = 0; try { if (forceDex || dalvik.system.DexFile.isDexOptNeeded(path)) { - ret = mInstaller.dexopt(path, pkg.applicationInfo.uid, - !isForwardLocked(pkg)); - pkg.mDidDexOpt = true; - performed = true; + if (!forceDex && defer) { + mDeferredDexOpt.add(pkg); + return DEX_OPT_DEFERRED; + } else { + Log.i(TAG, "Running dexopt on: " + pkg.applicationInfo.packageName); + ret = mInstaller.dexopt(path, pkg.applicationInfo.uid, + !isForwardLocked(pkg)); + pkg.mDidDexOpt = true; + performed = true; + } } } catch (FileNotFoundException e) { Slog.w(TAG, "Apk not found for dexopt: " + path); @@ -3487,7 +3526,8 @@ public class PackageManagerService extends IPackageManager.Stub { pkg.mScanPath = path; if ((scanMode&SCAN_NO_DEX) == 0) { - if (performDexOptLI(pkg, forceDex) == DEX_OPT_FAILED) { + if (performDexOptLI(pkg, forceDex, (scanMode&SCAN_DEFER_DEX) != 0) + == DEX_OPT_FAILED) { mLastScanError = PackageManager.INSTALL_FAILED_DEXOPT; return null; } diff --git a/services/java/com/android/server/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java index a01c975..8f51466 100644 --- a/services/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/java/com/android/server/usb/UsbDeviceManager.java @@ -568,12 +568,9 @@ public class UsbDeviceManager { notification.sound = null; notification.vibrate = null; - Intent intent = new Intent( - Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | - Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); - intent.setComponent(new ComponentName("com.android.settings", - "com.android.settings.UsbSettings")); + Intent intent = Intent.makeRestartActivityTask( + new ComponentName("com.android.settings", + "com.android.settings.UsbSettings")); PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0); notification.setLatestEventInfo(mContext, title, message, pi); @@ -604,12 +601,9 @@ public class UsbDeviceManager { notification.sound = null; notification.vibrate = null; - Intent intent = new Intent( - Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | - Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); - intent.setComponent(new ComponentName("com.android.settings", - "com.android.settings.DevelopmentSettings")); + Intent intent = Intent.makeRestartActivityTask( + new ComponentName("com.android.settings", + "com.android.settings.DevelopmentSettings")); PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0); notification.setLatestEventInfo(mContext, title, message, pi); diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 8fd4f95..e258b1a 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -53,7 +53,6 @@ import android.app.IActivityManager; import android.app.StatusBarManager; import android.app.admin.DevicePolicyManager; import android.content.BroadcastReceiver; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -163,6 +162,8 @@ public class WindowManagerService extends IWindowManager.Stub static final boolean DEBUG_REORDER = false; static final boolean DEBUG_WALLPAPER = false; static final boolean DEBUG_DRAG = false; + static final boolean DEBUG_SCREEN_ON = false; + static final boolean DEBUG_SCREENSHOT = false; static final boolean SHOW_SURFACE_ALLOC = false; static final boolean SHOW_TRANSACTIONS = false; static final boolean HIDE_STACK_CRAWLS = true; @@ -407,6 +408,8 @@ public class WindowManagerService extends IWindowManager.Stub boolean mSafeMode; boolean mDisplayEnabled = false; boolean mSystemBooted = false; + boolean mForceDisplayEnabled = false; + boolean mShowingBootMessages = false; int mInitialDisplayWidth = 0; int mInitialDisplayHeight = 0; int mBaseDisplayWidth = 0; @@ -2187,7 +2190,7 @@ public class WindowManagerService extends IWindowManager.Stub // to hold off on removing the window until the animation is done. // If the display is frozen, just remove immediately, since the // animation wouldn't be seen. - if (win.mSurface != null && !mDisplayFrozen && mPolicy.isScreenOn()) { + if (win.mSurface != null && !mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOn()) { // If we are not currently running the exit animation, we // need to see about starting one. if (wasVisible=win.isWinVisibleLw()) { @@ -2534,6 +2537,12 @@ public class WindowManagerService extends IWindowManager.Stub win.mRelayoutCalled = true; final int oldVisibility = win.mViewVisibility; win.mViewVisibility = viewVisibility; + if (DEBUG_SCREEN_ON) { + RuntimeException stack = new RuntimeException(); + stack.fillInStackTrace(); + Slog.i(TAG, "Relayout " + win + ": oldVis=" + oldVisibility + + " newVis=" + viewVisibility, stack); + } if (viewVisibility == View.VISIBLE && (win.mAppToken == null || !win.mAppToken.clientHidden)) { displayed = !win.isVisibleLw(); @@ -2554,7 +2563,7 @@ public class WindowManagerService extends IWindowManager.Stub if (displayed) { if (win.mSurface != null && !win.mDrawPending && !win.mCommitDrawPending && !mDisplayFrozen - && mPolicy.isScreenOn()) { + && mDisplayEnabled && mPolicy.isScreenOn()) { applyEnterAnimationLocked(win); } if ((win.mAttrs.flags @@ -2847,7 +2856,7 @@ public class WindowManagerService extends IWindowManager.Stub // frozen, there is no reason to animate and it can cause strange // artifacts when we unfreeze the display if some different animation // is running. - if (!mDisplayFrozen && mPolicy.isScreenOn()) { + if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOn()) { int anim = mPolicy.selectAnimationLw(win, transit); int attr = -1; Animation a = null; @@ -2933,7 +2942,7 @@ public class WindowManagerService extends IWindowManager.Stub // frozen, there is no reason to animate and it can cause strange // artifacts when we unfreeze the display if some different animation // is running. - if (!mDisplayFrozen && mPolicy.isScreenOn()) { + if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOn()) { Animation a; if (mNextAppTransitionPackage != null) { a = loadAnimation(mNextAppTransitionPackage, enter ? @@ -3499,7 +3508,7 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_APP_TRANSITIONS) Slog.v( TAG, "Prepare app transition: transit=" + transit + " mNextAppTransition=" + mNextAppTransition); - if (!mDisplayFrozen && mPolicy.isScreenOn()) { + if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOn()) { if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET || mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) { mNextAppTransition = transit; @@ -3583,7 +3592,7 @@ public class WindowManagerService extends IWindowManager.Stub // If the display is frozen, we won't do anything until the // actual window is displayed so there is no reason to put in // the starting window. - if (mDisplayFrozen || !mPolicy.isScreenOn()) { + if (mDisplayFrozen || !mDisplayEnabled || !mPolicy.isScreenOn()) { return; } @@ -3865,7 +3874,7 @@ public class WindowManagerService extends IWindowManager.Stub // If we are preparing an app transition, then delay changing // the visibility of this token until we execute that transition. - if (!mDisplayFrozen && mPolicy.isScreenOn() + if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOn() && mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { // Already in requested state, don't do anything more. if (wtoken.hiddenRequested != visible) { @@ -4685,43 +4694,95 @@ public class WindowManagerService extends IWindowManager.Stub return; } mSystemBooted = true; + hideBootMessagesLocked(); + // If the screen still doesn't come up after 30 seconds, give + // up and turn it on. + Message msg = mH.obtainMessage(H.BOOT_TIMEOUT); + mH.sendMessageDelayed(msg, 30*1000); } performEnableScreen(); } - public void enableScreenIfNeededLocked() { + void enableScreenIfNeededLocked() { if (mDisplayEnabled) { return; } - if (!mSystemBooted) { + if (!mSystemBooted && !mShowingBootMessages) { return; } mH.sendMessage(mH.obtainMessage(H.ENABLE_SCREEN)); } + public void performBootTimeout() { + synchronized(mWindowMap) { + if (mDisplayEnabled) { + return; + } + Slog.w(TAG, "***** BOOT TIMEOUT: forcing display enabled"); + mForceDisplayEnabled = true; + } + performEnableScreen(); + } + public void performEnableScreen() { synchronized(mWindowMap) { if (mDisplayEnabled) { return; } - if (!mSystemBooted) { + if (!mSystemBooted && !mShowingBootMessages) { return; } - // Don't enable the screen until all existing windows - // have been drawn. - final int N = mWindows.size(); - for (int i=0; i<N; i++) { - WindowState w = mWindows.get(i); - if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) { + if (!mForceDisplayEnabled) { + // Don't enable the screen until all existing windows + // have been drawn. + boolean haveBootMsg = false; + boolean haveApp = false; + boolean haveWallpaper = false; + boolean haveKeyguard = false; + final int N = mWindows.size(); + for (int i=0; i<N; i++) { + WindowState w = mWindows.get(i); + if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) { + return; + } + if (w.isDrawnLw()) { + if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_BOOT_PROGRESS) { + haveBootMsg = true; + } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION) { + haveApp = true; + } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_WALLPAPER) { + haveWallpaper = true; + } else if (w.mAttrs.type == WindowManager.LayoutParams.TYPE_KEYGUARD) { + haveKeyguard = true; + } + } + } + + if (DEBUG_SCREEN_ON) { + Slog.i(TAG, "******** booted=" + mSystemBooted + " msg=" + mShowingBootMessages + + " haveBoot=" + haveBootMsg + " haveApp=" + haveApp + + " haveWall=" + haveWallpaper + " haveKeyguard=" + haveKeyguard); + } + + // If we are turning on the screen to show the boot message, + // don't do it until the boot message is actually displayed. + if (!mSystemBooted && !haveBootMsg) { + return; + } + + // If we are turning on the screen after the boot is completed + // normally, don't do so until we have the application and + // wallpaper. + if (mSystemBooted && ((!haveApp && !haveKeyguard) || !haveWallpaper)) { return; } } mDisplayEnabled = true; + if (DEBUG_SCREEN_ON) Slog.i(TAG, "******************** ENABLING SCREEN!"); if (false) { - Slog.i(TAG, "ENABLING SCREEN!"); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); this.dump(null, pw, null); @@ -4749,6 +4810,33 @@ public class WindowManagerService extends IWindowManager.Stub mLastRotationFlags | Surface.FLAGS_ORIENTATION_ANIMATION_DISABLE); } + public void showBootMessage(final CharSequence msg, final boolean always) { + boolean first = false; + synchronized(mWindowMap) { + if (!mShowingBootMessages) { + if (!always) { + return; + } + first = true; + } + if (mSystemBooted) { + return; + } + mShowingBootMessages = true; + mPolicy.showBootMessage(msg, always); + } + if (first) { + performEnableScreen(); + } + } + + public void hideBootMessagesLocked() { + if (mShowingBootMessages) { + mShowingBootMessages = false; + mPolicy.hideBootMessages(); + } + } + public void setInTouchMode(boolean mode) { synchronized(mWindowMap) { mInTouchMode = mode; @@ -4909,6 +4997,14 @@ public class WindowManagerService extends IWindowManager.Stub dh = tmp; rot = (rot == Surface.ROTATION_90) ? Surface.ROTATION_270 : Surface.ROTATION_90; } + if (DEBUG_SCREENSHOT) { + Slog.i(TAG, "Screenshot: " + dw + "x" + dh + " from 0 to " + maxLayer); + for (int i=0; i<mWindows.size(); i++) { + Slog.i(TAG, mWindows.get(i) + ": " + mWindows.get(i).mLayer + + " animLayer=" + mWindows.get(i).mAnimLayer + + " surfaceLayer=" + mWindows.get(i).mSurfaceLayer); + } + } rawss = Surface.screenshot(dw, dh, 0, maxLayer); } @@ -6136,7 +6232,7 @@ public class WindowManagerService extends IWindowManager.Stub return mSafeMode; } - public void systemReady() { + public void displayReady() { synchronized(mWindowMap) { if (mDisplay != null) { throw new IllegalStateException("Display already initialized"); @@ -6165,14 +6261,16 @@ public class WindowManagerService extends IWindowManager.Stub mActivityManager.updateConfiguration(null); } catch (RemoteException e) { } - - mPolicy.systemReady(); - + synchronized (mWindowMap) { readForcedDisplaySizeLocked(); } } + public void systemReady() { + mPolicy.systemReady(); + } + // This is an animation that does nothing: it just immediately finishes // itself every time it is called. It is used as a stub animation in cases // where we want to synchronize multiple things that may be animating. @@ -6207,6 +6305,7 @@ public class WindowManagerService extends IWindowManager.Stub public static final int DRAG_START_TIMEOUT = 20; public static final int DRAG_END_TIMEOUT = 21; public static final int REPORT_HARD_KEYBOARD_STATUS_CHANGE = 22; + public static final int BOOT_TIMEOUT = 23; private Session mLastReportedHold; @@ -6517,6 +6616,11 @@ public class WindowManagerService extends IWindowManager.Stub break; } + case BOOT_TIMEOUT: { + performBootTimeout(); + break; + } + case APP_FREEZE_TIMEOUT: { synchronized (mWindowMap) { Slog.w(TAG, "App freeze timeout expired."); @@ -8268,7 +8372,7 @@ public class WindowManagerService extends IWindowManager.Stub if (mDimAnimator != null && mDimAnimator.mDimShown) { animating |= mDimAnimator.updateSurface(dimming, currentTime, - mDisplayFrozen || !mPolicy.isScreenOn()); + mDisplayFrozen || !mDisplayEnabled || !mPolicy.isScreenOn()); } if (!blurring && mBlurShown) { @@ -8466,12 +8570,44 @@ public class WindowManagerService extends IWindowManager.Stub mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); } } - + + mWindowMap.notifyAll(); + // Check to see if we are now in a state where the screen should // be enabled, because the window obscured flags have changed. enableScreenIfNeededLocked(); } - + + public void waitForAllDrawn() { + synchronized (mWindowMap) { + while (true) { + final int N = mWindows.size(); + boolean okay = true; + for (int i=0; i<N && okay; i++) { + WindowState w = mWindows.get(i); + if (DEBUG_SCREEN_ON) { + Slog.i(TAG, "Window " + w + " vis=" + w.isVisibleLw() + + " obscured=" + w.mObscured + " drawn=" + w.isDrawnLw()); + } + if (w.isVisibleLw() && !w.mObscured && !w.isDrawnLw()) { + if (DEBUG_SCREEN_ON) { + Slog.i(TAG, "Window not yet drawn: " + w); + } + okay = false; + break; + } + } + if (okay) { + return; + } + try { + mWindowMap.wait(); + } catch (InterruptedException e) { + } + } + } + } + /** * Must be called with the main window manager lock held. */ diff --git a/services/sensorservice/Fusion.cpp b/services/sensorservice/Fusion.cpp index ff4786b..0ab86c3 100644 --- a/services/sensorservice/Fusion.cpp +++ b/services/sensorservice/Fusion.cpp @@ -47,9 +47,46 @@ static const float biasVAR = 1e-8; // (rad/s)^2 / s (guessed) static const float accSTDEV = 0.05f; // m/s^2 (measured 0.08 / CDD 0.05) static const float magSTDEV = 0.5f; // uT (measured 0.7 / CDD 0.5) -static const float FREE_FALL_THRESHOLD = 0.981f; static const float SYMMETRY_TOLERANCE = 1e-10f; +/* + * Accelerometer updates will not be performed near free fall to avoid + * ill-conditioning and div by zeros. + * Threshhold: 10% of g, in m/s^2 + */ +static const float FREE_FALL_THRESHOLD = 0.981f; +static const float FREE_FALL_THRESHOLD_SQ = + FREE_FALL_THRESHOLD*FREE_FALL_THRESHOLD; + +/* + * The geomagnetic-field should be between 30uT and 60uT. + * Fields strengths greater than this likely indicate a local magnetic + * disturbance which we do not want to update into the fused frame. + */ +static const float MAX_VALID_MAGNETIC_FIELD = 100; // uT +static const float MAX_VALID_MAGNETIC_FIELD_SQ = + MAX_VALID_MAGNETIC_FIELD*MAX_VALID_MAGNETIC_FIELD; + +/* + * Values of the field smaller than this should be ignored in fusion to avoid + * ill-conditioning. This state can happen with anomalous local magnetic + * disturbances canceling the Earth field. + */ +static const float MIN_VALID_MAGNETIC_FIELD = 10; // uT +static const float MIN_VALID_MAGNETIC_FIELD_SQ = + MIN_VALID_MAGNETIC_FIELD*MIN_VALID_MAGNETIC_FIELD; + +/* + * If the cross product of two vectors has magnitude squared less than this, + * we reject it as invalid due to alignment of the vectors. + * This threshold is used to check for the case where the magnetic field sample + * is parallel to the gravity field, which can happen in certain places due + * to magnetic field disturbances. + */ +static const float MIN_VALID_CROSS_PRODUCT_MAG = 1.0e-3; +static const float MIN_VALID_CROSS_PRODUCT_MAG_SQ = + MIN_VALID_CROSS_PRODUCT_MAG*MIN_VALID_CROSS_PRODUCT_MAG; + // ----------------------------------------------------------------------- template <typename TYPE, size_t C, size_t R> @@ -240,8 +277,9 @@ void Fusion::handleGyro(const vec3_t& w, float dT) { status_t Fusion::handleAcc(const vec3_t& a) { // ignore acceleration data if we're close to free-fall - if (length(a) < FREE_FALL_THRESHOLD) + if (length_squared(a) < FREE_FALL_THRESHOLD_SQ) { return BAD_VALUE; + } if (!checkInitComplete(ACC, a)) return BAD_VALUE; @@ -253,15 +291,34 @@ status_t Fusion::handleAcc(const vec3_t& a) { status_t Fusion::handleMag(const vec3_t& m) { // the geomagnetic-field should be between 30uT and 60uT - // reject obviously wrong magnetic-fields - if (length(m) > 100) + // reject if too large to avoid spurious magnetic sources + const float magFieldSq = length_squared(m); + if (magFieldSq > MAX_VALID_MAGNETIC_FIELD_SQ) { + return BAD_VALUE; + } else if (magFieldSq < MIN_VALID_MAGNETIC_FIELD_SQ) { + // Also reject if too small since we will get ill-defined (zero mag) + // cross-products below return BAD_VALUE; + } if (!checkInitComplete(MAG, m)) return BAD_VALUE; + // Orthogonalize the magnetic field to the gravity field, mapping it into + // tangent to Earth. const vec3_t up( getRotationMatrix() * Ba ); const vec3_t east( cross_product(m, up) ); + + // If the m and up vectors align, the cross product magnitude will + // approach 0. + // Reject this case as well to avoid div by zero problems and + // ill-conditioning below. + if (length_squared(east) < MIN_VALID_CROSS_PRODUCT_MAG_SQ) { + return BAD_VALUE; + } + + // If we have created an orthogonal magnetic field successfully, + // then pass it in as the update. vec3_t north( cross_product(up, east) ); const float l = 1 / length(north); diff --git a/services/sensorservice/vec.h b/services/sensorservice/vec.h index f74ccc5..24f30ff 100644 --- a/services/sensorservice/vec.h +++ b/services/sensorservice/vec.h @@ -212,6 +212,15 @@ template < typename TYPE, size_t SIZE > +TYPE PURE length_squared(const V<TYPE, SIZE>& v) { + return dot_product(v, v); +} + +template < + template<typename T, size_t S> class V, + typename TYPE, + size_t SIZE +> V<TYPE, SIZE> PURE normalize(const V<TYPE, SIZE>& v) { return v * (1/length(v)); } diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 19c7ddd..f8925b8 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -244,9 +244,6 @@ void Layer::setPerFrameData(hwc_layer_t* hwcl) { } } -static inline uint16_t pack565(int r, int g, int b) { - return (r<<11)|(g<<5)|b; -} void Layer::onDraw(const Region& clip) const { if (CC_UNLIKELY(mActiveBuffer == 0)) { @@ -260,7 +257,8 @@ void Layer::onDraw(const Region& clip) const // figure out if there is something below us Region under; - const SurfaceFlinger::LayerVector& drawingLayers(mFlinger->mDrawingState.layersSortedByZ); + const SurfaceFlinger::LayerVector& drawingLayers( + mFlinger->mDrawingState.layersSortedByZ); const size_t count = drawingLayers.size(); for (size_t i=0 ; i<count ; ++i) { const sp<LayerBase>& layer(drawingLayers[i]); @@ -276,7 +274,7 @@ void Layer::onDraw(const Region& clip) const return; } - GLenum target = mSurfaceTexture->getCurrentTextureTarget(); + const GLenum target = GL_TEXTURE_EXTERNAL_OES; glBindTexture(target, mTextureName); if (getFiltering() || needsFiltering() || isFixedSize() || isCropped()) { // TODO: we could be more subtle with isFixedSize() @@ -439,9 +437,8 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) recomputeVisibleRegions = true; } - const GLenum target(mSurfaceTexture->getCurrentTextureTarget()); - glTexParameterx(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterx(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); // update the layer size and release freeze-lock const Layer::State& front(drawingState()); @@ -541,9 +538,9 @@ void Layer::dump(String8& result, char* buffer, size_t SIZE) const snprintf(buffer, SIZE, " " "format=%2d, activeBuffer=[%4ux%4u:%4u,%3X]," - " freezeLock=%p, queued-frames=%d\n", + " freezeLock=%p, transform-hint=0x%02x, queued-frames=%d\n", mFormat, w0, h0, s0,f0, - getFreezeLock().get(), mQueuedFrames); + getFreezeLock().get(), getTransformHint(), mQueuedFrames); result.append(buffer); @@ -559,9 +556,21 @@ uint32_t Layer::getEffectiveUsage(uint32_t usage) const // need a hardware-protected path to external video sink usage |= GraphicBuffer::USAGE_PROTECTED; } + usage |= GraphicBuffer::USAGE_HW_COMPOSER; return usage; } +uint32_t Layer::getTransformHint() const { + uint32_t orientation = 0; + if (!mFlinger->mDebugDisableTransformHint) { + orientation = getOrientation(); + if (orientation & Transform::ROT_INVALID) { + orientation = 0; + } + } + return orientation; +} + // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 5f0be80..d06a35f 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -89,6 +89,7 @@ private: void onFrameQueued(); virtual sp<ISurface> createSurface(); uint32_t getEffectiveUsage(uint32_t usage) const; + uint32_t getTransformHint() const; bool isCropped() const; static bool getOpacityForFormat(uint32_t format); diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 50afb3d..6fde361 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -93,6 +93,7 @@ SurfaceFlinger::SurfaceFlinger() mDebugBackground(0), mDebugDDMS(0), mDebugDisableHWC(0), + mDebugDisableTransformHint(0), mDebugInSwapBuffers(0), mLastSwapBufferTime(0), mDebugInTransaction(0), @@ -822,7 +823,7 @@ void SurfaceFlinger::handleWorkList() hwc_layer_t* const cur(hwc.getLayers()); for (size_t i=0 ; cur && i<count ; i++) { currentLayers[i]->setGeometry(&cur[i]); - if (mDebugDisableHWC) { + if (mDebugDisableHWC || mDebugRegion) { cur[i].compositionType = HWC_FRAMEBUFFER; cur[i].flags |= HWC_SKIP_LAYER; } @@ -974,6 +975,10 @@ void SurfaceFlinger::debugFlashRegions() { const DisplayHardware& hw(graphicPlane(0).displayHardware()); const uint32_t flags = hw.getFlags(); + const int32_t height = hw.getHeight(); + if (mInvalidRegion.isEmpty()) { + return; + } if (!((flags & DisplayHardware::SWAP_RECTANGLE) || (flags & DisplayHardware::BUFFER_PRESERVED))) { @@ -999,26 +1004,21 @@ void SurfaceFlinger::debugFlashRegions() while (it != end) { const Rect& r = *it++; GLfloat vertices[][2] = { - { r.left, r.top }, - { r.left, r.bottom }, - { r.right, r.bottom }, - { r.right, r.top } + { r.left, height - r.top }, + { r.left, height - r.bottom }, + { r.right, height - r.bottom }, + { r.right, height - r.top } }; glVertexPointer(2, GL_FLOAT, 0, vertices); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } - if (mInvalidRegion.isEmpty()) { - mDirtyRegion.dump("mDirtyRegion"); - mInvalidRegion.dump("mInvalidRegion"); - } hw.flip(mInvalidRegion); if (mDebugRegion > 1) usleep(mDebugRegion * 1000); glEnable(GL_SCISSOR_TEST); - //mDirtyRegion.dump("mDirtyRegion"); } void SurfaceFlinger::drawWormhole() const @@ -1581,7 +1581,7 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) HWComposer& hwc(hw.getHwComposer()); snprintf(buffer, SIZE, " h/w composer %s and %s\n", hwc.initCheck()==NO_ERROR ? "present" : "not present", - mDebugDisableHWC ? "disabled" : "enabled"); + (mDebugDisableHWC || mDebugRegion) ? "disabled" : "enabled"); result.append(buffer); hwc.dump(result, buffer, SIZE); @@ -1660,21 +1660,15 @@ status_t SurfaceFlinger::onTransact( case 1002: // SHOW_UPDATES n = data.readInt32(); mDebugRegion = n ? n : (mDebugRegion ? 0 : 1); + invalidateHwcGeometry(); + repaintEverything(); return NO_ERROR; case 1003: // SHOW_BACKGROUND n = data.readInt32(); mDebugBackground = n ? 1 : 0; return NO_ERROR; - case 1008: // toggle use of hw composer - n = data.readInt32(); - mDebugDisableHWC = n ? 1 : 0; - invalidateHwcGeometry(); - // fall-through... case 1004:{ // repaint everything - Mutex::Autolock _l(mStateLock); - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - mDirtyRegion.set(hw.bounds()); // careful that's not thread-safe - signalEvent(); + repaintEverything(); return NO_ERROR; } case 1005:{ // force transaction @@ -1690,6 +1684,18 @@ status_t SurfaceFlinger::onTransact( mFreezeCount = data.readInt32(); mFreezeDisplayTime = 0; return NO_ERROR; + case 1008: // toggle use of hw composer + n = data.readInt32(); + mDebugDisableHWC = n ? 1 : 0; + invalidateHwcGeometry(); + repaintEverything(); + return NO_ERROR; + case 1009: // toggle use of transform hint + n = data.readInt32(); + mDebugDisableTransformHint = n ? 1 : 0; + invalidateHwcGeometry(); + repaintEverything(); + return NO_ERROR; case 1010: // interrogate. reply->writeInt32(0); reply->writeInt32(0); @@ -1707,6 +1713,13 @@ status_t SurfaceFlinger::onTransact( return err; } +void SurfaceFlinger::repaintEverything() { + Mutex::Autolock _l(mStateLock); + const DisplayHardware& hw(graphicPlane(0).displayHardware()); + mDirtyRegion.set(hw.bounds()); // careful that's not thread-safe + signalEvent(); +} + // --------------------------------------------------------------------------- status_t SurfaceFlinger::renderScreenToTextureLocked(DisplayID dpy, @@ -2194,7 +2207,7 @@ status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, return BAD_VALUE; // make sure none of the layers are protected - const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ); + const LayerVector& layers(mDrawingState.layersSortedByZ); const size_t count = layers.size(); for (size_t i=0 ; i<count ; ++i) { const sp<LayerBase>& layer(layers[i]); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 1738238..5f8eb08 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -278,6 +278,7 @@ private: void handleRepaint(); void postFramebuffer(); void composeSurfaces(const Region& dirty); + void repaintEverything(); ssize_t addClientLayer(const sp<Client>& client, @@ -373,6 +374,7 @@ private: int mDebugBackground; int mDebugDDMS; int mDebugDisableHWC; + int mDebugDisableTransformHint; volatile nsecs_t mDebugInSwapBuffers; nsecs_t mLastSwapBufferTime; volatile nsecs_t mDebugInTransaction; diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp index 79cd0c3..4390ca1 100644 --- a/services/surfaceflinger/SurfaceTextureLayer.cpp +++ b/services/surfaceflinger/SurfaceTextureLayer.cpp @@ -57,16 +57,10 @@ status_t SurfaceTextureLayer::queueBuffer(int buf, int64_t timestamp, status_t res = SurfaceTexture::queueBuffer(buf, timestamp, outWidth, outHeight, outTransform); - sp<Layer> layer(mLayer.promote()); if (layer != NULL) { - uint32_t orientation = layer->getOrientation(); - if (orientation & Transform::ROT_INVALID) { - orientation = 0; - } - *outTransform = orientation; + *outTransform = layer->getTransformHint(); } - return res; } diff --git a/services/surfaceflinger/TextureManager.cpp b/services/surfaceflinger/TextureManager.cpp deleted file mode 100644 index bb63c37..0000000 --- a/services/surfaceflinger/TextureManager.cpp +++ /dev/null @@ -1,341 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <stdlib.h> -#include <stdint.h> -#include <sys/types.h> - -#include <utils/Errors.h> -#include <utils/Log.h> - -#include <ui/GraphicBuffer.h> - -#include <GLES/gl.h> -#include <GLES/glext.h> - -#include <hardware/hardware.h> - -#include "clz.h" -#include "DisplayHardware/DisplayHardware.h" -#include "GLExtensions.h" -#include "TextureManager.h" - -namespace android { - -// --------------------------------------------------------------------------- - -TextureManager::TextureManager() - : mGLExtensions(GLExtensions::getInstance()) -{ -} - -GLenum TextureManager::getTextureTarget(const Image* image) { -#if defined(GL_OES_EGL_image_external) - switch (image->target) { - case Texture::TEXTURE_EXTERNAL: - return GL_TEXTURE_EXTERNAL_OES; - } -#endif - return GL_TEXTURE_2D; -} - -status_t TextureManager::initTexture(Texture* texture) -{ - if (texture->name != -1UL) - return INVALID_OPERATION; - - GLuint textureName = -1; - glGenTextures(1, &textureName); - texture->name = textureName; - texture->width = 0; - texture->height = 0; - - const GLenum target = GL_TEXTURE_2D; - glBindTexture(target, textureName); - glTexParameterx(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterx(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - return NO_ERROR; -} - -status_t TextureManager::initTexture(Image* pImage, int32_t format) -{ - if (pImage->name != -1UL) - return INVALID_OPERATION; - - GLuint textureName = -1; - glGenTextures(1, &textureName); - pImage->name = textureName; - pImage->width = 0; - pImage->height = 0; - - GLenum target = GL_TEXTURE_2D; -#if defined(GL_OES_EGL_image_external) - if (GLExtensions::getInstance().haveTextureExternal()) { - if (format && isYuvFormat(format)) { - target = GL_TEXTURE_EXTERNAL_OES; - pImage->target = Texture::TEXTURE_EXTERNAL; - } - } -#endif - - glBindTexture(target, textureName); - glTexParameterx(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterx(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - - return NO_ERROR; -} - -bool TextureManager::isSupportedYuvFormat(int format) -{ - switch (format) { - case HAL_PIXEL_FORMAT_YV12: - return true; - } - return false; -} - -bool TextureManager::isYuvFormat(int format) -{ - switch (format) { - // supported YUV formats - case HAL_PIXEL_FORMAT_YV12: - // Legacy/deprecated YUV formats - case HAL_PIXEL_FORMAT_YCbCr_422_SP: - case HAL_PIXEL_FORMAT_YCrCb_420_SP: - case HAL_PIXEL_FORMAT_YCbCr_422_I: - return true; - } - - // Any OEM format needs to be considered - if (format>=0x100 && format<=0x1FF) - return true; - - return false; -} - -status_t TextureManager::initEglImage(Image* pImage, - EGLDisplay dpy, const sp<GraphicBuffer>& buffer) -{ - status_t err = NO_ERROR; - if (!pImage->dirty) return err; - - // free the previous image - if (pImage->image != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(dpy, pImage->image); - pImage->image = EGL_NO_IMAGE_KHR; - } - - // construct an EGL_NATIVE_BUFFER_ANDROID - ANativeWindowBuffer* clientBuf = buffer->getNativeBuffer(); - - // create the new EGLImageKHR - const EGLint attrs[] = { - EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, - EGL_NONE, EGL_NONE - }; - pImage->image = eglCreateImageKHR( - dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, - (EGLClientBuffer)clientBuf, attrs); - - if (pImage->image != EGL_NO_IMAGE_KHR) { - if (pImage->name == -1UL) { - initTexture(pImage, buffer->format); - } - const GLenum target = getTextureTarget(pImage); - glBindTexture(target, pImage->name); - glEGLImageTargetTexture2DOES(target, (GLeglImageOES)pImage->image); - GLint error = glGetError(); - if (error != GL_NO_ERROR) { - LOGE("glEGLImageTargetTexture2DOES(%p) failed err=0x%04x", - pImage->image, error); - err = INVALID_OPERATION; - } else { - // Everything went okay! - pImage->dirty = false; - pImage->width = clientBuf->width; - pImage->height = clientBuf->height; - } - } else { - LOGE("eglCreateImageKHR() failed. err=0x%4x", eglGetError()); - err = INVALID_OPERATION; - } - return err; -} - -status_t TextureManager::loadTexture(Texture* texture, - const Region& dirty, const GGLSurface& t) -{ - if (texture->name == -1UL) { - status_t err = initTexture(texture); - LOGE_IF(err, "loadTexture failed in initTexture (%s)", strerror(err)); - if (err != NO_ERROR) return err; - } - - if (texture->target != Texture::TEXTURE_2D) - return INVALID_OPERATION; - - glBindTexture(GL_TEXTURE_2D, texture->name); - - /* - * In OpenGL ES we can't specify a stride with glTexImage2D (however, - * GL_UNPACK_ALIGNMENT is a limited form of stride). - * So if the stride here isn't representable with GL_UNPACK_ALIGNMENT, we - * need to do something reasonable (here creating a bigger texture). - * - * extra pixels = (((stride - width) * pixelsize) / GL_UNPACK_ALIGNMENT); - * - * This situation doesn't happen often, but some h/w have a limitation - * for their framebuffer (eg: must be multiple of 8 pixels), and - * we need to take that into account when using these buffers as - * textures. - * - * This should never be a problem with POT textures - */ - - int unpack = __builtin_ctz(t.stride * bytesPerPixel(t.format)); - unpack = 1 << ((unpack > 3) ? 3 : unpack); - glPixelStorei(GL_UNPACK_ALIGNMENT, unpack); - - /* - * round to POT if needed - */ - if (!mGLExtensions.haveNpot()) { - texture->NPOTAdjust = true; - } - - if (texture->NPOTAdjust) { - // find the smallest power-of-two that will accommodate our surface - texture->potWidth = 1 << (31 - clz(t.width)); - texture->potHeight = 1 << (31 - clz(t.height)); - if (texture->potWidth < t.width) texture->potWidth <<= 1; - if (texture->potHeight < t.height) texture->potHeight <<= 1; - texture->wScale = float(t.width) / texture->potWidth; - texture->hScale = float(t.height) / texture->potHeight; - } else { - texture->potWidth = t.width; - texture->potHeight = t.height; - } - - Rect bounds(dirty.bounds()); - GLvoid* data = 0; - if (texture->width != t.width || texture->height != t.height) { - texture->width = t.width; - texture->height = t.height; - - // texture size changed, we need to create a new one - bounds.set(Rect(t.width, t.height)); - if (t.width == texture->potWidth && - t.height == texture->potHeight) { - // we can do it one pass - data = t.data; - } - - if (t.format == HAL_PIXEL_FORMAT_RGB_565) { - glTexImage2D(GL_TEXTURE_2D, 0, - GL_RGB, texture->potWidth, texture->potHeight, 0, - GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data); - } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) { - glTexImage2D(GL_TEXTURE_2D, 0, - GL_RGBA, texture->potWidth, texture->potHeight, 0, - GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, data); - } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 || - t.format == HAL_PIXEL_FORMAT_RGBX_8888) { - glTexImage2D(GL_TEXTURE_2D, 0, - GL_RGBA, texture->potWidth, texture->potHeight, 0, - GL_RGBA, GL_UNSIGNED_BYTE, data); - } else if (isSupportedYuvFormat(t.format)) { - // just show the Y plane of YUV buffers - glTexImage2D(GL_TEXTURE_2D, 0, - GL_LUMINANCE, texture->potWidth, texture->potHeight, 0, - GL_LUMINANCE, GL_UNSIGNED_BYTE, data); - } else { - // oops, we don't handle this format! - LOGE("texture=%d, using format %d, which is not " - "supported by the GL", texture->name, t.format); - } - } - if (!data) { - if (t.format == HAL_PIXEL_FORMAT_RGB_565) { - glTexSubImage2D(GL_TEXTURE_2D, 0, - 0, bounds.top, t.width, bounds.height(), - GL_RGB, GL_UNSIGNED_SHORT_5_6_5, - t.data + bounds.top*t.stride*2); - } else if (t.format == HAL_PIXEL_FORMAT_RGBA_4444) { - glTexSubImage2D(GL_TEXTURE_2D, 0, - 0, bounds.top, t.width, bounds.height(), - GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4, - t.data + bounds.top*t.stride*2); - } else if (t.format == HAL_PIXEL_FORMAT_RGBA_8888 || - t.format == HAL_PIXEL_FORMAT_RGBX_8888) { - glTexSubImage2D(GL_TEXTURE_2D, 0, - 0, bounds.top, t.width, bounds.height(), - GL_RGBA, GL_UNSIGNED_BYTE, - t.data + bounds.top*t.stride*4); - } else if (isSupportedYuvFormat(t.format)) { - // just show the Y plane of YUV buffers - glTexSubImage2D(GL_TEXTURE_2D, 0, - 0, bounds.top, t.width, bounds.height(), - GL_LUMINANCE, GL_UNSIGNED_BYTE, - t.data + bounds.top*t.stride); - } - } - return NO_ERROR; -} - -void TextureManager::activateTexture(const Texture& texture, bool filter) -{ - const GLenum target = getTextureTarget(&texture); - if (target == GL_TEXTURE_2D) { - glBindTexture(GL_TEXTURE_2D, texture.name); - glEnable(GL_TEXTURE_2D); -#if defined(GL_OES_EGL_image_external) - if (GLExtensions::getInstance().haveTextureExternal()) { - glDisable(GL_TEXTURE_EXTERNAL_OES); - } - } else { - glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture.name); - glEnable(GL_TEXTURE_EXTERNAL_OES); - glDisable(GL_TEXTURE_2D); -#endif - } - - if (filter) { - glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } else { - glTexParameterx(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameterx(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } -} - -void TextureManager::deactivateTextures() -{ - glDisable(GL_TEXTURE_2D); -#if defined(GL_OES_EGL_image_external) - if (GLExtensions::getInstance().haveTextureExternal()) { - glDisable(GL_TEXTURE_EXTERNAL_OES); - } -#endif -} - -// --------------------------------------------------------------------------- - -}; // namespace android diff --git a/services/surfaceflinger/TextureManager.h b/services/surfaceflinger/TextureManager.h deleted file mode 100644 index 18c4348..0000000 --- a/services/surfaceflinger/TextureManager.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ANDROID_TEXTURE_MANAGER_H -#define ANDROID_TEXTURE_MANAGER_H - -#include <stdint.h> -#include <sys/types.h> - -#include <EGL/egl.h> -#include <EGL/eglext.h> -#include <GLES/gl.h> - -#include <ui/Region.h> - -#include <pixelflinger/pixelflinger.h> - -namespace android { - -// --------------------------------------------------------------------------- - -class GLExtensions; -class GraphicBuffer; - -// --------------------------------------------------------------------------- - -struct Image { - enum { TEXTURE_2D=0, TEXTURE_EXTERNAL=1 }; - Image() : name(-1U), image(EGL_NO_IMAGE_KHR), width(0), height(0), - dirty(1), target(TEXTURE_2D) { } - GLuint name; - EGLImageKHR image; - GLuint width; - GLuint height; - unsigned dirty : 1; - unsigned target : 1; -}; - -struct Texture : public Image { - Texture() : Image(), NPOTAdjust(0) { } - GLuint potWidth; - GLuint potHeight; - GLfloat wScale; - GLfloat hScale; - unsigned NPOTAdjust : 1; -}; - -// --------------------------------------------------------------------------- - -class TextureManager { - const GLExtensions& mGLExtensions; - static status_t initTexture(Image* texture, int32_t format); - static status_t initTexture(Texture* texture); - static bool isSupportedYuvFormat(int format); - static bool isYuvFormat(int format); - static GLenum getTextureTarget(const Image* pImage); -public: - - TextureManager(); - - // load bitmap data into the active buffer - status_t loadTexture(Texture* texture, - const Region& dirty, const GGLSurface& t); - - // make active buffer an EGLImage if needed - status_t initEglImage(Image* texture, - EGLDisplay dpy, const sp<GraphicBuffer>& buffer); - - // activate a texture - static void activateTexture(const Texture& texture, bool filter); - - // deactivate a texture - static void deactivateTextures(); -}; - -// --------------------------------------------------------------------------- - -}; // namespace android - -#endif // ANDROID_TEXTURE_MANAGER_H diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java index 845aa3f..f67d251 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java @@ -79,6 +79,7 @@ import com.google.common.util.concurrent.AbstractFuture; import org.easymock.Capture; import org.easymock.EasyMock; import org.easymock.IAnswer; +import org.easymock.IExpectationSetters; import java.io.File; import java.util.LinkedHashSet; @@ -87,6 +88,8 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import libcore.io.IoUtils; + /** * Tests for {@link NetworkPolicyManagerService}. */ @@ -117,6 +120,9 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { private Binder mStubBinder = new Binder(); + private long mStartTime; + private long mElapsedRealtime; + private static final int UID_A = android.os.Process.FIRST_APPLICATION_UID + 800; private static final int UID_B = android.os.Process.FIRST_APPLICATION_UID + 801; @@ -128,6 +134,8 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { public void setUp() throws Exception { super.setUp(); + setCurrentTimeMillis(TEST_START); + // intercept various broadcasts, and pretend that uids have packages mServiceContext = new BroadcastInterceptingContext(getContext()) { @Override @@ -160,8 +168,8 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { }; mPolicyDir = getContext().getFilesDir(); - for (File file : mPolicyDir.listFiles()) { - file.delete(); + if (mPolicyDir.exists()) { + IoUtils.deleteContents(mPolicyDir); } mActivityManager = createMock(IActivityManager.class); @@ -173,9 +181,8 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { mConnManager = createMock(IConnectivityManager.class); mNotifManager = createMock(INotificationManager.class); - mService = new NetworkPolicyManagerService( - mServiceContext, mActivityManager, mPowerManager, mStatsService, - mNetworkManager, mTime, mPolicyDir); + mService = new NetworkPolicyManagerService(mServiceContext, mActivityManager, mPowerManager, + mStatsService, mNetworkManager, mTime, mPolicyDir, true); mService.bindConnectivityManager(mConnManager); mService.bindNotificationManager(mNotifManager); @@ -198,7 +205,7 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { // expect to answer screen status during systemReady() expect(mPowerManager.isScreenOn()).andReturn(true).atLeastOnce(); - expectTime(System.currentTimeMillis()); + expectCurrentTime(); replay(); mService.systemReady(); @@ -485,7 +492,6 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { } public void testNetworkPolicyAppliedCycleLastMonth() throws Exception { - long elapsedRealtime = 0; NetworkState[] state = null; NetworkStats stats = null; Future<Void> future; @@ -494,11 +500,13 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { final long TIME_MAR_10 = 1173484800000L; final int CYCLE_DAY = 15; + setCurrentTimeMillis(TIME_MAR_10); + // first, pretend that wifi network comes online. no policy active, // which means we shouldn't push limit to interface. state = new NetworkState[] { buildWifi() }; expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce(); - expectTime(TIME_MAR_10 + elapsedRealtime); + expectCurrentTime(); expectClearNotifications(); future = expectMeteredIfacesChanged(); @@ -510,10 +518,10 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { // now change cycle to be on 15th, and test in early march, to verify we // pick cycle day in previous month. expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce(); - expectTime(TIME_MAR_10 + elapsedRealtime); + expectCurrentTime(); // pretend that 512 bytes total have happened - stats = new NetworkStats(elapsedRealtime, 1) + stats = new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 256L, 2L, 256L, 2L); expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, TIME_MAR_10)) .andReturn(stats).atLeastOnce(); @@ -521,8 +529,6 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { // TODO: consider making strongly ordered mock expectRemoveInterfaceQuota(TEST_IFACE); expectSetInterfaceQuota(TEST_IFACE, 1536L); - expectRemoveInterfaceAlert(TEST_IFACE); - expectSetInterfaceAlert(TEST_IFACE, 512L); expectClearNotifications(); future = expectMeteredIfacesChanged(TEST_IFACE); @@ -558,8 +564,6 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { } public void testOverWarningLimitNotification() throws Exception { - long elapsedRealtime = 0; - long currentTime = 0; NetworkState[] state = null; NetworkStats stats = null; Future<Void> future; @@ -569,14 +573,18 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { final long TIME_MAR_10 = 1173484800000L; final int CYCLE_DAY = 15; + setCurrentTimeMillis(TIME_MAR_10); + // assign wifi policy - elapsedRealtime = 0; - currentTime = TIME_MAR_10 + elapsedRealtime; state = new NetworkState[] {}; + stats = new NetworkStats(getElapsedRealtime(), 1) + .addIfaceValues(TEST_IFACE, 0L, 0L, 0L, 0L); { - expectTime(currentTime); + expectCurrentTime(); expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce(); + expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis())) + .andReturn(stats).atLeastOnce(); expectClearNotifications(); future = expectMeteredIfacesChanged(); @@ -589,22 +597,19 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { } // bring up wifi network - elapsedRealtime += MINUTE_IN_MILLIS; - currentTime = TIME_MAR_10 + elapsedRealtime; - stats = new NetworkStats(elapsedRealtime, 1) - .addIfaceValues(TEST_IFACE, 0L, 0L, 0L, 0L); + incrementCurrentTime(MINUTE_IN_MILLIS); state = new NetworkState[] { buildWifi() }; + stats = new NetworkStats(getElapsedRealtime(), 1) + .addIfaceValues(TEST_IFACE, 0L, 0L, 0L, 0L); { - expectTime(currentTime); + expectCurrentTime(); expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce(); - expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTime)) + expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis())) .andReturn(stats).atLeastOnce(); expectRemoveInterfaceQuota(TEST_IFACE); expectSetInterfaceQuota(TEST_IFACE, 2048L); - expectRemoveInterfaceAlert(TEST_IFACE); - expectSetInterfaceAlert(TEST_IFACE, 1024L); expectClearNotifications(); future = expectMeteredIfacesChanged(TEST_IFACE); @@ -616,14 +621,13 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { } // go over warning, which should kick notification - elapsedRealtime += MINUTE_IN_MILLIS; - currentTime = TIME_MAR_10 + elapsedRealtime; - stats = new NetworkStats(elapsedRealtime, 1) + incrementCurrentTime(MINUTE_IN_MILLIS); + stats = new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 1536L, 15L, 0L, 0L); { - expectTime(currentTime); - expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTime)) + expectCurrentTime(); + expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis())) .andReturn(stats).atLeastOnce(); expectForceUpdate(); @@ -637,15 +641,15 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { } // go over limit, which should kick notification and dialog - elapsedRealtime += MINUTE_IN_MILLIS; - currentTime = TIME_MAR_10 + elapsedRealtime; - stats = new NetworkStats(elapsedRealtime, 1) + incrementCurrentTime(MINUTE_IN_MILLIS); + stats = new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 5120L, 512L, 0L, 0L); { - expectTime(currentTime); - expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTime)) + expectCurrentTime(); + expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis())) .andReturn(stats).atLeastOnce(); + expectPolicyDataEnable(TYPE_WIFI, false).atLeastOnce(); expectForceUpdate(); expectClearNotifications(); @@ -658,21 +662,23 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { } // now snooze policy, which should remove quota - elapsedRealtime += MINUTE_IN_MILLIS; - currentTime = TIME_MAR_10 + elapsedRealtime; + incrementCurrentTime(MINUTE_IN_MILLIS); { - expectTime(currentTime); + expectCurrentTime(); expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce(); - expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTime)) + expect(mStatsService.getSummaryForNetwork(sTemplateWifi, TIME_FEB_15, currentTimeMillis())) .andReturn(stats).atLeastOnce(); + expectPolicyDataEnable(TYPE_WIFI, true).atLeastOnce(); + // snoozed interface still has high quota so background data is + // still restricted. expectRemoveInterfaceQuota(TEST_IFACE); - expectRemoveInterfaceAlert(TEST_IFACE); + expectSetInterfaceQuota(TEST_IFACE, Long.MAX_VALUE); expectClearNotifications(); tag = expectEnqueueNotification(); - future = expectMeteredIfacesChanged(); + future = expectMeteredIfacesChanged(TEST_IFACE); replay(); mService.snoozePolicy(sTemplateWifi); @@ -700,10 +706,10 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { return new NetworkState(info, prop, null); } - private void expectTime(long currentTime) throws Exception { + private void expectCurrentTime() throws Exception { expect(mTime.forceRefresh()).andReturn(false).anyTimes(); expect(mTime.hasCache()).andReturn(true).anyTimes(); - expect(mTime.currentTimeMillis()).andReturn(currentTime).anyTimes(); + expect(mTime.currentTimeMillis()).andReturn(currentTimeMillis()).anyTimes(); expect(mTime.getCacheAge()).andReturn(0L).anyTimes(); expect(mTime.getCacheCertainty()).andReturn(0L).anyTimes(); } @@ -770,6 +776,12 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { return future; } + private <T> IExpectationSetters<T> expectPolicyDataEnable(int type, boolean enabled) + throws Exception { + mConnManager.setPolicyDataEnable(type, enabled); + return expectLastCall(); + } + private static class FutureAnswer extends AbstractFuture<Void> implements IAnswer<Void> { @Override public Void get() throws InterruptedException, ExecutionException { @@ -818,6 +830,23 @@ public class NetworkPolicyManagerServiceTest extends AndroidTestCase { Integer.toString(expected), actualTag.substring(actualTag.lastIndexOf(':') + 1)); } + private long getElapsedRealtime() { + return mElapsedRealtime; + } + + private void setCurrentTimeMillis(long currentTimeMillis) { + mStartTime = currentTimeMillis; + mElapsedRealtime = 0L; + } + + private long currentTimeMillis() { + return mStartTime + mElapsedRealtime; + } + + private void incrementCurrentTime(long duration) { + mElapsedRealtime += duration; + } + private void replay() { EasyMock.replay(mActivityManager, mPowerManager, mStatsService, mPolicyListener, mNetworkManager, mTime, mConnManager, mNotifManager); |