diff options
34 files changed, 1163 insertions, 520 deletions
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index 50a597407e58..75b74913870f 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -6,4 +6,5 @@ checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPL packages/PrintSpooler/ services/print/ services/usb/ + telephony/ diff --git a/api/current.txt b/api/current.txt index 047a20e70aa9..603b6d4b32c4 100644 --- a/api/current.txt +++ b/api/current.txt @@ -7922,7 +7922,7 @@ package android.bluetooth { method public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices(); method public int getConnectionState(android.bluetooth.BluetoothDevice); method public java.util.List<android.bluetooth.BluetoothDevice> getDevicesMatchingConnectionStates(int[]); - method public boolean registerApp(android.bluetooth.BluetoothHidDeviceAppSdpSettings, android.bluetooth.BluetoothHidDeviceAppQosSettings, android.bluetooth.BluetoothHidDeviceAppQosSettings, android.bluetooth.BluetoothHidDeviceCallback); + method public boolean registerApp(android.bluetooth.BluetoothHidDeviceAppSdpSettings, android.bluetooth.BluetoothHidDeviceAppQosSettings, android.bluetooth.BluetoothHidDeviceAppQosSettings, java.util.concurrent.Executor, android.bluetooth.BluetoothHidDevice.Callback); method public boolean replyReport(android.bluetooth.BluetoothDevice, byte, byte, byte[]); method public boolean reportError(android.bluetooth.BluetoothDevice, byte); method public boolean sendReport(android.bluetooth.BluetoothDevice, int, byte[]); @@ -7952,56 +7952,44 @@ package android.bluetooth { field public static final byte SUBCLASS2_UNCATEGORIZED = 0; // 0x0 } + public static abstract class BluetoothHidDevice.Callback { + ctor public BluetoothHidDevice.Callback(); + method public void onAppStatusChanged(android.bluetooth.BluetoothDevice, boolean); + method public void onConnectionStateChanged(android.bluetooth.BluetoothDevice, int); + method public void onGetReport(android.bluetooth.BluetoothDevice, byte, byte, int); + method public void onInterruptData(android.bluetooth.BluetoothDevice, byte, byte[]); + method public void onSetProtocol(android.bluetooth.BluetoothDevice, byte); + method public void onSetReport(android.bluetooth.BluetoothDevice, byte, byte, byte[]); + method public void onVirtualCableUnplug(android.bluetooth.BluetoothDevice); + } + public final class BluetoothHidDeviceAppQosSettings implements android.os.Parcelable { ctor public BluetoothHidDeviceAppQosSettings(int, int, int, int, int, int); method public int describeContents(); - method public int[] toArray(); + method public int getDelayVariation(); + method public int getLatency(); + method public int getPeakBandwidth(); + method public int getServiceType(); + method public int getTokenBucketSize(); + method public int getTokenRate(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothHidDeviceAppQosSettings> CREATOR; field public static final int MAX = -1; // 0xffffffff field public static final int SERVICE_BEST_EFFORT = 1; // 0x1 field public static final int SERVICE_GUARANTEED = 2; // 0x2 field public static final int SERVICE_NO_TRAFFIC = 0; // 0x0 - field public final int delayVariation; - field public final int latency; - field public final int peakBandwidth; - field public final int serviceType; - field public final int tokenBucketSize; - field public final int tokenRate; - } - - public static class BluetoothHidDeviceAppQosSettings.Builder { - ctor public BluetoothHidDeviceAppQosSettings.Builder(); - method public android.bluetooth.BluetoothHidDeviceAppQosSettings build(); - method public android.bluetooth.BluetoothHidDeviceAppQosSettings.Builder delayVariation(int); - method public android.bluetooth.BluetoothHidDeviceAppQosSettings.Builder latency(int); - method public android.bluetooth.BluetoothHidDeviceAppQosSettings.Builder peakBandwidth(int); - method public android.bluetooth.BluetoothHidDeviceAppQosSettings.Builder serviceType(int); - method public android.bluetooth.BluetoothHidDeviceAppQosSettings.Builder tokenBucketSize(int); - method public android.bluetooth.BluetoothHidDeviceAppQosSettings.Builder tokenRate(int); } public final class BluetoothHidDeviceAppSdpSettings implements android.os.Parcelable { ctor public BluetoothHidDeviceAppSdpSettings(java.lang.String, java.lang.String, java.lang.String, byte, byte[]); method public int describeContents(); + method public java.lang.String getDescription(); + method public byte[] getDescriptors(); + method public java.lang.String getName(); + method public java.lang.String getProvider(); + method public byte getSubclass(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothHidDeviceAppSdpSettings> CREATOR; - field public final java.lang.String description; - field public final byte[] descriptors; - field public final java.lang.String name; - field public final java.lang.String provider; - field public final byte subclass; - } - - public abstract class BluetoothHidDeviceCallback { - ctor public BluetoothHidDeviceCallback(); - method public void onAppStatusChanged(android.bluetooth.BluetoothDevice, boolean); - method public void onConnectionStateChanged(android.bluetooth.BluetoothDevice, int); - method public void onGetReport(android.bluetooth.BluetoothDevice, byte, byte, int); - method public void onInterruptData(android.bluetooth.BluetoothDevice, byte, byte[]); - method public void onSetProtocol(android.bluetooth.BluetoothDevice, byte); - method public void onSetReport(android.bluetooth.BluetoothDevice, byte, byte, byte[]); - method public void onVirtualCableUnplug(android.bluetooth.BluetoothDevice); } public final class BluetoothManager { diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp index 1671337511b7..12083b6fe20b 100644 --- a/cmds/app_process/app_main.cpp +++ b/cmds/app_process/app_main.cpp @@ -13,6 +13,7 @@ #include <sys/stat.h> #include <unistd.h> +#include <android-base/macros.h> #include <binder/IPCThreadState.h> #include <hwbinder/IPCThreadState.h> #include <utils/Log.h> @@ -137,27 +138,12 @@ static size_t computeArgBlockSize(int argc, char* const argv[]) { } static void maybeCreateDalvikCache() { -#if defined(__aarch64__) - static const char kInstructionSet[] = "arm64"; -#elif defined(__x86_64__) - static const char kInstructionSet[] = "x86_64"; -#elif defined(__arm__) - static const char kInstructionSet[] = "arm"; -#elif defined(__i386__) - static const char kInstructionSet[] = "x86"; -#elif defined (__mips__) && !defined(__LP64__) - static const char kInstructionSet[] = "mips"; -#elif defined (__mips__) && defined(__LP64__) - static const char kInstructionSet[] = "mips64"; -#else -#error "Unknown instruction set" -#endif const char* androidRoot = getenv("ANDROID_DATA"); LOG_ALWAYS_FATAL_IF(androidRoot == NULL, "ANDROID_DATA environment variable unset"); char dalvikCacheDir[PATH_MAX]; const int numChars = snprintf(dalvikCacheDir, PATH_MAX, - "%s/dalvik-cache/%s", androidRoot, kInstructionSet); + "%s/dalvik-cache/" ABI_STRING, androidRoot); LOG_ALWAYS_FATAL_IF((numChars >= PATH_MAX || numChars < 0), "Error constructing dalvik cache : %s", strerror(errno)); diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java index 2fab305ba8bd..a3d6968e4c7a 100644 --- a/core/java/android/bluetooth/BluetoothHidDevice.java +++ b/core/java/android/bluetooth/BluetoothHidDevice.java @@ -27,8 +27,8 @@ import android.os.RemoteException; import android.util.Log; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; +import java.util.concurrent.Executor; /** * Provides the public APIs to control the Bluetooth HID Device profile. @@ -37,7 +37,6 @@ import java.util.List; * Use {@link BluetoothAdapter#getProfileProxy} to get the BluetoothHidDevice proxy object. */ public final class BluetoothHidDevice implements BluetoothProfile { - private static final String TAG = BluetoothHidDevice.class.getSimpleName(); /** @@ -62,106 +61,327 @@ public final class BluetoothHidDevice implements BluetoothProfile { "android.bluetooth.hiddevice.profile.action.CONNECTION_STATE_CHANGED"; /** - * Constants representing device subclass. + * Constant representing unspecified HID device subclass. * * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings, - * BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceCallback) + * BluetoothHidDeviceAppQosSettings, Executor, Callback) */ public static final byte SUBCLASS1_NONE = (byte) 0x00; + /** + * Constant representing keyboard subclass. + * + * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings, + * BluetoothHidDeviceAppQosSettings, Executor, Callback) + */ public static final byte SUBCLASS1_KEYBOARD = (byte) 0x40; + /** + * Constant representing mouse subclass. + * + * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings, + * BluetoothHidDeviceAppQosSettings, Executor, Callback) + */ public static final byte SUBCLASS1_MOUSE = (byte) 0x80; + /** + * Constant representing combo keyboard and mouse subclass. + * + * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings, + * BluetoothHidDeviceAppQosSettings, Executor, Callback) + */ public static final byte SUBCLASS1_COMBO = (byte) 0xC0; + /** + * Constant representing uncategorized HID device subclass. + * + * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings, + * BluetoothHidDeviceAppQosSettings, Executor, Callback) + */ public static final byte SUBCLASS2_UNCATEGORIZED = (byte) 0x00; + /** + * Constant representing joystick subclass. + * + * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings, + * BluetoothHidDeviceAppQosSettings, Executor, Callback) + */ public static final byte SUBCLASS2_JOYSTICK = (byte) 0x01; + /** + * Constant representing gamepad subclass. + * + * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings, + * BluetoothHidDeviceAppQosSettings, Executor, Callback) + */ public static final byte SUBCLASS2_GAMEPAD = (byte) 0x02; + /** + * Constant representing remote control subclass. + * + * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings, + * BluetoothHidDeviceAppQosSettings, Executor, Callback) + */ public static final byte SUBCLASS2_REMOTE_CONTROL = (byte) 0x03; + /** + * Constant representing sensing device subclass. + * + * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings, + * BluetoothHidDeviceAppQosSettings, Executor, Callback) + */ public static final byte SUBCLASS2_SENSING_DEVICE = (byte) 0x04; + /** + * Constant representing digitizer tablet subclass. + * + * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings, + * BluetoothHidDeviceAppQosSettings, Executor, Callback) + */ public static final byte SUBCLASS2_DIGITIZER_TABLET = (byte) 0x05; + /** + * Constant representing card reader subclass. + * + * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings, + * BluetoothHidDeviceAppQosSettings, Executor, Callback) + */ public static final byte SUBCLASS2_CARD_READER = (byte) 0x06; /** - * Constants representing report types. + * Constant representing HID Input Report type. * - * @see BluetoothHidDeviceCallback#onGetReport(BluetoothDevice, byte, byte, int) - * @see BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[]) - * @see BluetoothHidDeviceCallback#onInterruptData(BluetoothDevice, byte, byte[]) + * @see Callback#onGetReport(BluetoothDevice, byte, byte, int) + * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[]) + * @see Callback#onInterruptData(BluetoothDevice, byte, byte[]) */ public static final byte REPORT_TYPE_INPUT = (byte) 1; + /** + * Constant representing HID Output Report type. + * + * @see Callback#onGetReport(BluetoothDevice, byte, byte, int) + * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[]) + * @see Callback#onInterruptData(BluetoothDevice, byte, byte[]) + */ public static final byte REPORT_TYPE_OUTPUT = (byte) 2; + /** + * Constant representing HID Feature Report type. + * + * @see Callback#onGetReport(BluetoothDevice, byte, byte, int) + * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[]) + * @see Callback#onInterruptData(BluetoothDevice, byte, byte[]) + */ public static final byte REPORT_TYPE_FEATURE = (byte) 3; /** - * Constants representing error response for Set Report. + * Constant representing success response for Set Report. * - * @see BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[]) + * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[]) */ public static final byte ERROR_RSP_SUCCESS = (byte) 0; + /** + * Constant representing error response for Set Report due to "not ready". + * + * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[]) + */ public static final byte ERROR_RSP_NOT_READY = (byte) 1; + /** + * Constant representing error response for Set Report due to "invalid report ID". + * + * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[]) + */ public static final byte ERROR_RSP_INVALID_RPT_ID = (byte) 2; + /** + * Constant representing error response for Set Report due to "unsupported request". + * + * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[]) + */ public static final byte ERROR_RSP_UNSUPPORTED_REQ = (byte) 3; + /** + * Constant representing error response for Set Report due to "invalid parameter". + * + * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[]) + */ public static final byte ERROR_RSP_INVALID_PARAM = (byte) 4; + /** + * Constant representing error response for Set Report with unknown reason. + * + * @see Callback#onSetReport(BluetoothDevice, byte, byte, byte[]) + */ public static final byte ERROR_RSP_UNKNOWN = (byte) 14; /** - * Constants representing protocol mode used set by host. Default is always {@link + * Constant representing boot protocol mode used set by host. Default is always {@link * #PROTOCOL_REPORT_MODE} unless notified otherwise. * - * @see BluetoothHidDeviceCallback#onSetProtocol(BluetoothDevice, byte) + * @see Callback#onSetProtocol(BluetoothDevice, byte) */ public static final byte PROTOCOL_BOOT_MODE = (byte) 0; + /** + * Constant representing report protocol mode used set by host. Default is always {@link + * #PROTOCOL_REPORT_MODE} unless notified otherwise. + * + * @see Callback#onSetProtocol(BluetoothDevice, byte) + */ public static final byte PROTOCOL_REPORT_MODE = (byte) 1; - private Context mContext; + /** + * The template class that applications use to call callback functions on events from the HID + * host. Callback functions are wrapped in this class and registered to the Android system + * during app registration. + */ + public abstract static class Callback { + + private static final String TAG = "BluetoothHidDevCallback"; + + /** + * Callback called when application registration state changes. Usually it's called due to + * either {@link BluetoothHidDevice#registerApp (String, String, String, byte, byte[], + * Executor, Callback)} or {@link BluetoothHidDevice#unregisterApp()} , but can be also + * unsolicited in case e.g. Bluetooth was turned off in which case application is + * unregistered automatically. + * + * @param pluggedDevice {@link BluetoothDevice} object which represents host that currently + * has Virtual Cable established with device. Only valid when application is registered, + * can be <code>null</code>. + * @param registered <code>true</code> if application is registered, <code>false</code> + * otherwise. + */ + public void onAppStatusChanged(BluetoothDevice pluggedDevice, boolean registered) { + Log.d( + TAG, + "onAppStatusChanged: pluggedDevice=" + + pluggedDevice + + " registered=" + + registered); + } - private ServiceListener mServiceListener; + /** + * Callback called when connection state with remote host was changed. Application can + * assume than Virtual Cable is established when called with {@link + * BluetoothProfile#STATE_CONNECTED} <code>state</code>. + * + * @param device {@link BluetoothDevice} object representing host device which connection + * state was changed. + * @param state Connection state as defined in {@link BluetoothProfile}. + */ + public void onConnectionStateChanged(BluetoothDevice device, int state) { + Log.d(TAG, "onConnectionStateChanged: device=" + device + " state=" + state); + } - private volatile IBluetoothHidDevice mService; + /** + * Callback called when GET_REPORT is received from remote host. Should be replied by + * application using {@link BluetoothHidDevice#replyReport(BluetoothDevice, byte, byte, + * byte[])}. + * + * @param type Requested Report Type. + * @param id Requested Report Id, can be 0 if no Report Id are defined in descriptor. + * @param bufferSize Requested buffer size, application shall respond with at least given + * number of bytes. + */ + public void onGetReport(BluetoothDevice device, byte type, byte id, int bufferSize) { + Log.d( + TAG, + "onGetReport: device=" + + device + + " type=" + + type + + " id=" + + id + + " bufferSize=" + + bufferSize); + } + + /** + * Callback called when SET_REPORT is received from remote host. In case received data are + * invalid, application shall respond with {@link + * BluetoothHidDevice#reportError(BluetoothDevice, byte)}. + * + * @param type Report Type. + * @param id Report Id. + * @param data Report data. + */ + public void onSetReport(BluetoothDevice device, byte type, byte id, byte[] data) { + Log.d(TAG, "onSetReport: device=" + device + " type=" + type + " id=" + id); + } + + /** + * Callback called when SET_PROTOCOL is received from remote host. Application shall use + * this information to send only reports valid for given protocol mode. By default, {@link + * BluetoothHidDevice#PROTOCOL_REPORT_MODE} shall be assumed. + * + * @param protocol Protocol Mode. + */ + public void onSetProtocol(BluetoothDevice device, byte protocol) { + Log.d(TAG, "onSetProtocol: device=" + device + " protocol=" + protocol); + } + /** + * Callback called when report data is received over interrupt channel. Report Type is + * assumed to be {@link BluetoothHidDevice#REPORT_TYPE_OUTPUT}. + * + * @param reportId Report Id. + * @param data Report data. + */ + public void onInterruptData(BluetoothDevice device, byte reportId, byte[] data) { + Log.d(TAG, "onInterruptData: device=" + device + " reportId=" + reportId); + } + + /** + * Callback called when Virtual Cable is removed. After this callback is received connection + * will be disconnected automatically. + */ + public void onVirtualCableUnplug(BluetoothDevice device) { + Log.d(TAG, "onVirtualCableUnplug: device=" + device); + } + } + + private Context mContext; + private ServiceListener mServiceListener; + private volatile IBluetoothHidDevice mService; private BluetoothAdapter mAdapter; - private static class BluetoothHidDeviceCallbackWrapper - extends IBluetoothHidDeviceCallback.Stub { + private static class CallbackWrapper extends IBluetoothHidDeviceCallback.Stub { - private BluetoothHidDeviceCallback mCallback; + private final Executor mExecutor; + private final Callback mCallback; - public BluetoothHidDeviceCallbackWrapper(BluetoothHidDeviceCallback callback) { + CallbackWrapper(Executor executor, Callback callback) { + mExecutor = executor; mCallback = callback; } @Override public void onAppStatusChanged(BluetoothDevice pluggedDevice, boolean registered) { - mCallback.onAppStatusChanged(pluggedDevice, registered); + clearCallingIdentity(); + mExecutor.execute(() -> mCallback.onAppStatusChanged(pluggedDevice, registered)); } @Override public void onConnectionStateChanged(BluetoothDevice device, int state) { - mCallback.onConnectionStateChanged(device, state); + clearCallingIdentity(); + mExecutor.execute(() -> mCallback.onConnectionStateChanged(device, state)); } @Override public void onGetReport(BluetoothDevice device, byte type, byte id, int bufferSize) { - mCallback.onGetReport(device, type, id, bufferSize); + clearCallingIdentity(); + mExecutor.execute(() -> mCallback.onGetReport(device, type, id, bufferSize)); } @Override public void onSetReport(BluetoothDevice device, byte type, byte id, byte[] data) { - mCallback.onSetReport(device, type, id, data); + clearCallingIdentity(); + mExecutor.execute(() -> mCallback.onSetReport(device, type, id, data)); } @Override public void onSetProtocol(BluetoothDevice device, byte protocol) { - mCallback.onSetProtocol(device, protocol); + clearCallingIdentity(); + mExecutor.execute(() -> mCallback.onSetProtocol(device, protocol)); } @Override public void onInterruptData(BluetoothDevice device, byte reportId, byte[] data) { - mCallback.onInterruptData(device, reportId, data); + clearCallingIdentity(); + mExecutor.execute(() -> mCallback.onInterruptData(device, reportId, data)); } @Override public void onVirtualCableUnplug(BluetoothDevice device) { - mCallback.onVirtualCableUnplug(device); + clearCallingIdentity(); + mExecutor.execute(() -> mCallback.onVirtualCableUnplug(device)); } } @@ -213,8 +433,6 @@ public final class BluetoothHidDevice implements BluetoothProfile { }; BluetoothHidDevice(Context context, ServiceListener listener) { - Log.v(TAG, "BluetoothHidDevice"); - mContext = context; mServiceListener = listener; mAdapter = BluetoothAdapter.getDefaultAdapter(); @@ -245,7 +463,6 @@ public final class BluetoothHidDevice implements BluetoothProfile { } void doUnbind() { - Log.d(TAG, "Unbinding HidDevService"); if (mService != null) { mService = null; try { @@ -257,8 +474,6 @@ public final class BluetoothHidDevice implements BluetoothProfile { } void close() { - Log.v(TAG, "close()"); - IBluetoothManager mgr = mAdapter.getBluetoothManager(); if (mgr != null) { try { @@ -277,8 +492,6 @@ public final class BluetoothHidDevice implements BluetoothProfile { /** {@inheritDoc} */ @Override public List<BluetoothDevice> getConnectedDevices() { - Log.v(TAG, "getConnectedDevices()"); - final IBluetoothHidDevice service = mService; if (service != null) { try { @@ -290,14 +503,12 @@ public final class BluetoothHidDevice implements BluetoothProfile { Log.w(TAG, "Proxy not attached to service"); } - return new ArrayList<BluetoothDevice>(); + return new ArrayList<>(); } /** {@inheritDoc} */ @Override public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { - Log.v(TAG, "getDevicesMatchingConnectionStates(): states=" + Arrays.toString(states)); - final IBluetoothHidDevice service = mService; if (service != null) { try { @@ -309,14 +520,12 @@ public final class BluetoothHidDevice implements BluetoothProfile { Log.w(TAG, "Proxy not attached to service"); } - return new ArrayList<BluetoothDevice>(); + return new ArrayList<>(); } /** {@inheritDoc} */ @Override public int getConnectionState(BluetoothDevice device) { - Log.v(TAG, "getConnectionState(): device=" + device); - final IBluetoothHidDevice service = mService; if (service != null) { try { @@ -336,9 +545,9 @@ public final class BluetoothHidDevice implements BluetoothProfile { * when application is registered. Only one application can be registered at one time. When an * application is registered, the HID Host service will be disabled until it is unregistered. * When no longer used, application should be unregistered using {@link #unregisterApp()}. The - * registration status should be tracked by the application by handling callback from - * BluetoothHidDeviceCallback#onAppStatusChanged. The app registration status is not related to - * the return value of this method. + * app will be automatically unregistered if it is not foreground. The registration status + * should be tracked by the application by handling callback from Callback#onAppStatusChanged. + * The app registration status is not related to the return value of this method. * * @param sdp {@link BluetoothHidDeviceAppSdpSettings} object of HID Device SDP record. The HID * Device SDP record is required. @@ -348,27 +557,36 @@ public final class BluetoothHidDevice implements BluetoothProfile { * @param outQos {@link BluetoothHidDeviceAppQosSettings} object of Outgoing QoS Settings. The * Outgoing QoS Settings is not required. Use null or default * BluetoothHidDeviceAppQosSettings.Builder for default values. - * @param callback {@link BluetoothHidDeviceCallback} object to which callback messages will be - * sent. The BluetoothHidDeviceCallback object is required. + * @param executor {@link Executor} object on which callback will be executed. The Executor + * object is required. + * @param callback {@link Callback} object to which callback messages will be sent. The Callback + * object is required. * @return true if the command is successfully sent; otherwise false. */ - public boolean registerApp(BluetoothHidDeviceAppSdpSettings sdp, - BluetoothHidDeviceAppQosSettings inQos, BluetoothHidDeviceAppQosSettings outQos, - BluetoothHidDeviceCallback callback) { - Log.v(TAG, "registerApp(): sdp=" + sdp + " inQos=" + inQos + " outQos=" + outQos - + " callback=" + callback); - + public boolean registerApp( + BluetoothHidDeviceAppSdpSettings sdp, + BluetoothHidDeviceAppQosSettings inQos, + BluetoothHidDeviceAppQosSettings outQos, + Executor executor, + Callback callback) { boolean result = false; - if (sdp == null || callback == null) { - return false; + if (sdp == null) { + throw new IllegalArgumentException("sdp parameter cannot be null"); + } + + if (executor == null) { + throw new IllegalArgumentException("executor parameter cannot be null"); + } + + if (callback == null) { + throw new IllegalArgumentException("callback parameter cannot be null"); } final IBluetoothHidDevice service = mService; if (service != null) { try { - BluetoothHidDeviceCallbackWrapper cbw = - new BluetoothHidDeviceCallbackWrapper(callback); + CallbackWrapper cbw = new CallbackWrapper(executor, callback); result = service.registerApp(sdp, inQos, outQos, cbw); } catch (RemoteException e) { Log.e(TAG, e.toString()); @@ -384,16 +602,13 @@ public final class BluetoothHidDevice implements BluetoothProfile { * Unregisters application. Active connection will be disconnected and no new connections will * be allowed until registered again using {@link #registerApp * (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings, - * BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceCallback)} The registration status should - * be tracked by the application by handling callback from - * BluetoothHidDeviceCallback#onAppStatusChanged. The app registration status is not related to - * the return value of this method. + * BluetoothHidDeviceAppQosSettings, Executor, Callback)}. The registration status should be + * tracked by the application by handling callback from Callback#onAppStatusChanged. The app + * registration status is not related to the return value of this method. * * @return true if the command is successfully sent; otherwise false. */ public boolean unregisterApp() { - Log.v(TAG, "unregisterApp()"); - boolean result = false; final IBluetoothHidDevice service = mService; @@ -437,7 +652,7 @@ public final class BluetoothHidDevice implements BluetoothProfile { /** * Sends report to remote host as reply for GET_REPORT request from {@link - * BluetoothHidDeviceCallback#onGetReport(BluetoothDevice, byte, byte, int)}. + * Callback#onGetReport(BluetoothDevice, byte, byte, int)}. * * @param type Report Type, as in request. * @param id Report Id, as in request. @@ -445,8 +660,6 @@ public final class BluetoothHidDevice implements BluetoothProfile { * @return true if the command is successfully sent; otherwise false. */ public boolean replyReport(BluetoothDevice device, byte type, byte id, byte[] data) { - Log.v(TAG, "replyReport(): device=" + device + " type=" + type + " id=" + id); - boolean result = false; final IBluetoothHidDevice service = mService; @@ -465,14 +678,12 @@ public final class BluetoothHidDevice implements BluetoothProfile { /** * Sends error handshake message as reply for invalid SET_REPORT request from {@link - * BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[])}. + * Callback#onSetReport(BluetoothDevice, byte, byte, byte[])}. * * @param error Error to be sent for SET_REPORT via HANDSHAKE. * @return true if the command is successfully sent; otherwise false. */ public boolean reportError(BluetoothDevice device, byte error) { - Log.v(TAG, "reportError(): device=" + device + " error=" + error); - boolean result = false; final IBluetoothHidDevice service = mService; @@ -496,8 +707,6 @@ public final class BluetoothHidDevice implements BluetoothProfile { * {@hide} */ public boolean unplug(BluetoothDevice device) { - Log.v(TAG, "unplug(): device=" + device); - boolean result = false; final IBluetoothHidDevice service = mService; @@ -517,15 +726,12 @@ public final class BluetoothHidDevice implements BluetoothProfile { /** * Initiates connection to host which is currently paired with this device. If the application * is not registered, #connect(BluetoothDevice) will fail. The connection state should be - * tracked by the application by handling callback from - * BluetoothHidDeviceCallback#onConnectionStateChanged. The connection state is not related to - * the return value of this method. + * tracked by the application by handling callback from Callback#onConnectionStateChanged. The + * connection state is not related to the return value of this method. * * @return true if the command is successfully sent; otherwise false. */ public boolean connect(BluetoothDevice device) { - Log.v(TAG, "connect(): device=" + device); - boolean result = false; final IBluetoothHidDevice service = mService; @@ -544,14 +750,12 @@ public final class BluetoothHidDevice implements BluetoothProfile { /** * Disconnects from currently connected host. The connection state should be tracked by the - * application by handling callback from BluetoothHidDeviceCallback#onConnectionStateChanged. - * The connection state is not related to the return value of this method. + * application by handling callback from Callback#onConnectionStateChanged. The connection state + * is not related to the return value of this method. * * @return true if the command is successfully sent; otherwise false. */ public boolean disconnect(BluetoothDevice device) { - Log.v(TAG, "disconnect(): device=" + device); - boolean result = false; final IBluetoothHidDevice service = mService; diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java index c05df2d23e45..a485b898c2d4 100644 --- a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java +++ b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java @@ -29,12 +29,12 @@ import android.os.Parcelable; */ public final class BluetoothHidDeviceAppQosSettings implements Parcelable { - public final int serviceType; - public final int tokenRate; - public final int tokenBucketSize; - public final int peakBandwidth; - public final int latency; - public final int delayVariation; + private final int mServiceType; + private final int mTokenRate; + private final int mTokenBucketSize; + private final int mPeakBandwidth; + private final int mLatency; + private final int mDelayVariation; public static final int SERVICE_NO_TRAFFIC = 0x00; public static final int SERVICE_BEST_EFFORT = 0x01; @@ -44,38 +44,53 @@ public final class BluetoothHidDeviceAppQosSettings implements Parcelable { /** * Create a BluetoothHidDeviceAppQosSettings object for the Bluetooth L2CAP channel. The QoS - * Settings is optional. Recommended to use BluetoothHidDeviceAppQosSettings.Builder. - * Please refer to Bluetooth HID Specfication v1.1.1 Section 5.2 and Appendix D for parameters. + * Settings is optional. Please refer to Bluetooth HID Specfication v1.1.1 Section 5.2 and + * Appendix D for parameters. * - * @param serviceType L2CAP service type - * @param tokenRate L2CAP token rate - * @param tokenBucketSize L2CAP token bucket size - * @param peakBandwidth L2CAP peak bandwidth - * @param latency L2CAP latency - * @param delayVariation L2CAP delay variation + * @param serviceType L2CAP service type, default = SERVICE_BEST_EFFORT + * @param tokenRate L2CAP token rate, default = 0 + * @param tokenBucketSize L2CAP token bucket size, default = 0 + * @param peakBandwidth L2CAP peak bandwidth, default = 0 + * @param latency L2CAP latency, default = MAX + * @param delayVariation L2CAP delay variation, default = MAX */ - public BluetoothHidDeviceAppQosSettings(int serviceType, int tokenRate, int tokenBucketSize, - int peakBandwidth, int latency, int delayVariation) { - this.serviceType = serviceType; - this.tokenRate = tokenRate; - this.tokenBucketSize = tokenBucketSize; - this.peakBandwidth = peakBandwidth; - this.latency = latency; - this.delayVariation = delayVariation; + public BluetoothHidDeviceAppQosSettings( + int serviceType, + int tokenRate, + int tokenBucketSize, + int peakBandwidth, + int latency, + int delayVariation) { + mServiceType = serviceType; + mTokenRate = tokenRate; + mTokenBucketSize = tokenBucketSize; + mPeakBandwidth = peakBandwidth; + mLatency = latency; + mDelayVariation = delayVariation; } - @Override - public boolean equals(Object o) { - if (o instanceof BluetoothHidDeviceAppQosSettings) { - BluetoothHidDeviceAppQosSettings qos = (BluetoothHidDeviceAppQosSettings) o; - return this.serviceType == qos.serviceType - && this.tokenRate == qos.tokenRate - && this.tokenBucketSize == qos.tokenBucketSize - && this.peakBandwidth == qos.peakBandwidth - && this.latency == qos.latency - && this.delayVariation == qos.delayVariation; - } - return false; + public int getServiceType() { + return mServiceType; + } + + public int getTokenRate() { + return mTokenRate; + } + + public int getTokenBucketSize() { + return mTokenBucketSize; + } + + public int getPeakBandwidth() { + return mPeakBandwidth; + } + + public int getLatency() { + return mLatency; + } + + public int getDelayVariation() { + return mDelayVariation; } @Override @@ -106,104 +121,11 @@ public final class BluetoothHidDeviceAppQosSettings implements Parcelable { @Override public void writeToParcel(Parcel out, int flags) { - out.writeInt(serviceType); - out.writeInt(tokenRate); - out.writeInt(tokenBucketSize); - out.writeInt(peakBandwidth); - out.writeInt(latency); - out.writeInt(delayVariation); - } - - /** @return an int array representation of this instance */ - public int[] toArray() { - return new int[] { - serviceType, tokenRate, tokenBucketSize, peakBandwidth, latency, delayVariation - }; - } - - /** A helper to build the BluetoothHidDeviceAppQosSettings object. */ - public static class Builder { - // Optional parameters - initialized to default values - private int mServiceType = SERVICE_BEST_EFFORT; - private int mTokenRate = 0; - private int mTokenBucketSize = 0; - private int mPeakBandwidth = 0; - private int mLatency = MAX; - private int mDelayVariation = MAX; - - /** - * Set the service type. - * - * @param val service type. Should be one of {SERVICE_NO_TRAFFIC, SERVICE_BEST_EFFORT, - * SERVICE_GUARANTEED}, with SERVICE_BEST_EFFORT being the default one. - * @return BluetoothHidDeviceAppQosSettings Builder with specified service type. - */ - public Builder serviceType(int val) { - mServiceType = val; - return this; - } - /** - * Set the token rate. - * - * @param val token rate - * @return BluetoothHidDeviceAppQosSettings Builder with specified token rate. - */ - public Builder tokenRate(int val) { - mTokenRate = val; - return this; - } - - /** - * Set the bucket size. - * - * @param val bucket size - * @return BluetoothHidDeviceAppQosSettings Builder with specified bucket size. - */ - public Builder tokenBucketSize(int val) { - mTokenBucketSize = val; - return this; - } - - /** - * Set the peak bandwidth. - * - * @param val peak bandwidth - * @return BluetoothHidDeviceAppQosSettings Builder with specified peak bandwidth. - */ - public Builder peakBandwidth(int val) { - mPeakBandwidth = val; - return this; - } - /** - * Set the latency. - * - * @param val latency - * @return BluetoothHidDeviceAppQosSettings Builder with specified latency. - */ - public Builder latency(int val) { - mLatency = val; - return this; - } - - /** - * Set the delay variation. - * - * @param val delay variation - * @return BluetoothHidDeviceAppQosSettings Builder with specified delay variation. - */ - public Builder delayVariation(int val) { - mDelayVariation = val; - return this; - } - - /** - * Build the BluetoothHidDeviceAppQosSettings object. - * - * @return BluetoothHidDeviceAppQosSettings object with current settings. - */ - public BluetoothHidDeviceAppQosSettings build() { - return new BluetoothHidDeviceAppQosSettings(mServiceType, mTokenRate, mTokenBucketSize, - mPeakBandwidth, mLatency, mDelayVariation); - } + out.writeInt(mServiceType); + out.writeInt(mTokenRate); + out.writeInt(mTokenBucketSize); + out.writeInt(mPeakBandwidth); + out.writeInt(mLatency); + out.writeInt(mDelayVariation); } } diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java index 562c559eddc4..237082e4cb66 100644 --- a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java +++ b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java @@ -19,7 +19,6 @@ package android.bluetooth; import android.os.Parcel; import android.os.Parcelable; -import java.util.Arrays; /** * Represents the Service Discovery Protocol (SDP) settings for a Bluetooth HID Device application. @@ -31,11 +30,11 @@ import java.util.Arrays; */ public final class BluetoothHidDeviceAppSdpSettings implements Parcelable { - public final String name; - public final String description; - public final String provider; - public final byte subclass; - public final byte[] descriptors; + private final String mName; + private final String mDescription; + private final String mProvider; + private final byte mSubclass; + private final byte[] mDescriptors; /** * Create a BluetoothHidDeviceAppSdpSettings object for the Bluetooth SDP record. @@ -52,24 +51,31 @@ public final class BluetoothHidDeviceAppSdpSettings implements Parcelable { */ public BluetoothHidDeviceAppSdpSettings( String name, String description, String provider, byte subclass, byte[] descriptors) { - this.name = name; - this.description = description; - this.provider = provider; - this.subclass = subclass; - this.descriptors = descriptors.clone(); + mName = name; + mDescription = description; + mProvider = provider; + mSubclass = subclass; + mDescriptors = descriptors.clone(); } - @Override - public boolean equals(Object o) { - if (o instanceof BluetoothHidDeviceAppSdpSettings) { - BluetoothHidDeviceAppSdpSettings sdp = (BluetoothHidDeviceAppSdpSettings) o; - return this.name.equals(sdp.name) - && this.description.equals(sdp.description) - && this.provider.equals(sdp.provider) - && this.subclass == sdp.subclass - && Arrays.equals(this.descriptors, sdp.descriptors); - } - return false; + public String getName() { + return mName; + } + + public String getDescription() { + return mDescription; + } + + public String getProvider() { + return mProvider; + } + + public byte getSubclass() { + return mSubclass; + } + + public byte[] getDescriptors() { + return mDescriptors; } @Override @@ -99,10 +105,10 @@ public final class BluetoothHidDeviceAppSdpSettings implements Parcelable { @Override public void writeToParcel(Parcel out, int flags) { - out.writeString(name); - out.writeString(description); - out.writeString(provider); - out.writeByte(subclass); - out.writeByteArray(descriptors); + out.writeString(mName); + out.writeString(mDescription); + out.writeString(mProvider); + out.writeByte(mSubclass); + out.writeByteArray(mDescriptors); } } diff --git a/core/java/android/bluetooth/BluetoothHidDeviceCallback.java b/core/java/android/bluetooth/BluetoothHidDeviceCallback.java deleted file mode 100644 index e71b00f2349f..000000000000 --- a/core/java/android/bluetooth/BluetoothHidDeviceCallback.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2016 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.bluetooth; - -import android.util.Log; - -/** - * The template class that applications use to call callback functions on events from the HID host. - * Callback functions are wrapped in this class and registered to the Android system during app - * registration. - * - * <p>{@see BluetoothHidDevice} - */ -public abstract class BluetoothHidDeviceCallback { - - private static final String TAG = "BluetoothHidDevCallback"; - - /** - * Callback called when application registration state changes. Usually it's called due to - * either {@link BluetoothHidDevice#registerApp (String, String, String, byte, byte[], - * BluetoothHidDeviceCallback)} or {@link BluetoothHidDevice#unregisterApp()} , but can be also - * unsolicited in case e.g. Bluetooth was turned off in which case application is unregistered - * automatically. - * - * @param pluggedDevice {@link BluetoothDevice} object which represents host that currently has - * Virtual Cable established with device. Only valid when application is registered, can be - * <code>null</code>. - * @param registered <code>true</code> if application is registered, <code>false</code> - * otherwise. - */ - public void onAppStatusChanged(BluetoothDevice pluggedDevice, boolean registered) { - Log.d(TAG, - "onAppStatusChanged: pluggedDevice=" + pluggedDevice + " registered=" + registered); - } - - /** - * Callback called when connection state with remote host was changed. Application can assume - * than Virtual Cable is established when called with {@link BluetoothProfile#STATE_CONNECTED} - * <code>state</code>. - * - * @param device {@link BluetoothDevice} object representing host device which connection state - * was changed. - * @param state Connection state as defined in {@link BluetoothProfile}. - */ - public void onConnectionStateChanged(BluetoothDevice device, int state) { - Log.d(TAG, "onConnectionStateChanged: device=" + device + " state=" + state); - } - - /** - * Callback called when GET_REPORT is received from remote host. Should be replied by - * application using {@link BluetoothHidDevice#replyReport(BluetoothDevice, byte, byte, - * byte[])}. - * - * @param type Requested Report Type. - * @param id Requested Report Id, can be 0 if no Report Id are defined in descriptor. - * @param bufferSize Requested buffer size, application shall respond with at least given number - * of bytes. - */ - public void onGetReport(BluetoothDevice device, byte type, byte id, int bufferSize) { - Log.d(TAG, "onGetReport: device=" + device + " type=" + type + " id=" + id + " bufferSize=" - + bufferSize); - } - - /** - * Callback called when SET_REPORT is received from remote host. In case received data are - * invalid, application shall respond with {@link - * BluetoothHidDevice#reportError(BluetoothDevice, byte)}. - * - * @param type Report Type. - * @param id Report Id. - * @param data Report data. - */ - public void onSetReport(BluetoothDevice device, byte type, byte id, byte[] data) { - Log.d(TAG, "onSetReport: device=" + device + " type=" + type + " id=" + id); - } - - /** - * Callback called when SET_PROTOCOL is received from remote host. Application shall use this - * information to send only reports valid for given protocol mode. By default, {@link - * BluetoothHidDevice#PROTOCOL_REPORT_MODE} shall be assumed. - * - * @param protocol Protocol Mode. - */ - public void onSetProtocol(BluetoothDevice device, byte protocol) { - Log.d(TAG, "onSetProtocol: device=" + device + " protocol=" + protocol); - } - - /** - * Callback called when report data is received over interrupt channel. Report Type is assumed - * to be {@link BluetoothHidDevice#REPORT_TYPE_OUTPUT}. - * - * @param reportId Report Id. - * @param data Report data. - */ - public void onInterruptData(BluetoothDevice device, byte reportId, byte[] data) { - Log.d(TAG, "onInterruptData: device=" + device + " reportId=" + reportId); - } - - /** - * Callback called when Virtual Cable is removed. After this callback is - * received connection will be disconnected automatically. - */ - public void onVirtualCableUnplug(BluetoothDevice device) { - Log.d(TAG, "onVirtualCableUnplug: device=" + device); - } -} diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index 8ea81a4aa99b..ebc88ff7116b 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -1046,6 +1046,58 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { /** @hide */ public String[] splitClassLoaderNames; + /** + * Represents the default policy. The actual policy used will depend on other properties of + * the application, e.g. the target SDK version. + * @hide + */ + public static final int HIDDEN_API_ENFORCEMENT_DEFAULT = -1; + /** + * No API enforcement; the app can access the entire internal private API. Only for use by + * system apps. + * @hide + */ + public static final int HIDDEN_API_ENFORCEMENT_NONE = 0; + /** + * Light grey list enforcement, the strictest option. Enforces the light grey, dark grey and + * black lists. + * @hide + * */ + public static final int HIDDEN_API_ENFORCEMENT_ALL_LISTS = 1; + /** + * Dark grey list enforcement. Enforces the dark grey and black lists + * @hide + */ + public static final int HIDDEN_API_ENFORCEMENT_DARK_GREY_AND_BLACK = 2; + /** + * Blacklist enforcement only. + * @hide + */ + public static final int HIDDEN_API_ENFORCEMENT_BLACK = 3; + + private static final int HIDDEN_API_ENFORCEMENT_MAX = HIDDEN_API_ENFORCEMENT_BLACK; + + /** + * Values in this IntDef MUST be kept in sync with enum hiddenapi::EnforcementPolicy in + * art/runtime/hidden_api.h + * @hide + */ + @IntDef(prefix = { "HIDDEN_API_ENFORCEMENT_" }, value = { + HIDDEN_API_ENFORCEMENT_DEFAULT, + HIDDEN_API_ENFORCEMENT_NONE, + HIDDEN_API_ENFORCEMENT_ALL_LISTS, + HIDDEN_API_ENFORCEMENT_DARK_GREY_AND_BLACK, + HIDDEN_API_ENFORCEMENT_BLACK, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface HiddenApiEnforcementPolicy {} + + private boolean isValidHiddenApiEnforcementPolicy(int policy) { + return policy >= HIDDEN_API_ENFORCEMENT_DEFAULT && policy <= HIDDEN_API_ENFORCEMENT_MAX; + } + + private int mHiddenApiPolicy = HIDDEN_API_ENFORCEMENT_DEFAULT; + public void dump(Printer pw, String prefix) { dump(pw, prefix, DUMP_FLAG_ALL); } @@ -1133,6 +1185,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { if (category != CATEGORY_UNDEFINED) { pw.println(prefix + "category=" + category); } + pw.println(prefix + "HiddenApiEnforcementPolicy=" + getHiddenApiEnforcementPolicy()); } super.dumpBack(pw, prefix); } @@ -1228,6 +1281,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { targetSandboxVersion = orig.targetSandboxVersion; classLoaderName = orig.classLoaderName; splitClassLoaderNames = orig.splitClassLoaderNames; + mHiddenApiPolicy = orig.mHiddenApiPolicy; } public String toString() { @@ -1298,6 +1352,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeInt(targetSandboxVersion); dest.writeString(classLoaderName); dest.writeStringArray(splitClassLoaderNames); + dest.writeInt(mHiddenApiPolicy); } public static final Parcelable.Creator<ApplicationInfo> CREATOR @@ -1365,6 +1420,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { targetSandboxVersion = source.readInt(); classLoaderName = source.readString(); splitClassLoaderNames = source.readStringArray(); + mHiddenApiPolicy = source.readInt(); } /** @@ -1456,14 +1512,31 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { } } + private boolean isPackageWhitelistedForHiddenApis() { + return SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains(packageName); + } + /** * @hide */ - public boolean isAllowedToUseHiddenApi() { - boolean whitelisted = - SystemConfig.getInstance().getHiddenApiWhitelistedApps().contains(packageName); - return isSystemApp() || // TODO get rid of this once the whitelist has been populated - (whitelisted && (isSystemApp() || isUpdatedSystemApp())); + public @HiddenApiEnforcementPolicy int getHiddenApiEnforcementPolicy() { + if (mHiddenApiPolicy != HIDDEN_API_ENFORCEMENT_DEFAULT) { + return mHiddenApiPolicy; + } + if (isPackageWhitelistedForHiddenApis() && (isSystemApp() || isUpdatedSystemApp())) { + return HIDDEN_API_ENFORCEMENT_NONE; + } + return HIDDEN_API_ENFORCEMENT_BLACK; + } + + /** + * @hide + */ + public void setHiddenApiEnforcementPolicy(@HiddenApiEnforcementPolicy int policy) { + if (!isValidHiddenApiEnforcementPolicy(policy)) { + throw new IllegalArgumentException("Invalid API enforcement policy: " + policy); + } + mHiddenApiPolicy = policy; } /** diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index f136e276a1c4..9d518e9e00fa 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1977,13 +1977,6 @@ public class ConnectivityManager { * services.jar, possibly in com.android.server.net. */ /** {@hide} */ - public static final boolean checkChangePermission(Context context) { - int uid = Binder.getCallingUid(); - return Settings.checkAndNoteChangeNetworkStateOperation(context, uid, Settings - .getPackageNameForUid(context, uid), false /* throwException */); - } - - /** {@hide} */ public static final void enforceChangePermission(Context context) { int uid = Binder.getCallingUid(); Settings.checkAndNoteChangeNetworkStateOperation(context, uid, Settings diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 90e3ffd550b4..eab70418a959 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -44,6 +44,16 @@ interface INetworkStatsService { /** Return data layer snapshot of UID network usage. */ NetworkStats getDataLayerSnapshotForUid(int uid); + + /** Get a detailed snapshot of stats since boot for all UIDs. + * + * <p>Results will not always be limited to stats on requiredIfaces when specified: stats for + * interfaces stacked on the specified interfaces, or for interfaces on which the specified + * interfaces are stacked on, will also be included. + * @param requiredIfaces Interface names to get data for, or {@link NetworkStats#INTERFACES_ALL}. + */ + NetworkStats getDetailedUidStats(in String[] requiredIfaces); + /** Return set of any ifaces associated with mobile networks since boot. */ String[] getMobileIfaces(); diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index 96826f800066..1ee0ed7d90fc 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -23,6 +23,7 @@ import android.os.Process; import android.text.TextUtils; import java.util.Objects; +import java.util.Set; /** * Defines a request for a network, made through {@link NetworkRequest.Builder} and used @@ -204,6 +205,19 @@ public class NetworkRequest implements Parcelable { } /** + * Set the watched UIDs for this request. This will be reset and wiped out unless + * the calling app holds the CHANGE_NETWORK_STATE permission. + * + * @param uids The watched UIDs as a set of UidRanges, or null for everything. + * @return The builder to facilitate chaining. + * @hide + */ + public Builder setUids(Set<UidRange> uids) { + mNetworkCapabilities.setUids(uids); + return this; + } + + /** * Add a capability that must not exist in the requested network. * <p> * If the capability was previously added to the list of required capabilities (for diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 01b2b39213f9..940f98580c39 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -64,6 +64,9 @@ public class NetworkStats implements Parcelable { /** Debug {@link #set} value when the VPN stats are moved out of a vpn UID. */ public static final int SET_DBG_VPN_OUT = 1002; + /** Include all interfaces when filtering */ + public static final String[] INTERFACES_ALL = null; + /** {@link #tag} value for total data across all tags. */ // TODO: Rename TAG_NONE to TAG_ALL. public static final int TAG_NONE = 0; @@ -359,23 +362,27 @@ public class NetworkStats implements Parcelable { capacity = newLength; } - iface[size] = entry.iface; - uid[size] = entry.uid; - set[size] = entry.set; - tag[size] = entry.tag; - metered[size] = entry.metered; - roaming[size] = entry.roaming; - defaultNetwork[size] = entry.defaultNetwork; - rxBytes[size] = entry.rxBytes; - rxPackets[size] = entry.rxPackets; - txBytes[size] = entry.txBytes; - txPackets[size] = entry.txPackets; - operations[size] = entry.operations; + setValues(size, entry); size++; return this; } + private void setValues(int i, Entry entry) { + iface[i] = entry.iface; + uid[i] = entry.uid; + set[i] = entry.set; + tag[i] = entry.tag; + metered[i] = entry.metered; + roaming[i] = entry.roaming; + defaultNetwork[i] = entry.defaultNetwork; + rxBytes[i] = entry.rxBytes; + rxPackets[i] = entry.rxPackets; + txBytes[i] = entry.txBytes; + txPackets[i] = entry.txPackets; + operations[i] = entry.operations; + } + /** * Return specific stats entry. */ @@ -824,6 +831,39 @@ public class NetworkStats implements Parcelable { return stats; } + /** + * Only keep entries that match all specified filters. + * + * <p>This mutates the original structure in place. After this method is called, + * size is the number of matching entries, and capacity is the previous capacity. + * @param limitUid UID to filter for, or {@link #UID_ALL}. + * @param limitIfaces Interfaces to filter for, or {@link #INTERFACES_ALL}. + * @param limitTag Tag to filter for, or {@link #TAG_ALL}. + */ + public void filter(int limitUid, String[] limitIfaces, int limitTag) { + if (limitUid == UID_ALL && limitTag == TAG_ALL && limitIfaces == INTERFACES_ALL) { + return; + } + + Entry entry = new Entry(); + int nextOutputEntry = 0; + for (int i = 0; i < size; i++) { + entry = getValues(i, entry); + final boolean matches = + (limitUid == UID_ALL || limitUid == entry.uid) + && (limitTag == TAG_ALL || limitTag == entry.tag) + && (limitIfaces == INTERFACES_ALL + || ArrayUtils.contains(limitIfaces, entry.iface)); + + if (matches) { + setValues(nextOutputEntry, entry); + nextOutputEntry++; + } + } + + size = nextOutputEntry; + } + public void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime); diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index 2437ed1b6d61..31dbafad62e3 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -268,10 +268,12 @@ interface INetworkManagementService NetworkStats getNetworkStatsDetail(); /** - * Return detailed network statistics for the requested UID, + * Return detailed network statistics for the requested UID and interfaces, * including interface and tag details. + * @param uid UID to obtain statistics for, or {@link NetworkStats#UID_ALL}. + * @param ifaces Interfaces to obtain statistics for, or {@link NetworkStats#INTERFACES_ALL}. */ - NetworkStats getNetworkStatsUidDetail(int uid); + NetworkStats getNetworkStatsUidDetail(int uid, in String[] ifaces); /** * Return summary of network statistics all tethering interfaces. diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index 902bd120e811..8172a206321d 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -22,16 +22,14 @@ import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static com.android.server.NetworkManagementSocketTagger.kernelToTag; +import android.annotation.Nullable; import android.net.NetworkStats; import android.os.StrictMode; import android.os.SystemClock; -import android.util.ArrayMap; -import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ProcFileReader; -import com.google.android.collect.Lists; import libcore.io.IoUtils; @@ -41,8 +39,10 @@ import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.net.ProtocolException; -import java.util.ArrayList; -import java.util.Objects; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; /** * Creates {@link NetworkStats} instances by parsing various {@code /proc/} @@ -70,18 +70,55 @@ public class NetworkStatsFactory { private boolean mUseBpfStats; - // TODO: to improve testability and avoid global state, do not use a static variable. - @GuardedBy("sStackedIfaces") - private static final ArrayMap<String, String> sStackedIfaces = new ArrayMap<>(); + // TODO: only do adjustments in NetworkStatsService and remove this. + /** + * (Stacked interface) -> (base interface) association for all connected ifaces since boot. + * + * Because counters must never roll backwards, once a given interface is stacked on top of an + * underlying interface, the stacked interface can never be stacked on top of + * another interface. */ + private static final ConcurrentHashMap<String, String> sStackedIfaces + = new ConcurrentHashMap<>(); public static void noteStackedIface(String stackedIface, String baseIface) { - synchronized (sStackedIfaces) { - if (baseIface != null) { - sStackedIfaces.put(stackedIface, baseIface); - } else { - sStackedIfaces.remove(stackedIface); + if (stackedIface != null && baseIface != null) { + sStackedIfaces.put(stackedIface, baseIface); + } + } + + /** + * Get a set of interfaces containing specified ifaces and stacked interfaces. + * + * <p>The added stacked interfaces are ifaces stacked on top of the specified ones, or ifaces + * on which the specified ones are stacked. Stacked interfaces are those noted with + * {@link #noteStackedIface(String, String)}, but only interfaces noted before this method + * is called are guaranteed to be included. + */ + public static String[] augmentWithStackedInterfacesLocked(@Nullable String[] requiredIfaces) { + if (requiredIfaces == NetworkStats.INTERFACES_ALL) { + return null; + } + + HashSet<String> relatedIfaces = new HashSet<>(Arrays.asList(requiredIfaces)); + // ConcurrentHashMap's EntrySet iterators are "guaranteed to traverse + // elements as they existed upon construction exactly once, and may + // (but are not guaranteed to) reflect any modifications subsequent to construction". + // This is enough here. + for (Map.Entry<String, String> entry : sStackedIfaces.entrySet()) { + if (relatedIfaces.contains(entry.getKey())) { + relatedIfaces.add(entry.getValue()); + } else if (relatedIfaces.contains(entry.getValue())) { + relatedIfaces.add(entry.getKey()); } } + + String[] outArray = new String[relatedIfaces.size()]; + return relatedIfaces.toArray(outArray); + } + + @VisibleForTesting + public static void clearStackedIfaces() { + sStackedIfaces.clear(); } public NetworkStatsFactory() { @@ -250,12 +287,9 @@ public class NetworkStatsFactory { NetworkStats lastStats) throws IOException { final NetworkStats stats = readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag, lastStats); - final ArrayMap<String, String> stackedIfaces; - synchronized (sStackedIfaces) { - stackedIfaces = new ArrayMap<>(sStackedIfaces); - } // Total 464xlat traffic to subtract from uid 0 on all base interfaces. - final NetworkStats adjustments = new NetworkStats(0, stackedIfaces.size()); + // sStackedIfaces may grow afterwards, but NetworkStats will just be resized automatically. + final NetworkStats adjustments = new NetworkStats(0, sStackedIfaces.size()); NetworkStats.Entry entry = null; // For recycling @@ -269,7 +303,7 @@ public class NetworkStatsFactory { if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) { continue; } - final String baseIface = stackedIfaces.get(entry.iface); + final String baseIface = sStackedIfaces.get(entry.iface); if (baseIface == null) { continue; } diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java index 49010802c784..f0e779694c90 100644 --- a/core/java/com/android/internal/os/WrapperInit.java +++ b/core/java/com/android/internal/os/WrapperInit.java @@ -115,6 +115,14 @@ public class WrapperInit { command.append(' '); command.append(appProcess); + // Generate bare minimum of debug information to be able to backtrace through JITed code. + // We assume that if the invoke wrapper is used, backtraces are desirable: + // * The wrap.sh script can only be used by debuggable apps, which would enable this flag + // without the script anyway (the fork-zygote path). So this makes the two consistent. + // * The wrap.* property can only be used on userdebug builds and is likely to be used by + // developers (e.g. enable debug-malloc), in which case backtraces are also useful. + command.append(" -Xcompiler-option --generate-mini-debug-info"); + command.append(" /system/bin --application"); if (niceName != null) { command.append(" '--nice-name=").append(niceName).append("'"); diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index e23cbf815b87..0d1088896f40 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -55,10 +55,21 @@ public final class Zygote { public static final int DISABLE_VERIFIER = 1 << 9; /** Only use oat files located in /system. Otherwise use dex/jar/apk . */ public static final int ONLY_USE_SYSTEM_OAT_FILES = 1 << 10; - /** Do enfore hidden API access restrictions. */ - public static final int ENABLE_HIDDEN_API_CHECKS = 1 << 11; /** Force generation of native debugging information for backtraces. */ - public static final int DEBUG_GENERATE_MINI_DEBUG_INFO = 1 << 12; + public static final int DEBUG_GENERATE_MINI_DEBUG_INFO = 1 << 11; + /** + * Hidden API access restrictions. This is a mask for bits representing the API enforcement + * policy, defined by {@code @ApplicationInfo.HiddenApiEnforcementPolicy}. + */ + public static final int API_ENFORCEMENT_POLICY_MASK = (1 << 12) | (1 << 13); + /** + * Bit shift for use with {@link #API_ENFORCEMENT_POLICY_MASK}. + * + * (flags & API_ENFORCEMENT_POLICY_MASK) >> API_ENFORCEMENT_POLICY_SHIFT gives + * @ApplicationInfo.ApiEnforcementPolicy values. + */ + public static final int API_ENFORCEMENT_POLICY_SHIFT = + Integer.numberOfTrailingZeros(API_ENFORCEMENT_POLICY_MASK); /** No external storage should be mounted. */ public static final int MOUNT_EXTERNAL_NONE = 0; diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 3784d4daa2e9..6c46cfc751b0 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -20,6 +20,7 @@ #include <android_runtime/AndroidRuntime.h> +#include <android-base/macros.h> #include <android-base/properties.h> #include <binder/IBinder.h> #include <binder/IPCThreadState.h> @@ -860,34 +861,18 @@ int AndroidRuntime::startVm(JavaVM** pJavaVM, JNIEnv** pEnv, bool zygote) // The runtime will compile a boot image, when necessary, not using installd. Thus, we need to // pass the instruction-set-features/variant as an image-compiler-option. - // TODO: Find a better way for the instruction-set. -#if defined(__arm__) - constexpr const char* instruction_set = "arm"; -#elif defined(__aarch64__) - constexpr const char* instruction_set = "arm64"; -#elif defined(__mips__) && !defined(__LP64__) - constexpr const char* instruction_set = "mips"; -#elif defined(__mips__) && defined(__LP64__) - constexpr const char* instruction_set = "mips64"; -#elif defined(__i386__) - constexpr const char* instruction_set = "x86"; -#elif defined(__x86_64__) - constexpr const char* instruction_set = "x86_64"; -#else - constexpr const char* instruction_set = "unknown"; -#endif // Note: it is OK to reuse the buffer, as the values are exactly the same between // * compiler-option, used for runtime compilation (DexClassLoader) // * image-compiler-option, used for boot-image compilation on device // Copy the variant. - sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", instruction_set); + sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", ABI_STRING); parseCompilerOption(dex2oat_isa_variant_key, dex2oat_isa_variant, "--instruction-set-variant=", "-Ximage-compiler-option"); parseCompilerOption(dex2oat_isa_variant_key, dex2oat_isa_variant, "--instruction-set-variant=", "-Xcompiler-option"); // Copy the features. - sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", instruction_set); + sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", ABI_STRING); parseCompilerOption(dex2oat_isa_features_key, dex2oat_isa_features, "--instruction-set-features=", "-Ximage-compiler-option"); parseCompilerOption(dex2oat_isa_features_key, dex2oat_isa_features, diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 210625cfef14..9e38efe8f060 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -149,6 +149,9 @@ <!-- Notification content to tell the user that voice/data/emergency service is blocked by access control. --> <string name="RestrictedStateContent">Temporarily turned off by your carrier</string> + <!-- Notification content to tell the user that voice/data/emergency service is blocked by access control when multiple SIMs are active. --> + <string name="RestrictedStateContentMsimTemplate">Temporarily turned off by your carrier for SIM <xliff:g id="simNumber" example="1">%d</xliff:g></string> + <!-- Displayed to tell the user that they should switch their network preference. --> <string name="NetworkPreferenceSwitchTitle">Can\u2019t reach mobile network</string> <!-- Displayed to tell the user that they should switch their network preference. --> @@ -215,14 +218,14 @@ <string name="roamingTextSearching">Searching for Service</string> <!-- Displayed when WFC registration fails --> - <string name="wfcRegErrorTitle">Wi-Fi Calling</string> + <string name="wfcRegErrorTitle">Couldn\u2019t set up Wi\u2011Fi calling</string> <!-- WFC Operator Error Messages showed as alerts --> <string-array name="wfcOperatorErrorAlertMessages"> <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings. (Error code: <xliff:g id="code" example="REG09 - No 911 Address">%1$s</xliff:g>)</item> </string-array> <!-- WFC Operator Error Messages showed as notifications --> <string-array name="wfcOperatorErrorNotificationMessages"> - <item>Register with your carrier (Error code: <xliff:g id="code" example="REG09 - No 911 Address">%1$s</xliff:g>)</item> + <item>Issue registering Wi\u2011Fi calling with your carrier: <xliff:g id="code" example="REG09 - No 911 Address">%1$s</xliff:g></item> </string-array> <!-- Template for showing mobile network operator name while WFC is active --> <string-array name="wfcSpnFormats"> @@ -4688,6 +4691,12 @@ <string name="mmcc_illegal_ms">SIM not allowed for voice</string> <string name="mmcc_illegal_me">Phone not allowed for voice</string> + <!-- Title of notification when UE fails to register network with MM reject cause code when multiple SIMs are active. --> + <string name="mmcc_authentication_reject_msim_template">SIM <xliff:g id="simNumber" example="1">%d</xliff:g> not allowed</string> + <string name="mmcc_imsi_unknown_in_hlr_msim_template">SIM <xliff:g id="simNumber" example="1">%d</xliff:g> not provisioned</string> + <string name="mmcc_illegal_ms_msim_template">SIM <xliff:g id="simNumber" example="1">%d</xliff:g> not allowed</string> + <string name="mmcc_illegal_me_msim_template">SIM <xliff:g id="simNumber" example="1">%d</xliff:g> not allowed</string> + <!-- Popup window default title to be read by a screen reader--> <string name="popup_window_default_title">Popup Window</string> </resources> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index f089ff0ddb6d..e52f0f818636 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -547,6 +547,7 @@ <java-symbol type="string" name="RestrictedOnEmergencyTitle" /> <java-symbol type="string" name="RestrictedOnNormalTitle" /> <java-symbol type="string" name="RestrictedStateContent" /> + <java-symbol type="string" name="RestrictedStateContentMsimTemplate" /> <java-symbol type="string" name="notification_channel_network_alert" /> <java-symbol type="string" name="notification_channel_call_forward" /> <java-symbol type="string" name="notification_channel_emergency_callback" /> @@ -1956,6 +1957,10 @@ <java-symbol type="string" name="mmcc_imsi_unknown_in_hlr" /> <java-symbol type="string" name="mmcc_illegal_ms" /> <java-symbol type="string" name="mmcc_illegal_me" /> + <java-symbol type="string" name="mmcc_authentication_reject_msim_template" /> + <java-symbol type="string" name="mmcc_imsi_unknown_in_hlr_msim_template" /> + <java-symbol type="string" name="mmcc_illegal_ms_msim_template" /> + <java-symbol type="string" name="mmcc_illegal_me_msim_template" /> <java-symbol type="string" name="notification_listener_binding_label" /> <java-symbol type="string" name="vr_listener_binding_label" /> <java-symbol type="string" name="condition_provider_service_binding_label" /> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java index b22ce1822acd..0adb4392a174 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java @@ -64,6 +64,7 @@ public class SecurityControllerImpl extends CurrentUserTracker implements Securi .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) .removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED) + .setUids(null) .build(); private static final int NO_NETWORK = -1; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java index 7ca9d73a230e..f76de5a03d2d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java @@ -19,11 +19,15 @@ package com.android.systemui.statusbar.policy; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.argThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import android.app.admin.DevicePolicyManager; import android.content.ComponentName; @@ -32,6 +36,9 @@ import android.content.Intent; import android.content.pm.StringParceledListSlice; import android.content.pm.UserInfo; import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; +import android.net.NetworkCapabilities; +import android.net.NetworkRequest; import android.os.UserManager; import android.security.IKeyChainService; import android.support.test.runner.AndroidJUnit4; @@ -61,6 +68,7 @@ public class SecurityControllerTest extends SysuiTestCase implements SecurityCon private final UserManager mUserManager = mock(UserManager.class); private SecurityControllerImpl mSecurityController; private CountDownLatch mStateChangedLatch; + private ConnectivityManager mConnectivityManager = mock(ConnectivityManager.class); // implementing SecurityControllerCallback @Override @@ -72,7 +80,7 @@ public class SecurityControllerTest extends SysuiTestCase implements SecurityCon public void setUp() throws Exception { mContext.addMockSystemService(Context.DEVICE_POLICY_SERVICE, mDevicePolicyManager); mContext.addMockSystemService(Context.USER_SERVICE, mUserManager); - mContext.addMockSystemService(Context.CONNECTIVITY_SERVICE, mock(ConnectivityManager.class)); + mContext.addMockSystemService(Context.CONNECTIVITY_SERVICE, mConnectivityManager); Intent intent = new Intent(IKeyChainService.class.getName()); ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0); @@ -176,4 +184,12 @@ public class SecurityControllerTest extends SysuiTestCase implements SecurityCon //assertTrue(mStateChangedLatch.await(31, TimeUnit.SECONDS)); //assertFalse(mSecurityController.hasCACertInCurrentUser()); } + + @Test + public void testNetworkRequest() { + verify(mConnectivityManager, times(1)).registerNetworkCallback(argThat( + (NetworkRequest request) -> request.networkCapabilities.getUids() == null + && request.networkCapabilities.getCapabilities().length == 0 + ), any(NetworkCallback.class)); + } } diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index a7515e52d5ab..6494a81d9ddf 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -60,6 +60,7 @@ import android.os.UserManagerInternal.UserRestrictionsListener; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.util.Slog; +import android.util.StatsLog; import com.android.internal.R; import com.android.internal.util.DumpUtils; @@ -2145,6 +2146,11 @@ class BluetoothManagerService extends IBluetoothManager.Stub { mActiveLogs.add( new ActiveLog(reason, packageName, enable, System.currentTimeMillis())); } + + int state = enable ? StatsLog.BLUETOOTH_ENABLED_STATE_CHANGED__STATE__ENABLED : + StatsLog.BLUETOOTH_ENABLED_STATE_CHANGED__STATE__DISABLED; + StatsLog.write_non_chained(StatsLog.BLUETOOTH_ENABLED_STATE_CHANGED, + Binder.getCallingUid(), null, state, reason, packageName); } private void addCrashLog() { diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 9bf00494adf4..ae7ac8f04165 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1356,6 +1356,12 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + private void restrictBackgroundRequestForCaller(NetworkCapabilities nc) { + if (!mPermissionMonitor.hasUseBackgroundNetworksPermission(Binder.getCallingUid())) { + nc.addCapability(NET_CAPABILITY_FOREGROUND); + } + } + @Override public NetworkState[] getAllNetworkState() { // Require internal since we're handing out IMSI details @@ -4365,15 +4371,13 @@ public class ConnectivityService extends IConnectivityManager.Stub NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities); restrictRequestUidsForCaller(nc); - if (!ConnectivityManager.checkChangePermission(mContext)) { - // Apps without the CHANGE_NETWORK_STATE permission can't use background networks, so - // make all their listens include NET_CAPABILITY_FOREGROUND. That way, they will get - // onLost and onAvailable callbacks when networks move in and out of the background. - // There is no need to do this for requests because an app without CHANGE_NETWORK_STATE - // can't request networks. - nc.addCapability(NET_CAPABILITY_FOREGROUND); - } - ensureValidNetworkSpecifier(networkCapabilities); + // Apps without the CHANGE_NETWORK_STATE permission can't use background networks, so + // make all their listens include NET_CAPABILITY_FOREGROUND. That way, they will get + // onLost and onAvailable callbacks when networks move in and out of the background. + // There is no need to do this for requests because an app without CHANGE_NETWORK_STATE + // can't request networks. + restrictBackgroundRequestForCaller(nc); + ensureValidNetworkSpecifier(nc); NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(), NetworkRequest.Type.LISTEN); @@ -5268,7 +5272,6 @@ public class ConnectivityService extends IConnectivityManager.Stub for (LinkProperties stacked : newNetwork.linkProperties.getStackedLinks()) { final String stackedIface = stacked.getInterfaceName(); bs.noteNetworkInterfaceType(stackedIface, type); - NetworkStatsFactory.noteStackedIface(stackedIface, baseIface); } } catch (RemoteException ignored) { } diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 478953f8ffdf..5d719ad46a05 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -1867,10 +1867,10 @@ public class NetworkManagementService extends INetworkManagementService.Stub } @Override - public NetworkStats getNetworkStatsUidDetail(int uid) { + public NetworkStats getNetworkStatsUidDetail(int uid, String[] ifaces) { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); try { - return mStatsFactory.readNetworkStatsDetail(uid, null, TAG_ALL, null); + return mStatsFactory.readNetworkStatsDetail(uid, ifaces, TAG_ALL, null); } catch (IOException e) { throw new IllegalStateException(e); } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 8731cdad69c5..4f24d9f82418 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -257,6 +257,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; +import android.content.pm.ApplicationInfo.HiddenApiEnforcementPolicy; import android.content.pm.ConfigurationInfo; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageManager; @@ -3944,12 +3945,14 @@ public class ActivityManagerService extends IActivityManager.Stub runtimeFlags |= Zygote.ONLY_USE_SYSTEM_OAT_FILES; } - if (!app.info.isAllowedToUseHiddenApi() && - !disableHiddenApiChecks && - !mHiddenApiBlacklist.isDisabled()) { - // This app is not allowed to use undocumented and private APIs, or blacklisting is - // enabled. Set up its runtime with the appropriate flag. - runtimeFlags |= Zygote.ENABLE_HIDDEN_API_CHECKS; + if (!disableHiddenApiChecks && !mHiddenApiBlacklist.isDisabled()) { + @HiddenApiEnforcementPolicy int policy = + app.info.getHiddenApiEnforcementPolicy(); + int policyBits = (policy << Zygote.API_ENFORCEMENT_POLICY_SHIFT); + if ((policyBits & Zygote.API_ENFORCEMENT_POLICY_MASK) != policyBits) { + throw new IllegalStateException("Invalid API policy: " + policy); + } + runtimeFlags |= policyBits; } String invokeWith = null; @@ -5678,15 +5681,16 @@ public class ActivityManagerService extends IActivityManager.Stub * since it's the system_server that creates trace files for most ANRs. */ private static void maybePruneOldTraces(File tracesDir) { - final long now = System.currentTimeMillis(); - final File[] traceFiles = tracesDir.listFiles(); + final File[] files = tracesDir.listFiles(); + if (files == null) return; - if (traceFiles != null) { - for (File file : traceFiles) { - if ((now - file.lastModified()) > DAY_IN_MILLIS) { - if (!file.delete()) { - Slog.w(TAG, "Unable to prune stale trace file: " + file); - } + final int max = SystemProperties.getInt("tombstoned.max_anr_count", 64); + final long now = System.currentTimeMillis(); + Arrays.sort(files, Comparator.comparingLong(File::lastModified).reversed()); + for (int i = 0; i < files.length; ++i) { + if (i > max || (now - files[i].lastModified()) > DAY_IN_MILLIS) { + if (!files[i].delete()) { + Slog.w(TAG, "Unable to prune stale trace file: " + files[i]); } } } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 9e37c78017e5..5573cd99fbaa 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -684,6 +684,14 @@ public class AudioService extends IAudioService.Stub int maxCallVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps", -1); if (maxCallVolume != -1) { MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxCallVolume; + } + + int defaultCallVolume = SystemProperties.getInt("ro.config.vc_call_vol_default", -1); + if (defaultCallVolume != -1 && + defaultCallVolume <= MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] && + defaultCallVolume >= MIN_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) { + AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = defaultCallVolume; + } else { AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = (maxCallVolume * 3) / 4; } @@ -695,7 +703,8 @@ public class AudioService extends IAudioService.Stub int defaultMusicVolume = SystemProperties.getInt("ro.config.media_vol_default", -1); if (defaultMusicVolume != -1 && - defaultMusicVolume <= MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) { + defaultMusicVolume <= MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] && + defaultMusicVolume >= MIN_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) { AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = defaultMusicVolume; } else { if (isPlatformTelevision()) { diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java index e084ff827c09..d578e959314e 100644 --- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java +++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java @@ -19,6 +19,7 @@ package com.android.server.connectivity; import static android.Manifest.permission.CHANGE_NETWORK_STATE; import static android.Manifest.permission.CONNECTIVITY_INTERNAL; import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS; +import static android.Manifest.permission.NETWORK_STACK; import static android.content.pm.ApplicationInfo.FLAG_SYSTEM; import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; import static android.content.pm.PackageManager.GET_PERMISSIONS; @@ -27,6 +28,7 @@ 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.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; @@ -39,6 +41,8 @@ import android.os.UserManager; import android.text.TextUtils; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; + import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -150,7 +154,14 @@ public class PermissionMonitor { update(mUsers, mApps, true); } - private boolean hasPermission(PackageInfo app, String permission) { + @VisibleForTesting + boolean isPreinstalledSystemApp(PackageInfo app) { + int flags = app.applicationInfo != null ? app.applicationInfo.flags : 0; + return (flags & (FLAG_SYSTEM | FLAG_UPDATED_SYSTEM_APP)) != 0; + } + + @VisibleForTesting + boolean hasPermission(PackageInfo app, String permission) { if (app.requestedPermissions != null) { for (String p : app.requestedPermissions) { if (permission.equals(p)) { @@ -166,14 +177,40 @@ public class PermissionMonitor { } private boolean hasRestrictedNetworkPermission(PackageInfo app) { - int flags = app.applicationInfo != null ? app.applicationInfo.flags : 0; - if ((flags & FLAG_SYSTEM) != 0 || (flags & FLAG_UPDATED_SYSTEM_APP) != 0) { - return true; - } + if (isPreinstalledSystemApp(app)) return true; return hasPermission(app, CONNECTIVITY_INTERNAL) || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS); } + private boolean hasUseBackgroundNetworksPermission(PackageInfo app) { + // This function defines what it means to hold the permission to use + // background networks. + return hasPermission(app, CHANGE_NETWORK_STATE) + || hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS) + || hasPermission(app, CONNECTIVITY_INTERNAL) + || hasPermission(app, NETWORK_STACK) + // TODO : remove this check (b/31479477). Not all preinstalled apps should + // have access to background networks, they should just request the appropriate + // permission for their use case from the list above. + || isPreinstalledSystemApp(app); + } + + public boolean hasUseBackgroundNetworksPermission(int uid) { + final String[] names = mPackageManager.getPackagesForUid(uid); + if (null == names || names.length == 0) return false; + try { + // Only using the first package name. There may be multiple names if multiple + // apps share the same UID, but in that case they also share permissions so + // querying with any of the names will return the same results. + final PackageInfo app = mPackageManager.getPackageInfo(names[0], GET_PERMISSIONS); + return hasUseBackgroundNetworksPermission(app); + } catch (NameNotFoundException e) { + // App not found. + loge("NameNotFoundException " + names[0], e); + return false; + } + } + private int[] toIntArray(List<Integer> list) { int[] array = new int[list.size()]; for (int i = 0; i < list.size(); i++) { @@ -308,4 +345,8 @@ public class PermissionMonitor { private static void loge(String s) { Log.e(TAG, s); } + + private static void loge(String s, Throwable e) { + Log.e(TAG, s, e); + } } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 82981275fca1..e0a86437e0f8 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -27,6 +27,7 @@ import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.isNetworkTypeMobile; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.INTERFACES_ALL; import static android.net.NetworkStats.METERED_ALL; import static android.net.NetworkStats.ROAMING_ALL; import static android.net.NetworkStats.SET_ALL; @@ -34,6 +35,7 @@ import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.SET_FOREGROUND; import static android.net.NetworkStats.STATS_PER_IFACE; import static android.net.NetworkStats.STATS_PER_UID; +import static android.net.NetworkStats.TAG_ALL; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkStatsHistory.FIELD_ALL; @@ -128,6 +130,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.net.NetworkStatsFactory; import com.android.internal.net.VpnInfo; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; @@ -143,6 +146,7 @@ import java.io.PrintWriter; import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.Map; /** * Collect and persist detailed network statistics, and provide this data to @@ -726,7 +730,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final long token = Binder.clearCallingIdentity(); final NetworkStats networkLayer; try { - networkLayer = mNetworkManager.getNetworkStatsUidDetail(uid); + networkLayer = mNetworkManager.getNetworkStatsUidDetail(uid, + NetworkStats.INTERFACES_ALL); } finally { Binder.restoreCallingIdentity(token); } @@ -748,6 +753,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override + public NetworkStats getDetailedUidStats(String[] requiredIfaces) { + try { + final String[] ifacesToQuery = + NetworkStatsFactory.augmentWithStackedInterfacesLocked(requiredIfaces); + return getNetworkStatsUidDetail(ifacesToQuery); + } catch (RemoteException e) { + Log.wtf(TAG, "Error compiling UID stats", e); + return new NetworkStats(0L, 0); + } + } + + @Override public String[] getMobileIfaces() { return mMobileIfaces; } @@ -1109,6 +1126,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (isMobile) { mobileIfaces.add(stackedIface); } + + NetworkStatsFactory.noteStackedIface(stackedIface, baseIface); } } } @@ -1130,7 +1149,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void recordSnapshotLocked(long currentTime) throws RemoteException { // snapshot and record current counters; read UID stats first to // avoid over counting dev stats. - final NetworkStats uidSnapshot = getNetworkStatsUidDetail(); + final NetworkStats uidSnapshot = getNetworkStatsUidDetail(INTERFACES_ALL); final NetworkStats xtSnapshot = getNetworkStatsXt(); final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev(); @@ -1464,12 +1483,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Return snapshot of current UID statistics, including any * {@link TrafficStats#UID_TETHERING}, video calling data usage, and {@link #mUidOperations} * values. + * + * @param ifaces A list of interfaces the stats should be restricted to, or + * {@link NetworkStats#INTERFACES_ALL}. */ - private NetworkStats getNetworkStatsUidDetail() throws RemoteException { - final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); + private NetworkStats getNetworkStatsUidDetail(String[] ifaces) + throws RemoteException { + + final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL, + ifaces); // fold tethering stats and operations into uid snapshot final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID); + tetherSnapshot.filter(UID_ALL, ifaces, TAG_ALL); uidSnapshot.combineAllValues(tetherSnapshot); final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService( @@ -1478,10 +1504,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // fold video calling data usage stats into uid snapshot final NetworkStats vtStats = telephonyManager.getVtDataUsage(STATS_PER_UID); if (vtStats != null) { + vtStats.filter(UID_ALL, ifaces, TAG_ALL); uidSnapshot.combineAllValues(vtStats); } + uidSnapshot.combineAllValues(mUidOperations); + // TODO: apply tethering & VC 464xlat adjustments here + return uidSnapshot; } diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index 5ea778b838a7..ae4884472522 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -47,6 +47,8 @@ import java.util.Map; import dalvik.system.DexFile; +import static android.content.pm.ApplicationInfo.HIDDEN_API_ENFORCEMENT_NONE; + import static com.android.server.pm.Installer.DEXOPT_BOOTCOMPLETE; import static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE; import static com.android.server.pm.Installer.DEXOPT_PROFILE_GUIDED; @@ -532,7 +534,10 @@ public class PackageDexOptimizer { int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0; // Some apps are executed with restrictions on hidden API usage. If this app is one // of them, pass a flag to dexopt to enable the same restrictions during compilation. - int hiddenApiFlag = info.isAllowedToUseHiddenApi() ? 0 : DEXOPT_ENABLE_HIDDEN_API_CHECKS; + // TODO we should pass the actual flag value to dexopt, rather than assuming blacklist + int hiddenApiFlag = info.getHiddenApiEnforcementPolicy() == HIDDEN_API_ENFORCEMENT_NONE + ? 0 + : DEXOPT_ENABLE_HIDDEN_API_CHECKS; // Avoid generating CompactDex for modes that are latency critical. final int compilationReason = options.getCompilationReason(); boolean generateCompactDex = true; diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 9c831b9be0dd..e971d08aae7a 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -17,7 +17,6 @@ package android.telephony; import android.annotation.IntDef; -import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; import android.os.Bundle; @@ -496,9 +495,8 @@ public class ServiceState implements Parcelable { * * @return Current serving cell bandwidths */ - @Nullable public int[] getCellBandwidths() { - return mCellBandwidths; + return mCellBandwidths == null ? new int[0] : mCellBandwidths; } /** diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java index 035a4cd7601a..0530a86f4e25 100644 --- a/tests/net/java/android/net/NetworkStatsTest.java +++ b/tests/net/java/android/net/NetworkStatsTest.java @@ -19,6 +19,7 @@ package android.net; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.DEFAULT_NETWORK_NO; import static android.net.NetworkStats.DEFAULT_NETWORK_YES; +import static android.net.NetworkStats.INTERFACES_ALL; import static android.net.NetworkStats.METERED_ALL; import static android.net.NetworkStats.METERED_NO; import static android.net.NetworkStats.METERED_YES; @@ -31,6 +32,7 @@ import static android.net.NetworkStats.SET_DBG_VPN_IN; import static android.net.NetworkStats.SET_DBG_VPN_OUT; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.TAG_ALL; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static org.junit.Assert.assertEquals; @@ -641,6 +643,136 @@ public class NetworkStatsTest { ROAMING_ALL, DEFAULT_NETWORK_ALL, 50500L, 27L, 100200L, 55, 0); } + @Test + public void testFilter_NoFilter() { + NetworkStats.Entry entry1 = new NetworkStats.Entry( + "test1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats.Entry entry2 = new NetworkStats.Entry( + "test2", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats.Entry entry3 = new NetworkStats.Entry( + "test2", 10101, SET_DEFAULT, 123, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats stats = new NetworkStats(TEST_START, 3) + .addValues(entry1) + .addValues(entry2) + .addValues(entry3); + + stats.filter(UID_ALL, INTERFACES_ALL, TAG_ALL); + assertEquals(3, stats.size()); + assertEquals(entry1, stats.getValues(0, null)); + assertEquals(entry2, stats.getValues(1, null)); + assertEquals(entry3, stats.getValues(2, null)); + } + + @Test + public void testFilter_UidFilter() { + final int testUid = 10101; + NetworkStats.Entry entry1 = new NetworkStats.Entry( + "test1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats.Entry entry2 = new NetworkStats.Entry( + "test2", testUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats.Entry entry3 = new NetworkStats.Entry( + "test2", testUid, SET_DEFAULT, 123, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats stats = new NetworkStats(TEST_START, 3) + .addValues(entry1) + .addValues(entry2) + .addValues(entry3); + + stats.filter(testUid, INTERFACES_ALL, TAG_ALL); + assertEquals(2, stats.size()); + assertEquals(entry2, stats.getValues(0, null)); + assertEquals(entry3, stats.getValues(1, null)); + } + + @Test + public void testFilter_InterfaceFilter() { + final String testIf1 = "testif1"; + final String testIf2 = "testif2"; + NetworkStats.Entry entry1 = new NetworkStats.Entry( + testIf1, 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats.Entry entry2 = new NetworkStats.Entry( + "otherif", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats.Entry entry3 = new NetworkStats.Entry( + testIf1, 10101, SET_DEFAULT, 123, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats.Entry entry4 = new NetworkStats.Entry( + testIf2, 10101, SET_DEFAULT, 123, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats stats = new NetworkStats(TEST_START, 4) + .addValues(entry1) + .addValues(entry2) + .addValues(entry3) + .addValues(entry4); + + stats.filter(UID_ALL, new String[] { testIf1, testIf2 }, TAG_ALL); + assertEquals(3, stats.size()); + assertEquals(entry1, stats.getValues(0, null)); + assertEquals(entry3, stats.getValues(1, null)); + assertEquals(entry4, stats.getValues(2, null)); + } + + @Test + public void testFilter_EmptyInterfaceFilter() { + NetworkStats.Entry entry1 = new NetworkStats.Entry( + "if1", 10100, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats.Entry entry2 = new NetworkStats.Entry( + "if2", 10101, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats stats = new NetworkStats(TEST_START, 3) + .addValues(entry1) + .addValues(entry2); + + stats.filter(UID_ALL, new String[] { }, TAG_ALL); + assertEquals(0, stats.size()); + } + + @Test + public void testFilter_TagFilter() { + final int testTag = 123; + final int otherTag = 456; + NetworkStats.Entry entry1 = new NetworkStats.Entry( + "test1", 10100, SET_DEFAULT, testTag, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats.Entry entry2 = new NetworkStats.Entry( + "test2", 10101, SET_DEFAULT, testTag, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats.Entry entry3 = new NetworkStats.Entry( + "test2", 10101, SET_DEFAULT, otherTag, METERED_NO, ROAMING_NO, + DEFAULT_NETWORK_NO, 50000L, 25L, 100000L, 50L, 0L); + + NetworkStats stats = new NetworkStats(TEST_START, 3) + .addValues(entry1) + .addValues(entry2) + .addValues(entry3); + + stats.filter(UID_ALL, INTERFACES_ALL, testTag); + assertEquals(2, stats.size()); + assertEquals(entry1, stats.getValues(0, null)); + assertEquals(entry2, stats.getValues(1, null)); + } + private static void assertContains(NetworkStats stats, String iface, int uid, int set, int tag, int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { diff --git a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java index b14f5509b709..fc46b9c85980 100644 --- a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java +++ b/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java @@ -184,7 +184,7 @@ public class NetworkStatsFactoryTest { assertStatsEntry(stats, "dummy0", 0, SET_DEFAULT, 0x0, 0L, 168L); assertStatsEntry(stats, "lo", 0, SET_DEFAULT, 0x0, 1288L, 1288L); - NetworkStatsFactory.noteStackedIface("v4-wlan0", null); + NetworkStatsFactory.clearStackedIfaces(); } @Test @@ -212,7 +212,7 @@ public class NetworkStatsFactoryTest { assertStatsEntry(stats, "v4-wlan0", 10106, SET_FOREGROUND, 0x0, appRxBytesAfter, 7867488L); assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytesAfter, 647587L); - NetworkStatsFactory.noteStackedIface("v4-wlan0", null); + NetworkStatsFactory.clearStackedIfaces(); } /** diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java new file mode 100644 index 000000000000..4a83d1ba4f85 --- /dev/null +++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2018 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.connectivity; + +import static android.Manifest.permission.CHANGE_NETWORK_STATE; +import static android.Manifest.permission.CHANGE_WIFI_STATE; +import static android.Manifest.permission.CONNECTIVITY_INTERNAL; +import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS; +import static android.Manifest.permission.NETWORK_STACK; +import static android.content.pm.ApplicationInfo.FLAG_SYSTEM; +import static android.content.pm.PackageManager.GET_PERMISSIONS; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class PermissionMonitorTest { + private static final int MOCK_UID = 10001; + private static final String[] MOCK_PACKAGE_NAMES = new String[] { "com.foo.bar" }; + + @Mock private Context mContext; + @Mock private PackageManager mPackageManager; + + private PermissionMonitor mPermissionMonitor; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + when(mPackageManager.getPackagesForUid(MOCK_UID)).thenReturn(MOCK_PACKAGE_NAMES); + mPermissionMonitor = new PermissionMonitor(mContext, null); + } + + private void expectPermission(String[] permissions, boolean preinstalled) throws Exception { + final PackageInfo packageInfo = packageInfoWithPermissions(permissions, preinstalled); + when(mPackageManager.getPackageInfo(MOCK_PACKAGE_NAMES[0], GET_PERMISSIONS)) + .thenReturn(packageInfo); + } + + private PackageInfo packageInfoWithPermissions(String[] permissions, boolean preinstalled) { + final PackageInfo packageInfo = new PackageInfo(); + packageInfo.requestedPermissions = permissions; + packageInfo.applicationInfo = new ApplicationInfo(); + packageInfo.applicationInfo.flags = preinstalled ? FLAG_SYSTEM : 0; + return packageInfo; + } + + @Test + public void testHasPermission() { + PackageInfo app = packageInfoWithPermissions(new String[] {}, false); + assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE)); + assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK)); + assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS)); + assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL)); + + app = packageInfoWithPermissions(new String[] { + CHANGE_NETWORK_STATE, NETWORK_STACK + }, false); + assertTrue(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE)); + assertTrue(mPermissionMonitor.hasPermission(app, NETWORK_STACK)); + assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS)); + assertFalse(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL)); + + app = packageInfoWithPermissions(new String[] { + CONNECTIVITY_USE_RESTRICTED_NETWORKS, CONNECTIVITY_INTERNAL + }, false); + assertFalse(mPermissionMonitor.hasPermission(app, CHANGE_NETWORK_STATE)); + assertFalse(mPermissionMonitor.hasPermission(app, NETWORK_STACK)); + assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_USE_RESTRICTED_NETWORKS)); + assertTrue(mPermissionMonitor.hasPermission(app, CONNECTIVITY_INTERNAL)); + } + + @Test + public void testIsPreinstalledSystemApp() { + PackageInfo app = packageInfoWithPermissions(new String[] {}, false); + assertFalse(mPermissionMonitor.isPreinstalledSystemApp(app)); + + app = packageInfoWithPermissions(new String[] {}, true); + assertTrue(mPermissionMonitor.isPreinstalledSystemApp(app)); + } + + @Test + public void testHasUseBackgroundNetworksPermission() throws Exception { + expectPermission(new String[] { CHANGE_NETWORK_STATE }, false); + assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID)); + + expectPermission(new String[] { NETWORK_STACK, CONNECTIVITY_INTERNAL }, false); + assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID)); + + // TODO : make this false when b/31479477 is fixed + expectPermission(new String[] {}, true); + assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID)); + expectPermission(new String[] { CHANGE_WIFI_STATE }, true); + assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID)); + + expectPermission(new String[] { NETWORK_STACK, CONNECTIVITY_INTERNAL }, true); + assertTrue(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID)); + + expectPermission(new String[] {}, false); + assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID)); + + expectPermission(new String[] { CHANGE_WIFI_STATE }, false); + assertFalse(mPermissionMonitor.hasUseBackgroundNetworksPermission(MOCK_UID)); + } +} diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index 47c345540973..17ca651b8405 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -25,6 +25,7 @@ import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.DEFAULT_NETWORK_NO; import static android.net.NetworkStats.DEFAULT_NETWORK_YES; import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.INTERFACES_ALL; import static android.net.NetworkStats.METERED_ALL; import static android.net.NetworkStats.METERED_NO; import static android.net.NetworkStats.METERED_YES; @@ -58,6 +59,9 @@ import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -95,6 +99,7 @@ import android.util.Log; import android.util.TrustedTime; import com.android.internal.net.VpnInfo; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.server.net.NetworkStatsService.NetworkStatsSettings; import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config; @@ -668,6 +673,94 @@ public class NetworkStatsServiceTest { } @Test + public void testDetailedUidStats() throws Exception { + // pretend that network comes online + expectDefaultSettings(); + expectNetworkState(buildWifiState()); + expectNetworkStatsSummary(buildEmptyStats()); + expectNetworkStatsUidDetail(buildEmptyStats()); + expectBandwidthControlCheck(); + + mService.forceUpdateIfaces(NETWORKS_WIFI); + + NetworkStats.Entry entry1 = new NetworkStats.Entry( + TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L); + NetworkStats.Entry entry2 = new NetworkStats.Entry( + TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 50L, 5L, 50L, 5L, 0L); + NetworkStats.Entry entry3 = new NetworkStats.Entry( + TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xBEEF, 1024L, 8L, 512L, 4L, 0L); + + incrementCurrentTime(HOUR_IN_MILLIS); + expectDefaultSettings(); + expectNetworkStatsSummary(buildEmptyStats()); + expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) + .addValues(entry1) + .addValues(entry2) + .addValues(entry3)); + mService.incrementOperationCount(UID_RED, 0xF00D, 1); + + NetworkStats stats = mService.getDetailedUidStats(INTERFACES_ALL); + + assertEquals(3, stats.size()); + entry1.operations = 1; + assertEquals(entry1, stats.getValues(0, null)); + entry2.operations = 1; + assertEquals(entry2, stats.getValues(1, null)); + assertEquals(entry3, stats.getValues(2, null)); + } + + @Test + public void testDetailedUidStats_Filtered() throws Exception { + // pretend that network comes online + expectDefaultSettings(); + + final String stackedIface = "stacked-test0"; + final LinkProperties stackedProp = new LinkProperties(); + stackedProp.setInterfaceName(stackedIface); + final NetworkState wifiState = buildWifiState(); + wifiState.linkProperties.addStackedLink(stackedProp); + expectNetworkState(wifiState); + + expectNetworkStatsSummary(buildEmptyStats()); + expectNetworkStatsUidDetail(buildEmptyStats()); + expectBandwidthControlCheck(); + + mService.forceUpdateIfaces(NETWORKS_WIFI); + + NetworkStats.Entry uidStats = new NetworkStats.Entry( + TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L); + // Stacked on matching interface + NetworkStats.Entry tetheredStats1 = new NetworkStats.Entry( + stackedIface, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L); + // Different interface + NetworkStats.Entry tetheredStats2 = new NetworkStats.Entry( + "otherif", UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L); + + final String[] ifaceFilter = new String[] { TEST_IFACE }; + incrementCurrentTime(HOUR_IN_MILLIS); + expectDefaultSettings(); + expectNetworkStatsSummary(buildEmptyStats()); + when(mNetManager.getNetworkStatsUidDetail(eq(UID_ALL), any())) + .thenReturn(new NetworkStats(getElapsedRealtime(), 1) + .addValues(uidStats)); + when(mNetManager.getNetworkStatsTethering(STATS_PER_UID)) + .thenReturn(new NetworkStats(getElapsedRealtime(), 2) + .addValues(tetheredStats1) + .addValues(tetheredStats2)); + + NetworkStats stats = mService.getDetailedUidStats(ifaceFilter); + + verify(mNetManager, times(1)).getNetworkStatsUidDetail(eq(UID_ALL), argThat(ifaces -> + ifaces != null && ifaces.length == 2 + && ArrayUtils.contains(ifaces, TEST_IFACE) + && ArrayUtils.contains(ifaces, stackedIface))); + + assertEquals(2, stats.size()); + assertEquals(uidStats, stats.getValues(0, null)); + assertEquals(tetheredStats1, stats.getValues(1, null)); + } + + @Test public void testForegroundBackground() throws Exception { // pretend that network comes online expectCurrentTime(); @@ -1056,7 +1149,7 @@ public class NetworkStatsServiceTest { private void expectNetworkStatsUidDetail(NetworkStats detail, NetworkStats tetherStats) throws Exception { - when(mNetManager.getNetworkStatsUidDetail(UID_ALL)).thenReturn(detail); + when(mNetManager.getNetworkStatsUidDetail(UID_ALL, INTERFACES_ALL)).thenReturn(detail); // also include tethering details, since they are folded into UID when(mNetManager.getNetworkStatsTethering(STATS_PER_UID)).thenReturn(tetherStats); |