Merge "Carrier confirmation code."
diff --git a/Android.bp b/Android.bp
index e0e5ed9..b0493aa 100644
--- a/Android.bp
+++ b/Android.bp
@@ -530,14 +530,7 @@
"core/java/android/net/EventLogTags.logtags",
"core/java/android/webkit/EventLogTags.logtags",
"core/java/com/android/internal/logging/EventLogTags.logtags",
- ],
- logtags: [
- "core/java/android/app/admin/SecurityLogTags.logtags",
- "core/java/android/content/EventLogTags.logtags",
- "core/java/android/speech/tts/EventLogTags.logtags",
- "core/java/android/net/EventLogTags.logtags",
- "core/java/android/webkit/EventLogTags.logtags",
- "core/java/com/android/internal/logging/EventLogTags.logtags",
+ "core/java/com/android/server/DropboxLogTags.logtags",
],
aidl: {
diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java
index 85550c7..90ae0e6 100644
--- a/core/java/android/bluetooth/BluetoothHeadset.java
+++ b/core/java/android/bluetooth/BluetoothHeadset.java
@@ -670,33 +670,6 @@
}
/**
- * Get battery usage hint for Bluetooth Headset service.
- * This is a monotonically increasing integer. Wraps to 0 at
- * Integer.MAX_INT, and at boot.
- * Current implementation returns the number of AT commands handled since
- * boot. This is a good indicator for spammy headset/handsfree units that
- * can keep the device awake by polling for cellular status updates. As a
- * rule of thumb, each AT command prevents the CPU from sleeping for 500 ms
- *
- * @param device the bluetooth headset.
- * @return monotonically increasing battery usage hint, or a negative error code on error
- * @hide
- */
- public int getBatteryUsageHint(BluetoothDevice device) {
- if (VDBG) log("getBatteryUsageHint()");
- final IBluetoothHeadset service = mService;
- if (service != null && isEnabled() && isValidDevice(device)) {
- try {
- return service.getBatteryUsageHint(device);
- } catch (RemoteException e) {
- Log.e(TAG, Log.getStackTraceString(new Throwable()));
- }
- }
- if (service == null) Log.w(TAG, "Proxy not attached to service");
- return -1;
- }
-
- /**
* Indicates if current platform supports voice dialing over bluetooth SCO.
*
* @return true if voice dialing over bluetooth is supported, false otherwise.
@@ -708,49 +681,6 @@
}
/**
- * Accept the incoming connection.
- * Note: This is an internal function and shouldn't be exposed
- *
- * @hide
- */
- public boolean acceptIncomingConnect(BluetoothDevice device) {
- if (DBG) log("acceptIncomingConnect");
- final IBluetoothHeadset service = mService;
- if (service != null && isEnabled()) {
- try {
- return service.acceptIncomingConnect(device);
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
- } else {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- }
- return false;
- }
-
- /**
- * Reject the incoming connection.
- *
- * @hide
- */
- public boolean rejectIncomingConnect(BluetoothDevice device) {
- if (DBG) log("rejectIncomingConnect");
- final IBluetoothHeadset service = mService;
- if (service != null) {
- try {
- return service.rejectIncomingConnect(device);
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
- } else {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- }
- return false;
- }
-
- /**
* Get the current audio state of the Headset.
* Note: This is an internal function and shouldn't be exposed
*
@@ -1045,50 +975,6 @@
}
/**
- * enable WBS codec setting.
- *
- * @return true if successful false if there was some error such as there is no connected
- * headset
- * @hide
- */
- public boolean enableWBS() {
- final IBluetoothHeadset service = mService;
- if (service != null && isEnabled()) {
- try {
- return service.enableWBS();
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
- } else {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- }
- return false;
- }
-
- /**
- * disable WBS codec settting. It set NBS codec.
- *
- * @return true if successful false if there was some error such as there is no connected
- * headset
- * @hide
- */
- public boolean disableWBS() {
- final IBluetoothHeadset service = mService;
- if (service != null && isEnabled()) {
- try {
- return service.disableWBS();
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
- } else {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- }
- return false;
- }
-
- /**
* check if in-band ringing is supported for this platform.
*
* @return true if in-band ringing is supported false if in-band ringing is not supported
@@ -1099,30 +985,6 @@
com.android.internal.R.bool.config_bluetooth_hfp_inband_ringing_support);
}
- /**
- * Send Headset the BIND response from AG to report change in the status of the
- * HF indicators to the headset
- *
- * @param indId Assigned Number of the indicator (defined by SIG)
- * @param indStatus possible values- false-Indicator is disabled, no value changes shall be
- * sent for this indicator true-Indicator is enabled, value changes may be sent for this
- * indicator
- * @hide
- */
- public void bindResponse(int indId, boolean indStatus) {
- final IBluetoothHeadset service = mService;
- if (service != null && isEnabled()) {
- try {
- service.bindResponse(indId, indStatus);
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
- } else {
- Log.w(TAG, "Proxy not attached to service");
- if (DBG) Log.d(TAG, Log.getStackTraceString(new Throwable()));
- }
- }
-
private final IBluetoothProfileServiceConnection mConnection =
new IBluetoothProfileServiceConnection.Stub() {
@Override
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
index 5a203d0..330a0bf 100644
--- a/core/java/android/bluetooth/BluetoothHidDevice.java
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -31,36 +31,33 @@
import java.util.List;
/**
- * Provides the public APIs to control the Bluetooth HID Device
- * profile.
+ * Provides the public APIs to control the Bluetooth HID Device profile.
*
- * BluetoothHidDevice is a proxy object for controlling the Bluetooth HID
- * Device Service via IPC. Use {@link BluetoothAdapter#getProfileProxy} to get
- * the BluetoothHidDevice proxy object.
+ * <p>BluetoothHidDevice is a proxy object for controlling the Bluetooth HID Device Service via IPC.
+ * Use {@link BluetoothAdapter#getProfileProxy} to get the BluetoothHidDevice proxy object.
*
- * {@hide}
+ * <p>{@hide}
*/
public final class BluetoothHidDevice implements BluetoothProfile {
private static final String TAG = BluetoothHidDevice.class.getSimpleName();
/**
- * Intent used to broadcast the change in connection state of the Input
- * Host profile.
+ * Intent used to broadcast the change in connection state of the Input Host profile.
*
* <p>This intent will have 3 extras:
+ *
* <ul>
- * <li> {@link #EXTRA_STATE} - The current state of the profile. </li>
- * <li> {@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.</li>
- * <li> {@link BluetoothDevice#EXTRA_DEVICE} - The remote device. </li>
+ * <li>{@link #EXTRA_STATE} - The current state of the profile.
+ * <li>{@link #EXTRA_PREVIOUS_STATE}- The previous state of the profile.
+ * <li>{@link BluetoothDevice#EXTRA_DEVICE} - The remote device.
* </ul>
*
- * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of
- * {@link #STATE_DISCONNECTED}, {@link #STATE_CONNECTING},
- * {@link #STATE_CONNECTED}, {@link #STATE_DISCONNECTING}.
+ * <p>{@link #EXTRA_STATE} or {@link #EXTRA_PREVIOUS_STATE} can be any of {@link
+ * #STATE_DISCONNECTED}, {@link #STATE_CONNECTING}, {@link #STATE_CONNECTED}, {@link
+ * #STATE_DISCONNECTING}.
*
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to
- * receive.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission to receive.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_CONNECTION_STATE_CHANGED =
@@ -69,9 +66,8 @@
/**
* Constants representing device subclass.
*
- * @see #registerApp
- * (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
- * BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceCallback)
+ * @see #registerApp (BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceAppQosSettings,
+ * BluetoothHidDeviceAppQosSettings, BluetoothHidDeviceCallback)
*/
public static final byte SUBCLASS1_NONE = (byte) 0x00;
public static final byte SUBCLASS1_KEYBOARD = (byte) 0x40;
@@ -110,8 +106,8 @@
public static final byte ERROR_RSP_UNKNOWN = (byte) 14;
/**
- * Constants representing protocol mode used set by host. Default is always
- * {@link #PROTOCOL_REPORT_MODE} unless notified otherwise.
+ * Constants representing protocol mode used set by host. Default is always {@link
+ * #PROTOCOL_REPORT_MODE} unless notified otherwise.
*
* @see BluetoothHidDeviceCallback#onSetProtocol(BluetoothDevice, byte)
*/
@@ -126,8 +122,8 @@
private BluetoothAdapter mAdapter;
- private static class BluetoothHidDeviceCallbackWrapper extends
- IBluetoothHidDeviceCallback.Stub {
+ private static class BluetoothHidDeviceCallbackWrapper
+ extends IBluetoothHidDeviceCallback.Stub {
private BluetoothHidDeviceCallback mCallback;
@@ -184,13 +180,11 @@
doBind();
}
} catch (IllegalStateException e) {
- Log.e(TAG,
- "onBluetoothStateChange: could not bind to HID Dev "
- + "service: ", e);
+ Log.e(TAG, "onBluetoothStateChange: could not bind to HID Dev "
+ + "service: ", e);
} catch (SecurityException e) {
- Log.e(TAG,
- "onBluetoothStateChange: could not bind to HID Dev "
- + "service: ", e);
+ Log.e(TAG, "onBluetoothStateChange: could not bind to HID Dev "
+ + "service: ", e);
}
} else {
Log.d(TAG, "Unbinding service...");
@@ -200,23 +194,25 @@
}
};
- private final ServiceConnection mConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- Log.d(TAG, "onServiceConnected()");
- mService = IBluetoothHidDevice.Stub.asInterface(service);
- if (mServiceListener != null) {
- mServiceListener.onServiceConnected(BluetoothProfile.HID_DEVICE,
- BluetoothHidDevice.this);
- }
- }
- public void onServiceDisconnected(ComponentName className) {
- Log.d(TAG, "onServiceDisconnected()");
- mService = null;
- if (mServiceListener != null) {
- mServiceListener.onServiceDisconnected(BluetoothProfile.HID_DEVICE);
- }
- }
- };
+ private final ServiceConnection mConnection =
+ new ServiceConnection() {
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ Log.d(TAG, "onServiceConnected()");
+ mService = IBluetoothHidDevice.Stub.asInterface(service);
+ if (mServiceListener != null) {
+ mServiceListener.onServiceConnected(
+ BluetoothProfile.HID_DEVICE, BluetoothHidDevice.this);
+ }
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ Log.d(TAG, "onServiceDisconnected()");
+ mService = null;
+ if (mServiceListener != null) {
+ mServiceListener.onServiceDisconnected(BluetoothProfile.HID_DEVICE);
+ }
+ }
+ };
BluetoothHidDevice(Context context, ServiceListener listener) {
Log.v(TAG, "BluetoothHidDevice");
@@ -280,9 +276,7 @@
mServiceListener = null;
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public List<BluetoothDevice> getConnectedDevices() {
Log.v(TAG, "getConnectedDevices()");
@@ -301,9 +295,7 @@
return new ArrayList<BluetoothDevice>();
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) {
Log.v(TAG, "getDevicesMatchingConnectionStates(): states=" + Arrays.toString(states));
@@ -322,9 +314,7 @@
return new ArrayList<BluetoothDevice>();
}
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
@Override
public int getConnectionState(BluetoothDevice device) {
Log.v(TAG, "getConnectionState(): device=" + device);
@@ -344,33 +334,31 @@
}
/**
- * Registers application to be used for HID device. Connections to HID
- * Device are only possible when application is registered. Only one
- * application can be registered at time. 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.
+ * Registers application to be used for HID device. Connections to HID Device are only possible
+ * 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.
*
- * @param sdp {@link BluetoothHidDeviceAppSdpSettings} object of HID Device SDP record.
- * The HID Device SDP record is required.
- * @param inQos {@link BluetoothHidDeviceAppQosSettings} object of Incoming QoS Settings.
- * The Incoming QoS Settings is not required. Use null or default
- * BluetoothHidDeviceAppQosSettings.Builder for default values.
- * @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 sdp {@link BluetoothHidDeviceAppSdpSettings} object of HID Device SDP record. The HID
+ * Device SDP record is required.
+ * @param inQos {@link BluetoothHidDeviceAppQosSettings} object of Incoming QoS Settings. The
+ * Incoming QoS Settings is not required. Use null or default
+ * BluetoothHidDeviceAppQosSettings.Builder for default values.
+ * @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.
+ * sent. The BluetoothHidDeviceCallback 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);
+ + " callback=" + callback);
boolean result = false;
@@ -395,14 +383,13 @@
}
/**
- * Unregisters application. Active connection will be disconnected and no
- * new connections will be allowed until registered again using
- * {@link #registerApp
+ * 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, 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.
*
* @return true if the command is successfully sent; otherwise false.
*/
@@ -429,7 +416,7 @@
* Sends report to remote host using interrupt channel.
*
* @param id Report Id, as defined in descriptor. Can be 0 in case Report Id are not defined in
- * descriptor.
+ * descriptor.
* @param data Report data, not including Report Id.
* @return true if the command is successfully sent; otherwise false.
*/
@@ -451,8 +438,8 @@
}
/**
- * Sends report to remote host as reply for GET_REPORT request from
- * {@link BluetoothHidDeviceCallback#onGetReport(BluetoothDevice, byte, byte, int)}.
+ * Sends report to remote host as reply for GET_REPORT request from {@link
+ * BluetoothHidDeviceCallback#onGetReport(BluetoothDevice, byte, byte, int)}.
*
* @param type Report Type, as in request.
* @param id Report Id, as in request.
@@ -479,8 +466,8 @@
}
/**
- * Sends error handshake message as reply for invalid SET_REPORT request
- * from {@link BluetoothHidDeviceCallback#onSetReport(BluetoothDevice, byte, byte, byte[])}.
+ * Sends error handshake message as reply for invalid SET_REPORT request from {@link
+ * BluetoothHidDeviceCallback#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.
@@ -508,6 +495,7 @@
* Sends Virtual Cable Unplug to currently connected host.
*
* @return
+ * {@hide}
*/
public boolean unplug(BluetoothDevice device) {
Log.v(TAG, "unplug(): device=" + device);
@@ -529,11 +517,11 @@
}
/**
- * 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.
+ * 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.
*
* @return true if the command is successfully sent; otherwise false.
*/
@@ -557,10 +545,9 @@
}
/**
- * 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.
+ * 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.
*
* @return true if the command is successfully sent; otherwise false.
*/
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
index 881ae98..4609d52 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppQosSettings.java
@@ -20,15 +20,14 @@
import android.os.Parcelable;
/**
- * Represents the Quality of Service (QoS) settings for a Bluetooth HID Device
- * application.
+ * Represents the Quality of Service (QoS) settings for a Bluetooth HID Device application.
*
- * The BluetoothHidDevice framework will update the L2CAP QoS settings for the
- * app during registration.
+ * <p>The BluetoothHidDevice framework will update the L2CAP QoS settings for the app during
+ * registration.
*
- * {@see BluetoothHidDevice}
+ * <p>{@see BluetoothHidDevice}
*
- * {@hide}
+ * <p>{@hide}
*/
public final class BluetoothHidDeviceAppQosSettings implements Parcelable {
@@ -46,13 +45,12 @@
public static final int MAX = (int) 0xffffffff;
/**
- * Create a BluetoothHidDeviceAppQosSettings object for the Bluetooth L2CAP channel.
- * The QoS Settings is optional.
- * Recommended to use BluetoothHidDeviceAppQosSettings.Builder.
- * {@see <a href="https://www.bluetooth.com/specifications/profiles-overview">
- * https://www.bluetooth.com/specifications/profiles-overview
- * </a>
- * Bluetooth HID Specfication v1.1.1 Section 5.2 and Appendix D }
+ * Create a BluetoothHidDeviceAppQosSettings object for the Bluetooth L2CAP channel. The QoS
+ * Settings is optional. Recommended to use BluetoothHidDeviceAppQosSettings.Builder. {@see <a
+ * href="https://www.bluetooth.com/specifications/profiles-overview">
+ * https://www.bluetooth.com/specifications/profiles-overview </a> Bluetooth HID Specfication
+ * v1.1.1 Section 5.2 and Appendix D }
+ *
* @param serviceType L2CAP service type
* @param tokenRate L2CAP token rate
* @param tokenBucketSize L2CAP token bucket size
@@ -123,13 +121,11 @@
/** @return an int array representation of this instance */
public int[] toArray() {
return new int[] {
- serviceType, tokenRate, tokenBucketSize, peakBandwidth, latency, delayVariation
+ serviceType, tokenRate, tokenBucketSize, peakBandwidth, latency, delayVariation
};
}
- /**
- * A helper to build the BluetoothHidDeviceAppQosSettings object.
- */
+ /** A helper to build the BluetoothHidDeviceAppQosSettings object. */
public static class Builder {
// Optional parameters - initialized to default values
private int mServiceType = SERVICE_BEST_EFFORT;
@@ -141,8 +137,9 @@
/**
* 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.
+ * SERVICE_GUARANTEED}, with SERVICE_BEST_EFFORT being the default one.
* @return BluetoothHidDeviceAppQosSettings Builder with specified service type.
*/
public Builder serviceType(int val) {
@@ -151,6 +148,7 @@
}
/**
* Set the token rate.
+ *
* @param val token rate
* @return BluetoothHidDeviceAppQosSettings Builder with specified token rate.
*/
@@ -161,6 +159,7 @@
/**
* Set the bucket size.
+ *
* @param val bucket size
* @return BluetoothHidDeviceAppQosSettings Builder with specified bucket size.
*/
@@ -171,6 +170,7 @@
/**
* Set the peak bandwidth.
+ *
* @param val peak bandwidth
* @return BluetoothHidDeviceAppQosSettings Builder with specified peak bandwidth.
*/
@@ -180,6 +180,7 @@
}
/**
* Set the latency.
+ *
* @param val latency
* @return BluetoothHidDeviceAppQosSettings Builder with specified latency.
*/
@@ -190,6 +191,7 @@
/**
* Set the delay variation.
+ *
* @param val delay variation
* @return BluetoothHidDeviceAppQosSettings Builder with specified delay variation.
*/
@@ -200,6 +202,7 @@
/**
* Build the BluetoothHidDeviceAppQosSettings object.
+ *
* @return BluetoothHidDeviceAppQosSettings object with current settings.
*/
public BluetoothHidDeviceAppQosSettings build() {
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
index 4669637..2da64e5 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceAppSdpSettings.java
@@ -22,16 +22,14 @@
import java.util.Arrays;
/**
- * Represents the Service Discovery Protocol (SDP) settings for a Bluetooth
- * HID Device application.
+ * Represents the Service Discovery Protocol (SDP) settings for a Bluetooth HID Device application.
*
- * The BluetoothHidDevice framework adds the SDP record during app
- * registration, so that the Android device can be discovered as a Bluetooth
- * HID Device.
+ * <p>The BluetoothHidDevice framework adds the SDP record during app registration, so that the
+ * Android device can be discovered as a Bluetooth HID Device.
*
- * {@see BluetoothHidDevice}
+ * <p>{@see BluetoothHidDevice}
*
- * {@hide}
+ * <p>{@hide}
*/
public final class BluetoothHidDeviceAppSdpSettings implements Parcelable {
@@ -43,18 +41,19 @@
/**
* Create a BluetoothHidDeviceAppSdpSettings object for the Bluetooth SDP record.
+ *
* @param name Name of this Bluetooth HID device. Maximum length is 50 bytes.
* @param description Description for this Bluetooth HID device. Maximum length is 50 bytes.
* @param provider Provider of this Bluetooth HID device. Maximum length is 50 bytes.
- * @param subclass Subclass of this Bluetooth HID device.
- * See <a href="www.usb.org/developers/hidpage/HID1_11.pdf">
+ * @param subclass Subclass of this Bluetooth HID device. See <a
+ * href="www.usb.org/developers/hidpage/HID1_11.pdf">
* www.usb.org/developers/hidpage/HID1_11.pdf Section 4.2</a>
- * @param descriptors Descriptors of this Bluetooth HID device.
- * See <a href="www.usb.org/developers/hidpage/HID1_11.pdf">
+ * @param descriptors Descriptors of this Bluetooth HID device. See <a
+ * href="www.usb.org/developers/hidpage/HID1_11.pdf">
* www.usb.org/developers/hidpage/HID1_11.pdf Chapter 6</a> Maximum length is 2048 bytes.
*/
- public BluetoothHidDeviceAppSdpSettings(String name, String description, String provider,
- byte subclass, byte[] descriptors) {
+ public BluetoothHidDeviceAppSdpSettings(
+ String name, String description, String provider, byte subclass, byte[] descriptors) {
this.name = name;
this.description = description;
this.provider = provider;
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceCallback.java b/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
index dc6f9fa..6ed1965 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
@@ -19,46 +19,43 @@
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.
+ * 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.
*
- * {@see BluetoothHidDevice}
+ * <p>{@see BluetoothHidDevice}
*
- * {@hide}
+ * <p>{@hide}
*/
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.
+ * 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>.
+ * 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.
+ * otherwise.
*/
public void onAppStatusChanged(BluetoothDevice pluggedDevice, boolean registered) {
- Log.d(TAG, "onAppStatusChanged: pluggedDevice=" + pluggedDevice + " registered="
- + 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>.
+ * 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.
+ * was changed.
* @param state Connection state as defined in {@link BluetoothProfile}.
*/
public void onConnectionStateChanged(BluetoothDevice device, int state) {
@@ -66,14 +63,14 @@
}
/**
- * Callback called when GET_REPORT is received from remote host. Should be
- * replied by application using
- * {@link BluetoothHidDevice#replyReport(BluetoothDevice, byte, byte, byte[])}.
+ * 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.
+ * of bytes.
*/
public void onGetReport(BluetoothDevice device, byte type, byte id, int bufferSize) {
Log.d(TAG, "onGetReport: device=" + device + " type=" + type + " id=" + id + " bufferSize="
@@ -81,9 +78,9 @@
}
/**
- * 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)}.
+ * 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.
@@ -94,10 +91,9 @@
}
/**
- * 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.
+ * 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.
*/
@@ -106,9 +102,8 @@
}
/**
- * Callback called when report data is received over interrupt channel.
- * Report Type is assumed to be
- * {@link BluetoothHidDevice#REPORT_TYPE_OUTPUT}.
+ * 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.
@@ -118,10 +113,8 @@
}
/**
- * Callback called when Virtual Cable is removed. This can be either due to
- * {@link BluetoothHidDevice#unplug(BluetoothDevice)} or request from remote
- * side. After this callback is received connection will be disconnected
- * automatically.
+ * 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/net/metrics/DefaultNetworkEvent.java b/core/java/android/net/metrics/DefaultNetworkEvent.java
index 8ff8e4f..6f383b4 100644
--- a/core/java/android/net/metrics/DefaultNetworkEvent.java
+++ b/core/java/android/net/metrics/DefaultNetworkEvent.java
@@ -74,7 +74,7 @@
j.add("final_score=" + finalScore);
}
j.add(String.format("duration=%.0fs", durationMs / 1000.0));
- j.add(String.format("validation=%4.1f%%", (validatedMs * 100.0) / durationMs));
+ j.add(String.format("validation=%04.1f%%", (validatedMs * 100.0) / durationMs));
return j.toString();
}
diff --git a/core/java/com/android/internal/widget/ButtonBarLayout.java b/core/java/com/android/internal/widget/ButtonBarLayout.java
index 6a0edef..82affe2 100644
--- a/core/java/com/android/internal/widget/ButtonBarLayout.java
+++ b/core/java/com/android/internal/widget/ButtonBarLayout.java
@@ -151,7 +151,7 @@
private void setStacked(boolean stacked) {
setOrientation(stacked ? LinearLayout.VERTICAL : LinearLayout.HORIZONTAL);
- setGravity(stacked ? Gravity.RIGHT : Gravity.BOTTOM);
+ setGravity(stacked ? Gravity.END : Gravity.BOTTOM);
final View spacer = findViewById(R.id.spacer);
if (spacer != null) {
diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java
index 4354486..8848e393 100644
--- a/core/java/com/android/server/BootReceiver.java
+++ b/core/java/com/android/server/BootReceiver.java
@@ -33,6 +33,7 @@
import android.provider.Downloads;
import android.text.TextUtils;
import android.util.AtomicFile;
+import android.util.EventLog;
import android.util.Slog;
import android.util.Xml;
@@ -40,6 +41,7 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
+import com.android.server.DropboxLogTags;
import java.io.File;
import java.io.FileInputStream;
@@ -297,6 +299,7 @@
Slog.i(TAG, "Copying " + filename + " to DropBox (" + tag + ")");
db.addText(tag, headers + FileUtils.readTextFile(file, maxSize, "[[TRUNCATED]]\n") +
footers);
+ EventLog.writeEvent(DropboxLogTags.DROPBOX_FILE_COPY, filename, maxSize, tag);
}
private static void addAuditErrorsToDropBox(DropBoxManager db,
diff --git a/core/java/com/android/server/DropboxLogTags.logtags b/core/java/com/android/server/DropboxLogTags.logtags
new file mode 100644
index 0000000..c461cfe
--- /dev/null
+++ b/core/java/com/android/server/DropboxLogTags.logtags
@@ -0,0 +1,12 @@
+# See system/core/logcat/event.logtags for a description of the format of this file.
+
+# The java package name happens to be the same as frameworks/base/services/core
+# /java/com/android/server/EventLogTags.logtags. To avoid conflict, this file's name cannot
+# be EventLogTags.logtags because it generates a class with the same name.
+
+option java_package com.android.server;
+
+# -----------------------------
+# BootReceiver.java
+# -----------------------------
+81002 dropbox_file_copy (FileName|3),(Size|1),(Tag|3)
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index e9357df..befebd9 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4422,7 +4422,9 @@
<string name="stk_cc_ussd_to_dial">USSD request is modified to DIAL request.</string>
<string name="stk_cc_ussd_to_ss">USSD request is modified to SS request.</string>
<string name="stk_cc_ussd_to_ussd">USSD request is modified to new USSD request.</string>
+ <string name="stk_cc_ussd_to_dial_video">USSD request is modified to Video DIAL request.</string>
<string name="stk_cc_ss_to_dial">SS request is modified to DIAL request.</string>
+ <string name="stk_cc_ss_to_dial_video">SS request is modified to Video DIAL request.</string>
<string name="stk_cc_ss_to_ussd">SS request is modified to USSD request.</string>
<string name="stk_cc_ss_to_ss">SS request is modified to new SS request.</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 451a285..1703ef0 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1031,9 +1031,11 @@
<java-symbol type="string" name="stk_cc_ss_to_dial" />
<java-symbol type="string" name="stk_cc_ss_to_ss" />
<java-symbol type="string" name="stk_cc_ss_to_ussd" />
+ <java-symbol type="string" name="stk_cc_ss_to_dial_video" />
<java-symbol type="string" name="stk_cc_ussd_to_dial" />
<java-symbol type="string" name="stk_cc_ussd_to_ss" />
<java-symbol type="string" name="stk_cc_ussd_to_ussd" />
+ <java-symbol type="string" name="stk_cc_ussd_to_dial_video" />
<java-symbol type="string" name="safe_media_volume_warning" />
<java-symbol type="string" name="media_route_status_scanning" />
<java-symbol type="string" name="media_route_status_connecting" />
diff --git a/packages/InputDevices/res/raw/keyboard_layout_azerbaijani.kcm b/packages/InputDevices/res/raw/keyboard_layout_azerbaijani.kcm
new file mode 100644
index 0000000..69490cc
--- /dev/null
+++ b/packages/InputDevices/res/raw/keyboard_layout_azerbaijani.kcm
@@ -0,0 +1,312 @@
+# Copyright (C) 2017 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.
+
+#
+# Azerbaijan (AZ) keyboard layout.
+#
+
+type OVERLAY
+
+### ROW 1
+
+key GRAVE {
+ label: '`'
+ base: '`'
+ shift: '~'
+}
+
+key 1 {
+ label: '1'
+ base: '1'
+ shift: '!'
+}
+
+key 2 {
+ label: '2'
+ base: '2'
+ shift: '"'
+ ralt: '@'
+}
+
+key 3 {
+ label: '3'
+ base: '3'
+ shift: '\u2166'
+}
+
+key 4 {
+ label: '4'
+ base: '4'
+ shift: ';'
+}
+
+key 5 {
+ label: '5'
+ base: '5'
+ shift: '%'
+}
+
+key 6 {
+ label: '6'
+ base: '6'
+ shift: ':'
+ shift+ralt: '^'
+}
+
+key 7 {
+ label: '7'
+ base: '7'
+ shift: '?'
+ ralt: '&'
+}
+
+key 8 {
+ label: '8'
+ base: '8'
+ shift: '*'
+}
+
+key 9 {
+ label: '9'
+ base: '9'
+ shift: '('
+}
+
+key 0 {
+ label: '0'
+ base: '0'
+ shift: ')'
+}
+
+key MINUS {
+ label: '-'
+ base: '-'
+ shift: '_'
+}
+
+key EQUALS {
+ label: '='
+ base: '='
+ shift: '+'
+}
+
+### ROW 2
+
+key Q {
+ label: 'Q'
+ base: 'q'
+ shift, capslock: 'Q'
+}
+
+key W {
+ label: '\u00dc'
+ base: '\u00fc'
+ shift, capslock: '\u00dc'
+}
+
+key E {
+ label: 'E'
+ base: 'e'
+ shift, capslock: 'E'
+}
+
+key R {
+ label: 'R'
+ base: 'r'
+ shift, capslock: 'R'
+}
+
+key T {
+ label: 'T'
+ base: 't'
+ shift, capslock: 'T'
+}
+
+key Y {
+ label: 'Y'
+ base: 'y'
+ shift, capslock: 'Y'
+}
+
+key U {
+ label: 'U'
+ base: 'u'
+ shift, capslock: 'U'
+}
+
+key I {
+ label: '\u0130'
+ base: 'i'
+ shift, capslock: '\u0130'
+}
+
+key O {
+ label: 'O'
+ base: 'o'
+ shift, capslock: 'O'
+}
+
+key P {
+ label: 'P'
+ base: 'p'
+ shift, capslock: 'P'
+}
+
+key LEFT_BRACKET {
+ label: '\u00d6'
+ base: '\u00f6'
+ shift: '\u00d6'
+}
+
+key RIGHT_BRACKET {
+ label: '\u011e'
+ base: '\u011f'
+ shift: '\u011e'
+}
+
+key BACKSLASH {
+ label: '\\'
+ base: '\\'
+ shift: '|'
+}
+
+### ROW 3
+
+key A {
+ label: 'A'
+ base: 'a'
+ shift, capslock: 'A'
+}
+
+key S {
+ label: 'S'
+ base: 's'
+ shift, capslock: 'S'
+}
+
+key D {
+ label: 'D'
+ base: 'd'
+ shift, capslock: 'D'
+}
+
+key F {
+ label: 'F'
+ base: 'f'
+ shift, capslock: 'F'
+}
+
+key G {
+ label: 'G'
+ base: 'g'
+ shift, capslock: 'G'
+}
+
+key H {
+ label: 'H'
+ base: 'h'
+ shift, capslock: 'H'
+}
+
+key J {
+ label: 'J'
+ base: 'j'
+ shift, capslock: 'J'
+}
+
+key K {
+ label: 'K'
+ base: 'k'
+ shift, capslock: 'K'
+}
+
+key L {
+ label: 'L'
+ base: 'l'
+ shift, capslock: 'L'
+}
+
+key SEMICOLON {
+ label: 'I'
+ base: '\u0131'
+ shift: 'I'
+}
+
+key APOSTROPHE {
+ label: '\u018f'
+ base: '\u0259'
+ shift: '\u018f'
+}
+
+### ROW 4
+
+key Z {
+ label: 'Z'
+ base: 'z'
+ shift, capslock: 'Z'
+}
+
+key X {
+ label: 'X'
+ base: 'x'
+ shift, capslock: 'X'
+}
+
+key C {
+ label: 'C'
+ base: 'c'
+ shift, capslock: 'C'
+}
+
+key V {
+ label: 'V'
+ base: 'v'
+ shift, capslock: 'V'
+}
+
+key B {
+ label: 'B'
+ base: 'b'
+ shift, capslock: 'B'
+}
+
+key N {
+ label: 'N'
+ base: 'n'
+ shift, capslock: 'N'
+}
+
+key M {
+ label: 'M'
+ base: 'm'
+ shift, capslock: 'M'
+}
+
+key COMMA {
+ label: '\u00c7'
+ base: '\u00e7'
+ shift: '\u00c7'
+}
+
+key PERIOD {
+ label: '\u015e'
+ base: '\u015f'
+ shift: '\u015e'
+}
+
+key SLASH {
+ label: '.'
+ base: '.'
+ shift: ','
+}
diff --git a/packages/InputDevices/res/values/strings.xml b/packages/InputDevices/res/values/strings.xml
index 1e26226..61d3234 100644
--- a/packages/InputDevices/res/values/strings.xml
+++ b/packages/InputDevices/res/values/strings.xml
@@ -122,4 +122,7 @@
<!-- Persian keyboard layout label. [CHAR LIMIT=35] -->
<string name="keyboard_layout_persian">Persian</string>
+
+ <!-- Azerbaijani keyboard layout label. [CHAR LIMIT=35] -->
+ <string name="keyboard_layout_azerbaijani">Azerbaijani</string>
</resources>
diff --git a/packages/InputDevices/res/xml/keyboard_layouts.xml b/packages/InputDevices/res/xml/keyboard_layouts.xml
index c55711a..c6bfc1f 100644
--- a/packages/InputDevices/res/xml/keyboard_layouts.xml
+++ b/packages/InputDevices/res/xml/keyboard_layouts.xml
@@ -155,4 +155,8 @@
<keyboard-layout android:name="keyboard_layout_persian"
android:label="@string/keyboard_layout_persian"
android:keyboardLayout="@raw/keyboard_layout_persian" />
+
+ <keyboard-layout android:name="keyboard_layout_azerbaijani"
+ android:label="@string/keyboard_layout_azerbaijani"
+ android:keyboardLayout="@raw/keyboard_layout_azerbaijani" />
</keyboard-layouts>
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index cb23cf3..cbcbf2d6 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -364,4 +364,20 @@
<!-- Fingerprint hint message when finger was not recognized.-->
<string name="fingerprint_not_recognized">Not recognized</string>
+ <!-- Instructions telling the user remaining times when enter SIM PIN view. -->
+ <plurals name="kg_password_default_pin_message">
+ <item quantity="one">Enter SIM PIN, you have <xliff:g id="number">%d</xliff:g> remaining
+attempt before you must contact your carrier to unlock your device.</item>
+ <item quantity="other">Enter SIM PIN, you have <xliff:g id="number">%d</xliff:g> remaining
+attempts.</item>
+ </plurals>
+
+ <!-- Instructions telling the user remaining times when enter SIM PUK view. -->
+ <plurals name="kg_password_default_puk_message">
+ <item quantity="one">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="
+number">%d</xliff:g> remaining attempt before SIM becomes permanently unusable. Contact carrier for details.</item>
+ <item quantity="other">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="
+number">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact carrier for details.</item>
+ </plurals>
+
</resources>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
index 432b406..6e0b56e2 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPinView.java
@@ -53,8 +53,13 @@
private ProgressDialog mSimUnlockProgressDialog = null;
private CheckSimPin mCheckSimPinThread;
+ // Below flag is set to true during power-up or when a new SIM card inserted on device.
+ // When this is true and when SIM card is PIN locked state, on PIN lock screen, message would
+ // be displayed to inform user about the number of remaining PIN attempts left.
+ private boolean mShowDefaultMessage = true;
+ private int mRemainingAttempts = -1;
private AlertDialog mRemainingAttemptsDialog;
- private int mSubId;
+ private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private ImageView mSimImageView;
KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
@@ -91,34 +96,71 @@
public void resetState() {
super.resetState();
if (DEBUG) Log.v(TAG, "Resetting state");
- KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
- mSubId = monitor.getNextSubIdForState(IccCardConstants.State.PIN_REQUIRED);
- boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
- if (SubscriptionManager.isValidSubscriptionId(mSubId)) {
- int count = TelephonyManager.getDefault().getSimCount();
- Resources rez = getResources();
- String msg;
- int color = Color.WHITE;
- if (count < 2) {
- msg = rez.getString(R.string.kg_sim_pin_instructions);
- } else {
- SubscriptionInfo info = monitor.getSubscriptionInfoForSubId(mSubId);
- CharSequence displayName = info != null ? info.getDisplayName() : ""; // don't crash
- msg = rez.getString(R.string.kg_sim_pin_instructions_multi, displayName);
- if (info != null) {
- color = info.getIconTint();
- }
- }
- if (isEsimLocked) {
- msg = msg + " " + rez.getString(R.string.kg_sim_lock_instructions_esim);
- }
- mSecurityMessageDisplay.setMessage(msg);
- mSimImageView.setImageTintList(ColorStateList.valueOf(color));
+ handleSubInfoChangeIfNeeded();
+ if (mShowDefaultMessage) {
+ showDefaultMessage();
}
+ boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
+
KeyguardEsimArea esimButton = findViewById(R.id.keyguard_esim_area);
esimButton.setVisibility(isEsimLocked ? View.VISIBLE : View.GONE);
}
+ private void showDefaultMessage() {
+ if (mRemainingAttempts >= 0) {
+ mSecurityMessageDisplay.setMessage(getPinPasswordErrorMessage(
+ mRemainingAttempts, true));
+ return;
+ }
+
+ boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
+ int count = TelephonyManager.getDefault().getSimCount();
+ Resources rez = getResources();
+ String msg;
+ int color = Color.WHITE;
+ if (count < 2) {
+ msg = rez.getString(R.string.kg_sim_pin_instructions);
+ } else {
+ SubscriptionInfo info = KeyguardUpdateMonitor.getInstance(mContext).
+ getSubscriptionInfoForSubId(mSubId);
+ CharSequence displayName = info != null ? info.getDisplayName() : ""; // don't crash
+ msg = rez.getString(R.string.kg_sim_pin_instructions_multi, displayName);
+ if (info != null) {
+ color = info.getIconTint();
+ }
+ }
+
+ if (isEsimLocked) {
+ msg = msg + " " + rez.getString(R.string.kg_sim_lock_instructions_esim);
+ }
+
+ mSecurityMessageDisplay.setMessage(msg);
+ mSimImageView.setImageTintList(ColorStateList.valueOf(color));
+
+ // Sending empty PIN here to query the number of remaining PIN attempts
+ new CheckSimPin("", mSubId) {
+ void onSimCheckResponse(final int result, final int attemptsRemaining) {
+ Log.d(LOG_TAG, "onSimCheckResponse " + " dummy One result" + result +
+ " attemptsRemaining=" + attemptsRemaining);
+ if (attemptsRemaining >= 0) {
+ mRemainingAttempts = attemptsRemaining;
+ mSecurityMessageDisplay.setMessage(
+ getPinPasswordErrorMessage(attemptsRemaining, true));
+ }
+ }
+ }.start();
+ }
+
+ private void handleSubInfoChangeIfNeeded() {
+ KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
+ int subId = monitor.getNextSubIdForState(IccCardConstants.State.PIN_REQUIRED);
+ if (subId != mSubId && SubscriptionManager.isValidSubscriptionId(subId)) {
+ mSubId = subId;
+ mShowDefaultMessage = true;
+ mRemainingAttempts = -1;
+ }
+ }
+
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
@@ -131,17 +173,19 @@
return 0;
}
- private String getPinPasswordErrorMessage(int attemptsRemaining) {
+ private String getPinPasswordErrorMessage(int attemptsRemaining, boolean isDefault) {
String displayMessage;
-
+ int msgId;
if (attemptsRemaining == 0) {
displayMessage = getContext().getString(R.string.kg_password_wrong_pin_code_pukked);
} else if (attemptsRemaining > 0) {
+ msgId = isDefault ? R.plurals.kg_password_default_pin_message :
+ R.plurals.kg_password_wrong_pin_code;
displayMessage = getContext().getResources()
- .getQuantityString(R.plurals.kg_password_wrong_pin_code, attemptsRemaining,
- attemptsRemaining);
+ .getQuantityString(msgId, attemptsRemaining, attemptsRemaining);
} else {
- displayMessage = getContext().getString(R.string.kg_password_pin_failed);
+ msgId = isDefault ? R.string.kg_sim_pin_instructions : R.string.kg_password_pin_failed;
+ displayMessage = getContext().getString(msgId);
}
if (DEBUG) Log.d(LOG_TAG, "getPinPasswordErrorMessage:"
+ " attemptsRemaining=" + attemptsRemaining + " displayMessage=" + displayMessage);
@@ -252,7 +296,7 @@
}
private Dialog getSimRemainingAttemptsDialog(int remaining) {
- String msg = getPinPasswordErrorMessage(remaining);
+ String msg = getPinPasswordErrorMessage(remaining, false);
if (mRemainingAttemptsDialog == null) {
Builder builder = new AlertDialog.Builder(mContext);
builder.setMessage(msg);
@@ -288,6 +332,7 @@
post(new Runnable() {
@Override
public void run() {
+ mRemainingAttempts = attemptsRemaining;
if (mSimUnlockProgressDialog != null) {
mSimUnlockProgressDialog.hide();
}
@@ -296,8 +341,13 @@
if (result == PhoneConstants.PIN_RESULT_SUCCESS) {
KeyguardUpdateMonitor.getInstance(getContext())
.reportSimUnlocked(mSubId);
- mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
+ mRemainingAttempts = -1;
+ mShowDefaultMessage = true;
+ if (mCallback != null) {
+ mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
+ }
} else {
+ mShowDefaultMessage = false;
if (result == PhoneConstants.PIN_PASSWORD_INCORRECT) {
if (attemptsRemaining <= 2) {
// this is getting critical - show dialog
@@ -305,7 +355,7 @@
} else {
// show message
mSecurityMessageDisplay.setMessage(
- getPinPasswordErrorMessage(attemptsRemaining));
+ getPinPasswordErrorMessage(attemptsRemaining, false));
}
} else {
// "PIN operation failed!" - no idea what this was and no way to
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
index 7f79008..876d170 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSimPukView.java
@@ -52,11 +52,17 @@
private ProgressDialog mSimUnlockProgressDialog = null;
private CheckSimPuk mCheckSimPukThread;
+
+ // Below flag is set to true during power-up or when a new SIM card inserted on device.
+ // When this is true and when SIM card is PUK locked state, on PIN lock screen, message would
+ // be displayed to inform user about the number of remaining PUK attempts left.
+ private boolean mShowDefaultMessage = true;
+ private int mRemainingAttempts = -1;
private String mPukText;
private String mPinText;
private StateMachine mStateMachine = new StateMachine();
private AlertDialog mRemainingAttemptsDialog;
- private int mSubId;
+ private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private ImageView mSimImageView;
KeyguardUpdateMonitorCallback mUpdateMonitorCallback = new KeyguardUpdateMonitorCallback() {
@@ -132,34 +138,17 @@
}
}
+
void reset() {
mPinText="";
mPukText="";
state = ENTER_PUK;
- KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
- mSubId = monitor.getNextSubIdForState(IccCardConstants.State.PUK_REQUIRED);
- boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
- if (SubscriptionManager.isValidSubscriptionId(mSubId)) {
- int count = TelephonyManager.getDefault().getSimCount();
- Resources rez = getResources();
- String msg;
- int color = Color.WHITE;
- if (count < 2) {
- msg = rez.getString(R.string.kg_puk_enter_puk_hint);
- } else {
- SubscriptionInfo info = monitor.getSubscriptionInfoForSubId(mSubId);
- CharSequence displayName = info != null ? info.getDisplayName() : "";
- msg = rez.getString(R.string.kg_puk_enter_puk_hint_multi, displayName);
- if (info != null) {
- color = info.getIconTint();
- }
- }
- if (isEsimLocked) {
- msg = msg + " " + rez.getString(R.string.kg_sim_lock_instructions_esim);
- }
- mSecurityMessageDisplay.setMessage(msg);
- mSimImageView.setImageTintList(ColorStateList.valueOf(color));
+ handleSubInfoChangeIfNeeded();
+ if (mShowDefaultMessage) {
+ showDefaultMessage();
}
+ boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
+
KeyguardEsimArea esimButton = findViewById(R.id.keyguard_esim_area);
esimButton.setVisibility(isEsimLocked ? View.VISIBLE : View.GONE);
mPasswordEntry.requestFocus();
@@ -168,23 +157,79 @@
}
+ private void showDefaultMessage() {
+ if (mRemainingAttempts >= 0) {
+ mSecurityMessageDisplay.setMessage(getPukPasswordErrorMessage(
+ mRemainingAttempts, true));
+ return;
+ }
+
+ boolean isEsimLocked = KeyguardEsimArea.isEsimLocked(mContext, mSubId);
+ int count = TelephonyManager.getDefault().getSimCount();
+ Resources rez = getResources();
+ String msg;
+ int color = Color.WHITE;
+ if (count < 2) {
+ msg = rez.getString(R.string.kg_puk_enter_puk_hint);
+ } else {
+ SubscriptionInfo info = KeyguardUpdateMonitor.getInstance(mContext).
+ getSubscriptionInfoForSubId(mSubId);
+ CharSequence displayName = info != null ? info.getDisplayName() : "";
+ msg = rez.getString(R.string.kg_puk_enter_puk_hint_multi, displayName);
+ if (info != null) {
+ color = info.getIconTint();
+ }
+ }
+ if (isEsimLocked) {
+ msg = msg + " " + rez.getString(R.string.kg_sim_lock_instructions_esim);
+ }
+ mSecurityMessageDisplay.setMessage(msg);
+ mSimImageView.setImageTintList(ColorStateList.valueOf(color));
+
+ // Sending empty PUK here to query the number of remaining PIN attempts
+ new CheckSimPuk("", "", mSubId) {
+ void onSimLockChangedResponse(final int result, final int attemptsRemaining) {
+ Log.d(LOG_TAG, "onSimCheckResponse " + " dummy One result" + result +
+ " attemptsRemaining=" + attemptsRemaining);
+ if (attemptsRemaining >= 0) {
+ mRemainingAttempts = attemptsRemaining;
+ mSecurityMessageDisplay.setMessage(
+ getPukPasswordErrorMessage(attemptsRemaining, true));
+ }
+ }
+ }.start();
+ }
+
+ private void handleSubInfoChangeIfNeeded() {
+ KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext);
+ int subId = monitor.getNextSubIdForState(IccCardConstants.State.PUK_REQUIRED);
+ if (subId != mSubId && SubscriptionManager.isValidSubscriptionId(subId)) {
+ mSubId = subId;
+ mShowDefaultMessage = true;
+ mRemainingAttempts = -1;
+ }
+ }
+
@Override
protected int getPromtReasonStringRes(int reason) {
// No message on SIM Puk
return 0;
}
- private String getPukPasswordErrorMessage(int attemptsRemaining) {
+ private String getPukPasswordErrorMessage(int attemptsRemaining, boolean isDefault) {
String displayMessage;
if (attemptsRemaining == 0) {
displayMessage = getContext().getString(R.string.kg_password_wrong_puk_code_dead);
} else if (attemptsRemaining > 0) {
+ int msgId = isDefault ? R.plurals.kg_password_default_puk_message :
+ R.plurals.kg_password_wrong_puk_code;
displayMessage = getContext().getResources()
- .getQuantityString(R.plurals.kg_password_wrong_puk_code, attemptsRemaining,
- attemptsRemaining);
+ .getQuantityString(msgId, attemptsRemaining, attemptsRemaining);
} else {
- displayMessage = getContext().getString(R.string.kg_password_puk_failed);
+ int msgId = isDefault ? R.string.kg_puk_enter_puk_hint :
+ R.string.kg_password_puk_failed;
+ displayMessage = getContext().getString(msgId);
}
if (DEBUG) Log.d(LOG_TAG, "getPukPasswordErrorMessage:"
+ " attemptsRemaining=" + attemptsRemaining + " displayMessage=" + displayMessage);
@@ -303,7 +348,7 @@
}
private Dialog getPukRemainingAttemptsDialog(int remaining) {
- String msg = getPukPasswordErrorMessage(remaining);
+ String msg = getPukPasswordErrorMessage(remaining, false);
if (mRemainingAttemptsDialog == null) {
AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
builder.setMessage(msg);
@@ -359,16 +404,25 @@
if (result == PhoneConstants.PIN_RESULT_SUCCESS) {
KeyguardUpdateMonitor.getInstance(getContext())
.reportSimUnlocked(mSubId);
- mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
+ mRemainingAttempts = -1;
+ mShowDefaultMessage = true;
+ if (mCallback != null) {
+ mCallback.dismiss(true, KeyguardUpdateMonitor.getCurrentUser());
+ }
} else {
+ mShowDefaultMessage = false;
if (result == PhoneConstants.PIN_PASSWORD_INCORRECT) {
+ // show message
+ mSecurityMessageDisplay.setMessage(getPukPasswordErrorMessage(
+ attemptsRemaining, false));
if (attemptsRemaining <= 2) {
// this is getting critical - show dialog
getPukRemainingAttemptsDialog(attemptsRemaining).show();
} else {
// show message
mSecurityMessageDisplay.setMessage(
- getPukPasswordErrorMessage(attemptsRemaining));
+ getPukPasswordErrorMessage(
+ attemptsRemaining, false));
}
} else {
mSecurityMessageDisplay.setMessage(getContext().getString(
diff --git a/services/Android.bp b/services/Android.bp
new file mode 100644
index 0000000..84c45fe
--- /dev/null
+++ b/services/Android.bp
@@ -0,0 +1,8 @@
+// native library
+// =============================================================
+
+cc_library_shared {
+ name: "libandroid_servers",
+ defaults: ["libservices.core-libs"],
+ whole_static_libs: ["libservices.core"],
+}
diff --git a/services/Android.mk b/services/Android.mk
index ed2ba1f8..81d8181 100644
--- a/services/Android.mk
+++ b/services/Android.mk
@@ -52,23 +52,6 @@
include $(BUILD_JAVA_LIBRARY)
-# native library
-# =============================================================
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES :=
-LOCAL_SHARED_LIBRARIES :=
-
-# include all the jni subdirs to collect their sources
-include $(wildcard $(LOCAL_PATH)/*/jni/Android.mk)
-
-LOCAL_CFLAGS += -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES
-
-LOCAL_MODULE:= libandroid_servers
-
-include $(BUILD_SHARED_LIBRARY)
-
# =============================================================
ifeq (,$(ONE_SHOT_MAKEFILE))
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 763a4e4..d9713a5 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -1628,7 +1628,7 @@
//Do enable request
try {
- if (mQuietEnable) {
+ if (!mQuietEnable) {
if (!mBluetooth.enable()) {
Slog.e(TAG, "IBluetooth.enable() returned false");
}
diff --git a/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java b/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
index 28c3585..bd2e96e 100644
--- a/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
+++ b/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
@@ -51,6 +51,7 @@
// Information about the current status of the default network.
@GuardedBy("this")
private DefaultNetworkEvent mCurrentDefaultNetwork;
+ // True if the current default network has been validated.
@GuardedBy("this")
private boolean mIsCurrentlyValid;
@GuardedBy("this")
@@ -71,6 +72,8 @@
printEvent(localTimeMs, pw, ev);
}
mCurrentDefaultNetwork.updateDuration(timeMs);
+ // When printing default network events for bug reports, update validation time
+ // and refresh the last validation timestmap for future validation time updates.
if (mIsCurrentlyValid) {
updateValidationTime(timeMs);
mLastValidationTimeMs = timeMs;
@@ -92,11 +95,13 @@
}
public synchronized void logDefaultNetworkValidity(long timeMs, boolean isValid) {
+ // Transition from valid to invalid: update validity duration since last update
if (!isValid && mIsCurrentlyValid) {
mIsCurrentlyValid = false;
updateValidationTime(timeMs);
}
+ // Transition from invalid to valid: simply mark the validation timestamp.
if (isValid && !mIsCurrentlyValid) {
mIsCurrentlyValid = true;
mLastValidationTimeMs = timeMs;
@@ -114,6 +119,9 @@
}
private void logCurrentDefaultNetwork(long timeMs, NetworkAgentInfo oldNai) {
+ if (mIsCurrentlyValid) {
+ updateValidationTime(timeMs);
+ }
DefaultNetworkEvent ev = mCurrentDefaultNetwork;
ev.updateDuration(timeMs);
ev.previousTransports = mLastTransports;
@@ -122,7 +130,6 @@
// The system acquired a new default network.
fillLinkInfo(ev, oldNai);
ev.finalScore = oldNai.getCurrentScore();
- ev.validatedMs = ev.durationMs;
}
// Only change transport of the previous default network if the event currently logged
// corresponds to an existing default network, and not to the absence of a default network.
@@ -143,9 +150,10 @@
fillLinkInfo(ev, newNai);
ev.initialScore = newNai.getCurrentScore();
if (newNai.lastValidated) {
- mIsCurrentlyValid = true;
- mLastValidationTimeMs = timeMs;
+ logDefaultNetworkValidity(timeMs, true);
}
+ } else {
+ mIsCurrentlyValid = false;
}
mCurrentDefaultNetwork = ev;
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 920deb9..08c8813 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -14629,14 +14629,13 @@
if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
return null;
}
- // writer
- synchronized (mPackages) {
- if (!isExternalMediaAvailable()) {
+ if (!isExternalMediaAvailable()) {
// If the external storage is no longer mounted at this point,
// the caller may not have been able to delete all of this
// packages files and can not delete any more. Bail.
- return null;
- }
+ return null;
+ }
+ synchronized (mPackages) {
final ArrayList<PackageCleanItem> pkgs = mSettings.mPackagesToBeCleaned;
if (lastPackage != null) {
pkgs.remove(lastPackage);
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
new file mode 100644
index 0000000..27acaee
--- /dev/null
+++ b/services/core/jni/Android.bp
@@ -0,0 +1,121 @@
+cc_library_static {
+ name: "libservices.core",
+ defaults: ["libservices.core-libs"],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-parameter",
+
+ "-DEGL_EGLEXT_PROTOTYPES",
+ "-DGL_GLEXT_PROTOTYPES",
+ ],
+
+ srcs: [
+ "BroadcastRadio/JavaRef.cpp",
+ "BroadcastRadio/NativeCallbackThread.cpp",
+ "BroadcastRadio/BroadcastRadioService.cpp",
+ "BroadcastRadio/Tuner.cpp",
+ "BroadcastRadio/TunerCallback.cpp",
+ "BroadcastRadio/convert.cpp",
+ "BroadcastRadio/regions.cpp",
+ "com_android_server_AlarmManagerService.cpp",
+ "com_android_server_am_BatteryStatsService.cpp",
+ "com_android_server_connectivity_Vpn.cpp",
+ "com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp",
+ "com_android_server_ConsumerIrService.cpp",
+ "com_android_server_HardwarePropertiesManagerService.cpp",
+ "com_android_server_hdmi_HdmiCecController.cpp",
+ "com_android_server_input_InputApplicationHandle.cpp",
+ "com_android_server_input_InputManagerService.cpp",
+ "com_android_server_input_InputWindowHandle.cpp",
+ "com_android_server_lights_LightsService.cpp",
+ "com_android_server_location_ContextHubService.cpp",
+ "com_android_server_location_GnssLocationProvider.cpp",
+ "com_android_server_locksettings_SyntheticPasswordManager.cpp",
+ "com_android_server_power_PowerManagerService.cpp",
+ "com_android_server_SerialService.cpp",
+ "com_android_server_storage_AppFuseBridge.cpp",
+ "com_android_server_SystemServer.cpp",
+ "com_android_server_tv_TvUinputBridge.cpp",
+ "com_android_server_tv_TvInputHal.cpp",
+ "com_android_server_vr_VrManagerService.cpp",
+ "com_android_server_UsbDeviceManager.cpp",
+ "com_android_server_UsbDescriptorParser.cpp",
+ "com_android_server_UsbMidiDevice.cpp",
+ "com_android_server_UsbHostManager.cpp",
+ "com_android_server_VibratorService.cpp",
+ "com_android_server_PersistentDataBlockService.cpp",
+ "com_android_server_GraphicsStatsService.cpp",
+ "onload.cpp",
+ ],
+
+ include_dirs: [
+ "frameworks/base/libs",
+ "frameworks/native/services",
+ "system/gatekeeper/include",
+ ],
+}
+
+cc_defaults {
+ name: "libservices.core-libs",
+ shared_libs: [
+ "libandroid_runtime",
+ "libandroidfw",
+ "libaudioclient",
+ "libbase",
+ "libappfuse",
+ "libbinder",
+ "libcutils",
+ "libcrypto",
+ "liblog",
+ "libhardware",
+ "libhardware_legacy",
+ "libhidlbase",
+ "libkeystore_binder",
+ "libnativehelper",
+ "libutils",
+ "libui",
+ "libinput",
+ "libinputflinger",
+ "libinputservice",
+ "libschedulerservicehidl",
+ "libsensorservice",
+ "libsensorservicehidl",
+ "libskia",
+ "libgui",
+ "libusbhost",
+ "libsuspend",
+ "libEGL",
+ "libGLESv2",
+ "libnetutils",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ "libhwui",
+ "android.hardware.audio.common@2.0",
+ "android.hardware.broadcastradio@1.0",
+ "android.hardware.broadcastradio@1.1",
+ "android.hardware.contexthub@1.0",
+ "android.hardware.gnss@1.0",
+ "android.hardware.ir@1.0",
+ "android.hardware.light@2.0",
+ "android.hardware.power@1.0",
+ "android.hardware.power@1.1",
+ "android.hardware.tetheroffload.config@1.0",
+ "android.hardware.thermal@1.0",
+ "android.hardware.tv.cec@1.0",
+ "android.hardware.tv.input@1.0",
+ "android.hardware.vibrator@1.0",
+ "android.hardware.vibrator@1.1",
+ "android.hardware.vr@1.0",
+ "android.frameworks.schedulerservice@1.0",
+ "android.frameworks.sensorservice@1.0",
+ ],
+
+ static_libs: [
+ "android.hardware.broadcastradio@1.1-utils-lib",
+ "libscrypt_static",
+ ],
+}
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
deleted file mode 100644
index bf9f941..0000000
--- a/services/core/jni/Android.mk
+++ /dev/null
@@ -1,114 +0,0 @@
-# This file is included by the top level services directory to collect source
-# files
-LOCAL_REL_DIR := core/jni
-
-LOCAL_CFLAGS += -Wall -Werror -Wno-unused-parameter
-
-LOCAL_SRC_FILES += \
- $(LOCAL_REL_DIR)/BroadcastRadio/JavaRef.cpp \
- $(LOCAL_REL_DIR)/BroadcastRadio/NativeCallbackThread.cpp \
- $(LOCAL_REL_DIR)/BroadcastRadio/BroadcastRadioService.cpp \
- $(LOCAL_REL_DIR)/BroadcastRadio/Tuner.cpp \
- $(LOCAL_REL_DIR)/BroadcastRadio/TunerCallback.cpp \
- $(LOCAL_REL_DIR)/BroadcastRadio/convert.cpp \
- $(LOCAL_REL_DIR)/BroadcastRadio/regions.cpp \
- $(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \
- $(LOCAL_REL_DIR)/com_android_server_am_BatteryStatsService.cpp \
- $(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \
- $(LOCAL_REL_DIR)/com_android_server_connectivity_tethering_OffloadHardwareInterface.cpp \
- $(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \
- $(LOCAL_REL_DIR)/com_android_server_HardwarePropertiesManagerService.cpp \
- $(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecController.cpp \
- $(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \
- $(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \
- $(LOCAL_REL_DIR)/com_android_server_input_InputWindowHandle.cpp \
- $(LOCAL_REL_DIR)/com_android_server_lights_LightsService.cpp \
- $(LOCAL_REL_DIR)/com_android_server_location_ContextHubService.cpp \
- $(LOCAL_REL_DIR)/com_android_server_location_GnssLocationProvider.cpp \
- $(LOCAL_REL_DIR)/com_android_server_locksettings_SyntheticPasswordManager.cpp \
- $(LOCAL_REL_DIR)/com_android_server_power_PowerManagerService.cpp \
- $(LOCAL_REL_DIR)/com_android_server_SerialService.cpp \
- $(LOCAL_REL_DIR)/com_android_server_storage_AppFuseBridge.cpp \
- $(LOCAL_REL_DIR)/com_android_server_SystemServer.cpp \
- $(LOCAL_REL_DIR)/com_android_server_tv_TvUinputBridge.cpp \
- $(LOCAL_REL_DIR)/com_android_server_tv_TvInputHal.cpp \
- $(LOCAL_REL_DIR)/com_android_server_vr_VrManagerService.cpp \
- $(LOCAL_REL_DIR)/com_android_server_UsbDeviceManager.cpp \
- $(LOCAL_REL_DIR)/com_android_server_UsbDescriptorParser.cpp \
- $(LOCAL_REL_DIR)/com_android_server_UsbMidiDevice.cpp \
- $(LOCAL_REL_DIR)/com_android_server_UsbHostManager.cpp \
- $(LOCAL_REL_DIR)/com_android_server_VibratorService.cpp \
- $(LOCAL_REL_DIR)/com_android_server_PersistentDataBlockService.cpp \
- $(LOCAL_REL_DIR)/com_android_server_GraphicsStatsService.cpp \
- $(LOCAL_REL_DIR)/onload.cpp
-
-LOCAL_C_INCLUDES += \
- $(JNI_H_INCLUDE) \
- external/scrypt/lib/crypto \
- frameworks/base/services \
- frameworks/base/libs \
- frameworks/base/core/jni \
- frameworks/native/services \
- system/core/libappfuse/include \
- system/gatekeeper/include \
- system/security/keystore/include \
- $(call include-path-for, libhardware)/hardware \
- $(call include-path-for, libhardware_legacy)/hardware_legacy \
-
-LOCAL_SHARED_LIBRARIES += \
- libandroid_runtime \
- libandroidfw \
- libaudioclient \
- libbase \
- libappfuse \
- libbinder \
- libcutils \
- libcrypto \
- liblog \
- libhardware \
- libhardware_legacy \
- libhidlbase \
- libkeystore_binder \
- libnativehelper \
- libutils \
- libui \
- libinput \
- libinputflinger \
- libinputservice \
- libschedulerservicehidl \
- libsensorservice \
- libsensorservicehidl \
- libskia \
- libgui \
- libusbhost \
- libsuspend \
- libEGL \
- libGLESv2 \
- libnetutils \
- libhidlbase \
- libhidltransport \
- libhwbinder \
- libutils \
- libhwui \
- android.hardware.audio.common@2.0 \
- android.hardware.broadcastradio@1.0 \
- android.hardware.broadcastradio@1.1 \
- android.hardware.contexthub@1.0 \
- android.hardware.gnss@1.0 \
- android.hardware.ir@1.0 \
- android.hardware.light@2.0 \
- android.hardware.power@1.0 \
- android.hardware.power@1.1 \
- android.hardware.tetheroffload.config@1.0 \
- android.hardware.thermal@1.0 \
- android.hardware.tv.cec@1.0 \
- android.hardware.tv.input@1.0 \
- android.hardware.vibrator@1.0 \
- android.hardware.vibrator@1.1 \
- android.hardware.vr@1.0 \
- android.frameworks.schedulerservice@1.0 \
- android.frameworks.sensorservice@1.0 \
-
-LOCAL_STATIC_LIBRARIES += \
- android.hardware.broadcastradio@1.1-utils-lib \
- libscrypt_static \
diff --git a/services/net/java/android/net/ip/ConnectivityPacketTracker.java b/services/net/java/android/net/ip/ConnectivityPacketTracker.java
index 1925c39..6cf4fa9a 100644
--- a/services/net/java/android/net/ip/ConnectivityPacketTracker.java
+++ b/services/net/java/android/net/ip/ConnectivityPacketTracker.java
@@ -19,7 +19,7 @@
import static android.system.OsConstants.*;
import android.net.NetworkUtils;
-import android.net.util.BlockingSocketReader;
+import android.net.util.PacketReader;
import android.net.util.ConnectivityPacketSummary;
import android.os.Handler;
import android.system.ErrnoException;
@@ -65,7 +65,7 @@
private final String mTag;
private final LocalLog mLog;
- private final BlockingSocketReader mPacketListener;
+ private final PacketReader mPacketListener;
private boolean mRunning;
private String mDisplayName;
@@ -101,7 +101,7 @@
mDisplayName = null;
}
- private final class PacketListener extends BlockingSocketReader {
+ private final class PacketListener extends PacketReader {
private final int mIfIndex;
private final byte mHwAddr[];
diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java
index 70983c8..fdb366c 100644
--- a/services/net/java/android/net/ip/IpClient.java
+++ b/services/net/java/android/net/ip/IpClient.java
@@ -815,6 +815,15 @@
pw.println(Objects.toString(provisioningConfig, "N/A"));
pw.decreaseIndent();
+ final IpReachabilityMonitor iprm = mIpReachabilityMonitor;
+ if (iprm != null) {
+ pw.println();
+ pw.println(mTag + " current IpReachabilityMonitor state:");
+ pw.increaseIndent();
+ iprm.dump(pw);
+ pw.decreaseIndent();
+ }
+
pw.println();
pw.println(mTag + " StateMachine dump:");
pw.increaseIndent();
@@ -1237,6 +1246,7 @@
mIpReachabilityMonitor = new IpReachabilityMonitor(
mContext,
mInterfaceName,
+ getHandler(),
mLog,
new IpReachabilityMonitor.Callback() {
@Override
diff --git a/services/net/java/android/net/ip/IpNeighborMonitor.java b/services/net/java/android/net/ip/IpNeighborMonitor.java
new file mode 100644
index 0000000..6807334
--- /dev/null
+++ b/services/net/java/android/net/ip/IpNeighborMonitor.java
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2017 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.net.ip;
+
+import android.net.netlink.NetlinkConstants;
+import android.net.netlink.NetlinkErrorMessage;
+import android.net.netlink.NetlinkMessage;
+import android.net.netlink.NetlinkSocket;
+import android.net.netlink.RtNetlinkNeighborMessage;
+import android.net.netlink.StructNdMsg;
+import android.net.netlink.StructNlMsgHdr;
+import android.net.util.PacketReader;
+import android.net.util.SharedLog;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.system.ErrnoException;
+import android.system.NetlinkSocketAddress;
+import android.system.Os;
+import android.system.OsConstants;
+import android.util.Log;
+
+import com.android.internal.util.BitUtils;
+
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+
+import java.io.FileDescriptor;
+import java.net.InetAddress;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.StringJoiner;
+
+
+/**
+ * IpNeighborMonitor.
+ *
+ * Monitors the kernel rtnetlink neighbor notifications and presents to callers
+ * NeighborEvents describing each event. Callers can provide a consumer instance
+ * to both filter (e.g. by interface index and IP address) and handle the
+ * generated NeighborEvents.
+ *
+ * @hide
+ */
+public class IpNeighborMonitor extends PacketReader {
+ private static final String TAG = IpNeighborMonitor.class.getSimpleName();
+ private static final boolean DBG = false;
+ private static final boolean VDBG = false;
+
+ /**
+ * Make the kernel perform neighbor reachability detection (IPv4 ARP or IPv6 ND)
+ * for the given IP address on the specified interface index.
+ *
+ * @return 0 if the request was successfully passed to the kernel; otherwise return
+ * a non-zero error code.
+ */
+ public static int startKernelNeighborProbe(int ifIndex, InetAddress ip) {
+ final String msgSnippet = "probing ip=" + ip.getHostAddress() + "%" + ifIndex;
+ if (DBG) { Log.d(TAG, msgSnippet); }
+
+ final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage(
+ 1, ip, StructNdMsg.NUD_PROBE, ifIndex, null);
+
+ try {
+ NetlinkSocket.sendOneShotKernelMessage(OsConstants.NETLINK_ROUTE, msg);
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Error " + msgSnippet + ": " + e);
+ return -e.errno;
+ }
+
+ return 0;
+ }
+
+ public static class NeighborEvent {
+ final long elapsedMs;
+ final short msgType;
+ final int ifindex;
+ final InetAddress ip;
+ final short nudState;
+ final byte[] linkLayerAddr;
+
+ public NeighborEvent(long elapsedMs, short msgType, int ifindex, InetAddress ip,
+ short nudState, byte[] linkLayerAddr) {
+ this.elapsedMs = elapsedMs;
+ this.msgType = msgType;
+ this.ifindex = ifindex;
+ this.ip = ip;
+ this.nudState = nudState;
+ this.linkLayerAddr = linkLayerAddr;
+ }
+
+ boolean isConnected() {
+ return (msgType != NetlinkConstants.RTM_DELNEIGH) &&
+ StructNdMsg.isNudStateConnected(nudState);
+ }
+
+ boolean isValid() {
+ return (msgType != NetlinkConstants.RTM_DELNEIGH) &&
+ StructNdMsg.isNudStateValid(nudState);
+ }
+
+ @Override
+ public String toString() {
+ final StringJoiner j = new StringJoiner(",", "NeighborEvent{", "}");
+ return j.add("@" + elapsedMs)
+ .add(NetlinkConstants.stringForNlMsgType(msgType))
+ .add("if=" + ifindex)
+ .add(ip.getHostAddress())
+ .add(StructNdMsg.stringForNudState(nudState))
+ .add("[" + NetlinkConstants.hexify(linkLayerAddr) + "]")
+ .toString();
+ }
+ }
+
+ public interface NeighborEventConsumer {
+ // Every neighbor event received on the netlink socket is passed in
+ // here. Subclasses should filter for events of interest.
+ public void accept(NeighborEvent event);
+ }
+
+ private final SharedLog mLog;
+ private final NeighborEventConsumer mConsumer;
+
+ public IpNeighborMonitor(Handler h, SharedLog log, NeighborEventConsumer cb) {
+ super(h, NetlinkSocket.DEFAULT_RECV_BUFSIZE);
+ mLog = log.forSubComponent(TAG);
+ mConsumer = (cb != null) ? cb : (event) -> { /* discard */ };
+ }
+
+ @Override
+ protected FileDescriptor createFd() {
+ FileDescriptor fd = null;
+
+ try {
+ fd = NetlinkSocket.forProto(OsConstants.NETLINK_ROUTE);
+ Os.bind(fd, (SocketAddress)(new NetlinkSocketAddress(0, OsConstants.RTMGRP_NEIGH)));
+ Os.connect(fd, (SocketAddress)(new NetlinkSocketAddress(0, 0)));
+
+ if (VDBG) {
+ final NetlinkSocketAddress nlAddr = (NetlinkSocketAddress) Os.getsockname(fd);
+ Log.d(TAG, "bound to sockaddr_nl{"
+ + BitUtils.uint32(nlAddr.getPortId()) + ", "
+ + nlAddr.getGroupsMask()
+ + "}");
+ }
+ } catch (ErrnoException|SocketException e) {
+ logError("Failed to create rtnetlink socket", e);
+ IoUtils.closeQuietly(fd);
+ return null;
+ }
+
+ return fd;
+ }
+
+ @Override
+ protected void handlePacket(byte[] recvbuf, int length) {
+ final long whenMs = SystemClock.elapsedRealtime();
+
+ final ByteBuffer byteBuffer = ByteBuffer.wrap(recvbuf, 0, length);
+ byteBuffer.order(ByteOrder.nativeOrder());
+
+ parseNetlinkMessageBuffer(byteBuffer, whenMs);
+ }
+
+ private void parseNetlinkMessageBuffer(ByteBuffer byteBuffer, long whenMs) {
+ while (byteBuffer.remaining() > 0) {
+ final int position = byteBuffer.position();
+ final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer);
+ if (nlMsg == null || nlMsg.getHeader() == null) {
+ byteBuffer.position(position);
+ mLog.e("unparsable netlink msg: " + NetlinkConstants.hexify(byteBuffer));
+ break;
+ }
+
+ final int srcPortId = nlMsg.getHeader().nlmsg_pid;
+ if (srcPortId != 0) {
+ mLog.e("non-kernel source portId: " + BitUtils.uint32(srcPortId));
+ break;
+ }
+
+ if (nlMsg instanceof NetlinkErrorMessage) {
+ mLog.e("netlink error: " + nlMsg);
+ continue;
+ } else if (!(nlMsg instanceof RtNetlinkNeighborMessage)) {
+ mLog.i("non-rtnetlink neighbor msg: " + nlMsg);
+ continue;
+ }
+
+ evaluateRtNetlinkNeighborMessage((RtNetlinkNeighborMessage) nlMsg, whenMs);
+ }
+ }
+
+ private void evaluateRtNetlinkNeighborMessage(
+ RtNetlinkNeighborMessage neighMsg, long whenMs) {
+ final short msgType = neighMsg.getHeader().nlmsg_type;
+ final StructNdMsg ndMsg = neighMsg.getNdHeader();
+ if (ndMsg == null) {
+ mLog.e("RtNetlinkNeighborMessage without ND message header!");
+ return;
+ }
+
+ final int ifindex = ndMsg.ndm_ifindex;
+ final InetAddress destination = neighMsg.getDestination();
+ final short nudState =
+ (msgType == NetlinkConstants.RTM_DELNEIGH)
+ ? StructNdMsg.NUD_NONE
+ : ndMsg.ndm_state;
+
+ final NeighborEvent event = new NeighborEvent(
+ whenMs, msgType, ifindex, destination, nudState, neighMsg.getLinkLayerAddress());
+
+ if (VDBG) {
+ Log.d(TAG, neighMsg.toString());
+ }
+ if (DBG) {
+ Log.d(TAG, event.toString());
+ }
+
+ mConsumer.accept(event);
+ }
+}
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index 714b35a..b31ffbb 100644
--- a/services/net/java/android/net/ip/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -22,30 +22,27 @@
import android.net.LinkProperties.ProvisioningChange;
import android.net.ProxyInfo;
import android.net.RouteInfo;
+import android.net.ip.IpNeighborMonitor.NeighborEvent;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.IpReachabilityEvent;
-import android.net.netlink.NetlinkConstants;
-import android.net.netlink.NetlinkErrorMessage;
-import android.net.netlink.NetlinkMessage;
-import android.net.netlink.NetlinkSocket;
-import android.net.netlink.RtNetlinkNeighborMessage;
import android.net.netlink.StructNdMsg;
-import android.net.netlink.StructNdaCacheInfo;
-import android.net.netlink.StructNlMsgHdr;
import android.net.util.MultinetworkPolicyTracker;
import android.net.util.SharedLog;
+import android.os.Handler;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.SystemClock;
import android.system.ErrnoException;
-import android.system.NetlinkSocketAddress;
import android.system.OsConstants;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.util.DumpUtils.Dump;
import java.io.InterruptedIOException;
+import java.io.PrintWriter;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
@@ -134,6 +131,8 @@
* state it may be best for the link to disconnect completely and
* reconnect afresh.
*
+ * Accessing an instance of this class from multiple threads is NOT safe.
+ *
* @hide
*/
public class IpReachabilityMonitor {
@@ -169,64 +168,33 @@
}
}
- private final Object mLock = new Object();
private final String mInterfaceName;
private final int mInterfaceIndex;
+ private final IpNeighborMonitor mIpNeighborMonitor;
private final SharedLog mLog;
private final Callback mCallback;
private final Dependencies mDependencies;
private final MultinetworkPolicyTracker mMultinetworkPolicyTracker;
- private final NetlinkSocketObserver mNetlinkSocketObserver;
- private final Thread mObserverThread;
private final IpConnectivityLog mMetricsLog = new IpConnectivityLog();
- @GuardedBy("mLock")
private LinkProperties mLinkProperties = new LinkProperties();
- // TODO: consider a map to a private NeighborState class holding more
- // information than a single NUD state entry.
- @GuardedBy("mLock")
- private Map<InetAddress, Short> mIpWatchList = new HashMap<>();
- @GuardedBy("mLock")
- private int mIpWatchListVersion;
- private volatile boolean mRunning;
+ private Map<InetAddress, NeighborEvent> mNeighborWatchList = new HashMap<>();
// Time in milliseconds of the last forced probe request.
private volatile long mLastProbeTimeMs;
- /**
- * Make the kernel perform neighbor reachability detection (IPv4 ARP or IPv6 ND)
- * for the given IP address on the specified interface index.
- *
- * @return 0 if the request was successfully passed to the kernel; otherwise return
- * a non-zero error code.
- */
- private static int probeNeighbor(int ifIndex, InetAddress ip) {
- final String msgSnippet = "probing ip=" + ip.getHostAddress() + "%" + ifIndex;
- if (DBG) { Log.d(TAG, msgSnippet); }
-
- final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage(
- 1, ip, StructNdMsg.NUD_PROBE, ifIndex, null);
-
- try {
- NetlinkSocket.sendOneShotKernelMessage(OsConstants.NETLINK_ROUTE, msg);
- } catch (ErrnoException e) {
- Log.e(TAG, "Error " + msgSnippet + ": " + e);
- return -e.errno;
- }
-
- return 0;
+ public IpReachabilityMonitor(
+ Context context, String ifName, Handler h, SharedLog log, Callback callback) {
+ this(context, ifName, h, log, callback, null);
}
- public IpReachabilityMonitor(Context context, String ifName, SharedLog log, Callback callback) {
- this(context, ifName, log, callback, null);
- }
-
- public IpReachabilityMonitor(Context context, String ifName, SharedLog log, Callback callback,
+ public IpReachabilityMonitor(
+ Context context, String ifName, Handler h, SharedLog log, Callback callback,
MultinetworkPolicyTracker tracker) {
- this(ifName, getInterfaceIndex(ifName), log, callback, tracker,
+ this(ifName, getInterfaceIndex(ifName), h, log, callback, tracker,
Dependencies.makeDefault(context, ifName));
}
@VisibleForTesting
- IpReachabilityMonitor(String ifName, int ifIndex, SharedLog log, Callback callback,
+ IpReachabilityMonitor(String ifName, int ifIndex, Handler h, SharedLog log, Callback callback,
MultinetworkPolicyTracker tracker, Dependencies dependencies) {
mInterfaceName = ifName;
mLog = log.forSubComponent(TAG);
@@ -234,47 +202,56 @@
mMultinetworkPolicyTracker = tracker;
mInterfaceIndex = ifIndex;
mDependencies = dependencies;
- mNetlinkSocketObserver = new NetlinkSocketObserver();
- mObserverThread = new Thread(mNetlinkSocketObserver);
- mObserverThread.start();
+
+ mIpNeighborMonitor = new IpNeighborMonitor(h, mLog,
+ (NeighborEvent event) -> {
+ if (mInterfaceIndex != event.ifindex) return;
+ if (!mNeighborWatchList.containsKey(event.ip)) return;
+
+ final NeighborEvent prev = mNeighborWatchList.put(event.ip, event);
+
+ // TODO: Consider what to do with other states that are not within
+ // NeighborEvent#isValid() (i.e. NUD_NONE, NUD_INCOMPLETE).
+ if (event.nudState == StructNdMsg.NUD_FAILED) {
+ mLog.w("ALERT neighbor went from: " + prev + " to: " + event);
+ handleNeighborLost(event);
+ }
+ });
+ mIpNeighborMonitor.start();
}
public void stop() {
- mRunning = false;
+ mIpNeighborMonitor.stop();
clearLinkProperties();
- mNetlinkSocketObserver.clearNetlinkSocket();
}
- // TODO: add a public dump() method that can be called during a bug report.
+ public void dump(PrintWriter pw) {
+ DumpUtils.dumpAsync(
+ mIpNeighborMonitor.getHandler(),
+ new Dump() {
+ @Override
+ public void dump(PrintWriter pw, String prefix) {
+ pw.println(describeWatchList("\n"));
+ }
+ },
+ pw, "", 1000);
+ }
- private String describeWatchList() {
- final String delimiter = ", ";
- StringBuilder sb = new StringBuilder();
- synchronized (mLock) {
- sb.append("iface{" + mInterfaceName + "/" + mInterfaceIndex + "}, ");
- sb.append("v{" + mIpWatchListVersion + "}, ");
- sb.append("ntable=[");
- boolean firstTime = true;
- for (Map.Entry<InetAddress, Short> entry : mIpWatchList.entrySet()) {
- if (firstTime) {
- firstTime = false;
- } else {
- sb.append(delimiter);
- }
- sb.append(entry.getKey().getHostAddress() + "/" +
- StructNdMsg.stringForNudState(entry.getValue()));
- }
- sb.append("]");
+ private String describeWatchList() { return describeWatchList(" "); }
+
+ private String describeWatchList(String sep) {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("iface{" + mInterfaceName + "/" + mInterfaceIndex + "}," + sep);
+ sb.append("ntable=[" + sep);
+ String delimiter = "";
+ for (Map.Entry<InetAddress, NeighborEvent> entry : mNeighborWatchList.entrySet()) {
+ sb.append(delimiter).append(entry.getKey().getHostAddress() + "/" + entry.getValue());
+ delimiter = "," + sep;
}
+ sb.append("]");
return sb.toString();
}
- private boolean isWatching(InetAddress ip) {
- synchronized (mLock) {
- return mRunning && mIpWatchList.containsKey(ip);
- }
- }
-
private static boolean isOnLink(List<RouteInfo> routes, InetAddress ip) {
for (RouteInfo route : routes) {
if (!route.hasGateway() && route.matches(ip)) {
@@ -284,13 +261,6 @@
return false;
}
- private short getNeighborStateLocked(InetAddress ip) {
- if (mIpWatchList.containsKey(ip)) {
- return mIpWatchList.get(ip);
- }
- return StructNdMsg.NUD_NONE;
- }
-
public void updateLinkProperties(LinkProperties lp) {
if (!mInterfaceName.equals(lp.getInterfaceName())) {
// TODO: figure out whether / how to cope with interface changes.
@@ -299,70 +269,63 @@
return;
}
- synchronized (mLock) {
- mLinkProperties = new LinkProperties(lp);
- Map<InetAddress, Short> newIpWatchList = new HashMap<>();
+ mLinkProperties = new LinkProperties(lp);
+ Map<InetAddress, NeighborEvent> newNeighborWatchList = new HashMap<>();
- final List<RouteInfo> routes = mLinkProperties.getRoutes();
- for (RouteInfo route : routes) {
- if (route.hasGateway()) {
- InetAddress gw = route.getGateway();
- if (isOnLink(routes, gw)) {
- newIpWatchList.put(gw, getNeighborStateLocked(gw));
- }
+ final List<RouteInfo> routes = mLinkProperties.getRoutes();
+ for (RouteInfo route : routes) {
+ if (route.hasGateway()) {
+ InetAddress gw = route.getGateway();
+ if (isOnLink(routes, gw)) {
+ newNeighborWatchList.put(gw, mNeighborWatchList.getOrDefault(gw, null));
}
}
-
- for (InetAddress nameserver : lp.getDnsServers()) {
- if (isOnLink(routes, nameserver)) {
- newIpWatchList.put(nameserver, getNeighborStateLocked(nameserver));
- }
- }
-
- mIpWatchList = newIpWatchList;
- mIpWatchListVersion++;
}
+
+ for (InetAddress dns : lp.getDnsServers()) {
+ if (isOnLink(routes, dns)) {
+ newNeighborWatchList.put(dns, mNeighborWatchList.getOrDefault(dns, null));
+ }
+ }
+
+ mNeighborWatchList = newNeighborWatchList;
if (DBG) { Log.d(TAG, "watch: " + describeWatchList()); }
}
public void clearLinkProperties() {
- synchronized (mLock) {
- mLinkProperties.clear();
- mIpWatchList.clear();
- mIpWatchListVersion++;
- }
+ mLinkProperties.clear();
+ mNeighborWatchList.clear();
if (DBG) { Log.d(TAG, "clear: " + describeWatchList()); }
}
- private void handleNeighborLost(String msg) {
+ private void handleNeighborLost(NeighborEvent event) {
+ final LinkProperties whatIfLp = new LinkProperties(mLinkProperties);
+
InetAddress ip = null;
- final ProvisioningChange delta;
- synchronized (mLock) {
- LinkProperties whatIfLp = new LinkProperties(mLinkProperties);
+ for (Map.Entry<InetAddress, NeighborEvent> entry : mNeighborWatchList.entrySet()) {
+ // TODO: Consider using NeighborEvent#isValid() here; it's more
+ // strict but may interact badly if other entries are somehow in
+ // NUD_INCOMPLETE (say, during network attach).
+ if (entry.getValue().nudState != StructNdMsg.NUD_FAILED) continue;
- for (Map.Entry<InetAddress, Short> entry : mIpWatchList.entrySet()) {
- if (entry.getValue() != StructNdMsg.NUD_FAILED) {
- continue;
- }
-
- ip = entry.getKey();
- for (RouteInfo route : mLinkProperties.getRoutes()) {
- if (ip.equals(route.getGateway())) {
- whatIfLp.removeRoute(route);
- }
- }
-
- if (avoidingBadLinks() || !(ip instanceof Inet6Address)) {
- // We should do this unconditionally, but alas we cannot: b/31827713.
- whatIfLp.removeDnsServer(ip);
+ ip = entry.getKey();
+ for (RouteInfo route : mLinkProperties.getRoutes()) {
+ if (ip.equals(route.getGateway())) {
+ whatIfLp.removeRoute(route);
}
}
- delta = LinkProperties.compareProvisioning(mLinkProperties, whatIfLp);
+ if (avoidingBadLinks() || !(ip instanceof Inet6Address)) {
+ // We should do this unconditionally, but alas we cannot: b/31827713.
+ whatIfLp.removeDnsServer(ip);
+ }
}
+ final ProvisioningChange delta = LinkProperties.compareProvisioning(
+ mLinkProperties, whatIfLp);
+
if (delta == ProvisioningChange.LOST_PROVISIONING) {
- final String logMsg = "FAILURE: LOST_PROVISIONING, " + msg;
+ final String logMsg = "FAILURE: LOST_PROVISIONING, " + event;
Log.w(TAG, logMsg);
if (mCallback != null) {
// TODO: remove |ip| when the callback signature no longer has
@@ -378,12 +341,9 @@
}
public void probeAll() {
- final List<InetAddress> ipProbeList;
- synchronized (mLock) {
- ipProbeList = new ArrayList<>(mIpWatchList.keySet());
- }
+ final List<InetAddress> ipProbeList = new ArrayList<>(mNeighborWatchList.keySet());
- if (!ipProbeList.isEmpty() && mRunning) {
+ if (!ipProbeList.isEmpty()) {
// Keep the CPU awake long enough to allow all ARP/ND
// probes a reasonable chance at success. See b/23197666.
//
@@ -394,13 +354,10 @@
}
for (InetAddress target : ipProbeList) {
- if (!mRunning) {
- break;
- }
- final int returnValue = probeNeighbor(mInterfaceIndex, target);
+ final int rval = IpNeighborMonitor.startKernelNeighborProbe(mInterfaceIndex, target);
mLog.log(String.format("put neighbor %s into NUD_PROBE state (rval=%d)",
- target.getHostAddress(), returnValue));
- logEvent(IpReachabilityEvent.PROBE, returnValue);
+ target.getHostAddress(), rval));
+ logEvent(IpReachabilityEvent.PROBE, rval);
}
mLastProbeTimeMs = SystemClock.elapsedRealtime();
}
@@ -446,153 +403,4 @@
int eventType = IpReachabilityEvent.nudFailureEventType(isFromProbe, isProvisioningLost);
mMetricsLog.log(mInterfaceName, new IpReachabilityEvent(eventType));
}
-
- // TODO: simplify the number of objects by making this extend Thread.
- private final class NetlinkSocketObserver implements Runnable {
- private NetlinkSocket mSocket;
-
- @Override
- public void run() {
- if (VDBG) { Log.d(TAG, "Starting observing thread."); }
- mRunning = true;
-
- try {
- setupNetlinkSocket();
- } catch (ErrnoException | SocketException e) {
- Log.e(TAG, "Failed to suitably initialize a netlink socket", e);
- mRunning = false;
- }
-
- while (mRunning) {
- final ByteBuffer byteBuffer;
- try {
- byteBuffer = recvKernelReply();
- } catch (ErrnoException e) {
- if (mRunning) { Log.w(TAG, "ErrnoException: ", e); }
- break;
- }
- final long whenMs = SystemClock.elapsedRealtime();
- if (byteBuffer == null) {
- continue;
- }
- parseNetlinkMessageBuffer(byteBuffer, whenMs);
- }
-
- clearNetlinkSocket();
-
- mRunning = false; // Not a no-op when ErrnoException happened.
- if (VDBG) { Log.d(TAG, "Finishing observing thread."); }
- }
-
- private void clearNetlinkSocket() {
- if (mSocket != null) {
- mSocket.close();
- }
- }
-
- // TODO: Refactor the main loop to recreate the socket upon recoverable errors.
- private void setupNetlinkSocket() throws ErrnoException, SocketException {
- clearNetlinkSocket();
- mSocket = new NetlinkSocket(OsConstants.NETLINK_ROUTE);
-
- final NetlinkSocketAddress listenAddr = new NetlinkSocketAddress(
- 0, OsConstants.RTMGRP_NEIGH);
- mSocket.bind(listenAddr);
-
- if (VDBG) {
- final NetlinkSocketAddress nlAddr = mSocket.getLocalAddress();
- Log.d(TAG, "bound to sockaddr_nl{"
- + ((long) (nlAddr.getPortId() & 0xffffffff)) + ", "
- + nlAddr.getGroupsMask()
- + "}");
- }
- }
-
- private ByteBuffer recvKernelReply() throws ErrnoException {
- try {
- return mSocket.recvMessage(0);
- } catch (InterruptedIOException e) {
- // Interruption or other error, e.g. another thread closed our file descriptor.
- } catch (ErrnoException e) {
- if (e.errno != OsConstants.EAGAIN) {
- throw e;
- }
- }
- return null;
- }
-
- private void parseNetlinkMessageBuffer(ByteBuffer byteBuffer, long whenMs) {
- while (byteBuffer.remaining() > 0) {
- final int position = byteBuffer.position();
- final NetlinkMessage nlMsg = NetlinkMessage.parse(byteBuffer);
- if (nlMsg == null || nlMsg.getHeader() == null) {
- byteBuffer.position(position);
- Log.e(TAG, "unparsable netlink msg: " + NetlinkConstants.hexify(byteBuffer));
- break;
- }
-
- final int srcPortId = nlMsg.getHeader().nlmsg_pid;
- if (srcPortId != 0) {
- Log.e(TAG, "non-kernel source portId: " + ((long) (srcPortId & 0xffffffff)));
- break;
- }
-
- if (nlMsg instanceof NetlinkErrorMessage) {
- Log.e(TAG, "netlink error: " + nlMsg);
- continue;
- } else if (!(nlMsg instanceof RtNetlinkNeighborMessage)) {
- if (DBG) {
- Log.d(TAG, "non-rtnetlink neighbor msg: " + nlMsg);
- }
- continue;
- }
-
- evaluateRtNetlinkNeighborMessage((RtNetlinkNeighborMessage) nlMsg, whenMs);
- }
- }
-
- private void evaluateRtNetlinkNeighborMessage(
- RtNetlinkNeighborMessage neighMsg, long whenMs) {
- final StructNdMsg ndMsg = neighMsg.getNdHeader();
- if (ndMsg == null || ndMsg.ndm_ifindex != mInterfaceIndex) {
- return;
- }
-
- final InetAddress destination = neighMsg.getDestination();
- if (!isWatching(destination)) {
- return;
- }
-
- final short msgType = neighMsg.getHeader().nlmsg_type;
- final short nudState = ndMsg.ndm_state;
- final String eventMsg = "NeighborEvent{"
- + "elapsedMs=" + whenMs + ", "
- + destination.getHostAddress() + ", "
- + "[" + NetlinkConstants.hexify(neighMsg.getLinkLayerAddress()) + "], "
- + NetlinkConstants.stringForNlMsgType(msgType) + ", "
- + StructNdMsg.stringForNudState(nudState)
- + "}";
-
- if (VDBG) {
- Log.d(TAG, neighMsg.toString());
- } else if (DBG) {
- Log.d(TAG, eventMsg);
- }
-
- synchronized (mLock) {
- if (mIpWatchList.containsKey(destination)) {
- final short value =
- (msgType == NetlinkConstants.RTM_DELNEIGH)
- ? StructNdMsg.NUD_NONE
- : nudState;
- mIpWatchList.put(destination, value);
- }
- }
-
- if (nudState == StructNdMsg.NUD_FAILED) {
- Log.w(TAG, "ALERT: " + eventMsg);
- handleNeighborLost(eventMsg);
- }
- }
- }
}
diff --git a/services/net/java/android/net/netlink/NetlinkSocket.java b/services/net/java/android/net/netlink/NetlinkSocket.java
index f5f211d..5af3c29 100644
--- a/services/net/java/android/net/netlink/NetlinkSocket.java
+++ b/services/net/java/android/net/netlink/NetlinkSocket.java
@@ -16,16 +16,24 @@
package android.net.netlink;
+import static android.system.OsConstants.AF_NETLINK;
+import static android.system.OsConstants.EIO;
+import static android.system.OsConstants.EPROTO;
+import static android.system.OsConstants.ETIMEDOUT;
+import static android.system.OsConstants.SO_RCVBUF;
+import static android.system.OsConstants.SO_RCVTIMEO;
+import static android.system.OsConstants.SO_SNDTIMEO;
+import static android.system.OsConstants.SOCK_DGRAM;
+import static android.system.OsConstants.SOL_SOCKET;
+
import android.system.ErrnoException;
import android.system.NetlinkSocketAddress;
import android.system.Os;
-import android.system.OsConstants;
import android.system.StructTimeval;
import android.util.Log;
import libcore.io.IoUtils;
import libcore.io.Libcore;
-import java.io.Closeable;
import java.io.FileDescriptor;
import java.io.InterruptedIOException;
import java.net.SocketAddress;
@@ -37,28 +45,27 @@
/**
* NetlinkSocket
*
- * A small wrapper class to assist with AF_NETLINK socket operations.
+ * A small static class to assist with AF_NETLINK socket operations.
*
* @hide
*/
-public class NetlinkSocket implements Closeable {
+public class NetlinkSocket {
private static final String TAG = "NetlinkSocket";
- private static final int SOCKET_RECV_BUFSIZE = 64 * 1024;
- private static final int DEFAULT_RECV_BUFSIZE = 8 * 1024;
- final private FileDescriptor mDescriptor;
- private NetlinkSocketAddress mAddr;
- private long mLastRecvTimeoutMs;
- private long mLastSendTimeoutMs;
+ public static final int DEFAULT_RECV_BUFSIZE = 8 * 1024;
+ public static final int SOCKET_RECV_BUFSIZE = 64 * 1024;
public static void sendOneShotKernelMessage(int nlProto, byte[] msg) throws ErrnoException {
final String errPrefix = "Error in NetlinkSocket.sendOneShotKernelMessage";
+ final long IO_TIMEOUT = 300L;
- try (NetlinkSocket nlSocket = new NetlinkSocket(nlProto)) {
- final long IO_TIMEOUT = 300L;
- nlSocket.connectToKernel();
- nlSocket.sendMessage(msg, 0, msg.length, IO_TIMEOUT);
- final ByteBuffer bytes = nlSocket.recvMessage(IO_TIMEOUT);
+ FileDescriptor fd;
+
+ try {
+ fd = forProto(nlProto);
+ connectToKernel(fd);
+ sendMessage(fd, msg, 0, msg.length, IO_TIMEOUT);
+ final ByteBuffer bytes = recvMessage(fd, DEFAULT_RECV_BUFSIZE, IO_TIMEOUT);
// recvMessage() guaranteed to not return null if it did not throw.
final NetlinkMessage response = NetlinkMessage.parse(bytes);
if (response != null && response instanceof NetlinkErrorMessage &&
@@ -81,61 +88,30 @@
errmsg = response.toString();
}
Log.e(TAG, errPrefix + ", errmsg=" + errmsg);
- throw new ErrnoException(errmsg, OsConstants.EPROTO);
+ throw new ErrnoException(errmsg, EPROTO);
}
} catch (InterruptedIOException e) {
Log.e(TAG, errPrefix, e);
- throw new ErrnoException(errPrefix, OsConstants.ETIMEDOUT, e);
+ throw new ErrnoException(errPrefix, ETIMEDOUT, e);
} catch (SocketException e) {
Log.e(TAG, errPrefix, e);
- throw new ErrnoException(errPrefix, OsConstants.EIO, e);
+ throw new ErrnoException(errPrefix, EIO, e);
}
+
+ IoUtils.closeQuietly(fd);
}
- public NetlinkSocket(int nlProto) throws ErrnoException {
- mDescriptor = Os.socket(
- OsConstants.AF_NETLINK, OsConstants.SOCK_DGRAM, nlProto);
-
- Os.setsockoptInt(
- mDescriptor, OsConstants.SOL_SOCKET,
- OsConstants.SO_RCVBUF, SOCKET_RECV_BUFSIZE);
+ public static FileDescriptor forProto(int nlProto) throws ErrnoException {
+ final FileDescriptor fd = Os.socket(AF_NETLINK, SOCK_DGRAM, nlProto);
+ Os.setsockoptInt(fd, SOL_SOCKET, SO_RCVBUF, SOCKET_RECV_BUFSIZE);
+ return fd;
}
- public NetlinkSocketAddress getLocalAddress() throws ErrnoException {
- return (NetlinkSocketAddress) Os.getsockname(mDescriptor);
+ public static void connectToKernel(FileDescriptor fd) throws ErrnoException, SocketException {
+ Os.connect(fd, (SocketAddress) (new NetlinkSocketAddress(0, 0)));
}
- public void bind(NetlinkSocketAddress localAddr) throws ErrnoException, SocketException {
- Os.bind(mDescriptor, (SocketAddress)localAddr);
- }
-
- public void connectTo(NetlinkSocketAddress peerAddr)
- throws ErrnoException, SocketException {
- Os.connect(mDescriptor, (SocketAddress) peerAddr);
- }
-
- public void connectToKernel() throws ErrnoException, SocketException {
- connectTo(new NetlinkSocketAddress(0, 0));
- }
-
- /**
- * Wait indefinitely (or until underlying socket error) for a
- * netlink message of at most DEFAULT_RECV_BUFSIZE size.
- */
- public ByteBuffer recvMessage()
- throws ErrnoException, InterruptedIOException {
- return recvMessage(DEFAULT_RECV_BUFSIZE, 0);
- }
-
- /**
- * Wait up to |timeoutMs| (or until underlying socket error) for a
- * netlink message of at most DEFAULT_RECV_BUFSIZE size.
- */
- public ByteBuffer recvMessage(long timeoutMs) throws ErrnoException, InterruptedIOException {
- return recvMessage(DEFAULT_RECV_BUFSIZE, timeoutMs);
- }
-
- private void checkTimeout(long timeoutMs) {
+ private static void checkTimeout(long timeoutMs) {
if (timeoutMs < 0) {
throw new IllegalArgumentException("Negative timeouts not permitted");
}
@@ -147,21 +123,14 @@
*
* Multi-threaded calls with different timeouts will cause unexpected results.
*/
- public ByteBuffer recvMessage(int bufsize, long timeoutMs)
+ public static ByteBuffer recvMessage(FileDescriptor fd, int bufsize, long timeoutMs)
throws ErrnoException, IllegalArgumentException, InterruptedIOException {
checkTimeout(timeoutMs);
- synchronized (mDescriptor) {
- if (mLastRecvTimeoutMs != timeoutMs) {
- Os.setsockoptTimeval(mDescriptor,
- OsConstants.SOL_SOCKET, OsConstants.SO_RCVTIMEO,
- StructTimeval.fromMillis(timeoutMs));
- mLastRecvTimeoutMs = timeoutMs;
- }
- }
+ Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(timeoutMs));
ByteBuffer byteBuffer = ByteBuffer.allocate(bufsize);
- int length = Os.read(mDescriptor, byteBuffer);
+ int length = Os.read(fd, byteBuffer);
if (length == bufsize) {
Log.w(TAG, "maximum read");
}
@@ -172,39 +141,16 @@
}
/**
- * Send a message to a peer to which this socket has previously connected.
- *
- * This blocks until completion or an error occurs.
- */
- public boolean sendMessage(byte[] bytes, int offset, int count)
- throws ErrnoException, InterruptedIOException {
- return sendMessage(bytes, offset, count, 0);
- }
-
- /**
* Send a message to a peer to which this socket has previously connected,
* waiting at most |timeoutMs| milliseconds for the send to complete.
*
* Multi-threaded calls with different timeouts will cause unexpected results.
*/
- public boolean sendMessage(byte[] bytes, int offset, int count, long timeoutMs)
+ public static int sendMessage(
+ FileDescriptor fd, byte[] bytes, int offset, int count, long timeoutMs)
throws ErrnoException, IllegalArgumentException, InterruptedIOException {
checkTimeout(timeoutMs);
-
- synchronized (mDescriptor) {
- if (mLastSendTimeoutMs != timeoutMs) {
- Os.setsockoptTimeval(mDescriptor,
- OsConstants.SOL_SOCKET, OsConstants.SO_SNDTIMEO,
- StructTimeval.fromMillis(timeoutMs));
- mLastSendTimeoutMs = timeoutMs;
- }
- }
-
- return (count == Os.write(mDescriptor, bytes, offset, count));
- }
-
- @Override
- public void close() {
- IoUtils.closeQuietly(mDescriptor);
+ Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(timeoutMs));
+ return Os.write(fd, bytes, offset, count);
}
}
diff --git a/services/net/java/android/net/netlink/StructNdMsg.java b/services/net/java/android/net/netlink/StructNdMsg.java
index b68ec0b..e34ec39 100644
--- a/services/net/java/android/net/netlink/StructNdMsg.java
+++ b/services/net/java/android/net/netlink/StructNdMsg.java
@@ -63,6 +63,11 @@
return ((nudState & (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE)) != 0);
}
+ public static boolean isNudStateValid(short nudState) {
+ return (isNudStateConnected(nudState) ||
+ ((nudState & (NUD_PROBE|NUD_STALE|NUD_DELAY)) != 0));
+ }
+
// Neighbor Cache Entry Flags
public static byte NTF_USE = (byte) 0x01;
public static byte NTF_SELF = (byte) 0x02;
@@ -143,7 +148,7 @@
}
public boolean nudValid() {
- return (nudConnected() || ((ndm_state & (NUD_PROBE|NUD_STALE|NUD_DELAY)) != 0));
+ return isNudStateValid(ndm_state);
}
@Override
diff --git a/services/net/java/android/net/util/BlockingSocketReader.java b/services/net/java/android/net/util/PacketReader.java
similarity index 97%
rename from services/net/java/android/net/util/BlockingSocketReader.java
rename to services/net/java/android/net/util/PacketReader.java
index 99bf469..10da2a5 100644
--- a/services/net/java/android/net/util/BlockingSocketReader.java
+++ b/services/net/java/android/net/util/PacketReader.java
@@ -67,7 +67,7 @@
*
* @hide
*/
-public abstract class BlockingSocketReader {
+public abstract class PacketReader {
private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR;
private static final int UNREGISTER_THIS_FD = 0;
@@ -83,11 +83,11 @@
IoUtils.closeQuietly(fd);
}
- protected BlockingSocketReader(Handler h) {
+ protected PacketReader(Handler h) {
this(h, DEFAULT_RECV_BUF_SIZE);
}
- protected BlockingSocketReader(Handler h, int recvbufsize) {
+ protected PacketReader(Handler h, int recvbufsize) {
mHandler = h;
mQueue = mHandler.getLooper().getQueue();
mPacket = new byte[Math.max(recvbufsize, DEFAULT_RECV_BUF_SIZE)];
@@ -115,6 +115,8 @@
}
}
+ public Handler getHandler() { return mHandler; }
+
public final int recvBufSize() { return mPacket.length; }
public final long numPacketsReceived() { return mPacketsReceived; }
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index c3a2ceb..56e1e64 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -280,6 +280,36 @@
* {@hide}
*/
public static final int NORMAL_UNSPECIFIED = 65;
+
+ /**
+ * Stk Call Control modified DIAL request to video DIAL request.
+ * {@hide}
+ */
+ public static final int DIAL_MODIFIED_TO_DIAL_VIDEO = 66;
+
+ /**
+ * Stk Call Control modified Video DIAL request to SS request.
+ * {@hide}
+ */
+ public static final int DIAL_VIDEO_MODIFIED_TO_SS = 67;
+
+ /**
+ * Stk Call Control modified Video DIAL request to USSD request.
+ * {@hide}
+ */
+ public static final int DIAL_VIDEO_MODIFIED_TO_USSD = 68;
+
+ /**
+ * Stk Call Control modified Video DIAL request to DIAL request.
+ * {@hide}
+ */
+ public static final int DIAL_VIDEO_MODIFIED_TO_DIAL = 69;
+
+ /**
+ * Stk Call Control modified Video DIAL request to Video DIAL request.
+ * {@hide}
+ */
+ public static final int DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO = 70;
//*********************************************************************************************
// When adding a disconnect type:
// 1) Update toString() with the newly added disconnect type.
@@ -382,6 +412,16 @@
return "DIAL_MODIFIED_TO_SS";
case DIAL_MODIFIED_TO_DIAL:
return "DIAL_MODIFIED_TO_DIAL";
+ case DIAL_MODIFIED_TO_DIAL_VIDEO:
+ return "DIAL_MODIFIED_TO_DIAL_VIDEO";
+ case DIAL_VIDEO_MODIFIED_TO_SS:
+ return "DIAL_VIDEO_MODIFIED_TO_SS";
+ case DIAL_VIDEO_MODIFIED_TO_USSD:
+ return "DIAL_VIDEO_MODIFIED_TO_USSD";
+ case DIAL_VIDEO_MODIFIED_TO_DIAL:
+ return "DIAL_VIDEO_MODIFIED_TO_DIAL";
+ case DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO:
+ return "DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO";
case ERROR_UNSPECIFIED:
return "ERROR_UNSPECIFIED";
case OUTGOING_FAILURE:
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtListenerImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtListenerImplBase.java
index b371efb..daa74c8 100644
--- a/telephony/java/android/telephony/ims/stub/ImsUtListenerImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsUtListenerImplBase.java
@@ -21,6 +21,7 @@
import com.android.ims.ImsCallForwardInfo;
import com.android.ims.ImsReasonInfo;
+import com.android.ims.ImsSsData;
import com.android.ims.ImsSsInfo;
import com.android.ims.internal.IImsUt;
import com.android.ims.internal.IImsUtListener;
@@ -85,4 +86,10 @@
public void utConfigurationCallWaitingQueried(IImsUt ut, int id, ImsSsInfo[] cwInfo)
throws RemoteException {
}
+
+ /**
+ * Notifies client when Supplementary Service indication is received
+ */
+ @Override
+ public void onSupplementaryServiceIndication(ImsSsData ssData) {}
}
diff --git a/telephony/java/com/android/ims/ImsReasonInfo.java b/telephony/java/com/android/ims/ImsReasonInfo.java
index cdfc1fd..6ad54c1 100644
--- a/telephony/java/com/android/ims/ImsReasonInfo.java
+++ b/telephony/java/com/android/ims/ImsReasonInfo.java
@@ -111,6 +111,16 @@
// and this capability is not supported by the network.
public static final int CODE_IMEI_NOT_ACCEPTED = 243;
+ //STK CC errors
+ public static final int CODE_DIAL_MODIFIED_TO_USSD = 244;
+ public static final int CODE_DIAL_MODIFIED_TO_SS = 245;
+ public static final int CODE_DIAL_MODIFIED_TO_DIAL = 246;
+ public static final int CODE_DIAL_MODIFIED_TO_DIAL_VIDEO = 247;
+ public static final int CODE_DIAL_VIDEO_MODIFIED_TO_DIAL = 248;
+ public static final int CODE_DIAL_VIDEO_MODIFIED_TO_DIAL_VIDEO = 249;
+ public static final int CODE_DIAL_VIDEO_MODIFIED_TO_SS = 250;
+ public static final int CODE_DIAL_VIDEO_MODIFIED_TO_USSD = 251;
+
/**
* STATUSCODE (SIP response code) (IMS -> Telephony)
*/
@@ -217,6 +227,11 @@
public static final int CODE_UT_OPERATION_NOT_ALLOWED = 803;
public static final int CODE_UT_NETWORK_ERROR = 804;
public static final int CODE_UT_CB_PASSWORD_MISMATCH = 821;
+ //STK CC errors
+ public static final int CODE_UT_SS_MODIFIED_TO_DIAL = 822;
+ public static final int CODE_UT_SS_MODIFIED_TO_USSD = 823;
+ public static final int CODE_UT_SS_MODIFIED_TO_SS = 824;
+ public static final int CODE_UT_SS_MODIFIED_TO_DIAL_VIDEO = 825;
/**
* ECBM
diff --git a/telephony/java/com/android/ims/ImsSsData.aidl b/telephony/java/com/android/ims/ImsSsData.aidl
new file mode 100644
index 0000000..33f8306
--- /dev/null
+++ b/telephony/java/com/android/ims/ImsSsData.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2017 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.ims;
+
+parcelable ImsSsData;
diff --git a/telephony/java/com/android/ims/ImsSsData.java b/telephony/java/com/android/ims/ImsSsData.java
new file mode 100644
index 0000000..7336c13
--- /dev/null
+++ b/telephony/java/com/android/ims/ImsSsData.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (c) 2017 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.ims;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+
+/**
+ * Provided STK Call Control Suplementary Service information
+ *
+ * {@hide}
+ */
+public class ImsSsData implements Parcelable {
+
+ //ServiceType
+ public static final int SS_CFU = 0;
+ public static final int SS_CF_BUSY = 1;
+ public static final int SS_CF_NO_REPLY = 2;
+ public static final int SS_CF_NOT_REACHABLE = 3;
+ public static final int SS_CF_ALL = 4;
+ public static final int SS_CF_ALL_CONDITIONAL = 5;
+ public static final int SS_CFUT = 6;
+ public static final int SS_CLIP = 7;
+ public static final int SS_CLIR = 8;
+ public static final int SS_COLP = 9;
+ public static final int SS_COLR = 10;
+ public static final int SS_CNAP = 11;
+ public static final int SS_WAIT = 12;
+ public static final int SS_BAOC = 13;
+ public static final int SS_BAOIC = 14;
+ public static final int SS_BAOIC_EXC_HOME = 15;
+ public static final int SS_BAIC = 16;
+ public static final int SS_BAIC_ROAMING = 17;
+ public static final int SS_ALL_BARRING = 18;
+ public static final int SS_OUTGOING_BARRING = 19;
+ public static final int SS_INCOMING_BARRING = 20;
+ public static final int SS_INCOMING_BARRING_DN = 21;
+ public static final int SS_INCOMING_BARRING_ANONYMOUS = 22;
+
+ //SSRequestType
+ public static final int SS_ACTIVATION = 0;
+ public static final int SS_DEACTIVATION = 1;
+ public static final int SS_INTERROGATION = 2;
+ public static final int SS_REGISTRATION = 3;
+ public static final int SS_ERASURE = 4;
+
+ //TeleserviceType
+ public static final int SS_ALL_TELE_AND_BEARER_SERVICES = 0;
+ public static final int SS_ALL_TELESEVICES = 1;
+ public static final int SS_TELEPHONY = 2;
+ public static final int SS_ALL_DATA_TELESERVICES = 3;
+ public static final int SS_SMS_SERVICES = 4;
+ public static final int SS_ALL_TELESERVICES_EXCEPT_SMS = 5;
+
+ // Refer to ServiceType
+ public int serviceType;
+ // Refere to SSRequestType
+ public int requestType;
+ // Refer to TeleserviceType
+ public int teleserviceType;
+ // Service Class
+ public int serviceClass;
+ // Error information
+ public int result;
+
+ public int[] ssInfo; /* Valid for all supplementary services.
+ This field will be empty for RequestType SS_INTERROGATION
+ and ServiceType SS_CF_*, SS_INCOMING_BARRING_DN,
+ SS_INCOMING_BARRING_ANONYMOUS.*/
+
+ public ImsCallForwardInfo[] cfInfo; /* Valid only for supplementary services
+ ServiceType SS_CF_* and RequestType SS_INTERROGATION */
+
+ public ImsSsInfo[] imsSsInfo; /* Valid only for ServiceType SS_INCOMING_BARRING_DN and
+ ServiceType SS_INCOMING_BARRING_ANONYMOUS */
+
+ public ImsSsData() {}
+
+ public ImsSsData(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public static final Creator<ImsSsData> CREATOR = new Creator<ImsSsData>() {
+ @Override
+ public ImsSsData createFromParcel(Parcel in) {
+ return new ImsSsData(in);
+ }
+
+ @Override
+ public ImsSsData[] newArray(int size) {
+ return new ImsSsData[size];
+ }
+ };
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(serviceType);
+ out.writeInt(requestType);
+ out.writeInt(teleserviceType);
+ out.writeInt(serviceClass);
+ out.writeInt(result);
+ out.writeIntArray(ssInfo);
+ out.writeParcelableArray(cfInfo, 0);
+ }
+
+ private void readFromParcel(Parcel in) {
+ serviceType = in.readInt();
+ requestType = in.readInt();
+ teleserviceType = in.readInt();
+ serviceClass = in.readInt();
+ result = in.readInt();
+ ssInfo = in.createIntArray();
+ cfInfo = (ImsCallForwardInfo[])in.readParcelableArray(this.getClass().getClassLoader());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public boolean isTypeCF() {
+ return (serviceType == SS_CFU || serviceType == SS_CF_BUSY ||
+ serviceType == SS_CF_NO_REPLY || serviceType == SS_CF_NOT_REACHABLE ||
+ serviceType == SS_CF_ALL || serviceType == SS_CF_ALL_CONDITIONAL);
+ }
+
+ public boolean isTypeUnConditional() {
+ return (serviceType == SS_CFU || serviceType == SS_CF_ALL);
+ }
+
+ public boolean isTypeCW() {
+ return (serviceType == SS_WAIT);
+ }
+
+ public boolean isTypeClip() {
+ return (serviceType == SS_CLIP);
+ }
+
+ public boolean isTypeColr() {
+ return (serviceType == SS_COLR);
+ }
+
+ public boolean isTypeColp() {
+ return (serviceType == SS_COLP);
+ }
+
+ public boolean isTypeClir() {
+ return (serviceType == SS_CLIR);
+ }
+
+ public boolean isTypeIcb() {
+ return (serviceType == SS_INCOMING_BARRING_DN ||
+ serviceType == SS_INCOMING_BARRING_ANONYMOUS);
+ }
+
+ public boolean isTypeBarring() {
+ return (serviceType == SS_BAOC || serviceType == SS_BAOIC ||
+ serviceType == SS_BAOIC_EXC_HOME || serviceType == SS_BAIC ||
+ serviceType == SS_BAIC_ROAMING || serviceType == SS_ALL_BARRING ||
+ serviceType == SS_OUTGOING_BARRING || serviceType == SS_INCOMING_BARRING);
+ }
+
+ public boolean isTypeInterrogation() {
+ return (requestType == SS_INTERROGATION);
+ }
+
+ public String toString() {
+ return "[ImsSsData] " + "ServiceType: " + serviceType
+ + " RequestType: " + requestType
+ + " TeleserviceType: " + teleserviceType
+ + " ServiceClass: " + serviceClass
+ + " Result: " + result;
+ }
+}
diff --git a/telephony/java/com/android/ims/ImsUtInterface.java b/telephony/java/com/android/ims/ImsUtInterface.java
index 250371f..14c184a 100644
--- a/telephony/java/com/android/ims/ImsUtInterface.java
+++ b/telephony/java/com/android/ims/ImsUtInterface.java
@@ -16,6 +16,7 @@
package com.android.ims;
+import android.os.Handler;
import android.os.Message;
/**
@@ -188,4 +189,18 @@
* Updates the configuration of the COLP supplementary service.
*/
public void updateCOLP(boolean enable, Message result);
+
+ /**
+ * Register for UNSOL_ON_SS indications.
+ * @param handler the {@link Handler} that is notified when there is an ss indication.
+ * @param event Supplimentary service indication event.
+ * @param Object user object.
+ */
+ public void registerForSuppServiceIndication(Handler handler, int event, Object object);
+
+ /**
+ * Deregister for UNSOL_ON_SS indications.
+ * @param handler the {@link Handler} that is notified when there is an ss indication.
+ */
+ public void unregisterForSuppServiceIndication(Handler handler);
}
diff --git a/telephony/java/com/android/ims/internal/IImsUtListener.aidl b/telephony/java/com/android/ims/internal/IImsUtListener.aidl
index 300273a..1bc0369 100644
--- a/telephony/java/com/android/ims/internal/IImsUtListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsUtListener.aidl
@@ -19,6 +19,7 @@
import android.os.Bundle;
import com.android.ims.ImsCallForwardInfo;
+import com.android.ims.ImsSsData;
import com.android.ims.ImsSsInfo;
import com.android.ims.internal.IImsUt;
import com.android.ims.ImsReasonInfo;
@@ -56,4 +57,11 @@
*/
void utConfigurationCallWaitingQueried(in IImsUt ut,
int id, in ImsSsInfo[] cwInfo);
+
+ /**
+ * Notifies client when Supplementary Service indication is received
+ *
+ * @param ssData Details of SS request and response information
+ */
+ void onSupplementaryServiceIndication(in ImsSsData ssData);
}
diff --git a/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java b/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java
index f849689..54776db 100644
--- a/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java
+++ b/tests/net/java/android/net/ip/IpReachabilityMonitorTest.java
@@ -18,10 +18,12 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.when;
import android.net.util.SharedLog;
+import android.os.Handler;
+import android.os.Looper;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -42,14 +44,18 @@
@Mock IpReachabilityMonitor.Callback mCallback;
@Mock IpReachabilityMonitor.Dependencies mDependencies;
@Mock SharedLog mLog;
+ Handler mHandler;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ when(mLog.forSubComponent(anyString())).thenReturn(mLog);
+ mHandler = new Handler(Looper.getMainLooper());
}
IpReachabilityMonitor makeMonitor() {
- return new IpReachabilityMonitor("fake0", 1, mLog, mCallback, null, mDependencies);
+ return new IpReachabilityMonitor(
+ "fake0", 1, mHandler, mLog, mCallback, null, mDependencies);
}
@Test
diff --git a/tests/net/java/android/net/netlink/NetlinkSocketTest.java b/tests/net/java/android/net/netlink/NetlinkSocketTest.java
index bd36bac8..11be40b 100644
--- a/tests/net/java/android/net/netlink/NetlinkSocketTest.java
+++ b/tests/net/java/android/net/netlink/NetlinkSocketTest.java
@@ -16,6 +16,8 @@
package android.net.netlink;
+import static android.net.netlink.NetlinkSocket.DEFAULT_RECV_BUFSIZE;
+import static android.system.OsConstants.NETLINK_ROUTE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -28,10 +30,12 @@
import android.support.test.filters.SmallTest;
import android.system.ErrnoException;
import android.system.NetlinkSocketAddress;
-import android.system.OsConstants;
+import android.system.Os;
import android.util.Log;
+import libcore.io.IoUtils;
import java.io.InterruptedIOException;
+import java.io.FileDescriptor;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
@@ -46,29 +50,28 @@
@Test
public void testBasicWorkingGetNeighborsQuery() throws Exception {
- NetlinkSocket s = new NetlinkSocket(OsConstants.NETLINK_ROUTE);
- assertNotNull(s);
+ final FileDescriptor fd = NetlinkSocket.forProto(NETLINK_ROUTE);
+ assertNotNull(fd);
- s.connectToKernel();
+ NetlinkSocket.connectToKernel(fd);
- NetlinkSocketAddress localAddr = s.getLocalAddress();
+ final NetlinkSocketAddress localAddr = (NetlinkSocketAddress) Os.getsockname(fd);
assertNotNull(localAddr);
assertEquals(0, localAddr.getGroupsMask());
assertTrue(0 != localAddr.getPortId());
final int TEST_SEQNO = 5;
- final byte[] request = RtNetlinkNeighborMessage.newGetNeighborsRequest(TEST_SEQNO);
- assertNotNull(request);
+ final byte[] req = RtNetlinkNeighborMessage.newGetNeighborsRequest(TEST_SEQNO);
+ assertNotNull(req);
final long TIMEOUT = 500;
- assertTrue(s.sendMessage(request, 0, request.length, TIMEOUT));
+ assertEquals(req.length, NetlinkSocket.sendMessage(fd, req, 0, req.length, TIMEOUT));
int neighMessageCount = 0;
int doneMessageCount = 0;
while (doneMessageCount == 0) {
- ByteBuffer response = null;
- response = s.recvMessage(TIMEOUT);
+ ByteBuffer response = NetlinkSocket.recvMessage(fd, DEFAULT_RECV_BUFSIZE, TIMEOUT);
assertNotNull(response);
assertTrue(StructNlMsgHdr.STRUCT_SIZE <= response.limit());
assertEquals(0, response.position());
@@ -100,30 +103,6 @@
// TODO: make sure this test passes sanely in airplane mode.
assertTrue(neighMessageCount > 0);
- s.close();
- }
-
- @Test
- public void testRepeatedCloseCallsAreQuiet() throws Exception {
- // Create a working NetlinkSocket.
- NetlinkSocket s = new NetlinkSocket(OsConstants.NETLINK_ROUTE);
- assertNotNull(s);
- s.connectToKernel();
- NetlinkSocketAddress localAddr = s.getLocalAddress();
- assertNotNull(localAddr);
- assertEquals(0, localAddr.getGroupsMask());
- assertTrue(0 != localAddr.getPortId());
- // Close once.
- s.close();
- // Test that it is closed.
- boolean expectedErrorSeen = false;
- try {
- localAddr = s.getLocalAddress();
- } catch (ErrnoException e) {
- expectedErrorSeen = true;
- }
- assertTrue(expectedErrorSeen);
- // Close once more.
- s.close();
+ IoUtils.closeQuietly(fd);
}
}
diff --git a/tests/net/java/android/net/util/BlockingSocketReaderTest.java b/tests/net/java/android/net/util/PacketReaderTest.java
similarity index 91%
rename from tests/net/java/android/net/util/BlockingSocketReaderTest.java
rename to tests/net/java/android/net/util/PacketReaderTest.java
index 29dfa4c..dced743 100644
--- a/tests/net/java/android/net/util/BlockingSocketReaderTest.java
+++ b/tests/net/java/android/net/util/PacketReaderTest.java
@@ -16,7 +16,7 @@
package android.net.util;
-import static android.net.util.BlockingSocketReader.DEFAULT_RECV_BUF_SIZE;
+import static android.net.util.PacketReader.DEFAULT_RECV_BUF_SIZE;
import static android.system.OsConstants.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -53,13 +53,13 @@
import libcore.io.IoBridge;
/**
- * Tests for BlockingSocketReader.
+ * Tests for PacketReader.
*
* @hide
*/
@RunWith(AndroidJUnit4.class)
@SmallTest
-public class BlockingSocketReaderTest {
+public class PacketReaderTest {
static final InetAddress LOOPBACK6 = Inet6Address.getLoopbackAddress();
static final StructTimeval TIMEO = StructTimeval.fromMillis(500);
@@ -69,9 +69,9 @@
protected byte[] mLastRecvBuf;
protected boolean mStopped;
protected HandlerThread mHandlerThread;
- protected BlockingSocketReader mReceiver;
+ protected PacketReader mReceiver;
- class UdpLoopbackReader extends BlockingSocketReader {
+ class UdpLoopbackReader extends PacketReader {
public UdpLoopbackReader(Handler h) {
super(h);
}
@@ -121,7 +121,7 @@
mLastRecvBuf = null;
mStopped = false;
- mHandlerThread = new HandlerThread(BlockingSocketReaderTest.class.getSimpleName());
+ mHandlerThread = new HandlerThread(PacketReaderTest.class.getSimpleName());
mHandlerThread.start();
}
@@ -188,8 +188,8 @@
mReceiver = null;
}
- class NullBlockingSocketReader extends BlockingSocketReader {
- public NullBlockingSocketReader(Handler h, int recvbufsize) {
+ class NullPacketReader extends PacketReader {
+ public NullPacketReader(Handler h, int recvbufsize) {
super(h, recvbufsize);
}
@@ -202,7 +202,7 @@
final Handler h = mHandlerThread.getThreadHandler();
for (int i : new int[]{-1, 0, 1, DEFAULT_RECV_BUF_SIZE-1}) {
- final BlockingSocketReader b = new NullBlockingSocketReader(h, i);
+ final PacketReader b = new NullPacketReader(h, i);
assertEquals(DEFAULT_RECV_BUF_SIZE, b.recvBufSize());
}
}
diff --git a/wifi/java/android/net/wifi/aware/PeerHandle.java b/wifi/java/android/net/wifi/aware/PeerHandle.java
index cd45c52..b525212 100644
--- a/wifi/java/android/net/wifi/aware/PeerHandle.java
+++ b/wifi/java/android/net/wifi/aware/PeerHandle.java
@@ -32,4 +32,22 @@
/** @hide */
public int peerId;
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+
+ if (!(o instanceof PeerHandle)) {
+ return false;
+ }
+
+ return peerId == ((PeerHandle) o).peerId;
+ }
+
+ @Override
+ public int hashCode() {
+ return peerId;
+ }
}