OSDN Git Service

Merge changes from topic 'PasspointUI' into mnc-dev
authorVinit Deshpande <vinitd@google.com>
Wed, 29 Apr 2015 23:51:55 +0000 (23:51 +0000)
committerAndroid (Google) Code Review <android-gerrit@google.com>
Wed, 29 Apr 2015 23:51:59 +0000 (23:51 +0000)
* changes:
  Implement 'Available via Passpoint' feature [DO NOT MERGE]
  Fix settings UI for passpoint networks [DO NOT MERGE]

76 files changed:
Android.mk
api/current.txt
api/system-current.txt
core/java/android/accounts/AccountManager.java
core/java/android/app/AppOpsManager.java
core/java/android/app/KeyguardManager.java
core/java/android/content/ContentProviderNative.java
core/java/android/hardware/usb/UsbDevice.java
core/java/android/net/INetworkPolicyManager.aidl
core/java/android/net/NetworkPolicyManager.java
core/java/android/os/IDeviceIdleController.aidl [new file with mode: 0644]
core/java/android/os/INetworkManagementService.aidl
core/java/android/os/IPermissionController.aidl
core/java/android/os/PowerManager.java
core/java/android/security/keymaster/KeyCharacteristics.java
core/java/android/view/View.java
core/java/com/android/internal/content/PackageMonitor.java
core/java/com/android/internal/widget/FloatingToolbar.java
core/jni/Android.mk
core/jni/android_media_AudioRecord.cpp
core/jni/android_media_AudioTrack.cpp
core/jni/android_media_RemoteDisplay.cpp
core/res/AndroidManifest.xml
data/fonts/Android.mk
graphics/java/android/graphics/drawable/LayerDrawable.java
keystore/java/android/security/GateKeeper.java
keystore/java/android/security/KeyPermanentlyInvalidatedException.java [new file with mode: 0644]
keystore/java/android/security/KeyStore.java
keystore/java/android/security/KeyStoreCipherSpi.java
keystore/java/android/security/KeyStoreHmacSpi.java
keystore/java/android/security/KeymasterUtils.java
keystore/java/android/security/NewFingerprintEnrolledException.java [deleted file]
keystore/java/android/security/UserNotAuthenticatedException.java
libs/hwui/DeferredDisplayList.cpp
libs/hwui/DeferredDisplayList.h
libs/hwui/FrameInfo.h
libs/hwui/OpenGLRenderer.cpp
libs/hwui/OpenGLRenderer.h
libs/hwui/RenderNode.cpp
libs/hwui/RenderProperties.cpp
libs/hwui/renderstate/Stencil.cpp
libs/hwui/renderstate/Stencil.h
libs/hwui/renderthread/CanvasContext.cpp
media/java/android/media/AudioRecord.java
media/java/android/media/AudioTrack.java
media/java/android/media/MediaRecorder.java
media/java/android/media/RemoteDisplay.java
media/java/android/media/audiofx/AudioEffect.java
media/java/android/media/audiofx/Visualizer.java
media/java/android/media/midi/MidiDeviceInfo.java
media/jni/android_media_MediaRecorder.cpp
media/jni/audioeffect/android_media_AudioEffect.cpp
media/jni/audioeffect/android_media_Visualizer.cpp
packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
services/core/java/com/android/server/AlarmManagerService.java
services/core/java/com/android/server/ConnectivityService.java
services/core/java/com/android/server/DeviceIdleController.java [new file with mode: 0644]
services/core/java/com/android/server/NetworkManagementService.java
services/core/java/com/android/server/accounts/AccountManagerService.java
services/core/java/com/android/server/am/ActivityManagerService.java
services/core/java/com/android/server/am/BroadcastQueue.java
services/core/java/com/android/server/display/WifiDisplayController.java
services/core/java/com/android/server/location/GpsLocationProvider.java
services/core/java/com/android/server/net/LockdownVpnTracker.java
services/core/java/com/android/server/net/NetworkPolicyManagerService.java
services/core/java/com/android/server/power/DeviceIdleController.java [deleted file]
services/core/jni/com_android_server_UsbHostManager.cpp
services/java/com/android/server/SystemServer.java
services/usage/java/com/android/server/usage/UsageStatsService.java
services/usb/java/com/android/server/usb/UsbAlsaManager.java
services/usb/java/com/android/server/usb/UsbHostManager.java
telephony/java/android/telephony/CarrierConfigManager.java
tests/permission/src/com/android/framework/permission/tests/ServiceManagerPermissionTests.java

index bd8b16a..b71f08c 100644 (file)
@@ -197,6 +197,7 @@ LOCAL_SRC_FILES += \
        core/java/android/os/IBatteryPropertiesListener.aidl \
        core/java/android/os/IBatteryPropertiesRegistrar.aidl \
        core/java/android/os/ICancellationSignal.aidl \
+       core/java/android/os/IDeviceIdleController.aidl \
        core/java/android/os/IMessenger.aidl \
        core/java/android/os/INetworkActivityListener.aidl \
        core/java/android/os/INetworkManagementService.aidl \
index 3ba9483..f67270e 100644 (file)
@@ -2733,7 +2733,6 @@ package android.accounts {
   }
 
   public class AccountManager {
-    method public boolean accountAuthenticated(android.accounts.Account);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> addAccount(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle);
     method public void addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean);
@@ -2757,6 +2756,7 @@ package android.accounts {
     method public android.accounts.AccountManagerFuture<java.lang.Boolean> hasFeatures(android.accounts.Account, java.lang.String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
     method public void invalidateAuthToken(java.lang.String, java.lang.String);
     method public static android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, java.lang.String[], boolean, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle);
+    method public boolean notifyAccountAuthenticated(android.accounts.Account);
     method public java.lang.String peekAuthToken(android.accounts.Account, java.lang.String);
     method public deprecated android.accounts.AccountManagerFuture<java.lang.Boolean> removeAccount(android.accounts.Account, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> removeAccount(android.accounts.Account, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
@@ -2794,7 +2794,7 @@ package android.accounts {
     field public static final java.lang.String KEY_ERROR_CODE = "errorCode";
     field public static final java.lang.String KEY_ERROR_MESSAGE = "errorMessage";
     field public static final java.lang.String KEY_INTENT = "intent";
-    field public static final java.lang.String KEY_LAST_AUTHENTICATE_TIME_MILLIS_EPOCH = "lastAuthenticatedTimeMillisEpoch";
+    field public static final java.lang.String KEY_LAST_AUTHENTICATED_TIME = "lastAuthenticatedTime";
     field public static final java.lang.String KEY_PASSWORD = "password";
     field public static final java.lang.String KEY_USERDATA = "userdata";
     field public static final java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
@@ -14025,6 +14025,7 @@ package android.hardware.usb {
     method public java.lang.String getProductName();
     method public java.lang.String getSerialNumber();
     method public int getVendorId();
+    method public java.lang.String getVersion();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.usb.UsbDevice> CREATOR;
   }
@@ -17266,6 +17267,7 @@ package android.media.midi {
     field public static final java.lang.String PROPERTY_PRODUCT = "product";
     field public static final java.lang.String PROPERTY_SERIAL_NUMBER = "serial_number";
     field public static final java.lang.String PROPERTY_USB_DEVICE = "usb_device";
+    field public static final java.lang.String PROPERTY_VERSION = "version";
     field public static final int TYPE_BLUETOOTH = 3; // 0x3
     field public static final int TYPE_USB = 1; // 0x1
     field public static final int TYPE_VIRTUAL = 2; // 0x2
@@ -28614,6 +28616,12 @@ package android.security {
     method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
   }
 
+  public class KeyPermanentlyInvalidatedException extends java.security.InvalidKeyException {
+    ctor public KeyPermanentlyInvalidatedException();
+    ctor public KeyPermanentlyInvalidatedException(java.lang.String);
+    ctor public KeyPermanentlyInvalidatedException(java.lang.String, java.lang.Throwable);
+  }
+
   public abstract class KeyStoreKeyProperties {
   }
 
@@ -28694,11 +28702,6 @@ package android.security {
     method public boolean isCleartextTrafficPermitted();
   }
 
-  public class NewFingerprintEnrolledException extends java.security.InvalidKeyException {
-    ctor public NewFingerprintEnrolledException();
-    ctor public NewFingerprintEnrolledException(java.lang.String);
-  }
-
   public class UserNotAuthenticatedException extends java.security.InvalidKeyException {
     ctor public UserNotAuthenticatedException();
     ctor public UserNotAuthenticatedException(java.lang.String);
@@ -30683,11 +30686,34 @@ package android.telephony {
     method public android.os.Bundle getConfigForSubId(int);
     method public void reloadCarrierConfigForSubId(int);
     field public static final java.lang.String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
+    field public static final java.lang.String BOOL_ADDITIONAL_CALL_SETTING = "bool_additional_call_setting";
+    field public static final java.lang.String BOOL_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG = "bool_allow_emergency_numbers_in_call_log";
+    field public static final java.lang.String BOOL_ALLOW_LOCAL_DTMF_TONES = "bool_allow_local_dtmf_tones";
     field public static final java.lang.String BOOL_APN_EXPAND = "bool_apn_expand";
+    field public static final java.lang.String BOOL_AUTO_RETRY_ENABLED = "bool_auto_retry_enabled";
+    field public static final java.lang.String BOOL_CARRIER_SETTINGS_ENABLE = "bool_carrier_settings_enable";
     field public static final java.lang.String BOOL_CARRIER_VOLTE_AVAILABLE = "bool_carrier_volte_available";
     field public static final java.lang.String BOOL_CARRIER_VOLTE_PROVISIONED = "bool_carrier_volte_provisioned";
     field public static final java.lang.String BOOL_CARRIER_VOLTE_TTY_SUPPORTED = "bool_carrier_volte_tty_supported";
+    field public static final java.lang.String BOOL_DISABLE_CDMA_ACTIVATION_CODE = "bool_disable_cdma_activation_code";
+    field public static final java.lang.String BOOL_DTMF_TYPE_ENABLED = "bool_dtmf_type_enabled";
+    field public static final java.lang.String BOOL_ENABLE_DIALER_KEY_VIBRATION = "bool_enable_dialer_key_vibration";
+    field public static final java.lang.String BOOL_HAS_IN_CALL_NOISE_SUPPRESSION = "bool_has_in_call_noise_suppression";
+    field public static final java.lang.String BOOL_HIDE_CARRIER_NETWORK_SETTINGS = "bool_hide_carrier_network_settings";
+    field public static final java.lang.String BOOL_IGNORE_SIM_NETWORK_LOCKED_EVENTS = "bool_ignore_sim_network_locked_events";
+    field public static final java.lang.String BOOL_OPERATOR_SELECTION_EXPAND = "bool_operator_selection_expand";
+    field public static final java.lang.String BOOL_PREFER_2G = "bool_prefer_2g";
     field public static final java.lang.String BOOL_SHOW_APN_SETTING_CDMA = "bool_show_apn_setting_cdma";
+    field public static final java.lang.String BOOL_SHOW_CDMA = "bool_show_cdma";
+    field public static final java.lang.String BOOL_SHOW_ONSCREEN_DIAL_BUTTON = "bool_show_onscreen_dial_button";
+    field public static final java.lang.String BOOL_SIM_NETWORK_UNLOCK_ALLOW_DISMISS = "bool_sim_network_unlock_allow_dismiss";
+    field public static final java.lang.String BOOL_SUPPORT_PAUSE_IMS_VIDEO_CALLS = "bool_support_pause_ims_video_calls";
+    field public static final java.lang.String BOOL_SUPPORT_SWAP_AFTER_MERGE = "bool_support_swap_after_merge";
+    field public static final java.lang.String BOOL_USE_HFA_FOR_PROVISIONING = "bool_use_hfa_for_provisioning";
+    field public static final java.lang.String BOOL_USE_OTASP_FOR_PROVISIONING = "bool_use_otasp_for_provisioning";
+    field public static final java.lang.String BOOL_VOICEMAIL_NOTIFICATION_PERSISTENT = "bool_voicemail_notification_persistent";
+    field public static final java.lang.String BOOL_VOICE_PRIVACY_DISABLE = "bool_voice_privacy_disable";
+    field public static final java.lang.String BOOL_WORLD_PHONE = "bool_world_phone";
     field public static final java.lang.String INT_VOLTE_REPLACEMENT_RAT = "int_volte_replacement_rat";
   }
 
index 77e9366..bac38d9 100644 (file)
@@ -2811,7 +2811,6 @@ package android.accounts {
   }
 
   public class AccountManager {
-    method public boolean accountAuthenticated(android.accounts.Account);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> addAccount(java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
     method public boolean addAccountExplicitly(android.accounts.Account, java.lang.String, android.os.Bundle);
     method public void addOnAccountsUpdatedListener(android.accounts.OnAccountsUpdateListener, android.os.Handler, boolean);
@@ -2835,6 +2834,7 @@ package android.accounts {
     method public android.accounts.AccountManagerFuture<java.lang.Boolean> hasFeatures(android.accounts.Account, java.lang.String[], android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
     method public void invalidateAuthToken(java.lang.String, java.lang.String);
     method public static android.content.Intent newChooseAccountIntent(android.accounts.Account, java.util.ArrayList<android.accounts.Account>, java.lang.String[], boolean, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle);
+    method public boolean notifyAccountAuthenticated(android.accounts.Account);
     method public java.lang.String peekAuthToken(android.accounts.Account, java.lang.String);
     method public deprecated android.accounts.AccountManagerFuture<java.lang.Boolean> removeAccount(android.accounts.Account, android.accounts.AccountManagerCallback<java.lang.Boolean>, android.os.Handler);
     method public android.accounts.AccountManagerFuture<android.os.Bundle> removeAccount(android.accounts.Account, android.app.Activity, android.accounts.AccountManagerCallback<android.os.Bundle>, android.os.Handler);
@@ -2872,7 +2872,7 @@ package android.accounts {
     field public static final java.lang.String KEY_ERROR_CODE = "errorCode";
     field public static final java.lang.String KEY_ERROR_MESSAGE = "errorMessage";
     field public static final java.lang.String KEY_INTENT = "intent";
-    field public static final java.lang.String KEY_LAST_AUTHENTICATE_TIME_MILLIS_EPOCH = "lastAuthenticatedTimeMillisEpoch";
+    field public static final java.lang.String KEY_LAST_AUTHENTICATED_TIME = "lastAuthenticatedTime";
     field public static final java.lang.String KEY_PASSWORD = "password";
     field public static final java.lang.String KEY_USERDATA = "userdata";
     field public static final java.lang.String LOGIN_ACCOUNTS_CHANGED_ACTION = "android.accounts.LOGIN_ACCOUNTS_CHANGED";
@@ -3949,6 +3949,7 @@ package android.app {
     method public void finishOp(java.lang.String, int, java.lang.String);
     method public int noteOp(java.lang.String, int, java.lang.String);
     method public int noteOpNoThrow(java.lang.String, int, java.lang.String);
+    method public static java.lang.String permissionToOp(java.lang.String);
     method public int startOp(java.lang.String, int, java.lang.String);
     method public int startOpNoThrow(java.lang.String, int, java.lang.String);
     method public void startWatchingMode(java.lang.String, java.lang.String, android.app.AppOpsManager.OnOpChangedListener);
@@ -14929,6 +14930,7 @@ package android.hardware.usb {
     method public java.lang.String getProductName();
     method public java.lang.String getSerialNumber();
     method public int getVendorId();
+    method public java.lang.String getVersion();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.hardware.usb.UsbDevice> CREATOR;
   }
@@ -18558,6 +18560,7 @@ package android.media.midi {
     field public static final java.lang.String PROPERTY_PRODUCT = "product";
     field public static final java.lang.String PROPERTY_SERIAL_NUMBER = "serial_number";
     field public static final java.lang.String PROPERTY_USB_DEVICE = "usb_device";
+    field public static final java.lang.String PROPERTY_VERSION = "version";
     field public static final int TYPE_BLUETOOTH = 3; // 0x3
     field public static final int TYPE_USB = 1; // 0x1
     field public static final int TYPE_VIRTUAL = 2; // 0x2
@@ -30626,6 +30629,12 @@ package android.security {
     method public android.security.KeyPairGeneratorSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
   }
 
+  public class KeyPermanentlyInvalidatedException extends java.security.InvalidKeyException {
+    ctor public KeyPermanentlyInvalidatedException();
+    ctor public KeyPermanentlyInvalidatedException(java.lang.String);
+    ctor public KeyPermanentlyInvalidatedException(java.lang.String, java.lang.Throwable);
+  }
+
   public abstract class KeyStoreKeyProperties {
   }
 
@@ -30706,11 +30715,6 @@ package android.security {
     method public boolean isCleartextTrafficPermitted();
   }
 
-  public class NewFingerprintEnrolledException extends java.security.InvalidKeyException {
-    ctor public NewFingerprintEnrolledException();
-    ctor public NewFingerprintEnrolledException(java.lang.String);
-  }
-
   public class UserNotAuthenticatedException extends java.security.InvalidKeyException {
     ctor public UserNotAuthenticatedException();
     ctor public UserNotAuthenticatedException(java.lang.String);
@@ -32846,11 +32850,34 @@ package android.telephony {
     method public void reloadCarrierConfigForSubId(int);
     method public void updateConfigForPhoneId(int, java.lang.String);
     field public static final java.lang.String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
+    field public static final java.lang.String BOOL_ADDITIONAL_CALL_SETTING = "bool_additional_call_setting";
+    field public static final java.lang.String BOOL_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG = "bool_allow_emergency_numbers_in_call_log";
+    field public static final java.lang.String BOOL_ALLOW_LOCAL_DTMF_TONES = "bool_allow_local_dtmf_tones";
     field public static final java.lang.String BOOL_APN_EXPAND = "bool_apn_expand";
+    field public static final java.lang.String BOOL_AUTO_RETRY_ENABLED = "bool_auto_retry_enabled";
+    field public static final java.lang.String BOOL_CARRIER_SETTINGS_ENABLE = "bool_carrier_settings_enable";
     field public static final java.lang.String BOOL_CARRIER_VOLTE_AVAILABLE = "bool_carrier_volte_available";
     field public static final java.lang.String BOOL_CARRIER_VOLTE_PROVISIONED = "bool_carrier_volte_provisioned";
     field public static final java.lang.String BOOL_CARRIER_VOLTE_TTY_SUPPORTED = "bool_carrier_volte_tty_supported";
+    field public static final java.lang.String BOOL_DISABLE_CDMA_ACTIVATION_CODE = "bool_disable_cdma_activation_code";
+    field public static final java.lang.String BOOL_DTMF_TYPE_ENABLED = "bool_dtmf_type_enabled";
+    field public static final java.lang.String BOOL_ENABLE_DIALER_KEY_VIBRATION = "bool_enable_dialer_key_vibration";
+    field public static final java.lang.String BOOL_HAS_IN_CALL_NOISE_SUPPRESSION = "bool_has_in_call_noise_suppression";
+    field public static final java.lang.String BOOL_HIDE_CARRIER_NETWORK_SETTINGS = "bool_hide_carrier_network_settings";
+    field public static final java.lang.String BOOL_IGNORE_SIM_NETWORK_LOCKED_EVENTS = "bool_ignore_sim_network_locked_events";
+    field public static final java.lang.String BOOL_OPERATOR_SELECTION_EXPAND = "bool_operator_selection_expand";
+    field public static final java.lang.String BOOL_PREFER_2G = "bool_prefer_2g";
     field public static final java.lang.String BOOL_SHOW_APN_SETTING_CDMA = "bool_show_apn_setting_cdma";
+    field public static final java.lang.String BOOL_SHOW_CDMA = "bool_show_cdma";
+    field public static final java.lang.String BOOL_SHOW_ONSCREEN_DIAL_BUTTON = "bool_show_onscreen_dial_button";
+    field public static final java.lang.String BOOL_SIM_NETWORK_UNLOCK_ALLOW_DISMISS = "bool_sim_network_unlock_allow_dismiss";
+    field public static final java.lang.String BOOL_SUPPORT_PAUSE_IMS_VIDEO_CALLS = "bool_support_pause_ims_video_calls";
+    field public static final java.lang.String BOOL_SUPPORT_SWAP_AFTER_MERGE = "bool_support_swap_after_merge";
+    field public static final java.lang.String BOOL_USE_HFA_FOR_PROVISIONING = "bool_use_hfa_for_provisioning";
+    field public static final java.lang.String BOOL_USE_OTASP_FOR_PROVISIONING = "bool_use_otasp_for_provisioning";
+    field public static final java.lang.String BOOL_VOICEMAIL_NOTIFICATION_PERSISTENT = "bool_voicemail_notification_persistent";
+    field public static final java.lang.String BOOL_VOICE_PRIVACY_DISABLE = "bool_voice_privacy_disable";
+    field public static final java.lang.String BOOL_WORLD_PHONE = "bool_world_phone";
     field public static final java.lang.String INT_VOLTE_REPLACEMENT_RAT = "int_volte_replacement_rat";
   }
 
index 480d171..ffa36d6 100644 (file)
@@ -207,8 +207,7 @@ public class AccountManager {
      * were authenticated successfully. Time is specified in milliseconds since
      * epoch.
      */
-    public static final String KEY_LAST_AUTHENTICATE_TIME_MILLIS_EPOCH =
-            "lastAuthenticatedTimeMillisEpoch";
+    public static final String KEY_LAST_AUTHENTICATED_TIME = "lastAuthenticatedTime";
 
     /**
      * Authenticators using 'customTokens' option will also get the UID of the
@@ -671,8 +670,8 @@ public class AccountManager {
     }
 
     /**
-     * Informs the system that the account has been authenticated recently. This
-     * recency may be used by other applications to verify the account. This
+     * Notifies the system that the account has just been authenticated. This
+     * information may be used by other applications to verify the account. This
      * should be called only when the user has entered correct credentials for
      * the account.
      * <p>
@@ -685,7 +684,7 @@ public class AccountManager {
      *
      * @param account The {@link Account} to be updated.
      */
-    public boolean accountAuthenticated(Account account) {
+    public boolean notifyAccountAuthenticated(Account account) {
         if (account == null)
             throw new IllegalArgumentException("account is null");
         try {
@@ -1587,7 +1586,7 @@ public class AccountManager {
      * password prompt.
      * 
      * <p>Also the returning Bundle may contain {@link
-     * #KEY_LAST_AUTHENTICATE_TIME_MILLIS_EPOCH} indicating the last time the
+     * #KEY_LAST_AUTHENTICATED_TIME} indicating the last time the
      * credential was validated/created.
      * 
      * If an error occurred,{@link AccountManagerFuture#getResult()} throws:
index 223d528..48e380b 100644 (file)
@@ -726,6 +726,16 @@ public class AppOpsManager {
             false
     };
 
+    /**
+     * This is a mapping from a permission name to public app op name.
+     */
+    private static final ArrayMap<String, String> sPermToOp = new ArrayMap<>();
+    static {
+        sPermToOp.put(Manifest.permission.ACCESS_COARSE_LOCATION, OPSTR_COARSE_LOCATION);
+        sPermToOp.put(Manifest.permission.ACCESS_FINE_LOCATION, OPSTR_FINE_LOCATION);
+        sPermToOp.put(Manifest.permission.PACKAGE_USAGE_STATS, OPSTR_GET_USAGE_STATS);
+    }
+
     private static HashMap<String, Integer> sOpStrToOp = new HashMap<String, Integer>();
 
     static {
@@ -1066,6 +1076,21 @@ public class AppOpsManager {
     }
 
     /**
+     * Gets the app op name associated with a given permission.
+     * The app op name is one of the public constants defined
+     * in this class such as {@link #OPSTR_COARSE_LOCATION}.
+     *
+     * @param permission The permission.
+     * @return The app op associated with the permission or null.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static String permissionToOp(String permission) {
+        return sPermToOp.get(permission);
+    }
+
+    /**
      * Monitor for changes to the operating mode for the given op in the given app package.
      * @param op The operation to monitor, one of OPSTR_*.
      * @param packageName The name of the application to monitor.
index ebb3c43..2c12317 100644 (file)
@@ -199,9 +199,12 @@ public class KeyguardManager {
     }
 
     /**
-     * Return whether the keyguard requires a password to unlock.
+     * Return whether the keyguard is secured by a PIN, pattern or password or a SIM card
+     * is currently locked.
      *
-     * @return true if keyguard is secure.
+     * <p>See also {@link #isDeviceSecure()} which ignores SIM locked states.
+     *
+     * @return true if a PIN, pattern or password is set or a SIM card is locked.
      */
     public boolean isKeyguardSecure() {
         try {
@@ -240,12 +243,8 @@ public class KeyguardManager {
     }
 
     /**
-     * Returns whether the device is currently locked and requires a PIN, pattern or
-     * password to unlock.
+     * Per-user version of {@link #isDeviceLocked()}.
      *
-     * @param userId the user for which the locked state should be reported.
-     * @return true if unlocking the device currently requires a PIN, pattern or
-     * password.
      * @hide
      */
     public boolean isDeviceLocked(int userId) {
@@ -260,6 +259,8 @@ public class KeyguardManager {
      * Returns whether the device is secured with a PIN, pattern or
      * password.
      *
+     * <p>See also {@link #isKeyguardSecure} which treats SIM locked states as secure.
+     *
      * @return true if a PIN, pattern or password was set.
      */
     public boolean isDeviceSecure() {
@@ -267,11 +268,8 @@ public class KeyguardManager {
     }
 
     /**
-     * Returns whether the device is secured with a PIN, pattern or
-     * password.
+     * Per-user version of {@link #isDeviceSecure()}.
      *
-     * @param userId the user for which the secure state should be reported.
-     * @return true if a PIN, pattern or password was set.
      * @hide
      */
     public boolean isDeviceSecure(int userId) {
index f2e7fc4..4769bd0 100644 (file)
@@ -593,7 +593,8 @@ final class ContentProviderProxy implements IContentProvider
 
             DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply);
             int has = reply.readInt();
-            ParcelFileDescriptor fd = has != 0 ? reply.readFileDescriptor() : null;
+            ParcelFileDescriptor fd = has != 0 ? ParcelFileDescriptor.CREATOR
+                    .createFromParcel(reply) : null;
             return fd;
         } finally {
             data.recycle();
index 1a42319..410d550 100644 (file)
@@ -45,6 +45,7 @@ public class UsbDevice implements Parcelable {
     private final String mName;
     private final String mManufacturerName;
     private final String mProductName;
+    private final String mVersion;
     private final String mSerialNumber;
     private final int mVendorId;
     private final int mProductId;
@@ -62,7 +63,7 @@ public class UsbDevice implements Parcelable {
      */
     public UsbDevice(String name, int vendorId, int productId,
             int Class, int subClass, int protocol,
-            String manufacturerName, String productName, String serialNumber) {
+            String manufacturerName, String productName, String version, String serialNumber) {
         mName = name;
         mVendorId = vendorId;
         mProductId = productId;
@@ -71,6 +72,7 @@ public class UsbDevice implements Parcelable {
         mProtocol = protocol;
         mManufacturerName = manufacturerName;
         mProductName = productName;
+        mVersion = version;
         mSerialNumber = serialNumber;
     }
 
@@ -104,6 +106,15 @@ public class UsbDevice implements Parcelable {
     }
 
     /**
+     * Returns the version number of the device.
+     *
+     * @return the device version
+     */
+    public String getVersion() {
+        return mVersion;
+    }
+
+    /**
      * Returns the serial number of the device.
      *
      * @return the serial number name
@@ -263,7 +274,7 @@ public class UsbDevice implements Parcelable {
                 ",mVendorId=" + mVendorId + ",mProductId=" + mProductId +
                 ",mClass=" + mClass + ",mSubclass=" + mSubclass + ",mProtocol=" + mProtocol +
                 ",mManufacturerName=" + mManufacturerName + ",mProductName=" + mProductName +
-                ",mSerialNumber=" + mSerialNumber + ",mConfigurations=[");
+                ",mVersion=" + mVersion + ",mSerialNumber=" + mSerialNumber + ",mConfigurations=[");
         for (int i = 0; i < mConfigurations.length; i++) {
             builder.append("\n");
             builder.append(mConfigurations[i].toString());
@@ -283,10 +294,11 @@ public class UsbDevice implements Parcelable {
             int protocol = in.readInt();
             String manufacturerName = in.readString();
             String productName = in.readString();
+            String version = in.readString();
             String serialNumber = in.readString();
             Parcelable[] configurations = in.readParcelableArray(UsbInterface.class.getClassLoader());
             UsbDevice device = new UsbDevice(name, vendorId, productId, clasz, subClass, protocol,
-                                 manufacturerName, productName, serialNumber);
+                                 manufacturerName, productName, version, serialNumber);
             device.setConfigurations(configurations);
             return device;
         }
@@ -309,6 +321,7 @@ public class UsbDevice implements Parcelable {
         parcel.writeInt(mProtocol);
         parcel.writeString(mManufacturerName);
         parcel.writeString(mProductName);
+        parcel.writeString(mVersion);
         parcel.writeString(mSerialNumber);
         parcel.writeParcelableArray(mConfigurations, 0);
    }
index c722fbc..7f5f377 100644 (file)
@@ -38,8 +38,6 @@ interface INetworkPolicyManager {
 
     boolean isUidForeground(int uid);
 
-    int[] getPowerSaveAppIdWhitelist();
-
     void registerListener(INetworkPolicyListener listener);
     void unregisterListener(INetworkPolicyListener listener);
 
index bc03637..ecc3fb4 100644 (file)
@@ -41,6 +41,7 @@ import java.util.HashSet;
  */
 public class NetworkPolicyManager {
 
+    /* POLICY_* are masks and can be ORed */
     /** No specific network policy, use system default. */
     public static final int POLICY_NONE = 0x0;
     /** Reject network usage on metered networks when application in background. */
@@ -48,10 +49,17 @@ public class NetworkPolicyManager {
     /** Allow network use (metered or not) in the background in battery save mode. */
     public static final int POLICY_ALLOW_BACKGROUND_BATTERY_SAVE = 0x2;
 
+    /* RULE_* are not masks and they must be exclusive */
     /** All network traffic should be allowed. */
     public static final int RULE_ALLOW_ALL = 0x0;
     /** Reject traffic on metered networks. */
     public static final int RULE_REJECT_METERED = 0x1;
+    /** Reject traffic on all networks. */
+    public static final int RULE_REJECT_ALL = 0x2;
+
+    public static final int FIREWALL_RULE_DEFAULT = 0;
+    public static final int FIREWALL_RULE_ALLOW = 1;
+    public static final int FIREWALL_RULE_DENY = 2;
 
     private static final boolean ALLOW_PLATFORM_APP_POLICY = true;
 
@@ -80,7 +88,7 @@ public class NetworkPolicyManager {
      * Set policy flags for specific UID.
      *
      * @param policy {@link #POLICY_NONE} or combination of flags like
-     * {@link #POLICY_REJECT_METERED_BACKGROUND}, {@link #POLICY_ALLOW_BACKGROUND_BATTERY_SAVE}.
+     * {@link #POLICY_REJECT_METERED_BACKGROUND} or {@link #POLICY_ALLOW_BACKGROUND_BATTERY_SAVE}.
      */
     public void setUidPolicy(int uid, int policy) {
         try {
@@ -129,14 +137,6 @@ public class NetworkPolicyManager {
         }
     }
 
-    public int[] getPowerSaveAppIdWhitelist() {
-        try {
-            return mService.getPowerSaveAppIdWhitelist();
-        } catch (RemoteException e) {
-            return new int[0];
-        }
-    }
-
     public void registerListener(INetworkPolicyListener listener) {
         try {
             mService.registerListener(listener);
@@ -330,6 +330,8 @@ public class NetworkPolicyManager {
         fout.write("[");
         if ((rules & RULE_REJECT_METERED) != 0) {
             fout.write("REJECT_METERED");
+        } else if ((rules & RULE_REJECT_ALL) != 0) {
+            fout.write("REJECT_ALL");
         }
         fout.write("]");
     }
diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl
new file mode 100644 (file)
index 0000000..3cb29ff
--- /dev/null
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2015, 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.
+ */
+
+package android.os;
+
+/** @hide */
+interface IDeviceIdleController {
+    void addPowerSaveWhitelistApp(String name);
+    void removePowerSaveWhitelistApp(String name);
+    String[] getSystemPowerWhitelist();
+    String[] getFullPowerWhitelist();
+    int[] getAppIdWhitelist();
+}
index f93550a..b29e8d0 100644 (file)
@@ -342,7 +342,7 @@ interface INetworkManagementService
     void setFirewallInterfaceRule(String iface, boolean allow);
     void setFirewallEgressSourceRule(String addr, boolean allow);
     void setFirewallEgressDestRule(String addr, int port, boolean allow);
-    void setFirewallUidRule(int uid, boolean allow);
+    void setFirewallUidRule(int uid, int rule);
 
     /**
      * Set all packets from users in ranges to go through VPN specified by netId.
index 73a68f1..0cc1603 100644 (file)
@@ -20,4 +20,5 @@ package android.os;
 /** @hide */
 interface IPermissionController {
     boolean checkPermission(String permission, int pid, int uid);
+    String[] getPackagesForUid(int uid);
 }
index 01c9a21..1d9d7d2 100644 (file)
@@ -920,6 +920,14 @@ public final class PowerManager {
             = "android.os.action.DEVICE_IDLE_MODE_CHANGED";
 
     /**
+     * @hide Intent that is broadcast when the set of power save whitelist apps has changed.
+     * This broadcast is only sent to registered receivers.
+     */
+    @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_POWER_SAVE_WHITELIST_CHANGED
+            = "android.os.action.POWER_SAVE_WHITELIST_CHANGED";
+
+    /**
      * Intent that is broadcast when the state of {@link #isPowerSaveMode()} is about to change.
      * This broadcast is only sent to registered receivers.
      *
index 458f153..03248e5 100644 (file)
@@ -87,6 +87,28 @@ public class KeyCharacteristics implements Parcelable {
         return result;
     }
 
+    public Long getLong(int tag) {
+        if (hwEnforced.containsTag(tag)) {
+            return hwEnforced.getLong(tag, -1);
+        } else if (swEnforced.containsTag(tag)) {
+            return swEnforced.getLong(tag, -1);
+        } else {
+            return null;
+        }
+    }
+
+    public long getLong(int tag, long defaultValue) {
+        Long result = getLong(tag);
+        return (result != null) ? result : defaultValue;
+    }
+
+    public List<Long> getLongs(int tag) {
+        List<Long> result = new ArrayList<Long>();
+        result.addAll(hwEnforced.getLongs(tag));
+        result.addAll(swEnforced.getLongs(tag));
+        return result;
+    }
+
     public Date getDate(int tag) {
         Date result = hwEnforced.getDate(tag, null);
         if (result == null) {
index e8fc15e..b5b7f0f 100644 (file)
@@ -15490,12 +15490,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                         if (drawingWithRenderNode) {
                             renderNode.setAlpha(alpha * getAlpha() * getTransitionAlpha());
                         } else if (layerType == LAYER_TYPE_NONE) {
-                            int layerFlags = Canvas.HAS_ALPHA_LAYER_SAVE_FLAG;
-                            if ((parentFlags & ViewGroup.FLAG_CLIP_CHILDREN) != 0) {
-                                layerFlags |= Canvas.CLIP_TO_LAYER_SAVE_FLAG;
-                            }
                             canvas.saveLayerAlpha(sx, sy, sx + getWidth(), sy + getHeight(),
-                                    multipliedAlpha, layerFlags);
+                                    multipliedAlpha);
                         }
                     } else {
                         // Alpha is handled by the child directly, clobber the layer's alpha
index eff44bd..481ab0e 100644 (file)
@@ -44,7 +44,6 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
         sPackageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED);
         sPackageFilt.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
         sPackageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED);
-        sPackageFilt.addAction(Intent.ACTION_UID_REMOVED);
         sPackageFilt.addDataScheme("package");
         sNonDataFilt.addAction(Intent.ACTION_UID_REMOVED);
         sNonDataFilt.addAction(Intent.ACTION_USER_STOPPED);
index 3a1e0ca..3f7696f 100644 (file)
@@ -438,6 +438,9 @@ public final class FloatingToolbar {
             // Make sure a panel is set as the content.
             if (mContentContainer.getChildCount() == 0) {
                 setMainPanelAsContent();
+                // If we're yet to show the popup, set the container visibility to zero.
+                // The "show" animation will make this visible.
+                mContentContainer.setAlpha(0);
             }
             preparePopupContent();
             mPopupWindow.showAtLocation(mParent, Gravity.NO_GRAVITY, x, y);
@@ -478,7 +481,7 @@ public final class FloatingToolbar {
          * Returns {@code true} if this popup is currently showing. {@code false} otherwise.
          */
         public boolean isShowing() {
-            return mPopupWindow.isShowing() && !mDismissed && !mHidden;
+            return !mDismissed && !mHidden;
         }
 
         /**
@@ -494,7 +497,7 @@ public final class FloatingToolbar {
          * This is a no-op if this popup is not showing.
          */
         public void updateCoordinates(int x, int y) {
-            if (!isShowing()) {
+            if (!isShowing() || !mPopupWindow.isShowing()) {
                 return;
             }
 
index cd117eb..bbdd860 100644 (file)
@@ -176,6 +176,7 @@ LOCAL_C_INCLUDES += \
     $(call include-path-for, libhardware)/hardware \
     $(call include-path-for, libhardware_legacy)/hardware_legacy \
     $(TOP)/frameworks/av/include \
+    $(TOP)/frameworks/base/media/jni \
     $(TOP)/system/media/camera/include \
     $(TOP)/system/netd/include \
     external/pdfium/core/include/fpdfapi \
index c384ef9..6afb226 100644 (file)
@@ -26,6 +26,8 @@
 #include <utils/Log.h>
 #include <media/AudioRecord.h>
 
+#include <ScopedUtfChars.h>
+
 #include "android_media_AudioFormat.h"
 #include "android_media_AudioErrors.h"
 
@@ -146,7 +148,7 @@ static sp<AudioRecord> setAudioRecord(JNIEnv* env, jobject thiz, const sp<AudioR
 static jint
 android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
         jobject jaa, jint sampleRateInHertz, jint channelMask, jint channelIndexMask,
-        jint audioFormat, jint buffSizeInBytes, jintArray jSession)
+        jint audioFormat, jint buffSizeInBytes, jintArray jSession, jstring opPackageName)
 {
     //ALOGV(">> Entering android_media_AudioRecord_setup");
     //ALOGV("sampleRate=%d, audioFormat=%d, channel mask=%x, buffSizeInBytes=%d",
@@ -208,8 +210,10 @@ android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
     env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
     nSession = NULL;
 
+    ScopedUtfChars opPackageNameStr(env, opPackageName);
+
     // create an uninitialized AudioRecord object
-    sp<AudioRecord> lpRecorder = new AudioRecord();
+    sp<AudioRecord> lpRecorder = new AudioRecord(String16(opPackageNameStr.c_str()));
 
     audio_attributes_t *paa = NULL;
     // read the AudioAttributes values
@@ -597,7 +601,7 @@ static JNINativeMethod gMethods[] = {
     // name,               signature,  funcPtr
     {"native_start",         "(II)I",    (void *)android_media_AudioRecord_start},
     {"native_stop",          "()V",    (void *)android_media_AudioRecord_stop},
-    {"native_setup",         "(Ljava/lang/Object;Ljava/lang/Object;IIIII[I)I",
+    {"native_setup",         "(Ljava/lang/Object;Ljava/lang/Object;IIIII[ILjava/lang/String;)I",
                                        (void *)android_media_AudioRecord_setup},
     {"native_finalize",      "()V",    (void *)android_media_AudioRecord_finalize},
     {"native_release",       "()V",    (void *)android_media_AudioRecord_release},
index 2f6a69c..26b82c5 100644 (file)
@@ -35,6 +35,7 @@
 
 #include "android_media_AudioFormat.h"
 #include "android_media_AudioErrors.h"
+#include "android_media_PlaybackSettings.h"
 
 // ----------------------------------------------------------------------------
 
@@ -59,6 +60,7 @@ struct audio_attributes_fields_t {
 };
 static audio_track_fields_t      javaAudioTrackFields;
 static audio_attributes_fields_t javaAudioAttrFields;
+static PlaybackSettings::fields_t gPlaybackSettingsFields;
 
 struct audiotrack_callback_cookie {
     jclass      audioTrack_class;
@@ -690,7 +692,7 @@ static jint android_media_AudioTrack_get_playback_rate(JNIEnv *env,  jobject thi
 
 // ----------------------------------------------------------------------------
 static void android_media_AudioTrack_set_playback_settings(JNIEnv *env,  jobject thiz,
-        jfloatArray floatArray, jintArray intArray) {
+        jobject settings) {
     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
@@ -698,50 +700,39 @@ static void android_media_AudioTrack_set_playback_settings(JNIEnv *env,  jobject
         return;
     }
 
-    // NOTE: Get<Primitive>ArrayRegion throws ArrayIndexOutOfBoundsException if not valid.
-    // TODO: consider the actual occupancy.
-    float farray[2];
-    int iarray[2];
-    if ((env->GetFloatArrayRegion(floatArray, 0, 2, farray), env->ExceptionCheck()) == JNI_FALSE
-            &&
-        (env->GetIntArrayRegion(intArray, 0, 2, iarray), env->ExceptionCheck()) == JNI_FALSE) {
-        // arrays retrieved OK
-        AudioPlaybackRate playbackRate;
-        playbackRate.mSpeed = farray[0];
-        playbackRate.mPitch = farray[1];
-        playbackRate.mFallbackMode = (AudioTimestretchFallbackMode)iarray[0];
-        playbackRate.mStretchMode = (AudioTimestretchStretchMode)iarray[1];
-        if (lpTrack->setPlaybackRate(playbackRate) != OK) {
-            jniThrowException(env, "java/lang/IllegalArgumentException",
-                    "arguments out of range");
-        }
+    PlaybackSettings pbs;
+    pbs.fillFromJobject(env, gPlaybackSettingsFields, settings);
+
+    ALOGV("setPlaybackSettings: %d:%f %d:%f %d:%u %d:%u",
+            pbs.speedSet, pbs.audioRate.mSpeed,
+            pbs.pitchSet, pbs.audioRate.mPitch,
+            pbs.audioFallbackModeSet, pbs.audioRate.mFallbackMode,
+            pbs.audioStretchModeSet, pbs.audioRate.mStretchMode);
+
+    if (lpTrack->setPlaybackRate(pbs.audioRate) != OK) {
+        jniThrowException(env, "java/lang/IllegalArgumentException",
+                "arguments out of range");
     }
 }
 
 
 // ----------------------------------------------------------------------------
-static void android_media_AudioTrack_get_playback_settings(JNIEnv *env,  jobject thiz,
-        jfloatArray floatArray, jintArray intArray) {
+static jobject android_media_AudioTrack_get_playback_settings(JNIEnv *env,  jobject thiz,
+        jobject settings) {
     sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
     if (lpTrack == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
             "AudioTrack not initialized");
-        return;
+        return NULL;
     }
 
-    AudioPlaybackRate playbackRate = lpTrack->getPlaybackRate();
-
-    float farray[2] = {
-            playbackRate.mSpeed,
-            playbackRate.mPitch,
-    };
-    int iarray[2] = {
-            playbackRate.mFallbackMode,
-            playbackRate.mStretchMode,
-    };
-    // NOTE: Set<Primitive>ArrayRegion throws ArrayIndexOutOfBoundsException if not valid.
-    env->SetFloatArrayRegion(floatArray, 0, 2, farray);
-    env->SetIntArrayRegion(intArray, 0, 2, iarray);
+    PlaybackSettings pbs;
+    pbs.audioRate = lpTrack->getPlaybackRate();
+    pbs.speedSet = true;
+    pbs.pitchSet = true;
+    pbs.audioFallbackModeSet = true;
+    pbs.audioStretchModeSet = true;
+    return pbs.asJobject(env, gPlaybackSettingsFields);
 }
 
 
@@ -1012,9 +1003,11 @@ static JNINativeMethod gMethods[] = {
     {"native_get_playback_rate",
                              "()I",      (void *)android_media_AudioTrack_get_playback_rate},
     {"native_set_playback_settings",
-                             "([F[I)V",  (void *)android_media_AudioTrack_set_playback_settings},
+                             "(Landroid/media/PlaybackSettings;)V",
+                                         (void *)android_media_AudioTrack_set_playback_settings},
     {"native_get_playback_settings",
-                             "([F[I)V",  (void *)android_media_AudioTrack_get_playback_settings},
+                             "()Landroid/media/PlaybackSettings;",
+                                         (void *)android_media_AudioTrack_get_playback_settings},
     {"native_set_marker_pos","(I)I",     (void *)android_media_AudioTrack_set_marker_pos},
     {"native_get_marker_pos","()I",      (void *)android_media_AudioTrack_get_marker_pos},
     {"native_set_pos_update_period",
@@ -1088,6 +1081,8 @@ int register_android_media_AudioTrack(JNIEnv *env)
     javaAudioTrackFields.fieldStreamType = GetFieldIDOrDie(env,
             audioTrackClass, JAVA_STREAMTYPE_FIELD_NAME, "I");
 
+    env->DeleteLocalRef(audioTrackClass);
+
     // Get the AudioAttributes class and fields
     jclass audioAttrClass = FindClassOrDie(env, kAudioAttributesClassPathName);
     javaAudioAttrFields.fieldUsage = GetFieldIDOrDie(env, audioAttrClass, "mUsage", "I");
@@ -1097,6 +1092,11 @@ int register_android_media_AudioTrack(JNIEnv *env)
     javaAudioAttrFields.fieldFormattedTags = GetFieldIDOrDie(env,
             audioAttrClass, "mFormattedTags", "Ljava/lang/String;");
 
+    env->DeleteLocalRef(audioAttrClass);
+
+    // initialize PlaybackSettings field info
+    gPlaybackSettingsFields.init(env);
+
     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
index e2bba30..9bc223b 100644 (file)
@@ -134,8 +134,10 @@ private:
 
 // ----------------------------------------------------------------------------
 
-static jlong nativeListen(JNIEnv* env, jobject remoteDisplayObj, jstring ifaceStr) {
+static jlong nativeListen(JNIEnv* env, jobject remoteDisplayObj, jstring ifaceStr,
+        jstring opPackageNameStr) {
     ScopedUtfChars iface(env, ifaceStr);
+    ScopedUtfChars opPackageName(env, opPackageNameStr);
 
     sp<IServiceManager> sm = defaultServiceManager();
     sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(
@@ -146,7 +148,7 @@ static jlong nativeListen(JNIEnv* env, jobject remoteDisplayObj, jstring ifaceSt
     }
 
     sp<NativeRemoteDisplayClient> client(new NativeRemoteDisplayClient(env, remoteDisplayObj));
-    sp<IRemoteDisplay> display = service->listenForRemoteDisplay(
+    sp<IRemoteDisplay> display = service->listenForRemoteDisplay(String16(opPackageName.c_str()),
             client, String8(iface.c_str()));
     if (display == NULL) {
         ALOGE("Media player service rejected request to listen for remote display '%s'.",
@@ -176,7 +178,7 @@ static void nativeDispose(JNIEnv* env, jobject remoteDisplayObj, jlong ptr) {
 // ----------------------------------------------------------------------------
 
 static JNINativeMethod gMethods[] = {
-    {"nativeListen", "(Ljava/lang/String;)J",
+    {"nativeListen", "(Ljava/lang/String;Ljava/lang/String;)J",
             (void*)nativeListen },
     {"nativeDispose", "(J)V",
             (void*)nativeDispose },
index 45c078d..942e6a6 100644 (file)
@@ -79,6 +79,8 @@
 
     <protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED" />
     <protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGING" />
+    <protected-broadcast android:name="android.os.action.DEVICE_IDLE_MODE_CHANGED" />
+    <protected-broadcast android:name="android.os.action.POWER_SAVE_WHITELIST_CHANGED" />
 
     <protected-broadcast android:name="android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED" />
 
index a0b26f3..1ea459f 100644 (file)
@@ -50,7 +50,7 @@ extra_font_files := \
 # Do not include Motoya on space-constrained devices
 ifneq ($(SMALLER_FONT_FOOTPRINT),true)
 # Do not include Motoya if we are including full NotoSans
-ifneq ($(FONT_NOTOSANS_FULL),true)
+ifneq ($(FONT_NOTOSANS_JP_FULL),true)
 
 include $(CLEAR_VARS)
 LOCAL_MODULE := MTLmr3m.ttf
@@ -61,7 +61,7 @@ LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts
 include $(BUILD_PREBUILT)
 extra_font_files += MTLmr3m.ttf
 
-endif  # !FONT_NOTOSANS_FULL
+endif  # !FONT_NOTOSANS_JP_FULL
 endif  # !SMALLER_FONT_FOOTPRINT
 
 ################################
index c3d8cfa..e5b4612 100644 (file)
@@ -564,8 +564,6 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
 
         if (drawable != null) {
             drawable.setCallback(this);
-            drawable.setLayoutDirection(getLayoutDirection());
-            drawable.setLevel(getLevel());
         }
 
         childDrawable.mDrawable = drawable;
index c9f06e9..5617836 100644 (file)
@@ -15,13 +15,17 @@ public abstract class GateKeeper {
     private GateKeeper() {}
 
     public static IGateKeeperService getService() {
-        return IGateKeeperService.Stub.asInterface(
+        IGateKeeperService service = IGateKeeperService.Stub.asInterface(
                 ServiceManager.getService("android.service.gatekeeper.IGateKeeperService"));
+        if (service == null) {
+            throw new IllegalStateException("Gatekeeper service not available");
+        }
+        return service;
     }
 
     public static long getSecureUserId() throws IllegalStateException {
         try {
-            return GateKeeper.getService().getSecureUserId(UserHandle.myUserId());
+            return getService().getSecureUserId(UserHandle.myUserId());
         } catch (RemoteException e) {
             throw new IllegalStateException(
                     "Failed to obtain secure user ID from gatekeeper", e);
diff --git a/keystore/java/android/security/KeyPermanentlyInvalidatedException.java b/keystore/java/android/security/KeyPermanentlyInvalidatedException.java
new file mode 100644 (file)
index 0000000..229eab0
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package android.security;
+
+import java.security.InvalidKeyException;
+
+/**
+ * Indicates that the key can no longer be used because it has been permanently invalidated.
+ *
+ * <p>This can currently occur only for keys that require user authentication. Such keys are
+ * permanently invalidated once the secure lock screen is disabled (i.e., reconfigured to None,
+ * Swipe or other mode which does not authenticate the user) or when the secure lock screen is
+ * forcibly reset (e.g., by Device Admin). Additionally, keys configured to require user
+ * authentication for every use of the key are also permanently invalidated once a new fingerprint
+ * is enrolled or once no more fingerprints are enrolled.
+ */
+public class KeyPermanentlyInvalidatedException extends InvalidKeyException {
+
+    /**
+     * Constructs a new {@code KeyPermanentlyInvalidatedException} without detail message and cause.
+     */
+    public KeyPermanentlyInvalidatedException() {
+        super("Key permanently invalidated");
+    }
+
+    /**
+     * Constructs a new {@code KeyPermanentlyInvalidatedException} with the provided detail message
+     * and no cause.
+     */
+    public KeyPermanentlyInvalidatedException(String message) {
+        super(message);
+    }
+
+    /**
+     * Constructs a new {@code KeyPermanentlyInvalidatedException} with the provided detail message
+     * and cause.
+     */
+    public KeyPermanentlyInvalidatedException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}
index 5d863c2..f3b447e 100644 (file)
@@ -18,6 +18,8 @@ package android.security;
 
 import com.android.org.conscrypt.NativeConstants;
 
+import android.content.Context;
+import android.hardware.fingerprint.IFingerprintService;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -31,6 +33,7 @@ import android.security.keymaster.OperationResult;
 import android.util.Log;
 
 import java.security.InvalidKeyException;
+import java.util.List;
 import java.util.Locale;
 
 /**
@@ -490,7 +493,8 @@ public class KeyStore {
     /**
      * Check if the operation referenced by {@code token} is currently authorized.
      *
-     * @param token An operation token returned by a call to {@link KeyStore.begin}.
+     * @param token An operation token returned by a call to
+     * {@link #begin(String, int, boolean, KeymasterArguments, byte[], KeymasterArguments) begin}.
      */
     public boolean isOperationAuthorized(IBinder token) {
         try {
@@ -561,27 +565,80 @@ public class KeyStore {
      * Returns an {@link InvalidKeyException} corresponding to the provided
      * {@link KeyStoreException}.
      */
-    static InvalidKeyException getInvalidKeyException(KeyStoreException e) {
+    InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, KeyStoreException e) {
         switch (e.getErrorCode()) {
             case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
                 return new KeyExpiredException();
             case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID:
                 return new KeyNotYetValidException();
             case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
-                return new UserNotAuthenticatedException();
-            // TODO: Handle TBD Keymaster error code "invalid key: new fingerprint enrolled"
-            // case KeymasterDefs.KM_ERROR_TBD
-            //     return new NewFingerprintEnrolledException();
+            {
+                // We now need to determine whether the key/operation can become usable if user
+                // authentication is performed, or whether it can never become usable again.
+                // User authentication requirements are contained in the key's characteristics. We
+                // need to check whether these requirements can be be satisfied by asking the user
+                // to authenticate.
+                KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
+                int getKeyCharacteristicsErrorCode =
+                        getKeyCharacteristics(keystoreKeyAlias, null, null, keyCharacteristics);
+                if (getKeyCharacteristicsErrorCode != NO_ERROR) {
+                    return new InvalidKeyException(
+                            "Failed to obtained key characteristics",
+                            getKeyStoreException(getKeyCharacteristicsErrorCode));
+                }
+                List<Long> keySids =
+                        keyCharacteristics.getLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
+                if (keySids.isEmpty()) {
+                    // Key is not bound to any SIDs -- no amount of authentication will help here.
+                    return new KeyPermanentlyInvalidatedException();
+                }
+                long rootSid = GateKeeper.getSecureUserId();
+                if ((rootSid != 0) && (keySids.contains(Long.valueOf(rootSid)))) {
+                    // One of the key's SIDs is the current root SID -- user can be authenticated
+                    // against that SID.
+                    return new UserNotAuthenticatedException();
+                }
+
+                long fingerprintOnlySid = getFingerprintOnlySid();
+                if ((fingerprintOnlySid != 0)
+                        && (keySids.contains(Long.valueOf(fingerprintOnlySid)))) {
+                    // One of the key's SIDs is the current fingerprint SID -- user can be
+                    // authenticated against that SID.
+                    return new UserNotAuthenticatedException();
+                }
+
+                // None of the key's SIDs can ever be authenticated
+                return new KeyPermanentlyInvalidatedException();
+            }
             default:
                 return new InvalidKeyException("Keystore operation failed", e);
         }
     }
 
+    private static long getFingerprintOnlySid() {
+        IFingerprintService service = IFingerprintService.Stub.asInterface(
+                ServiceManager.getService(Context.FINGERPRINT_SERVICE));
+        if (service == null) {
+            return 0;
+        }
+
+        try {
+            long deviceId = 0; // TODO: plumb hardware id to FPMS
+            if (!service.isHardwareDetected(deviceId)) {
+                return 0;
+            }
+
+            return service.getAuthenticatorId();
+        } catch (RemoteException e) {
+            throw new IllegalStateException("Failed to communicate with fingerprint service", e);
+        }
+    }
+
     /**
      * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error
      * code.
      */
-    static InvalidKeyException getInvalidKeyException(int errorCode) {
-        return getInvalidKeyException(getKeyStoreException(errorCode));
+    InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int errorCode) {
+        return getInvalidKeyException(keystoreKeyAlias, getKeyStoreException(errorCode));
     }
 }
index 3b13e83..9393e32 100644 (file)
@@ -303,7 +303,7 @@ public abstract class KeyStoreCipherSpi extends CipherSpi implements KeyStoreCry
                 case KeymasterDefs.KM_ERROR_INVALID_NONCE:
                     throw new InvalidAlgorithmParameterException("Invalid IV");
             }
-            throw KeyStore.getInvalidKeyException(opResult.resultCode);
+            throw mKeyStore.getInvalidKeyException(mKey.getAlias(), opResult.resultCode);
         }
 
         if (opResult.token == null) {
index 175369c..8d71d1d 100644 (file)
@@ -169,7 +169,7 @@ public abstract class KeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOp
         if (opResult == null) {
             throw new KeyStoreConnectException();
         } else if (opResult.resultCode != KeyStore.NO_ERROR) {
-            throw KeyStore.getInvalidKeyException(opResult.resultCode);
+            throw mKeyStore.getInvalidKeyException(mKey.getAlias(), opResult.resultCode);
         }
         if (opResult.token == null) {
             throw new IllegalStateException("Keystore returned null operation token");
index 7bf5475..3ccb588 100644 (file)
@@ -18,12 +18,8 @@ package android.security;
 
 import android.content.Context;
 import android.hardware.fingerprint.FingerprintManager;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.UserHandle;
 import android.security.keymaster.KeymasterArguments;
 import android.security.keymaster.KeymasterDefs;
-import android.service.gatekeeper.IGateKeeperService;
 
 import libcore.util.EmptyArray;
 
@@ -347,20 +343,6 @@ public abstract class KeymasterUtils {
         return result;
     }
 
-    private static long getRootSid() {
-        IGateKeeperService gatekeeperService = IGateKeeperService.Stub.asInterface(
-                ServiceManager.getService("android.service.gatekeeper.IGateKeeperService"));
-        if (gatekeeperService == null) {
-            throw new IllegalStateException("Gatekeeper service not available");
-        }
-
-        try {
-            return gatekeeperService.getSecureUserId(UserHandle.myUserId());
-        } catch (RemoteException e) {
-            throw new IllegalStateException("Failed to obtain root SID");
-        }
-    }
-
     /**
      * Adds keymaster arguments to express the key's authorization policy supported by user
      * authentication.
@@ -402,7 +384,7 @@ public abstract class KeymasterUtils {
         } else {
             // The key is authorized for use for the specified amount of time after the user has
             // authenticated. Whatever unlocks the secure lock screen should authorize this key.
-            long rootSid = getRootSid();
+            long rootSid = GateKeeper.getSecureUserId();
             if (rootSid == 0) {
                 throw new IllegalStateException("Secure lock screen must be enabled"
                         + " to create keys requiring user authentication");
diff --git a/keystore/java/android/security/NewFingerprintEnrolledException.java b/keystore/java/android/security/NewFingerprintEnrolledException.java
deleted file mode 100644 (file)
index 4fe210b..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-package android.security;
-
-import java.security.InvalidKeyException;
-
-/**
- * Indicates that a cryptographic operation could not be performed because the key used by the
- * operation is permanently invalid because a new fingerprint was enrolled.
- */
-public class NewFingerprintEnrolledException extends InvalidKeyException {
-
-    /**
-     * Constructs a new {@code NewFingerprintEnrolledException} without detail message and cause.
-     */
-    public NewFingerprintEnrolledException() {
-        super("Invalid key: new fingerprint enrolled");
-    }
-
-    /**
-     * Constructs a new {@code NewFingerprintEnrolledException} with the provided detail message and
-     * no cause.
-     */
-    public NewFingerprintEnrolledException(String message) {
-        super(message);
-    }
-}
index 66f4dd8..2954fa7 100644 (file)
@@ -20,7 +20,7 @@ import java.security.InvalidKeyException;
 
 /**
  * Indicates that a cryptographic operation could not be performed because the user has not been
- * authenticated recently enough.
+ * authenticated recently enough. Authenticating the user will resolve this issue.
  */
 public class UserNotAuthenticatedException extends InvalidKeyException {
 
index c78971a..dd6af03 100644 (file)
@@ -638,8 +638,7 @@ void DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty) {
     DEFER_LOGD("--flushing");
     renderer.eventMark("Flush");
 
-    // save and restore (with draw modifiers) so that reordering doesn't affect final state
-    DrawModifiers restoreDrawModifiers = renderer.getDrawModifiers();
+    // save and restore so that reordering doesn't affect final state
     renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
 
     if (CC_LIKELY(mAvoidOverdraw)) {
@@ -654,7 +653,6 @@ void DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty) {
     replayBatchList(mBatches, renderer, dirty);
 
     renderer.restoreToCount(1);
-    renderer.setDrawModifiers(restoreDrawModifiers);
 
     DEFER_LOGD("--flush complete, returning %x", status);
     clear();
index f535afb..3d0ca6d 100644 (file)
@@ -61,7 +61,6 @@ public:
     int mClipSideFlags; // specifies which sides of the bounds are clipped, unclipped if cleared
     bool mClipped;
     mat4 mMatrix;
-    DrawModifiers mDrawModifiers;
     float mAlpha;
     const RoundRectClipState* mRoundRectClipState;
 };
index 65daf03..c8189b8 100644 (file)
@@ -53,6 +53,7 @@ enum class FrameInfoFlags {
     kWindowLayoutChanged = 1 << 0,
     kRTAnimation = 1 << 1,
     kSurfaceCanvas = 1 << 2,
+    kSkippedFrame = 1 << 3,
 };
 MAKE_FLAGS_ENUM(FrameInfoFlags)
 
@@ -101,6 +102,10 @@ public:
         set(FrameInfoIndex::kFrameCompleted) = systemTime(CLOCK_MONOTONIC);
     }
 
+    void addFlag(FrameInfoFlags flag) {
+        set(FrameInfoIndex::kFlags) |= static_cast<uint64_t>(flag);
+    }
+
     int64_t operator[](FrameInfoIndex index) const {
         if (index == FrameInfoIndex::kNumIndexes) return 0;
         return mFrameInfo[static_cast<int>(index)];
index 30935d5..7fc31b8 100644 (file)
@@ -76,9 +76,6 @@ OpenGLRenderer::OpenGLRenderer(RenderState& renderState)
         , mLightRadius(FLT_MIN)
         , mAmbientShadowAlpha(0)
         , mSpotShadowAlpha(0) {
-    // *set* draw modifiers to be 0
-    memset(&mDrawModifiers, 0, sizeof(mDrawModifiers));
-    mDrawModifiers.mOverrideLayerAlpha = 1.0f;
 }
 
 OpenGLRenderer::~OpenGLRenderer() {
@@ -1188,10 +1185,9 @@ bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDef
         state.mClip.set(currentClip);
     }
 
-    // Transform, drawModifiers, and alpha always deferred, since they are used by state operations
+    // Transform and alpha always deferred, since they are used by state operations
     // (Note: saveLayer/restore use colorFilter and alpha, so we just save restore everything)
     state.mMatrix.load(*currentMatrix);
-    state.mDrawModifiers = mDrawModifiers;
     state.mAlpha = currentSnapshot()->alpha;
 
     // always store/restore, since it's just a pointer
@@ -1202,7 +1198,6 @@ bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDef
 void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore) {
     setMatrix(state.mMatrix);
     writableSnapshot()->alpha = state.mAlpha;
-    mDrawModifiers = state.mDrawModifiers;
     writableSnapshot()->roundRectClipState = state.mRoundRectClipState;
 
     if (state.mClipValid && !skipClipRestore) {
@@ -1262,7 +1257,7 @@ void OpenGLRenderer::attachStencilBufferToLayer(Layer* layer) {
         endTiling();
 
         RenderBuffer* buffer = mCaches.renderBufferCache.get(
-                Stencil::getSmallestStencilFormat(),
+                Stencil::getLayerStencilFormat(),
                 layer->getWidth(), layer->getHeight());
         layer->setStencilRenderBuffer(buffer);
 
@@ -2541,21 +2536,11 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot
 void OpenGLRenderer::getAlphaAndMode(const SkPaint* paint, int* alpha,
         SkXfermode::Mode* mode) const {
     getAlphaAndModeDirect(paint, alpha,  mode);
-    if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
-        // if drawing a layer, ignore the paint's alpha
-        *alpha = mDrawModifiers.mOverrideLayerAlpha * 255;
-    }
     *alpha *= currentSnapshot()->alpha;
 }
 
 float OpenGLRenderer::getLayerAlpha(const Layer* layer) const {
-    float alpha;
-    if (mDrawModifiers.mOverrideLayerAlpha < 1.0f) {
-        alpha = mDrawModifiers.mOverrideLayerAlpha;
-    } else {
-        alpha = layer->getAlpha() / 255.0f;
-    }
-    return alpha * currentSnapshot()->alpha;
+    return (layer->getAlpha() / 255.0f) * currentSnapshot()->alpha;
 }
 
 }; // namespace uirenderer
index 5f8960a..c34eb2c 100755 (executable)
@@ -68,17 +68,6 @@ class RenderNode;
 class TextDrawFunctor;
 class VertexBuffer;
 
-struct DrawModifiers {
-    DrawModifiers()
-        : mOverrideLayerAlpha(0.0f) {}
-
-    void reset() {
-        mOverrideLayerAlpha = 0.0f;
-    }
-
-    float mOverrideLayerAlpha;
-};
-
 enum StateDeferFlags {
     kStateDeferFlag_Draw = 0x1,
     kStateDeferFlag_Clip = 0x2
@@ -236,9 +225,6 @@ public:
 
     void setDrawFilter(SkDrawFilter* filter);
 
-    // If this value is set to < 1.0, it overrides alpha set on layer (see drawBitmap, drawLayer)
-    void setOverrideLayerAlpha(float alpha) { mDrawModifiers.mOverrideLayerAlpha = alpha; }
-
     /**
      * Store the current display state (most importantly, the current clip and transform), and
      * additionally map the state's bounds from local to window coordinates.
@@ -249,9 +235,6 @@ public:
     void restoreDisplayState(const DeferredDisplayState& state, bool skipClipRestore = false);
     void setupMergedMultiDraw(const Rect* clipRect);
 
-    const DrawModifiers& getDrawModifiers() { return mDrawModifiers; }
-    void setDrawModifiers(const DrawModifiers& drawModifiers) { mDrawModifiers = drawModifiers; }
-
     bool isCurrentTransformSimple() {
         return currentTransform()->isSimple();
     }
@@ -523,8 +506,7 @@ protected:
 
     /**
      * Gets the alpha and xfermode out of a paint object. If the paint is null
-     * alpha will be 255 and the xfermode will be SRC_OVER. Accounts for both
-     * snapshot alpha, and overrideLayerAlpha
+     * alpha will be 255 and the xfermode will be SRC_OVER. Accounts for snapshot alpha.
      *
      * @param paint The paint to extract values from
      * @param alpha Where to store the resulting alpha
@@ -533,7 +515,7 @@ protected:
     inline void getAlphaAndMode(const SkPaint* paint, int* alpha, SkXfermode::Mode* mode) const;
 
     /**
-     * Gets the alpha from a layer, accounting for snapshot alpha and overrideLayerAlpha
+     * Gets the alpha from a layer, accounting for snapshot alpha
      *
      * @param layer The layer from which the alpha is extracted
      */
@@ -868,10 +850,6 @@ private:
     // Default UV mapper
     const UvMapper mUvMapper;
 
-    // shader, filters, and shadow
-    DrawModifiers mDrawModifiers;
-    SkPaint mFilteredPaint;
-
     // List of rectangles to clear after saveLayer() is invoked
     std::vector<Rect> mLayers;
     // List of layers to update at the beginning of a frame
index ac4c0d0..8f95e0d 100644 (file)
@@ -389,12 +389,9 @@ void RenderNode::setViewProperties(OpenGLRenderer& renderer, T& handler) {
     if (properties().getAlpha() < 1) {
         if (isLayer) {
             clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
-
-            renderer.setOverrideLayerAlpha(properties().getAlpha());
-        } else {
-            LOG_ALWAYS_FATAL_IF(properties().getHasOverlappingRendering());
-            renderer.scaleAlpha(properties().getAlpha());
         }
+        LOG_ALWAYS_FATAL_IF(!isLayer && properties().getHasOverlappingRendering());
+        renderer.scaleAlpha(properties().getAlpha());
     }
     if (clipFlags) {
         Rect clipRect;
@@ -902,7 +899,6 @@ void RenderNode::issueOperations(OpenGLRenderer& renderer, T& handler) {
     DISPLAY_LIST_LOGD("%*sRestoreToCount %d", (level + 1) * 2, "", restoreTo);
     handler(new (alloc) RestoreToCountOp(restoreTo),
             PROPERTY_SAVECOUNT, properties().getClipToBounds());
-    renderer.setOverrideLayerAlpha(1.0f);
 
     DISPLAY_LIST_LOGD("%*sDone (%p, %s)", level * 2, "", this, getName());
     handler.endMark();
index 0ed3c47..7b75690 100644 (file)
@@ -149,12 +149,10 @@ void RenderProperties::debugOutputProperties(const int level) const {
     if (mPrimitiveFields.mAlpha < 1) {
         if (isLayer) {
             clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
-
-            ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
-        } else {
-            LOG_ALWAYS_FATAL_IF(mPrimitiveFields.mHasOverlappingRendering);
-            ALOGD("%*sScaleAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
         }
+
+        LOG_ALWAYS_FATAL_IF(!isLayer && mPrimitiveFields.mHasOverlappingRendering);
+        ALOGD("%*sScaleAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
     }
     if (clipFlags) {
         Rect clipRect;
index cedb233..92a057d 100644 (file)
@@ -42,12 +42,17 @@ uint8_t Stencil::getStencilSize() {
     return STENCIL_BUFFER_SIZE;
 }
 
-GLenum Stencil::getSmallestStencilFormat() {
+/**
+ * This method will return either GL_STENCIL_INDEX4_OES if supported,
+ * GL_STENCIL_INDEX8 if not.
+ *
+ * Layers can't use a single bit stencil because multi-rect ClipArea needs a high enough
+ * stencil resolution to represent the summation of multiple intersecting rect geometries.
+ */
+GLenum Stencil::getLayerStencilFormat() {
 #if !DEBUG_STENCIL
     const Extensions& extensions = Caches::getInstance().extensions();
-    if (extensions.has1BitStencil()) {
-        return GL_STENCIL_INDEX1_OES;
-    } else if (extensions.has4BitStencil()) {
+    if (extensions.has4BitStencil()) {
         return GL_STENCIL_INDEX4_OES;
     }
 #endif
index e4f0f3f..3a8f8eb 100644 (file)
@@ -42,10 +42,7 @@ public:
      */
     ANDROID_API static uint8_t getStencilSize();
 
-    /**
-     * Returns the smallest stencil format accepted by render buffers.
-     */
-    static GLenum getSmallestStencilFormat();
+    static GLenum getLayerStencilFormat();
 
     /**
      * Clears the stencil buffer.
index 9237151..3de3086 100644 (file)
 #include "../OpenGLRenderer.h"
 
 #include <algorithm>
+#include <cutils/properties.h>
 #include <private/hwui/DrawGlInfo.h>
 #include <strings.h>
 
 #define TRIM_MEMORY_COMPLETE 80
 #define TRIM_MEMORY_UI_HIDDEN 20
 
+#define PROPERTY_SKIP_EMPTY_DAMAGE "debug.hwui.skip_empty_damage"
+
+static bool sInitialized = false;
+static bool sSkipEmptyDamage = true;
+
+static void initGlobals() {
+    if (sInitialized) return;
+    sInitialized = true;
+    sSkipEmptyDamage = property_get_bool(PROPERTY_SKIP_EMPTY_DAMAGE,
+            sSkipEmptyDamage);
+}
+
 namespace android {
 namespace uirenderer {
 namespace renderthread {
@@ -45,6 +58,9 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent,
         , mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord()))
         , mRootRenderNode(rootRenderNode)
         , mJankTracker(thread.timeLord().frameIntervalNanos()) {
+    // Done lazily at first draw instead of at library load to avoid
+    // running pre-zygote fork
+    initGlobals();
     mRenderThread.renderState().registerCanvasContext(this);
     mProfiler.setDensity(mRenderThread.mainDisplayInfo().density);
 }
@@ -203,12 +219,17 @@ void CanvasContext::draw() {
     LOG_ALWAYS_FATAL_IF(!mCanvas || mEglSurface == EGL_NO_SURFACE,
             "drawRenderNode called on a context with no canvas or surface!");
 
-    profiler().markPlaybackStart();
-    mCurrentFrameInfo->markIssueDrawCommandsStart();
-
     SkRect dirty;
     mDamageAccumulator.finish(&dirty);
 
+    if (dirty.isEmpty() && sSkipEmptyDamage) {
+        mCurrentFrameInfo->addFlag(FrameInfoFlags::kSkippedFrame);
+        return;
+    }
+
+    profiler().markPlaybackStart();
+    mCurrentFrameInfo->markIssueDrawCommandsStart();
+
     EGLint width, height;
     mEglManager.beginFrame(mEglSurface, &width, &height);
     if (width != mCanvas->getViewportWidth() || height != mCanvas->getViewportHeight()) {
@@ -277,6 +298,8 @@ void CanvasContext::doFrame() {
     prepareTree(info, frameInfo);
     if (info.out.canDrawThisFrame) {
         draw();
+    } else {
+        mCurrentFrameInfo->addFlag(FrameInfoFlags::kSkippedFrame);
     }
 }
 
index 201a796..d5e6b3e 100644 (file)
@@ -26,6 +26,8 @@ import java.util.Iterator;
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.app.ActivityThread;
+import android.app.Application;
 import android.os.Binder;
 import android.os.Handler;
 import android.os.IBinder;
@@ -378,7 +380,7 @@ public class AudioRecord
         int initResult = native_setup( new WeakReference<AudioRecord>(this),
                 mAudioAttributes, mSampleRate, mChannelMask, mChannelIndexMask,
                 mAudioFormat, mNativeBufferSizeInBytes,
-                session);
+                session, getMyOpPackageName());
         if (initResult != SUCCESS) {
             loge("Error code "+initResult+" when initializing native AudioRecord object.");
             return; // with mState == STATE_UNINITIALIZED
@@ -1321,7 +1323,6 @@ public class AudioRecord
         return native_set_pos_update_period(periodInFrames);
     }
 
-
     //--------------------------------------------------------------------------
     // Explicit Routing
     //--------------------
@@ -1451,7 +1452,7 @@ public class AudioRecord
     private native final int native_setup(Object audiorecord_this,
             Object /*AudioAttributes*/ attributes,
             int sampleRate, int channelMask, int channelIndexMask, int audioFormat,
-            int buffSizeInBytes, int[] sessionId);
+            int buffSizeInBytes, int[] sessionId, String opPackageName);
 
     // TODO remove: implementation calls directly into implementation of native_release()
     private native final void native_finalize();
@@ -1500,4 +1501,14 @@ public class AudioRecord
         Log.e(TAG, msg);
     }
 
+    private static String getMyOpPackageName() {
+        ActivityThread activityThread = ActivityThread.currentActivityThread();
+        if (activityThread != null) {
+            Application application = activityThread.getApplication();
+            if (application != null) {
+                return application.getOpPackageName();
+            }
+        }
+        throw new IllegalStateException("Cannot create AudioRecord outside of an app");
+    }
 }
index 6f1fd24..cb05cc5 100644 (file)
@@ -920,13 +920,7 @@ public class AudioTrack
      * @throws IllegalStateException if track is not initialized.
      */
     public @NonNull PlaybackSettings getPlaybackSettings() {
-        float[] floatArray = new float[2];
-        int[] intArray = new int[2];
-        native_get_playback_settings(floatArray, intArray);
-        return new PlaybackSettings()
-                .setSpeed(floatArray[0])
-                .setPitch(floatArray[1])
-                .setAudioFallbackMode(intArray[0]);
+        return native_get_playback_settings();
     }
 
     /**
@@ -1340,21 +1334,7 @@ public class AudioTrack
         if (settings == null) {
             throw new IllegalArgumentException("settings is null");
         }
-        float[] floatArray;
-        int[] intArray;
-        try {
-            floatArray = new float[] {
-                    settings.getSpeed(),
-                    settings.getPitch(),
-            };
-            intArray = new int[] {
-                    settings.getAudioFallbackMode(),
-                    PlaybackSettings.AUDIO_STRETCH_MODE_DEFAULT,
-            };
-        } catch (IllegalStateException e) {
-            throw new IllegalArgumentException(e);
-        }
-        native_set_playback_settings(floatArray, intArray);
+        native_set_playback_settings(settings);
     }
 
 
@@ -2353,14 +2333,8 @@ public class AudioTrack
     private native final int native_set_playback_rate(int sampleRateInHz);
     private native final int native_get_playback_rate();
 
-    // floatArray must be a non-null array of length >= 2
-    // [0] is speed
-    // [1] is pitch
-    // intArray must be a non-null array of length >= 2
-    // [0] is audio fallback mode
-    // [1] is audio stretch mode
-    private native final void native_set_playback_settings(float[] floatArray, int[] intArray);
-    private native final void native_get_playback_settings(float[] floatArray, int[] intArray);
+    private native final void native_set_playback_settings(@NonNull PlaybackSettings settings);
+    private native final @NonNull PlaybackSettings native_get_playback_settings();
 
     private native final int native_set_marker_pos(int marker);
     private native final int native_get_marker_pos();
index 78fd9f0..1b054cc 100644 (file)
@@ -18,6 +18,7 @@ package android.media;
 
 import android.annotation.SystemApi;
 import android.app.ActivityThread;
+import android.app.Application;
 import android.hardware.Camera;
 import android.os.Handler;
 import android.os.Looper;
@@ -111,7 +112,7 @@ public class MediaRecorder
         /* Native setup requires a weak reference to our object.
          * It's easier to create it here than in C++.
          */
-        native_setup(new WeakReference<MediaRecorder>(this), packageName);
+        native_setup(new WeakReference<MediaRecorder>(this), packageName, getMyOpPackageName());
     }
 
     /**
@@ -1080,7 +1081,7 @@ public class MediaRecorder
     private static native final void native_init();
 
     private native final void native_setup(Object mediarecorder_this,
-            String clientName) throws IllegalStateException;
+            String clientName, String opPackageName) throws IllegalStateException;
 
     private native final void native_finalize();
 
@@ -1088,4 +1089,15 @@ public class MediaRecorder
 
     @Override
     protected void finalize() { native_finalize(); }
+
+    private static String getMyOpPackageName() {
+        ActivityThread activityThread = ActivityThread.currentActivityThread();
+        if (activityThread != null) {
+            Application application = activityThread.getApplication();
+            if (application != null) {
+                return application.getOpPackageName();
+            }
+        }
+        throw new IllegalStateException("Cannot create AudioRecord outside of an app");
+    }
 }
index 4e937a5..5add65a 100644 (file)
@@ -37,17 +37,19 @@ public final class RemoteDisplay {
     private final CloseGuard mGuard = CloseGuard.get();
     private final Listener mListener;
     private final Handler mHandler;
+    private final String mOpPackageName;
 
     private long mPtr;
 
-    private native long nativeListen(String iface);
+    private native long nativeListen(String iface, String opPackageName);
     private native void nativeDispose(long ptr);
     private native void nativePause(long ptr);
     private native void nativeResume(long ptr);
 
-    private RemoteDisplay(Listener listener, Handler handler) {
+    private RemoteDisplay(Listener listener, Handler handler, String opPackageName) {
         mListener = listener;
         mHandler = handler;
+        mOpPackageName = opPackageName;
     }
 
     @Override
@@ -66,7 +68,8 @@ public final class RemoteDisplay {
      * @param listener The listener to invoke when displays are connected or disconnected.
      * @param handler The handler on which to invoke the listener.
      */
-    public static RemoteDisplay listen(String iface, Listener listener, Handler handler) {
+    public static RemoteDisplay listen(String iface, Listener listener, Handler handler,
+            String opPackageName) {
         if (iface == null) {
             throw new IllegalArgumentException("iface must not be null");
         }
@@ -77,7 +80,7 @@ public final class RemoteDisplay {
             throw new IllegalArgumentException("handler must not be null");
         }
 
-        RemoteDisplay display = new RemoteDisplay(listener, handler);
+        RemoteDisplay display = new RemoteDisplay(listener, handler, opPackageName);
         display.startListening(iface);
         return display;
     }
@@ -113,7 +116,7 @@ public final class RemoteDisplay {
     }
 
     private void startListening(String iface) {
-        mPtr = nativeListen(iface);
+        mPtr = nativeListen(iface, mOpPackageName);
         if (mPtr == 0) {
             throw new IllegalStateException("Could not start listening for "
                     + "remote display connection on \"" + iface + "\"");
index a8b9686..9fc90df 100644 (file)
@@ -18,6 +18,8 @@ package android.media.audiofx;
 
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.app.ActivityThread;
+import android.app.Application;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -395,7 +397,7 @@ public class AudioEffect {
         // native initialization
         int initResult = native_setup(new WeakReference<AudioEffect>(this),
                 type.toString(), uuid.toString(), priority, audioSession, id,
-                desc);
+                desc, getMyOpPackageName());
         if (initResult != SUCCESS && initResult != ALREADY_EXISTS) {
             Log.e(TAG, "Error code " + initResult
                     + " when initializing AudioEffect.");
@@ -1217,7 +1219,8 @@ public class AudioEffect {
     private static native final void native_init();
 
     private native final int native_setup(Object audioeffect_this, String type,
-            String uuid, int priority, int audioSession, int[] id, Object[] desc);
+            String uuid, int priority, int audioSession, int[] id, Object[] desc,
+            String opPackageName);
 
     private native final void native_finalize();
 
@@ -1356,4 +1359,15 @@ public class AudioEffect {
         }
         return b;
     }
+
+    private static String getMyOpPackageName() {
+        ActivityThread activityThread = ActivityThread.currentActivityThread();
+        if (activityThread != null) {
+            Application application = activityThread.getApplication();
+            if (application != null) {
+                return application.getOpPackageName();
+            }
+        }
+        throw new IllegalStateException("Cannot create AudioEffect outside of an app");
+    }
 }
index 24c74ac..0c48063 100644 (file)
@@ -16,6 +16,8 @@
 
 package android.media.audiofx;
 
+import android.app.ActivityThread;
+import android.app.Application;
 import android.util.Log;
 import java.lang.ref.WeakReference;
 import android.os.Handler;
@@ -206,7 +208,8 @@ public class Visualizer {
         synchronized (mStateLock) {
             mState = STATE_UNINITIALIZED;
             // native initialization
-            int result = native_setup(new WeakReference<Visualizer>(this), audioSession, id);
+            int result = native_setup(new WeakReference<Visualizer>(this), audioSession, id,
+                    getMyOpPackageName());
             if (result != SUCCESS && result != ALREADY_EXISTS) {
                 Log.e(TAG, "Error code "+result+" when initializing Visualizer.");
                 switch (result) {
@@ -716,7 +719,8 @@ public class Visualizer {
 
     private native final int native_setup(Object audioeffect_this,
                                           int audioSession,
-                                          int[] id);
+                                          int[] id,
+                                          String opPackageName);
 
     private native final void native_finalize();
 
@@ -766,5 +770,15 @@ public class Visualizer {
 
     }
 
+    private static String getMyOpPackageName() {
+        ActivityThread activityThread = ActivityThread.currentActivityThread();
+        if (activityThread != null) {
+            Application application = activityThread.getApplication();
+            if (application != null) {
+                return application.getOpPackageName();
+            }
+        }
+        throw new IllegalStateException("Cannot create AudioRecord outside of an app");
+    }
 }
 
index af108eb..35374ed 100644 (file)
@@ -69,6 +69,13 @@ public final class MidiDeviceInfo implements Parcelable {
     public static final String PROPERTY_PRODUCT = "product";
 
     /**
+     * Bundle key for the device's version property.
+     * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
+     * Matches the USB device version number for USB MIDI devices.
+     */
+    public static final String PROPERTY_VERSION = "version";
+
+    /**
      * Bundle key for the device's serial number property.
      * Used with the {@link android.os.Bundle} returned by {@link #getProperties}
      * Matches the USB device serial number for USB MIDI devices.
index 8b7d40d..02297fc 100644 (file)
@@ -31,6 +31,8 @@
 #include <media/mediarecorder.h>
 #include <utils/threads.h>
 
+#include <ScopedUtfChars.h>
+
 #include "jni.h"
 #include "JNIHelp.h"
 #include "android_runtime/AndroidRuntime.h"
@@ -444,11 +446,13 @@ android_media_MediaRecorder_native_init(JNIEnv *env)
 
 static void
 android_media_MediaRecorder_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
-                                         jstring packageName)
+                                         jstring packageName, jstring opPackageName)
 {
     ALOGV("setup");
 
-    sp<MediaRecorder> mr = new MediaRecorder();
+    ScopedUtfChars opPackageNameStr(env, opPackageName);
+
+    sp<MediaRecorder> mr = new MediaRecorder(String16(opPackageNameStr.c_str()));
     if (mr == NULL) {
         jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
         return;
@@ -506,7 +510,8 @@ static JNINativeMethod gMethods[] = {
     {"native_reset",         "()V",                             (void *)android_media_MediaRecorder_native_reset},
     {"release",              "()V",                             (void *)android_media_MediaRecorder_release},
     {"native_init",          "()V",                             (void *)android_media_MediaRecorder_native_init},
-    {"native_setup",         "(Ljava/lang/Object;Ljava/lang/String;)V", (void *)android_media_MediaRecorder_native_setup},
+    {"native_setup",         "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)V",
+                                                                (void *)android_media_MediaRecorder_native_setup},
     {"native_finalize",      "()V",                             (void *)android_media_MediaRecorder_native_finalize},
 };
 
index c364d46..96b72a2 100644 (file)
@@ -25,6 +25,8 @@
 #include <android_runtime/AndroidRuntime.h>
 #include "media/AudioEffect.h"
 
+#include <ScopedUtfChars.h>
+
 using namespace android;
 
 #define AUDIOEFFECT_SUCCESS                      0
@@ -249,7 +251,8 @@ android_media_AudioEffect_native_init(JNIEnv *env)
 
 static jint
 android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
-        jstring type, jstring uuid, jint priority, jint sessionId, jintArray jId, jobjectArray javadesc)
+        jstring type, jstring uuid, jint priority, jint sessionId, jintArray jId,
+        jobjectArray javadesc, jstring opPackageName)
 {
     ALOGV("android_media_AudioEffect_native_setup");
     AudioEffectJniStorage* lpJniStorage = NULL;
@@ -267,6 +270,8 @@ android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_t
     jstring jdescName;
     jstring jdescImplementor;
 
+    ScopedUtfChars opPackageNameStr(env, opPackageName);
+
     if (type != NULL) {
         typeStr = env->GetStringUTFChars(type, NULL);
         if (typeStr == NULL) {  // Out of memory
@@ -312,6 +317,7 @@ android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_t
 
     // create the native AudioEffect object
     lpAudioEffect = new AudioEffect(typeStr,
+                                    String16(opPackageNameStr.c_str()),
                                     uuidStr,
                                     priority,
                                     effectCallback,
@@ -868,7 +874,7 @@ android_media_AudioEffect_native_queryPreProcessings(JNIEnv *env, jclass clazz _
 // Dalvik VM type signatures
 static JNINativeMethod gMethods[] = {
     {"native_init",          "()V",      (void *)android_media_AudioEffect_native_init},
-    {"native_setup",         "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;)I",
+    {"native_setup",         "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;Ljava/lang/String;)I",
                                          (void *)android_media_AudioEffect_native_setup},
     {"native_finalize",      "()V",      (void *)android_media_AudioEffect_native_finalize},
     {"native_release",       "()V",      (void *)android_media_AudioEffect_native_release},
index 460277f..abc681e 100644 (file)
@@ -26,6 +26,8 @@
 #include <utils/threads.h>
 #include "media/Visualizer.h"
 
+#include <ScopedUtfChars.h>
+
 using namespace android;
 
 #define VISUALIZER_SUCCESS                      0
@@ -331,7 +333,7 @@ static void android_media_visualizer_effect_callback(int32_t event,
 
 static jint
 android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
-        jint sessionId, jintArray jId)
+        jint sessionId, jintArray jId, jstring opPackageName)
 {
     ALOGV("android_media_visualizer_native_setup");
     visualizerJniStorage* lpJniStorage = NULL;
@@ -339,6 +341,8 @@ android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
     Visualizer* lpVisualizer = NULL;
     jint* nId = NULL;
 
+    ScopedUtfChars opPackageNameStr(env, opPackageName);
+
     lpJniStorage = new visualizerJniStorage();
     if (lpJniStorage == NULL) {
         ALOGE("setup: Error creating JNI Storage");
@@ -362,7 +366,8 @@ android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_th
     }
 
     // create the native Visualizer object
-    lpVisualizer = new Visualizer(0,
+    lpVisualizer = new Visualizer(String16(opPackageNameStr.c_str()),
+                                  0,
                                   android_media_visualizer_effect_callback,
                                   lpJniStorage,
                                   sessionId);
@@ -662,7 +667,7 @@ android_media_setPeriodicCapture(JNIEnv *env, jobject thiz, jint rate, jboolean
 // Dalvik VM type signatures
 static JNINativeMethod gMethods[] = {
     {"native_init",            "()V",     (void *)android_media_visualizer_native_init},
-    {"native_setup",           "(Ljava/lang/Object;I[I)I",
+    {"native_setup",           "(Ljava/lang/Object;I[ILjava/lang/String;)I",
                                           (void *)android_media_visualizer_native_setup},
     {"native_finalize",          "()V",   (void *)android_media_visualizer_native_finalize},
     {"native_release",           "()V",   (void *)android_media_visualizer_native_release},
index 7b13e4b..a8ecc42 100644 (file)
@@ -2158,7 +2158,7 @@ public class NotificationPanelView extends PanelView implements
     }
 
     @Override
-    public void onPinnedModeChanged(final boolean inPinnedMode) {
+    public void onHeadsUpPinnedModeChanged(final boolean inPinnedMode) {
         if (inPinnedMode) {
             mHeadsUpExistenceChangedRunnable.run();
             updateNotificationTranslucency();
index bf27e84..9a6a80e 100644 (file)
@@ -1852,7 +1852,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
     }
 
     @Override
-    public void onPinnedModeChanged(boolean inPinnedMode) {
+    public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
         if (inPinnedMode) {
             mStatusBarWindowManager.setHeadsUpShowing(true);
         } else {
@@ -1874,6 +1874,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
 
     @Override
     public void onHeadsUpPinned(ExpandableNotificationRow headsUp) {
+        dismissVolumeDialog();
     }
 
     @Override
@@ -2377,13 +2378,17 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
         }
         // manually dismiss the volume panel when interacting with the nav bar
         if (changing && interacting && barWindow == StatusBarManager.WINDOW_NAVIGATION_BAR) {
-            if (mVolumeComponent != null) {
-                mVolumeComponent.dismissNow();
-            }
+            dismissVolumeDialog();
         }
         checkBarModes();
     }
 
+    private void dismissVolumeDialog() {
+        if (mVolumeComponent != null) {
+            mVolumeComponent.dismissNow();
+        }
+    }
+
     private void resumeSuspendedAutohide() {
         if (mAutohideSuspended) {
             scheduleAutohide();
index ae98e76..e6edbea 100644 (file)
@@ -347,7 +347,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener,
     }
 
     @Override
-    public void onPinnedModeChanged(boolean inPinnedMode) {
+    public void onHeadsUpPinnedModeChanged(boolean inPinnedMode) {
     }
 
     @Override
index 8f83daa..0db9221 100644 (file)
@@ -208,7 +208,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
         }
         mHasPinnedNotification = hasPinnedNotification;
         for (OnHeadsUpChangedListener listener : mListeners) {
-            listener.onPinnedModeChanged(hasPinnedNotification);
+            listener.onHeadsUpPinnedModeChanged(hasPinnedNotification);
         }
     }
 
@@ -539,7 +539,7 @@ public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsL
          *
          * @param inPinnedMode whether there are any pinned heads-ups
          */
-        void onPinnedModeChanged(boolean inPinnedMode);
+        void onHeadsUpPinnedModeChanged(boolean inPinnedMode);
 
         /**
          * A notification was just pinned to the top.
index 0e3867d..745c190 100644 (file)
@@ -461,7 +461,7 @@ class AlarmManagerService extends SystemService {
     // to run during this time are placed in mPendingWhileIdleAlarms
     Alarm mPendingIdleUntil = null;
     Alarm mNextWakeFromIdle = null;
-    final ArrayList<Alarm> mPendingWhileIdleAlarms = new ArrayList<>();
+    ArrayList<Alarm> mPendingWhileIdleAlarms = new ArrayList<>();
 
     public AlarmManagerService(Context context) {
         super(context);
@@ -567,10 +567,14 @@ class AlarmManagerService extends SystemService {
 
     void restorePendingWhileIdleAlarmsLocked() {
         // Bring pending alarms back into the main list.
-        final long nowElapsed = SystemClock.elapsedRealtime();
-        for (int i=mPendingWhileIdleAlarms.size() - 1; i >= 0 && mPendingIdleUntil == null; i--) {
-            Alarm a = mPendingWhileIdleAlarms.remove(i);
-            reAddAlarmLocked(a, nowElapsed, false);
+        if (mPendingWhileIdleAlarms.size() > 0) {
+            ArrayList<Alarm> alarms = mPendingWhileIdleAlarms;
+            mPendingWhileIdleAlarms = new ArrayList<>();
+            final long nowElapsed = SystemClock.elapsedRealtime();
+            for (int i=alarms.size() - 1; i >= 0; i--) {
+                Alarm a = alarms.get(i);
+                reAddAlarmLocked(a, nowElapsed, false);
+            }
         }
 
         // Reschedule everything.
@@ -1053,11 +1057,16 @@ class AlarmManagerService extends SystemService {
                     dumpAlarmList(pw, b.alarms, "  ", nowELAPSED, nowRTC, sdf);
                 }
             }
-            if (mPendingIdleUntil != null) {
+            if (mPendingIdleUntil != null || mPendingWhileIdleAlarms.size() > 0) {
                 pw.println();
                 pw.println("Idle mode state:");
-                pw.print("  Idling until: "); pw.println(mPendingIdleUntil);
-                mPendingIdleUntil.dump(pw, "    ", nowRTC, nowELAPSED, sdf);
+                pw.print("  Idling until: ");
+                if (mPendingIdleUntil != null) {
+                    pw.println(mPendingIdleUntil);
+                    mPendingIdleUntil.dump(pw, "    ", nowRTC, nowELAPSED, sdf);
+                } else {
+                    pw.println("null");
+                }
                 pw.println("  Pending alarms:");
                 dumpAlarmList(pw, mPendingWhileIdleAlarms, "    ", nowELAPSED, nowRTC, sdf);
             }
index 12a99b0..1a75b8a 100644 (file)
@@ -24,6 +24,7 @@ import static android.net.ConnectivityManager.TYPE_VPN;
 import static android.net.ConnectivityManager.getNetworkTypeName;
 import static android.net.ConnectivityManager.isNetworkTypeValid;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
+import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
 
 import android.annotation.Nullable;
@@ -832,7 +833,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
             uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
         }
 
-        if (networkCostly && (uidRules & RULE_REJECT_METERED) != 0) {
+        if ((uidRules & RULE_REJECT_ALL) != 0
+                || (networkCostly && (uidRules & RULE_REJECT_METERED) != 0)) {
             return true;
         }
 
@@ -3490,7 +3492,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
             synchronized(mRulesLock) {
                 uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
             }
-            if ((uidRules & RULE_REJECT_METERED) != 0) {
+            if ((uidRules & (RULE_REJECT_METERED | RULE_REJECT_ALL)) != 0) {
                 // we could silently fail or we can filter the available nets to only give
                 // them those they have access to.  Chose the more useful
                 networkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
new file mode 100644 (file)
index 0000000..b7bc0f0
--- /dev/null
@@ -0,0 +1,879 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+package com.android.server;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.hardware.Sensor;
+import android.hardware.SensorManager;
+import android.hardware.TriggerEvent;
+import android.hardware.TriggerEventListener;
+import android.hardware.display.DisplayManager;
+import android.net.INetworkPolicyManager;
+import android.os.Binder;
+import android.os.Environment;
+import android.os.FileUtils;
+import android.os.Handler;
+import android.os.IDeviceIdleController;
+import android.os.Looper;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.PowerManagerInternal;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Slog;
+import android.util.SparseBooleanArray;
+import android.util.TimeUtils;
+import android.util.Xml;
+import android.view.Display;
+import com.android.internal.app.IBatteryStats;
+import com.android.internal.os.AtomicFile;
+import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+import com.android.server.am.BatteryStatsService;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * Keeps track of device idleness and drives low power mode based on that.
+ */
+public class DeviceIdleController extends SystemService {
+    private static final String TAG = "DeviceIdleController";
+
+    public static final String SERVICE_NAME = "deviceidle";
+
+    private static final String ACTION_STEP_IDLE_STATE =
+            "com.android.server.device_idle.STEP_IDLE_STATE";
+
+    // TODO: These need to be moved to system settings.
+
+    /**
+     * This is the time, after becoming inactive, at which we start looking at the
+     * motion sensor to determine if the device is being left alone.  We don't do this
+     * immediately after going inactive just because we don't want to be continually running
+     * the significant motion sensor whenever the screen is off.
+     */
+    private static final long DEFAULT_INACTIVE_TIMEOUT = 30*60*1000L;
+    /**
+     * This is the time, after seeing motion, that we wait after becoming inactive from
+     * that until we start looking for motion again.
+     */
+    private static final long DEFAULT_MOTION_INACTIVE_TIMEOUT = 10*60*1000L;
+    /**
+     * This is the time, after the inactive timeout elapses, that we will wait looking
+     * for significant motion until we truly consider the device to be idle.
+     */
+    private static final long DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT = 30*60*1000L;
+    /**
+     * This is the initial time, after being idle, that we will allow ourself to be back
+     * in the IDLE_PENDING state allowing the system to run normally until we return to idle.
+     */
+    private static final long DEFAULT_IDLE_PENDING_TIMEOUT = 5*60*1000L;
+    /**
+     * Maximum pending idle timeout (time spent running) we will be allowed to use.
+     */
+    private static final long DEFAULT_MAX_IDLE_PENDING_TIMEOUT = 10*60*1000L;
+    /**
+     * Scaling factor to apply to current pending idle timeout each time we cycle through
+     * that state.
+     */
+    private static final float DEFAULT_IDLE_PENDING_FACTOR = 2f;
+    /**
+     * This is the initial time that we want to sit in the idle state before waking up
+     * again to return to pending idle and allowing normal work to run.
+     */
+    private static final long DEFAULT_IDLE_TIMEOUT = 60*60*1000L;
+    /**
+     * Maximum idle duration we will be allowed to use.
+     */
+    private static final long DEFAULT_MAX_IDLE_TIMEOUT = 6*60*60*1000L;
+    /**
+     * Scaling factor to apply to current idle timeout each time we cycle through that state.
+     */
+    private static final float DEFAULT_IDLE_FACTOR = 2f;
+    /**
+     * This is the minimum time we will allow until the next upcoming alarm for us to
+     * actually go in to idle mode.
+     */
+    private static final long DEFAULT_MIN_TIME_TO_ALARM = 60*60*1000L;
+
+    private AlarmManager mAlarmManager;
+    private IBatteryStats mBatteryStats;
+    private PowerManagerInternal mLocalPowerManager;
+    private INetworkPolicyManager mNetworkPolicyManager;
+    private DisplayManager mDisplayManager;
+    private SensorManager mSensorManager;
+    private Sensor mSigMotionSensor;
+    private PendingIntent mAlarmIntent;
+    private Intent mIdleIntent;
+    private Display mCurDisplay;
+    private boolean mScreenOn;
+    private boolean mCharging;
+    private boolean mSigMotionActive;
+
+    /** Device is currently active. */
+    private static final int STATE_ACTIVE = 0;
+    /** Device is inactve (screen off, no motion) and we are waiting to for idle. */
+    private static final int STATE_INACTIVE = 1;
+    /** Device is past the initial inactive period, and waiting for the next idle period. */
+    private static final int STATE_IDLE_PENDING = 2;
+    /** Device is in the idle state, trying to stay asleep as much as possible. */
+    private static final int STATE_IDLE = 3;
+    /** Device is in the idle state, but temporarily out of idle to do regular maintenance. */
+    private static final int STATE_IDLE_MAINTENANCE = 4;
+    private static String stateToString(int state) {
+        switch (state) {
+            case STATE_ACTIVE: return "ACTIVE";
+            case STATE_INACTIVE: return "INACTIVE";
+            case STATE_IDLE_PENDING: return "IDLE_PENDING";
+            case STATE_IDLE: return "IDLE";
+            case STATE_IDLE_MAINTENANCE: return "IDLE_MAINTENANCE";
+            default: return Integer.toString(state);
+        }
+    }
+
+    private int mState;
+
+    private long mInactiveTimeout;
+    private long mNextAlarmTime;
+    private long mNextIdlePendingDelay;
+    private long mNextIdleDelay;
+
+    public final AtomicFile mConfigFile;
+
+    /**
+     * Package names the system has white-listed to opt out of power save restrictions.
+     */
+    private final ArrayMap<String, Integer> mPowerSaveWhitelistApps = new ArrayMap<>();
+
+    /**
+     * Package names the user has white-listed to opt out of power save restrictions.
+     */
+    private final ArrayMap<String, Integer> mPowerSaveWhitelistUserApps = new ArrayMap<>();
+
+    /**
+     * UIDs that have been white-listed to opt out of power save restrictions.
+     */
+    private final SparseBooleanArray mPowerSaveWhitelistAppIds = new SparseBooleanArray();
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override public void onReceive(Context context, Intent intent) {
+            if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
+                int plugged = intent.getIntExtra("plugged", 0);
+                updateChargingLocked(plugged != 0);
+            } else if (ACTION_STEP_IDLE_STATE.equals(intent.getAction())) {
+                synchronized (DeviceIdleController.this) {
+                    stepIdleStateLocked();
+                }
+            }
+        }
+    };
+
+    private final DisplayManager.DisplayListener mDisplayListener
+            = new DisplayManager.DisplayListener() {
+        @Override public void onDisplayAdded(int displayId) {
+        }
+
+        @Override public void onDisplayRemoved(int displayId) {
+        }
+
+        @Override public void onDisplayChanged(int displayId) {
+            if (displayId == Display.DEFAULT_DISPLAY) {
+                synchronized (DeviceIdleController.this) {
+                    updateDisplayLocked();
+                }
+            }
+        }
+    };
+
+    private final TriggerEventListener mSigMotionListener = new TriggerEventListener() {
+        @Override public void onTrigger(TriggerEvent event) {
+            synchronized (DeviceIdleController.this) {
+                significantMotionLocked();
+            }
+        }
+    };
+
+    static final int MSG_WRITE_CONFIG = 1;
+    static final int MSG_REPORT_IDLE_ON = 2;
+    static final int MSG_REPORT_IDLE_OFF = 3;
+    static final int MSG_REPORT_ACTIVE = 4;
+
+    final class MyHandler extends Handler {
+        MyHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_WRITE_CONFIG: {
+                    handleWriteConfigFile();
+                } break;
+                case MSG_REPORT_IDLE_ON: {
+                    mLocalPowerManager.setDeviceIdleMode(true);
+                    try {
+                        mNetworkPolicyManager.setDeviceIdleMode(true);
+                        mBatteryStats.noteDeviceIdleMode(true, false, false);
+                    } catch (RemoteException e) {
+                    }
+                    getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
+                } break;
+                case MSG_REPORT_IDLE_OFF: {
+                    mLocalPowerManager.setDeviceIdleMode(false);
+                    try {
+                        mNetworkPolicyManager.setDeviceIdleMode(false);
+                        mBatteryStats.noteDeviceIdleMode(false, false, false);
+                    } catch (RemoteException e) {
+                    }
+                    getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
+                } break;
+                case MSG_REPORT_ACTIVE: {
+                    boolean fromMotion = msg.arg1 != 0;
+                    boolean needBroadcast = msg.arg2 != 0;
+                    mLocalPowerManager.setDeviceIdleMode(false);
+                    try {
+                        mNetworkPolicyManager.setDeviceIdleMode(false);
+                        mBatteryStats.noteDeviceIdleMode(false, !fromMotion, fromMotion);
+                    } catch (RemoteException e) {
+                    }
+                    if (needBroadcast) {
+                        getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
+                    }
+                } break;
+            }
+        }
+    }
+
+    final MyHandler mHandler;
+
+    private final class BinderService extends IDeviceIdleController.Stub {
+        @Override public void addPowerSaveWhitelistApp(String name) {
+            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
+                    null);
+            addPowerSaveWhitelistAppInternal(name);
+        }
+
+        @Override public void removePowerSaveWhitelistApp(String name) {
+            getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
+                    null);
+            removePowerSaveWhitelistAppInternal(name);
+        }
+
+        @Override public String[] getSystemPowerWhitelist() {
+            return getSystemPowerWhitelistInternal();
+        }
+
+        @Override public String[] getFullPowerWhitelist() {
+            return getFullPowerWhitelistInternal();
+        }
+
+        @Override public int[] getAppIdWhitelist() {
+            return getAppIdWhitelistInternal();
+        }
+
+        @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            DeviceIdleController.this.dump(fd, pw, args);
+        }
+    }
+
+    public DeviceIdleController(Context context) {
+        super(context);
+        mConfigFile = new AtomicFile(new File(getSystemDir(), "deviceidle.xml"));
+        mHandler = new MyHandler(BackgroundThread.getHandler().getLooper());
+    }
+
+    private static File getSystemDir() {
+        return new File(Environment.getDataDirectory(), "system");
+    }
+
+    @Override
+    public void onStart() {
+        final PackageManager pm = getContext().getPackageManager();
+
+        synchronized (this) {
+            SystemConfig sysConfig = SystemConfig.getInstance();
+            ArraySet<String> allowPower = sysConfig.getAllowInPowerSave();
+            for (int i=0; i<allowPower.size(); i++) {
+                String pkg = allowPower.valueAt(i);
+                try {
+                    ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
+                    if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
+                        mPowerSaveWhitelistApps.put(ai.packageName,
+                                UserHandle.getAppId(ai.uid));
+                    }
+                } catch (PackageManager.NameNotFoundException e) {
+                }
+            }
+
+            readConfigFileLocked();
+            updateWhitelistAppIdsLocked();
+
+            mScreenOn = true;
+            // Start out assuming we are charging.  If we aren't, we will at least get
+            // a battery update the next time the level drops.
+            mCharging = true;
+            mState = STATE_ACTIVE;
+            mInactiveTimeout = DEFAULT_INACTIVE_TIMEOUT;
+        }
+
+        publishBinderService(SERVICE_NAME, new BinderService());
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == PHASE_SYSTEM_SERVICES_READY) {
+            synchronized (this) {
+                mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
+                mBatteryStats = BatteryStatsService.getService();
+                mLocalPowerManager = getLocalService(PowerManagerInternal.class);
+                mNetworkPolicyManager = INetworkPolicyManager.Stub.asInterface(
+                                    ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
+                mDisplayManager = (DisplayManager) getContext().getSystemService(
+                        Context.DISPLAY_SERVICE);
+                mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
+                mSigMotionSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);
+
+                Intent intent = new Intent(ACTION_STEP_IDLE_STATE)
+                        .setPackage("android")
+                        .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+                mAlarmIntent = PendingIntent.getBroadcast(getContext(), 0, intent, 0);
+
+                mIdleIntent = new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
+                mIdleIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+
+                IntentFilter filter = new IntentFilter();
+                filter.addAction(Intent.ACTION_BATTERY_CHANGED);
+                filter.addAction(ACTION_STEP_IDLE_STATE);
+                getContext().registerReceiver(mReceiver, filter);
+
+                mDisplayManager.registerDisplayListener(mDisplayListener, null);
+                updateDisplayLocked();
+            }
+        }
+    }
+
+    public boolean addPowerSaveWhitelistAppInternal(String name) {
+        synchronized (this) {
+            try {
+                ApplicationInfo ai = getContext().getPackageManager().getApplicationInfo(name, 0);
+                if (mPowerSaveWhitelistUserApps.put(name, UserHandle.getAppId(ai.uid)) == null) {
+                    reportPowerSaveWhitelistChangedLocked();
+                    updateWhitelistAppIdsLocked();
+                    writeConfigFileLocked();
+                }
+                return true;
+            } catch (PackageManager.NameNotFoundException e) {
+                return false;
+            }
+        }
+    }
+
+    public boolean removePowerSaveWhitelistAppInternal(String name) {
+        synchronized (this) {
+            if (mPowerSaveWhitelistUserApps.remove(name) != null) {
+                reportPowerSaveWhitelistChangedLocked();
+                updateWhitelistAppIdsLocked();
+                writeConfigFileLocked();
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public String[] getSystemPowerWhitelistInternal() {
+        synchronized (this) {
+            int size = mPowerSaveWhitelistApps.size();
+            String[] apps = new String[size];
+            for (int i = 0; i < mPowerSaveWhitelistApps.size(); i++) {
+                apps[i] = mPowerSaveWhitelistApps.keyAt(i);
+            }
+            return apps;
+        }
+    }
+
+    public String[] getFullPowerWhitelistInternal() {
+        synchronized (this) {
+            int size = mPowerSaveWhitelistApps.size() + mPowerSaveWhitelistUserApps.size();
+            String[] apps = new String[size];
+            int cur = 0;
+            for (int i = 0; i < mPowerSaveWhitelistApps.size(); i++) {
+                apps[cur] = mPowerSaveWhitelistApps.keyAt(i);
+                cur++;
+            }
+            for (int i = 0; i < mPowerSaveWhitelistUserApps.size(); i++) {
+                apps[cur] = mPowerSaveWhitelistUserApps.keyAt(i);
+                cur++;
+            }
+            return apps;
+        }
+    }
+
+    public int[] getAppIdWhitelistInternal() {
+        synchronized (this) {
+            int size = mPowerSaveWhitelistAppIds.size();
+            int[] appids = new int[size];
+            for (int i = 0; i < size; i++) {
+                appids[i] = mPowerSaveWhitelistAppIds.keyAt(i);
+            }
+            return appids;
+        }
+    }
+
+    void updateDisplayLocked() {
+        mCurDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
+        // We consider any situation where the display is showing something to be it on,
+        // because if there is anything shown we are going to be updating it at some
+        // frequency so can't be allowed to go into deep sleeps.
+        boolean screenOn = mCurDisplay.getState() != Display.STATE_OFF;;
+        if (!screenOn && mScreenOn) {
+            mScreenOn = false;
+            becomeInactiveIfAppropriateLocked();
+        } else if (screenOn) {
+            mScreenOn = true;
+            becomeActiveLocked("screen");
+        }
+    }
+
+    void updateChargingLocked(boolean charging) {
+        if (!charging && mCharging) {
+            mCharging = false;
+            becomeInactiveIfAppropriateLocked();
+        } else if (charging) {
+            mCharging = charging;
+            becomeActiveLocked("charging");
+        }
+    }
+
+    void scheduleReportActiveLocked(boolean fromMotion) {
+        Message msg = mHandler.obtainMessage(MSG_REPORT_ACTIVE, fromMotion ? 1 : 0,
+                mState == STATE_IDLE ? 1 : 0);
+        mHandler.sendMessage(msg);
+    }
+
+    void becomeActiveLocked(String reason) {
+        if (mState != STATE_ACTIVE) {
+            EventLogTags.writeDeviceIdle(STATE_ACTIVE, reason);
+            scheduleReportActiveLocked(false);
+            mState = STATE_ACTIVE;
+            mInactiveTimeout = DEFAULT_INACTIVE_TIMEOUT;
+            mNextIdlePendingDelay = 0;
+            mNextIdleDelay = 0;
+            cancelAlarmLocked();
+            stopMonitoringSignificantMotion();
+        }
+    }
+
+    void becomeInactiveIfAppropriateLocked() {
+        if (!mScreenOn && !mCharging && mState == STATE_ACTIVE) {
+            // Screen has turned off; we are now going to become inactive and start
+            // waiting to see if we will ultimately go idle.
+            mState = STATE_INACTIVE;
+            mNextIdlePendingDelay = 0;
+            mNextIdleDelay = 0;
+            scheduleAlarmLocked(mInactiveTimeout, false);
+            EventLogTags.writeDeviceIdle(mState, "no activity");
+        }
+    }
+
+    void stepIdleStateLocked() {
+        EventLogTags.writeDeviceIdleStep();
+
+        final long now = SystemClock.elapsedRealtime();
+        if ((now+DEFAULT_MIN_TIME_TO_ALARM) > mAlarmManager.getNextWakeFromIdleTime()) {
+            // Whoops, there is an upcoming alarm.  We don't actually want to go idle.
+            if (mState != STATE_ACTIVE) {
+                becomeActiveLocked("alarm");
+            }
+            return;
+        }
+
+        switch (mState) {
+            case STATE_INACTIVE:
+                // We have now been inactive long enough, it is time to start looking
+                // for significant motion and sleep some more while doing so.
+                startMonitoringSignificantMotion();
+                scheduleAlarmLocked(DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT, false);
+                // Reset the upcoming idle delays.
+                mNextIdlePendingDelay = DEFAULT_IDLE_PENDING_TIMEOUT;
+                mNextIdleDelay = DEFAULT_IDLE_TIMEOUT;
+                mState = STATE_IDLE_PENDING;
+                EventLogTags.writeDeviceIdle(mState, "step");
+                break;
+            case STATE_IDLE_PENDING:
+            case STATE_IDLE_MAINTENANCE:
+                // We have been waiting to become idle, and now it is time!  This is the
+                // only case where we want to use a wakeup alarm, because we do want to
+                // drag the device out of its sleep state in this case to do the next
+                // scheduled work.
+                scheduleAlarmLocked(mNextIdleDelay, true);
+                mNextIdleDelay = (long)(mNextIdleDelay*DEFAULT_IDLE_FACTOR);
+                if (mNextIdleDelay > DEFAULT_MAX_IDLE_TIMEOUT) {
+                    mNextIdleDelay = DEFAULT_MAX_IDLE_TIMEOUT;
+                }
+                mState = STATE_IDLE;
+                EventLogTags.writeDeviceIdle(mState, "step");
+                mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON);
+                break;
+            case STATE_IDLE:
+                // We have been idling long enough, now it is time to do some work.
+                scheduleAlarmLocked(mNextIdlePendingDelay, false);
+                mNextIdlePendingDelay = (long)(mNextIdlePendingDelay*DEFAULT_IDLE_PENDING_FACTOR);
+                if (mNextIdlePendingDelay > DEFAULT_MAX_IDLE_PENDING_TIMEOUT) {
+                    mNextIdlePendingDelay = DEFAULT_MAX_IDLE_PENDING_TIMEOUT;
+                }
+                mState = STATE_IDLE_MAINTENANCE;
+                EventLogTags.writeDeviceIdle(mState, "step");
+                mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
+                break;
+        }
+    }
+
+    void significantMotionLocked() {
+        // When the sensor goes off, its trigger is automatically removed.
+        mSigMotionActive = false;
+        // The device is not yet active, so we want to go back to the pending idle
+        // state to wait again for no motion.  Note that we only monitor for significant
+        // motion after moving out of the inactive state, so no need to worry about that.
+        if (mState != STATE_ACTIVE) {
+            scheduleReportActiveLocked(true);
+            mState = STATE_ACTIVE;
+            mInactiveTimeout = DEFAULT_MOTION_INACTIVE_TIMEOUT;
+            EventLogTags.writeDeviceIdle(mState, "motion");
+            becomeInactiveIfAppropriateLocked();
+        }
+    }
+
+    void startMonitoringSignificantMotion() {
+        if (mSigMotionSensor != null && !mSigMotionActive) {
+            mSensorManager.requestTriggerSensor(mSigMotionListener, mSigMotionSensor);
+            mSigMotionActive = true;
+        }
+    }
+
+    void stopMonitoringSignificantMotion() {
+        if (mSigMotionActive) {
+            mSensorManager.cancelTriggerSensor(mSigMotionListener, mSigMotionSensor);
+            mSigMotionActive = false;
+        }
+    }
+
+    void cancelAlarmLocked() {
+        if (mNextAlarmTime != 0) {
+            mNextAlarmTime = 0;
+            mAlarmManager.cancel(mAlarmIntent);
+        }
+    }
+
+    void scheduleAlarmLocked(long delay, boolean idleUntil) {
+        if (mSigMotionSensor == null) {
+            // If there is no significant motion sensor on this device, then we won't schedule
+            // alarms, because we can't determine if the device is not moving.  This effectively
+            // turns off normal exeuction of device idling, although it is still possible to
+            // manually poke it by pretending like the alarm is going off.
+            return;
+        }
+        mNextAlarmTime = SystemClock.elapsedRealtime() + delay;
+        if (idleUntil) {
+            mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                    mNextAlarmTime, mAlarmIntent);
+        } else {
+            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
+                    mNextAlarmTime, mAlarmIntent);
+        }
+    }
+
+    private void updateWhitelistAppIdsLocked() {
+        mPowerSaveWhitelistAppIds.clear();
+        for (int i=0; i<mPowerSaveWhitelistApps.size(); i++) {
+            mPowerSaveWhitelistAppIds.put(mPowerSaveWhitelistApps.valueAt(i), true);
+        }
+        for (int i=0; i<mPowerSaveWhitelistUserApps.size(); i++) {
+            mPowerSaveWhitelistAppIds.put(mPowerSaveWhitelistUserApps.valueAt(i), true);
+        }
+    }
+
+    private void reportPowerSaveWhitelistChangedLocked() {
+        Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
+        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+        getContext().sendBroadcast(intent);
+    }
+
+    void readConfigFileLocked() {
+        Slog.d(TAG, "Reading config from " + mConfigFile.getBaseFile());
+        mPowerSaveWhitelistUserApps.clear();
+        FileInputStream stream;
+        try {
+            stream = mConfigFile.openRead();
+        } catch (FileNotFoundException e) {
+            return;
+        }
+        try {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(stream, null);
+            readConfigFileLocked(parser);
+        } catch (XmlPullParserException e) {
+        } finally {
+            try {
+                stream.close();
+            } catch (IOException e) {
+            }
+        }
+
+    }
+
+    private void readConfigFileLocked(XmlPullParser parser) {
+        final PackageManager pm = getContext().getPackageManager();
+
+        try {
+            int type;
+            while ((type = parser.next()) != XmlPullParser.START_TAG
+                    && type != XmlPullParser.END_DOCUMENT) {
+                ;
+            }
+
+            if (type != XmlPullParser.START_TAG) {
+                throw new IllegalStateException("no start tag found");
+            }
+
+            int outerDepth = parser.getDepth();
+            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                    continue;
+                }
+
+                String tagName = parser.getName();
+                if (tagName.equals("wl")) {
+                    String name = parser.getAttributeValue(null, "n");
+                    if (name != null) {
+                        try {
+                            ApplicationInfo ai = pm.getApplicationInfo(name, 0);
+                            mPowerSaveWhitelistUserApps.put(ai.packageName,
+                                    UserHandle.getAppId(ai.uid));
+                        } catch (PackageManager.NameNotFoundException e) {
+                        }
+                    }
+                } else {
+                    Slog.w(TAG, "Unknown element under <config>: "
+                            + parser.getName());
+                    XmlUtils.skipCurrentTag(parser);
+                }
+            }
+
+        } catch (IllegalStateException e) {
+            Slog.w(TAG, "Failed parsing config " + e);
+        } catch (NullPointerException e) {
+            Slog.w(TAG, "Failed parsing config " + e);
+        } catch (NumberFormatException e) {
+            Slog.w(TAG, "Failed parsing config " + e);
+        } catch (XmlPullParserException e) {
+            Slog.w(TAG, "Failed parsing config " + e);
+        } catch (IOException e) {
+            Slog.w(TAG, "Failed parsing config " + e);
+        } catch (IndexOutOfBoundsException e) {
+            Slog.w(TAG, "Failed parsing config " + e);
+        }
+    }
+
+    void writeConfigFileLocked() {
+        mHandler.removeMessages(MSG_WRITE_CONFIG);
+        mHandler.sendEmptyMessageDelayed(MSG_WRITE_CONFIG, 5000);
+    }
+
+    void handleWriteConfigFile() {
+        final ByteArrayOutputStream memStream = new ByteArrayOutputStream();
+
+        try {
+            synchronized (this) {
+                XmlSerializer out = new FastXmlSerializer();
+                out.setOutput(memStream, "utf-8");
+                writeConfigFileLocked(out);
+            }
+        } catch (IOException e) {
+        }
+
+        synchronized (mConfigFile) {
+            FileOutputStream stream = null;
+            try {
+                stream = mConfigFile.startWrite();
+                memStream.writeTo(stream);
+                stream.flush();
+                FileUtils.sync(stream);
+                stream.close();
+                mConfigFile.finishWrite(stream);
+            } catch (IOException e) {
+                Slog.w(TAG, "Error writing config file", e);
+                mConfigFile.failWrite(stream);
+            }
+        }
+    }
+
+    void writeConfigFileLocked(XmlSerializer out) throws IOException {
+        out.startDocument(null, true);
+        out.startTag(null, "config");
+        for (int i=0; i<mPowerSaveWhitelistUserApps.size(); i++) {
+            String name = mPowerSaveWhitelistUserApps.keyAt(i);
+            out.startTag(null, "wl");
+            out.attribute(null, "n", name);
+            out.endTag(null, "wl");
+        }
+        out.endTag(null, "config");
+        out.endDocument();
+    }
+
+    private void dumpHelp(PrintWriter pw) {
+        pw.println("Device idle controller (deviceidle) dump options:");
+        pw.println("  [-h] [CMD]");
+        pw.println("  -h: print this help text.");
+        pw.println("Commands:");
+        pw.println("  step");
+        pw.println("    Immediately step to next state, without waiting for alarm.");
+        pw.println("  whitelist");
+        pw.println("    Add (prefix with +) or remove (prefix with -) packages.");
+    }
+
+    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+            pw.println("Permission Denial: can't dump DeviceIdleController from from pid="
+                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+                    + " without permission " + android.Manifest.permission.DUMP);
+            return;
+        }
+
+        if (args != null) {
+            for (int i=0; i<args.length; i++) {
+                String arg = args[i];
+                if ("-h".equals(arg)) {
+                    dumpHelp(pw);
+                    return;
+                } else if ("step".equals(arg)) {
+                    synchronized (this) {
+                        stepIdleStateLocked();
+                        pw.print("Stepped to: "); pw.println(stateToString(mState));
+                    }
+                    return;
+                } else if ("whitelist".equals(arg)) {
+                    i++;
+                    while (i < args.length) {
+                        arg = args[i];
+                        i++;
+                        if (arg.length() < 1 || (arg.charAt(0) != '-'
+                                && arg.charAt(0) != '+')) {
+                            pw.println("Package must be prefixed with + or -: " + arg);
+                            return;
+                        }
+                        char op = arg.charAt(0);
+                        String pkg = arg.substring(1);
+                        if (op == '+') {
+                            if (addPowerSaveWhitelistAppInternal(pkg)) {
+                                pw.println("Added: " + pkg);
+                            } else {
+                                pw.println("Unknown package: " + pkg);
+                            }
+                        } else {
+                            if (removePowerSaveWhitelistAppInternal(pkg)) {
+                                pw.println("Removed: " + pkg);
+                            }
+                        }
+                    }
+                    return;
+                } else if (arg.length() > 0 && arg.charAt(0) == '-'){
+                    pw.println("Unknown option: " + arg);
+                    return;
+                } else {
+                    pw.println("Unknown command: " + arg);
+                    return;
+                }
+            }
+        }
+
+        synchronized (this) {
+            int size = mPowerSaveWhitelistApps.size();
+            if (size > 0) {
+                pw.println("  Whitelist system apps:");
+                for (int i = 0; i < size; i++) {
+                    pw.print("    ");
+                    pw.println(mPowerSaveWhitelistApps.keyAt(i));
+                }
+            }
+            size = mPowerSaveWhitelistUserApps.size();
+            if (size > 0) {
+                pw.println("  Whitelist user apps:");
+                for (int i = 0; i < size; i++) {
+                    pw.print("    ");
+                    pw.println(mPowerSaveWhitelistUserApps.keyAt(i));
+                }
+            }
+            size = mPowerSaveWhitelistAppIds.size();
+            if (size > 0) {
+                pw.println("  Whitelist app uids:");
+                for (int i = 0; i < size; i++) {
+                    pw.print("    UID=");
+                    pw.print(mPowerSaveWhitelistAppIds.keyAt(i));
+                    pw.print(": ");
+                    pw.print(mPowerSaveWhitelistAppIds.valueAt(i));
+                    pw.println();
+                }
+            }
+            pw.print("  mSigMotionSensor="); pw.println(mSigMotionSensor);
+            pw.print("  mCurDisplay="); pw.println(mCurDisplay);
+            pw.print("  mScreenOn="); pw.println(mScreenOn);
+            pw.print("  mCharging="); pw.println(mCharging);
+            pw.print("  mSigMotionActive="); pw.println(mSigMotionActive);
+            pw.print("  mState="); pw.println(stateToString(mState));
+            pw.print("  mInactiveTimeout="); TimeUtils.formatDuration(mInactiveTimeout, pw);
+            pw.println();
+            if (mNextAlarmTime != 0) {
+                pw.print("  mNextAlarmTime=");
+                TimeUtils.formatDuration(mNextAlarmTime, SystemClock.elapsedRealtime(), pw);
+                pw.println();
+            }
+            if (mNextIdlePendingDelay != 0) {
+                pw.print("  mNextIdlePendingDelay=");
+                TimeUtils.formatDuration(mNextIdlePendingDelay, pw);
+                pw.println();
+            }
+            if (mNextIdleDelay != 0) {
+                pw.print("  mNextIdleDelay=");
+                TimeUtils.formatDuration(mNextIdleDelay, pw);
+                pw.println();
+            }
+        }
+    }
+}
index b5b62b4..f6998ca 100644 (file)
@@ -43,6 +43,7 @@ import android.net.InterfaceConfiguration;
 import android.net.IpPrefix;
 import android.net.LinkAddress;
 import android.net.Network;
+import android.net.NetworkPolicyManager;
 import android.net.NetworkStats;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
@@ -107,8 +108,8 @@ import java.util.concurrent.CountDownLatch;
  */
 public class NetworkManagementService extends INetworkManagementService.Stub
         implements Watchdog.Monitor {
-    private static final String TAG = "NetworkManagementService";
-    private static final boolean DBG = false;
+    private static final String TAG = "NetworkManagement";
+    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
     private static final String NETD_TAG = "NetdConnector";
     private static final String NETD_SOCKET_NAME = "netd";
 
@@ -188,6 +189,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub
     /** Set of UIDs with cleartext penalties. */
     @GuardedBy("mQuotaLock")
     private SparseIntArray mUidCleartextPolicy = new SparseIntArray();
+    /** Set of UIDs that are to be blocked/allowed by firewall controller. */
+    @GuardedBy("mQuotaLock")
+    private SparseIntArray mUidFirewallRules = new SparseIntArray();
 
     private Object mIdleTimerLock = new Object();
     /** Set of interfaces with active idle timers. */
@@ -563,10 +567,19 @@ public class NetworkManagementService extends INetworkManagementService.Stub
                     setUidCleartextNetworkPolicy(local.keyAt(i), local.valueAt(i));
                 }
             }
-        }
 
-        // TODO: Push any existing firewall state
-        setFirewallEnabled(mFirewallEnabled || LockdownVpnTracker.isEnabled());
+            setFirewallEnabled(mFirewallEnabled || LockdownVpnTracker.isEnabled());
+
+            size = mUidFirewallRules.size();
+            if (size > 0) {
+                Slog.d(TAG, "Pushing " + size + " active firewall UID rules");
+                final SparseIntArray uidFirewallRules = mUidFirewallRules;
+                mUidFirewallRules = new SparseIntArray();
+                for (int i = 0; i < uidFirewallRules.size(); i++) {
+                    setFirewallUidRule(uidFirewallRules.keyAt(i), uidFirewallRules.valueAt(i));
+                }
+            }
+        }
     }
 
     /**
@@ -1899,7 +1912,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
     public void setFirewallEnabled(boolean enabled) {
         enforceSystemUid();
         try {
-            mConnector.execute("firewall", enabled ? "enable" : "disable");
+            mConnector.execute("firewall", "enable", enabled ? "whitelist" : "blacklist");
             mFirewallEnabled = enabled;
         } catch (NativeDaemonConnectorException e) {
             throw e.rethrowAsParcelableException();
@@ -1949,14 +1962,48 @@ public class NetworkManagementService extends INetworkManagementService.Stub
     }
 
     @Override
-    public void setFirewallUidRule(int uid, boolean allow) {
+    public void setFirewallUidRule(int uid, int rule) {
         enforceSystemUid();
-        Preconditions.checkState(mFirewallEnabled);
-        final String rule = allow ? "allow" : "deny";
-        try {
-            mConnector.execute("firewall", "set_uid_rule", uid, rule);
-        } catch (NativeDaemonConnectorException e) {
-            throw e.rethrowAsParcelableException();
+        if (rule == NetworkPolicyManager.FIREWALL_RULE_ALLOW) {
+            Preconditions.checkState(mFirewallEnabled);
+        }
+        synchronized (mQuotaLock) {
+            final int oldUidFirewallRule = mUidFirewallRules.get(uid);
+            if (DBG) {
+                Slog.d(TAG, "oldRule = " + oldUidFirewallRule
+                        + ", newRule=" + rule + " for uid=" + uid);
+            }
+            if (oldUidFirewallRule == rule) {
+                if (DBG) Slog.d(TAG, "!!!!! Skipping change");
+                // TODO: eventually consider throwing
+                return;
+            }
+
+            try {
+                String ruleName;
+                if (isFirewallEnabled()) { // Whitelist mode
+                    if (rule == NetworkPolicyManager.FIREWALL_RULE_ALLOW) {
+                        ruleName = "allow";
+                    } else {
+                        ruleName = "deny";
+                    }
+                } else { // Blacklist mode
+                    if (rule == NetworkPolicyManager.FIREWALL_RULE_DENY) {
+                        ruleName = "deny";
+                    } else {
+                        ruleName = "allow";
+                    }
+                }
+
+                if (rule == NetworkPolicyManager.FIREWALL_RULE_DEFAULT) {
+                    mUidFirewallRules.delete(uid);
+                } else {
+                    mUidFirewallRules.put(uid, rule);
+                }
+                mConnector.execute("firewall", "set_uid_rule", uid, ruleName);
+            } catch (NativeDaemonConnectorException e) {
+                throw e.rethrowAsParcelableException();
+            }
         }
     }
 
@@ -2072,6 +2119,18 @@ public class NetworkManagementService extends INetworkManagementService.Stub
             pw.println("]");
         }
 
+        synchronized (mUidFirewallRules) {
+            pw.print("UID firewall rule: [");
+            final int size = mUidFirewallRules.size();
+            for (int i = 0; i < size; i++) {
+                pw.print(mUidFirewallRules.keyAt(i));
+                pw.print(":");
+                pw.print(mUidFirewallRules.valueAt(i));
+                if (i < size - 1) pw.print(",");
+            }
+            pw.println("]");
+        }
+
         synchronized (mIdleTimerLock) {
             pw.println("Idle timers:");
             for (HashMap.Entry<String, IdleTimerParams> ent : mActiveIdleTimers.entrySet()) {
index ac2f5b0..62f168d 100644 (file)
@@ -2771,26 +2771,10 @@ public class AccountManagerService
                                             mAccountName, mAccountType
                                     });
                         }
-                        result.putLong(AccountManager.KEY_LAST_AUTHENTICATE_TIME_MILLIS_EPOCH,
+                        result.putLong(AccountManager.KEY_LAST_AUTHENTICATED_TIME,
                                 lastAuthenticatedTime);
                     }
                 }
-                if (mAuthDetailsRequired) {
-                    long lastAuthenticatedTime = -1;
-                    if (isAccountPresentForCaller(mAccountName, mAccountType)) {
-                        lastAuthenticatedTime = DatabaseUtils.longForQuery(
-                                mAccounts.openHelper.getReadableDatabase(),
-                                "select " + ACCOUNTS_LAST_AUTHENTICATE_TIME_EPOCH_MILLIS + " from "
-                                        +
-                                        TABLE_ACCOUNTS + " WHERE " + ACCOUNTS_NAME + "=? AND "
-                                        + ACCOUNTS_TYPE + "=?",
-                                new String[] {
-                                        mAccountName, mAccountType
-                                });
-                    }
-                    result.putLong(AccountManager.KEY_LAST_AUTHENTICATE_TIME_MILLIS_EPOCH,
-                            lastAuthenticatedTime);
-                }
             }
             if (result != null
                     && (intent = result.getParcelable(AccountManager.KEY_INTENT)) != null) {
index 15d7367..25a98c0 100644 (file)
@@ -699,12 +699,10 @@ public final class ActivityManagerService extends ActivityManagerNative
     private final StringBuilder mStrictModeBuffer = new StringBuilder();
 
     /**
-     * Keeps track of all IIntentReceivers that have been registered for
-     * broadcasts.  Hash keys are the receiver IBinder, hash value is
-     * a ReceiverList.
+     * Keeps track of all IIntentReceivers that have been registered for broadcasts.
+     * Hash keys are the receiver IBinder, hash value is a ReceiverList.
      */
-    final HashMap<IBinder, ReceiverList> mRegisteredReceivers =
-            new HashMap<IBinder, ReceiverList>();
+    final HashMap<IBinder, ReceiverList> mRegisteredReceivers = new HashMap<>();
 
     /**
      * Resolver for broadcast intents to registered receivers.
@@ -716,7 +714,7 @@ public final class ActivityManagerService extends ActivityManagerNative
         protected boolean allowFilterResult(
                 BroadcastFilter filter, List<BroadcastFilter> dest) {
             IBinder target = filter.receiverList.receiver.asBinder();
-            for (int i=dest.size()-1; i>=0; i--) {
+            for (int i = dest.size() - 1; i >= 0; i--) {
                 if (dest.get(i).receiverList.receiver.asBinder() == target) {
                     return false;
                 }
@@ -6603,6 +6601,12 @@ public final class ActivityManagerService extends ActivityManagerNative
             return mActivityManagerService.checkPermission(permission, pid,
                     uid) == PackageManager.PERMISSION_GRANTED;
         }
+
+        @Override
+        public String[] getPackagesForUid(int uid) {
+            return mActivityManagerService.mContext.getPackageManager()
+                    .getPackagesForUid(uid);
+        }
     }
 
     class IntentFirewallInterface implements IntentFirewall.AMSInterface {
@@ -15656,8 +15660,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                 // Original caller already died
                 return null;
             }
-            ReceiverList rl
-                = (ReceiverList)mRegisteredReceivers.get(receiver.asBinder());
+            ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
             if (rl == null) {
                 rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                         userId, receiver);
@@ -15689,7 +15692,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                     permission, callingUid, userId);
             rl.add(bf);
             if (!bf.debugCheck()) {
-                Slog.w(TAG, "==> For Dynamic broadast");
+                Slog.w(TAG, "==> For Dynamic broadcast");
             }
             mReceiverResolver.addFilter(bf);
 
@@ -15699,9 +15702,9 @@ public final class ActivityManagerService extends ActivityManagerNative
                 ArrayList receivers = new ArrayList();
                 receivers.add(bf);
 
-                int N = allSticky.size();
-                for (int i=0; i<N; i++) {
-                    Intent intent = (Intent)allSticky.get(i);
+                final int stickyCount = allSticky.size();
+                for (int i = 0; i < stickyCount; i++) {
+                    Intent intent = allSticky.get(i);
                     BroadcastQueue queue = broadcastQueueForIntent(intent);
                     BroadcastRecord r = new BroadcastRecord(queue, intent, null,
                             null, -1, -1, null, null, AppOpsManager.OP_NONE, receivers, null, 0,
@@ -15761,8 +15764,7 @@ public final class ActivityManagerService extends ActivityManagerNative
 
     void removeReceiverLocked(ReceiverList rl) {
         mRegisteredReceivers.remove(rl.receiver.asBinder());
-        int N = rl.size();
-        for (int i=0; i<N; i++) {
+        for (int i = rl.size() - 1; i >= 0; i--) {
             mReceiverResolver.removeFilter(rl.get(i));
         }
     }
@@ -16133,24 +16135,24 @@ public final class ActivityManagerService extends ActivityManagerNative
             }
             ArrayMap<String, ArrayList<Intent>> stickies = mStickyBroadcasts.get(userId);
             if (stickies == null) {
-                stickies = new ArrayMap<String, ArrayList<Intent>>();
+                stickies = new ArrayMap<>();
                 mStickyBroadcasts.put(userId, stickies);
             }
             ArrayList<Intent> list = stickies.get(intent.getAction());
             if (list == null) {
-                list = new ArrayList<Intent>();
+                list = new ArrayList<>();
                 stickies.put(intent.getAction(), list);
             }
-            int N = list.size();
+            final int stickiesCount = list.size();
             int i;
-            for (i=0; i<N; i++) {
+            for (i = 0; i < stickiesCount; i++) {
                 if (intent.filterEquals(list.get(i))) {
                     // This sticky already exists, replace it.
                     list.set(i, new Intent(intent));
                     break;
                 }
             }
-            if (i >= N) {
+            if (i >= stickiesCount) {
                 list.add(new Intent(intent));
             }
         }
index a91a7ca..e5c5dff 100644 (file)
@@ -309,7 +309,6 @@ public final class BroadcastQueue {
     }
 
     public void skipCurrentReceiverLocked(ProcessRecord app) {
-        boolean reschedule = false;
         BroadcastRecord r = app.curReceiver;
         if (r != null && r.queue == this) {
             // The current broadcast is waiting for this app's receiver
@@ -318,7 +317,6 @@ public final class BroadcastQueue {
             logBroadcastReceiverDiscardLocked(r);
             finishReceiverLocked(r, r.resultCode, r.resultData,
                     r.resultExtras, r.resultAbort, false);
-            reschedule = true;
         }
         if (r == null && mPendingBroadcast != null && mPendingBroadcast.curApp == app) {
             if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
index 31c1eea..8932ca0 100644 (file)
@@ -775,7 +775,7 @@ final class WifiDisplayController implements DumpUtils.Dump {
                         handleConnectionFailure(false);
                     }
                 }
-            }, mHandler);
+            }, mHandler, mContext.getOpPackageName());
 
             // Use extended timeout value for certification, as some tests require user inputs
             int rtspTimeout = mWifiDisplayCertMode ?
index d3240ec..6bd646d 100644 (file)
@@ -952,13 +952,18 @@ public class GpsLocationProvider implements LocationProviderInterface {
                     return GPS_POSITION_MODE_STANDALONE;
                 }
             }
+            // MS-Based is the preferred mode for Assisted-GPS position computation, so we favor
+            // such mode when it is available
+            if (hasCapability(GPS_CAPABILITY_MSB) && (suplMode & AGPS_SUPL_MODE_MSB) != 0) {
+                return GPS_POSITION_MODE_MS_BASED;
+            }
+            // for now, just as the legacy code did, we fallback to MS-Assisted if it is available,
+            // do fallback only for single-shot requests, because it is too expensive to do for
+            // periodic requests as well
             if (singleShot
                     && hasCapability(GPS_CAPABILITY_MSA)
                     && (suplMode & AGPS_SUPL_MODE_MSA) != 0) {
                 return GPS_POSITION_MODE_MS_ASSISTED;
-            } else if (hasCapability(GPS_CAPABILITY_MSB)
-                    && (suplMode & AGPS_SUPL_MODE_MSB) != 0) {
-                return GPS_POSITION_MODE_MS_BASED;
             }
         }
         return GPS_POSITION_MODE_STANDALONE;
index 6ffe6ac..0f88883 100644 (file)
@@ -17,6 +17,8 @@
 package com.android.server.net;
 
 import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
+import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
+import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
 
 import android.app.Notification;
 import android.app.NotificationManager;
@@ -31,6 +33,7 @@ import android.net.LinkAddress;
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkInfo.State;
+import android.net.NetworkPolicyManager;
 import android.os.INetworkManagementService;
 import android.os.RemoteException;
 import android.security.Credentials;
@@ -198,8 +201,8 @@ public class LockdownVpnTracker {
                     setFirewallEgressSourceRule(addr, true);
                 }
 
-                mNetService.setFirewallUidRule(ROOT_UID, true);
-                mNetService.setFirewallUidRule(Os.getuid(), true);
+                mNetService.setFirewallUidRule(ROOT_UID, FIREWALL_RULE_ALLOW);
+                mNetService.setFirewallUidRule(Os.getuid(), FIREWALL_RULE_ALLOW);
 
                 mErrorCount = 0;
                 mAcceptedIface = iface;
@@ -288,8 +291,8 @@ public class LockdownVpnTracker {
                     setFirewallEgressSourceRule(addr, false);
                 }
 
-                mNetService.setFirewallUidRule(ROOT_UID, false);
-                mNetService.setFirewallUidRule(Os.getuid(), false);
+                mNetService.setFirewallUidRule(ROOT_UID, FIREWALL_RULE_DEFAULT);
+                mNetService.setFirewallUidRule(Os.getuid(), FIREWALL_RULE_DEFAULT);
 
                 mAcceptedSourceAddr = null;
             }
index 818f0aa..57df1c3 100644 (file)
@@ -36,11 +36,14 @@ import static android.net.NetworkPolicy.LIMIT_DISABLED;
 import static android.net.NetworkPolicy.SNOOZE_NEVER;
 import static android.net.NetworkPolicy.WARNING_DISABLED;
 import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
+import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY;
+import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
 import static android.net.NetworkPolicyManager.POLICY_ALLOW_BACKGROUND_BATTERY_SAVE;
 import static android.net.NetworkPolicyManager.POLICY_NONE;
 import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
+import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
 import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
 import static android.net.NetworkPolicyManager.dumpPolicy;
 import static android.net.NetworkPolicyManager.dumpRules;
@@ -80,6 +83,8 @@ import android.app.INotificationManager;
 import android.app.IProcessObserver;
 import android.app.Notification;
 import android.app.PendingIntent;
+import android.app.usage.UsageStatsManagerInternal;
+import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -88,6 +93,7 @@ import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
 import android.net.ConnectivityManager;
@@ -110,13 +116,16 @@ import android.os.Binder;
 import android.os.Environment;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.IDeviceIdleController;
 import android.os.INetworkManagementService;
 import android.os.IPowerManager;
 import android.os.Message;
 import android.os.MessageQueue.IdleHandler;
+import android.os.PowerManager;
 import android.os.PowerManagerInternal;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -137,7 +146,6 @@ import android.util.SparseIntArray;
 import android.util.TrustedTime;
 import android.util.Xml;
 
-import com.android.server.AppOpsService;
 import libcore.io.IoUtils;
 
 import com.android.internal.R;
@@ -145,6 +153,8 @@ import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.AppOpsService;
+import com.android.server.DeviceIdleController;
 import com.android.server.LocalServices;
 import com.android.server.SystemConfig;
 import com.google.android.collect.Lists;
@@ -172,7 +182,8 @@ import java.util.List;
  * and delivers to listeners, such as {@link ConnectivityManager}, for
  * enforcement.
  */
-public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
+public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
+        implements AppIdleStateChangeListener {
     private static final String TAG = "NetworkPolicy";
     private static final boolean LOGD = false;
     private static final boolean LOGV = false;
@@ -240,11 +251,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
     private final IPowerManager mPowerManager;
     private final INetworkStatsService mNetworkStats;
     private final INetworkManagementService mNetworkManager;
+    private UsageStatsManagerInternal mUsageStats;
     private final TrustedTime mTime;
 
     private IConnectivityManager mConnManager;
     private INotificationManager mNotifManager;
     private PowerManagerInternal mPowerManagerInternal;
+    private IDeviceIdleController mDeviceIdleController;
 
     final Object mRulesLock = new Object();
 
@@ -321,6 +334,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
         mPowerManager = checkNotNull(powerManager, "missing powerManager");
         mNetworkStats = checkNotNull(networkStats, "missing networkStats");
         mNetworkManager = checkNotNull(networkManagement, "missing networkManagement");
+        mDeviceIdleController = IDeviceIdleController.Stub.asInterface(ServiceManager.getService(
+                DeviceIdleController.SERVICE_NAME));
         mTime = checkNotNull(time, "missing TrustedTime");
 
         HandlerThread thread = new HandlerThread(TAG);
@@ -342,28 +357,31 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
         mNotifManager = checkNotNull(notifManager, "missing INotificationManager");
     }
 
+    void updatePowerSaveWhitelistLocked() {
+        try {
+            final int[] whitelist = mDeviceIdleController.getAppIdWhitelist();
+            mPowerSaveWhitelistAppIds.clear();
+            if (whitelist != null) {
+                for (int uid : whitelist) {
+                    mPowerSaveWhitelistAppIds.put(uid, true);
+                }
+            }
+        } catch (RemoteException e) {
+        }
+    }
+
     public void systemReady() {
         if (!isBandwidthControlEnabled()) {
             Slog.w(TAG, "bandwidth controls disabled, unable to enforce policy");
             return;
         }
 
+        mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
+
         final PackageManager pm = mContext.getPackageManager();
 
         synchronized (mRulesLock) {
-            SystemConfig sysConfig = SystemConfig.getInstance();
-            ArraySet<String> allowPower = sysConfig.getAllowInPowerSave();
-            for (int i=0; i<allowPower.size(); i++) {
-                String pkg = allowPower.valueAt(i);
-                try {
-                    ApplicationInfo ai = pm.getApplicationInfo(pkg, 0);
-                    if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
-                        mPowerSaveWhitelistAppIds.put(UserHandle.getAppId(ai.uid), true);
-                    }
-                } catch (PackageManager.NameNotFoundException e) {
-                }
-            }
-
+            updatePowerSaveWhitelistLocked();
             mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
             mPowerManagerInternal.registerLowPowerModeObserver(
                     new PowerManagerInternal.LowPowerModeListener() {
@@ -406,6 +424,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
         screenFilter.addAction(Intent.ACTION_SCREEN_OFF);
         mContext.registerReceiver(mScreenReceiver, screenFilter);
 
+        // listen for changes to power save whitelist
+        final IntentFilter whitelistFilter = new IntentFilter(
+                PowerManager.ACTION_POWER_SAVE_WHITELIST_CHANGED);
+        mContext.registerReceiver(mPowerSaveWhitelistReceiver, whitelistFilter, null, mHandler);
+
         // watch for network interfaces to be claimed
         final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION);
         mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler);
@@ -449,6 +472,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                 WifiManager.NETWORK_STATE_CHANGED_ACTION);
         mContext.registerReceiver(mWifiStateReceiver, wifiStateFilter, null, mHandler);
 
+        mUsageStats.addAppIdleStateChangeListener(this);
+
     }
 
     private IProcessObserver mProcessObserver = new IProcessObserver.Stub() {
@@ -489,6 +514,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
         }
     };
 
+    private BroadcastReceiver mPowerSaveWhitelistReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            // on background handler thread, and POWER_SAVE_WHITELIST_CHANGED is protected
+            synchronized (mRulesLock) {
+                updatePowerSaveWhitelistLocked();
+                updateRulesForGlobalChangeLocked(false);
+            }
+        }
+    };
+
     private BroadcastReceiver mScreenReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -546,12 +582,17 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
             final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
             if (userId == -1) return;
 
-            synchronized (mRulesLock) {
-                // Remove any policies for given user; both cleaning up after a
-                // USER_REMOVED, and one last sanity check during USER_ADDED
-                removePoliciesForUserLocked(userId);
-                // Update global restrict for new user
-                updateRulesForGlobalChangeLocked(true);
+            switch (action) {
+                case ACTION_USER_REMOVED:
+                case ACTION_USER_ADDED:
+                    synchronized (mRulesLock) {
+                        // Remove any policies for given user; both cleaning up after a
+                        // USER_REMOVED, and one last sanity check during USER_ADDED
+                        removePoliciesForUserLocked(userId);
+                        // Update global restrict for new user
+                        updateRulesForGlobalChangeLocked(true);
+                    }
+                    break;
             }
         }
     };
@@ -1528,20 +1569,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
         return uids;
     }
 
-    @Override
-    public int[] getPowerSaveAppIdWhitelist() {
-        mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
-
-        synchronized (mRulesLock) {
-            int size = mPowerSaveWhitelistAppIds.size();
-            int[] appids = new int[size];
-            for (int i = 0; i < size; i++) {
-                appids[i] = mPowerSaveWhitelistAppIds.keyAt(i);
-            }
-            return appids;
-        }
-    }
-
     /**
      * Remove any policies associated with given {@link UserHandle}, persisting
      * if any changes are made.
@@ -2032,6 +2059,22 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
         return false;
     }
 
+    private boolean isUidIdle(int uid) {
+        final String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
+        final int userId = UserHandle.getUserId(uid);
+
+        for (String packageName : packages) {
+            if (!mUsageStats.isAppIdle(packageName, userId)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Applies network rules to bandwidth and firewall controllers based on uid policy.
+     * @param uid The uid for which to apply the latest policy
+     */
     void updateRulesForUidLocked(int uid) {
         if (!isUidValidForRules(uid)) return;
 
@@ -2048,10 +2091,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
 
         final int uidPolicy = mUidPolicy.get(uid, POLICY_NONE);
         final boolean uidForeground = isUidForegroundLocked(uid);
+        final boolean uidIdle = isUidIdle(uid);
 
         // derive active rules based on policy and active state
+
         int uidRules = RULE_ALLOW_ALL;
-        if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
+        if (uidIdle && !mPowerSaveWhitelistAppIds.get(UserHandle.getAppId(uid))) {
+            uidRules = RULE_REJECT_ALL;
+        } else if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) {
             // uid in background, and policy says to block metered data
             uidRules = RULE_REJECT_METERED;
         } else if (mRestrictBackground) {
@@ -2070,7 +2117,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
             }
         }
 
-        // TODO: only dispatch when rules actually change
+        final int oldRules = mUidRules.get(uid);
 
         if (uidRules == RULE_ALLOW_ALL) {
             mUidRules.delete(uid);
@@ -2078,11 +2125,24 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
             mUidRules.put(uid, uidRules);
         }
 
+        // Update bandwidth rules if necessary
+        final boolean oldRejectMetered = (oldRules & RULE_REJECT_METERED) != 0;
         final boolean rejectMetered = (uidRules & RULE_REJECT_METERED) != 0;
-        setUidNetworkRules(uid, rejectMetered);
+        if (oldRejectMetered != rejectMetered) {
+            setUidNetworkRules(uid, rejectMetered);
+        }
+
+        // Update firewall rules if necessary
+        final boolean oldFirewallReject = (oldRules & RULE_REJECT_ALL) != 0;
+        final boolean firewallReject = (uidRules & RULE_REJECT_ALL) != 0;
+        if (oldFirewallReject != firewallReject) {
+            setUidFirewallRules(uid, firewallReject);
+        }
 
         // dispatch changed rule to existing listeners
-        mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules).sendToTarget();
+        if (oldRules != uidRules) {
+            mHandler.obtainMessage(MSG_RULES_CHANGED, uid, uidRules).sendToTarget();
+        }
 
         try {
             // adjust stats accounting based on foreground status
@@ -2092,6 +2152,18 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
         }
     }
 
+    @Override
+    public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
+        try {
+            int uid = mContext.getPackageManager().getPackageUid(packageName, userId);
+            synchronized (mRulesLock) {
+                updateRulesForUidLocked(uid);
+            }
+        } catch (NameNotFoundException nnfe) {
+            return;
+        }
+    }
+
     private Handler.Callback mHandlerCallback = new Handler.Callback() {
         @Override
         public boolean handleMessage(Message msg) {
@@ -2215,6 +2287,22 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
         }
     }
 
+    /**
+     * Add or remove a uid to the firewall blacklist for all network ifaces.
+     * @param uid
+     * @param rejectOnAll
+     */
+    private void setUidFirewallRules(int uid, boolean rejectOnAll) {
+        try {
+            mNetworkManager.setFirewallUidRule(uid,
+                    rejectOnAll ? FIREWALL_RULE_DENY : FIREWALL_RULE_DEFAULT);
+        } catch (IllegalStateException e) {
+            Log.wtf(TAG, "problem setting firewall uid rules", e);
+        } catch (RemoteException e) {
+            // ignored; service lives in system_server
+        }
+    }
+
     private long getTotalBytes(NetworkTemplate template, long start, long end) {
         try {
             return mNetworkStats.getNetworkTotalBytes(template, start, end);
diff --git a/services/core/java/com/android/server/power/DeviceIdleController.java b/services/core/java/com/android/server/power/DeviceIdleController.java
deleted file mode 100644 (file)
index 6b29b9a..0000000
+++ /dev/null
@@ -1,489 +0,0 @@
-/*
- * Copyright (C) 2015 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.
- */
-
-package com.android.server.power;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.hardware.Sensor;
-import android.hardware.SensorManager;
-import android.hardware.TriggerEvent;
-import android.hardware.TriggerEventListener;
-import android.hardware.display.DisplayManager;
-import android.net.INetworkPolicyManager;
-import android.os.Binder;
-import android.os.PowerManager;
-import android.os.PowerManagerInternal;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.util.TimeUtils;
-import android.view.Display;
-import com.android.internal.app.IBatteryStats;
-import com.android.server.SystemService;
-import com.android.server.am.BatteryStatsService;
-import com.android.server.EventLogTags;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * Keeps track of device idleness and drives low power mode based on that.
- */
-public class DeviceIdleController extends SystemService {
-    private static final String TAG = "DeviceIdleController";
-
-    private static final String ACTION_STEP_IDLE_STATE =
-            "com.android.server.device_idle.STEP_IDLE_STATE";
-
-    // TODO: These need to be moved to system settings.
-
-    /**
-     * This is the time, after becoming inactive, at which we start looking at the
-     * motion sensor to determine if the device is being left alone.  We don't do this
-     * immediately after going inactive just because we don't want to be continually running
-     * the significant motion sensor whenever the screen is off.
-     */
-    private static final long DEFAULT_INACTIVE_TIMEOUT = 30*60*1000L;
-    /**
-     * This is the time, after seeing motion, that we wait after becoming inactive from
-     * that until we start looking for motion again.
-     */
-    private static final long DEFAULT_MOTION_INACTIVE_TIMEOUT = 10*60*1000L;
-    /**
-     * This is the time, after the inactive timeout elapses, that we will wait looking
-     * for significant motion until we truly consider the device to be idle.
-     */
-    private static final long DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT = 30*60*1000L;
-    /**
-     * This is the initial time, after being idle, that we will allow ourself to be back
-     * in the IDLE_PENDING state allowing the system to run normally until we return to idle.
-     */
-    private static final long DEFAULT_IDLE_PENDING_TIMEOUT = 5*60*1000L;
-    /**
-     * Maximum pending idle timeout (time spent running) we will be allowed to use.
-     */
-    private static final long DEFAULT_MAX_IDLE_PENDING_TIMEOUT = 10*60*1000L;
-    /**
-     * Scaling factor to apply to current pending idle timeout each time we cycle through
-     * that state.
-     */
-    private static final float DEFAULT_IDLE_PENDING_FACTOR = 2f;
-    /**
-     * This is the initial time that we want to sit in the idle state before waking up
-     * again to return to pending idle and allowing normal work to run.
-     */
-    private static final long DEFAULT_IDLE_TIMEOUT = 60*60*1000L;
-    /**
-     * Maximum idle duration we will be allowed to use.
-     */
-    private static final long DEFAULT_MAX_IDLE_TIMEOUT = 6*60*60*1000L;
-    /**
-     * Scaling factor to apply to current idle timeout each time we cycle through that state.
-     */
-    private static final float DEFAULT_IDLE_FACTOR = 2f;
-    /**
-     * This is the minimum time we will allow until the next upcoming alarm for us to
-     * actually go in to idle mode.
-     */
-    private static final long DEFAULT_MIN_TIME_TO_ALARM = 60*60*1000L;
-
-    private AlarmManager mAlarmManager;
-    private IBatteryStats mBatteryStats;
-    private PowerManagerInternal mLocalPowerManager;
-    private INetworkPolicyManager mNetworkPolicyManager;
-    private DisplayManager mDisplayManager;
-    private SensorManager mSensorManager;
-    private Sensor mSigMotionSensor;
-    private PendingIntent mAlarmIntent;
-    private Intent mIdleIntent;
-    private Display mCurDisplay;
-    private boolean mScreenOn;
-    private boolean mCharging;
-    private boolean mSigMotionActive;
-
-    /** Device is currently active. */
-    private static final int STATE_ACTIVE = 0;
-    /** Device is inactve (screen off, no motion) and we are waiting to for idle. */
-    private static final int STATE_INACTIVE = 1;
-    /** Device is past the initial inactive period, and waiting for the next idle period. */
-    private static final int STATE_IDLE_PENDING = 2;
-    /** Device is in the idle state, trying to stay asleep as much as possible. */
-    private static final int STATE_IDLE = 3;
-    private static String stateToString(int state) {
-        switch (state) {
-            case STATE_ACTIVE: return "ACTIVE";
-            case STATE_INACTIVE: return "INACTIVE";
-            case STATE_IDLE_PENDING: return "IDLE_PENDING";
-            case STATE_IDLE: return "IDLE";
-            default: return Integer.toString(state);
-        }
-    }
-
-    private int mState;
-
-    private long mInactiveTimeout;
-    private long mNextAlarmTime;
-    private long mNextIdlePendingDelay;
-    private long mNextIdleDelay;
-
-    private final Binder mBinder = new Binder() {
-        @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-            DeviceIdleController.this.dump(fd, pw, args);
-        }
-    };
-
-    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-        @Override public void onReceive(Context context, Intent intent) {
-            if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
-                int plugged = intent.getIntExtra("plugged", 0);
-                updateChargingLocked(plugged != 0);
-            } else if (ACTION_STEP_IDLE_STATE.equals(intent.getAction())) {
-                synchronized (DeviceIdleController.this) {
-                    stepIdleStateLocked();
-                }
-            }
-        }
-    };
-
-    private final DisplayManager.DisplayListener mDisplayListener
-            = new DisplayManager.DisplayListener() {
-        @Override public void onDisplayAdded(int displayId) {
-        }
-
-        @Override public void onDisplayRemoved(int displayId) {
-        }
-
-        @Override public void onDisplayChanged(int displayId) {
-            if (displayId == Display.DEFAULT_DISPLAY) {
-                synchronized (DeviceIdleController.this) {
-                    updateDisplayLocked();
-                }
-            }
-        }
-    };
-
-    private final TriggerEventListener mSigMotionListener = new TriggerEventListener() {
-        @Override public void onTrigger(TriggerEvent event) {
-            synchronized (DeviceIdleController.this) {
-                significantMotionLocked();
-            }
-        }
-    };
-
-    public DeviceIdleController(Context context) {
-        super(context);
-    }
-
-    @Override
-    public void onStart() {
-        synchronized (this) {
-            mAlarmManager = (AlarmManager) getContext().getSystemService(Context.ALARM_SERVICE);
-            mBatteryStats = BatteryStatsService.getService();
-            mLocalPowerManager = getLocalService(PowerManagerInternal.class);
-            mNetworkPolicyManager = INetworkPolicyManager.Stub.asInterface(
-                                ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
-            mDisplayManager = (DisplayManager) getContext().getSystemService(
-                    Context.DISPLAY_SERVICE);
-            mSensorManager = (SensorManager) getContext().getSystemService(Context.SENSOR_SERVICE);
-            mSigMotionSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION);
-
-            Intent intent = new Intent(ACTION_STEP_IDLE_STATE)
-                    .setPackage("android")
-                    .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-            mAlarmIntent = PendingIntent.getBroadcast(getContext(), 0, intent, 0);
-
-            mIdleIntent = new Intent(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
-            mIdleIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-
-            IntentFilter filter = new IntentFilter();
-            filter.addAction(Intent.ACTION_BATTERY_CHANGED);
-            filter.addAction(ACTION_STEP_IDLE_STATE);
-            getContext().registerReceiver(mReceiver, filter);
-
-            mDisplayManager.registerDisplayListener(mDisplayListener, null);
-
-            mScreenOn = true;
-            // Start out assuming we are charging.  If we aren't, we will at least get
-            // a battery update the next time the level drops.
-            mCharging = true;
-            mState = STATE_ACTIVE;
-            mInactiveTimeout = DEFAULT_INACTIVE_TIMEOUT;
-            updateDisplayLocked();
-        }
-
-        publishBinderService("deviceidle", mBinder);
-    }
-
-    void updateDisplayLocked() {
-        mCurDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY);
-        // We consider any situation where the display is showing something to be it on,
-        // because if there is anything shown we are going to be updating it at some
-        // frequency so can't be allowed to go into deep sleeps.
-        boolean screenOn = mCurDisplay.getState() != Display.STATE_OFF;;
-        if (!screenOn && mScreenOn) {
-            mScreenOn = false;
-            becomeInactiveIfAppropriateLocked();
-        } else if (screenOn) {
-            mScreenOn = true;
-            becomeActiveLocked("screen");
-        }
-    }
-
-    void updateChargingLocked(boolean charging) {
-        if (!charging && mCharging) {
-            mCharging = false;
-            becomeInactiveIfAppropriateLocked();
-        } else if (charging) {
-            mCharging = charging;
-            becomeActiveLocked("charging");
-        }
-    }
-
-    void becomeActiveLocked(String reason) {
-        if (mState != STATE_ACTIVE) {
-            EventLogTags.writeDeviceIdle(STATE_ACTIVE, reason);
-            mLocalPowerManager.setDeviceIdleMode(false);
-            try {
-                mNetworkPolicyManager.setDeviceIdleMode(false);
-                mBatteryStats.noteDeviceIdleMode(false, true, false);
-            } catch (RemoteException e) {
-            }
-            if (mState == STATE_IDLE) {
-                getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
-            }
-            mState = STATE_ACTIVE;
-            mInactiveTimeout = DEFAULT_INACTIVE_TIMEOUT;
-            mNextIdlePendingDelay = 0;
-            mNextIdleDelay = 0;
-            cancelAlarmLocked();
-            stopMonitoringSignificantMotion();
-        }
-    }
-
-    void becomeInactiveIfAppropriateLocked() {
-        if (!mScreenOn && !mCharging && mState == STATE_ACTIVE) {
-            // Screen has turned off; we are now going to become inactive and start
-            // waiting to see if we will ultimately go idle.
-            mState = STATE_INACTIVE;
-            mNextIdlePendingDelay = 0;
-            mNextIdleDelay = 0;
-            scheduleAlarmLocked(mInactiveTimeout, false);
-            EventLogTags.writeDeviceIdle(mState, "no activity");
-        }
-    }
-
-    void stepIdleStateLocked() {
-        EventLogTags.writeDeviceIdleStep();
-
-        final long now = SystemClock.elapsedRealtime();
-        if ((now+DEFAULT_MIN_TIME_TO_ALARM) > mAlarmManager.getNextWakeFromIdleTime()) {
-            // Whoops, there is an upcoming alarm.  We don't actually want to go idle.
-            if (mState != STATE_ACTIVE) {
-                becomeActiveLocked("alarm");
-            }
-            return;
-        }
-
-        switch (mState) {
-            case STATE_INACTIVE:
-                // We have now been inactive long enough, it is time to start looking
-                // for significant motion and sleep some more while doing so.
-                startMonitoringSignificantMotion();
-                scheduleAlarmLocked(DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT, false);
-                // Reset the upcoming idle delays.
-                mNextIdlePendingDelay = DEFAULT_IDLE_PENDING_TIMEOUT;
-                mNextIdleDelay = DEFAULT_IDLE_TIMEOUT;
-                mState = STATE_IDLE_PENDING;
-                EventLogTags.writeDeviceIdle(mState, "step");
-                break;
-            case STATE_IDLE_PENDING:
-                // We have been waiting to become idle, and now it is time!  This is the
-                // only case where we want to use a wakeup alarm, because we do want to
-                // drag the device out of its sleep state in this case to do the next
-                // scheduled work.
-                scheduleAlarmLocked(mNextIdleDelay, true);
-                mNextIdleDelay = (long)(mNextIdleDelay*DEFAULT_IDLE_FACTOR);
-                if (mNextIdleDelay > DEFAULT_MAX_IDLE_TIMEOUT) {
-                    mNextIdleDelay = DEFAULT_MAX_IDLE_TIMEOUT;
-                }
-                mState = STATE_IDLE;
-                EventLogTags.writeDeviceIdle(mState, "step");
-                mLocalPowerManager.setDeviceIdleMode(true);
-                try {
-                    mNetworkPolicyManager.setDeviceIdleMode(true);
-                    mBatteryStats.noteDeviceIdleMode(true, false, false);
-                } catch (RemoteException e) {
-                }
-                getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
-                break;
-            case STATE_IDLE:
-                // We have been idling long enough, now it is time to do some work.
-                scheduleAlarmLocked(mNextIdlePendingDelay, false);
-                mNextIdlePendingDelay = (long)(mNextIdlePendingDelay*DEFAULT_IDLE_PENDING_FACTOR);
-                if (mNextIdlePendingDelay > DEFAULT_MAX_IDLE_PENDING_TIMEOUT) {
-                    mNextIdlePendingDelay = DEFAULT_MAX_IDLE_PENDING_TIMEOUT;
-                }
-                mState = STATE_IDLE_PENDING;
-                EventLogTags.writeDeviceIdle(mState, "step");
-                mLocalPowerManager.setDeviceIdleMode(false);
-                try {
-                    mNetworkPolicyManager.setDeviceIdleMode(false);
-                    mBatteryStats.noteDeviceIdleMode(false, false, false);
-                } catch (RemoteException e) {
-                }
-                getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
-                break;
-        }
-    }
-
-    void significantMotionLocked() {
-        // When the sensor goes off, its trigger is automatically removed.
-        mSigMotionActive = false;
-        // The device is not yet active, so we want to go back to the pending idle
-        // state to wait again for no motion.  Note that we only monitor for significant
-        // motion after moving out of the inactive state, so no need to worry about that.
-        if (mState != STATE_ACTIVE) {
-            mLocalPowerManager.setDeviceIdleMode(false);
-            try {
-                mNetworkPolicyManager.setDeviceIdleMode(false);
-                mBatteryStats.noteDeviceIdleMode(false, false, true);
-            } catch (RemoteException e) {
-            }
-            if (mState == STATE_IDLE) {
-                getContext().sendBroadcastAsUser(mIdleIntent, UserHandle.ALL);
-            }
-            mState = STATE_ACTIVE;
-            mInactiveTimeout = DEFAULT_MOTION_INACTIVE_TIMEOUT;
-            EventLogTags.writeDeviceIdle(mState, "motion");
-            becomeInactiveIfAppropriateLocked();
-        }
-    }
-
-    void startMonitoringSignificantMotion() {
-        if (mSigMotionSensor != null && !mSigMotionActive) {
-            mSensorManager.requestTriggerSensor(mSigMotionListener, mSigMotionSensor);
-            mSigMotionActive = true;
-        }
-    }
-
-    void stopMonitoringSignificantMotion() {
-        if (mSigMotionActive) {
-            mSensorManager.cancelTriggerSensor(mSigMotionListener, mSigMotionSensor);
-            mSigMotionActive = false;
-        }
-    }
-
-    void cancelAlarmLocked() {
-        if (mNextAlarmTime != 0) {
-            mNextAlarmTime = 0;
-            mAlarmManager.cancel(mAlarmIntent);
-        }
-    }
-
-    void scheduleAlarmLocked(long delay, boolean idleUntil) {
-        if (mSigMotionSensor == null) {
-            // If there is no significant motion sensor on this device, then we won't schedule
-            // alarms, because we can't determine if the device is not moving.  This effectively
-            // turns off normal exeuction of device idling, although it is still possible to
-            // manually poke it by pretending like the alarm is going off.
-            return;
-        }
-        mNextAlarmTime = SystemClock.elapsedRealtime() + delay;
-        if (idleUntil) {
-            mAlarmManager.setIdleUntil(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                    mNextAlarmTime, mAlarmIntent);
-        } else {
-            mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                    mNextAlarmTime, mAlarmIntent);
-        }
-    }
-
-    private void dumpHelp(PrintWriter pw) {
-        pw.println("Device idle controller (deviceidle) dump options:");
-        pw.println("  [-h] [CMD]");
-        pw.println("  -h: print this help text.");
-        pw.println("Commands:");
-        pw.println("  step");
-        pw.println("    Immediately step to next state, without waiting for alarm.");
-    }
-
-    void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
-                != PackageManager.PERMISSION_GRANTED) {
-            pw.println("Permission Denial: can't dump DeviceIdleController from from pid="
-                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
-                    + " without permission " + android.Manifest.permission.DUMP);
-            return;
-        }
-
-        if (args != null) {
-            for (int i=0; i<args.length; i++) {
-                String arg = args[i];
-                if ("-h".equals(arg)) {
-                    dumpHelp(pw);
-                    return;
-                } else if ("step".equals(arg)) {
-                    synchronized (this) {
-                        stepIdleStateLocked();
-                        pw.print("Stepped to: "); pw.println(stateToString(mState));
-                    }
-                    return;
-                } else if (arg.length() > 0 && arg.charAt(0) == '-'){
-                    pw.println("Unknown option: " + arg);
-                    dumpHelp(pw);
-                    return;
-                } else {
-                    pw.println("Unknown command: " + arg);
-                    dumpHelp(pw);
-                    return;
-                }
-            }
-        }
-
-        synchronized (this) {
-            pw.print("  mSigMotionSensor="); pw.println(mSigMotionSensor);
-            pw.print("  mCurDisplay="); pw.println(mCurDisplay);
-            pw.print("  mScreenOn="); pw.println(mScreenOn);
-            pw.print("  mCharging="); pw.println(mCharging);
-            pw.print("  mSigMotionActive="); pw.println(mSigMotionActive);
-            pw.print("  mState="); pw.println(stateToString(mState));
-            pw.print("  mInactiveTimeout="); TimeUtils.formatDuration(mInactiveTimeout, pw);
-            pw.println();
-            if (mNextAlarmTime != 0) {
-                pw.print("  mNextAlarmTime=");
-                TimeUtils.formatDuration(mNextAlarmTime, SystemClock.elapsedRealtime(), pw);
-                pw.println();
-            }
-            if (mNextIdlePendingDelay != 0) {
-                pw.print("  mNextIdlePendingDelay=");
-                TimeUtils.formatDuration(mNextIdlePendingDelay, pw);
-                pw.println();
-            }
-            if (mNextIdleDelay != 0) {
-                pw.print("  mNextIdleDelay=");
-                TimeUtils.formatDuration(mNextIdleDelay, pw);
-                pw.println();
-            }
-        }
-    }
-}
index ee50ff9..d8c172f 100644 (file)
@@ -71,6 +71,7 @@ static int usb_device_added(const char *devname, void* client_data) {
 
     char *manufacturer = usb_device_get_manufacturer_name(device);
     char *product = usb_device_get_product_name(device);
+    int version = usb_device_get_version(device);
     char *serial = usb_device_get_serial(device);
 
     jstring deviceName = env->NewStringUTF(devname);
@@ -81,7 +82,7 @@ static int usb_device_added(const char *devname, void* client_data) {
     jboolean result = env->CallBooleanMethod(thiz, method_beginUsbDeviceAdded,
             deviceName, usb_device_get_vendor_id(device), usb_device_get_product_id(device),
             deviceDesc->bDeviceClass, deviceDesc->bDeviceSubClass, deviceDesc->bDeviceProtocol,
-            manufacturerName, productName, serialNumber);
+            manufacturerName, productName, version, serialNumber);
 
     env->DeleteLocalRef(serialNumber);
     env->DeleteLocalRef(productName);
@@ -199,7 +200,7 @@ int register_android_server_UsbHostManager(JNIEnv *env)
         return -1;
     }
     method_beginUsbDeviceAdded = env->GetMethodID(clazz, "beginUsbDeviceAdded",
-            "(Ljava/lang/String;IIIIILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z");
+            "(Ljava/lang/String;IIIIILjava/lang/String;Ljava/lang/String;ILjava/lang/String;)Z");
     if (method_beginUsbDeviceAdded == NULL) {
         ALOGE("Can't find beginUsbDeviceAdded");
         return -1;
index 593853c..2922130 100644 (file)
@@ -76,7 +76,6 @@ import com.android.server.pm.Installer;
 import com.android.server.pm.LauncherAppsService;
 import com.android.server.pm.PackageManagerService;
 import com.android.server.pm.UserManagerService;
-import com.android.server.power.DeviceIdleController;
 import com.android.server.power.PowerManagerService;
 import com.android.server.power.ShutdownThread;
 import com.android.server.restrictions.RestrictionsManagerService;
@@ -599,6 +598,8 @@ public final class SystemServer {
                     mSystemServiceManager.startService(PersistentDataBlockService.class);
                 }
 
+                mSystemServiceManager.startService(DeviceIdleController.class);
+
                 // Always start the Device Policy Manager, so that the API is compatible with
                 // API8.
                 mSystemServiceManager.startService(DevicePolicyManagerService.Lifecycle.class);
@@ -965,7 +966,6 @@ public final class SystemServer {
 
         if (!disableNonCoreServices) {
             mSystemServiceManager.startService(MediaProjectionManagerService.class);
-            mSystemServiceManager.startService(DeviceIdleController.class);
         }
 
         // Before things start rolling, be sure we have decided whether
index 04984d3..c2e61c6 100644 (file)
@@ -28,7 +28,6 @@ import android.app.usage.UsageEvents.Event;
 import android.app.usage.UsageStats;
 import android.app.usage.UsageStatsManagerInternal;
 import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
-import android.appwidget.AppWidgetManager;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -41,6 +40,7 @@ import android.content.pm.UserInfo;
 import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.net.Uri;
+import android.os.BatteryManager;
 import android.os.Binder;
 import android.os.Environment;
 import android.os.Handler;
@@ -81,6 +81,8 @@ public class UsageStatsService extends SystemService implements
     private static final long TWENTY_MINUTES = 20 * 60 * 1000;
     private static final long FLUSH_INTERVAL = DEBUG ? TEN_SECONDS : TWENTY_MINUTES;
     private static final long TIME_CHANGE_THRESHOLD_MILLIS = 2 * 1000; // Two seconds.
+    static final long DEFAULT_APP_IDLE_THRESHOLD_MILLIS = 2L * 24 * 60 * 60 * 1000; // 1 day
+    static final long DEFAULT_CHECK_IDLE_INTERVAL = 8 * 3600 * 1000; // 8 hours
 
     // Handler message types.
     static final int MSG_REPORT_EVENT = 0;
@@ -88,6 +90,7 @@ public class UsageStatsService extends SystemService implements
     static final int MSG_REMOVE_USER = 2;
     static final int MSG_INFORM_LISTENERS = 3;
     static final int MSG_RESET_LAST_TIMESTAMP = 4;
+    static final int MSG_CHECK_IDLE_STATES = 5;
 
     private final Object mLock = new Object();
     Handler mHandler;
@@ -98,9 +101,11 @@ public class UsageStatsService extends SystemService implements
     private File mUsageStatsDir;
     long mRealTimeSnapshot;
     long mSystemTimeSnapshot;
+    boolean mAppIdleParoled;
 
-    private static final long DEFAULT_APP_IDLE_THRESHOLD_MILLIS = 1L * 24 * 60 * 60 * 1000; // 1 day
-    private long mAppIdleDurationMillis;
+    long mAppIdleDurationMillis;
+
+    long mCheckIdleIntervalMillis = DEFAULT_CHECK_IDLE_INTERVAL;
 
     private ArrayList<UsageStatsManagerInternal.AppIdleStateChangeListener>
             mPackageAccessListeners = new ArrayList<>();
@@ -113,6 +118,7 @@ public class UsageStatsService extends SystemService implements
     public void onStart() {
         mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
         mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
+
         mHandler = new H(BackgroundThread.get().getLooper());
 
         File systemDataDir = new File(Environment.getDataDirectory(), "system");
@@ -123,9 +129,14 @@ public class UsageStatsService extends SystemService implements
                     + mUsageStatsDir.getAbsolutePath());
         }
 
-        getContext().registerReceiver(new UserRemovedReceiver(),
-                new IntentFilter(Intent.ACTION_USER_REMOVED));
+        IntentFilter userActions = new IntentFilter(Intent.ACTION_USER_REMOVED);
+        userActions.addAction(Intent.ACTION_USER_STARTED);
+        getContext().registerReceiverAsUser(new UserActionsReceiver(), UserHandle.ALL, userActions,
+                null, null);
 
+        IntentFilter deviceStates = new IntentFilter(BatteryManager.ACTION_CHARGING);
+        deviceStates.addAction(BatteryManager.ACTION_DISCHARGING);
+        getContext().registerReceiver(new DeviceStateReceiver(), deviceStates);
         synchronized (mLock) {
             cleanUpRemovedUsersLocked();
         }
@@ -147,18 +158,35 @@ public class UsageStatsService extends SystemService implements
         if (phase == PHASE_SYSTEM_SERVICES_READY) {
             // Observe changes to the threshold
             new SettingsObserver(mHandler).registerObserver();
+        } else if (phase == PHASE_BOOT_COMPLETED) {
+            setAppIdleParoled(getContext().getSystemService(BatteryManager.class).isCharging());
         }
     }
 
-    private class UserRemovedReceiver extends BroadcastReceiver {
+    private class UserActionsReceiver extends BroadcastReceiver {
 
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (intent != null && intent.getAction().equals(Intent.ACTION_USER_REMOVED)) {
-                final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+            if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
                 if (userId >= 0) {
                     mHandler.obtainMessage(MSG_REMOVE_USER, userId, 0).sendToTarget();
                 }
+            } else if (Intent.ACTION_USER_STARTED.equals(intent.getAction())) {
+                if (userId >=0) {
+                    postCheckIdleStates();
+                }
+            }
+        }
+    }
+
+    private class DeviceStateReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            final String action = intent.getAction();
+            if (BatteryManager.ACTION_CHARGING.equals(action)
+                    || BatteryManager.ACTION_DISCHARGING.equals(action)) {
+                setAppIdleParoled(BatteryManager.ACTION_CHARGING.equals(action));
             }
         }
     }
@@ -195,6 +223,49 @@ public class UsageStatsService extends SystemService implements
         }
     }
 
+    void setAppIdleParoled(boolean paroled) {
+        synchronized (mLock) {
+            if (mAppIdleParoled != paroled) {
+                mAppIdleParoled = paroled;
+                postCheckIdleStates();
+            }
+        }
+    }
+
+    void postCheckIdleStates() {
+        mHandler.removeMessages(MSG_CHECK_IDLE_STATES);
+        mHandler.sendEmptyMessage(MSG_CHECK_IDLE_STATES);
+    }
+
+    /** Check all running users' apps to see if they enter an idle state. */
+    void checkIdleStates() {
+        final int[] runningUsers;
+        try {
+            runningUsers = ActivityManagerNative.getDefault().getRunningUserIds();
+        } catch (RemoteException re) {
+            return;
+        }
+
+        for (int i = 0; i < runningUsers.length; i++) {
+            final int userId = runningUsers[i];
+            List<PackageInfo> packages =
+                    getContext().getPackageManager().getInstalledPackages(
+                            PackageManager.GET_DISABLED_COMPONENTS
+                                | PackageManager.GET_UNINSTALLED_PACKAGES,
+                            userId);
+            synchronized (mLock) {
+                final int packageCount = packages.size();
+                for (int p = 0; p < packageCount; p++) {
+                    final String packageName = packages.get(p).packageName;
+                    final boolean isIdle = isAppIdle(packageName, userId);
+                    mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
+                            userId, isIdle ? 1 : 0, packageName));
+                }
+            }
+        }
+        mHandler.sendEmptyMessageDelayed(MSG_CHECK_IDLE_STATES, mCheckIdleIntervalMillis);
+    }
+
     private static void deleteRecursively(File f) {
         File[] files = f.listFiles();
         if (files != null) {
@@ -291,7 +362,7 @@ public class UsageStatsService extends SystemService implements
     void resetLastTimestamp(String packageName, int userId, boolean idle) {
         synchronized (mLock) {
             final long timeNow = checkAndGetTimeLocked();
-            final long lastTimestamp = timeNow - (idle ? mAppIdleDurationMillis : 0);
+            final long lastTimestamp = timeNow - (idle ? mAppIdleDurationMillis : 0) - 5000;
 
             final UserUsageStatsService service =
                     getUserDataAndInitializeIfNeededLocked(userId, timeNow);
@@ -409,14 +480,22 @@ public class UsageStatsService extends SystemService implements
 
     private boolean hasPassedIdleDuration(long lastUsed) {
         final long now = System.currentTimeMillis();
-        return lastUsed < now - mAppIdleDurationMillis;
+        return lastUsed <= now - mAppIdleDurationMillis;
     }
 
     boolean isAppIdle(String packageName, int userId) {
         if (packageName == null) return false;
+        synchronized (mLock) {
+            // Temporary exemption, probably due to device charging or occasional allowance to
+            // be allowed to sync, etc.
+            if (mAppIdleParoled) {
+                return false;
+            }
+        }
         if (SystemConfig.getInstance().getAllowInPowerSave().contains(packageName)) {
             return false;
         }
+        // TODO: Optimize this check
         if (isActiveDeviceAdmin(packageName, userId)) {
             return false;
         }
@@ -518,6 +597,9 @@ public class UsageStatsService extends SystemService implements
                     resetLastTimestamp((String) msg.obj, msg.arg1, msg.arg2 == 1);
                     break;
 
+                case MSG_CHECK_IDLE_STATES:
+                    checkIdleStates();
+                    break;
                 default:
                     super.handleMessage(msg);
                     break;
@@ -544,7 +626,9 @@ public class UsageStatsService extends SystemService implements
             mAppIdleDurationMillis = Settings.Secure.getLongForUser(getContext().getContentResolver(),
                     Settings.Secure.APP_IDLE_DURATION, DEFAULT_APP_IDLE_THRESHOLD_MILLIS,
                     UserHandle.USER_OWNER);
-            // TODO: Check if we need to update idle states of all the apps
+            mCheckIdleIntervalMillis = Math.min(DEFAULT_CHECK_IDLE_INTERVAL,
+                    mAppIdleDurationMillis / 4);
+            postCheckIdleStates();
         }
     }
 
index daccf95..27c97d0 100644 (file)
@@ -401,6 +401,7 @@ public final class UsbAlsaManager {
                     Bundle properties = new Bundle();
                     String manufacturer = usbDevice.getManufacturerName();
                     String product = usbDevice.getProductName();
+                    String version = usbDevice.getVersion();
                     String name;
                     if (manufacturer == null || manufacturer.isEmpty()) {
                         name = product;
@@ -412,6 +413,7 @@ public final class UsbAlsaManager {
                     properties.putString(MidiDeviceInfo.PROPERTY_NAME, name);
                     properties.putString(MidiDeviceInfo.PROPERTY_MANUFACTURER, manufacturer);
                     properties.putString(MidiDeviceInfo.PROPERTY_PRODUCT, product);
+                    properties.putString(MidiDeviceInfo.PROPERTY_VERSION, version);
                     properties.putString(MidiDeviceInfo.PROPERTY_SERIAL_NUMBER,
                             usbDevice.getSerialNumber());
                     properties.putInt(MidiDeviceInfo.PROPERTY_ALSA_CARD, alsaDevice.mCard);
index 5b58051..f5f2b07 100644 (file)
@@ -112,7 +112,7 @@ public class UsbHostManager {
      */
     private boolean beginUsbDeviceAdded(String deviceName, int vendorID, int productID,
             int deviceClass, int deviceSubclass, int deviceProtocol,
-            String manufacturerName, String productName, String serialNumber) {
+            String manufacturerName, String productName, int version, String serialNumber) {
 
         if (DEBUG) {
             Slog.d(TAG, "usb:UsbHostManager.beginUsbDeviceAdded(" + deviceName + ")");
@@ -149,9 +149,12 @@ public class UsbHostManager {
                 return false;
             }
 
+            // Create version string in "%.%" format
+            String versionString = Integer.toString(version >> 8) + "." + (version & 0xFF);
+
             mNewDevice = new UsbDevice(deviceName, vendorID, productID,
                     deviceClass, deviceSubclass, deviceProtocol,
-                    manufacturerName, productName, serialNumber);
+                    manufacturerName, productName, versionString, serialNumber);
 
             mNewConfigurations = new ArrayList<UsbConfiguration>();
             mNewInterfaces = new ArrayList<UsbInterface>();
index 831a194..299c7c4 100644 (file)
@@ -48,33 +48,147 @@ public class CarrierConfigManager {
             ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
 
     /**
-     * Flag specifying whether VoLTE should be available for carrier, independent of carrier
-     * provisioning. If false: hard disabled. If true: then depends on carrier provisioning,
-     * availability, etc.
+     * Flag indicating whether the Phone app should ignore EVENT_SIM_NETWORK_LOCKED
+     * events from the Sim.
+     * If true, this will prevent the IccNetworkDepersonalizationPanel from being shown, and
+     * effectively disable the "Sim network lock" feature.
      */
-    public static final String BOOL_CARRIER_VOLTE_AVAILABLE = "bool_carrier_volte_available";
+    public static final String
+            BOOL_IGNORE_SIM_NETWORK_LOCKED_EVENTS = "bool_ignore_sim_network_locked_events";
 
     /**
-     * Flag specifying whether VoLTE availability is based on provisioning.
+     * Flag indicating whether the Phone app should provide a "Dismiss" button on the SIM network
+     * unlock screen. The default value is true. If set to false, there will be *no way* to dismiss
+     * the SIM network unlock screen if you don't enter the correct unlock code. (One important
+     * consequence: there will be no way to make an Emergency Call if your SIM is network-locked and
+     * you don't know the PIN.)
      */
-    public static final String BOOL_CARRIER_VOLTE_PROVISIONED = "bool_carrier_volte_provisioned";
+    public static final String
+            BOOL_SIM_NETWORK_UNLOCK_ALLOW_DISMISS = "bool_sim_network_unlock_allow_dismiss";
+
+    /** Flag indicating if the phone is a world phone */
+    public static final String BOOL_WORLD_PHONE = "bool_world_phone";
 
     /**
-     * Flag specifying whether VoLTE TTY is supported.
+     * If true, enable vibration (haptic feedback) for key presses in the EmergencyDialer activity.
+     * The pattern is set on a per-platform basis using config_virtualKeyVibePattern. To be
+     * consistent with the regular Dialer, this value should agree with the corresponding values
+     * from config.xml under apps/Contacts.
      */
-    public static final String BOOL_CARRIER_VOLTE_TTY_SUPPORTED
-            = "bool_carrier_volte_tty_supported";
+    public static final String
+            BOOL_ENABLE_DIALER_KEY_VIBRATION = "bool_enable_dialer_key_vibration";
+
+    /** Flag indicating if dtmf tone type is enabled */
+    public static final String BOOL_DTMF_TYPE_ENABLED = "bool_dtmf_type_enabled";
+
+    /** Flag indicating if auto retry is enabled */
+    public static final String BOOL_AUTO_RETRY_ENABLED = "bool_auto_retry_enabled";
 
     /**
-     * Show APN Settings for some CDMA carriers.
+     * Determine whether we want to play local DTMF tones in a call, or just let the radio/BP handle
+     * playing of the tones.
      */
-    public static final String BOOL_SHOW_APN_SETTING_CDMA = "bool_show_apn_setting_cdma";
+    public static final String BOOL_ALLOW_LOCAL_DTMF_TONES = "bool_allow_local_dtmf_tones";
+
+    /**
+     * If true, show an onscreen "Dial" button in the dialer. In practice this is used on all
+     * platforms, even the ones with hard SEND/END keys, but for maximum flexibility it's controlled
+     * by a flag here (which can be overridden on a per-product basis.)
+     */
+    public static final String BOOL_SHOW_ONSCREEN_DIAL_BUTTON = "bool_show_onscreen_dial_button";
+
+    /** Determines if device implements a noise suppression device for in call audio. */
+    public static final String
+            BOOL_HAS_IN_CALL_NOISE_SUPPRESSION = "bool_has_in_call_noise_suppression";
 
     /**
-     * Control whether users can edit APNs in Settings.
+     * Determines if the current device should allow emergency numbers to be logged in the Call Log.
+     * (Some carriers require that emergency calls *not* be logged, presumably to avoid the risk of
+     * accidental redialing from the call log UI. This is a good idea, so the default here is
+     * false.)
+     * <p>
+     * TODO: on the other hand, it might still be useful to have some record of the emergency calls
+     * you've made, or to be able to look up the exact date/time of an emergency call. So perhaps we
+     * <b>should</b> log those calls, but instead fix the call log to disable the "call" button for
+     * emergency numbers.
      */
+    public static final String
+            BOOL_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG = "bool_allow_emergency_numbers_in_call_log";
+
+    /** If true, removes the Voice Privacy option from Call Settings */
+    public static final String BOOL_VOICE_PRIVACY_DISABLE = "bool_voice_privacy_disable";
+
+    /** Control whether users can reach the carrier portions of Cellular Network Settings. */
+    public static final String
+            BOOL_HIDE_CARRIER_NETWORK_SETTINGS = "bool_hide_carrier_network_settings";
+
+    /** Control whether users can edit APNs in Settings. */
     public static final String BOOL_APN_EXPAND = "bool_apn_expand";
 
+    /** Control whether users can choose a network operator. */
+    public static final String BOOL_OPERATOR_SELECTION_EXPAND = "bool_operator_selection_expand";
+
+    /** Used in Cellular Network Settings for preferred network type. */
+    public static final String BOOL_PREFER_2G = "bool_prefer_2g";
+
+    /** Show cdma auto network mode in (glabal) roaming */
+    public static final String BOOL_SHOW_CDMA = "bool_show_cdma";
+
+    /** CDMA activation goes through HFA */
+    public static final String BOOL_USE_HFA_FOR_PROVISIONING = "bool_use_hfa_for_provisioning";
+
+    /**
+     * CDMA activation goes through OTASP.
+     * <p>
+     * TODO: This should be combined with config_use_hfa_for_provisioning and implemented as an enum
+     * (NONE, HFA, OTASP).
+     */
+    public static final String BOOL_USE_OTASP_FOR_PROVISIONING = "bool_use_otasp_for_provisioning";
+
+    /** Display carrier settings menu if true */
+    public static final String BOOL_CARRIER_SETTINGS_ENABLE = "bool_carrier_settings_enable";
+
+    /** Does not display additional call seting for IMS phone based on GSM Phone */
+    public static final String BOOL_ADDITIONAL_CALL_SETTING = "bool_additional_call_setting";
+
+    /** Show APN Settings for some CDMA carriers */
+    public static final String BOOL_SHOW_APN_SETTING_CDMA = "bool_show_apn_setting_cdma";
+
+    /** After a CDMA conference call is merged, the swap button should be displayed. */
+    public static final String BOOL_SUPPORT_SWAP_AFTER_MERGE = "bool_support_swap_after_merge";
+
+    /**
+     * Determine whether the voicemail notification is persistent in the notification bar. If true,
+     * the voicemail notifications cannot be dismissed from the notification bar.
+     */
+    public static final String
+            BOOL_VOICEMAIL_NOTIFICATION_PERSISTENT = "bool_voicemail_notification_persistent";
+
+    /** For IMS video over LTE calls, determines whether video pause signalling is supported. */
+    public static final String
+            BOOL_SUPPORT_PAUSE_IMS_VIDEO_CALLS = "bool_support_pause_ims_video_calls";
+
+    /**
+     * Disables dialing "*228" (OTASP provisioning) on CDMA carriers where it is not supported or is
+     * potentially harmful by locking the SIM to 3G.
+     */
+    public static final String
+            BOOL_DISABLE_CDMA_ACTIVATION_CODE = "bool_disable_cdma_activation_code";
+
+    /**
+     * Flag specifying whether VoLTE should be available for carrier, independent of carrier
+     * provisioning. If false: hard disabled. If true: then depends on carrier provisioning,
+     * availability, etc.
+     */
+    public static final String BOOL_CARRIER_VOLTE_AVAILABLE = "bool_carrier_volte_available";
+
+    /** Flag specifying whether VoLTE availability is based on provisioning. */
+    public static final String BOOL_CARRIER_VOLTE_PROVISIONED = "bool_carrier_volte_provisioned";
+
+    /** Flag specifying whether VoLTE TTY is supported. */
+    public static final String BOOL_CARRIER_VOLTE_TTY_SUPPORTED
+            = "bool_carrier_volte_tty_supported";
+
     /**
      * If Voice Radio Technology is RIL_RADIO_TECHNOLOGY_LTE:14 or RIL_RADIO_TECHNOLOGY_UNKNOWN:0
      * this is the value that should be used instead. A configuration value of
@@ -86,9 +200,9 @@ public class CarrierConfigManager {
     /* The following 3 fields are related to carrier visual voicemail. */
 
     /**
-     *  The carrier number MO sms messages are sent to.
+     * The carrier number MO sms messages are sent to.
      *
-     *  @hide
+     * @hide
      */
     public static final String STRING_VVM_DESTINATION_NUMBER = "string_vvm_destination_number";
 
@@ -122,17 +236,38 @@ public class CarrierConfigManager {
 
     static {
         sDefaults = new Bundle();
+        sDefaults.putBoolean(BOOL_ADDITIONAL_CALL_SETTING, true);
+        sDefaults.putBoolean(BOOL_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG, false);
+        sDefaults.putBoolean(BOOL_ALLOW_LOCAL_DTMF_TONES, true);
+        sDefaults.putBoolean(BOOL_APN_EXPAND, true);
+        sDefaults.putBoolean(BOOL_AUTO_RETRY_ENABLED, false);
+        sDefaults.putBoolean(BOOL_CARRIER_SETTINGS_ENABLE, false);
         sDefaults.putBoolean(BOOL_CARRIER_VOLTE_AVAILABLE, false);
         sDefaults.putBoolean(BOOL_CARRIER_VOLTE_PROVISIONED, false);
         sDefaults.putBoolean(BOOL_CARRIER_VOLTE_TTY_SUPPORTED, true);
+        sDefaults.putBoolean(BOOL_DISABLE_CDMA_ACTIVATION_CODE, false);
+        sDefaults.putBoolean(BOOL_DTMF_TYPE_ENABLED, false);
+        sDefaults.putBoolean(BOOL_ENABLE_DIALER_KEY_VIBRATION, true);
+        sDefaults.putBoolean(BOOL_HAS_IN_CALL_NOISE_SUPPRESSION, false);
+        sDefaults.putBoolean(BOOL_HIDE_CARRIER_NETWORK_SETTINGS, false);
+        sDefaults.putBoolean(BOOL_IGNORE_SIM_NETWORK_LOCKED_EVENTS, false);
+        sDefaults.putBoolean(BOOL_OPERATOR_SELECTION_EXPAND, true);
+        sDefaults.putBoolean(BOOL_PREFER_2G, true);
         sDefaults.putBoolean(BOOL_SHOW_APN_SETTING_CDMA, false);
-        sDefaults.putBoolean(BOOL_APN_EXPAND, true);
-
+        sDefaults.putBoolean(BOOL_SHOW_CDMA, false);
+        sDefaults.putBoolean(BOOL_SHOW_ONSCREEN_DIAL_BUTTON, true);
+        sDefaults.putBoolean(BOOL_SIM_NETWORK_UNLOCK_ALLOW_DISMISS, true);
+        sDefaults.putBoolean(BOOL_SUPPORT_PAUSE_IMS_VIDEO_CALLS, true);
+        sDefaults.putBoolean(BOOL_SUPPORT_SWAP_AFTER_MERGE, true);
+        sDefaults.putBoolean(BOOL_USE_HFA_FOR_PROVISIONING, false);
+        sDefaults.putBoolean(BOOL_USE_OTASP_FOR_PROVISIONING, false);
+        sDefaults.putBoolean(BOOL_VOICEMAIL_NOTIFICATION_PERSISTENT, false);
+        sDefaults.putBoolean(BOOL_VOICE_PRIVACY_DISABLE, false);
+        sDefaults.putBoolean(BOOL_WORLD_PHONE, false);
         sDefaults.putInt(INT_VOLTE_REPLACEMENT_RAT, 0);
-
+        sDefaults.putInt(INT_VVM_PORT_NUMBER, 0);
         sDefaults.putString(STRING_VVM_DESTINATION_NUMBER, "");
         sDefaults.putString(STRING_VVM_TYPE, "");
-        sDefaults.putInt(INT_VVM_PORT_NUMBER, 0);
     }
 
     /**
@@ -190,10 +325,11 @@ public class CarrierConfigManager {
 
     /**
      * Request the carrier config loader to update the cofig for phoneId.
-     *
-     * Depending on simState, the config may be cleared or loaded from config app.
-     * This is only used by SubscriptionInfoUpdater.
-     *
+     * <p>
+     * Depending on simState, the config may be cleared or loaded from config app. This is only used
+     * by SubscriptionInfoUpdater.
+     * </p>
+     * 
      * @hide
      */
     @SystemApi
index 322b853..30d204f 100644 (file)
@@ -52,6 +52,11 @@ public class ServiceManagerPermissionTests extends TestCase {
                 public boolean checkPermission(java.lang.String permission, int pid, int uid) {
                     return true;
                 }
+
+                @Override
+                public String[] getPackagesForUid(int uid) {
+                    return new String[0];
+                }
             };
             ServiceManagerNative.asInterface(BinderInternal.getContextObject())
                     .setPermissionController(pc);