Merge "Remove duplicate definitions of utility variables"
diff --git a/api/current.txt b/api/current.txt
index 4c6e621..7f076cb 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -25828,8 +25828,8 @@
public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
method public void close() throws java.io.IOException;
+ method public java.io.FileDescriptor getFileDescriptor();
method public int getPort();
- method public java.io.FileDescriptor getSocket();
}
public final class IpSecTransform implements java.lang.AutoCloseable {
@@ -37011,17 +37011,17 @@
package android.se.omapi {
- public class Channel {
+ public final class Channel implements java.nio.channels.Channel {
method public void close();
method public byte[] getSelectResponse();
method public android.se.omapi.Session getSession();
method public boolean isBasicChannel();
- method public boolean isClosed();
+ method public boolean isOpen();
method public boolean selectNext() throws java.io.IOException;
method public byte[] transmit(byte[]) throws java.io.IOException;
}
- public class Reader {
+ public final class Reader {
method public void closeSessions();
method public java.lang.String getName();
method public android.se.omapi.SEService getSEService();
@@ -37029,26 +37029,28 @@
method public android.se.omapi.Session openSession() throws java.io.IOException;
}
- public class SEService {
- ctor public SEService(android.content.Context, android.se.omapi.SEService.SecureElementListener);
+ public final class SEService {
+ ctor public SEService(android.content.Context, java.util.concurrent.Executor, android.se.omapi.SEService.OnConnectedListener);
method public android.se.omapi.Reader[] getReaders();
method public java.lang.String getVersion();
method public boolean isConnected();
method public void shutdown();
}
- public static abstract interface SEService.SecureElementListener {
- method public abstract void onServiceConnected();
+ public static abstract interface SEService.OnConnectedListener {
+ method public abstract void onConnected();
}
- public class Session {
+ public final class Session {
method public void close();
method public void closeChannels();
method public byte[] getATR();
method public android.se.omapi.Reader getReader();
method public boolean isClosed();
method public android.se.omapi.Channel openBasicChannel(byte[], byte) throws java.io.IOException;
+ method public android.se.omapi.Channel openBasicChannel(byte[]) throws java.io.IOException;
method public android.se.omapi.Channel openLogicalChannel(byte[], byte) throws java.io.IOException;
+ method public android.se.omapi.Channel openLogicalChannel(byte[]) throws java.io.IOException;
}
}
@@ -39390,7 +39392,7 @@
method public final void putExtras(android.os.Bundle);
method public final void removeExtras(java.util.List<java.lang.String>);
method public final void removeExtras(java.lang.String...);
- method public void requestBluetoothAudio(java.lang.String);
+ method public void requestBluetoothAudio(android.bluetooth.BluetoothDevice);
method public void sendConnectionEvent(java.lang.String, android.os.Bundle);
method public final void sendRemoteRttRequest();
method public final void sendRttInitiationFailure(int);
@@ -39601,7 +39603,7 @@
method public void onCanAddCallChanged(boolean);
method public void onConnectionEvent(android.telecom.Call, java.lang.String, android.os.Bundle);
method public void onSilenceRinger();
- method public final void requestBluetoothAudio(java.lang.String);
+ method public final void requestBluetoothAudio(android.bluetooth.BluetoothDevice);
method public final void setAudioRoute(int);
method public final void setMuted(boolean);
field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.InCallService";
@@ -40193,6 +40195,8 @@
public abstract class CellIdentity implements android.os.Parcelable {
method public int describeContents();
+ method public java.lang.CharSequence getOperatorAlphaLong();
+ method public java.lang.CharSequence getOperatorAlphaShort();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.CellIdentity> CREATOR;
}
@@ -40202,8 +40206,6 @@
method public int getLatitude();
method public int getLongitude();
method public int getNetworkId();
- method public java.lang.CharSequence getOperatorAlphaLong();
- method public java.lang.CharSequence getOperatorAlphaShort();
method public int getSystemId();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityCdma> CREATOR;
@@ -40219,8 +40221,6 @@
method public deprecated int getMnc();
method public java.lang.String getMncString();
method public java.lang.String getMobileNetworkOperator();
- method public java.lang.CharSequence getOperatorAlphaLong();
- method public java.lang.CharSequence getOperatorAlphaShort();
method public deprecated int getPsc();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityGsm> CREATOR;
@@ -40235,8 +40235,6 @@
method public deprecated int getMnc();
method public java.lang.String getMncString();
method public java.lang.String getMobileNetworkOperator();
- method public java.lang.CharSequence getOperatorAlphaLong();
- method public java.lang.CharSequence getOperatorAlphaShort();
method public int getPci();
method public int getTac();
method public void writeToParcel(android.os.Parcel, int);
@@ -40261,8 +40259,6 @@
method public deprecated int getMnc();
method public java.lang.String getMncString();
method public java.lang.String getMobileNetworkOperator();
- method public java.lang.CharSequence getOperatorAlphaLong();
- method public java.lang.CharSequence getOperatorAlphaShort();
method public int getPsc();
method public int getUarfcn();
method public void writeToParcel(android.os.Parcel, int);
@@ -40392,17 +40388,17 @@
}
public class MbmsDownloadSession implements java.lang.AutoCloseable {
- method public int addProgressListener(android.telephony.mbms.DownloadRequest, java.util.concurrent.Executor, android.telephony.mbms.DownloadProgressListener);
- method public int addStatusListener(android.telephony.mbms.DownloadRequest, java.util.concurrent.Executor, android.telephony.mbms.DownloadStatusListener);
- method public int cancelDownload(android.telephony.mbms.DownloadRequest);
+ method public void addProgressListener(android.telephony.mbms.DownloadRequest, java.util.concurrent.Executor, android.telephony.mbms.DownloadProgressListener);
+ method public void addStatusListener(android.telephony.mbms.DownloadRequest, java.util.concurrent.Executor, android.telephony.mbms.DownloadStatusListener);
+ method public void cancelDownload(android.telephony.mbms.DownloadRequest);
method public void close();
method public static android.telephony.MbmsDownloadSession create(android.content.Context, java.util.concurrent.Executor, android.telephony.mbms.MbmsDownloadSessionCallback);
method public static android.telephony.MbmsDownloadSession create(android.content.Context, java.util.concurrent.Executor, int, android.telephony.mbms.MbmsDownloadSessionCallback);
- method public int download(android.telephony.mbms.DownloadRequest);
+ method public void download(android.telephony.mbms.DownloadRequest);
method public java.io.File getTempFileRootDirectory();
method public java.util.List<android.telephony.mbms.DownloadRequest> listPendingDownloads();
- method public int removeProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener);
- method public int removeStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener);
+ method public void removeProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener);
+ method public void removeStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener);
method public void requestDownloadState(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo);
method public void requestUpdateFileServices(java.util.List<java.lang.String>);
method public void resetDownloadKnowledge(android.telephony.mbms.DownloadRequest);
@@ -41161,6 +41157,7 @@
field public static final int EMBEDDED_SUBSCRIPTION_RESULT_OK = 0; // 0x0
field public static final int EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR = 1; // 0x1
field public static final java.lang.String EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DETAILED_CODE";
+ field public static final java.lang.String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION";
field public static final java.lang.String META_DATA_CARRIER_ICON = "android.telephony.euicc.carriericon";
}
@@ -41323,6 +41320,7 @@
field public static final int ERROR_MIDDLEWARE_NOT_BOUND = 2; // 0x2
field public static final int ERROR_NO_UNIQUE_MIDDLEWARE = 1; // 0x1
field public static final int SUCCESS = 0; // 0x0
+ field public static final int UNKNOWN = -1; // 0xffffffff
}
public static class MbmsErrors.DownloadErrors {
diff --git a/api/system-current.txt b/api/system-current.txt
index 31a6d4d..3fc10f7 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4544,7 +4544,6 @@
field public static final int EUICC_OTA_NOT_NEEDED = 4; // 0x4
field public static final int EUICC_OTA_STATUS_UNAVAILABLE = 5; // 0x5
field public static final int EUICC_OTA_SUCCEEDED = 3; // 0x3
- field public static final java.lang.String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION";
field public static final java.lang.String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS = "android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTIONS";
}
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 2eabd86..44a8930 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -264,7 +264,7 @@
* @return Whether the dialog is currently showing.
*/
public boolean isShowing() {
- return mShowing;
+ return mDecor == null ? false : mDecor.getVisibility() == View.VISIBLE;
}
/**
diff --git a/core/java/android/bluetooth/BluetoothHearingAid.java b/core/java/android/bluetooth/BluetoothHearingAid.java
index 8f8083e..159e165 100644
--- a/core/java/android/bluetooth/BluetoothHearingAid.java
+++ b/core/java/android/bluetooth/BluetoothHearingAid.java
@@ -421,29 +421,29 @@
}
/**
- * Check whether the device is active.
+ * Get the connected physical Hearing Aid devices that are active
*
* <p>Requires {@link android.Manifest.permission#BLUETOOTH}
* permission.
*
- * @return the connected device that is active or null if no device
- * is active
+ * @return the list of active devices. The first element is the left active
+ * device; the second element is the right active device. If either or both side
+ * is not active, it will be null on that position. Returns empty list on error.
* @hide
*/
@RequiresPermission(Manifest.permission.BLUETOOTH)
- public boolean isActiveDevice(@Nullable BluetoothDevice device) {
- if (VDBG) log("isActiveDevice()");
+ public List<BluetoothDevice> getActiveDevices() {
+ if (VDBG) log("getActiveDevices()");
try {
mServiceLock.readLock().lock();
- if (mService != null && isEnabled()
- && ((device == null) || isValidDevice(device))) {
- return mService.isActiveDevice(device);
+ if (mService != null && isEnabled()) {
+ return mService.getActiveDevices();
}
if (mService == null) Log.w(TAG, "Proxy not attached to service");
- return false;
+ return new ArrayList<>();
} catch (RemoteException e) {
Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
- return false;
+ return new ArrayList<>();
} finally {
mServiceLock.readLock().unlock();
}
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
index a3d6968..e017c42 100644
--- a/core/java/android/bluetooth/BluetoothHidDevice.java
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -701,29 +701,6 @@
}
/**
- * Sends Virtual Cable Unplug to currently connected host.
- *
- * @return
- * {@hide}
- */
- public boolean unplug(BluetoothDevice device) {
- boolean result = false;
-
- final IBluetoothHidDevice service = mService;
- if (service != null) {
- try {
- result = service.unplug(device);
- } catch (RemoteException e) {
- Log.e(TAG, e.toString());
- }
- } else {
- Log.w(TAG, "Proxy not attached to service");
- }
-
- return result;
- }
-
- /**
* 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 Callback#onConnectionStateChanged. The
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 9d518e9..40f47b0 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -861,6 +861,10 @@
* You should always check {@link NetworkInfo#isConnected()} before initiating
* network traffic. This may return {@code null} when there is no default
* network.
+ * Note that if the default network is a VPN, this method will return the
+ * NetworkInfo for one of its underlying networks instead, or null if the
+ * VPN agent did not specify any. Apps interested in learning about VPNs
+ * should use {@link #getNetworkInfo(android.net.Network)} instead.
*
* @return a {@link NetworkInfo} object for the current default network
* or {@code null} if no default network is currently active
@@ -1018,7 +1022,11 @@
* which you're interested.
* @return a {@link NetworkInfo} object for the requested
* network type or {@code null} if the type is not
- * supported by the device.
+ * supported by the device. If {@code networkType} is
+ * TYPE_VPN and a VPN is active for the calling app,
+ * then this method will try to return one of the
+ * underlying networks for the VPN or null if the
+ * VPN agent didn't specify any.
*
* @deprecated This method does not support multiple connected networks
* of the same type. Use {@link #getAllNetworks} and
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
index 57f0588..8034bb6 100644
--- a/core/java/android/net/IpSecAlgorithm.java
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -56,7 +56,8 @@
* new applications and is provided for legacy compatibility with 3gpp infrastructure.</b>
*
* <p>Keys for this algorithm must be 128 bits in length.
- * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 128.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 96 to 128.
*/
public static final String AUTH_HMAC_MD5 = "hmac(md5)";
@@ -65,7 +66,8 @@
* new applications and is provided for legacy compatibility with 3gpp infrastructure.</b>
*
* <p>Keys for this algorithm must be 160 bits in length.
- * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 160.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 96 to 160.
*/
public static final String AUTH_HMAC_SHA1 = "hmac(sha1)";
@@ -73,7 +75,8 @@
* SHA256 HMAC Authentication/Integrity Algorithm.
*
* <p>Keys for this algorithm must be 256 bits in length.
- * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 256.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 96 to 256.
*/
public static final String AUTH_HMAC_SHA256 = "hmac(sha256)";
@@ -81,7 +84,8 @@
* SHA384 HMAC Authentication/Integrity Algorithm.
*
* <p>Keys for this algorithm must be 384 bits in length.
- * <p>Valid truncation lengths are multiples of 8 bits from 192 to (default) 384.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 192 to 384.
*/
public static final String AUTH_HMAC_SHA384 = "hmac(sha384)";
@@ -89,7 +93,8 @@
* SHA512 HMAC Authentication/Integrity Algorithm.
*
* <p>Keys for this algorithm must be 512 bits in length.
- * <p>Valid truncation lengths are multiples of 8 bits from 256 to (default) 512.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 256 to 512.
*/
public static final String AUTH_HMAC_SHA512 = "hmac(sha512)";
@@ -112,6 +117,7 @@
AUTH_HMAC_MD5,
AUTH_HMAC_SHA1,
AUTH_HMAC_SHA256,
+ AUTH_HMAC_SHA384,
AUTH_HMAC_SHA512,
AUTH_CRYPT_AES_GCM
})
@@ -126,11 +132,14 @@
* Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are
* defined as constants in this class.
*
+ * <p>For algorithms that produce an integrity check value, the truncation length is a required
+ * parameter. See {@link #IpSecAlgorithm(String algorithm, byte[] key, int truncLenBits)}
+ *
* @param algorithm name of the algorithm.
* @param key key padded to a multiple of 8 bits.
*/
public IpSecAlgorithm(@NonNull @AlgorithmName String algorithm, @NonNull byte[] key) {
- this(algorithm, key, key.length * 8);
+ this(algorithm, key, 0);
}
/**
@@ -228,6 +237,7 @@
case AUTH_CRYPT_AES_GCM:
// The keying material for GCM is a key plus a 32-bit salt
isValidLen = keyLen == 128 + 32 || keyLen == 192 + 32 || keyLen == 256 + 32;
+ isValidTruncLen = truncLen == 64 || truncLen == 96 || truncLen == 128;
break;
default:
throw new IllegalArgumentException("Couldn't find an algorithm: " + name);
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index dc3c765..cc22771 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -274,7 +274,8 @@
*
* @param destinationAddress the destination address for traffic bearing the requested SPI.
* For inbound traffic, the destination should be an address currently assigned on-device.
- * @param requestedSpi the requested SPI, or '0' to allocate a random SPI
+ * @param requestedSpi the requested SPI, or '0' to allocate a random SPI. The range 1-255 is
+ * reserved and may not be used. See RFC 4303 Section 2.1.
* @return the reserved SecurityParameterIndex
* @throws {@link #ResourceUnavailableException} indicating that too many SPIs are
* currently allocated for this user
@@ -335,6 +336,9 @@
*/
public void applyTransportModeTransform(@NonNull Socket socket,
@PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException {
+ // Ensure creation of FD. See b/77548890 for more details.
+ socket.getSoLinger();
+
applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform);
}
@@ -439,6 +443,9 @@
* @throws IOException indicating that the transform could not be removed from the socket
*/
public void removeTransportModeTransforms(@NonNull Socket socket) throws IOException {
+ // Ensure creation of FD. See b/77548890 for more details.
+ socket.getSoLinger();
+
removeTransportModeTransforms(socket.getFileDescriptor$());
}
@@ -502,7 +509,7 @@
* signalling and UDP encapsulated IPsec traffic. Instances can be obtained by calling {@link
* IpSecManager#openUdpEncapsulationSocket}. The provided socket cannot be re-bound by the
* caller. The caller should not close the {@code FileDescriptor} returned by {@link
- * #getSocket}, but should use {@link #close} instead.
+ * #getFileDescriptor}, but should use {@link #close} instead.
*
* <p>Allowing the user to close or unbind a UDP encapsulation socket could impact the traffic
* of the next user who binds to that port. To prevent this scenario, these sockets are held
@@ -541,8 +548,8 @@
mCloseGuard.open("constructor");
}
- /** Get the wrapped socket. */
- public FileDescriptor getSocket() {
+ /** Get the encapsulation socket's file descriptor. */
+ public FileDescriptor getFileDescriptor() {
if (mPfd == null) {
return null;
}
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index 3683d34..f14847f 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -25,6 +25,8 @@
import com.android.okhttp.internalandroidapi.Dns;
import com.android.okhttp.internalandroidapi.HttpURLConnectionFactory;
+import libcore.io.IoUtils;
+
import java.io.FileDescriptor;
import java.io.IOException;
import java.net.DatagramSocket;
@@ -136,9 +138,15 @@
for (int i = 0; i < hostAddresses.length; i++) {
try {
Socket socket = createSocket();
- if (localAddress != null) socket.bind(localAddress);
- socket.connect(new InetSocketAddress(hostAddresses[i], port));
- return socket;
+ boolean failed = true;
+ try {
+ if (localAddress != null) socket.bind(localAddress);
+ socket.connect(new InetSocketAddress(hostAddresses[i], port));
+ failed = false;
+ return socket;
+ } finally {
+ if (failed) IoUtils.closeQuietly(socket);
+ }
} catch (IOException e) {
if (i == (hostAddresses.length - 1)) throw e;
}
@@ -155,15 +163,27 @@
public Socket createSocket(InetAddress address, int port, InetAddress localAddress,
int localPort) throws IOException {
Socket socket = createSocket();
- socket.bind(new InetSocketAddress(localAddress, localPort));
- socket.connect(new InetSocketAddress(address, port));
+ boolean failed = true;
+ try {
+ socket.bind(new InetSocketAddress(localAddress, localPort));
+ socket.connect(new InetSocketAddress(address, port));
+ failed = false;
+ } finally {
+ if (failed) IoUtils.closeQuietly(socket);
+ }
return socket;
}
@Override
public Socket createSocket(InetAddress host, int port) throws IOException {
Socket socket = createSocket();
- socket.connect(new InetSocketAddress(host, port));
+ boolean failed = true;
+ try {
+ socket.connect(new InetSocketAddress(host, port));
+ failed = false;
+ } finally {
+ if (failed) IoUtils.closeQuietly(socket);
+ }
return socket;
}
@@ -175,7 +195,13 @@
@Override
public Socket createSocket() throws IOException {
Socket socket = new Socket();
- bindSocket(socket);
+ boolean failed = true;
+ try {
+ bindSocket(socket);
+ failed = false;
+ } finally {
+ if (failed) IoUtils.closeQuietly(socket);
+ }
return socket;
}
}
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 22cffcc..19f0c90 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -315,7 +315,7 @@
/**
* Capabilities that suggest that a network is restricted.
- * {@see #maybeMarkCapabilitiesRestricted}.
+ * {@see #maybeMarkCapabilitiesRestricted}, {@see #FORCE_RESTRICTED_CAPABILITIES}
*/
@VisibleForTesting
/* package */ static final long RESTRICTED_CAPABILITIES =
@@ -326,7 +326,13 @@
(1 << NET_CAPABILITY_IA) |
(1 << NET_CAPABILITY_IMS) |
(1 << NET_CAPABILITY_RCS) |
- (1 << NET_CAPABILITY_XCAP) |
+ (1 << NET_CAPABILITY_XCAP);
+
+ /**
+ * Capabilities that force network to be restricted.
+ * {@see #maybeMarkCapabilitiesRestricted}.
+ */
+ private static final long FORCE_RESTRICTED_CAPABILITIES =
(1 << NET_CAPABILITY_OEM_PAID);
/**
@@ -531,16 +537,21 @@
* @hide
*/
public void maybeMarkCapabilitiesRestricted() {
+ // Check if we have any capability that forces the network to be restricted.
+ final boolean forceRestrictedCapability =
+ (mNetworkCapabilities & FORCE_RESTRICTED_CAPABILITIES) != 0;
+
// Verify there aren't any unrestricted capabilities. If there are we say
- // the whole thing is unrestricted.
+ // the whole thing is unrestricted unless it is forced to be restricted.
final boolean hasUnrestrictedCapabilities =
- ((mNetworkCapabilities & UNRESTRICTED_CAPABILITIES) != 0);
+ (mNetworkCapabilities & UNRESTRICTED_CAPABILITIES) != 0;
// Must have at least some restricted capabilities.
final boolean hasRestrictedCapabilities =
- ((mNetworkCapabilities & RESTRICTED_CAPABILITIES) != 0);
+ (mNetworkCapabilities & RESTRICTED_CAPABILITIES) != 0;
- if (hasRestrictedCapabilities && !hasUnrestrictedCapabilities) {
+ if (forceRestrictedCapability
+ || (hasRestrictedCapabilities && !hasUnrestrictedCapabilities)) {
removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
}
}
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index 940f985..d6cbc88 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -31,6 +31,7 @@
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.HashSet;
+import java.util.Map;
import java.util.Objects;
/**
@@ -97,6 +98,11 @@
/** Denotes a request for stats at the interface and UID level. */
public static final int STATS_PER_UID = 1;
+ private static final String CLATD_INTERFACE_PREFIX = "v4-";
+ // Delta between IPv4 header (20b) and IPv6 header (40b).
+ // Used for correct stats accounting on clatd interfaces.
+ private static final int IPV4V6_HEADER_DELTA = 20;
+
// TODO: move fields to "mVariable" notation
/**
@@ -752,6 +758,75 @@
}
/**
+ * Calculate and apply adjustments to captured statistics for 464xlat traffic counted twice.
+ *
+ * <p>This mutates both base and stacked traffic stats, to account respectively for
+ * double-counted traffic and IPv4/IPv6 header size difference.
+ *
+ * <p>For 464xlat traffic, xt_qtaguid sees every IPv4 packet twice, once as a native IPv4
+ * packet on the stacked interface, and once as translated to an IPv6 packet on the
+ * base interface. For correct stats accounting on the base interface, every 464xlat
+ * packet needs to be subtracted from the root UID on the base interface both for tx
+ * and rx traffic (http://b/12249687, http:/b/33681750).
+ *
+ * <p>This method will behave fine if {@code stackedIfaces} is an non-synchronized but add-only
+ * {@code ConcurrentHashMap}
+ * @param baseTraffic Traffic on the base interfaces. Will be mutated.
+ * @param stackedTraffic Stats with traffic stacked on top of our ifaces. Will also be mutated.
+ * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both.
+ */
+ public static void apply464xlatAdjustments(NetworkStats baseTraffic,
+ NetworkStats stackedTraffic, Map<String, String> stackedIfaces) {
+ // Total 464xlat traffic to subtract from uid 0 on all base interfaces.
+ // stackedIfaces may grow afterwards, but NetworkStats will just be resized automatically.
+ final NetworkStats adjustments = new NetworkStats(0, stackedIfaces.size());
+
+ // For recycling
+ Entry entry = null;
+ Entry adjust = new NetworkStats.Entry(IFACE_ALL, 0, 0, 0, 0, 0, 0, 0L, 0L, 0L, 0L, 0L);
+
+ for (int i = 0; i < stackedTraffic.size; i++) {
+ entry = stackedTraffic.getValues(i, entry);
+ if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) {
+ continue;
+ }
+ final String baseIface = stackedIfaces.get(entry.iface);
+ if (baseIface == null) {
+ continue;
+ }
+ // Subtract any 464lat traffic seen for the root UID on the current base interface.
+ adjust.iface = baseIface;
+ adjust.rxBytes = -(entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA);
+ adjust.txBytes = -(entry.txBytes + entry.txPackets * IPV4V6_HEADER_DELTA);
+ adjust.rxPackets = -entry.rxPackets;
+ adjust.txPackets = -entry.txPackets;
+ adjustments.combineValues(adjust);
+
+ // For 464xlat traffic, xt_qtaguid only counts the bytes of the native IPv4 packet sent
+ // on the stacked interface with prefix "v4-" and drops the IPv6 header size after
+ // unwrapping. To account correctly for on-the-wire traffic, add the 20 additional bytes
+ // difference for all packets (http://b/12249687, http:/b/33681750).
+ entry.rxBytes += entry.rxPackets * IPV4V6_HEADER_DELTA;
+ entry.txBytes += entry.txPackets * IPV4V6_HEADER_DELTA;
+ stackedTraffic.setValues(i, entry);
+ }
+
+ baseTraffic.combineAllValues(adjustments);
+ }
+
+ /**
+ * Calculate and apply adjustments to captured statistics for 464xlat traffic counted twice.
+ *
+ * <p>This mutates the object this method is called on. Equivalent to calling
+ * {@link #apply464xlatAdjustments(NetworkStats, NetworkStats, Map)} with {@code this} as
+ * base and stacked traffic.
+ * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both.
+ */
+ public void apply464xlatAdjustments(Map<String, String> stackedIfaces) {
+ apply464xlatAdjustments(this, this, stackedIfaces);
+ }
+
+ /**
* Return total statistics grouped by {@link #iface}; doesn't mutate the
* original structure.
*/
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index ecec448..5bf051d 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -4,6 +4,9 @@
import android.util.Log;
import android.util.proto.ProtoOutputStream;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
import java.util.Arrays;
/**
@@ -356,6 +359,15 @@
return result;
}
+ /**
+ * Temporary dummy function.
+ * @hide
+ */
+ public ArrayList<WorkChain> getWorkChains() {
+ return null;
+ }
+
+
private boolean removeUids(WorkSource other) {
int N1 = mNum;
final int[] uids1 = mUids;
@@ -664,6 +676,52 @@
}
}
+ /**
+ * Temporary dummy class for WorkChain. Will be removed.
+ * @hide
+ */
+ public static final class WorkChain implements Parcelable {
+ // @VisibleForTesting
+ public WorkChain() {
+ }
+
+ private WorkChain(Parcel in) {
+ in.readInt();
+ }
+
+ /** @hide */
+ @VisibleForTesting
+ public int[] getUids() {
+ return null;
+ }
+
+ /** @hide */
+ @VisibleForTesting
+ public String[] getTags() {
+ return null;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(0);
+ }
+
+ public static final Parcelable.Creator<WorkChain> CREATOR =
+ new Parcelable.Creator<WorkChain>() {
+ public WorkChain createFromParcel(Parcel in) {
+ return new WorkChain(in);
+ }
+ public WorkChain[] newArray(int size) {
+ return new WorkChain[size];
+ }
+ };
+ }
+
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/se/omapi/Channel.java b/core/java/android/se/omapi/Channel.java
index c8efede..5db3c1a 100644
--- a/core/java/android/se/omapi/Channel.java
+++ b/core/java/android/se/omapi/Channel.java
@@ -39,7 +39,7 @@
*
* @see <a href="http://globalplatform.org">GlobalPlatform Open Mobile API</a>
*/
-public class Channel {
+public final class Channel implements java.nio.channels.Channel {
private static final String TAG = "OMAPI.Channel";
private Session mSession;
@@ -64,7 +64,7 @@
* before closing the channel.
*/
public void close() {
- if (!isClosed()) {
+ if (isOpen()) {
synchronized (mLock) {
try {
mChannel.close();
@@ -76,21 +76,21 @@
}
/**
- * Tells if this channel is closed.
+ * Tells if this channel is open.
*
- * @return <code>true</code> if the channel is closed or in case of an error.
- * <code>false</code> otherwise.
+ * @return <code>false</code> if the channel is closed or in case of an error.
+ * <code>true</code> otherwise.
*/
- public boolean isClosed() {
+ public boolean isOpen() {
if (!mService.isConnected()) {
Log.e(TAG, "service not connected to system");
- return true;
+ return false;
}
try {
- return mChannel.isClosed();
+ return !mChannel.isClosed();
} catch (RemoteException e) {
Log.e(TAG, "Exception in isClosed()");
- return true;
+ return false;
}
}
diff --git a/core/java/android/se/omapi/Reader.java b/core/java/android/se/omapi/Reader.java
index 9be3da6..80262f7 100644
--- a/core/java/android/se/omapi/Reader.java
+++ b/core/java/android/se/omapi/Reader.java
@@ -37,7 +37,7 @@
*
* @see <a href="http://globalplatform.org">GlobalPlatform Open Mobile API</a>
*/
-public class Reader {
+public final class Reader {
private static final String TAG = "OMAPI.Reader";
private final String mName;
diff --git a/core/java/android/se/omapi/SEService.java b/core/java/android/se/omapi/SEService.java
index 311dc4c..14727f0 100644
--- a/core/java/android/se/omapi/SEService.java
+++ b/core/java/android/se/omapi/SEService.java
@@ -32,6 +32,7 @@
import android.util.Log;
import java.util.HashMap;
+import java.util.concurrent.Executor;
/**
* The SEService realises the communication to available Secure Elements on the
@@ -40,7 +41,7 @@
*
* @see <a href="http://simalliance.org">SIMalliance Open Mobile API v3.0</a>
*/
-public class SEService {
+public final class SEService {
/**
* Error code used with ServiceSpecificException.
@@ -62,11 +63,11 @@
/**
* Interface to send call-backs to the application when the service is connected.
*/
- public interface SecureElementListener {
+ public interface OnConnectedListener {
/**
* Called by the framework when the service is connected.
*/
- void onServiceConnected();
+ void onConnected();
}
/**
@@ -74,16 +75,22 @@
* SEService could be bound to the backend.
*/
private class SEListener extends ISecureElementListener.Stub {
- public SecureElementListener mListener = null;
+ public OnConnectedListener mListener = null;
+ public Executor mExecutor = null;
@Override
public IBinder asBinder() {
return this;
}
- public void onServiceConnected() {
- if (mListener != null) {
- mListener.onServiceConnected();
+ public void onConnected() {
+ if (mListener != null && mExecutor != null) {
+ mExecutor.execute(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onConnected();
+ }
+ });
}
}
}
@@ -116,22 +123,26 @@
* the specified listener is called or if isConnected() returns
* <code>true</code>. <br>
* The call-back object passed as a parameter will have its
- * onServiceConnected() method called when the connection actually happen.
+ * onConnected() method called when the connection actually happen.
*
* @param context
* the context of the calling application. Cannot be
* <code>null</code>.
* @param listener
- * a SecureElementListener object.
+ * a OnConnectedListener object.
+ * @param executor
+ * an Executor which will be used when invoking the callback.
*/
- public SEService(@NonNull Context context, @NonNull SecureElementListener listener) {
+ public SEService(@NonNull Context context, @NonNull Executor executor,
+ @NonNull OnConnectedListener listener) {
- if (context == null) {
- throw new NullPointerException("context must not be null");
+ if (context == null || listener == null || executor == null) {
+ throw new NullPointerException("Arguments must not be null");
}
mContext = context;
mSEListener.mListener = listener;
+ mSEListener.mExecutor = executor;
mConnection = new ServiceConnection() {
@@ -140,7 +151,7 @@
mSecureElementService = ISecureElementService.Stub.asInterface(service);
if (mSEListener != null) {
- mSEListener.onServiceConnected();
+ mSEListener.onConnected();
}
Log.i(TAG, "Service onServiceConnected");
}
@@ -171,12 +182,12 @@
}
/**
- * Returns the list of available Secure Element readers.
+ * Returns an array of available Secure Element readers.
* There must be no duplicated objects in the returned list.
* All available readers shall be listed even if no card is inserted.
*
- * @return The readers list, as an array of Readers. If there are no
- * readers the returned array is of length 0.
+ * @return An array of Readers. If there are no readers the returned array
+ * is of length 0.
*/
public @NonNull Reader[] getReaders() {
if (mSecureElementService == null) {
@@ -212,7 +223,8 @@
* (including any binding to an underlying service).
* As a result isConnected() will return false after shutdown() was called.
* After this method call, the SEService object is not connected.
- * It is recommended to call this method in the termination method of the calling application
+ * This method should be called when connection to the Secure Element is not needed
+ * or in the termination method of the calling application
* (or part of this application) which is bound to this SEService.
*/
public void shutdown() {
diff --git a/core/java/android/se/omapi/Session.java b/core/java/android/se/omapi/Session.java
index adfeddd..d5f8c82 100644
--- a/core/java/android/se/omapi/Session.java
+++ b/core/java/android/se/omapi/Session.java
@@ -39,7 +39,7 @@
*
* @see <a href="http://simalliance.org">SIMalliance Open Mobile API v3.0</a>
*/
-public class Session {
+public final class Session {
private final Object mLock = new Object();
private final SEService mService;
@@ -225,6 +225,32 @@
}
/**
+ * This method is provided to ease the development of mobile application and for compliancy
+ * with existing applications.
+ * This method is equivalent to openBasicChannel(aid, P2=0x00)
+ *
+ * @param aid the AID of the Applet to be selected on this channel, as a
+ * byte array, or null if no Applet is to be selected.
+ * @throws IOException if there is a communication problem to the reader or
+ * the Secure Element.
+ * @throws IllegalStateException if the Secure Element session is used after
+ * being closed.
+ * @throws IllegalArgumentException if the aid's length is not within 5 to
+ * 16 (inclusive).
+ * @throws SecurityException if the calling application cannot be granted
+ * access to this AID or the default Applet on this
+ * session.
+ * @throws NoSuchElementException if the AID on the Secure Element is not available or cannot be
+ * selected.
+ * @throws UnsupportedOperationException if the given P2 parameter is not
+ * supported by the device
+ * @return an instance of Channel if available or null.
+ */
+ public @Nullable Channel openBasicChannel(@Nullable byte[] aid) throws IOException {
+ return openBasicChannel(aid, (byte) 0x00);
+ }
+
+ /**
* Open a logical channel with the Secure Element, selecting the Applet represented by
* the given AID. If the AID is null, which means no Applet is to be selected on this
* channel, the default Applet is used. It's up to the Secure Element to choose which
@@ -304,4 +330,32 @@
}
}
}
+
+ /**
+ * This method is provided to ease the development of mobile application and for compliancy
+ * with existing applications.
+ * This method is equivalent to openLogicalChannel(aid, P2=0x00)
+ *
+ * @param aid the AID of the Applet to be selected on this channel, as a
+ * byte array.
+ * @throws IOException if there is a communication problem to the reader or
+ * the Secure Element.
+ * @throws IllegalStateException if the Secure Element is used after being
+ * closed.
+ * @throws IllegalArgumentException if the aid's length is not within 5 to
+ * 16 (inclusive).
+ * @throws SecurityException if the calling application cannot be granted
+ * access to this AID or the default Applet on this
+ * session.
+ * @throws NoSuchElementException if the AID on the Secure Element is not
+ * available or cannot be selected or a logical channel is already
+ * open to a non-multiselectable Applet.
+ * @throws UnsupportedOperationException if the given P2 parameter is not
+ * supported by the device.
+ * @return an instance of Channel. Null if the Secure Element is unable to
+ * provide a new logical channel.
+ */
+ public @Nullable Channel openLogicalChannel(@Nullable byte[] aid) throws IOException {
+ return openLogicalChannel(aid, (byte) 0x00);
+ }
}
diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java
index a4ffbe4..433dd3a 100644
--- a/core/java/android/util/StatsLog.java
+++ b/core/java/android/util/StatsLog.java
@@ -35,6 +35,11 @@
public static final int BLUETOOTH_A2DP_AUDIO_STATE_CHANGED__STATE__PLAY = 1;
public static final int BLUETOOTH_A2DP_AUDIO_STATE_CHANGED__STATE__STOP = 2;
+ public static final int BLE_SCAN_STATE_CHANGED = 2;
+ public static final int BLE_SCAN_STATE_CHANGED__STATE__OFF = 0;
+ public static final int BLE_SCAN_STATE_CHANGED__STATE__ON = 1;
+ public static final int BLE_SCAN_STATE_CHANGED__STATE__RESET = 2;
+
private StatsLog() {}
public static void write(int id, int field1) {}
@@ -43,4 +48,12 @@
public static void write_non_chained(int id, int uid, String tag,
int field1, int field2, String field3) {}
+
+ /** I am a dummy javadoc comment. */
+ public static void write(int code, int[] uid, String[] tag, int arg2,
+ boolean arg3, boolean arg4, boolean arg5) {};
+
+ /** I am a dummy javadoc comment. */
+ public static void write_non_chained(int code, int arg1, String arg2, int arg3,
+ boolean arg4, boolean arg5, boolean arg6) {};
}
diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java
index 8172a20..8561bf0 100644
--- a/core/java/com/android/internal/net/NetworkStatsFactory.java
+++ b/core/java/com/android/internal/net/NetworkStatsFactory.java
@@ -54,11 +54,6 @@
private static final boolean USE_NATIVE_PARSING = true;
private static final boolean SANITY_CHECK_NATIVE = false;
- private static final String CLATD_INTERFACE_PREFIX = "v4-";
- // Delta between IPv4 header (20b) and IPv6 header (40b).
- // Used for correct stats accounting on clatd interfaces.
- private static final int IPV4V6_HEADER_DELTA = 20;
-
/** Path to {@code /proc/net/dev}. */
private final File mStatsIfaceDev;
/** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */
@@ -94,7 +89,7 @@
* {@link #noteStackedIface(String, String)}, but only interfaces noted before this method
* is called are guaranteed to be included.
*/
- public static String[] augmentWithStackedInterfacesLocked(@Nullable String[] requiredIfaces) {
+ public static String[] augmentWithStackedInterfaces(@Nullable String[] requiredIfaces) {
if (requiredIfaces == NetworkStats.INTERFACES_ALL) {
return null;
}
@@ -116,6 +111,15 @@
return relatedIfaces.toArray(outArray);
}
+ /**
+ * Applies 464xlat adjustments with ifaces noted with {@link #noteStackedIface(String, String)}.
+ * @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map)
+ */
+ public static void apply464xlatAdjustments(NetworkStats baseTraffic,
+ NetworkStats stackedTraffic) {
+ NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, sStackedIfaces);
+ }
+
@VisibleForTesting
public static void clearStackedIfaces() {
sStackedIfaces.clear();
@@ -287,48 +291,10 @@
NetworkStats lastStats) throws IOException {
final NetworkStats stats =
readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag, lastStats);
- // Total 464xlat traffic to subtract from uid 0 on all base interfaces.
- // sStackedIfaces may grow afterwards, but NetworkStats will just be resized automatically.
- final NetworkStats adjustments = new NetworkStats(0, sStackedIfaces.size());
- NetworkStats.Entry entry = null; // For recycling
-
- // For 464xlat traffic, xt_qtaguid sees every IPv4 packet twice, once as a native IPv4
- // packet on the stacked interface, and once as translated to an IPv6 packet on the
- // base interface. For correct stats accounting on the base interface, every 464xlat
- // packet needs to be subtracted from the root UID on the base interface both for tx
- // and rx traffic (http://b/12249687, http:/b/33681750).
- for (int i = 0; i < stats.size(); i++) {
- entry = stats.getValues(i, entry);
- if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) {
- continue;
- }
- final String baseIface = sStackedIfaces.get(entry.iface);
- if (baseIface == null) {
- continue;
- }
-
- NetworkStats.Entry adjust =
- new NetworkStats.Entry(baseIface, 0, 0, 0, 0, 0, 0, 0L, 0L, 0L, 0L, 0L);
- // Subtract any 464lat traffic seen for the root UID on the current base interface.
- adjust.rxBytes -= (entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA);
- adjust.txBytes -= (entry.txBytes + entry.txPackets * IPV4V6_HEADER_DELTA);
- adjust.rxPackets -= entry.rxPackets;
- adjust.txPackets -= entry.txPackets;
- adjustments.combineValues(adjust);
-
- // For 464xlat traffic, xt_qtaguid only counts the bytes of the native IPv4 packet sent
- // on the stacked interface with prefix "v4-" and drops the IPv6 header size after
- // unwrapping. To account correctly for on-the-wire traffic, add the 20 additional bytes
- // difference for all packets (http://b/12249687, http:/b/33681750).
- entry.rxBytes = entry.rxPackets * IPV4V6_HEADER_DELTA;
- entry.txBytes = entry.txPackets * IPV4V6_HEADER_DELTA;
- entry.rxPackets = 0;
- entry.txPackets = 0;
- stats.combineValues(entry);
- }
-
- stats.combineAllValues(adjustments);
+ // No locking here: apply464xlatAdjustments behaves fine with an add-only ConcurrentHashMap.
+ // TODO: remove this and only apply adjustments in NetworkStatsService.
+ stats.apply464xlatAdjustments(sStackedIfaces);
return stats;
}
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index bb5a0ad..a9cd5c8 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -34,6 +34,7 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.util.Objects;
import java.util.TimeZone;
import java.util.logging.LogManager;
import org.apache.harmony.luni.internal.util.TimezoneGetter;
@@ -67,8 +68,12 @@
* but apps can override that behavior.
*/
private static class LoggingHandler implements Thread.UncaughtExceptionHandler {
+ public volatile boolean mTriggered = false;
+
@Override
public void uncaughtException(Thread t, Throwable e) {
+ mTriggered = true;
+
// Don't re-enter if KillApplicationHandler has already run
if (mCrashing) return;
@@ -96,12 +101,33 @@
/**
* Handle application death from an uncaught exception. The framework
* catches these for the main threads, so this should only matter for
- * threads created by applications. Before this method runs,
- * {@link LoggingHandler} will already have logged details.
+ * threads created by applications. Before this method runs, the given
+ * instance of {@link LoggingHandler} should already have logged details
+ * (and if not it is run first).
*/
private static class KillApplicationHandler implements Thread.UncaughtExceptionHandler {
+ private final LoggingHandler mLoggingHandler;
+
+ /**
+ * Create a new KillApplicationHandler that follows the given LoggingHandler.
+ * If {@link #uncaughtException(Thread, Throwable) uncaughtException} is called
+ * on the created instance without {@code loggingHandler} having been triggered,
+ * {@link LoggingHandler#uncaughtException(Thread, Throwable)
+ * loggingHandler.uncaughtException} will be called first.
+ *
+ * @param loggingHandler the {@link LoggingHandler} expected to have run before
+ * this instance's {@link #uncaughtException(Thread, Throwable) uncaughtException}
+ * is being called.
+ */
+ public KillApplicationHandler(LoggingHandler loggingHandler) {
+ this.mLoggingHandler = Objects.requireNonNull(loggingHandler);
+ }
+
+ @Override
public void uncaughtException(Thread t, Throwable e) {
try {
+ ensureLogging(t, e);
+
// Don't re-enter -- avoid infinite loops if crash-reporting crashes.
if (mCrashing) return;
mCrashing = true;
@@ -132,6 +158,33 @@
System.exit(10);
}
}
+
+ /**
+ * Ensures that the logging handler has been triggered.
+ *
+ * See b/73380984. This reinstates the pre-O behavior of
+ *
+ * {@code thread.getUncaughtExceptionHandler().uncaughtException(thread, e);}
+ *
+ * logging the exception (in addition to killing the app). This behavior
+ * was never documented / guaranteed but helps in diagnostics of apps
+ * using the pattern.
+ *
+ * If this KillApplicationHandler is invoked the "regular" way (by
+ * {@link Thread#dispatchUncaughtException(Throwable)
+ * Thread.dispatchUncaughtException} in case of an uncaught exception)
+ * then the pre-handler (expected to be {@link #mLoggingHandler}) will already
+ * have run. Otherwise, we manually invoke it here.
+ */
+ private void ensureLogging(Thread t, Throwable e) {
+ if (!mLoggingHandler.mTriggered) {
+ try {
+ mLoggingHandler.uncaughtException(t, e);
+ } catch (Throwable loggingThrowable) {
+ // Ignored.
+ }
+ }
+ }
}
protected static final void commonInit() {
@@ -141,8 +194,9 @@
* set handlers; these apply to all threads in the VM. Apps can replace
* the default handler, but not the pre handler.
*/
- Thread.setUncaughtExceptionPreHandler(new LoggingHandler());
- Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler());
+ LoggingHandler loggingHandler = new LoggingHandler();
+ Thread.setUncaughtExceptionPreHandler(loggingHandler);
+ Thread.setDefaultUncaughtExceptionHandler(new KillApplicationHandler(loggingHandler));
/*
* Install a TimezoneGetter subclass for ZoneInfo.db
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 6c46cfc..7f6d19b 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -591,7 +591,6 @@
{
JavaVMInitArgs initArgs;
char propBuf[PROPERTY_VALUE_MAX];
- char stackTraceFileBuf[sizeof("-Xstacktracefile:")-1 + PROPERTY_VALUE_MAX];
char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
char heapstartsizeOptsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
char heapsizeOptsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
@@ -673,15 +672,7 @@
executionMode = kEMJitCompiler;
}
- // If dalvik.vm.stack-trace-dir is set, it enables the "new" stack trace
- // dump scheme and a new file is created for each stack dump. If it isn't set,
- // the old scheme is enabled.
- property_get("dalvik.vm.stack-trace-dir", propBuf, "");
- if (strlen(propBuf) > 0) {
- addOption("-Xusetombstonedtraces");
- } else {
- parseRuntimeOption("dalvik.vm.stack-trace-file", stackTraceFileBuf, "-Xstacktracefile:");
- }
+ addOption("-Xusetombstonedtraces");
strcpy(jniOptsBuf, "-Xjniopts:");
if (parseRuntimeOption("dalvik.vm.jniopts", jniOptsBuf, "-Xjniopts:")) {
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index f1b736b..e5281ff 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -260,7 +260,7 @@
}
// Apply system or app filter based on uid.
- if (getuid() >= AID_APP_START) {
+ if (uid >= AID_APP_START) {
set_app_seccomp_filter();
} else {
set_system_seccomp_filter();
@@ -619,11 +619,6 @@
fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
}
- // Must be called when the new process still has CAP_SYS_ADMIN. The other alternative is to
- // call prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that breaks SELinux domain transition (see
- // b/71859146).
- SetUpSeccompFilter(uid);
-
// Keep capabilities across UID change, unless we're staying root.
if (uid != 0) {
if (!EnableKeepCapabilities(&error_msg)) {
@@ -697,6 +692,13 @@
fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno)));
}
+ // Must be called when the new process still has CAP_SYS_ADMIN, in this case, before changing
+ // uid from 0, which clears capabilities. The other alternative is to call
+ // prctl(PR_SET_NO_NEW_PRIVS, 1) afterward, but that breaks SELinux domain transition (see
+ // b/71859146). As the result, privileged syscalls used below still need to be accessible in
+ // app process.
+ SetUpSeccompFilter(uid);
+
rc = setresuid(uid, uid, uid);
if (rc == -1) {
fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno)));
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index f5b350b..8947bf0 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -34,7 +34,7 @@
http://smscoin.net/software/engine/WordPress/Paid+SMS-registration/ -->
<!-- Arab Emirates -->
- <shortcode country="ae" free="3214|1017" />
+ <shortcode country="ae" pattern="\\d{1,5}" free="3214|1017" />
<!-- Albania: 5 digits, known short codes listed -->
<shortcode country="al" pattern="\\d{5}" premium="15191|55[56]00" />
@@ -80,7 +80,7 @@
<shortcode country="cn" premium="1066.*" free="1065.*" />
<!-- Colombia: 1-6 digits (not confirmed) -->
- <shortcode country="co" pattern="\\d{1,6}" free="890350" />
+ <shortcode country="co" pattern="\\d{1,6}" free="890350|908160" />
<!-- Cyprus: 4-6 digits (not confirmed), known premium codes listed, plus EU -->
<shortcode country="cy" pattern="\\d{4,6}" premium="7510" free="116\\d{3}" />
@@ -126,7 +126,7 @@
<shortcode country="gr" pattern="\\d{5}" premium="54\\d{3}|19[0-5]\\d{2}" free="116\\d{3}|12115" />
<!-- Croatia -->
- <shortcode country="hr" free="13062" />
+ <shortcode country="hr" pattern="\\d{1,5}" free="13062" />
<!-- Hungary: 4 or 10 digits starting with 1 or 0, plus EU:
http://clients.txtnation.com/entries/209633-hungary-premium-sms-short-code-regulations -->
@@ -150,7 +150,7 @@
<shortcode country="it" pattern="\\d{5}" premium="4\\d{4}" free="116\\d{3}|4112503" standard="43\\d{3}" />
<!-- Japan: 8083 used by SOFTBANK_DCB_2 -->
- <shortcode country="jp" free="8083" />
+ <shortcode country="jp" pattern="\\d{1,5}" free="8083" />
<!-- Kenya: 5 digits, known premium codes listed -->
<shortcode country="ke" pattern="\\d{5}" free="21725" />
@@ -165,10 +165,10 @@
<shortcode country="kz" pattern="\\d{4}" premium="335[02]|4161|444[469]|77[2359]0|8444|919[3-5]|968[2-5]" />
<!-- Kuwait: 1-5 digits (standard system default, not country specific) -->
- <shortcode country="kw" pattern="\\d{1,5}" free="1378|50420|94006" />
+ <shortcode country="kw" pattern="\\d{1,5}" free="1378|50420|94006|55991" />
<!-- Lithuania: 3-5 digits, known premium codes listed, plus EU -->
- <shortcode country="lt" pattern="\\d{3,5}" premium="13[89]1|1394|16[34]5" free="116\\d{3}|1399" />
+ <shortcode country="lt" pattern="\\d{3,5}" premium="13[89]1|1394|16[34]5" free="116\\d{3}|1399|1324" />
<!-- Luxembourg: 5 digits, 6xxxx, plus EU:
http://www.luxgsm.lu/assets/files/filepage/file_1253803400.pdf -->
@@ -199,10 +199,10 @@
<shortcode country="pe" pattern="\\d{4,5}" free="9963" />
<!-- Philippines -->
- <shortcode country="ph" free="2147|5495|5496" />
+ <shortcode country="ph" pattern="\\d{1,5}" free="2147|5495|5496" />
<!-- Pakistan -->
- <shortcode country="pk" free="2057" />
+ <shortcode country="pk" pattern="\\d{1,5}" free="2057" />
<!-- Poland: 4-5 digits (not confirmed), known premium codes listed, plus EU -->
<shortcode country="pl" pattern="\\d{4,5}" premium="74240|79(?:10|866)|92525" free="116\\d{3}|8012|80921" />
@@ -224,7 +224,7 @@
<shortcode country="ru" pattern="\\d{4}" premium="1(?:1[56]1|899)|2(?:09[57]|322|47[46]|880|990)|3[589]33|4161|44(?:4[3-9]|81)|77(?:33|81)|8424" free="6954|8501" standard="2037|2044"/>
<!-- Saudi Arabia -->
- <shortcode country="sa" free="8145" />
+ <shortcode country="sa" pattern="\\d{1,5}" free="8145" />
<!-- Sweden: 5 digits (72xxx), plus EU: http://www.viatel.se/en/premium-sms/ -->
<shortcode country="se" premium="72\\d{3}" free="116\\d{3}" />
@@ -240,13 +240,13 @@
<shortcode country="sk" premium="\\d{4}" free="116\\d{3}|8000" />
<!-- Thailand: 4186001 used by AIS_TH_DCB -->
- <shortcode country="th" free="4186001" />
+ <shortcode country="th" pattern="\\d{1,5}" free="4186001" />
<!-- Tajikistan: 4 digits, known premium codes listed -->
<shortcode country="tj" pattern="\\d{4}" premium="11[3-7]1|4161|4333|444[689]" />
<!-- Turkey -->
- <shortcode country="tr" free="7529|5528|6493" />
+ <shortcode country="tr" pattern="\\d{1,5}" free="7529|5528|6493" />
<!-- Ukraine: 4 digits, known premium codes listed -->
<shortcode country="ua" pattern="\\d{4}" premium="444[3-9]|70[579]4|7540" />
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index b767046..11360a1 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -62,7 +62,7 @@
"uniform mediump vec4 roundRectInnerRectLTWH;\n"
"uniform mediump float roundRectRadius;\n";
const char* gVS_Header_Varyings_HasTexture =
- "varying vec2 outTexCoords;\n";
+ "varying highp vec2 outTexCoords;\n";
const char* gVS_Header_Varyings_HasColors =
"varying vec4 outColors;\n";
const char* gVS_Header_Varyings_HasVertexAlpha =
diff --git a/packages/CaptivePortalLogin/Android.mk b/packages/CaptivePortalLogin/Android.mk
index 7dc23ff..8a96b16 100644
--- a/packages/CaptivePortalLogin/Android.mk
+++ b/packages/CaptivePortalLogin/Android.mk
@@ -2,7 +2,7 @@
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 services.net
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index 7828c4c..2a1bbed 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -30,6 +30,7 @@
import android.net.NetworkRequest;
import android.net.Proxy;
import android.net.Uri;
+import android.net.dns.ResolvUtil;
import android.net.http.SslError;
import android.os.Build;
import android.os.Bundle;
@@ -118,6 +119,8 @@
// Also initializes proxy system properties.
mCm.bindProcessToNetwork(mNetwork);
+ mCm.setProcessDefaultNetworkForHostResolution(
+ ResolvUtil.getNetworkWithUseLocalNameserversFlag(mNetwork));
// Proxy system properties must be initialized before setContentView is called because
// setContentView initializes the WebView logic which in turn reads the system properties.
diff --git a/packages/CarrierDefaultApp/Android.mk b/packages/CarrierDefaultApp/Android.mk
index df88afd..5068b3b 100644
--- a/packages/CarrierDefaultApp/Android.mk
+++ b/packages/CarrierDefaultApp/Android.mk
@@ -9,6 +9,8 @@
LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
+LOCAL_STATIC_JAVA_LIBRARIES := services.net
+
include $(BUILD_PACKAGE)
# This finds and builds the test apk as well, so a single make does both.
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
index 95ec83d..7479d9a 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
@@ -32,6 +32,7 @@
import android.net.Proxy;
import android.net.TrafficStats;
import android.net.Uri;
+import android.net.dns.ResolvUtil;
import android.net.http.SslError;
import android.os.Bundle;
import android.telephony.CarrierConfigManager;
@@ -115,6 +116,8 @@
requestNetworkForCaptivePortal();
} else {
mCm.bindProcessToNetwork(mNetwork);
+ mCm.setProcessDefaultNetworkForHostResolution(
+ ResolvUtil.getNetworkWithUseLocalNameserversFlag(mNetwork));
// Start initial page load so WebView finishes loading proxy settings.
// Actual load of mUrl is initiated by MyWebViewClient.
mWebView.loadData("", "text/html", null);
diff --git a/packages/InputDevices/res/raw/keyboard_layout_polish.kcm b/packages/InputDevices/res/raw/keyboard_layout_polish.kcm
new file mode 100644
index 0000000..559ec07
--- /dev/null
+++ b/packages/InputDevices/res/raw/keyboard_layout_polish.kcm
@@ -0,0 +1,327 @@
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+#
+# Polish (qwerty) 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: '@'
+}
+
+key 3 {
+ label: '3'
+ base: '3'
+ shift: '#'
+}
+
+key 4 {
+ label: '4'
+ base: '4'
+ shift: '$'
+}
+
+key 5 {
+ label: '5'
+ base: '5'
+ shift: '%'
+}
+
+key 6 {
+ label: '6'
+ base: '6'
+ shift: '^'
+}
+
+key 7 {
+ label: '7'
+ base: '7'
+ shift: '&'
+}
+
+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: 'W'
+ base: 'w'
+ shift, capslock: 'W'
+}
+
+key E {
+ label: 'E'
+ base: 'e'
+ shift, capslock: 'E'
+ ralt: '\u0119'
+ ralt+shift, ralt+capslock: '\u0118'
+}
+
+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: 'I'
+ base: 'i'
+ shift, capslock: 'I'
+}
+
+key O {
+ label: 'O'
+ base: 'o'
+ shift, capslock: 'O'
+ ralt: '\u00F3'
+ ralt+shift, ralt+capslock: '\u00D3'
+}
+
+key P {
+ label: 'P'
+ base: 'p'
+ shift, capslock: 'P'
+}
+
+key LEFT_BRACKET {
+ label: '['
+ base: '['
+ shift: '{'
+}
+
+key RIGHT_BRACKET {
+ label: ']'
+ base: ']'
+ shift: '}'
+}
+
+key BACKSLASH {
+ label: '\\'
+ base: '\\'
+ shift: '|'
+}
+
+### ROW 3
+
+key A {
+ label: 'A'
+ base: 'a'
+ shift, capslock: 'A'
+ ralt: '\u0105'
+ ralt+shift, ralt+capslock: '\u0104'
+}
+
+key S {
+ label: 'S'
+ base: 's'
+ shift, capslock: 'S'
+ ralt: '\u015b'
+ ralt+shift, ralt+capslock: '\u015a'
+}
+
+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'
+ ralt: '\u0142'
+ ralt+shift, ralt+capslock: '\u0141'
+}
+
+key SEMICOLON {
+ label: ';'
+ base: ';'
+ shift: ':'
+}
+
+key APOSTROPHE {
+ label: '\''
+ base: '\''
+ shift: '"'
+}
+
+### ROW 4
+
+key Z {
+ label: 'Z'
+ base: 'z'
+ shift, capslock: 'Z'
+ ralt: '\u017c'
+ ralt+shift, ralt+capslock: '\u017b'
+}
+
+key X {
+ label: 'X'
+ base: 'x'
+ shift, capslock: 'X'
+ ralt: '\u017a'
+ ralt+shift, ralt+capslock: '\u0179'
+}
+
+key C {
+ label: 'C'
+ base: 'c'
+ shift, capslock: 'C'
+ ralt: '\u0107'
+ ralt+shift, ralt+capslock: '\u0106'
+}
+
+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'
+ ralt: '\u0144'
+ ralt+shift, ralt+capslock: '\u0143'
+}
+
+key M {
+ label: 'M'
+ base: 'm'
+ shift, capslock: 'M'
+}
+
+key COMMA {
+ label: ','
+ base: ','
+ shift: '<'
+}
+
+key PERIOD {
+ label: '.'
+ base: '.'
+ shift: '>'
+}
+
+key SLASH {
+ label: '/'
+ base: '/'
+ shift: '?'
+}
diff --git a/packages/InputDevices/res/values/strings.xml b/packages/InputDevices/res/values/strings.xml
index 61d3234..5fdc4a6 100644
--- a/packages/InputDevices/res/values/strings.xml
+++ b/packages/InputDevices/res/values/strings.xml
@@ -125,4 +125,7 @@
<!-- Azerbaijani keyboard layout label. [CHAR LIMIT=35] -->
<string name="keyboard_layout_azerbaijani">Azerbaijani</string>
+
+ <!-- Polish keyboard layout label. [CHAR LIMIT=35] -->
+ <string name="keyboard_layout_polish">Polish</string>
</resources>
diff --git a/packages/InputDevices/res/xml/keyboard_layouts.xml b/packages/InputDevices/res/xml/keyboard_layouts.xml
index c6bfc1f..1807aea 100644
--- a/packages/InputDevices/res/xml/keyboard_layouts.xml
+++ b/packages/InputDevices/res/xml/keyboard_layouts.xml
@@ -159,4 +159,8 @@
<keyboard-layout android:name="keyboard_layout_azerbaijani"
android:label="@string/keyboard_layout_azerbaijani"
android:keyboardLayout="@raw/keyboard_layout_azerbaijani" />
+
+ <keyboard-layout android:name="keyboard_layout_polish"
+ android:label="@string/keyboard_layout_polish"
+ android:keyboardLayout="@raw/keyboard_layout_polish" />
</keyboard-layouts>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index b83b8e1..61b88a5 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -501,30 +501,30 @@
<!-- UI debug setting: Select Bluetooth AVRCP Version -->
<string name="bluetooth_select_avrcp_version_dialog_title">Select Bluetooth AVRCP Version</string>
- <!-- UI debug setting: Select Bluetooth Audio Codec -->
+ <!-- UI debug setting: Trigger Bluetooth Audio Codec Selection -->
<string name="bluetooth_select_a2dp_codec_type">Bluetooth Audio Codec</string>
- <!-- UI debug setting: Select Bluetooth Audio Codec -->
- <string name="bluetooth_select_a2dp_codec_type_dialog_title">Select Bluetooth Audio Codec</string>
+ <!-- UI debug setting: Trigger Bluetooth Audio Codec Selection -->
+ <string name="bluetooth_select_a2dp_codec_type_dialog_title">Trigger Bluetooth Audio Codec\u000ASelection</string>
- <!-- UI debug setting: Select Bluetooth Audio Sample Rate -->
+ <!-- UI debug setting: Trigger Bluetooth Audio Sample Rate Selection -->
<string name="bluetooth_select_a2dp_codec_sample_rate">Bluetooth Audio Sample Rate</string>
- <!-- UI debug setting: Select Bluetooth Audio Codec: Sample Rate -->
- <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title">Select Bluetooth Audio Codec:\u000ASample Rate</string>
+ <!-- UI debug setting: Trigger Bluetooth Audio Codec Selection: Sample Rate -->
+ <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title">Trigger Bluetooth Audio Codec\u000ASelection: Sample Rate</string>
- <!-- UI debug setting: Select Bluetooth Audio Bits Per Sample -->
+ <!-- UI debug setting: Trigger Bluetooth Audio Bits Per Sample Selection -->
<string name="bluetooth_select_a2dp_codec_bits_per_sample">Bluetooth Audio Bits Per Sample</string>
- <!-- UI debug setting: Select Bluetooth Audio Codec: Bits Per Sample -->
- <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title">Select Bluetooth Audio Codec:\u000ABits Per Sample</string>
+ <!-- UI debug setting: Trigger Bluetooth Audio Codec Selection: Bits Per Sample -->
+ <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title">Trigger Bluetooth Audio Codec\u000ASelection: Bits Per Sample</string>
- <!-- UI debug setting: Select Bluetooth Audio Channel Mode -->
+ <!-- UI debug setting: Trigger Bluetooth Audio Channel Mode Selection -->
<string name="bluetooth_select_a2dp_codec_channel_mode">Bluetooth Audio Channel Mode</string>
- <!-- UI debug setting: Select Bluetooth Audio Codec: Channel Mode -->
- <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title">Select Bluetooth Audio Codec:\u000AChannel Mode</string>
+ <!-- UI debug setting: Trigger Bluetooth Audio Codec Selection: Channel Mode -->
+ <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title">Trigger Bluetooth Audio Codec\u000ASelection: Channel Mode</string>
- <!-- UI debug setting: Select Bluetooth Audio LDAC Playback Quality -->
+ <!-- UI debug setting: Trigger Bluetooth Audio LDAC Playback Quality Selection -->
<string name="bluetooth_select_a2dp_codec_ldac_playback_quality">Bluetooth Audio LDAC Codec: Playback Quality</string>
<!-- UI debug setting: Select Bluetooth Audio LDAC Codec: LDAC Playback Quality -->
- <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title">Select Bluetooth Audio LDAC Codec:\u000APlayback Quality</string>
+ <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title">Trigger Bluetooth Audio LDAC Codec\u000ASelection: Playback Quality</string>
<!-- [CHAR LIMIT=NONE] Label for displaying Bluetooth Audio Codec Parameters while streaming -->
<string name="bluetooth_select_a2dp_codec_streaming_label">Streaming: <xliff:g id="streaming_parameter">%1$s</xliff:g></string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 6c068ff..dc2ecea 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -631,7 +631,7 @@
}
HearingAidProfile hearingAidProfile = mProfileManager.getHearingAidProfile();
if (hearingAidProfile != null) {
- mIsActiveDeviceHearingAid = hearingAidProfile.isActiveDevice(mDevice);
+ mIsActiveDeviceHearingAid = hearingAidProfile.getActiveDevices().contains(mDevice);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
index 920500f..6c5ecbf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java
@@ -136,13 +136,12 @@
public boolean setActiveDevice(BluetoothDevice device) {
if (mService == null) return false;
- mService.setActiveDevice(device);
- return true;
+ return mService.setActiveDevice(device);
}
- public boolean isActiveDevice(BluetoothDevice device) {
- if (mService == null) return false;
- return mService.isActiveDevice(device);
+ public List<BluetoothDevice> getActiveDevices() {
+ if (mService == null) return new ArrayList<>();
+ return mService.getActiveDevices();
}
public boolean isPreferred(BluetoothDevice device) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index ae7ac8f..995f926 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -878,7 +878,12 @@
private Tethering makeTethering() {
// TODO: Move other elements into @Overridden getters.
- final TetheringDependencies deps = new TetheringDependencies();
+ final TetheringDependencies deps = new TetheringDependencies() {
+ @Override
+ public boolean isTetheringSupported() {
+ return ConnectivityService.this.isTetheringSupported();
+ }
+ };
return new Tethering(mContext, mNetd, mStatsService, mPolicyManager,
IoThread.get().getLooper(), new MockableSystemProperties(),
deps);
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index d09a161..bde6bd8 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -931,7 +931,7 @@
return mPort;
}
- public FileDescriptor getSocket() {
+ public FileDescriptor getFileDescriptor() {
return mSocket;
}
@@ -1065,7 +1065,10 @@
public synchronized IpSecSpiResponse allocateSecurityParameterIndex(
String destinationAddress, int requestedSpi, IBinder binder) throws RemoteException {
checkInetAddress(destinationAddress);
- /* requestedSpi can be anything in the int range, so no check is needed. */
+ // RFC 4303 Section 2.1 - 0=local, 1-255=reserved.
+ if (requestedSpi > 0 && requestedSpi < 256) {
+ throw new IllegalArgumentException("ESP SPI must not be in the range of 0-255.");
+ }
checkNotNull(binder, "Null Binder passed to allocateSecurityParameterIndex");
UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 53285e6..155febd 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -587,13 +587,8 @@
}
private File dumpKernelStackTraces() {
- String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
- if (tracesPath == null || tracesPath.length() == 0) {
- return null;
- }
-
- native_dumpKernelStacks(tracesPath);
- return new File(tracesPath);
+ native_dumpKernelStacks("/data/anr");
+ return new File("/data/anr");
}
private native void native_dumpKernelStacks(String tracesPath);
@@ -615,14 +610,6 @@
return null;
}
- // Don't run the FD monitor on builds that have a global ANR trace file. We're using
- // the ANR trace directory as a quick hack in order to get these traces in bugreports
- // and we wouldn't want to overwrite something important.
- final String dumpDirStr = SystemProperties.get("dalvik.vm.stack-trace-dir", "");
- if (dumpDirStr.isEmpty()) {
- return null;
- }
-
final StructRlimit rlimit;
try {
rlimit = android.system.Os.getrlimit(OsConstants.RLIMIT_NOFILE);
@@ -639,7 +626,7 @@
// We do this to avoid having to enumerate the contents of /proc/self/fd in order to
// count the number of descriptors open in the process.
final File fdThreshold = new File("/proc/self/fd/" + (rlimit.rlim_cur - FD_HIGH_WATER_MARK));
- return new OpenFdMonitor(new File(dumpDirStr), fdThreshold);
+ return new OpenFdMonitor(new File("/data/anr"), fdThreshold);
}
OpenFdMonitor(File dumpDir, File fdThreshold) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 6b4cd4b..7cfc8af 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5610,57 +5610,20 @@
}
}
- boolean useTombstonedForJavaTraces = false;
- File tracesFile;
+ final File tracesDir = new File("/data/anr");
+ // Each set of ANR traces is written to a separate file and dumpstate will process
+ // all such files and add them to a captured bug report if they're recent enough.
+ maybePruneOldTraces(tracesDir);
- final String tracesDirProp = SystemProperties.get("dalvik.vm.stack-trace-dir", "");
- if (tracesDirProp.isEmpty()) {
- // When dalvik.vm.stack-trace-dir is not set, we are using the "old" trace
- // dumping scheme. All traces are written to a global trace file (usually
- // "/data/anr/traces.txt") so the code below must take care to unlink and recreate
- // the file if requested.
- //
- // This mode of operation will be removed in the near future.
-
-
- String globalTracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
- if (globalTracesPath.isEmpty()) {
- Slog.w(TAG, "dumpStackTraces: no trace path configured");
- return null;
- }
-
- tracesFile = new File(globalTracesPath);
- try {
- if (clearTraces && tracesFile.exists()) {
- tracesFile.delete();
- }
-
- tracesFile.createNewFile();
- FileUtils.setPermissions(globalTracesPath, 0666, -1, -1); // -rw-rw-rw-
- } catch (IOException e) {
- Slog.w(TAG, "Unable to prepare ANR traces file: " + tracesFile, e);
- return null;
- }
- } else {
- File tracesDir = new File(tracesDirProp);
- // When dalvik.vm.stack-trace-dir is set, we use the "new" trace dumping scheme.
- // Each set of ANR traces is written to a separate file and dumpstate will process
- // all such files and add them to a captured bug report if they're recent enough.
- maybePruneOldTraces(tracesDir);
-
- // NOTE: We should consider creating the file in native code atomically once we've
- // gotten rid of the old scheme of dumping and lot of the code that deals with paths
- // can be removed.
- tracesFile = createAnrDumpFile(tracesDir);
- if (tracesFile == null) {
- return null;
- }
-
- useTombstonedForJavaTraces = true;
+ // NOTE: We should consider creating the file in native code atomically once we've
+ // gotten rid of the old scheme of dumping and lot of the code that deals with paths
+ // can be removed.
+ File tracesFile = createAnrDumpFile(tracesDir);
+ if (tracesFile == null) {
+ return null;
}
- dumpStackTraces(tracesFile.getAbsolutePath(), firstPids, nativePids, extraPids,
- useTombstonedForJavaTraces);
+ dumpStackTraces(tracesFile.getAbsolutePath(), firstPids, nativePids, extraPids);
return tracesFile;
}
@@ -5713,68 +5676,6 @@
}
/**
- * Legacy code, do not use. Existing users will be deleted.
- *
- * @deprecated
- */
- @Deprecated
- public static class DumpStackFileObserver extends FileObserver {
- // Keep in sync with frameworks/native/cmds/dumpstate/utils.cpp
- private static final int TRACE_DUMP_TIMEOUT_MS = 10000; // 10 seconds
-
- private final String mTracesPath;
- private boolean mClosed;
-
- public DumpStackFileObserver(String tracesPath) {
- super(tracesPath, FileObserver.CLOSE_WRITE);
- mTracesPath = tracesPath;
- }
-
- @Override
- public synchronized void onEvent(int event, String path) {
- mClosed = true;
- notify();
- }
-
- public long dumpWithTimeout(int pid, long timeout) {
- sendSignal(pid, SIGNAL_QUIT);
- final long start = SystemClock.elapsedRealtime();
-
- final long waitTime = Math.min(timeout, TRACE_DUMP_TIMEOUT_MS);
- synchronized (this) {
- try {
- wait(waitTime); // Wait for traces file to be closed.
- } catch (InterruptedException e) {
- Slog.wtf(TAG, e);
- }
- }
-
- // This avoids a corner case of passing a negative time to the native
- // trace in case we've already hit the overall timeout.
- final long timeWaited = SystemClock.elapsedRealtime() - start;
- if (timeWaited >= timeout) {
- return timeWaited;
- }
-
- if (!mClosed) {
- Slog.w(TAG, "Didn't see close of " + mTracesPath + " for pid " + pid +
- ". Attempting native stack collection.");
-
- final long nativeDumpTimeoutMs = Math.min(
- NATIVE_DUMP_TIMEOUT_MS, timeout - timeWaited);
-
- Debug.dumpNativeBacktraceToFileTimeout(pid, mTracesPath,
- (int) (nativeDumpTimeoutMs / 1000));
- }
-
- final long end = SystemClock.elapsedRealtime();
- mClosed = false;
-
- return (end - start);
- }
- }
-
- /**
* Dump java traces for process {@code pid} to the specified file. If java trace dumping
* fails, a native backtrace is attempted. Note that the timeout {@code timeoutMs} only applies
* to the java section of the trace, a further {@code NATIVE_DUMP_TIMEOUT_MS} might be spent
@@ -5792,106 +5693,78 @@
}
private static void dumpStackTraces(String tracesFile, ArrayList<Integer> firstPids,
- ArrayList<Integer> nativePids, ArrayList<Integer> extraPids,
- boolean useTombstonedForJavaTraces) {
+ ArrayList<Integer> nativePids, ArrayList<Integer> extraPids) {
// We don't need any sort of inotify based monitoring when we're dumping traces via
// tombstoned. Data is piped to an "intercept" FD installed in tombstoned so we're in full
// control of all writes to the file in question.
- final DumpStackFileObserver observer;
- if (useTombstonedForJavaTraces) {
- observer = null;
- } else {
- // Use a FileObserver to detect when traces finish writing.
- // The order of traces is considered important to maintain for legibility.
- observer = new DumpStackFileObserver(tracesFile);
- }
// We must complete all stack dumps within 20 seconds.
long remainingTime = 20 * 1000;
- try {
- if (observer != null) {
- observer.startWatching();
+
+ // First collect all of the stacks of the most important pids.
+ if (firstPids != null) {
+ int num = firstPids.size();
+ for (int i = 0; i < num; i++) {
+ if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for pid " + firstPids.get(i));
+ final long timeTaken = dumpJavaTracesTombstoned(firstPids.get(i), tracesFile,
+ remainingTime);
+
+ remainingTime -= timeTaken;
+ if (remainingTime <= 0) {
+ Slog.e(TAG, "Aborting stack trace dump (current firstPid=" + firstPids.get(i) +
+ "); deadline exceeded.");
+ return;
+ }
+
+ if (DEBUG_ANR) {
+ Slog.d(TAG, "Done with pid " + firstPids.get(i) + " in " + timeTaken + "ms");
+ }
}
+ }
- // First collect all of the stacks of the most important pids.
- if (firstPids != null) {
- int num = firstPids.size();
- for (int i = 0; i < num; i++) {
- if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for pid "
- + firstPids.get(i));
- final long timeTaken;
- if (useTombstonedForJavaTraces) {
- timeTaken = dumpJavaTracesTombstoned(firstPids.get(i), tracesFile, remainingTime);
- } else {
- timeTaken = observer.dumpWithTimeout(firstPids.get(i), remainingTime);
- }
+ // Next collect the stacks of the native pids
+ if (nativePids != null) {
+ for (int pid : nativePids) {
+ if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for native pid " + pid);
+ final long nativeDumpTimeoutMs = Math.min(NATIVE_DUMP_TIMEOUT_MS, remainingTime);
- remainingTime -= timeTaken;
- if (remainingTime <= 0) {
- Slog.e(TAG, "Aborting stack trace dump (current firstPid=" + firstPids.get(i) +
+ final long start = SystemClock.elapsedRealtime();
+ Debug.dumpNativeBacktraceToFileTimeout(
+ pid, tracesFile, (int) (nativeDumpTimeoutMs / 1000));
+ final long timeTaken = SystemClock.elapsedRealtime() - start;
+
+ remainingTime -= timeTaken;
+ if (remainingTime <= 0) {
+ Slog.e(TAG, "Aborting stack trace dump (current native pid=" + pid +
+ "); deadline exceeded.");
+ return;
+ }
+
+ if (DEBUG_ANR) {
+ Slog.d(TAG, "Done with native pid " + pid + " in " + timeTaken + "ms");
+ }
+ }
+ }
+
+ // Lastly, dump stacks for all extra PIDs from the CPU tracker.
+ if (extraPids != null) {
+ for (int pid : extraPids) {
+ if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for extra pid " + pid);
+
+ final long timeTaken = dumpJavaTracesTombstoned(pid, tracesFile, remainingTime);
+
+ remainingTime -= timeTaken;
+ if (remainingTime <= 0) {
+ Slog.e(TAG, "Aborting stack trace dump (current extra pid=" + pid +
"); deadline exceeded.");
- return;
- }
-
- if (DEBUG_ANR) {
- Slog.d(TAG, "Done with pid " + firstPids.get(i) + " in " + timeTaken + "ms");
- }
+ return;
}
- }
- // Next collect the stacks of the native pids
- if (nativePids != null) {
- for (int pid : nativePids) {
- if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for native pid " + pid);
- final long nativeDumpTimeoutMs = Math.min(NATIVE_DUMP_TIMEOUT_MS, remainingTime);
-
- final long start = SystemClock.elapsedRealtime();
- Debug.dumpNativeBacktraceToFileTimeout(
- pid, tracesFile, (int) (nativeDumpTimeoutMs / 1000));
- final long timeTaken = SystemClock.elapsedRealtime() - start;
-
- remainingTime -= timeTaken;
- if (remainingTime <= 0) {
- Slog.e(TAG, "Aborting stack trace dump (current native pid=" + pid +
- "); deadline exceeded.");
- return;
- }
-
- if (DEBUG_ANR) {
- Slog.d(TAG, "Done with native pid " + pid + " in " + timeTaken + "ms");
- }
+ if (DEBUG_ANR) {
+ Slog.d(TAG, "Done with extra pid " + pid + " in " + timeTaken + "ms");
}
}
-
- // Lastly, dump stacks for all extra PIDs from the CPU tracker.
- if (extraPids != null) {
- for (int pid : extraPids) {
- if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for extra pid " + pid);
-
- final long timeTaken;
- if (useTombstonedForJavaTraces) {
- timeTaken = dumpJavaTracesTombstoned(pid, tracesFile, remainingTime);
- } else {
- timeTaken = observer.dumpWithTimeout(pid, remainingTime);
- }
-
- remainingTime -= timeTaken;
- if (remainingTime <= 0) {
- Slog.e(TAG, "Aborting stack trace dump (current extra pid=" + pid +
- "); deadline exceeded.");
- return;
- }
-
- if (DEBUG_ANR) {
- Slog.d(TAG, "Done with extra pid " + pid + " in " + timeTaken + "ms");
- }
- }
- }
- } finally {
- if (observer != null) {
- observer.stopWatching();
- }
}
}
@@ -5938,7 +5811,7 @@
if (app != null) {
ArrayList<Integer> firstPids = new ArrayList<Integer>();
firstPids.add(app.pid);
- dumpStackTraces(tracesPath, firstPids, null, null, true /* useTombstoned */);
+ dumpStackTraces(tracesPath, firstPids, null, null);
}
File lastTracesFile = null;
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index 36f5a6c..5579849 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -34,22 +34,19 @@
import android.net.Network;
import android.net.NetworkUtils;
import android.net.Uri;
+import android.net.dns.ResolvUtil;
import android.os.Binder;
import android.os.INetworkManagementService;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
-import android.system.GaiException;
-import android.system.OsConstants;
-import android.system.StructAddrinfo;
import android.text.TextUtils;
import android.util.Slog;
import com.android.server.connectivity.MockableSystemProperties;
-import libcore.io.Libcore;
-
import java.net.InetAddress;
+import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
@@ -126,28 +123,19 @@
}
public static PrivateDnsConfig tryBlockingResolveOf(Network network, String name) {
- final StructAddrinfo hints = new StructAddrinfo();
- // Unnecessary, but expressly no AI_ADDRCONFIG.
- hints.ai_flags = 0;
- // Fetch all IP addresses at once to minimize re-resolution.
- hints.ai_family = OsConstants.AF_UNSPEC;
- hints.ai_socktype = OsConstants.SOCK_DGRAM;
-
try {
- final InetAddress[] ips = Libcore.os.android_getaddrinfo(name, hints, network.netId);
- if (ips != null && ips.length > 0) {
- return new PrivateDnsConfig(name, ips);
- }
- } catch (GaiException ignored) {}
-
- return null;
+ final InetAddress[] ips = ResolvUtil.blockingResolveAllLocally(network, name);
+ return new PrivateDnsConfig(name, ips);
+ } catch (UnknownHostException uhe) {
+ return new PrivateDnsConfig(name, null);
+ }
}
public static Uri[] getPrivateDnsSettingsUris() {
- final Uri[] uris = new Uri[2];
- uris[0] = Settings.Global.getUriFor(PRIVATE_DNS_MODE);
- uris[1] = Settings.Global.getUriFor(PRIVATE_DNS_SPECIFIER);
- return uris;
+ return new Uri[]{
+ Settings.Global.getUriFor(PRIVATE_DNS_MODE),
+ Settings.Global.getUriFor(PRIVATE_DNS_SPECIFIER),
+ };
}
private final Context mContext;
@@ -203,7 +191,7 @@
// NetworkMonitor to decide which networks need validation and runs the
// blocking calls to resolve Private DNS strict mode hostnames.
//
- // At this time we do attempt to enable Private DNS on non-Internet
+ // At this time we do not attempt to enable Private DNS on non-Internet
// networks like IMS.
final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.get(netId);
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 9581308..e520d0c 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -19,6 +19,27 @@
import static android.hardware.usb.UsbManager.USB_CONFIGURED;
import static android.hardware.usb.UsbManager.USB_CONNECTED;
import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
+import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
+import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
+import static android.net.ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY;
+import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER;
+import static android.net.ConnectivityManager.EXTRA_ADD_TETHER_TYPE;
+import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER;
+import static android.net.ConnectivityManager.EXTRA_ERRORED_TETHER;
+import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
+import static android.net.ConnectivityManager.EXTRA_PROVISION_CALLBACK;
+import static android.net.ConnectivityManager.EXTRA_REM_TETHER_TYPE;
+import static android.net.ConnectivityManager.EXTRA_RUN_PROVISION;
+import static android.net.ConnectivityManager.EXTRA_SET_ALARM;
+import static android.net.ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
+import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
+import static android.net.ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL;
+import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
+import static android.net.ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
+import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
+import static android.net.ConnectivityManager.TETHERING_INVALID;
+import static android.net.ConnectivityManager.TETHERING_USB;
+import static android.net.ConnectivityManager.TETHERING_WIFI;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
@@ -45,7 +66,6 @@
import android.content.IntentFilter;
import android.content.res.Resources;
import android.hardware.usb.UsbManager;
-import android.net.ConnectivityManager;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
import android.net.IpPrefix;
@@ -56,6 +76,7 @@
import android.net.NetworkState;
import android.net.NetworkUtils;
import android.net.RouteInfo;
+import android.net.util.InterfaceSet;
import android.net.util.PrefixUtils;
import android.net.util.SharedLog;
import android.net.util.VersionedBroadcastListener;
@@ -98,6 +119,7 @@
import com.android.server.connectivity.tethering.TetherInterfaceStateMachine;
import com.android.server.connectivity.tethering.TetheringConfiguration;
import com.android.server.connectivity.tethering.TetheringDependencies;
+import com.android.server.connectivity.tethering.TetheringInterfaceUtils;
import com.android.server.connectivity.tethering.UpstreamNetworkMonitor;
import com.android.server.net.BaseNetworkObserver;
@@ -146,7 +168,7 @@
stateMachine = sm;
// Assume all state machines start out available and with no errors.
lastState = IControlsTethering.STATE_AVAILABLE;
- lastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ lastError = TETHER_ERROR_NO_ERROR;
}
public boolean isCurrentlyServing() {
@@ -184,7 +206,7 @@
private final TetheringDependencies mDeps;
private volatile TetheringConfiguration mConfig;
- private String mCurrentUpstreamIface;
+ private InterfaceSet mCurrentUpstreamIfaceSet;
private Notification.Builder mTetheredNotificationBuilder;
private int mLastNotificationId;
@@ -214,7 +236,7 @@
final Handler smHandler = mTetherMasterSM.getHandler();
mOffloadController = new OffloadController(smHandler,
- deps.getOffloadHardwareInterface(smHandler, mLog),
+ mDeps.getOffloadHardwareInterface(smHandler, mLog),
mContext.getContentResolver(), mNMService,
mLog);
mUpstreamNetworkMonitor = deps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog,
@@ -241,7 +263,7 @@
mStateReceiver = new StateReceiver();
filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_STATE);
- filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+ filter.addAction(CONNECTIVITY_ACTION);
filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
mContext.registerReceiver(mStateReceiver, filter, null, smHandler);
@@ -263,12 +285,6 @@
updateConfiguration();
}
- // We can't do this once in the Tethering() constructor and cache the value, because the
- // CONNECTIVITY_SERVICE is registered only after the Tethering() constructor has completed.
- private ConnectivityManager getConnectivityManager() {
- return (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
- }
-
private WifiManager getWifiManager() {
return (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
}
@@ -294,7 +310,7 @@
if (up) {
maybeTrackNewInterfaceLocked(iface);
} else {
- if (ifaceNameToType(iface) == ConnectivityManager.TETHERING_BLUETOOTH) {
+ if (ifaceNameToType(iface) == TETHERING_BLUETOOTH) {
stopTrackingInterfaceLocked(iface);
} else {
// Ignore usb0 down after enabling RNDIS.
@@ -316,13 +332,13 @@
final TetheringConfiguration cfg = mConfig;
if (cfg.isWifi(iface)) {
- return ConnectivityManager.TETHERING_WIFI;
+ return TETHERING_WIFI;
} else if (cfg.isUsb(iface)) {
- return ConnectivityManager.TETHERING_USB;
+ return TETHERING_USB;
} else if (cfg.isBluetooth(iface)) {
- return ConnectivityManager.TETHERING_BLUETOOTH;
+ return TETHERING_BLUETOOTH;
}
- return ConnectivityManager.TETHERING_INVALID;
+ return TETHERING_INVALID;
}
@Override
@@ -424,26 +440,26 @@
boolean isProvisioningRequired = enable && isTetherProvisioningRequired();
int result;
switch (type) {
- case ConnectivityManager.TETHERING_WIFI:
+ case TETHERING_WIFI:
result = setWifiTethering(enable);
- if (isProvisioningRequired && result == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
scheduleProvisioningRechecks(type);
}
sendTetherResult(receiver, result);
break;
- case ConnectivityManager.TETHERING_USB:
+ case TETHERING_USB:
result = setUsbTethering(enable);
- if (isProvisioningRequired && result == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
scheduleProvisioningRechecks(type);
}
sendTetherResult(receiver, result);
break;
- case ConnectivityManager.TETHERING_BLUETOOTH:
+ case TETHERING_BLUETOOTH:
setBluetoothTethering(enable, receiver);
break;
default:
Log.w(TAG, "Invalid tether type.");
- sendTetherResult(receiver, ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE);
+ sendTetherResult(receiver, TETHER_ERROR_UNKNOWN_IFACE);
}
}
@@ -454,7 +470,7 @@
}
private int setWifiTethering(final boolean enable) {
- int rval = ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
+ int rval = TETHER_ERROR_MASTER_ERROR;
final long ident = Binder.clearCallingIdentity();
try {
synchronized (mPublicSync) {
@@ -462,7 +478,7 @@
final WifiManager mgr = getWifiManager();
if ((enable && mgr.startSoftAp(null /* use existing wifi config */)) ||
(!enable && mgr.stopSoftAp())) {
- rval = ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ rval = TETHER_ERROR_NO_ERROR;
}
}
} finally {
@@ -476,7 +492,7 @@
if (adapter == null || !adapter.isEnabled()) {
Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: " +
(adapter == null));
- sendTetherResult(receiver, ConnectivityManager.TETHER_ERROR_SERVICE_UNAVAIL);
+ sendTetherResult(receiver, TETHER_ERROR_SERVICE_UNAVAIL);
return;
}
@@ -489,12 +505,12 @@
((BluetoothPan) proxy).setBluetoothTethering(enable);
// TODO: Enabling bluetooth tethering can fail asynchronously here.
// We should figure out a way to bubble up that failure instead of sending success.
- int result = ((BluetoothPan) proxy).isTetheringOn() == enable ?
- ConnectivityManager.TETHER_ERROR_NO_ERROR :
- ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
+ final int result = (((BluetoothPan) proxy).isTetheringOn() == enable)
+ ? TETHER_ERROR_NO_ERROR
+ : TETHER_ERROR_MASTER_ERROR;
sendTetherResult(receiver, result);
if (enable && isTetherProvisioningRequired()) {
- scheduleProvisioningRechecks(ConnectivityManager.TETHERING_BLUETOOTH);
+ scheduleProvisioningRechecks(TETHERING_BLUETOOTH);
}
adapter.closeProfileProxy(BluetoothProfile.PAN, proxy);
}
@@ -508,8 +524,8 @@
private void sendUiTetherProvisionIntent(int type, ResultReceiver receiver) {
Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING);
- intent.putExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, type);
- intent.putExtra(ConnectivityManager.EXTRA_PROVISION_CALLBACK, receiver);
+ intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
+ intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
final long ident = Binder.clearCallingIdentity();
try {
@@ -532,7 +548,7 @@
@Override
protected void onReceiveResult(int resultCode, Bundle resultData) {
// If provisioning is successful, enable tethering, otherwise just send the error.
- if (resultCode == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ if (resultCode == TETHER_ERROR_NO_ERROR) {
enableTetheringInternal(type, true, receiver);
} else {
sendTetherResult(receiver, resultCode);
@@ -552,8 +568,8 @@
private void scheduleProvisioningRechecks(int type) {
Intent intent = new Intent();
- intent.putExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, type);
- intent.putExtra(ConnectivityManager.EXTRA_SET_ALARM, true);
+ intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
+ intent.putExtra(EXTRA_SET_ALARM, true);
intent.setComponent(TETHER_SERVICE);
final long ident = Binder.clearCallingIdentity();
try {
@@ -570,9 +586,9 @@
private void sendSilentTetherProvisionIntent(int type, ResultReceiver receiver) {
Intent intent = new Intent();
- intent.putExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, type);
- intent.putExtra(ConnectivityManager.EXTRA_RUN_PROVISION, true);
- intent.putExtra(ConnectivityManager.EXTRA_PROVISION_CALLBACK, receiver);
+ intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
+ intent.putExtra(EXTRA_RUN_PROVISION, true);
+ intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
intent.setComponent(TETHER_SERVICE);
final long ident = Binder.clearCallingIdentity();
try {
@@ -583,9 +599,9 @@
}
private void cancelTetherProvisioningRechecks(int type) {
- if (getConnectivityManager().isTetheringSupported()) {
+ if (mDeps.isTetheringSupported()) {
Intent intent = new Intent();
- intent.putExtra(ConnectivityManager.EXTRA_REM_TETHER_TYPE, type);
+ intent.putExtra(EXTRA_REM_TETHER_TYPE, type);
intent.setComponent(TETHER_SERVICE);
final long ident = Binder.clearCallingIdentity();
try {
@@ -600,8 +616,8 @@
// TODO: De-duplicate with above code, where possible.
private void startProvisionIntent(int tetherType) {
final Intent startProvIntent = new Intent();
- startProvIntent.putExtra(ConnectivityManager.EXTRA_ADD_TETHER_TYPE, tetherType);
- startProvIntent.putExtra(ConnectivityManager.EXTRA_RUN_PROVISION, true);
+ startProvIntent.putExtra(EXTRA_ADD_TETHER_TYPE, tetherType);
+ startProvIntent.putExtra(EXTRA_RUN_PROVISION, true);
startProvIntent.setComponent(TETHER_SERVICE);
mContext.startServiceAsUser(startProvIntent, UserHandle.CURRENT);
}
@@ -616,13 +632,13 @@
TetherState tetherState = mTetherStates.get(iface);
if (tetherState == null) {
Log.e(TAG, "Tried to Tether an unknown iface: " + iface + ", ignoring");
- return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
+ return TETHER_ERROR_UNKNOWN_IFACE;
}
// Ignore the error status of the interface. If the interface is available,
// the errors are referring to past tethering attempts anyway.
if (tetherState.lastState != IControlsTethering.STATE_AVAILABLE) {
Log.e(TAG, "Tried to Tether an unavailable iface: " + iface + ", ignoring");
- return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
+ return TETHER_ERROR_UNAVAIL_IFACE;
}
// NOTE: If a CMD_TETHER_REQUESTED message is already in the TISM's
// queue but not yet processed, this will be a no-op and it will not
@@ -631,7 +647,7 @@
// TODO: reexamine the threading and messaging model.
tetherState.stateMachine.sendMessage(
TetherInterfaceStateMachine.CMD_TETHER_REQUESTED, requestedState);
- return ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ return TETHER_ERROR_NO_ERROR;
}
}
@@ -641,22 +657,22 @@
TetherState tetherState = mTetherStates.get(iface);
if (tetherState == null) {
Log.e(TAG, "Tried to Untether an unknown iface :" + iface + ", ignoring");
- return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
+ return TETHER_ERROR_UNKNOWN_IFACE;
}
if (!tetherState.isCurrentlyServing()) {
Log.e(TAG, "Tried to untether an inactive iface :" + iface + ", ignoring");
- return ConnectivityManager.TETHER_ERROR_UNAVAIL_IFACE;
+ return TETHER_ERROR_UNAVAIL_IFACE;
}
tetherState.stateMachine.sendMessage(
TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
- return ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ return TETHER_ERROR_NO_ERROR;
}
}
public void untetherAll() {
- stopTethering(ConnectivityManager.TETHERING_WIFI);
- stopTethering(ConnectivityManager.TETHERING_USB);
- stopTethering(ConnectivityManager.TETHERING_BLUETOOTH);
+ stopTethering(TETHERING_WIFI);
+ stopTethering(TETHERING_USB);
+ stopTethering(TETHERING_BLUETOOTH);
}
public int getLastTetherError(String iface) {
@@ -665,7 +681,7 @@
if (tetherState == null) {
Log.e(TAG, "Tried to getLastTetherError on an unknown iface :" + iface +
", ignoring");
- return ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
+ return TETHER_ERROR_UNKNOWN_IFACE;
}
return tetherState.lastError;
}
@@ -673,7 +689,7 @@
// TODO: Figure out how to update for local hotspot mode interfaces.
private void sendTetherStateChangedBroadcast() {
- if (!getConnectivityManager().isTetheringSupported()) return;
+ if (!mDeps.isTetheringSupported()) return;
final ArrayList<String> availableList = new ArrayList<>();
final ArrayList<String> tetherList = new ArrayList<>();
@@ -690,7 +706,7 @@
for (int i = 0; i < mTetherStates.size(); i++) {
TetherState tetherState = mTetherStates.valueAt(i);
String iface = mTetherStates.keyAt(i);
- if (tetherState.lastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ if (tetherState.lastError != TETHER_ERROR_NO_ERROR) {
erroredList.add(iface);
} else if (tetherState.lastState == IControlsTethering.STATE_AVAILABLE) {
availableList.add(iface);
@@ -708,13 +724,13 @@
}
}
}
- final Intent bcast = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
+ final Intent bcast = new Intent(ACTION_TETHER_STATE_CHANGED);
bcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_AVAILABLE_TETHER, availableList);
- bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY, localOnlyList);
- bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER, tetherList);
- bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER, erroredList);
+ bcast.putStringArrayListExtra(EXTRA_AVAILABLE_TETHER, availableList);
+ bcast.putStringArrayListExtra(EXTRA_ACTIVE_LOCAL_ONLY, localOnlyList);
+ bcast.putStringArrayListExtra(EXTRA_ACTIVE_TETHER, tetherList);
+ bcast.putStringArrayListExtra(EXTRA_ERRORED_TETHER, erroredList);
mContext.sendStickyBroadcastAsUser(bcast, UserHandle.ALL);
if (DBG) {
Log.d(TAG, String.format(
@@ -837,7 +853,7 @@
if (action.equals(UsbManager.ACTION_USB_STATE)) {
handleUsbAction(intent);
- } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
+ } else if (action.equals(CONNECTIVITY_ACTION)) {
handleConnectivityAction(intent);
} else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
handleWifiApAction(intent);
@@ -848,8 +864,8 @@
}
private void handleConnectivityAction(Intent intent) {
- final NetworkInfo networkInfo = (NetworkInfo)intent.getParcelableExtra(
- ConnectivityManager.EXTRA_NETWORK_INFO);
+ final NetworkInfo networkInfo =
+ (NetworkInfo) intent.getParcelableExtra(EXTRA_NETWORK_INFO);
if (networkInfo == null ||
networkInfo.getDetailedState() == NetworkInfo.DetailedState.FAILED) {
return;
@@ -885,14 +901,10 @@
synchronized (Tethering.this.mPublicSync) {
if (!usbConnected && mRndisEnabled) {
// Turn off tethering if it was enabled and there is a disconnect.
- tetherMatchingInterfaces(
- IControlsTethering.STATE_AVAILABLE,
- ConnectivityManager.TETHERING_USB);
+ tetherMatchingInterfaces(IControlsTethering.STATE_AVAILABLE, TETHERING_USB);
} else if (usbConfigured && rndisEnabled) {
// Tether if rndis is enabled and usb is configured.
- tetherMatchingInterfaces(
- IControlsTethering.STATE_TETHERED,
- ConnectivityManager.TETHERING_USB);
+ tetherMatchingInterfaces(IControlsTethering.STATE_TETHERED, TETHERING_USB);
}
mRndisEnabled = usbConfigured && rndisEnabled;
}
@@ -973,7 +985,7 @@
for (int i = 0; i < mTetherStates.size(); i++) {
TetherInterfaceStateMachine tism = mTetherStates.valueAt(i).stateMachine;
- if (tism.interfaceType() == ConnectivityManager.TETHERING_WIFI) {
+ if (tism.interfaceType() == TETHERING_WIFI) {
tism.unwanted();
return;
}
@@ -1001,7 +1013,7 @@
}
if (!TextUtils.isEmpty(ifname)) {
- maybeTrackNewInterfaceLocked(ifname, ConnectivityManager.TETHERING_WIFI);
+ maybeTrackNewInterfaceLocked(ifname, TETHERING_WIFI);
changeInterfaceState(ifname, ipServingMode);
} else {
mLog.e(String.format(
@@ -1060,7 +1072,7 @@
Log.wtf(TAG, "Unknown interface state: " + requestedState);
return;
}
- if (result != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ if (result != TETHER_ERROR_NO_ERROR) {
Log.e(TAG, "unable start or stop tethering on iface " + ifname);
return;
}
@@ -1101,7 +1113,7 @@
synchronized (mPublicSync) {
usbManager.setCurrentFunction(enable ? UsbManager.USB_FUNCTION_RNDIS : null, false);
}
- return ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ return TETHER_ERROR_NO_ERROR;
}
// TODO review API - figure out how to delete these entirely.
@@ -1140,7 +1152,7 @@
synchronized (mPublicSync) {
for (int i = 0; i < mTetherStates.size(); i++) {
TetherState tetherState = mTetherStates.valueAt(i);
- if (tetherState.lastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ if (tetherState.lastError != TETHER_ERROR_NO_ERROR) {
list.add(mTetherStates.keyAt(i));
}
}
@@ -1161,12 +1173,11 @@
}
// Needed because the canonical source of upstream truth is just the
- // upstream interface name, |mCurrentUpstreamIface|. This is ripe for
- // future simplification, once the upstream Network is canonical.
+ // upstream interface set, |mCurrentUpstreamIfaceSet|.
private boolean pertainsToCurrentUpstream(NetworkState ns) {
- if (ns != null && ns.linkProperties != null && mCurrentUpstreamIface != null) {
+ if (ns != null && ns.linkProperties != null && mCurrentUpstreamIfaceSet != null) {
for (String ifname : ns.linkProperties.getAllInterfaceNames()) {
- if (mCurrentUpstreamIface.equals(ifname)) {
+ if (mCurrentUpstreamIfaceSet.ifnames.contains(ifname)) {
return true;
}
}
@@ -1187,7 +1198,7 @@
}
String iface = mTetherStates.keyAt(i);
int interfaceType = ifaceNameToType(iface);
- if (interfaceType != ConnectivityManager.TETHERING_INVALID) {
+ if (interfaceType != TETHERING_INVALID) {
tethered.add(interfaceType);
}
}
@@ -1361,31 +1372,27 @@
}
protected void setUpstreamNetwork(NetworkState ns) {
- String iface = null;
+ InterfaceSet ifaces = null;
if (ns != null) {
// Find the interface with the default IPv4 route. It may be the
// interface described by linkProperties, or one of the interfaces
// stacked on top of it.
mLog.i("Looking for default routes on: " + ns.linkProperties);
- final String iface4 = getIPv4DefaultRouteInterface(ns);
- final String iface6 = getIPv6DefaultRouteInterface(ns);
- mLog.i("IPv4/IPv6 upstream interface(s): " + iface4 + "/" + iface6);
-
- iface = (iface4 != null) ? iface4 : null /* TODO: iface6 */;
+ ifaces = TetheringInterfaceUtils.getTetheringInterfaces(ns);
+ mLog.i("Found upstream interface(s): " + ifaces);
}
- if (iface != null) {
+ if (ifaces != null) {
setDnsForwarders(ns.network, ns.linkProperties);
}
- notifyDownstreamsOfNewUpstreamIface(iface);
+ notifyDownstreamsOfNewUpstreamIface(ifaces);
if (ns != null && pertainsToCurrentUpstream(ns)) {
// If we already have NetworkState for this network examine
// it immediately, because there likely will be no second
// EVENT_ON_AVAILABLE (it was already received).
handleNewUpstreamNetworkState(ns);
- } else if (mCurrentUpstreamIface == null) {
- // There are no available upstream networks, or none that
- // have an IPv4 default route (current metric for success).
+ } else if (mCurrentUpstreamIfaceSet == null) {
+ // There are no available upstream networks.
handleNewUpstreamNetworkState(null);
}
}
@@ -1412,12 +1419,10 @@
}
}
- protected void notifyDownstreamsOfNewUpstreamIface(String ifaceName) {
- mLog.log("Notifying downstreams of upstream=" + ifaceName);
- mCurrentUpstreamIface = ifaceName;
+ protected void notifyDownstreamsOfNewUpstreamIface(InterfaceSet ifaces) {
+ mCurrentUpstreamIfaceSet = ifaces;
for (TetherInterfaceStateMachine sm : mNotifyList) {
- sm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
- ifaceName);
+ sm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED, ifaces);
}
}
@@ -1443,7 +1448,7 @@
}
// If this is a Wi-Fi interface, notify WifiManager of the active serving state.
- if (who.interfaceType() == ConnectivityManager.TETHERING_WIFI) {
+ if (who.interfaceType() == TETHERING_WIFI) {
final WifiManager mgr = getWifiManager();
final String iface = who.interfaceName();
switch (mode) {
@@ -1467,8 +1472,8 @@
mForwardedDownstreams.remove(who);
// If this is a Wi-Fi interface, tell WifiManager of any errors.
- if (who.interfaceType() == ConnectivityManager.TETHERING_WIFI) {
- if (who.lastError() != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ if (who.interfaceType() == TETHERING_WIFI) {
+ if (who.lastError() != TETHER_ERROR_NO_ERROR) {
getWifiManager().updateInterfaceIpState(
who.interfaceName(), IFACE_IP_MODE_CONFIGURATION_ERROR);
}
@@ -1489,7 +1494,7 @@
// For example, after CONNECTIVITY_ACTION listening is removed, here
// is where we could observe a Wi-Fi network becoming available and
// passing validation.
- if (mCurrentUpstreamIface == null) {
+ if (mCurrentUpstreamIfaceSet == null) {
// If we have no upstream interface, try to run through upstream
// selection again. If, for example, IPv4 connectivity has shown up
// after IPv6 (e.g., 464xlat became available) we want the chance to
@@ -1513,8 +1518,7 @@
handleNewUpstreamNetworkState(ns);
break;
case UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES:
- setDnsForwarders(ns.network, ns.linkProperties);
- handleNewUpstreamNetworkState(ns);
+ chooseUpstreamType(false);
break;
case UpstreamNetworkMonitor.EVENT_ON_LOST:
// TODO: Re-evaluate possible upstreams. Currently upstream
@@ -1587,7 +1591,7 @@
if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
handleInterfaceServingStateActive(message.arg1, who);
who.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
- mCurrentUpstreamIface);
+ mCurrentUpstreamIfaceSet);
// If there has been a change and an upstream is now
// desired, kick off the selection process.
final boolean previousUpstreamWanted = updateUpstreamWanted();
@@ -1674,7 +1678,7 @@
who.sendMessage(mErrorNotification);
break;
case CMD_CLEAR_ERROR:
- mErrorNotification = ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ mErrorNotification = TETHER_ERROR_NO_ERROR;
transitionTo(mInitialState);
break;
default:
@@ -1865,7 +1869,7 @@
pw.println(" - lastError = " + tetherState.lastError);
}
pw.println("Upstream wanted: " + upstreamWanted());
- pw.println("Current upstream interface: " + mCurrentUpstreamIface);
+ pw.println("Current upstream interface(s): " + mCurrentUpstreamIfaceSet);
pw.decreaseIndent();
}
@@ -1936,7 +1940,7 @@
// If TetherMasterSM is in ErrorState, TetherMasterSM stays there.
// Thus we give a chance for TetherMasterSM to recover to InitialState
// by sending CMD_CLEAR_ERROR
- if (error == ConnectivityManager.TETHER_ERROR_MASTER_ERROR) {
+ if (error == TETHER_ERROR_MASTER_ERROR) {
mTetherMasterSM.sendMessage(TetherMasterSM.CMD_CLEAR_ERROR, who);
}
int which;
@@ -1980,7 +1984,7 @@
private void maybeTrackNewInterfaceLocked(final String iface) {
// If we don't care about this type of interface, ignore.
final int interfaceType = ifaceNameToType(iface);
- if (interfaceType == ConnectivityManager.TETHERING_INVALID) {
+ if (interfaceType == TETHERING_INVALID) {
mLog.log(iface + " is not a tetherable iface, ignoring");
return;
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index c9bdcf1..2fda08e 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -151,6 +151,13 @@
.multiply(BigInteger.valueOf(howManyPercentIsMost))
.divide(BigInteger.valueOf(100));
}
+ // How many routes to evaluate before bailing and declaring this Vpn should provide
+ // the INTERNET capability. This is necessary because computing the adress space is
+ // O(n²) and this is running in the system service, so a limit is needed to alleviate
+ // the risk of attack.
+ // This is taken as a total of IPv4 + IPV6 routes for simplicity, but the algorithm
+ // is actually O(n²)+O(n²).
+ private static final int MAX_ROUTES_TO_EVALUATE = 150;
// TODO: create separate trackers for each unique VPN to support
// automated reconnection
@@ -862,10 +869,12 @@
*/
@VisibleForTesting
static boolean providesRoutesToMostDestinations(LinkProperties lp) {
+ final List<RouteInfo> routes = lp.getAllRoutes();
+ if (routes.size() > MAX_ROUTES_TO_EVALUATE) return true;
final Comparator<IpPrefix> prefixLengthComparator = IpPrefix.lengthComparator();
TreeSet<IpPrefix> ipv4Prefixes = new TreeSet<>(prefixLengthComparator);
TreeSet<IpPrefix> ipv6Prefixes = new TreeSet<>(prefixLengthComparator);
- for (final RouteInfo route : lp.getAllRoutes()) {
+ for (final RouteInfo route : routes) {
IpPrefix destination = route.getDestination();
if (destination.isIPv4()) {
ipv4Prefixes.add(destination);
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
index 518f6c1..ba67c94 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
@@ -30,10 +30,8 @@
import java.net.Inet6Address;
import java.net.InetAddress;
-import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.LinkedList;
import java.util.Random;
@@ -119,7 +117,7 @@
if (VDBG) {
Log.d(TAG, "updateUpstreamNetworkState: " + toDebugString(ns));
}
- if (!canTetherIPv6(ns, mLog)) {
+ if (TetheringInterfaceUtils.getIPv6Interface(ns) == null) {
stopIPv6TetheringOnAllInterfaces();
setUpstreamNetworkState(null);
return;
@@ -208,70 +206,6 @@
return null;
}
- private static boolean canTetherIPv6(NetworkState ns, SharedLog sharedLog) {
- // Broadly speaking:
- //
- // [1] does the upstream have an IPv6 default route?
- //
- // and
- //
- // [2] does the upstream have one or more global IPv6 /64s
- // dedicated to this device?
- //
- // In lieu of Prefix Delegation and other evaluation of whether a
- // prefix may or may not be dedicated to this device, for now just
- // check whether the upstream is TRANSPORT_CELLULAR. This works
- // because "[t]he 3GPP network allocates each default bearer a unique
- // /64 prefix", per RFC 6459, Section 5.2.
-
- final boolean canTether =
- (ns != null) && (ns.network != null) &&
- (ns.linkProperties != null) && (ns.networkCapabilities != null) &&
- // At least one upstream DNS server:
- ns.linkProperties.isProvisioned() &&
- // Minimal amount of IPv6 provisioning:
- ns.linkProperties.hasIPv6DefaultRoute() &&
- ns.linkProperties.hasGlobalIPv6Address() &&
- // Temporary approximation of "dedicated prefix":
- ns.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
-
- // For now, we do not support separate IPv4 and IPv6 upstreams (e.g.
- // tethering with 464xlat involved). TODO: Rectify this shortcoming,
- // likely by calling NetworkManagementService#startInterfaceForwarding()
- // for all upstream interfaces.
- RouteInfo v4default = null;
- RouteInfo v6default = null;
- if (canTether) {
- for (RouteInfo r : ns.linkProperties.getAllRoutes()) {
- if (r.isIPv4Default()) {
- v4default = r;
- } else if (r.isIPv6Default()) {
- v6default = r;
- }
-
- if (v4default != null && v6default != null) {
- break;
- }
- }
- }
-
- final boolean supportedConfiguration =
- (v4default != null) && (v6default != null) &&
- (v4default.getInterface() != null) &&
- v4default.getInterface().equals(v6default.getInterface());
-
- final boolean outcome = canTether && supportedConfiguration;
-
- if (ns == null) {
- sharedLog.log("No available upstream.");
- } else {
- sharedLog.log(String.format("IPv6 tethering is %s for upstream: %s",
- (outcome ? "available" : "not available"), toDebugString(ns)));
- }
-
- return outcome;
- }
-
private static LinkProperties getIPv6OnlyLinkProperties(LinkProperties lp) {
final LinkProperties v6only = new LinkProperties();
if (lp == null) {
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index e4c7ca0..5ed14a0 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -31,7 +31,7 @@
import android.net.ip.RouterAdvertisementDaemon;
import android.net.ip.RouterAdvertisementDaemon.RaParams;
import android.net.util.InterfaceParams;
-import android.net.util.NetdService;
+import android.net.util.InterfaceSet;
import android.net.util.SharedLog;
import android.os.INetworkManagementService;
import android.os.Looper;
@@ -49,12 +49,12 @@
import java.net.Inet6Address;
import java.net.InetAddress;
-import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Objects;
import java.util.Random;
+import java.util.Set;
/**
* Provides the interface to IP-layer serving functionality for a given network
@@ -121,7 +121,7 @@
private int mLastError;
private int mServingMode;
- private String mMyUpstreamIfaceName; // may change over time
+ private InterfaceSet mUpstreamIfaceSet; // may change over time
private InterfaceParams mInterfaceParams;
// TODO: De-duplicate this with mLinkProperties above. Currently, these link
// properties are those selected by the IPv6TetheringCoordinator and relayed
@@ -622,10 +622,10 @@
}
private void cleanupUpstream() {
- if (mMyUpstreamIfaceName == null) return;
+ if (mUpstreamIfaceSet == null) return;
- cleanupUpstreamInterface(mMyUpstreamIfaceName);
- mMyUpstreamIfaceName = null;
+ for (String ifname : mUpstreamIfaceSet.ifnames) cleanupUpstreamInterface(ifname);
+ mUpstreamIfaceSet = null;
}
private void cleanupUpstreamInterface(String upstreamIface) {
@@ -661,34 +661,66 @@
mLog.e("CMD_TETHER_REQUESTED while already tethering.");
break;
case CMD_TETHER_CONNECTION_CHANGED:
- String newUpstreamIfaceName = (String)(message.obj);
- if ((mMyUpstreamIfaceName == null && newUpstreamIfaceName == null) ||
- (mMyUpstreamIfaceName != null &&
- mMyUpstreamIfaceName.equals(newUpstreamIfaceName))) {
+ final InterfaceSet newUpstreamIfaceSet = (InterfaceSet) message.obj;
+ if (noChangeInUpstreamIfaceSet(newUpstreamIfaceSet)) {
if (VDBG) Log.d(TAG, "Connection changed noop - dropping");
break;
}
- cleanupUpstream();
- if (newUpstreamIfaceName != null) {
+
+ if (newUpstreamIfaceSet == null) {
+ cleanupUpstream();
+ break;
+ }
+
+ for (String removed : upstreamInterfacesRemoved(newUpstreamIfaceSet)) {
+ cleanupUpstreamInterface(removed);
+ }
+
+ final Set<String> added = upstreamInterfacesAdd(newUpstreamIfaceSet);
+ // This makes the call to cleanupUpstream() in the error
+ // path for any interface neatly cleanup all the interfaces.
+ mUpstreamIfaceSet = newUpstreamIfaceSet;
+
+ for (String ifname : added) {
try {
- mNMService.enableNat(mIfaceName, newUpstreamIfaceName);
- mNMService.startInterfaceForwarding(mIfaceName,
- newUpstreamIfaceName);
+ mNMService.enableNat(mIfaceName, ifname);
+ mNMService.startInterfaceForwarding(mIfaceName, ifname);
} catch (Exception e) {
mLog.e("Exception enabling NAT: " + e);
- cleanupUpstreamInterface(newUpstreamIfaceName);
+ cleanupUpstream();
mLastError = ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
transitionTo(mInitialState);
return true;
}
}
- mMyUpstreamIfaceName = newUpstreamIfaceName;
break;
default:
return false;
}
return true;
}
+
+ private boolean noChangeInUpstreamIfaceSet(InterfaceSet newIfaces) {
+ if (mUpstreamIfaceSet == null && newIfaces == null) return true;
+ if (mUpstreamIfaceSet != null && newIfaces != null) {
+ return mUpstreamIfaceSet.equals(newIfaces);
+ }
+ return false;
+ }
+
+ private Set<String> upstreamInterfacesRemoved(InterfaceSet newIfaces) {
+ if (mUpstreamIfaceSet == null) return new HashSet<>();
+
+ final HashSet<String> removed = new HashSet<>(mUpstreamIfaceSet.ifnames);
+ removed.removeAll(newIfaces.ifnames);
+ return removed;
+ }
+
+ private Set<String> upstreamInterfacesAdd(InterfaceSet newIfaces) {
+ final HashSet<String> added = new HashSet<>(newIfaces.ifnames);
+ if (mUpstreamIfaceSet != null) added.removeAll(mUpstreamIfaceSet.ifnames);
+ return added;
+ }
}
/**
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
index 66afb0f..0ac7a36 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -60,4 +60,8 @@
public INetd getNetdService() {
return NetdService.getInstance();
}
+
+ public boolean isTetheringSupported() {
+ return true;
+ }
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java b/services/core/java/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java
new file mode 100644
index 0000000..6c7ff91
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringInterfaceUtils.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity.tethering;
+
+import android.annotation.Nullable;
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
+import android.net.NetworkState;
+import android.net.RouteInfo;
+import android.net.util.InterfaceSet;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+
+/**
+ * @hide
+ */
+public final class TetheringInterfaceUtils {
+ /**
+ * Get upstream interfaces for tethering based on default routes for IPv4/IPv6.
+ * @return null if there is no usable interface, or a set of at least one interface otherwise.
+ */
+ public static @Nullable InterfaceSet getTetheringInterfaces(NetworkState ns) {
+ if (ns == null) {
+ return null;
+ }
+
+ final LinkProperties lp = ns.linkProperties;
+ final String if4 = getInterfaceForDestination(lp, Inet4Address.ANY);
+ final String if6 = getIPv6Interface(ns);
+
+ return (if4 == null && if6 == null) ? null : new InterfaceSet(if4, if6);
+ }
+
+ /**
+ * Get the upstream interface for IPv6 tethering.
+ * @return null if there is no usable interface, or the interface name otherwise.
+ */
+ public static @Nullable String getIPv6Interface(NetworkState ns) {
+ // Broadly speaking:
+ //
+ // [1] does the upstream have an IPv6 default route?
+ //
+ // and
+ //
+ // [2] does the upstream have one or more global IPv6 /64s
+ // dedicated to this device?
+ //
+ // In lieu of Prefix Delegation and other evaluation of whether a
+ // prefix may or may not be dedicated to this device, for now just
+ // check whether the upstream is TRANSPORT_CELLULAR. This works
+ // because "[t]he 3GPP network allocates each default bearer a unique
+ // /64 prefix", per RFC 6459, Section 5.2.
+ final boolean canTether =
+ (ns != null) && (ns.network != null) &&
+ (ns.linkProperties != null) && (ns.networkCapabilities != null) &&
+ // At least one upstream DNS server:
+ ns.linkProperties.hasIPv6DnsServer() &&
+ // Minimal amount of IPv6 provisioning:
+ ns.linkProperties.hasGlobalIPv6Address() &&
+ // Temporary approximation of "dedicated prefix":
+ ns.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
+
+ return canTether
+ ? getInterfaceForDestination(ns.linkProperties, Inet6Address.ANY)
+ : null;
+ }
+
+ private static String getInterfaceForDestination(LinkProperties lp, InetAddress dst) {
+ final RouteInfo ri = (lp != null)
+ ? RouteInfo.selectBestRoute(lp.getAllRoutes(), dst)
+ : null;
+ return (ri != null) ? ri.getInterface() : null;
+ }
+}
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index e0a8643..da40692 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -146,7 +146,6 @@
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
-import java.util.Map;
/**
* Collect and persist detailed network statistics, and provide this data to
@@ -756,7 +755,7 @@
public NetworkStats getDetailedUidStats(String[] requiredIfaces) {
try {
final String[] ifacesToQuery =
- NetworkStatsFactory.augmentWithStackedInterfacesLocked(requiredIfaces);
+ NetworkStatsFactory.augmentWithStackedInterfaces(requiredIfaces);
return getNetworkStatsUidDetail(ifacesToQuery);
} catch (RemoteException e) {
Log.wtf(TAG, "Error compiling UID stats", e);
@@ -1490,12 +1489,14 @@
private NetworkStats getNetworkStatsUidDetail(String[] ifaces)
throws RemoteException {
+ // TODO: remove 464xlat adjustments from NetworkStatsFactory and apply all at once here.
final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL,
ifaces);
// fold tethering stats and operations into uid snapshot
final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID);
tetherSnapshot.filter(UID_ALL, ifaces, TAG_ALL);
+ NetworkStatsFactory.apply464xlatAdjustments(uidSnapshot, tetherSnapshot);
uidSnapshot.combineAllValues(tetherSnapshot);
final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService(
@@ -1505,13 +1506,12 @@
final NetworkStats vtStats = telephonyManager.getVtDataUsage(STATS_PER_UID);
if (vtStats != null) {
vtStats.filter(UID_ALL, ifaces, TAG_ALL);
+ NetworkStatsFactory.apply464xlatAdjustments(uidSnapshot, vtStats);
uidSnapshot.combineAllValues(vtStats);
}
uidSnapshot.combineAllValues(mUidOperations);
- // TODO: apply tethering & VC 464xlat adjustments here
-
return uidSnapshot;
}
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 504184c..73f4274 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -64,6 +64,8 @@
public static final int DEXOPT_ENABLE_HIDDEN_API_CHECKS = 1 << 10;
/** Indicates that dexopt should convert to CompactDex. */
public static final int DEXOPT_GENERATE_COMPACT_DEX = 1 << 11;
+ /** Indicates that dexopt should generate an app image */
+ public static final int DEXOPT_GENERATE_APP_IMAGE = 1 << 12;
// NOTE: keep in sync with installd
public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index faaa3ba..88caf32 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -267,7 +267,7 @@
final StringBuilder builder = new StringBuilder();
// The current version.
- builder.append("8 ");
+ builder.append("9 ");
builder.append("dexopt");
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index ae48844..f9e11f9 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -60,6 +60,7 @@
import static com.android.server.pm.Installer.DEXOPT_IDLE_BACKGROUND_JOB;
import static com.android.server.pm.Installer.DEXOPT_ENABLE_HIDDEN_API_CHECKS;
import static com.android.server.pm.Installer.DEXOPT_GENERATE_COMPACT_DEX;
+import static com.android.server.pm.Installer.DEXOPT_GENERATE_APP_IMAGE;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
@@ -454,13 +455,15 @@
pw.increaseIndent();
for (String isa : dexCodeInstructionSets) {
- String status = null;
try {
- status = DexFile.getDexFileStatus(path, isa);
+ String[] status = DexFile.getDexFileOptimizationStatus(path, isa);
+ String compilationStatus = status[0];
+ String compilationReason = status[1];
+ pw.println(isa + ": [status=" + compilationStatus
+ +"] reason=[" + compilationReason + "]");
} catch (IOException ioe) {
- status = "[Exception]: " + ioe.getMessage();
+ pw.println(isa + ": [Exception]: " + ioe.getMessage());
}
- pw.println(isa + ": " + status);
}
if (useInfo.isUsedByOtherApps(path)) {
@@ -521,6 +524,10 @@
return getDexFlags(pkg.applicationInfo, compilerFilter, options);
}
+ private boolean isAppImageEnabled() {
+ return SystemProperties.get("dalvik.vm.appimageformat", "").length() > 0;
+ }
+
private int getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options) {
int flags = info.flags;
boolean debuggable = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
@@ -547,6 +554,14 @@
case PackageManagerService.REASON_INSTALL:
generateCompactDex = false;
}
+ // Use app images only if it is enabled and we are compiling
+ // profile-guided (so the app image doesn't conservatively contain all classes).
+ // If the app didn't request for the splits to be loaded in isolation or if it does not
+ // declare inter-split dependencies, then all the splits will be loaded in the base
+ // apk class loader (in the order of their definition, otherwise disable app images
+ // because they are unsupported for multiple class loaders. b/7269679
+ boolean generateAppImage = isProfileGuidedFilter && (info.splitDependencies == null ||
+ !info.requestsIsolatedSplitLoading()) && isAppImageEnabled();
int dexFlags =
(isPublic ? DEXOPT_PUBLIC : 0)
| (debuggable ? DEXOPT_DEBUGGABLE : 0)
@@ -554,6 +569,7 @@
| (options.isBootComplete() ? DEXOPT_BOOTCOMPLETE : 0)
| (options.isDexoptIdleBackgroundJob() ? DEXOPT_IDLE_BACKGROUND_JOB : 0)
| (generateCompactDex ? DEXOPT_GENERATE_COMPACT_DEX : 0)
+ | (generateAppImage ? DEXOPT_GENERATE_APP_IMAGE : 0)
| hiddenApiFlag;
return adjustDexoptFlags(dexFlags);
}
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 7d9736e..92a09d3 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -16,21 +16,21 @@
package android.net.apf;
+import static android.net.util.NetworkConstants.*;
import static android.system.OsConstants.*;
-
import static com.android.internal.util.BitUtils.bytesToBEInt;
import static com.android.internal.util.BitUtils.getUint16;
import static com.android.internal.util.BitUtils.getUint32;
import static com.android.internal.util.BitUtils.getUint8;
-import static com.android.internal.util.BitUtils.uint16;
import static com.android.internal.util.BitUtils.uint32;
-import static com.android.internal.util.BitUtils.uint8;
-import android.os.SystemClock;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkUtils;
-import android.net.apf.ApfGenerator;
import android.net.apf.ApfGenerator.IllegalInstructionException;
import android.net.apf.ApfGenerator.Register;
import android.net.ip.IpClient;
@@ -39,31 +39,29 @@
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.RaEvent;
import android.net.util.InterfaceParams;
+import android.os.PowerManager;
+import android.os.SystemClock;
import android.system.ErrnoException;
import android.system.Os;
import android.system.PacketSocketAddress;
import android.text.format.DateUtils;
import android.util.Log;
import android.util.Pair;
-
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.HexDump;
import com.android.internal.util.IndentingPrintWriter;
-
import java.io.FileDescriptor;
import java.io.IOException;
-import java.lang.Thread;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
-import java.nio.ByteBuffer;
import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
-
import libcore.io.IoBridge;
/**
@@ -215,10 +213,6 @@
{ (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
private static final int ICMP6_TYPE_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
- private static final int ICMP6_ROUTER_SOLICITATION = 133;
- private static final int ICMP6_ROUTER_ADVERTISEMENT = 134;
- private static final int ICMP6_NEIGHBOR_SOLICITATION = 135;
- private static final int ICMP6_NEIGHBOR_ANNOUNCEMENT = 136;
// NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 2;
@@ -258,9 +252,26 @@
private long mUniqueCounter;
@GuardedBy("this")
private boolean mMulticastFilter;
+ @GuardedBy("this")
+ private boolean mInDozeMode;
private final boolean mDrop802_3Frames;
private final int[] mEthTypeBlackList;
+ // Detects doze mode state transitions.
+ private final BroadcastReceiver mDeviceIdleReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action.equals(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED)) {
+ PowerManager powerManager =
+ (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+ final boolean deviceIdle = powerManager.isDeviceIdleMode();
+ setDozeMode(deviceIdle);
+ }
+ }
+ };
+ private final Context mContext;
+
// Our IPv4 address, if we have just one, otherwise null.
@GuardedBy("this")
private byte[] mIPv4Address;
@@ -269,13 +280,14 @@
private int mIPv4PrefixLength;
@VisibleForTesting
- ApfFilter(ApfConfiguration config, InterfaceParams ifParams,
+ ApfFilter(Context context, ApfConfiguration config, InterfaceParams ifParams,
IpClient.Callback ipClientCallback, IpConnectivityLog log) {
mApfCapabilities = config.apfCapabilities;
mIpClientCallback = ipClientCallback;
mInterfaceParams = ifParams;
mMulticastFilter = config.multicastFilter;
mDrop802_3Frames = config.ieee802_3Filter;
+ mContext = context;
// Now fill the black list from the passed array
mEthTypeBlackList = filterEthTypeBlackList(config.ethTypeBlackList);
@@ -284,6 +296,10 @@
// TODO: ApfFilter should not generate programs until IpClient sends provisioning success.
maybeStartFilter();
+
+ // Listen for doze-mode transition changes to enable/disable the IPv6 multicast filter.
+ mContext.registerReceiver(mDeviceIdleReceiver,
+ new IntentFilter(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED));
}
private void log(String s) {
@@ -522,7 +538,7 @@
// to our packet socket. b/29586253
if (getUint16(mPacket, ETH_ETHERTYPE_OFFSET) != ETH_P_IPV6 ||
getUint8(mPacket, IPV6_NEXT_HEADER_OFFSET) != IPPROTO_ICMPV6 ||
- getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMP6_ROUTER_ADVERTISEMENT) {
+ getUint8(mPacket, ICMP6_TYPE_OFFSET) != ICMPV6_ROUTER_ADVERTISEMENT) {
throw new InvalidRaException("Not an ICMP6 router advertisement");
}
@@ -889,10 +905,11 @@
private void generateIPv6FilterLocked(ApfGenerator gen) throws IllegalInstructionException {
// Here's a basic summary of what the IPv6 filter program does:
//
- // if it's not ICMPv6:
- // if it's multicast and we're dropping multicast:
- // drop
- // pass
+ // if we're dropping multicast
+ // if it's not IPCMv6 or it's ICMPv6 but we're in doze mode:
+ // if it's multicast:
+ // drop
+ // pass
// if it's ICMPv6 RS to any:
// drop
// if it's ICMPv6 NA to ff02::1:
@@ -902,28 +919,44 @@
// Drop multicast if the multicast filter is enabled.
if (mMulticastFilter) {
- // Don't touch ICMPv6 multicast here, we deal with it in more detail later.
- String skipIpv6MulticastFilterLabel = "skipIPv6MulticastFilter";
- gen.addJumpIfR0Equals(IPPROTO_ICMPV6, skipIpv6MulticastFilterLabel);
+ final String skipIPv6MulticastFilterLabel = "skipIPv6MulticastFilter";
+ final String dropAllIPv6MulticastsLabel = "dropAllIPv6Multicast";
- // Drop all other packets sent to ff00::/8.
+ // While in doze mode, drop ICMPv6 multicast pings, let the others pass.
+ // While awake, let all ICMPv6 multicasts through.
+ if (mInDozeMode) {
+ // Not ICMPv6? -> Proceed to multicast filtering
+ gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, dropAllIPv6MulticastsLabel);
+
+ // ICMPv6 but not ECHO? -> Skip the multicast filter.
+ // (ICMPv6 ECHO requests will go through the multicast filter below).
+ gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
+ gen.addJumpIfR0NotEquals(ICMPV6_ECHO_REQUEST_TYPE, skipIPv6MulticastFilterLabel);
+ } else {
+ gen.addJumpIfR0Equals(IPPROTO_ICMPV6, skipIPv6MulticastFilterLabel);
+ }
+
+ // Drop all other packets sent to ff00::/8 (multicast prefix).
+ gen.defineLabel(dropAllIPv6MulticastsLabel);
gen.addLoad8(Register.R0, IPV6_DEST_ADDR_OFFSET);
gen.addJumpIfR0Equals(0xff, gen.DROP_LABEL);
- // Not multicast and not ICMPv6. Pass.
+ // Not multicast. Pass.
gen.addJump(gen.PASS_LABEL);
- gen.defineLabel(skipIpv6MulticastFilterLabel);
+ gen.defineLabel(skipIPv6MulticastFilterLabel);
} else {
// If not ICMPv6, pass.
gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, gen.PASS_LABEL);
}
+ // If we got this far, the packet is ICMPv6. Drop some specific types.
+
// Add unsolicited multicast neighbor announcements filter
String skipUnsolicitedMulticastNALabel = "skipUnsolicitedMulticastNA";
gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
// Drop all router solicitations (b/32833400)
- gen.addJumpIfR0Equals(ICMP6_ROUTER_SOLICITATION, gen.DROP_LABEL);
+ gen.addJumpIfR0Equals(ICMPV6_ROUTER_SOLICITATION, gen.DROP_LABEL);
// If not neighbor announcements, skip filter.
- gen.addJumpIfR0NotEquals(ICMP6_NEIGHBOR_ANNOUNCEMENT, skipUnsolicitedMulticastNALabel);
+ gen.addJumpIfR0NotEquals(ICMPV6_NEIGHBOR_ADVERTISEMENT, skipUnsolicitedMulticastNALabel);
// If to ff02::1, drop.
// TODO: Drop only if they don't contain the address of on-link neighbours.
gen.addLoadImmediate(Register.R0, IPV6_DEST_ADDR_OFFSET);
@@ -1167,9 +1200,9 @@
* Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet
* filtering using APF programs.
*/
- public static ApfFilter maybeCreate(ApfConfiguration config,
+ public static ApfFilter maybeCreate(Context context, ApfConfiguration config,
InterfaceParams ifParams, IpClient.Callback ipClientCallback) {
- if (config == null || ifParams == null) return null;
+ if (context == null || config == null || ifParams == null) return null;
ApfCapabilities apfCapabilities = config.apfCapabilities;
if (apfCapabilities == null) return null;
if (apfCapabilities.apfVersionSupported == 0) return null;
@@ -1186,7 +1219,8 @@
Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
return null;
}
- return new ApfFilter(config, ifParams, ipClientCallback, new IpConnectivityLog());
+
+ return new ApfFilter(context, config, ifParams, ipClientCallback, new IpConnectivityLog());
}
public synchronized void shutdown() {
@@ -1196,12 +1230,11 @@
mReceiveThread = null;
}
mRas.clear();
+ mContext.unregisterReceiver(mDeviceIdleReceiver);
}
public synchronized void setMulticastFilter(boolean isEnabled) {
- if (mMulticastFilter == isEnabled) {
- return;
- }
+ if (mMulticastFilter == isEnabled) return;
mMulticastFilter = isEnabled;
if (!isEnabled) {
mNumProgramUpdatesAllowingMulticast++;
@@ -1209,6 +1242,13 @@
installNewProgramLocked();
}
+ @VisibleForTesting
+ public synchronized void setDozeMode(boolean isEnabled) {
+ if (mInDozeMode == isEnabled) return;
+ mInDozeMode = isEnabled;
+ installNewProgramLocked();
+ }
+
/** Find the single IPv4 LinkAddress if there is one, otherwise return null. */
private static LinkAddress findIPv4LinkAddress(LinkProperties lp) {
LinkAddress ipv4Address = null;
diff --git a/services/net/java/android/net/apf/ApfGenerator.java b/services/net/java/android/net/apf/ApfGenerator.java
index d41fbce..ca8f727 100644
--- a/services/net/java/android/net/apf/ApfGenerator.java
+++ b/services/net/java/android/net/apf/ApfGenerator.java
@@ -367,7 +367,7 @@
*/
public boolean setApfVersion(int version) {
// This version number syncs up with APF_VERSION in hardware/google/apf/apf_interpreter.h
- return version == 2;
+ return version >= 2;
}
private void addInstruction(Instruction instruction) {
diff --git a/services/net/java/android/net/dns/ResolvUtil.java b/services/net/java/android/net/dns/ResolvUtil.java
new file mode 100644
index 0000000..97d20f4
--- /dev/null
+++ b/services/net/java/android/net/dns/ResolvUtil.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.dns;
+
+import android.net.Network;
+import android.net.NetworkUtils;
+import android.system.GaiException;
+import android.system.OsConstants;
+import android.system.StructAddrinfo;
+
+import libcore.io.Libcore;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+
+/**
+ * DNS resolution utility class.
+ *
+ * @hide
+ */
+public class ResolvUtil {
+ // Non-portable DNS resolution flag.
+ private static final long NETID_USE_LOCAL_NAMESERVERS = 0x80000000L;
+
+ private ResolvUtil() {}
+
+ public static InetAddress[] blockingResolveAllLocally(Network network, String name)
+ throws UnknownHostException {
+ final StructAddrinfo hints = new StructAddrinfo();
+ // Unnecessary, but expressly no AI_ADDRCONFIG.
+ hints.ai_flags = 0;
+ // Fetch all IP addresses at once to minimize re-resolution.
+ hints.ai_family = OsConstants.AF_UNSPEC;
+ hints.ai_socktype = OsConstants.SOCK_DGRAM;
+
+ final Network networkForResolv = getNetworkWithUseLocalNameserversFlag(network);
+
+ try {
+ return Libcore.os.android_getaddrinfo(name, hints, (int) networkForResolv.netId);
+ } catch (GaiException gai) {
+ gai.rethrowAsUnknownHostException(name + ": TLS-bypass resolution failed");
+ return null; // keep compiler quiet
+ }
+ }
+
+ public static Network getNetworkWithUseLocalNameserversFlag(Network network) {
+ final long netidForResolv = NETID_USE_LOCAL_NAMESERVERS | (long) network.netId;
+ return new Network((int) netidForResolv);
+ }
+}
diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java
index 9863370..a184b22 100644
--- a/services/net/java/android/net/ip/IpClient.java
+++ b/services/net/java/android/net/ip/IpClient.java
@@ -1490,7 +1490,7 @@
mContext.getResources().getBoolean(R.bool.config_apfDrop802_3Frames);
apfConfig.ethTypeBlackList =
mContext.getResources().getIntArray(R.array.config_apfEthTypeBlackList);
- mApfFilter = ApfFilter.maybeCreate(apfConfig, mInterfaceParams, mCallback);
+ mApfFilter = ApfFilter.maybeCreate(mContext, apfConfig, mInterfaceParams, mCallback);
// TODO: investigate the effects of any multicast filtering racing/interfering with the
// rest of this IP configuration startup.
if (mApfFilter == null) {
diff --git a/services/net/java/android/net/util/InterfaceSet.java b/services/net/java/android/net/util/InterfaceSet.java
new file mode 100644
index 0000000..9f26fa1
--- /dev/null
+++ b/services/net/java/android/net/util/InterfaceSet.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.util;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.StringJoiner;
+
+
+/**
+ * @hide
+ */
+public class InterfaceSet {
+ public final Set<String> ifnames;
+
+ public InterfaceSet(String... names) {
+ final Set<String> nameSet = new HashSet<>();
+ for (String name : names) {
+ if (name != null) nameSet.add(name);
+ }
+ ifnames = Collections.unmodifiableSet(nameSet);
+ }
+
+ @Override
+ public String toString() {
+ final StringJoiner sj = new StringJoiner(",", "[", "]");
+ for (String ifname : ifnames) sj.add(ifname);
+ return sj.toString();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj != null
+ && obj instanceof InterfaceSet
+ && ifnames.equals(((InterfaceSet)obj).ifnames);
+ }
+}
diff --git a/services/net/java/android/net/util/NetworkConstants.java b/services/net/java/android/net/util/NetworkConstants.java
index 984c9f8..53fd01f 100644
--- a/services/net/java/android/net/util/NetworkConstants.java
+++ b/services/net/java/android/net/util/NetworkConstants.java
@@ -136,6 +136,8 @@
* - https://tools.ietf.org/html/rfc4861
*/
public static final int ICMPV6_HEADER_MIN_LEN = 4;
+ public static final int ICMPV6_ECHO_REQUEST_TYPE = 128;
+ public static final int ICMPV6_ECHO_REPLY_TYPE = 129;
public static final int ICMPV6_ROUTER_SOLICITATION = 133;
public static final int ICMPV6_ROUTER_ADVERTISEMENT = 134;
public static final int ICMPV6_NEIGHBOR_SOLICITATION = 135;
@@ -147,7 +149,6 @@
public static final int ICMPV6_ND_OPTION_TLLA = 2;
public static final int ICMPV6_ND_OPTION_MTU = 5;
- public static final int ICMPV6_ECHO_REQUEST_TYPE = 128;
/**
* UDP constants.
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 9a53d8c..ca444d4 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -2598,7 +2598,6 @@
}
/**
- *
* Request audio routing to a specific bluetooth device. Calling this method may result in
* the device routing audio to a different bluetooth device than the one specified if the
* bluetooth stack is unable to route audio to the requested device.
@@ -2609,13 +2608,13 @@
* Used by self-managed {@link ConnectionService}s which wish to use bluetooth audio for a
* self-managed {@link Connection} (see {@link PhoneAccount#CAPABILITY_SELF_MANAGED}.)
* <p>
- * See also {@link InCallService#requestBluetoothAudio(String)}
- * @param bluetoothAddress The address of the bluetooth device to connect to, as returned by
- * {@link BluetoothDevice#getAddress()}.
+ * See also {@link InCallService#requestBluetoothAudio(BluetoothDevice)}
+ * @param bluetoothDevice The bluetooth device to connect to.
*/
- public void requestBluetoothAudio(@NonNull String bluetoothAddress) {
+ public void requestBluetoothAudio(@NonNull BluetoothDevice bluetoothDevice) {
for (Listener l : mListeners) {
- l.onAudioRouteChanged(this, CallAudioState.ROUTE_BLUETOOTH, bluetoothAddress);
+ l.onAudioRouteChanged(this, CallAudioState.ROUTE_BLUETOOTH,
+ bluetoothDevice.getAddress());
}
}
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index af65c65..bd25ab2 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -428,12 +428,11 @@
* A list of available devices can be obtained via
* {@link CallAudioState#getSupportedBluetoothDevices()}
*
- * @param bluetoothAddress The address of the bluetooth device to connect to, as returned by
- * {@link BluetoothDevice#getAddress()}.
+ * @param bluetoothDevice The bluetooth device to connect to.
*/
- public final void requestBluetoothAudio(@NonNull String bluetoothAddress) {
+ public final void requestBluetoothAudio(@NonNull BluetoothDevice bluetoothDevice) {
if (mPhone != null) {
- mPhone.requestBluetoothAudio(bluetoothAddress);
+ mPhone.requestBluetoothAudio(bluetoothDevice.getAddress());
}
}
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index 08f8bb6..890a6ea 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -18,11 +18,14 @@
import android.annotation.CallSuper;
import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
+import android.text.TextUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Objects;
/**
* CellIdentity represents the identity of a unique cell. This is the base class for
@@ -84,8 +87,16 @@
/** @hide */
protected final String mMncStr;
+ // long alpha Operator Name String or Enhanced Operator Name String
/** @hide */
- protected CellIdentity(String tag, int type, String mcc, String mnc) {
+ protected final String mAlphaLong;
+ // short alpha Operator Name String or Enhanced Operator Name String
+ /** @hide */
+ protected final String mAlphaShort;
+
+ /** @hide */
+ protected CellIdentity(String tag, int type, String mcc, String mnc, String alphal,
+ String alphas) {
mTag = tag;
mType = type;
@@ -113,6 +124,8 @@
mMncStr = null;
log("invalid MNC format: " + mnc);
}
+ mAlphaLong = alphal;
+ mAlphaShort = alphas;
}
/** Implement the Parcelable interface */
@@ -138,6 +151,40 @@
}
/**
+ * @return The long alpha tag associated with the current scan result (may be the operator
+ * name string or extended operator name string). May be null if unknown.
+ */
+ @Nullable
+ public CharSequence getOperatorAlphaLong() {
+ return mAlphaLong;
+ }
+
+ /**
+ * @return The short alpha tag associated with the current scan result (may be the operator
+ * name string or extended operator name string). May be null if unknown.
+ */
+ @Nullable
+ public CharSequence getOperatorAlphaShort() {
+ return mAlphaShort;
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof CellIdentity)) {
+ return false;
+ }
+
+ CellIdentity o = (CellIdentity) other;
+ return TextUtils.equals(mAlphaLong, o.mAlphaLong)
+ && TextUtils.equals(mAlphaShort, o.mAlphaShort);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mAlphaLong, mAlphaShort, mMccStr, mMncStr, mType);
+ }
+
+ /**
* Used by child classes for parceling.
*
* @hide
@@ -147,6 +194,8 @@
dest.writeInt(type);
dest.writeString(mMccStr);
dest.writeString(mMncStr);
+ dest.writeString(mAlphaLong);
+ dest.writeString(mAlphaShort);
}
/**
@@ -154,7 +203,8 @@
* @hide
*/
protected CellIdentity(String tag, int type, Parcel source) {
- this(tag, type, source.readString(), source.readString());
+ this(tag, type, source.readString(), source.readString(),
+ source.readString(), source.readString());
}
/** Implement the Parcelable interface */
diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java
index 713ac00..9a18c30 100644
--- a/telephony/java/android/telephony/CellIdentityCdma.java
+++ b/telephony/java/android/telephony/CellIdentityCdma.java
@@ -16,9 +16,7 @@
package android.telephony;
-import android.annotation.Nullable;
import android.os.Parcel;
-import android.text.TextUtils;
import java.util.Objects;
@@ -49,23 +47,17 @@
* to +90 degrees).
*/
private final int mLatitude;
- // long alpha Operator Name String or Enhanced Operator Name String
- private final String mAlphaLong;
- // short alpha Operator Name String or Enhanced Operator Name String
- private final String mAlphaShort;
/**
* @hide
*/
public CellIdentityCdma() {
- super(TAG, TYPE_CDMA, null, null);
+ super(TAG, TYPE_CDMA, null, null, null, null);
mNetworkId = Integer.MAX_VALUE;
mSystemId = Integer.MAX_VALUE;
mBasestationId = Integer.MAX_VALUE;
mLongitude = Integer.MAX_VALUE;
mLatitude = Integer.MAX_VALUE;
- mAlphaLong = null;
- mAlphaShort = null;
}
/**
@@ -100,7 +92,7 @@
*/
public CellIdentityCdma(int nid, int sid, int bid, int lon, int lat, String alphal,
String alphas) {
- super(TAG, TYPE_CDMA, null, null);
+ super(TAG, TYPE_CDMA, null, null, alphal, alphas);
mNetworkId = nid;
mSystemId = sid;
mBasestationId = bid;
@@ -110,8 +102,6 @@
} else {
mLongitude = mLatitude = Integer.MAX_VALUE;
}
- mAlphaLong = alphal;
- mAlphaShort = alphas;
}
private CellIdentityCdma(CellIdentityCdma cid) {
@@ -178,28 +168,10 @@
return mLatitude;
}
- /**
- * @return The long alpha tag associated with the current scan result (may be the operator
- * name string or extended operator name string). May be null if unknown.
- */
- @Nullable
- public CharSequence getOperatorAlphaLong() {
- return mAlphaLong;
- }
-
- /**
- * @return The short alpha tag associated with the current scan result (may be the operator
- * name string or extended operator name string). May be null if unknown.
- */
- @Nullable
- public CharSequence getOperatorAlphaShort() {
- return mAlphaShort;
- }
-
@Override
public int hashCode() {
return Objects.hash(mNetworkId, mSystemId, mBasestationId, mLatitude, mLongitude,
- mAlphaLong, mAlphaShort);
+ super.hashCode());
}
@Override
@@ -219,8 +191,7 @@
&& mBasestationId == o.mBasestationId
&& mLatitude == o.mLatitude
&& mLongitude == o.mLongitude
- && TextUtils.equals(mAlphaLong, o.mAlphaLong)
- && TextUtils.equals(mAlphaShort, o.mAlphaShort);
+ && super.equals(other);
}
@Override
@@ -246,8 +217,6 @@
dest.writeInt(mBasestationId);
dest.writeInt(mLongitude);
dest.writeInt(mLatitude);
- dest.writeString(mAlphaLong);
- dest.writeString(mAlphaShort);
}
/** Construct from Parcel, type has already been processed */
@@ -258,8 +227,6 @@
mBasestationId = in.readInt();
mLongitude = in.readInt();
mLatitude = in.readInt();
- mAlphaLong = in.readString();
- mAlphaShort = in.readString();
if (DBG) log(toString());
}
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index aae7929..b167850 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -16,7 +16,6 @@
package android.telephony;
-import android.annotation.Nullable;
import android.os.Parcel;
import android.text.TextUtils;
@@ -37,22 +36,16 @@
private final int mArfcn;
// 6-bit Base Station Identity Code
private final int mBsic;
- // long alpha Operator Name String or Enhanced Operator Name String
- private final String mAlphaLong;
- // short alpha Operator Name String or Enhanced Operator Name String
- private final String mAlphaShort;
/**
* @hide
*/
public CellIdentityGsm() {
- super(TAG, TYPE_GSM, null, null);
+ super(TAG, TYPE_GSM, null, null, null, null);
mLac = Integer.MAX_VALUE;
mCid = Integer.MAX_VALUE;
mArfcn = Integer.MAX_VALUE;
mBsic = Integer.MAX_VALUE;
- mAlphaLong = null;
- mAlphaShort = null;
}
/**
* public constructor
@@ -98,16 +91,13 @@
*/
public CellIdentityGsm(int lac, int cid, int arfcn, int bsic, String mccStr,
String mncStr, String alphal, String alphas) {
- super(TAG, TYPE_GSM, mccStr, mncStr);
+ super(TAG, TYPE_GSM, mccStr, mncStr, alphal, alphas);
mLac = lac;
mCid = cid;
mArfcn = arfcn;
// In RIL BSIC is a UINT8, so 0xFF is the 'INVALID' designator
// for inbound parcels
mBsic = (bsic == 0xFF) ? Integer.MAX_VALUE : bsic;
-
- mAlphaLong = alphal;
- mAlphaShort = alphas;
}
private CellIdentityGsm(CellIdentityGsm cid) {
@@ -188,24 +178,6 @@
return mMncStr;
}
- /**
- * @return The long alpha tag associated with the current scan result (may be the operator
- * name string or extended operator name string). May be null if unknown.
- */
- @Nullable
- public CharSequence getOperatorAlphaLong() {
- return mAlphaLong;
- }
-
- /**
- * @return The short alpha tag associated with the current scan result (may be the operator
- * name string or extended operator name string). May be null if unknown.
- */
- @Nullable
- public CharSequence getOperatorAlphaShort() {
- return mAlphaShort;
- }
-
/** @hide */
@Override
public int getChannelNumber() {
@@ -223,7 +195,7 @@
@Override
public int hashCode() {
- return Objects.hash(mMccStr, mMncStr, mLac, mCid, mAlphaLong, mAlphaShort);
+ return Objects.hash(mLac, mCid, super.hashCode());
}
@Override
@@ -243,8 +215,7 @@
&& mBsic == o.mBsic
&& TextUtils.equals(mMccStr, o.mMccStr)
&& TextUtils.equals(mMncStr, o.mMncStr)
- && TextUtils.equals(mAlphaLong, o.mAlphaLong)
- && TextUtils.equals(mAlphaShort, o.mAlphaShort);
+ && super.equals(other);
}
@Override
@@ -270,8 +241,6 @@
dest.writeInt(mCid);
dest.writeInt(mArfcn);
dest.writeInt(mBsic);
- dest.writeString(mAlphaLong);
- dest.writeString(mAlphaShort);
}
/** Construct from Parcel, type has already been processed */
@@ -281,8 +250,6 @@
mCid = in.readInt();
mArfcn = in.readInt();
mBsic = in.readInt();
- mAlphaLong = in.readString();
- mAlphaShort = in.readString();
if (DBG) log(toString());
}
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 9b3ef56..d421cbd 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -16,7 +16,6 @@
package android.telephony;
-import android.annotation.Nullable;
import android.os.Parcel;
import android.text.TextUtils;
@@ -37,10 +36,6 @@
private final int mTac;
// 18-bit Absolute RF Channel Number
private final int mEarfcn;
- // long alpha Operator Name String or Enhanced Operator Name String
- private final String mAlphaLong;
- // short alpha Operator Name String or Enhanced Operator Name String
- private final String mAlphaShort;
// cell bandwidth, in kHz
private final int mBandwidth;
@@ -48,14 +43,12 @@
* @hide
*/
public CellIdentityLte() {
- super(TAG, TYPE_LTE, null, null);
+ super(TAG, TYPE_LTE, null, null, null, null);
mCi = Integer.MAX_VALUE;
mPci = Integer.MAX_VALUE;
mTac = Integer.MAX_VALUE;
mEarfcn = Integer.MAX_VALUE;
mBandwidth = Integer.MAX_VALUE;
- mAlphaLong = null;
- mAlphaShort = null;
}
/**
@@ -105,14 +98,12 @@
*/
public CellIdentityLte(int ci, int pci, int tac, int earfcn, int bandwidth, String mccStr,
String mncStr, String alphal, String alphas) {
- super(TAG, TYPE_LTE, mccStr, mncStr);
+ super(TAG, TYPE_LTE, mccStr, mncStr, alphal, alphas);
mCi = ci;
mPci = pci;
mTac = tac;
mEarfcn = earfcn;
mBandwidth = bandwidth;
- mAlphaLong = alphal;
- mAlphaShort = alphas;
}
private CellIdentityLte(CellIdentityLte cid) {
@@ -198,24 +189,6 @@
return (mMccStr == null || mMncStr == null) ? null : mMccStr + mMncStr;
}
- /**
- * @return The long alpha tag associated with the current scan result (may be the operator
- * name string or extended operator name string). May be null if unknown.
- */
- @Nullable
- public CharSequence getOperatorAlphaLong() {
- return mAlphaLong;
- }
-
- /**
- * @return The short alpha tag associated with the current scan result (may be the operator
- * name string or extended operator name string). May be null if unknown.
- */
- @Nullable
- public CharSequence getOperatorAlphaShort() {
- return mAlphaShort;
- }
-
/** @hide */
@Override
public int getChannelNumber() {
@@ -224,7 +197,7 @@
@Override
public int hashCode() {
- return Objects.hash(mMccStr, mMncStr, mCi, mPci, mTac, mAlphaLong, mAlphaShort);
+ return Objects.hash(mCi, mPci, mTac, super.hashCode());
}
@Override
@@ -245,8 +218,7 @@
&& mBandwidth == o.mBandwidth
&& TextUtils.equals(mMccStr, o.mMccStr)
&& TextUtils.equals(mMncStr, o.mMncStr)
- && TextUtils.equals(mAlphaLong, o.mAlphaLong)
- && TextUtils.equals(mAlphaShort, o.mAlphaShort);
+ && super.equals(other);
}
@Override
@@ -274,8 +246,6 @@
dest.writeInt(mTac);
dest.writeInt(mEarfcn);
dest.writeInt(mBandwidth);
- dest.writeString(mAlphaLong);
- dest.writeString(mAlphaShort);
}
/** Construct from Parcel, type has already been processed */
@@ -286,8 +256,6 @@
mTac = in.readInt();
mEarfcn = in.readInt();
mBandwidth = in.readInt();
- mAlphaLong = in.readString();
- mAlphaShort = in.readString();
if (DBG) log(toString());
}
diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java
index 7475c74..3070bd1 100644
--- a/telephony/java/android/telephony/CellIdentityTdscdma.java
+++ b/telephony/java/android/telephony/CellIdentityTdscdma.java
@@ -16,7 +16,6 @@
package android.telephony;
-import android.annotation.Nullable;
import android.os.Parcel;
import android.text.TextUtils;
@@ -35,21 +34,15 @@
private final int mCid;
// 8-bit Cell Parameters ID described in TS 25.331, 0..127, INT_MAX if unknown.
private final int mCpid;
- // long alpha Operator Name String or Enhanced Operator Name String
- private final String mAlphaLong;
- // short alpha Operator Name String or Enhanced Operator Name String
- private final String mAlphaShort;
/**
* @hide
*/
public CellIdentityTdscdma() {
- super(TAG, TYPE_TDSCDMA, null, null);
+ super(TAG, TYPE_TDSCDMA, null, null, null, null);
mLac = Integer.MAX_VALUE;
mCid = Integer.MAX_VALUE;
mCpid = Integer.MAX_VALUE;
- mAlphaLong = null;
- mAlphaShort = null;
}
/**
@@ -76,12 +69,10 @@
* @hide
*/
public CellIdentityTdscdma(String mcc, String mnc, int lac, int cid, int cpid) {
- super(TAG, TYPE_TDSCDMA, mcc, mnc);
+ super(TAG, TYPE_TDSCDMA, mcc, mnc, null, null);
mLac = lac;
mCid = cid;
mCpid = cpid;
- mAlphaLong = null;
- mAlphaShort = null;
}
/**
@@ -97,12 +88,10 @@
*/
public CellIdentityTdscdma(String mcc, String mnc, int lac, int cid, int cpid,
String alphal, String alphas) {
- super(TAG, TYPE_TDSCDMA, mcc, mnc);
+ super(TAG, TYPE_TDSCDMA, mcc, mnc, alphal, alphas);
mLac = lac;
mCid = cid;
mCpid = cpid;
- mAlphaLong = alphal;
- mAlphaShort = alphas;
}
private CellIdentityTdscdma(CellIdentityTdscdma cid) {
@@ -151,31 +140,9 @@
return mCpid;
}
- /**
- * @return The long alpha tag associated with the current scan result (may be the operator
- * name string or extended operator name string). May be null if unknown.
- *
- * @hide
- */
- @Nullable
- public CharSequence getOperatorAlphaLong() {
- return mAlphaLong;
- }
-
- /**
- * @return The short alpha tag associated with the current scan result (may be the operator
- * name string or extended operator name string). May be null if unknown.
- *
- * @hide
- */
- @Nullable
- public CharSequence getOperatorAlphaShort() {
- return mAlphaShort;
- }
-
@Override
public int hashCode() {
- return Objects.hash(mMccStr, mMncStr, mLac, mCid, mCpid, mAlphaLong, mAlphaShort);
+ return Objects.hash(mLac, mCid, mCpid, super.hashCode());
}
@Override
@@ -194,8 +161,7 @@
&& mLac == o.mLac
&& mCid == o.mCid
&& mCpid == o.mCpid
- && mAlphaLong == o.mAlphaLong
- && mAlphaShort == o.mAlphaShort;
+ && super.equals(other);
}
@Override
@@ -219,8 +185,6 @@
dest.writeInt(mLac);
dest.writeInt(mCid);
dest.writeInt(mCpid);
- dest.writeString(mAlphaLong);
- dest.writeString(mAlphaShort);
}
/** Construct from Parcel, type has already been processed */
@@ -229,8 +193,6 @@
mLac = in.readInt();
mCid = in.readInt();
mCpid = in.readInt();
- mAlphaLong = in.readString();
- mAlphaShort = in.readString();
if (DBG) log(toString());
}
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index 52fa54f..f1167a6 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -16,7 +16,6 @@
package android.telephony;
-import android.annotation.Nullable;
import android.os.Parcel;
import android.text.TextUtils;
@@ -37,22 +36,16 @@
private final int mPsc;
// 16-bit UMTS Absolute RF Channel Number
private final int mUarfcn;
- // long alpha Operator Name String or Enhanced Operator Name String
- private final String mAlphaLong;
- // short alpha Operator Name String or Enhanced Operator Name String
- private final String mAlphaShort;
/**
* @hide
*/
public CellIdentityWcdma() {
- super(TAG, TYPE_TDSCDMA, null, null);
+ super(TAG, TYPE_TDSCDMA, null, null, null, null);
mLac = Integer.MAX_VALUE;
mCid = Integer.MAX_VALUE;
mPsc = Integer.MAX_VALUE;
mUarfcn = Integer.MAX_VALUE;
- mAlphaLong = null;
- mAlphaShort = null;
}
/**
* public constructor
@@ -99,13 +92,11 @@
*/
public CellIdentityWcdma (int lac, int cid, int psc, int uarfcn,
String mccStr, String mncStr, String alphal, String alphas) {
- super(TAG, TYPE_WCDMA, mccStr, mncStr);
+ super(TAG, TYPE_WCDMA, mccStr, mncStr, alphal, alphas);
mLac = lac;
mCid = cid;
mPsc = psc;
mUarfcn = uarfcn;
- mAlphaLong = alphal;
- mAlphaShort = alphas;
}
private CellIdentityWcdma(CellIdentityWcdma cid) {
@@ -179,27 +170,9 @@
return (mMccStr == null || mMncStr == null) ? null : mMccStr + mMncStr;
}
- /**
- * @return The long alpha tag associated with the current scan result (may be the operator
- * name string or extended operator name string). May be null if unknown.
- */
- @Nullable
- public CharSequence getOperatorAlphaLong() {
- return mAlphaLong;
- }
-
- /**
- * @return The short alpha tag associated with the current scan result (may be the operator
- * name string or extended operator name string). May be null if unknown.
- */
- @Nullable
- public CharSequence getOperatorAlphaShort() {
- return mAlphaShort;
- }
-
@Override
public int hashCode() {
- return Objects.hash(mMccStr, mMncStr, mLac, mCid, mPsc, mAlphaLong, mAlphaShort);
+ return Objects.hash(mLac, mCid, mPsc, super.hashCode());
}
/**
@@ -232,8 +205,7 @@
&& mUarfcn == o.mUarfcn
&& TextUtils.equals(mMccStr, o.mMccStr)
&& TextUtils.equals(mMncStr, o.mMncStr)
- && TextUtils.equals(mAlphaLong, o.mAlphaLong)
- && TextUtils.equals(mAlphaShort, o.mAlphaShort);
+ && super.equals(other);
}
@Override
@@ -259,8 +231,6 @@
dest.writeInt(mCid);
dest.writeInt(mPsc);
dest.writeInt(mUarfcn);
- dest.writeString(mAlphaLong);
- dest.writeString(mAlphaShort);
}
/** Construct from Parcel, type has already been processed */
@@ -270,8 +240,6 @@
mCid = in.readInt();
mPsc = in.readInt();
mUarfcn = in.readInt();
- mAlphaLong = in.readString();
- mAlphaShort = in.readString();
if (DBG) log(toString());
}
@@ -295,4 +263,4 @@
protected static CellIdentityWcdma createFromParcelBody(Parcel in) {
return new CellIdentityWcdma(in);
}
-}
\ No newline at end of file
+}
diff --git a/telephony/java/android/telephony/MbmsDownloadSession.java b/telephony/java/android/telephony/MbmsDownloadSession.java
index cdab521..d9fdd97 100644
--- a/telephony/java/android/telephony/MbmsDownloadSession.java
+++ b/telephony/java/android/telephony/MbmsDownloadSession.java
@@ -16,6 +16,8 @@
package android.telephony;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -32,14 +34,14 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.telephony.mbms.DownloadProgressListener;
+import android.telephony.mbms.DownloadRequest;
import android.telephony.mbms.DownloadStatusListener;
import android.telephony.mbms.FileInfo;
-import android.telephony.mbms.DownloadRequest;
import android.telephony.mbms.InternalDownloadProgressListener;
import android.telephony.mbms.InternalDownloadSessionCallback;
import android.telephony.mbms.InternalDownloadStatusListener;
-import android.telephony.mbms.MbmsDownloadSessionCallback;
import android.telephony.mbms.MbmsDownloadReceiver;
+import android.telephony.mbms.MbmsDownloadSessionCallback;
import android.telephony.mbms.MbmsErrors;
import android.telephony.mbms.MbmsTempFileProvider;
import android.telephony.mbms.MbmsUtils;
@@ -58,8 +60,6 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
-import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-
/**
* This class provides functionality for file download over MBMS.
*/
@@ -337,6 +337,12 @@
sIsInitialized.set(false);
return;
}
+ if (result == MbmsErrors.UNKNOWN) {
+ // Unbind and throw an obvious error
+ close();
+ throw new IllegalStateException("Middleware must not return an"
+ + " unknown error code");
+ }
if (result != MbmsErrors.SUCCESS) {
sendErrorToApp(result, "Error returned during initialization");
sIsInitialized.set(false);
@@ -388,6 +394,11 @@
}
try {
int returnCode = downloadService.requestUpdateFileServices(mSubscriptionId, classList);
+ if (returnCode == MbmsErrors.UNKNOWN) {
+ // Unbind and throw an obvious error
+ close();
+ throw new IllegalStateException("Middleware must not return an unknown error code");
+ }
if (returnCode != MbmsErrors.SUCCESS) {
sendErrorToApp(returnCode, null);
}
@@ -443,6 +454,11 @@
try {
int result = downloadService.setTempFileRootDirectory(mSubscriptionId, filePath);
+ if (result == MbmsErrors.UNKNOWN) {
+ // Unbind and throw an obvious error
+ close();
+ throw new IllegalStateException("Middleware must not return an unknown error code");
+ }
if (result != MbmsErrors.SUCCESS) {
sendErrorToApp(result, null);
return;
@@ -514,11 +530,13 @@
*
* Asynchronous errors through the callback may include any error not specific to the
* streaming use-case.
+ *
+ * If no error is delivered via the callback after calling this method, that means that the
+ * middleware has successfully started the download or scheduled the download, if the download
+ * is at a future time.
* @param request The request that specifies what should be downloaded.
- * @return {@link MbmsErrors#SUCCESS} if the operation did not encounter a synchronous error,
- * and some other error code otherwise.
*/
- public int download(@NonNull DownloadRequest request) {
+ public void download(@NonNull DownloadRequest request) {
IMbmsDownloadService downloadService = mService.get();
if (downloadService == null) {
throw new IllegalStateException("Middleware not yet bound");
@@ -540,12 +558,19 @@
int result = downloadService.download(request);
if (result == MbmsErrors.SUCCESS) {
writeDownloadRequestToken(request);
+ } else {
+ if (result == MbmsErrors.UNKNOWN) {
+ // Unbind and throw an obvious error
+ close();
+ throw new IllegalStateException("Middleware must not return an unknown"
+ + " error code");
+ }
+ sendErrorToApp(result, null);
}
- return result;
} catch (RemoteException e) {
mService.set(null);
sIsInitialized.set(false);
- return MbmsErrors.ERROR_MIDDLEWARE_LOST;
+ sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
}
}
@@ -581,14 +606,15 @@
* If the middleware is not aware of the specified download request,
* this method will throw an {@link IllegalArgumentException}.
*
+ * If the operation encountered an error, the error code will be delivered via
+ * {@link MbmsDownloadSessionCallback#onError}.
+ *
* @param request The {@link DownloadRequest} that you want updates on.
* @param executor The {@link Executor} on which calls to {@code listener } should be executed.
* @param listener The listener that should be called when the middleware has information to
* share on the status download.
- * @return {@link MbmsErrors#SUCCESS} if the operation did not encounter a synchronous error,
- * and some other error code otherwise.
*/
- public int addStatusListener(@NonNull DownloadRequest request,
+ public void addStatusListener(@NonNull DownloadRequest request,
@NonNull Executor executor, @NonNull DownloadStatusListener listener) {
IMbmsDownloadService downloadService = mService.get();
if (downloadService == null) {
@@ -600,20 +626,25 @@
try {
int result = downloadService.addStatusListener(request, internalListener);
+ if (result == MbmsErrors.UNKNOWN) {
+ // Unbind and throw an obvious error
+ close();
+ throw new IllegalStateException("Middleware must not return an unknown error code");
+ }
if (result != MbmsErrors.SUCCESS) {
if (result == MbmsErrors.DownloadErrors.ERROR_UNKNOWN_DOWNLOAD_REQUEST) {
throw new IllegalArgumentException("Unknown download request.");
}
- return result;
+ sendErrorToApp(result, null);
+ return;
}
} catch (RemoteException e) {
mService.set(null);
sIsInitialized.set(false);
- return MbmsErrors.ERROR_MIDDLEWARE_LOST;
+ sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
+ return;
}
mInternalDownloadStatusListeners.put(listener, internalListener);
- return MbmsErrors.SUCCESS;
-
}
/**
@@ -625,12 +656,13 @@
* If the middleware is not aware of the specified download request,
* this method will throw an {@link IllegalArgumentException}.
*
+ * If the operation encountered an error, the error code will be delivered via
+ * {@link MbmsDownloadSessionCallback#onError}.
+ *
* @param request The {@link DownloadRequest} provided during registration
* @param listener The listener provided during registration.
- * @return {@link MbmsErrors#SUCCESS} if the operation did not encounter a synchronous error,
- * and some other error code otherwise.
*/
- public int removeStatusListener(@NonNull DownloadRequest request,
+ public void removeStatusListener(@NonNull DownloadRequest request,
@NonNull DownloadStatusListener listener) {
try {
IMbmsDownloadService downloadService = mService.get();
@@ -646,16 +678,24 @@
try {
int result = downloadService.removeStatusListener(request, internalListener);
+ if (result == MbmsErrors.UNKNOWN) {
+ // Unbind and throw an obvious error
+ close();
+ throw new IllegalStateException("Middleware must not return an"
+ + " unknown error code");
+ }
if (result != MbmsErrors.SUCCESS) {
if (result == MbmsErrors.DownloadErrors.ERROR_UNKNOWN_DOWNLOAD_REQUEST) {
throw new IllegalArgumentException("Unknown download request.");
}
- return result;
+ sendErrorToApp(result, null);
+ return;
}
} catch (RemoteException e) {
mService.set(null);
sIsInitialized.set(false);
- return MbmsErrors.ERROR_MIDDLEWARE_LOST;
+ sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
+ return;
}
} finally {
InternalDownloadStatusListener internalCallback =
@@ -664,7 +704,6 @@
internalCallback.stop();
}
}
- return MbmsErrors.SUCCESS;
}
/**
@@ -676,14 +715,15 @@
* If the middleware is not aware of the specified download request,
* this method will throw an {@link IllegalArgumentException}.
*
+ * If the operation encountered an error, the error code will be delivered via
+ * {@link MbmsDownloadSessionCallback#onError}.
+ *
* @param request The {@link DownloadRequest} that you want updates on.
* @param executor The {@link Executor} on which calls to {@code listener} should be executed.
* @param listener The listener that should be called when the middleware has information to
* share on the progress of the download.
- * @return {@link MbmsErrors#SUCCESS} if the operation did not encounter a synchronous error,
- * and some other error code otherwise.
*/
- public int addProgressListener(@NonNull DownloadRequest request,
+ public void addProgressListener(@NonNull DownloadRequest request,
@NonNull Executor executor, @NonNull DownloadProgressListener listener) {
IMbmsDownloadService downloadService = mService.get();
if (downloadService == null) {
@@ -695,19 +735,25 @@
try {
int result = downloadService.addProgressListener(request, internalListener);
+ if (result == MbmsErrors.UNKNOWN) {
+ // Unbind and throw an obvious error
+ close();
+ throw new IllegalStateException("Middleware must not return an unknown error code");
+ }
if (result != MbmsErrors.SUCCESS) {
if (result == MbmsErrors.DownloadErrors.ERROR_UNKNOWN_DOWNLOAD_REQUEST) {
throw new IllegalArgumentException("Unknown download request.");
}
- return result;
+ sendErrorToApp(result, null);
+ return;
}
} catch (RemoteException e) {
mService.set(null);
sIsInitialized.set(false);
- return MbmsErrors.ERROR_MIDDLEWARE_LOST;
+ sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
+ return;
}
mInternalDownloadProgressListeners.put(listener, internalListener);
- return MbmsErrors.SUCCESS;
}
/**
@@ -719,12 +765,13 @@
* If the middleware is not aware of the specified download request,
* this method will throw an {@link IllegalArgumentException}.
*
+ * If the operation encountered an error, the error code will be delivered via
+ * {@link MbmsDownloadSessionCallback#onError}.
+ *
* @param request The {@link DownloadRequest} provided during registration
* @param listener The listener provided during registration.
- * @return {@link MbmsErrors#SUCCESS} if the operation did not encounter a synchronous error,
- * and some other error code otherwise.
*/
- public int removeProgressListener(@NonNull DownloadRequest request,
+ public void removeProgressListener(@NonNull DownloadRequest request,
@NonNull DownloadProgressListener listener) {
try {
IMbmsDownloadService downloadService = mService.get();
@@ -740,16 +787,24 @@
try {
int result = downloadService.removeProgressListener(request, internalListener);
+ if (result == MbmsErrors.UNKNOWN) {
+ // Unbind and throw an obvious error
+ close();
+ throw new IllegalStateException("Middleware must not"
+ + " return an unknown error code");
+ }
if (result != MbmsErrors.SUCCESS) {
if (result == MbmsErrors.DownloadErrors.ERROR_UNKNOWN_DOWNLOAD_REQUEST) {
throw new IllegalArgumentException("Unknown download request.");
}
- return result;
+ sendErrorToApp(result, null);
+ return;
}
} catch (RemoteException e) {
mService.set(null);
sIsInitialized.set(false);
- return MbmsErrors.ERROR_MIDDLEWARE_LOST;
+ sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
+ return;
}
} finally {
InternalDownloadProgressListener internalCallback =
@@ -758,20 +813,17 @@
internalCallback.stop();
}
}
- return MbmsErrors.SUCCESS;
}
/**
* Attempts to cancel the specified {@link DownloadRequest}.
*
- * If the middleware is not aware of the specified download request,
- * this method will throw an {@link IllegalArgumentException}.
+ * If the operation encountered an error, the error code will be delivered via
+ * {@link MbmsDownloadSessionCallback#onError}.
*
* @param downloadRequest The download request that you wish to cancel.
- * @return {@link MbmsErrors#SUCCESS} if the operation did not encounter a synchronous error,
- * and some other error code otherwise.
*/
- public int cancelDownload(@NonNull DownloadRequest downloadRequest) {
+ public void cancelDownload(@NonNull DownloadRequest downloadRequest) {
IMbmsDownloadService downloadService = mService.get();
if (downloadService == null) {
throw new IllegalStateException("Middleware not yet bound");
@@ -779,18 +831,20 @@
try {
int result = downloadService.cancelDownload(downloadRequest);
+ if (result == MbmsErrors.UNKNOWN) {
+ // Unbind and throw an obvious error
+ close();
+ throw new IllegalStateException("Middleware must not return an unknown error code");
+ }
if (result != MbmsErrors.SUCCESS) {
- if (result == MbmsErrors.DownloadErrors.ERROR_UNKNOWN_DOWNLOAD_REQUEST) {
- throw new IllegalArgumentException("Unknown download request.");
- }
+ sendErrorToApp(result, null);
} else {
deleteDownloadRequestToken(downloadRequest);
}
- return result;
} catch (RemoteException e) {
mService.set(null);
sIsInitialized.set(false);
- return MbmsErrors.ERROR_MIDDLEWARE_LOST;
+ sendErrorToApp(MbmsErrors.ERROR_MIDDLEWARE_LOST, null);
}
}
@@ -818,6 +872,11 @@
try {
int result = downloadService.requestDownloadState(downloadRequest, fileInfo);
+ if (result == MbmsErrors.UNKNOWN) {
+ // Unbind and throw an obvious error
+ close();
+ throw new IllegalStateException("Middleware must not return an unknown error code");
+ }
if (result != MbmsErrors.SUCCESS) {
if (result == MbmsErrors.DownloadErrors.ERROR_UNKNOWN_DOWNLOAD_REQUEST) {
throw new IllegalArgumentException("Unknown download request.");
@@ -862,6 +921,11 @@
try {
int result = downloadService.resetDownloadKnowledge(downloadRequest);
+ if (result == MbmsErrors.UNKNOWN) {
+ // Unbind and throw an obvious error
+ close();
+ throw new IllegalStateException("Middleware must not return an unknown error code");
+ }
if (result != MbmsErrors.SUCCESS) {
if (result == MbmsErrors.DownloadErrors.ERROR_UNKNOWN_DOWNLOAD_REQUEST) {
throw new IllegalArgumentException("Unknown download request.");
@@ -920,11 +984,11 @@
try {
if (!token.createNewFile()) {
throw new RuntimeException("Failed to create download token for request "
- + request);
+ + request + ". Token location is " + token.getPath());
}
} catch (IOException e) {
throw new RuntimeException("Failed to create download token for request " + request
- + " due to IOException " + e);
+ + " due to IOException " + e + ". Attempted to write to " + token.getPath());
}
}
@@ -978,10 +1042,6 @@
}
private void sendErrorToApp(int errorCode, String message) {
- try {
- mInternalCallback.onError(errorCode, message);
- } catch (RemoteException e) {
- // Ignore, should not happen locally.
- }
+ mInternalCallback.onError(errorCode, message);
}
}
diff --git a/telephony/java/android/telephony/MbmsStreamingSession.java b/telephony/java/android/telephony/MbmsStreamingSession.java
index 42c760d4..cd465d2 100644
--- a/telephony/java/android/telephony/MbmsStreamingSession.java
+++ b/telephony/java/android/telephony/MbmsStreamingSession.java
@@ -16,6 +16,8 @@
package android.telephony;
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
@@ -26,8 +28,8 @@
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
-import android.telephony.mbms.InternalStreamingSessionCallback;
import android.telephony.mbms.InternalStreamingServiceCallback;
+import android.telephony.mbms.InternalStreamingSessionCallback;
import android.telephony.mbms.MbmsErrors;
import android.telephony.mbms.MbmsStreamingSessionCallback;
import android.telephony.mbms.MbmsUtils;
@@ -44,8 +46,6 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
-import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-
/**
* This class provides functionality for streaming media over MBMS.
*/
@@ -208,6 +208,11 @@
try {
int returnCode = streamingService.requestUpdateStreamingServices(
mSubscriptionId, serviceClassList);
+ if (returnCode == MbmsErrors.UNKNOWN) {
+ // Unbind and throw an obvious error
+ close();
+ throw new IllegalStateException("Middleware must not return an unknown error code");
+ }
if (returnCode != MbmsErrors.SUCCESS) {
sendErrorToApp(returnCode, null);
}
@@ -255,6 +260,11 @@
try {
int returnCode = streamingService.startStreaming(
mSubscriptionId, serviceInfo.getServiceId(), serviceCallback);
+ if (returnCode == MbmsErrors.UNKNOWN) {
+ // Unbind and throw an obvious error
+ close();
+ throw new IllegalStateException("Middleware must not return an unknown error code");
+ }
if (returnCode != MbmsErrors.SUCCESS) {
sendErrorToApp(returnCode, null);
return null;
@@ -301,6 +311,12 @@
sIsInitialized.set(false);
return;
}
+ if (result == MbmsErrors.UNKNOWN) {
+ // Unbind and throw an obvious error
+ close();
+ throw new IllegalStateException("Middleware must not return"
+ + " an unknown error code");
+ }
if (result != MbmsErrors.SUCCESS) {
sendErrorToApp(result, "Error returned during initialization");
sIsInitialized.set(false);
diff --git a/telephony/java/android/telephony/NetworkServiceCallback.java b/telephony/java/android/telephony/NetworkServiceCallback.java
index 92ebf36..dbad02f 100644
--- a/telephony/java/android/telephony/NetworkServiceCallback.java
+++ b/telephony/java/android/telephony/NetworkServiceCallback.java
@@ -83,6 +83,8 @@
} catch (RemoteException e) {
Rlog.e(mTag, "Failed to onGetNetworkRegistrationStateComplete on the remote");
}
+ } else {
+ Rlog.e(mTag, "Weak reference of callback is null.");
}
}
}
\ No newline at end of file
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index 77413d9c..936505c 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -335,7 +335,7 @@
return this.mCountryIso;
}
- /** @return whether the subscription is an embedded one. */
+ /** @return whether the subscription is an eUICC one. */
public boolean isEmbedded() {
return this.mIsEmbedded;
}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 05b8b57..1d7b724 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1704,26 +1704,28 @@
*
* @param info The subscription to check.
* @return whether the app is authorized to manage this subscription per its metadata.
- * @throws UnsupportedOperationException if this subscription is not embedded.
+ * @throws IllegalArgumentException if this subscription is not embedded.
*/
public boolean canManageSubscription(SubscriptionInfo info) {
return canManageSubscription(info, mContext.getPackageName());
}
/**
- * Checks whether the given app is authorized to manage the given subscription according to its
- * metadata. Only supported for embedded subscriptions (if {@code SubscriptionInfo#isEmbedded}
+ * Checks whether the given app is authorized to manage the given subscription. An app can only
+ * be authorized if it is included in the {@link android.telephony.UiccAccessRule} of the
+ * {@link android.telephony.SubscriptionInfo} with the access status.
+ * Only supported for embedded subscriptions (if {@link SubscriptionInfo#isEmbedded}
* returns true).
*
* @param info The subscription to check.
* @param packageName Package name of the app to check.
- * @return whether the app is authorized to manage this subscription per its metadata.
- * @throws UnsupportedOperationException if this subscription is not embedded.
+ * @return whether the app is authorized to manage this subscription per its access rules.
+ * @throws IllegalArgumentException if this subscription is not embedded.
* @hide
*/
public boolean canManageSubscription(SubscriptionInfo info, String packageName) {
if (!info.isEmbedded()) {
- throw new UnsupportedOperationException("Not an embedded subscription");
+ throw new IllegalArgumentException("Not an embedded subscription");
}
if (info.getAccessRules() == null) {
return false;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index caf08e9..c2cbd06 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -40,6 +40,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.PersistableBundle;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.ServiceManager;
@@ -214,6 +215,10 @@
return ActivityThread.currentOpPackageName();
}
+ private boolean isSystemProcess() {
+ return Process.myUid() == Process.SYSTEM_UID;
+ }
+
/**
* Returns the multi SIM variant
* Returns DSDS for Dual SIM Dual Standby
@@ -2785,18 +2790,17 @@
* @return ImsiEncryptionInfo Carrier specific information that will be used to encrypt the
* IMSI and IMPI. This includes the public key and the key identifier. This information
* will be stored in the device keystore. The system will return a null when no key was
- * found, and the carrier does not require a key. The system will throw the following
- * exceptions:
- * 1. IllegalArgumentException when an invalid key is sent.
- * 2. RuntimeException if the key is required but not found; and also if there was an
- * internal exception.
+ * found, and the carrier does not require a key. The system will throw
+ * IllegalArgumentException when an invalid key is sent or when key is required but
+ * not found.
* @hide
*/
public ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int keyType) {
try {
IPhoneSubInfo info = getSubscriberInfo();
if (info == null) {
- throw new RuntimeException("IMSI error: Subscriber Info is null");
+ Rlog.e(TAG,"IMSI error: Subscriber Info is null");
+ return null;
}
int subId = getSubId(SubscriptionManager.getDefaultDataSubscriptionId());
if (keyType != KEY_TYPE_EPDG && keyType != KEY_TYPE_WLAN) {
@@ -2804,19 +2808,46 @@
}
ImsiEncryptionInfo imsiEncryptionInfo = info.getCarrierInfoForImsiEncryption(
subId, keyType, mContext.getOpPackageName());
- if (imsiEncryptionInfo == null
- && isImsiEncryptionRequired(subId, keyType)) {
+ if (imsiEncryptionInfo == null && isImsiEncryptionRequired(subId, keyType)) {
Rlog.e(TAG, "IMSI error: key is required but not found");
- throw new RuntimeException("IMSI error: key is required but not found");
+ throw new IllegalArgumentException("IMSI error: key is required but not found");
}
return imsiEncryptionInfo;
} catch (RemoteException ex) {
Rlog.e(TAG, "getCarrierInfoForImsiEncryption RemoteException" + ex);
- throw new RuntimeException("IMSI error: Remote Exception");
} catch (NullPointerException ex) {
// This could happen before phone restarts due to crashing
Rlog.e(TAG, "getCarrierInfoForImsiEncryption NullPointerException" + ex);
- throw new RuntimeException("IMSI error: Null Pointer exception");
+ }
+ return null;
+ }
+
+ /**
+ * Resets the Carrier Keys in the database. This involves 2 steps:
+ * 1. Delete the keys from the database.
+ * 2. Send an intent to download new Certificates.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ * @hide
+ */
+ public void resetCarrierKeysForImsiEncryption() {
+ try {
+ IPhoneSubInfo info = getSubscriberInfo();
+ if (info == null) {
+ Rlog.e(TAG, "IMSI error: Subscriber Info is null");
+ if (!isSystemProcess()) {
+ throw new RuntimeException("IMSI error: Subscriber Info is null");
+ }
+ return;
+ }
+ int subId = getSubId(SubscriptionManager.getDefaultDataSubscriptionId());
+ info.resetCarrierKeysForImsiEncryption(subId, mContext.getOpPackageName());
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "getCarrierInfoForImsiEncryption RemoteException" + ex);
+ if (!isSystemProcess()) {
+ ex.rethrowAsRuntimeException();
+ }
}
}
@@ -2855,7 +2886,7 @@
* device keystore.
* <p>
* Requires Permission:
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
* @param imsiEncryptionInfo which includes the Key Type, the Public Key
* (java.security.PublicKey) and the Key Identifier.and the Key Identifier.
* The keyIdentifier Attribute value pair that helps a server locate
@@ -3801,19 +3832,22 @@
*
* @throws SecurityException if the caller does not have carrier privileges or is not the
* current default dialer
- *
- * @throws IllegalStateException if telephony service is unavailable.
*/
public void sendDialerSpecialCode(String inputCode) {
try {
final ITelephony telephony = getITelephony();
+ if (telephony == null) {
+ if (!isSystemProcess()) {
+ throw new RuntimeException("Telephony service unavailable");
+ }
+ return;
+ }
telephony.sendDialerSpecialCode(mContext.getOpPackageName(), inputCode);
} catch (RemoteException ex) {
// This could happen if binder process crashes.
- ex.rethrowFromSystemServer();
- } catch (NullPointerException ex) {
- // This could happen before phone restarts due to crashing
- throw new IllegalStateException("Telephony service unavailable");
+ if (!isSystemProcess()) {
+ ex.rethrowAsRuntimeException();
+ }
}
}
@@ -4965,10 +4999,10 @@
String v = android.provider.Settings.Global.getString(cr, name);
if (index == Integer.MAX_VALUE) {
- throw new RuntimeException("putIntAtIndex index == MAX_VALUE index=" + index);
+ throw new IllegalArgumentException("putIntAtIndex index == MAX_VALUE index=" + index);
}
if (index < 0) {
- throw new RuntimeException("putIntAtIndex index < 0 index=" + index);
+ throw new IllegalArgumentException("putIntAtIndex index < 0 index=" + index);
}
if (v != null) {
valArray = v.split(",");
@@ -7236,7 +7270,6 @@
}
} catch (RemoteException ex) {
// This could happen if binder process crashes.
- ex.rethrowAsRuntimeException();
}
return UNKNOWN_CARRIER_ID;
}
@@ -7261,7 +7294,6 @@
}
} catch (RemoteException ex) {
// This could happen if binder process crashes.
- ex.rethrowAsRuntimeException();
}
return null;
}
@@ -7719,7 +7751,9 @@
}
} catch (RemoteException ex) {
// This could happen if binder process crashes.
- ex.rethrowAsRuntimeException();
+ if (!isSystemProcess()) {
+ ex.rethrowAsRuntimeException();
+ }
}
}
}
diff --git a/telephony/java/android/telephony/euicc/DownloadableSubscription.java b/telephony/java/android/telephony/euicc/DownloadableSubscription.java
index 88db22b..edf3b08 100644
--- a/telephony/java/android/telephony/euicc/DownloadableSubscription.java
+++ b/telephony/java/android/telephony/euicc/DownloadableSubscription.java
@@ -17,6 +17,7 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
+import android.app.PendingIntent;
import android.os.Parcel;
import android.os.Parcelable;
import android.telephony.UiccAccessRule;
@@ -26,7 +27,14 @@
import com.android.internal.util.Preconditions;
-/** Information about a subscription which is available for download. */
+/**
+ * Information about a subscription which is downloadable to an eUICC using
+ * {@link EuiccManager#downloadSubscription(DownloadableSubscription, boolean, PendingIntent).
+ *
+ * <p>For example, a DownloadableSubscription can be created through an activation code parsed from
+ * a QR code. A server address can be parsed from the activation code to download more information
+ * about the profile, such as carrier name, access rules, etc.
+ */
public final class DownloadableSubscription implements Parcelable {
public static final Creator<DownloadableSubscription> CREATOR =
@@ -136,7 +144,15 @@
/**
* Create a DownloadableSubscription for the given activation code.
*
- * @param encodedActivationCode the activation code to use. Must not be null.
+ * <p>This fills the encodedActivationCode field. Other fields like confirmationCode,
+ * carrierName and accessRules may be filled in the implementation of
+ * {@code android.service.euicc.EuiccService} if exists.
+ *
+ * @param encodedActivationCode the activation code to use. An activation code can be parsed
+ * from a user scanned QR code. The format of activation code is defined in SGP.22. For
+ * example, "1$SMDP.GSMA.COM$04386-AGYFT-A74Y8-3F815$1.3.6.1.4.1.31746". For detail, see
+ * {@code com.android.euicc.data.ActivationCode}. Must not be null.
+ *
* @return the {@link DownloadableSubscription} which may be passed to
* {@link EuiccManager#downloadSubscription}.
*/
@@ -157,6 +173,9 @@
/**
* Returns the confirmation code.
+ *
+ * <p>As an example, the confirmation code can be input by the user through a carrier app or the
+ * UI component of the eUICC local profile assistant (LPA) application.
*/
@Nullable
public String getConfirmationCode() {
diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java
index 8279123..d6f94da 100644
--- a/telephony/java/android/telephony/euicc/EuiccManager.java
+++ b/telephony/java/android/telephony/euicc/EuiccManager.java
@@ -142,11 +142,9 @@
"android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DETAILED_CODE";
/**
- * Key for an extra set on {@link #getDownloadableSubscriptionMetadata} PendingIntent result
+ * Key for an extra set on {@code #getDownloadableSubscriptionMetadata} PendingIntent result
* callbacks providing the downloadable subscription metadata.
- * @hide
*/
- @SystemApi
public static final String EXTRA_EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION =
"android.telephony.euicc.extra.EMBEDDED_SUBSCRIPTION_DOWNLOADABLE_SUBSCRIPTION";
diff --git a/telephony/java/android/telephony/mbms/InternalDownloadSessionCallback.java b/telephony/java/android/telephony/mbms/InternalDownloadSessionCallback.java
index c2a79d8..2916f81 100644
--- a/telephony/java/android/telephony/mbms/InternalDownloadSessionCallback.java
+++ b/telephony/java/android/telephony/mbms/InternalDownloadSessionCallback.java
@@ -17,7 +17,6 @@
package android.telephony.mbms;
import android.os.Binder;
-import android.os.RemoteException;
import java.util.List;
import java.util.concurrent.Executor;
@@ -36,7 +35,7 @@
}
@Override
- public void onError(final int errorCode, final String message) throws RemoteException {
+ public void onError(final int errorCode, final String message) {
if (mIsStopped) {
return;
}
@@ -55,7 +54,7 @@
}
@Override
- public void onFileServicesUpdated(final List<FileServiceInfo> services) throws RemoteException {
+ public void onFileServicesUpdated(final List<FileServiceInfo> services) {
if (mIsStopped) {
return;
}
@@ -74,7 +73,7 @@
}
@Override
- public void onMiddlewareReady() throws RemoteException {
+ public void onMiddlewareReady() {
if (mIsStopped) {
return;
}
diff --git a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
index b0c00c6..dd1061f 100644
--- a/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
+++ b/telephony/java/android/telephony/mbms/MbmsDownloadReceiver.java
@@ -31,6 +31,8 @@
import android.telephony.mbms.vendor.VendorUtils;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
@@ -268,7 +270,10 @@
Uri finalLocation;
try {
- finalLocation = moveToFinalLocation(finalTempFile, appSpecifiedDestination);
+ String relativeLocation = getFileRelativePath(request.getSourceUri().getPath(),
+ completedFileInfo.getUri().getPath());
+ finalLocation = moveToFinalLocation(finalTempFile, appSpecifiedDestination,
+ relativeLocation);
} catch (IOException e) {
Log.w(LOG_TAG, "Failed to move temp file to final destination");
setResultCode(RESULT_DOWNLOAD_FINALIZATION_ERROR);
@@ -297,7 +302,9 @@
for (Uri tempFileUri : tempFiles) {
if (verifyTempFilePath(context, request.getFileServiceId(), tempFileUri)) {
File tempFile = new File(tempFileUri.getSchemeSpecificPart());
- tempFile.delete();
+ if (!tempFile.delete()) {
+ Log.w(LOG_TAG, "Failed to delete temp file at " + tempFile.getPath());
+ }
}
}
}
@@ -440,7 +447,8 @@
/*
* Moves a tempfile located at fromPath to its final home where the app wants it
*/
- private static Uri moveToFinalLocation(Uri fromPath, Path appSpecifiedPath) throws IOException {
+ private static Uri moveToFinalLocation(Uri fromPath, Path appSpecifiedPath,
+ String relativeLocation) throws IOException {
if (!ContentResolver.SCHEME_FILE.equals(fromPath.getScheme())) {
Log.w(LOG_TAG, "Downloaded file location uri " + fromPath +
" does not have a file scheme");
@@ -448,16 +456,46 @@
}
Path fromFile = FileSystems.getDefault().getPath(fromPath.getPath());
- if (!Files.isDirectory(appSpecifiedPath)) {
- Files.createDirectory(appSpecifiedPath);
+ Path toFile = appSpecifiedPath.resolve(relativeLocation);
+
+ if (!Files.isDirectory(toFile.getParent())) {
+ Files.createDirectories(toFile.getParent());
}
- // TODO: do we want to support directory trees within the download directory?
- Path result = Files.move(fromFile, appSpecifiedPath.resolve(fromFile.getFileName()),
+ Path result = Files.move(fromFile, toFile,
StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
return Uri.fromFile(result.toFile());
}
+ /**
+ * @hide
+ */
+ @VisibleForTesting
+ public static String getFileRelativePath(String sourceUriPath, String fileInfoPath) {
+ if (sourceUriPath.endsWith("*")) {
+ // This is a wildcard path. Strip the last path component and use that as the root of
+ // the relative path.
+ int lastSlash = sourceUriPath.lastIndexOf('/');
+ sourceUriPath = sourceUriPath.substring(0, lastSlash);
+ }
+ if (!fileInfoPath.startsWith(sourceUriPath)) {
+ Log.e(LOG_TAG, "File location specified in FileInfo does not match the source URI."
+ + " source: " + sourceUriPath + " fileinfo path: " + fileInfoPath);
+ return null;
+ }
+ if (fileInfoPath.length() == sourceUriPath.length()) {
+ // This is the single-file download case. Return the name of the file so that the
+ // receiver puts the file directly into the dest directory.
+ return sourceUriPath.substring(sourceUriPath.lastIndexOf('/') + 1);
+ }
+
+ String prefixOmittedPath = fileInfoPath.substring(sourceUriPath.length());
+ if (prefixOmittedPath.startsWith("/")) {
+ prefixOmittedPath = prefixOmittedPath.substring(1);
+ }
+ return prefixOmittedPath;
+ }
+
private static boolean verifyTempFilePath(Context context, String serviceId,
Uri filePath) {
if (!ContentResolver.SCHEME_FILE.equals(filePath.getScheme())) {
@@ -474,6 +512,8 @@
if (!MbmsUtils.isContainedIn(
MbmsUtils.getEmbmsTempFileDirForService(context, serviceId), tempFile)) {
+ Log.w(LOG_TAG, "File at " + path + " is not contained in the temp file root," +
+ " which is " + MbmsUtils.getEmbmsTempFileDirForService(context, serviceId));
return false;
}
diff --git a/telephony/java/android/telephony/mbms/MbmsDownloadSessionCallback.java b/telephony/java/android/telephony/mbms/MbmsDownloadSessionCallback.java
index 77dea6f..5003b57 100644
--- a/telephony/java/android/telephony/mbms/MbmsDownloadSessionCallback.java
+++ b/telephony/java/android/telephony/mbms/MbmsDownloadSessionCallback.java
@@ -16,8 +16,11 @@
package android.telephony.mbms;
+import android.annotation.IntDef;
import android.telephony.MbmsDownloadSession;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.List;
/**
@@ -25,6 +28,26 @@
* cell-broadcast.
*/
public class MbmsDownloadSessionCallback {
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ MbmsErrors.ERROR_NO_UNIQUE_MIDDLEWARE,
+ MbmsErrors.ERROR_MIDDLEWARE_LOST,
+ MbmsErrors.ERROR_MIDDLEWARE_NOT_BOUND,
+ MbmsErrors.InitializationErrors.ERROR_APP_PERMISSIONS_NOT_GRANTED,
+ MbmsErrors.InitializationErrors.ERROR_DUPLICATE_INITIALIZE,
+ MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
+ MbmsErrors.GeneralErrors.ERROR_MIDDLEWARE_NOT_YET_READY,
+ MbmsErrors.GeneralErrors.ERROR_OUT_OF_MEMORY,
+ MbmsErrors.GeneralErrors.ERROR_MIDDLEWARE_TEMPORARILY_UNAVAILABLE,
+ MbmsErrors.GeneralErrors.ERROR_IN_E911,
+ MbmsErrors.GeneralErrors.ERROR_NOT_CONNECTED_TO_HOME_CARRIER_LTE,
+ MbmsErrors.GeneralErrors.ERROR_UNABLE_TO_READ_SIM,
+ MbmsErrors.GeneralErrors.ERROR_CARRIER_CHANGE_NOT_ALLOWED,
+ MbmsErrors.DownloadErrors.ERROR_CANNOT_CHANGE_TEMP_FILE_ROOT,
+ MbmsErrors.DownloadErrors.ERROR_UNKNOWN_DOWNLOAD_REQUEST,
+ MbmsErrors.DownloadErrors.ERROR_UNKNOWN_FILE_INFO}, prefix = { "ERROR_" })
+ private @interface DownloadError{}
/**
* Indicates that the middleware has encountered an asynchronous error.
@@ -32,7 +55,7 @@
* @param message A message, intended for debugging purposes, describing the error in further
* detail.
*/
- public void onError(int errorCode, String message) {
+ public void onError(@DownloadError int errorCode, String message) {
// default implementation empty
}
diff --git a/telephony/java/android/telephony/mbms/MbmsErrors.java b/telephony/java/android/telephony/mbms/MbmsErrors.java
index b5fec44..7c4321b 100644
--- a/telephony/java/android/telephony/mbms/MbmsErrors.java
+++ b/telephony/java/android/telephony/mbms/MbmsErrors.java
@@ -19,6 +19,13 @@
import android.telephony.MbmsStreamingSession;
public class MbmsErrors {
+ /**
+ * Indicates that the middleware has sent an error code that is not defined in the version of
+ * the SDK targeted by your app. This is an illegal value for the middleware to return -- it
+ * should only ever be generated by the framework.
+ */
+ public static final int UNKNOWN = -1;
+
/** Indicates that the operation was successful. */
public static final int SUCCESS = 0;
diff --git a/telephony/java/android/telephony/mbms/MbmsStreamingSessionCallback.java b/telephony/java/android/telephony/mbms/MbmsStreamingSessionCallback.java
index 6e03957..1bdb20bf 100644
--- a/telephony/java/android/telephony/mbms/MbmsStreamingSessionCallback.java
+++ b/telephony/java/android/telephony/mbms/MbmsStreamingSessionCallback.java
@@ -16,11 +16,13 @@
package android.telephony.mbms;
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.content.Context;
-import android.os.Handler;
import android.telephony.MbmsStreamingSession;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.List;
import java.util.concurrent.Executor;
@@ -30,13 +32,34 @@
* {@link MbmsStreamingSession#create(Context, Executor, int, MbmsStreamingSessionCallback)}.
*/
public class MbmsStreamingSessionCallback {
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ MbmsErrors.ERROR_NO_UNIQUE_MIDDLEWARE,
+ MbmsErrors.ERROR_MIDDLEWARE_LOST,
+ MbmsErrors.ERROR_MIDDLEWARE_NOT_BOUND,
+ MbmsErrors.InitializationErrors.ERROR_APP_PERMISSIONS_NOT_GRANTED,
+ MbmsErrors.InitializationErrors.ERROR_DUPLICATE_INITIALIZE,
+ MbmsErrors.InitializationErrors.ERROR_UNABLE_TO_INITIALIZE,
+ MbmsErrors.GeneralErrors.ERROR_MIDDLEWARE_NOT_YET_READY,
+ MbmsErrors.GeneralErrors.ERROR_OUT_OF_MEMORY,
+ MbmsErrors.GeneralErrors.ERROR_MIDDLEWARE_TEMPORARILY_UNAVAILABLE,
+ MbmsErrors.GeneralErrors.ERROR_IN_E911,
+ MbmsErrors.GeneralErrors.ERROR_NOT_CONNECTED_TO_HOME_CARRIER_LTE,
+ MbmsErrors.GeneralErrors.ERROR_UNABLE_TO_READ_SIM,
+ MbmsErrors.GeneralErrors.ERROR_CARRIER_CHANGE_NOT_ALLOWED,
+ MbmsErrors.StreamingErrors.ERROR_CONCURRENT_SERVICE_LIMIT_REACHED,
+ MbmsErrors.StreamingErrors.ERROR_UNABLE_TO_START_SERVICE,
+ MbmsErrors.StreamingErrors.ERROR_DUPLICATE_START_STREAM}, prefix = { "ERROR_" })
+ private @interface StreamingError{}
+
/**
* Called by the middleware when it has detected an error condition. The possible error codes
* are listed in {@link MbmsErrors}.
* @param errorCode The error code.
* @param message A human-readable message generated by the middleware for debugging purposes.
*/
- public void onError(int errorCode, @Nullable String message) {
+ public void onError(@StreamingError int errorCode, @Nullable String message) {
// default implementation empty
}
diff --git a/telephony/java/android/telephony/mbms/MbmsUtils.java b/telephony/java/android/telephony/mbms/MbmsUtils.java
index ef317ee..06b2120 100644
--- a/telephony/java/android/telephony/mbms/MbmsUtils.java
+++ b/telephony/java/android/telephony/mbms/MbmsUtils.java
@@ -130,8 +130,12 @@
* Returns a File linked to the directory used to store temp files for this file service
*/
public static File getEmbmsTempFileDirForService(Context context, String serviceId) {
+ // Replace all non-alphanumerics/underscores with an underscore. Some filesystems don't
+ // like special characters.
+ String sanitizedServiceId = serviceId.replaceAll("[^a-zA-Z0-9_]", "_");
+
File embmsTempFileDir = MbmsTempFileProvider.getEmbmsTempFileDir(context);
- return new File(embmsTempFileDir, serviceId);
+ return new File(embmsTempFileDir, sanitizedServiceId);
}
}
diff --git a/telephony/java/android/telephony/mbms/StreamingServiceCallback.java b/telephony/java/android/telephony/mbms/StreamingServiceCallback.java
index 0903824..c265db6 100644
--- a/telephony/java/android/telephony/mbms/StreamingServiceCallback.java
+++ b/telephony/java/android/telephony/mbms/StreamingServiceCallback.java
@@ -16,13 +16,34 @@
package android.telephony.mbms;
+import android.annotation.IntDef;
import android.annotation.Nullable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* A callback class for use when the application is actively streaming content. The middleware
* will provide updates on the status of the stream via this callback.
*/
public class StreamingServiceCallback {
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(value = {
+ MbmsErrors.ERROR_NO_UNIQUE_MIDDLEWARE,
+ MbmsErrors.ERROR_MIDDLEWARE_LOST,
+ MbmsErrors.ERROR_MIDDLEWARE_NOT_BOUND,
+ MbmsErrors.GeneralErrors.ERROR_MIDDLEWARE_NOT_YET_READY,
+ MbmsErrors.GeneralErrors.ERROR_OUT_OF_MEMORY,
+ MbmsErrors.GeneralErrors.ERROR_MIDDLEWARE_TEMPORARILY_UNAVAILABLE,
+ MbmsErrors.GeneralErrors.ERROR_IN_E911,
+ MbmsErrors.GeneralErrors.ERROR_NOT_CONNECTED_TO_HOME_CARRIER_LTE,
+ MbmsErrors.GeneralErrors.ERROR_UNABLE_TO_READ_SIM,
+ MbmsErrors.GeneralErrors.ERROR_CARRIER_CHANGE_NOT_ALLOWED,
+ MbmsErrors.StreamingErrors.ERROR_CONCURRENT_SERVICE_LIMIT_REACHED,
+ MbmsErrors.StreamingErrors.ERROR_UNABLE_TO_START_SERVICE,
+ MbmsErrors.StreamingErrors.ERROR_DUPLICATE_START_STREAM}, prefix = { "ERROR_" })
+ private @interface StreamingServiceError{}
/**
* Indicates broadcast signal strength is not available for this service.
@@ -39,7 +60,7 @@
* @param errorCode The error code.
* @param message A human-readable message generated by the middleware for debugging purposes.
*/
- public void onError(int errorCode, @Nullable String message) {
+ public void onError(@StreamingServiceError int errorCode, @Nullable String message) {
// default implementation empty
}
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
index f9d7161..a9f10b1 100644
--- a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
@@ -130,6 +130,10 @@
@Override
public void onError(int errorCode, String message) {
try {
+ if (errorCode == MbmsErrors.UNKNOWN) {
+ throw new IllegalArgumentException(
+ "Middleware cannot send an unknown error.");
+ }
callback.onError(errorCode, message);
} catch (RemoteException e) {
onAppCallbackDied(uid, subscriptionId);
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
index db177c0..5ce612d 100644
--- a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
@@ -77,6 +77,10 @@
@Override
public void onError(final int errorCode, final String message) {
try {
+ if (errorCode == MbmsErrors.UNKNOWN) {
+ throw new IllegalArgumentException(
+ "Middleware cannot send an unknown error.");
+ }
callback.onError(errorCode, message);
} catch (RemoteException e) {
onAppCallbackDied(uid, subscriptionId);
@@ -173,6 +177,10 @@
@Override
public void onError(final int errorCode, final String message) {
try {
+ if (errorCode == MbmsErrors.UNKNOWN) {
+ throw new IllegalArgumentException(
+ "Middleware cannot send an unknown error.");
+ }
callback.onError(errorCode, message);
} catch (RemoteException e) {
onAppCallbackDied(uid, subscriptionId);
diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index 303a068..0ed0820 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -152,6 +152,13 @@
in ImsiEncryptionInfo imsiEncryptionInfo);
/**
+ * Resets the Carrier Keys in the database. This involves 2 steps:
+ * 1. Delete the keys from the database.
+ * 2. Send an intent to download new Certificates.
+ */
+ void resetCarrierKeysForImsiEncryption(int subId, String callingPackage);
+
+ /**
* Retrieves the alpha identifier associated with the voice mail number.
*/
String getVoiceMailAlphaTag(String callingPackage);
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index f29d993c..51369d0 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -486,4 +486,10 @@
*/
public static final String ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE =
"com.android.omadm.service.CONFIGURATION_UPDATE";
+
+ /**
+ * Broadcast action to trigger the Carrier Certificate download.
+ */
+ public static final String ACTION_CARRIER_CERTIFICATE_DOWNLOAD =
+ "com.android.internal.telephony.ACTION_CARRIER_CERTIFICATE_DOWNLOAD";
}
diff --git a/tests/net/java/android/net/IpSecAlgorithmTest.java b/tests/net/java/android/net/IpSecAlgorithmTest.java
index 6bdfdc6..85e8361 100644
--- a/tests/net/java/android/net/IpSecAlgorithmTest.java
+++ b/tests/net/java/android/net/IpSecAlgorithmTest.java
@@ -22,8 +22,12 @@
import android.os.Parcel;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+
+import java.util.AbstractMap.SimpleEntry;
import java.util.Arrays;
+import java.util.Map.Entry;
import java.util.Random;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -40,19 +44,29 @@
};
@Test
- public void testDefaultTruncLen() throws Exception {
- IpSecAlgorithm explicit =
+ public void testNoTruncLen() throws Exception {
+ Entry<String, Integer>[] authAndAeadList =
+ new Entry[] {
+ new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_MD5, 128),
+ new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA1, 160),
+ new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA256, 256),
+ new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA384, 384),
+ new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA512, 512),
+ new SimpleEntry<>(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, 224)
+ };
+
+ // Expect auth and aead algorithms to throw errors if trunclen is omitted.
+ for (Entry<String, Integer> algData : authAndAeadList) {
+ try {
new IpSecAlgorithm(
- IpSecAlgorithm.AUTH_HMAC_SHA256, Arrays.copyOf(KEY_MATERIAL, 256 / 8), 256);
- IpSecAlgorithm implicit =
- new IpSecAlgorithm(
- IpSecAlgorithm.AUTH_HMAC_SHA256, Arrays.copyOf(KEY_MATERIAL, 256 / 8));
- assertTrue(
- "Default Truncation Length Incorrect, Explicit: "
- + explicit
- + "implicit: "
- + implicit,
- IpSecAlgorithm.equals(explicit, implicit));
+ algData.getKey(), Arrays.copyOf(KEY_MATERIAL, algData.getValue() / 8));
+ fail("Expected exception on unprovided auth trunclen");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ // Ensure crypt works with no truncation length supplied.
+ new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, Arrays.copyOf(KEY_MATERIAL, 256 / 8));
}
@Test
diff --git a/tests/net/java/android/net/IpSecConfigTest.java b/tests/net/java/android/net/IpSecConfigTest.java
index f186ee5..771faaf 100644
--- a/tests/net/java/android/net/IpSecConfigTest.java
+++ b/tests/net/java/android/net/IpSecConfigTest.java
@@ -62,7 +62,8 @@
c.setAuthentication(
new IpSecAlgorithm(
IpSecAlgorithm.AUTH_HMAC_MD5,
- new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0}));
+ new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0},
+ 128));
c.setAuthenticatedEncryption(
new IpSecAlgorithm(
IpSecAlgorithm.AUTH_CRYPT_AES_GCM,
diff --git a/tests/net/java/android/net/IpSecManagerTest.java b/tests/net/java/android/net/IpSecManagerTest.java
index 0ca20de..9191bd3 100644
--- a/tests/net/java/android/net/IpSecManagerTest.java
+++ b/tests/net/java/android/net/IpSecManagerTest.java
@@ -37,6 +37,7 @@
import com.android.server.IpSecService;
import java.net.InetAddress;
+import java.net.Socket;
import java.net.UnknownHostException;
import org.junit.Before;
@@ -179,7 +180,7 @@
IpSecManager.UdpEncapsulationSocket encapSocket =
mIpSecManager.openUdpEncapsulationSocket(TEST_UDP_ENCAP_PORT);
- assertNotNull(encapSocket.getSocket());
+ assertNotNull(encapSocket.getFileDescriptor());
assertEquals(TEST_UDP_ENCAP_PORT, encapSocket.getPort());
encapSocket.close();
@@ -188,6 +189,33 @@
}
@Test
+ public void testApplyTransportModeTransformEnsuresSocketCreation() throws Exception {
+ Socket socket = new Socket();
+ IpSecConfig dummyConfig = new IpSecConfig();
+ IpSecTransform dummyTransform = new IpSecTransform(null, dummyConfig);
+
+ // Even if underlying SocketImpl is not initalized, this should force the init, and
+ // thereby succeed.
+ mIpSecManager.applyTransportModeTransform(
+ socket, IpSecManager.DIRECTION_IN, dummyTransform);
+
+ // Check to make sure the FileDescriptor is non-null
+ assertNotNull(socket.getFileDescriptor$());
+ }
+
+ @Test
+ public void testRemoveTransportModeTransformsForcesSocketCreation() throws Exception {
+ Socket socket = new Socket();
+
+ // Even if underlying SocketImpl is not initalized, this should force the init, and
+ // thereby succeed.
+ mIpSecManager.removeTransportModeTransforms(socket);
+
+ // Check to make sure the FileDescriptor is non-null
+ assertNotNull(socket.getFileDescriptor$());
+ }
+
+ @Test
public void testOpenEncapsulationSocketOnRandomPort() throws Exception {
IpSecUdpEncapResponse udpEncapResp =
new IpSecUdpEncapResponse(
@@ -202,7 +230,7 @@
IpSecManager.UdpEncapsulationSocket encapSocket =
mIpSecManager.openUdpEncapsulationSocket();
- assertNotNull(encapSocket.getSocket());
+ assertNotNull(encapSocket.getFileDescriptor());
assertEquals(TEST_UDP_ENCAP_PORT, encapSocket.getPort());
encapSocket.close();
diff --git a/tests/net/java/android/net/NetworkCapabilitiesTest.java b/tests/net/java/android/net/NetworkCapabilitiesTest.java
index 69edc0c..0696592 100644
--- a/tests/net/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/java/android/net/NetworkCapabilitiesTest.java
@@ -273,14 +273,28 @@
@Test
public void testOemPaid() {
NetworkCapabilities nc = new NetworkCapabilities();
- nc.maybeMarkCapabilitiesRestricted();
+ // By default OEM_PAID is neither in the unwanted or required lists and the network is not
+ // restricted.
+ assertFalse(nc.hasUnwantedCapability(NET_CAPABILITY_OEM_PAID));
assertFalse(nc.hasCapability(NET_CAPABILITY_OEM_PAID));
+ nc.maybeMarkCapabilitiesRestricted();
assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+ // Adding OEM_PAID to capability list should make network restricted.
nc.addCapability(NET_CAPABILITY_OEM_PAID);
+ nc.addCapability(NET_CAPABILITY_INTERNET); // Combine with unrestricted capability.
nc.maybeMarkCapabilitiesRestricted();
assertTrue(nc.hasCapability(NET_CAPABILITY_OEM_PAID));
assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+
+ // Now let's make request for OEM_PAID network.
+ NetworkCapabilities nr = new NetworkCapabilities();
+ nr.addCapability(NET_CAPABILITY_OEM_PAID);
+ nr.maybeMarkCapabilitiesRestricted();
+ assertTrue(nr.satisfiedByNetworkCapabilities(nc));
+
+ // Request fails for network with the default capabilities.
+ assertFalse(nr.satisfiedByNetworkCapabilities(new NetworkCapabilities()));
}
@Test
@@ -295,7 +309,8 @@
request.addUnwantedCapability(NET_CAPABILITY_WIFI_P2P);
request.addUnwantedCapability(NET_CAPABILITY_NOT_METERED);
assertTrue(request.satisfiedByNetworkCapabilities(network));
- assertArrayEquals(new int[] {NET_CAPABILITY_WIFI_P2P, NET_CAPABILITY_NOT_METERED},
+ assertArrayEquals(new int[] {NET_CAPABILITY_WIFI_P2P,
+ NET_CAPABILITY_NOT_METERED},
request.getUnwantedCapabilities());
// This is a default capability, just want to make sure its there because we use it below.
diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java
index 0530a86..8f18d07 100644
--- a/tests/net/java/android/net/NetworkStatsTest.java
+++ b/tests/net/java/android/net/NetworkStatsTest.java
@@ -39,8 +39,10 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.os.Process;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.filters.SmallTest;
+import android.util.ArrayMap;
import com.google.android.collect.Sets;
@@ -773,6 +775,88 @@
assertEquals(entry2, stats.getValues(1, null));
}
+ @Test
+ public void testApply464xlatAdjustments() {
+ final String v4Iface = "v4-wlan0";
+ final String baseIface = "wlan0";
+ final String otherIface = "other";
+ final int appUid = 10001;
+ final int rootUid = Process.ROOT_UID;
+ ArrayMap<String, String> stackedIface = new ArrayMap<>();
+ stackedIface.put(v4Iface, baseIface);
+
+ NetworkStats.Entry otherEntry = new NetworkStats.Entry(
+ otherIface, appUid, SET_DEFAULT, TAG_NONE,
+ 2600 /* rxBytes */,
+ 2 /* rxPackets */,
+ 3800 /* txBytes */,
+ 3 /* txPackets */,
+ 0 /* operations */);
+
+ NetworkStats stats = new NetworkStats(TEST_START, 3)
+ .addValues(v4Iface, appUid, SET_DEFAULT, TAG_NONE,
+ 30501490 /* rxBytes */,
+ 22401 /* rxPackets */,
+ 876235 /* txBytes */,
+ 13805 /* txPackets */,
+ 0 /* operations */)
+ .addValues(baseIface, rootUid, SET_DEFAULT, TAG_NONE,
+ 31113087,
+ 22588,
+ 1169942,
+ 13902,
+ 0)
+ .addValues(otherEntry);
+
+ stats.apply464xlatAdjustments(stackedIface);
+
+ assertEquals(3, stats.size());
+ assertValues(stats, 0, v4Iface, appUid, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO,
+ 30949510,
+ 22401,
+ 1152335,
+ 13805,
+ 0);
+ assertValues(stats, 1, baseIface, 0, SET_DEFAULT, TAG_NONE,
+ METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO,
+ 163577,
+ 187,
+ 17607,
+ 97,
+ 0);
+ assertEquals(otherEntry, stats.getValues(2, null));
+ }
+
+ @Test
+ public void testApply464xlatAdjustments_noStackedIface() {
+ NetworkStats.Entry firstEntry = new NetworkStats.Entry(
+ "if1", 10002, SET_DEFAULT, TAG_NONE,
+ 2600 /* rxBytes */,
+ 2 /* rxPackets */,
+ 3800 /* txBytes */,
+ 3 /* txPackets */,
+ 0 /* operations */);
+ NetworkStats.Entry secondEntry = new NetworkStats.Entry(
+ "if2", 10002, SET_DEFAULT, TAG_NONE,
+ 5000 /* rxBytes */,
+ 3 /* rxPackets */,
+ 6000 /* txBytes */,
+ 4 /* txPackets */,
+ 0 /* operations */);
+
+ NetworkStats stats = new NetworkStats(TEST_START, 2)
+ .addValues(firstEntry)
+ .addValues(secondEntry);
+
+ // Empty map: no adjustment
+ stats.apply464xlatAdjustments(new ArrayMap<>());
+
+ assertEquals(2, stats.size());
+ assertEquals(firstEntry, stats.getValues(0, null));
+ assertEquals(secondEntry, stats.getValues(1, null));
+ }
+
private static void assertContains(NetworkStats stats, String iface, int uid, int set,
int tag, int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets,
long txBytes, long txPackets, long operations) {
diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java
index 9b75a50..fef702e 100644
--- a/tests/net/java/android/net/apf/ApfTest.java
+++ b/tests/net/java/android/net/apf/ApfTest.java
@@ -16,6 +16,7 @@
package android.net.apf;
+import static android.net.util.NetworkConstants.*;
import static android.system.OsConstants.*;
import static com.android.internal.util.BitUtils.bytesToBEInt;
import static com.android.internal.util.BitUtils.put;
@@ -26,6 +27,7 @@
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.verify;
+import android.content.Context;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkUtils;
@@ -82,6 +84,7 @@
private static final int TIMEOUT_MS = 500;
@Mock IpConnectivityLog mLog;
+ @Mock Context mContext;
@Before
public void setUp() throws Exception {
@@ -633,9 +636,9 @@
private FileDescriptor mWriteSocket;
private final long mFixedTimeMs = SystemClock.elapsedRealtime();
- public TestApfFilter(ApfConfiguration config, IpManager.Callback ipManagerCallback,
- IpConnectivityLog log) throws Exception {
- super(config, InterfaceParams.getByName("lo"), ipManagerCallback, log);
+ public TestApfFilter(Context context, ApfConfiguration config,
+ IpManager.Callback ipManagerCallback, IpConnectivityLog log) throws Exception {
+ super(context, config, InterfaceParams.getByName("lo"), ipManagerCallback, log);
}
// Pretend an RA packet has been received and show it to ApfFilter.
@@ -757,6 +760,17 @@
private static final byte[] ANOTHER_IPV4_ADDR = {10, 0, 0, 2};
private static final byte[] IPV4_ANY_HOST_ADDR = {0, 0, 0, 0};
+ // Helper to initialize a default apfFilter.
+ private ApfFilter setupApfFilter(IpManager.Callback ipManagerCallback, ApfConfiguration config)
+ throws Exception {
+ LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
+ LinkProperties lp = new LinkProperties();
+ lp.addLinkAddress(link);
+ TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
+ apfFilter.setLinkProperties(lp);
+ return apfFilter;
+ }
+
@Test
public void testApfFilterIPv4() throws Exception {
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
@@ -766,7 +780,7 @@
ApfConfiguration config = getDefaultConfig();
config.multicastFilter = DROP_MULTICAST;
- TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
+ TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
apfFilter.setLinkProperties(lp);
byte[] program = ipManagerCallback.getApfProgram();
@@ -818,7 +832,7 @@
public void testApfFilterIPv6() throws Exception {
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
ApfConfiguration config = getDefaultConfig();
- TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
+ TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
byte[] program = ipManagerCallback.getApfProgram();
// Verify empty IPv6 packet is passed
@@ -861,7 +875,7 @@
ApfConfiguration config = getDefaultConfig();
config.ieee802_3Filter = DROP_802_3_FRAMES;
- TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
+ TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
apfFilter.setLinkProperties(lp);
byte[] program = ipManagerCallback.getApfProgram();
@@ -925,7 +939,7 @@
apfFilter.shutdown();
config.multicastFilter = DROP_MULTICAST;
config.ieee802_3Filter = DROP_802_3_FRAMES;
- apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
+ apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
apfFilter.setLinkProperties(lp);
program = ipManagerCallback.getApfProgram();
assertDrop(program, mcastv4packet.array());
@@ -941,16 +955,47 @@
}
@Test
+ public void testApfFilterMulticastPingWhileDozing() throws Exception {
+ MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
+ ApfFilter apfFilter = setupApfFilter(ipManagerCallback, getDefaultConfig());
+
+ // Construct a multicast ICMPv6 ECHO request.
+ final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
+ ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
+ packet.putShort(ETH_ETHERTYPE_OFFSET, (short)ETH_P_IPV6);
+ packet.put(IPV6_NEXT_HEADER_OFFSET, (byte)IPPROTO_ICMPV6);
+ packet.put(ICMP6_TYPE_OFFSET, (byte)ICMPV6_ECHO_REQUEST_TYPE);
+ put(packet, IPV6_DEST_ADDR_OFFSET, multicastIpv6Addr);
+
+ // Normally, we let multicast pings alone...
+ assertPass(ipManagerCallback.getApfProgram(), packet.array());
+
+ // ...and even while dozing...
+ apfFilter.setDozeMode(true);
+ assertPass(ipManagerCallback.getApfProgram(), packet.array());
+
+ // ...but when the multicast filter is also enabled, drop the multicast pings to save power.
+ apfFilter.setMulticastFilter(true);
+ assertDrop(ipManagerCallback.getApfProgram(), packet.array());
+
+ // However, we should still let through all other ICMPv6 types.
+ ByteBuffer raPacket = ByteBuffer.wrap(packet.array().clone());
+ raPacket.put(ICMP6_TYPE_OFFSET, (byte)ICMPV6_ROUTER_ADVERTISEMENT);
+ assertPass(ipManagerCallback.getApfProgram(), raPacket.array());
+
+ // Now wake up from doze mode to ensure that we no longer drop the packets.
+ // (The multicast filter is still enabled at this point).
+ apfFilter.setDozeMode(false);
+ assertPass(ipManagerCallback.getApfProgram(), packet.array());
+
+ apfFilter.shutdown();
+ }
+
+ @Test
public void testApfFilter802_3() throws Exception {
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
- LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
- LinkProperties lp = new LinkProperties();
- lp.addLinkAddress(link);
-
ApfConfiguration config = getDefaultConfig();
- TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
- apfFilter.setLinkProperties(lp);
-
+ ApfFilter apfFilter = setupApfFilter(ipManagerCallback, config);
byte[] program = ipManagerCallback.getApfProgram();
// Verify empty packet of 100 zero bytes is passed
@@ -970,8 +1015,7 @@
ipManagerCallback.resetApfProgramWait();
apfFilter.shutdown();
config.ieee802_3Filter = DROP_802_3_FRAMES;
- apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
- apfFilter.setLinkProperties(lp);
+ apfFilter = setupApfFilter(ipManagerCallback, config);
program = ipManagerCallback.getApfProgram();
// Verify that IEEE802.3 frame is dropped
@@ -992,18 +1036,13 @@
@Test
public void testApfFilterEthTypeBL() throws Exception {
- MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
- LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
- LinkProperties lp = new LinkProperties();
- lp.addLinkAddress(link);
final int[] emptyBlackList = {};
final int[] ipv4BlackList = {ETH_P_IP};
final int[] ipv4Ipv6BlackList = {ETH_P_IP, ETH_P_IPV6};
+ MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
ApfConfiguration config = getDefaultConfig();
- TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
- apfFilter.setLinkProperties(lp);
-
+ ApfFilter apfFilter = setupApfFilter(ipManagerCallback, config);
byte[] program = ipManagerCallback.getApfProgram();
// Verify empty packet of 100 zero bytes is passed
@@ -1023,8 +1062,7 @@
ipManagerCallback.resetApfProgramWait();
apfFilter.shutdown();
config.ethTypeBlackList = ipv4BlackList;
- apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
- apfFilter.setLinkProperties(lp);
+ apfFilter = setupApfFilter(ipManagerCallback, config);
program = ipManagerCallback.getApfProgram();
// Verify that IPv4 frame will be dropped
@@ -1039,8 +1077,7 @@
ipManagerCallback.resetApfProgramWait();
apfFilter.shutdown();
config.ethTypeBlackList = ipv4Ipv6BlackList;
- apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
- apfFilter.setLinkProperties(lp);
+ apfFilter = setupApfFilter(ipManagerCallback, config);
program = ipManagerCallback.getApfProgram();
// Verify that IPv4 frame will be dropped
@@ -1081,7 +1118,7 @@
ApfConfiguration config = getDefaultConfig();
config.multicastFilter = DROP_MULTICAST;
config.ieee802_3Filter = DROP_802_3_FRAMES;
- TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
+ TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
// Verify initially ARP request filter is off, and GARP filter is on.
verifyArpFilter(ipManagerCallback.getApfProgram(), PASS);
@@ -1205,7 +1242,7 @@
ApfConfiguration config = getDefaultConfig();
config.multicastFilter = DROP_MULTICAST;
config.ieee802_3Filter = DROP_802_3_FRAMES;
- TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
+ TestApfFilter apfFilter = new TestApfFilter(mContext, config, ipManagerCallback, mLog);
byte[] program = ipManagerCallback.getApfProgram();
final int ROUTER_LIFETIME = 1000;
@@ -1351,7 +1388,7 @@
ApfConfiguration config = getDefaultConfig();
config.multicastFilter = DROP_MULTICAST;
config.ieee802_3Filter = DROP_802_3_FRAMES;
- TestApfFilter apfFilter = new TestApfFilter(config, cb, mLog);
+ TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
for (int i = 0; i < 1000; i++) {
byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
r.nextBytes(packet);
@@ -1372,7 +1409,7 @@
ApfConfiguration config = getDefaultConfig();
config.multicastFilter = DROP_MULTICAST;
config.ieee802_3Filter = DROP_802_3_FRAMES;
- TestApfFilter apfFilter = new TestApfFilter(config, cb, mLog);
+ TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
for (int i = 0; i < 1000; i++) {
byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
r.nextBytes(packet);
diff --git a/tests/net/java/android/net/util/InterfaceSetTest.java b/tests/net/java/android/net/util/InterfaceSetTest.java
new file mode 100644
index 0000000..8012838
--- /dev/null
+++ b/tests/net/java/android/net/util/InterfaceSetTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.util;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class InterfaceSetTest {
+ @Test
+ public void testNullNamesIgnored() {
+ final InterfaceSet set = new InterfaceSet(null, "if1", null, "if2", null);
+ assertEquals(2, set.ifnames.size());
+ assertTrue(set.ifnames.contains("if1"));
+ assertTrue(set.ifnames.contains("if2"));
+ }
+
+ @Test
+ public void testToString() {
+ final InterfaceSet set = new InterfaceSet("if1", "if2");
+ final String setString = set.toString();
+ assertTrue(setString.equals("[if1,if2]") || setString.equals("[if2,if1]"));
+ }
+
+ @Test
+ public void testToString_Empty() {
+ final InterfaceSet set = new InterfaceSet(null, null);
+ assertEquals("[]", set.toString());
+ }
+
+ @Test
+ public void testEquals() {
+ assertEquals(new InterfaceSet(null, "if1", "if2"), new InterfaceSet("if2", "if1"));
+ assertEquals(new InterfaceSet(null, null), new InterfaceSet());
+ assertFalse(new InterfaceSet("if1", "if3").equals(new InterfaceSet("if1", "if2")));
+ assertFalse(new InterfaceSet("if1", "if2").equals(new InterfaceSet("if1")));
+ assertFalse(new InterfaceSet().equals(null));
+ }
+}
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index c727bd2..8fb87f1 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -19,8 +19,14 @@
import static android.hardware.usb.UsbManager.USB_CONFIGURED;
import static android.hardware.usb.UsbManager.USB_CONNECTED;
import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
+import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
+import static android.net.ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY;
+import static android.net.ConnectivityManager.EXTRA_ACTIVE_TETHER;
+import static android.net.ConnectivityManager.EXTRA_AVAILABLE_TETHER;
+import static android.net.ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE;
import static android.net.ConnectivityManager.TETHERING_WIFI;
import static android.net.ConnectivityManager.TETHERING_USB;
+import static android.net.ConnectivityManager.TYPE_MOBILE;
import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY;
import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
@@ -29,7 +35,6 @@
import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.notNull;
@@ -55,7 +60,6 @@
import android.content.pm.ApplicationInfo;
import android.content.res.Resources;
import android.hardware.usb.UsbManager;
-import android.net.ConnectivityManager;
import android.net.INetd;
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
@@ -126,7 +130,6 @@
@Mock private ApplicationInfo mApplicationInfo;
@Mock private Context mContext;
- @Mock private ConnectivityManager mConnectivityManager;
@Mock private INetworkManagementService mNMService;
@Mock private INetworkStatsService mStatsService;
@Mock private INetworkPolicyManager mPolicyManager;
@@ -174,7 +177,6 @@
@Override
public Object getSystemService(String name) {
- if (Context.CONNECTIVITY_SERVICE.equals(name)) return mConnectivityManager;
if (Context.WIFI_SERVICE.equals(name)) return mWifiManager;
if (Context.USB_SERVICE.equals(name)) return mUsbManager;
return super.getSystemService(name);
@@ -182,8 +184,15 @@
}
public class MockTetheringDependencies extends TetheringDependencies {
- private StateMachine upstreamNetworkMonitorMasterSM;
- private ArrayList<TetherInterfaceStateMachine> ipv6CoordinatorNotifyList;
+ StateMachine upstreamNetworkMonitorMasterSM;
+ ArrayList<TetherInterfaceStateMachine> ipv6CoordinatorNotifyList;
+ int isTetheringSupportedCalls;
+
+ public void reset() {
+ upstreamNetworkMonitorMasterSM = null;
+ ipv6CoordinatorNotifyList = null;
+ isTetheringSupportedCalls = 0;
+ }
@Override
public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) {
@@ -223,10 +232,17 @@
return new InterfaceParams(ifName, index + IFINDEX_OFFSET,
MacAddress.ALL_ZEROS_ADDRESS);
}
+
+ @Override
+ public boolean isTetheringSupported() {
+ isTetheringSupportedCalls++;
+ return true;
+ }
}
- private static NetworkState buildMobileUpstreamState(boolean withIPv4, boolean withIPv6) {
- final NetworkInfo info = new NetworkInfo(ConnectivityManager.TYPE_MOBILE, 0, null, null);
+ private static NetworkState buildMobileUpstreamState(boolean withIPv4, boolean withIPv6,
+ boolean with464xlat) {
+ final NetworkInfo info = new NetworkInfo(TYPE_MOBILE, 0, null, null);
info.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(TEST_MOBILE_IFNAME);
@@ -245,6 +261,15 @@
NetworkUtils.numericToInetAddress("2001:db8::1"), TEST_MOBILE_IFNAME));
}
+ if (with464xlat) {
+ final LinkProperties stackedLink = new LinkProperties();
+ stackedLink.setInterfaceName(TEST_XLAT_MOBILE_IFNAME);
+ stackedLink.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0),
+ NetworkUtils.numericToInetAddress("192.0.0.1"), TEST_XLAT_MOBILE_IFNAME));
+
+ prop.addStackedLink(stackedLink);
+ }
+
final NetworkCapabilities capabilities = new NetworkCapabilities()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);;
@@ -252,11 +277,19 @@
}
private static NetworkState buildMobileIPv4UpstreamState() {
- return buildMobileUpstreamState(true, false);
+ return buildMobileUpstreamState(true, false, false);
+ }
+
+ private static NetworkState buildMobileIPv6UpstreamState() {
+ return buildMobileUpstreamState(false, true, false);
}
private static NetworkState buildMobileDualStackUpstreamState() {
- return buildMobileUpstreamState(true, true);
+ return buildMobileUpstreamState(true, true, false);
+ }
+
+ private static NetworkState buildMobile464xlatUpstreamState() {
+ return buildMobileUpstreamState(false, true, true);
}
@Before
@@ -291,7 +324,8 @@
}
};
mServiceContext.registerReceiver(mBroadcastReceiver,
- new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
+ new IntentFilter(ACTION_TETHER_STATE_CHANGED));
+ mTetheringDependencies.reset();
mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
mLooper.getLooper(), mSystemProperties,
mTetheringDependencies);
@@ -387,7 +421,7 @@
private void verifyTetheringBroadcast(String ifname, String whichExtra) {
// Verify that ifname is in the whichExtra array of the tether state changed broadcast.
final Intent bcast = mIntents.get(0);
- assertEquals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED, bcast.getAction());
+ assertEquals(ACTION_TETHER_STATE_CHANGED, bcast.getAction());
final ArrayList<String> ifnames = bcast.getStringArrayListExtra(whichExtra);
assertTrue(ifnames.contains(ifname));
mIntents.remove(bcast);
@@ -395,8 +429,6 @@
public void failingLocalOnlyHotspotLegacyApBroadcast(
boolean emulateInterfaceStatusChanged) throws Exception {
- when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
-
// Emulate externally-visible WifiManager effects, causing the
// per-interface state machine to start up, and telling us that
// hotspot mode is to be started.
@@ -410,16 +442,14 @@
// then it creates a TetherInterfaceStateMachine and sends out a
// broadcast indicating that the interface is "available".
if (emulateInterfaceStatusChanged) {
- verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
- verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+ assertEquals(1, mTetheringDependencies.isTetheringSupportedCalls);
+ verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
}
- verifyNoMoreInteractions(mConnectivityManager);
verifyNoMoreInteractions(mNMService);
verifyNoMoreInteractions(mWifiManager);
}
private void prepareUsbTethering(NetworkState upstreamState) {
- when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
.thenReturn(upstreamState);
@@ -437,7 +467,6 @@
prepareUsbTethering(upstreamState);
// This should produce no activity of any kind.
- verifyNoMoreInteractions(mConnectivityManager);
verifyNoMoreInteractions(mNMService);
// Pretend we then receive USB configured broadcast.
@@ -464,8 +493,6 @@
public void workingLocalOnlyHotspotEnrichedApBroadcast(
boolean emulateInterfaceStatusChanged) throws Exception {
- when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
-
// Emulate externally-visible WifiManager effects, causing the
// per-interface state machine to start up, and telling us that
// hotspot mode is to be started.
@@ -476,18 +503,17 @@
mLooper.dispatchAll();
verifyInterfaceServingModeStarted();
- verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+ verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
verify(mNMService, times(1)).setIpForwardingEnabled(true);
verify(mNMService, times(1)).startTethering(any(String[].class));
verifyNoMoreInteractions(mNMService);
verify(mWifiManager).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
verifyNoMoreInteractions(mWifiManager);
- verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY);
+ verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_LOCAL_ONLY);
verify(mUpstreamNetworkMonitor, times(1)).start();
// TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
- verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
- verifyNoMoreInteractions(mConnectivityManager);
+ assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls);
// Emulate externally-visible WifiManager effects, when hotspot mode
// is being torn down.
@@ -506,8 +532,7 @@
verifyNoMoreInteractions(mWifiManager);
// Asking for the last error after the per-interface state machine
// has been reaped yields an unknown interface error.
- assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
- mTethering.getLastTetherError(TEST_WLAN_IFNAME));
+ assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_WLAN_IFNAME));
}
/**
@@ -521,7 +546,7 @@
for (TetherInterfaceStateMachine tism :
mTetheringDependencies.ipv6CoordinatorNotifyList) {
- NetworkState ipv6OnlyState = buildMobileUpstreamState(false, true);
+ NetworkState ipv6OnlyState = buildMobileUpstreamState(false, true, false);
tism.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0,
upstreamState.linkProperties.isIPv6Provisioned()
? ipv6OnlyState.linkProperties
@@ -549,6 +574,19 @@
}
@Test
+ public void workingMobileUsbTethering_IPv6() throws Exception {
+ NetworkState upstreamState = buildMobileIPv6UpstreamState();
+ runUsbTethering(upstreamState);
+
+ verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+
+ sendIPv6TetherUpdates(upstreamState);
+ verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
+ verify(mNetd, times(1)).tetherApplyDnsInterfaces();
+ }
+
+ @Test
public void workingMobileUsbTethering_DualStack() throws Exception {
NetworkState upstreamState = buildMobileDualStackUpstreamState();
runUsbTethering(upstreamState);
@@ -562,6 +600,52 @@
verify(mNetd, times(1)).tetherApplyDnsInterfaces();
}
+ @Test
+ public void workingMobileUsbTethering_MultipleUpstreams() throws Exception {
+ NetworkState upstreamState = buildMobile464xlatUpstreamState();
+ runUsbTethering(upstreamState);
+
+ verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
+ verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME,
+ TEST_XLAT_MOBILE_IFNAME);
+
+ sendIPv6TetherUpdates(upstreamState);
+ verify(mRouterAdvertisementDaemon, times(1)).buildNewRa(any(), notNull());
+ verify(mNetd, times(1)).tetherApplyDnsInterfaces();
+ }
+
+ @Test
+ public void workingMobileUsbTethering_v6Then464xlat() throws Exception {
+ // Setup IPv6
+ NetworkState upstreamState = buildMobileIPv6UpstreamState();
+ runUsbTethering(upstreamState);
+
+ verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+
+ // Then 464xlat comes up
+ upstreamState = buildMobile464xlatUpstreamState();
+ when(mUpstreamNetworkMonitor.selectPreferredUpstreamType(any()))
+ .thenReturn(upstreamState);
+
+ // Upstream LinkProperties changed: UpstreamNetworkMonitor sends EVENT_ON_LINKPROPERTIES.
+ mTetheringDependencies.upstreamNetworkMonitorMasterSM.sendMessage(
+ Tethering.TetherMasterSM.EVENT_UPSTREAM_CALLBACK,
+ UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES,
+ 0,
+ upstreamState);
+ mLooper.dispatchAll();
+
+ // Forwarding is added for 464xlat
+ verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_XLAT_MOBILE_IFNAME);
+ verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME,
+ TEST_XLAT_MOBILE_IFNAME);
+ // Forwarding was not re-added for v6 (still times(1))
+ verify(mNMService, times(1)).enableNat(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ verify(mNMService, times(1)).startInterfaceForwarding(TEST_USB_IFNAME, TEST_MOBILE_IFNAME);
+ }
@Test
public void workingLocalOnlyHotspotEnrichedApBroadcastWithIfaceChanged() throws Exception {
@@ -576,7 +660,6 @@
// TODO: Test with and without interfaceStatusChanged().
@Test
public void failingWifiTetheringLegacyApBroadcast() throws Exception {
- when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
// Emulate pressing the WiFi tethering button.
@@ -584,7 +667,6 @@
mLooper.dispatchAll();
verify(mWifiManager, times(1)).startSoftAp(null);
verifyNoMoreInteractions(mWifiManager);
- verifyNoMoreInteractions(mConnectivityManager);
verifyNoMoreInteractions(mNMService);
// Emulate externally-visible WifiManager effects, causing the
@@ -594,9 +676,8 @@
sendWifiApStateChanged(WIFI_AP_STATE_ENABLED);
mLooper.dispatchAll();
- verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
- verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
- verifyNoMoreInteractions(mConnectivityManager);
+ assertEquals(1, mTetheringDependencies.isTetheringSupportedCalls);
+ verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
verifyNoMoreInteractions(mNMService);
verifyNoMoreInteractions(mWifiManager);
}
@@ -604,7 +685,6 @@
// TODO: Test with and without interfaceStatusChanged().
@Test
public void workingWifiTetheringEnrichedApBroadcast() throws Exception {
- when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
// Emulate pressing the WiFi tethering button.
@@ -612,7 +692,6 @@
mLooper.dispatchAll();
verify(mWifiManager, times(1)).startSoftAp(null);
verifyNoMoreInteractions(mWifiManager);
- verifyNoMoreInteractions(mConnectivityManager);
verifyNoMoreInteractions(mNMService);
// Emulate externally-visible WifiManager effects, causing the
@@ -623,21 +702,20 @@
mLooper.dispatchAll();
verifyInterfaceServingModeStarted();
- verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+ verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
verify(mNMService, times(1)).setIpForwardingEnabled(true);
verify(mNMService, times(1)).startTethering(any(String[].class));
verifyNoMoreInteractions(mNMService);
verify(mWifiManager).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
verifyNoMoreInteractions(mWifiManager);
- verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_ACTIVE_TETHER);
+ verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_ACTIVE_TETHER);
verify(mUpstreamNetworkMonitor, times(1)).start();
// In tethering mode, in the default configuration, an explicit request
// for a mobile network is also made.
verify(mUpstreamNetworkMonitor, times(1)).registerMobileNetworkRequest();
// TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
- verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
- verifyNoMoreInteractions(mConnectivityManager);
+ assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls);
/////
// We do not currently emulate any upstream being found.
@@ -651,7 +729,6 @@
mLooper.dispatchAll();
verify(mWifiManager, times(1)).stopSoftAp();
verifyNoMoreInteractions(mWifiManager);
- verifyNoMoreInteractions(mConnectivityManager);
verifyNoMoreInteractions(mNMService);
// Emulate externally-visible WifiManager effects, when tethering mode
@@ -671,14 +748,12 @@
verifyNoMoreInteractions(mWifiManager);
// Asking for the last error after the per-interface state machine
// has been reaped yields an unknown interface error.
- assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
- mTethering.getLastTetherError(TEST_WLAN_IFNAME));
+ assertEquals(TETHER_ERROR_UNKNOWN_IFACE, mTethering.getLastTetherError(TEST_WLAN_IFNAME));
}
// TODO: Test with and without interfaceStatusChanged().
@Test
public void failureEnablingIpForwarding() throws Exception {
- when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
doThrow(new RemoteException()).when(mNMService).setIpForwardingEnabled(true);
@@ -687,7 +762,6 @@
mLooper.dispatchAll();
verify(mWifiManager, times(1)).startSoftAp(null);
verifyNoMoreInteractions(mWifiManager);
- verifyNoMoreInteractions(mConnectivityManager);
verifyNoMoreInteractions(mNMService);
// Emulate externally-visible WifiManager effects, causing the
@@ -706,8 +780,9 @@
verify(mNMService, times(1)).tetherInterface(TEST_WLAN_IFNAME);
verify(mWifiManager).updateInterfaceIpState(
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_TETHERED);
- verify(mConnectivityManager, atLeastOnce()).isTetheringSupported();
- verifyTetheringBroadcast(TEST_WLAN_IFNAME, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+ // TODO: Figure out why this isn't exactly once, for sendTetherStateChangedBroadcast().
+ assertTrue(1 <= mTetheringDependencies.isTetheringSupportedCalls);
+ verifyTetheringBroadcast(TEST_WLAN_IFNAME, EXTRA_AVAILABLE_TETHER);
// This is called, but will throw.
verify(mNMService, times(1)).setIpForwardingEnabled(true);
// This never gets called because of the exception thrown above.
@@ -720,7 +795,6 @@
TEST_WLAN_IFNAME, WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR);
verifyNoMoreInteractions(mWifiManager);
- verifyNoMoreInteractions(mConnectivityManager);
verifyNoMoreInteractions(mNMService);
}
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index f59850d..e377a47 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -70,6 +70,7 @@
import android.os.Bundle;
import android.os.INetworkManagementService;
import android.os.Looper;
+import android.os.SystemClock;
import android.os.UserHandle;
import android.os.UserManager;
import android.support.test.filters.SmallTest;
@@ -88,6 +89,8 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.net.Inet4Address;
+import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -639,4 +642,32 @@
lp.addRoute(new RouteInfo(new IpPrefix("::/1")));
assertTrue(Vpn.providesRoutesToMostDestinations(lp));
}
+
+ @Test
+ public void testDoesNotLockUpWithTooManyRoutes() {
+ final LinkProperties lp = new LinkProperties();
+ final byte[] ad = new byte[4];
+ // Actually evaluating this many routes under 1500ms is impossible on
+ // current hardware and for some time, as the algorithm is O(n²).
+ // Make sure the system has a safeguard against this and does not
+ // lock up.
+ final int MAX_ROUTES = 4000;
+ final long MAX_ALLOWED_TIME_MS = 1500;
+ for (int i = 0; i < MAX_ROUTES; ++i) {
+ ad[0] = (byte)((i >> 24) & 0xFF);
+ ad[1] = (byte)((i >> 16) & 0xFF);
+ ad[2] = (byte)((i >> 8) & 0xFF);
+ ad[3] = (byte)(i & 0xFF);
+ try {
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.getByAddress(ad), 32)));
+ } catch (UnknownHostException e) {
+ // UnknownHostException is only thrown for an address of illegal length,
+ // which can't happen in the case above.
+ }
+ }
+ final long start = SystemClock.currentThreadTimeMillis();
+ assertTrue(Vpn.providesRoutesToMostDestinations(lp));
+ final long end = SystemClock.currentThreadTimeMillis();
+ assertTrue(end - start < MAX_ALLOWED_TIME_MS);
+ }
}
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
index 5f3fc54..7c77cf5 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
@@ -43,6 +43,7 @@
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.RouteInfo;
+import android.net.util.InterfaceSet;
import android.net.util.SharedLog;
import android.os.INetworkManagementService;
import android.os.RemoteException;
@@ -371,7 +372,7 @@
*/
private void dispatchTetherConnectionChanged(String upstreamIface) {
mTestedSm.sendMessage(TetherInterfaceStateMachine.CMD_TETHER_CONNECTION_CHANGED,
- upstreamIface);
+ new InterfaceSet(upstreamIface));
mLooper.dispatchAll();
}
diff --git a/tests/net/jni/apf_jni.cpp b/tests/net/jni/apf_jni.cpp
index d415d22..152e6c3 100644
--- a/tests/net/jni/apf_jni.cpp
+++ b/tests/net/jni/apf_jni.cpp
@@ -34,6 +34,8 @@
env->GetArrayLength(program),
(uint8_t*)env->GetByteArrayElements(packet, NULL),
env->GetArrayLength(packet),
+ nullptr,
+ 0,
filter_age);
}
@@ -143,7 +145,8 @@
do {
apf_packet = pcap_next(apf_pcap.get(), &apf_header);
} while (apf_packet != NULL && !accept_packet(
- apf_program, apf_program_len, apf_packet, apf_header.len, 0));
+ apf_program, apf_program_len, apf_packet, apf_header.len,
+ nullptr, 0, 0));
// Make sure both filters matched the same packet.
if (apf_packet == NULL && bpf_packet == NULL)
diff --git a/tools/bit/util.cpp b/tools/bit/util.cpp
index 9223931..a502a9d 100644
--- a/tools/bit/util.cpp
+++ b/tools/bit/util.cpp
@@ -241,6 +241,8 @@
char* buf = (char*)malloc(size);
if ((size_t) size != fread(buf, 1, size, file)) {
+ free(buf);
+ fclose(file);
return string();
}