Merge "Add MEDIA_TIMEOUT error for RTCP timeout"
diff --git a/api/current.txt b/api/current.txt
index 766b6b3..84aa984 100755
--- a/api/current.txt
+++ b/api/current.txt
@@ -100,7 +100,7 @@
field public static final String NFC_TRANSACTION_EVENT = "android.permission.NFC_TRANSACTION_EVENT";
field public static final String PACKAGE_USAGE_STATS = "android.permission.PACKAGE_USAGE_STATS";
field @Deprecated public static final String PERSISTENT_ACTIVITY = "android.permission.PERSISTENT_ACTIVITY";
- field public static final String PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS";
+ field @Deprecated public static final String PROCESS_OUTGOING_CALLS = "android.permission.PROCESS_OUTGOING_CALLS";
field public static final String READ_CALENDAR = "android.permission.READ_CALENDAR";
field public static final String READ_CALL_LOG = "android.permission.READ_CALL_LOG";
field public static final String READ_CONTACTS = "android.permission.READ_CONTACTS";
@@ -8351,7 +8351,6 @@
}
@Deprecated public final class BluetoothHealth implements android.bluetooth.BluetoothProfile {
- ctor @Deprecated public BluetoothHealth();
method @Deprecated public boolean connectChannelToSource(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration);
method @Deprecated public boolean disconnectChannel(android.bluetooth.BluetoothDevice, android.bluetooth.BluetoothHealthAppConfiguration, int);
method @Deprecated public java.util.List<android.bluetooth.BluetoothDevice> getConnectedDevices();
@@ -8375,7 +8374,6 @@
}
@Deprecated public final class BluetoothHealthAppConfiguration implements android.os.Parcelable {
- ctor @Deprecated public BluetoothHealthAppConfiguration();
method @Deprecated public int describeContents();
method @Deprecated public int getDataType();
method @Deprecated public String getName();
@@ -8750,7 +8748,7 @@
method @Nullable public byte[] getManufacturerSpecificData(int);
method public java.util.Map<android.os.ParcelUuid,byte[]> getServiceData();
method @Nullable public byte[] getServiceData(android.os.ParcelUuid);
- method @Nullable public java.util.List<android.os.ParcelUuid> getServiceSolicitationUuids();
+ method @NonNull public java.util.List<android.os.ParcelUuid> getServiceSolicitationUuids();
method public java.util.List<android.os.ParcelUuid> getServiceUuids();
method public int getTxPowerLevel();
}
@@ -27194,12 +27192,12 @@
public static class ConnectivityManager.NetworkCallback {
ctor public ConnectivityManager.NetworkCallback();
- method public void onAvailable(android.net.Network);
+ method public void onAvailable(@NonNull android.net.Network);
method public void onBlockedStatusChanged(@NonNull android.net.Network, boolean);
- method public void onCapabilitiesChanged(android.net.Network, android.net.NetworkCapabilities);
- method public void onLinkPropertiesChanged(android.net.Network, android.net.LinkProperties);
- method public void onLosing(android.net.Network, int);
- method public void onLost(android.net.Network);
+ method public void onCapabilitiesChanged(@NonNull android.net.Network, @NonNull android.net.NetworkCapabilities);
+ method public void onLinkPropertiesChanged(@NonNull android.net.Network, @NonNull android.net.LinkProperties);
+ method public void onLosing(@NonNull android.net.Network, int);
+ method public void onLost(@NonNull android.net.Network);
method public void onUnavailable();
}
@@ -27229,10 +27227,13 @@
public final class DnsResolver {
method @NonNull public static android.net.DnsResolver getInstance();
- method public <T> void query(@Nullable android.net.Network, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.AnswerCallback<T>);
- method public <T> void query(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.AnswerCallback<T>);
- method public void query(@Nullable android.net.Network, @NonNull String, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.InetAddressAnswerCallback);
+ method public void query(@Nullable android.net.Network, @NonNull String, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super java.util.List<java.net.InetAddress>>);
+ method public void query(@Nullable android.net.Network, @NonNull String, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super java.util.List<java.net.InetAddress>>);
+ method public void rawQuery(@Nullable android.net.Network, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super byte[]>);
+ method public void rawQuery(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super byte[]>);
field public static final int CLASS_IN = 1; // 0x1
+ field public static final int ERROR_PARSE = 0; // 0x0
+ field public static final int ERROR_SYSTEM = 1; // 0x1
field public static final int FLAG_EMPTY = 0; // 0x0
field public static final int FLAG_NO_CACHE_LOOKUP = 4; // 0x4
field public static final int FLAG_NO_CACHE_STORE = 2; // 0x2
@@ -27241,23 +27242,13 @@
field public static final int TYPE_AAAA = 28; // 0x1c
}
- public abstract static class DnsResolver.AnswerCallback<T> {
- ctor public DnsResolver.AnswerCallback(@NonNull android.net.DnsResolver.AnswerParser<T>);
- method public abstract void onAnswer(@NonNull T);
- method public abstract void onParseException(@NonNull android.net.ParseException);
- method public abstract void onQueryException(@NonNull android.system.ErrnoException);
+ public static interface DnsResolver.Callback<T> {
+ method public void onAnswer(@NonNull T, int);
+ method public void onError(@NonNull android.net.DnsResolver.DnsException);
}
- public static interface DnsResolver.AnswerParser<T> {
- method @NonNull public T parse(@NonNull byte[]) throws android.net.ParseException;
- }
-
- public abstract static class DnsResolver.InetAddressAnswerCallback extends android.net.DnsResolver.AnswerCallback<java.util.List<java.net.InetAddress>> {
- ctor public DnsResolver.InetAddressAnswerCallback();
- }
-
- public abstract static class DnsResolver.RawAnswerCallback extends android.net.DnsResolver.AnswerCallback<byte[]> {
- ctor public DnsResolver.RawAnswerCallback();
+ public static class DnsResolver.DnsException extends java.lang.Exception {
+ field public final int code;
}
public class InetAddresses {
@@ -27266,11 +27257,11 @@
}
public final class IpPrefix implements android.os.Parcelable {
- method public boolean contains(java.net.InetAddress);
+ method public boolean contains(@NonNull java.net.InetAddress);
method public int describeContents();
- method public java.net.InetAddress getAddress();
- method public int getPrefixLength();
- method public byte[] getRawAddress();
+ method @NonNull public java.net.InetAddress getAddress();
+ method @IntRange(from=0, to=128) public int getPrefixLength();
+ method @NonNull public byte[] getRawAddress();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
}
@@ -27343,7 +27334,7 @@
method public int describeContents();
method public java.net.InetAddress getAddress();
method public int getFlags();
- method public int getPrefixLength();
+ method @IntRange(from=0, to=128) public int getPrefixLength();
method public int getScope();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.LinkAddress> CREATOR;
@@ -27582,8 +27573,6 @@
}
public class ParseException extends java.lang.RuntimeException {
- ctor public ParseException(@NonNull String);
- ctor public ParseException(@NonNull String, @NonNull Throwable);
field public String response;
}
@@ -27612,9 +27601,9 @@
public final class RouteInfo implements android.os.Parcelable {
method public int describeContents();
- method public android.net.IpPrefix getDestination();
- method public java.net.InetAddress getGateway();
- method public String getInterface();
+ method @NonNull public android.net.IpPrefix getDestination();
+ method @Nullable public java.net.InetAddress getGateway();
+ method @Nullable public String getInterface();
method public boolean hasGateway();
method public boolean isDefaultRoute();
method public boolean matches(java.net.InetAddress);
@@ -35181,12 +35170,6 @@
field public static final String CACHED_NUMBER_TYPE = "numbertype";
field public static final String CACHED_PHOTO_ID = "photo_id";
field public static final String CACHED_PHOTO_URI = "photo_uri";
- field public static final String CALL_ID_APP_NAME = "call_id_app_name";
- field public static final String CALL_ID_DESCRIPTION = "call_id_description";
- field public static final String CALL_ID_DETAILS = "call_id_details";
- field public static final String CALL_ID_NAME = "call_id_name";
- field public static final String CALL_ID_NUISANCE_CONFIDENCE = "call_id_nuisance_confidence";
- field public static final String CALL_ID_PACKAGE_NAME = "call_id_package_name";
field public static final String CALL_SCREENING_APP_NAME = "call_screening_app_name";
field public static final String CALL_SCREENING_COMPONENT_NAME = "call_screening_component_name";
field public static final android.net.Uri CONTENT_FILTER_URI;
@@ -40426,6 +40409,8 @@
public final class ErrnoException extends java.lang.Exception {
ctor public ErrnoException(String, int);
ctor public ErrnoException(String, int, Throwable);
+ method @NonNull public java.io.IOException rethrowAsIOException() throws java.io.IOException;
+ method @NonNull public java.net.SocketException rethrowAsSocketException() throws java.net.SocketException;
field public final int errno;
}
@@ -40465,6 +40450,7 @@
method public static int getpid();
method public static int getppid();
method public static java.net.SocketAddress getsockname(java.io.FileDescriptor) throws android.system.ErrnoException;
+ method @NonNull public static android.system.StructTimeval getsockoptTimeval(@NonNull java.io.FileDescriptor, int, int) throws android.system.ErrnoException;
method public static int gettid();
method public static int getuid();
method public static byte[] getxattr(String, String) throws android.system.ErrnoException;
@@ -40515,6 +40501,7 @@
method @Deprecated public static void setgid(int) throws android.system.ErrnoException;
method public static int setsid() throws android.system.ErrnoException;
method public static void setsockoptInt(java.io.FileDescriptor, int, int, int) throws android.system.ErrnoException;
+ method public static void setsockoptTimeval(@NonNull java.io.FileDescriptor, int, int, @NonNull android.system.StructTimeval) throws android.system.ErrnoException;
method @Deprecated public static void setuid(int) throws android.system.ErrnoException;
method public static void setxattr(String, String, byte[], int) throws android.system.ErrnoException;
method public static void shutdown(java.io.FileDescriptor, int) throws android.system.ErrnoException;
@@ -40720,6 +40707,10 @@
field public static final int F_SETOWN;
field public static final int F_UNLCK;
field public static final int F_WRLCK;
+ field public static final int ICMP6_ECHO_REPLY;
+ field public static final int ICMP6_ECHO_REQUEST;
+ field public static final int ICMP_ECHO;
+ field public static final int ICMP_ECHOREPLY;
field public static final int IFA_F_DADFAILED;
field public static final int IFA_F_DEPRECATED;
field public static final int IFA_F_HOMEADDRESS;
@@ -41092,6 +41083,13 @@
field public final long tv_sec;
}
+ public final class StructTimeval {
+ method @NonNull public static android.system.StructTimeval fromMillis(long);
+ method public long toMillis();
+ field public final long tv_sec;
+ field public final long tv_usec;
+ }
+
public final class StructUtsname {
ctor public StructUtsname(String, String, String, String, String);
field public final String machine;
@@ -41189,7 +41187,6 @@
method public android.telecom.PhoneAccountHandle getAccountHandle();
method public int getCallCapabilities();
method public int getCallDirection();
- method @Nullable public android.telecom.CallIdentification getCallIdentification();
method public int getCallProperties();
method public String getCallerDisplayName();
method public int getCallerDisplayNamePresentation();
@@ -41271,34 +41268,6 @@
field public static final int ROUTE_WIRED_OR_EARPIECE = 5; // 0x5
}
- public final class CallIdentification implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public CharSequence getCallScreeningAppName();
- method @NonNull public String getCallScreeningPackageName();
- method @Nullable public CharSequence getDescription();
- method @Nullable public CharSequence getDetails();
- method @Nullable public CharSequence getName();
- method public int getNuisanceConfidence();
- method @Nullable public android.graphics.drawable.Icon getPhoto();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final int CONFIDENCE_LIKELY_NOT_NUISANCE = -1; // 0xffffffff
- field public static final int CONFIDENCE_LIKELY_NUISANCE = 1; // 0x1
- field public static final int CONFIDENCE_NOT_NUISANCE = -2; // 0xfffffffe
- field public static final int CONFIDENCE_NUISANCE = 2; // 0x2
- field public static final int CONFIDENCE_UNKNOWN = 0; // 0x0
- field public static final android.os.Parcelable.Creator<android.telecom.CallIdentification> CREATOR;
- }
-
- public static final class CallIdentification.Builder {
- ctor public CallIdentification.Builder();
- method @NonNull public android.telecom.CallIdentification build();
- method @NonNull public android.telecom.CallIdentification.Builder setDescription(@Nullable CharSequence);
- method @NonNull public android.telecom.CallIdentification.Builder setDetails(@Nullable CharSequence);
- method @NonNull public android.telecom.CallIdentification.Builder setName(@Nullable CharSequence);
- method @NonNull public android.telecom.CallIdentification.Builder setNuisanceConfidence(int);
- method @NonNull public android.telecom.CallIdentification.Builder setPhoto(@Nullable android.graphics.drawable.Icon);
- }
-
public abstract class CallRedirectionService extends android.app.Service {
ctor public CallRedirectionService();
method public final void cancelCall();
@@ -41314,17 +41283,7 @@
ctor public CallScreeningService();
method public android.os.IBinder onBind(android.content.Intent);
method public abstract void onScreenCall(@NonNull android.telecom.Call.Details);
- method public final void provideCallIdentification(@NonNull android.telecom.Call.Details, @NonNull android.telecom.CallIdentification);
method public final void respondToCall(@NonNull android.telecom.Call.Details, @NonNull android.telecom.CallScreeningService.CallResponse);
- field public static final String ACTION_NUISANCE_CALL_STATUS_CHANGED = "android.telecom.action.NUISANCE_CALL_STATUS_CHANGED";
- field public static final int CALL_DURATION_LONG = 4; // 0x4
- field public static final int CALL_DURATION_MEDIUM = 3; // 0x3
- field public static final int CALL_DURATION_SHORT = 2; // 0x2
- field public static final int CALL_DURATION_VERY_SHORT = 1; // 0x1
- field public static final String EXTRA_CALL_DURATION = "android.telecom.extra.CALL_DURATION";
- field public static final String EXTRA_CALL_HANDLE = "android.telecom.extra.CALL_HANDLE";
- field public static final String EXTRA_CALL_TYPE = "android.telecom.extra.CALL_TYPE";
- field public static final String EXTRA_IS_NUISANCE = "android.telecom.extra.IS_NUISANCE";
field public static final String SERVICE_INTERFACE = "android.telecom.CallScreeningService";
}
@@ -41931,7 +41890,6 @@
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isVoiceMailNumber(android.telecom.PhoneAccountHandle, String);
method @RequiresPermission(anyOf={android.Manifest.permission.CALL_PHONE, android.Manifest.permission.MANAGE_OWN_CALLS}) public void placeCall(android.net.Uri, android.os.Bundle);
method public void registerPhoneAccount(android.telecom.PhoneAccount);
- method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void reportNuisanceCallStatus(@NonNull android.net.Uri, boolean);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public void showInCallScreen(boolean);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void silenceRinger();
method public void unregisterPhoneAccount(android.telecom.PhoneAccountHandle);
@@ -42343,9 +42301,9 @@
method public int getCid();
method public int getLac();
method @Deprecated public int getMcc();
- method public String getMccString();
+ method @Nullable public String getMccString();
method @Deprecated public int getMnc();
- method public String getMncString();
+ method @Nullable public String getMncString();
method @Nullable public String getMobileNetworkOperator();
method @Deprecated public int getPsc();
method public void writeToParcel(android.os.Parcel, int);
@@ -42357,9 +42315,9 @@
method public int getCi();
method public int getEarfcn();
method @Deprecated public int getMcc();
- method public String getMccString();
+ method @Nullable public String getMccString();
method @Deprecated public int getMnc();
- method public String getMncString();
+ method @Nullable public String getMncString();
method @Nullable public String getMobileNetworkOperator();
method public int getPci();
method public int getTac();
@@ -42382,8 +42340,8 @@
method public int getCid();
method public int getCpid();
method public int getLac();
- method public String getMccString();
- method public String getMncString();
+ method @Nullable public String getMccString();
+ method @Nullable public String getMncString();
method @Nullable public String getMobileNetworkOperator();
method public int getUarfcn();
method public void writeToParcel(android.os.Parcel, int);
@@ -42394,9 +42352,9 @@
method public int getCid();
method public int getLac();
method @Deprecated public int getMcc();
- method public String getMccString();
+ method @Nullable public String getMccString();
method @Deprecated public int getMnc();
- method public String getMncString();
+ method @Nullable public String getMncString();
method @Nullable public String getMobileNetworkOperator();
method public int getPsc();
method public int getUarfcn();
@@ -42419,22 +42377,22 @@
}
public final class CellInfoCdma extends android.telephony.CellInfo implements android.os.Parcelable {
- method public android.telephony.CellIdentityCdma getCellIdentity();
- method public android.telephony.CellSignalStrengthCdma getCellSignalStrength();
+ method @NonNull public android.telephony.CellIdentityCdma getCellIdentity();
+ method @NonNull public android.telephony.CellSignalStrengthCdma getCellSignalStrength();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.CellInfoCdma> CREATOR;
}
public final class CellInfoGsm extends android.telephony.CellInfo implements android.os.Parcelable {
- method public android.telephony.CellIdentityGsm getCellIdentity();
- method public android.telephony.CellSignalStrengthGsm getCellSignalStrength();
+ method @NonNull public android.telephony.CellIdentityGsm getCellIdentity();
+ method @NonNull public android.telephony.CellSignalStrengthGsm getCellSignalStrength();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.CellInfoGsm> CREATOR;
}
public final class CellInfoLte extends android.telephony.CellInfo implements android.os.Parcelable {
- method public android.telephony.CellIdentityLte getCellIdentity();
- method public android.telephony.CellSignalStrengthLte getCellSignalStrength();
+ method @NonNull public android.telephony.CellIdentityLte getCellIdentity();
+ method @NonNull public android.telephony.CellSignalStrengthLte getCellSignalStrength();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.CellInfoLte> CREATOR;
}
@@ -42470,7 +42428,7 @@
method public abstract boolean equals(Object);
method public abstract int getAsuLevel();
method public abstract int getDbm();
- method public abstract int getLevel();
+ method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public abstract int getLevel();
method public abstract int hashCode();
field public static final int SIGNAL_STRENGTH_GOOD = 3; // 0x3
field public static final int SIGNAL_STRENGTH_GREAT = 4; // 0x4
@@ -42490,7 +42448,7 @@
method public int getEvdoEcio();
method public int getEvdoLevel();
method public int getEvdoSnr();
- method public int getLevel();
+ method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public int getLevel();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthCdma> CREATOR;
}
@@ -42500,7 +42458,7 @@
method public int getAsuLevel();
method public int getBitErrorRate();
method public int getDbm();
- method public int getLevel();
+ method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public int getLevel();
method public int getTimingAdvance();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthGsm> CREATOR;
@@ -42511,7 +42469,7 @@
method public int getAsuLevel();
method public int getCqi();
method public int getDbm();
- method public int getLevel();
+ method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public int getLevel();
method public int getRsrp();
method public int getRsrq();
method public int getRssi();
@@ -42528,7 +42486,7 @@
method public int getCsiRsrq();
method public int getCsiSinr();
method public int getDbm();
- method public int getLevel();
+ method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public int getLevel();
method public int getSsRsrp();
method public int getSsRsrq();
method public int getSsSinr();
@@ -42540,7 +42498,7 @@
method public int describeContents();
method public int getAsuLevel();
method public int getDbm();
- method public int getLevel();
+ method @IntRange(from=0, to=4) public int getLevel();
method public int getRscp();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthTdscdma> CREATOR;
@@ -42550,7 +42508,7 @@
method public int describeContents();
method public int getAsuLevel();
method public int getDbm();
- method public int getLevel();
+ method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public int getLevel();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthWcdma> CREATOR;
}
@@ -42965,7 +42923,7 @@
method public String getCountryIso();
method public int getDataRoaming();
method public CharSequence getDisplayName();
- method @Nullable public String getGroupUuid();
+ method @Nullable public android.os.ParcelUuid getGroupUuid();
method public String getIccId();
method public int getIconTint();
method @Deprecated public int getMcc();
@@ -42985,7 +42943,9 @@
public class SubscriptionManager {
method public void addOnOpportunisticSubscriptionsChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
method public void addOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void addSubscriptionsIntoGroup(@NonNull java.util.List<java.lang.Integer>, @NonNull android.os.ParcelUuid);
method public boolean canManageSubscription(android.telephony.SubscriptionInfo);
+ method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.os.ParcelUuid createSubscriptionGroup(@NonNull java.util.List<java.lang.Integer>);
method @Deprecated public static android.telephony.SubscriptionManager from(android.content.Context);
method public java.util.List<android.telephony.SubscriptionInfo> getAccessibleSubscriptionInfoList();
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public android.telephony.SubscriptionInfo getActiveSubscriptionInfo(int);
@@ -43001,17 +42961,15 @@
method public static int getSlotIndex(int);
method @Nullable public int[] getSubscriptionIds(int);
method @NonNull public java.util.List<android.telephony.SubscriptionPlan> getSubscriptionPlans(int);
- method @Nullable @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telephony.SubscriptionInfo> getSubscriptionsInGroup(int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public java.util.List<android.telephony.SubscriptionInfo> getSubscriptionsInGroup(@NonNull android.os.ParcelUuid);
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isActiveSubscriptionId(int);
method public boolean isNetworkRoaming(int);
method public static boolean isUsableSubscriptionId(int);
method public static boolean isValidSubscriptionId(int);
method public void removeOnOpportunisticSubscriptionsChangedListener(@NonNull android.telephony.SubscriptionManager.OnOpportunisticSubscriptionsChangedListener);
method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean removeSubscriptionsFromGroup(@NonNull int[]);
- method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setMetered(boolean, int);
+ method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void removeSubscriptionsFromGroup(@NonNull java.util.List<java.lang.Integer>, @NonNull android.os.ParcelUuid);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean setOpportunistic(boolean, int);
- method @Nullable @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String setSubscriptionGroup(@NonNull int[]);
method public void setSubscriptionOverrideCongested(int, boolean, long);
method public void setSubscriptionOverrideUnmetered(int, boolean, long);
method public void setSubscriptionPlans(int, @NonNull java.util.List<android.telephony.SubscriptionPlan>);
@@ -43249,7 +43207,7 @@
field public static final int PHONE_TYPE_GSM = 1; // 0x1
field public static final int PHONE_TYPE_NONE = 0; // 0x0
field public static final int PHONE_TYPE_SIP = 3; // 0x3
- field public static final int SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER = 2; // 0x2
+ field public static final int SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION = 2; // 0x2
field public static final int SET_OPPORTUNISTIC_SUB_SUCCESS = 0; // 0x0
field public static final int SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED = 1; // 0x1
field public static final int SIM_STATE_ABSENT = 1; // 0x1
diff --git a/api/system-current.txt b/api/system-current.txt
index 1717382..5bf5380 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -97,6 +97,7 @@
field public static final String MOVE_PACKAGE = "android.permission.MOVE_PACKAGE";
field public static final String NETWORK_SCAN = "android.permission.NETWORK_SCAN";
field public static final String NETWORK_SETUP_WIZARD = "android.permission.NETWORK_SETUP_WIZARD";
+ field public static final String NETWORK_SIGNAL_STRENGTH_WAKEUP = "android.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP";
field public static final String NOTIFICATION_DURING_SETUP = "android.permission.NOTIFICATION_DURING_SETUP";
field public static final String NOTIFY_TV_INPUTS = "android.permission.NOTIFY_TV_INPUTS";
field public static final String OBSERVE_APP_USAGE = "android.permission.OBSERVE_APP_USAGE";
@@ -745,9 +746,9 @@
public final class BluetoothDevice implements android.os.Parcelable {
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean cancelBondProcess();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public String getMetadata(int);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean getSilenceMode();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isConnected();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isEncrypted();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isInSilenceMode();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean removeBond();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMetadata(int, String);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setPhonebookAccessPermission(int);
@@ -756,7 +757,6 @@
field public static final int ACCESS_REJECTED = 2; // 0x2
field public static final int ACCESS_UNKNOWN = 0; // 0x0
field public static final String ACTION_SILENCE_MODE_CHANGED = "android.bluetooth.device.action.SILENCE_MODE_CHANGED";
- field public static final String EXTRA_SILENCE_ENABLED = "android.bluetooth.device.extra.SILENCE_ENABLED";
field public static final int METADATA_COMPANION_APP = 4; // 0x4
field public static final int METADATA_ENHANCED_SETTINGS_UI_URI = 16; // 0x10
field public static final int METADATA_HARDWARE_VERSION = 3; // 0x3
@@ -3133,13 +3133,13 @@
}
public final class IpPrefix implements android.os.Parcelable {
- ctor public IpPrefix(@NonNull java.net.InetAddress, int);
+ ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
ctor public IpPrefix(@NonNull String);
}
public class LinkAddress implements android.os.Parcelable {
- ctor public LinkAddress(java.net.InetAddress, int, int, int);
- ctor public LinkAddress(@NonNull java.net.InetAddress, int);
+ ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int);
+ ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
ctor public LinkAddress(@NonNull String);
ctor public LinkAddress(@NonNull String, int, int);
method public boolean isGlobalPreferred();
@@ -3203,7 +3203,7 @@
}
public static class NetworkRequest.Builder {
- method @NonNull public android.net.NetworkRequest.Builder setSignalStrength(int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int);
}
public class NetworkScoreManager {
@@ -3276,13 +3276,19 @@
method @Nullable public java.net.InetAddress getGateway();
method @Nullable public android.net.LinkAddress getIpAddress();
method @NonNull public java.util.List<android.net.RouteInfo> getRoutes(@Nullable String);
- method public void setDomains(@Nullable String);
- method public void setGateway(@Nullable java.net.InetAddress);
- method public void setIpAddress(@Nullable android.net.LinkAddress);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.StaticIpConfiguration> CREATOR;
}
+ public static final class StaticIpConfiguration.Builder {
+ ctor public StaticIpConfiguration.Builder();
+ method @NonNull public android.net.StaticIpConfiguration build();
+ method @NonNull public android.net.StaticIpConfiguration.Builder setDnsServers(@NonNull Iterable<java.net.InetAddress>);
+ method @NonNull public android.net.StaticIpConfiguration.Builder setDomains(@Nullable String);
+ method @NonNull public android.net.StaticIpConfiguration.Builder setGateway(@Nullable java.net.InetAddress);
+ method @NonNull public android.net.StaticIpConfiguration.Builder setIpAddress(@Nullable android.net.LinkAddress);
+ }
+
public class TrafficStats {
method public static void setThreadStatsTagApp();
method public static void setThreadStatsTagBackup();
@@ -3316,8 +3322,8 @@
public final class ApfCapabilities implements android.os.Parcelable {
ctor public ApfCapabilities(int, int, int);
method public int describeContents();
- method public static boolean getApfDrop8023Frames(@NonNull android.content.Context);
- method @NonNull public static int[] getApfEthTypeBlackList(@NonNull android.content.Context);
+ method public static boolean getApfDrop8023Frames();
+ method @NonNull public static int[] getApfEtherTypeBlackList();
method public boolean hasDataAccess();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.apf.ApfCapabilities> CREATOR;
@@ -3328,37 +3334,6 @@
}
-package android.net.captiveportal {
-
- public final class CaptivePortalProbeResult {
- ctor public CaptivePortalProbeResult(int);
- ctor public CaptivePortalProbeResult(int, @Nullable String, @Nullable String);
- ctor public CaptivePortalProbeResult(int, @Nullable String, @Nullable String, @Nullable android.net.captiveportal.CaptivePortalProbeSpec);
- method public boolean isFailed();
- method public boolean isPartialConnectivity();
- method public boolean isPortal();
- method public boolean isSuccessful();
- field @NonNull public static final android.net.captiveportal.CaptivePortalProbeResult FAILED;
- field public static final int FAILED_CODE = 599; // 0x257
- field public static final android.net.captiveportal.CaptivePortalProbeResult PARTIAL;
- field public static final int PORTAL_CODE = 302; // 0x12e
- field @NonNull public static final android.net.captiveportal.CaptivePortalProbeResult SUCCESS;
- field public static final int SUCCESS_CODE = 204; // 0xcc
- field @Nullable public final String detectUrl;
- field @Nullable public final android.net.captiveportal.CaptivePortalProbeSpec probeSpec;
- field @Nullable public final String redirectUrl;
- }
-
- public abstract class CaptivePortalProbeSpec {
- method @NonNull public String getEncodedSpec();
- method @NonNull public abstract android.net.captiveportal.CaptivePortalProbeResult getResult(int, @Nullable String);
- method @NonNull public java.net.URL getUrl();
- method @NonNull public static java.util.Collection<android.net.captiveportal.CaptivePortalProbeSpec> parseCaptivePortalProbeSpecs(@NonNull String);
- method @Nullable public static android.net.captiveportal.CaptivePortalProbeSpec parseSpecOrNull(@Nullable String);
- }
-
-}
-
package android.net.metrics {
public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event {
@@ -3519,16 +3494,11 @@
package android.net.util {
public final class SocketUtils {
- method public static void addArpEntry(@NonNull java.net.Inet4Address, @NonNull android.net.MacAddress, @NonNull String, @NonNull java.io.FileDescriptor) throws java.io.IOException;
- method public static void attachControlPacketFilter(@NonNull java.io.FileDescriptor, int) throws java.net.SocketException;
- method public static void attachDhcpFilter(@NonNull java.io.FileDescriptor) throws java.net.SocketException;
- method public static void attachRaFilter(@NonNull java.io.FileDescriptor, int) throws java.net.SocketException;
method public static void bindSocketToInterface(@NonNull java.io.FileDescriptor, @NonNull String) throws android.system.ErrnoException;
method public static void closeSocket(@Nullable java.io.FileDescriptor) throws java.io.IOException;
method @NonNull public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int);
method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
- method public static void setSocketTimeValueOption(@NonNull java.io.FileDescriptor, int, int, long) throws android.system.ErrnoException;
}
}
@@ -4650,11 +4620,6 @@
field public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https";
field public static final String CARRIER_APP_NAMES = "carrier_app_names";
field public static final String CARRIER_APP_WHITELIST = "carrier_app_whitelist";
- field public static final String DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = "data_stall_consecutive_dns_timeout_threshold";
- field public static final String DATA_STALL_EVALUATION_TYPE = "data_stall_evaluation_type";
- field public static final int DATA_STALL_EVALUATION_TYPE_DNS = 1; // 0x1
- field public static final String DATA_STALL_MIN_EVALUATE_INTERVAL = "data_stall_min_evaluate_interval";
- field public static final String DATA_STALL_VALID_DNS_TIME_THRESHOLD = "data_stall_valid_dns_time_threshold";
field public static final String DEFAULT_SM_DP_PLUS = "default_sm_dp_plus";
field public static final String EUICC_PROVISIONED = "euicc_provisioned";
field public static final String INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT = "install_carrier_app_notification_persistent";
@@ -5565,6 +5530,7 @@
}
public static final class CarrierRestrictionRules.Builder {
+ ctor public CarrierRestrictionRules.Builder();
method @NonNull public android.telephony.CarrierRestrictionRules build();
method @NonNull public android.telephony.CarrierRestrictionRules.Builder setAllCarriersAllowed();
method @NonNull public android.telephony.CarrierRestrictionRules.Builder setAllowedCarriers(@NonNull java.util.List<android.service.carrier.CarrierIdentifier>);
@@ -7736,7 +7702,7 @@
package android.telephony.mbms.vendor {
- public class MbmsDownloadServiceBase extends android.os.Binder {
+ public class MbmsDownloadServiceBase extends android.os.Binder implements android.os.IInterface {
ctor public MbmsDownloadServiceBase();
method public int addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) throws android.os.RemoteException;
method public int addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) throws android.os.RemoteException;
@@ -7769,7 +7735,7 @@
method public void updateGroupCall(int, long, @NonNull java.util.List<java.lang.Integer>, @NonNull java.util.List<java.lang.Integer>);
}
- public class MbmsStreamingServiceBase extends android.os.Binder {
+ public class MbmsStreamingServiceBase extends android.os.Binder implements android.os.IInterface {
ctor public MbmsStreamingServiceBase();
method public android.os.IBinder asBinder();
method public void dispose(int) throws android.os.RemoteException;
diff --git a/api/test-current.txt b/api/test-current.txt
index ca74109..524c1fb 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -616,7 +616,7 @@
}
public final class IpPrefix implements android.os.Parcelable {
- ctor public IpPrefix(@NonNull java.net.InetAddress, int);
+ ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
ctor public IpPrefix(@NonNull String);
}
@@ -625,8 +625,8 @@
}
public class LinkAddress implements android.os.Parcelable {
- ctor public LinkAddress(java.net.InetAddress, int, int, int);
- ctor public LinkAddress(@NonNull java.net.InetAddress, int);
+ ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int);
+ ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
ctor public LinkAddress(@NonNull String);
ctor public LinkAddress(@NonNull String, int, int);
method public boolean isGlobalPreferred();
@@ -696,13 +696,19 @@
method @Nullable public java.net.InetAddress getGateway();
method @Nullable public android.net.LinkAddress getIpAddress();
method @NonNull public java.util.List<android.net.RouteInfo> getRoutes(@Nullable String);
- method public void setDomains(@Nullable String);
- method public void setGateway(@Nullable java.net.InetAddress);
- method public void setIpAddress(@Nullable android.net.LinkAddress);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.StaticIpConfiguration> CREATOR;
}
+ public static final class StaticIpConfiguration.Builder {
+ ctor public StaticIpConfiguration.Builder();
+ method @NonNull public android.net.StaticIpConfiguration build();
+ method @NonNull public android.net.StaticIpConfiguration.Builder setDnsServers(@NonNull Iterable<java.net.InetAddress>);
+ method @NonNull public android.net.StaticIpConfiguration.Builder setDomains(@Nullable String);
+ method @NonNull public android.net.StaticIpConfiguration.Builder setGateway(@Nullable java.net.InetAddress);
+ method @NonNull public android.net.StaticIpConfiguration.Builder setIpAddress(@Nullable android.net.LinkAddress);
+ }
+
public final class TestNetworkInterface implements android.os.Parcelable {
ctor public TestNetworkInterface(android.os.ParcelFileDescriptor, String);
method public int describeContents();
@@ -713,6 +719,7 @@
}
public class TestNetworkManager {
+ method public android.net.TestNetworkInterface createTapInterface();
method public android.net.TestNetworkInterface createTunInterface(@NonNull android.net.LinkAddress[]);
method public void setupTestNetwork(@NonNull String, @NonNull android.os.IBinder);
method public void teardownTestNetwork(@NonNull android.net.Network);
@@ -735,8 +742,8 @@
public final class ApfCapabilities implements android.os.Parcelable {
ctor public ApfCapabilities(int, int, int);
method public int describeContents();
- method public static boolean getApfDrop8023Frames(@NonNull android.content.Context);
- method @NonNull public static int[] getApfEthTypeBlackList(@NonNull android.content.Context);
+ method public static boolean getApfDrop8023Frames();
+ method @NonNull public static int[] getApfEtherTypeBlackList();
method public boolean hasDataAccess();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.apf.ApfCapabilities> CREATOR;
@@ -747,37 +754,6 @@
}
-package android.net.captiveportal {
-
- public final class CaptivePortalProbeResult {
- ctor public CaptivePortalProbeResult(int);
- ctor public CaptivePortalProbeResult(int, @Nullable String, @Nullable String);
- ctor public CaptivePortalProbeResult(int, @Nullable String, @Nullable String, @Nullable android.net.captiveportal.CaptivePortalProbeSpec);
- method public boolean isFailed();
- method public boolean isPartialConnectivity();
- method public boolean isPortal();
- method public boolean isSuccessful();
- field @NonNull public static final android.net.captiveportal.CaptivePortalProbeResult FAILED;
- field public static final int FAILED_CODE = 599; // 0x257
- field public static final android.net.captiveportal.CaptivePortalProbeResult PARTIAL;
- field public static final int PORTAL_CODE = 302; // 0x12e
- field @NonNull public static final android.net.captiveportal.CaptivePortalProbeResult SUCCESS;
- field public static final int SUCCESS_CODE = 204; // 0xcc
- field @Nullable public final String detectUrl;
- field @Nullable public final android.net.captiveportal.CaptivePortalProbeSpec probeSpec;
- field @Nullable public final String redirectUrl;
- }
-
- public abstract class CaptivePortalProbeSpec {
- method @NonNull public String getEncodedSpec();
- method @NonNull public abstract android.net.captiveportal.CaptivePortalProbeResult getResult(int, @Nullable String);
- method @NonNull public java.net.URL getUrl();
- method @NonNull public static java.util.Collection<android.net.captiveportal.CaptivePortalProbeSpec> parseCaptivePortalProbeSpecs(@NonNull String);
- method @Nullable public static android.net.captiveportal.CaptivePortalProbeSpec parseSpecOrNull(@Nullable String);
- }
-
-}
-
package android.net.metrics {
public final class ApfProgramEvent implements android.net.metrics.IpConnectivityLog.Event {
@@ -938,16 +914,11 @@
package android.net.util {
public final class SocketUtils {
- method public static void addArpEntry(@NonNull java.net.Inet4Address, @NonNull android.net.MacAddress, @NonNull String, @NonNull java.io.FileDescriptor) throws java.io.IOException;
- method public static void attachControlPacketFilter(@NonNull java.io.FileDescriptor, int) throws java.net.SocketException;
- method public static void attachDhcpFilter(@NonNull java.io.FileDescriptor) throws java.net.SocketException;
- method public static void attachRaFilter(@NonNull java.io.FileDescriptor, int) throws java.net.SocketException;
method public static void bindSocketToInterface(@NonNull java.io.FileDescriptor, @NonNull String) throws android.system.ErrnoException;
method public static void closeSocket(@Nullable java.io.FileDescriptor) throws java.io.IOException;
method @NonNull public static java.net.SocketAddress makeNetlinkSocketAddress(int, int);
method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, int);
method @NonNull public static java.net.SocketAddress makePacketSocketAddress(int, @NonNull byte[]);
- method public static void setSocketTimeValueOption(@NonNull java.io.FileDescriptor, int, int, long) throws android.system.ErrnoException;
}
}
@@ -1243,11 +1214,6 @@
field public static final String CAPTIVE_PORTAL_OTHER_FALLBACK_URLS = "captive_portal_other_fallback_urls";
field public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent";
field public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https";
- field public static final String DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = "data_stall_consecutive_dns_timeout_threshold";
- field public static final String DATA_STALL_EVALUATION_TYPE = "data_stall_evaluation_type";
- field public static final int DATA_STALL_EVALUATION_TYPE_DNS = 1; // 0x1
- field public static final String DATA_STALL_MIN_EVALUATE_INTERVAL = "data_stall_min_evaluate_interval";
- field public static final String DATA_STALL_VALID_DNS_TIME_THRESHOLD = "data_stall_valid_dns_time_threshold";
field public static final String HIDDEN_API_BLACKLIST_EXEMPTIONS = "hidden_api_blacklist_exemptions";
field public static final String LOCATION_GLOBAL_KILL_SWITCH = "location_global_kill_switch";
field public static final String LOW_POWER_MODE = "low_power";
@@ -1581,6 +1547,7 @@
public class TelephonyManager {
method public int getCarrierIdListVersion();
+ method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public String getLine1AlphaTag();
method public android.util.Pair<java.lang.Integer,java.lang.Integer> getRadioHalVersion();
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void refreshUiccProfile();
method public void setCarrierTestOverride(String, String, String, String, String, String, String);
@@ -1619,7 +1586,7 @@
package android.telephony.mbms.vendor {
- public class MbmsDownloadServiceBase extends android.os.Binder {
+ public class MbmsDownloadServiceBase extends android.os.Binder implements android.os.IInterface {
ctor public MbmsDownloadServiceBase();
method public int addProgressListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadProgressListener) throws android.os.RemoteException;
method public int addStatusListener(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStatusListener) throws android.os.RemoteException;
@@ -1652,7 +1619,7 @@
method public void updateGroupCall(int, long, @NonNull java.util.List<java.lang.Integer>, @NonNull java.util.List<java.lang.Integer>);
}
- public class MbmsStreamingServiceBase extends android.os.Binder {
+ public class MbmsStreamingServiceBase extends android.os.Binder implements android.os.IInterface {
ctor public MbmsStreamingServiceBase();
method public android.os.IBinder asBinder();
method public void dispose(int) throws android.os.RemoteException;
diff --git a/cmds/am/Android.bp b/cmds/am/Android.bp
index bb16df1..ed73d55 100644
--- a/cmds/am/Android.bp
+++ b/cmds/am/Android.bp
@@ -10,3 +10,16 @@
export_proto_headers: true,
},
}
+
+java_binary {
+ name: "am",
+ wrapper: "am",
+ srcs: [
+ "src/**/*.java",
+ "proto/**/*.proto",
+ ],
+ proto: {
+ plugin: "javastream",
+ },
+ static_libs: ["libprotobuf-java-lite"],
+}
diff --git a/cmds/am/Android.mk b/cmds/am/Android.mk
deleted file mode 100644
index 9411c32..0000000
--- a/cmds/am/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright 2008 The Android Open Source Project
-#
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, src) \
- $(call all-proto-files-under, proto)
-LOCAL_MODULE := am
-LOCAL_PROTOC_OPTIMIZE_TYPE := stream
-include $(BUILD_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := am
-LOCAL_SRC_FILES := am
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_PREBUILT)
diff --git a/cmds/app_process/Android.bp b/cmds/app_process/Android.bp
new file mode 100644
index 0000000..d387531
--- /dev/null
+++ b/cmds/app_process/Android.bp
@@ -0,0 +1,63 @@
+cc_binary {
+ name: "app_process",
+
+ srcs: ["app_main.cpp"],
+
+ multilib: {
+ lib32: {
+ version_script: ":art_sigchain_version_script32.txt",
+ stem: "app_process32",
+ },
+ lib64: {
+ version_script: ":art_sigchain_version_script64.txt",
+ stem: "app_process64",
+ },
+ },
+
+ ldflags: ["-Wl,--export-dynamic"],
+
+ shared_libs: [
+ "libandroid_runtime",
+ "libbinder",
+ "libcutils",
+ "libdl",
+ "libhwbinder",
+ "liblog",
+ "libnativeloader",
+ "libutils",
+
+ // This is a list of libraries that need to be included in order to avoid
+ // bad apps. This prevents a library from having a mismatch when resolving
+ // new/delete from an app shared library.
+ // See b/21032018 for more details.
+ "libwilhelm",
+ ],
+
+ whole_static_libs: ["libsigchain"],
+
+ compile_multilib: "both",
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+
+ // If SANITIZE_LITE is revived this will need:
+ //product_variables: {
+ // sanitize_lite: {
+ // // In SANITIZE_LITE mode, we create the sanitized binary in a separate location (but reuse
+ // // the same module). Using the same module also works around an issue with make: binaries
+ // // that depend on sanitized libraries will be relinked, even if they set LOCAL_SANITIZE := never.
+ // //
+ // // Also pull in the asanwrapper helper.
+ // relative_install_path: "asan",
+ // required: ["asanwrapper"],
+ // },
+ //},
+
+ // Create a symlink from app_process to app_process32 or 64
+ // depending on the target configuration.
+ symlink_preferred_arch: true,
+}
diff --git a/cmds/app_process/Android.mk b/cmds/app_process/Android.mk
deleted file mode 100644
index 72fe051..0000000
--- a/cmds/app_process/Android.mk
+++ /dev/null
@@ -1,68 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-app_process_common_shared_libs := \
- libandroid_runtime \
- libbinder \
- libcutils \
- libdl \
- libhwbinder \
- liblog \
- libnativeloader \
- libutils \
-
-# This is a list of libraries that need to be included in order to avoid
-# bad apps. This prevents a library from having a mismatch when resolving
-# new/delete from an app shared library.
-# See b/21032018 for more details.
-app_process_common_shared_libs += \
- libwilhelm \
-
-app_process_common_static_libs := \
- libsigchain \
-
-app_process_src_files := \
- app_main.cpp \
-
-app_process_cflags := \
- -Wall -Werror -Wunused -Wunreachable-code
-
-app_process_ldflags_32 := \
- -Wl,--version-script,art/sigchainlib/version-script32.txt -Wl,--export-dynamic
-app_process_ldflags_64 := \
- -Wl,--version-script,art/sigchainlib/version-script64.txt -Wl,--export-dynamic
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= $(app_process_src_files)
-
-LOCAL_LDFLAGS_32 := $(app_process_ldflags_32)
-LOCAL_LDFLAGS_64 := $(app_process_ldflags_64)
-
-LOCAL_SHARED_LIBRARIES := $(app_process_common_shared_libs)
-
-LOCAL_WHOLE_STATIC_LIBRARIES := $(app_process_common_static_libs)
-
-LOCAL_MODULE:= app_process
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := app_process32
-LOCAL_MODULE_STEM_64 := app_process64
-
-LOCAL_CFLAGS += $(app_process_cflags)
-
-# In SANITIZE_LITE mode, we create the sanitized binary in a separate location (but reuse
-# the same module). Using the same module also works around an issue with make: binaries
-# that depend on sanitized libraries will be relinked, even if they set LOCAL_SANITIZE := never.
-#
-# Also pull in the asanwrapper helper.
-ifeq ($(SANITIZE_LITE),true)
-LOCAL_MODULE_PATH := $(TARGET_OUT_EXECUTABLES)/asan
-LOCAL_REQUIRED_MODULES := asanwrapper
-endif
-
-include $(BUILD_EXECUTABLE)
-
-# Create a symlink from app_process to app_process32 or 64
-# depending on the target configuration.
-ifneq ($(SANITIZE_LITE),true)
-include $(BUILD_SYSTEM)/executable_prefer_symlink.mk
-endif
diff --git a/cmds/appops/Android.bp b/cmds/appops/Android.bp
new file mode 100644
index 0000000..9f330fa
--- /dev/null
+++ b/cmds/appops/Android.bp
@@ -0,0 +1,6 @@
+// Copyright 2014 The Android Open Source Project
+
+sh_binary {
+ name: "appops",
+ src: "appops",
+}
diff --git a/cmds/appops/Android.mk b/cmds/appops/Android.mk
deleted file mode 100644
index 6801ce9..0000000
--- a/cmds/appops/Android.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2014 The Android Open Source Project
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := appops
-LOCAL_SRC_FILES := appops
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_PREBUILT)
diff --git a/cmds/appwidget/Android.bp b/cmds/appwidget/Android.bp
new file mode 100644
index 0000000..487d3e1
--- /dev/null
+++ b/cmds/appwidget/Android.bp
@@ -0,0 +1,7 @@
+// Copyright 2014 The Android Open Source Project
+
+java_binary {
+ name: "appwidget",
+ wrapper: "appwidget",
+ srcs: ["**/*.java"],
+}
diff --git a/cmds/appwidget/Android.mk b/cmds/appwidget/Android.mk
deleted file mode 100644
index 1fb258d..0000000
--- a/cmds/appwidget/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2014 The Android Open Source Project
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_MODULE := appwidget
-include $(BUILD_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := appwidget
-LOCAL_SRC_FILES := appwidget
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_PREBUILT)
-
diff --git a/cmds/bmgr/Android.bp b/cmds/bmgr/Android.bp
new file mode 100644
index 0000000..b64923b
--- /dev/null
+++ b/cmds/bmgr/Android.bp
@@ -0,0 +1,8 @@
+// Copyright 2007 The Android Open Source Project
+//
+
+java_binary {
+ name: "bmgr",
+ wrapper: "bmgr",
+ srcs: ["**/*.java"],
+}
diff --git a/cmds/bmgr/Android.mk b/cmds/bmgr/Android.mk
deleted file mode 100644
index d520cf2..0000000
--- a/cmds/bmgr/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2007 The Android Open Source Project
-#
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_MODULE := bmgrlib
-LOCAL_MODULE_STEM := bmgr
-include $(BUILD_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := bmgr
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_SRC_FILES := bmgr
-LOCAL_REQUIRED_MODULES := bmgrlib
-include $(BUILD_PREBUILT)
diff --git a/cmds/bu/Android.bp b/cmds/bu/Android.bp
new file mode 100644
index 0000000..0866ee0
--- /dev/null
+++ b/cmds/bu/Android.bp
@@ -0,0 +1,8 @@
+// Copyright 2011 The Android Open Source Project
+//
+
+java_binary {
+ name: "bu",
+ wrapper: "bu",
+ srcs: ["**/*.java"],
+}
diff --git a/cmds/bu/Android.mk b/cmds/bu/Android.mk
deleted file mode 100644
index 4fd5fec..0000000
--- a/cmds/bu/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-# Copyright 2011 The Android Open Source Project
-#
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_MODULE := bu
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := bu
-LOCAL_SRC_FILES := bu
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_PREBUILT)
-
-
diff --git a/cmds/content/Android.bp b/cmds/content/Android.bp
new file mode 100644
index 0000000..96d1469
--- /dev/null
+++ b/cmds/content/Android.bp
@@ -0,0 +1,7 @@
+// Copyright 2012 The Android Open Source Project
+
+java_binary {
+ name: "content",
+ wrapper: "content",
+ srcs: ["**/*.java"],
+}
diff --git a/cmds/content/Android.mk b/cmds/content/Android.mk
deleted file mode 100644
index 9302e2f..0000000
--- a/cmds/content/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2012 The Android Open Source Project
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_MODULE := content
-include $(BUILD_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := content
-LOCAL_SRC_FILES := content
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_PREBUILT)
diff --git a/cmds/dpm/Android.bp b/cmds/dpm/Android.bp
new file mode 100644
index 0000000..753121e
--- /dev/null
+++ b/cmds/dpm/Android.bp
@@ -0,0 +1,8 @@
+// Copyright 2014 The Android Open Source Project
+//
+
+java_binary {
+ name: "dpm",
+ wrapper: "dpm",
+ srcs: ["**/*.java"],
+}
diff --git a/cmds/dpm/Android.mk b/cmds/dpm/Android.mk
deleted file mode 100644
index 9f5aee4..0000000
--- a/cmds/dpm/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2014 The Android Open Source Project
-#
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_MODULE := dpm
-include $(BUILD_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := dpm
-LOCAL_SRC_FILES := dpm
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_PREBUILT)
diff --git a/cmds/hid/Android.bp b/cmds/hid/Android.bp
index 2b7963a..54c8bf3 100644
--- a/cmds/hid/Android.bp
+++ b/cmds/hid/Android.bp
@@ -1 +1,9 @@
-subdirs = ["jni"]
+// Copyright 2015 The Android Open Source Project
+//
+
+java_binary {
+ name: "hid",
+ wrapper: "hid",
+ srcs: ["**/*.java"],
+ required: ["libhidcommand_jni"],
+}
diff --git a/cmds/hid/Android.mk b/cmds/hid/Android.mk
deleted file mode 100644
index 574834d..0000000
--- a/cmds/hid/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-# Copyright 2015 The Android Open Source Project
-#
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_MODULE := hid
-LOCAL_JNI_SHARED_LIBRARIES := libhidcommand_jni
-LOCAL_REQUIRED_MODULES := libhidcommand_jni
-include $(BUILD_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := hid
-LOCAL_SRC_FILES := hid
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := EXECUTABLES
-include $(BUILD_PREBUILT)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/cmds/ime/Android.bp b/cmds/ime/Android.bp
new file mode 100644
index 0000000..76a16c8
--- /dev/null
+++ b/cmds/ime/Android.bp
@@ -0,0 +1,7 @@
+// Copyright 2007 The Android Open Source Project
+//
+
+sh_binary {
+ name: "ime",
+ src: "ime",
+}
diff --git a/cmds/ime/Android.mk b/cmds/ime/Android.mk
deleted file mode 100644
index ca608e8..0000000
--- a/cmds/ime/Android.mk
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright 2007 The Android Open Source Project
-#
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := ime
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_SRC_FILES := ime
-include $(BUILD_PREBUILT)
diff --git a/cmds/input/Android.bp b/cmds/input/Android.bp
new file mode 100644
index 0000000..a0ebde6
--- /dev/null
+++ b/cmds/input/Android.bp
@@ -0,0 +1,8 @@
+// Copyright 2008 The Android Open Source Project
+//
+
+java_binary {
+ name: "input",
+ wrapper: "input",
+ srcs: ["**/*.java"],
+}
diff --git a/cmds/input/Android.mk b/cmds/input/Android.mk
deleted file mode 100644
index 4e983e3..0000000
--- a/cmds/input/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2008 The Android Open Source Project
-#
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_MODULE := inputlib
-LOCAL_MODULE_STEM := input
-include $(BUILD_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := input
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_SRC_FILES := input
-LOCAL_REQUIRED_MODULES := inputlib
-include $(BUILD_PREBUILT)
diff --git a/cmds/locksettings/Android.bp b/cmds/locksettings/Android.bp
new file mode 100644
index 0000000..59ccc5c
--- /dev/null
+++ b/cmds/locksettings/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+java_binary {
+ name: "locksettings",
+ wrapper: "locksettings",
+ srcs: ["**/*.java"],
+}
diff --git a/cmds/locksettings/Android.mk b/cmds/locksettings/Android.mk
deleted file mode 100644
index 76766c7..0000000
--- a/cmds/locksettings/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_MODULE := locksettings
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := locksettings
-LOCAL_SRC_FILES := locksettings
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_PREBUILT)
-
-
diff --git a/cmds/media/Android.bp b/cmds/media/Android.bp
new file mode 100644
index 0000000..7879c53
--- /dev/null
+++ b/cmds/media/Android.bp
@@ -0,0 +1,8 @@
+// Copyright 2013 The Android Open Source Project
+//
+
+java_binary {
+ name: "media",
+ wrapper: "media",
+ srcs: ["**/*.java"],
+}
diff --git a/cmds/media/Android.mk b/cmds/media/Android.mk
deleted file mode 100644
index b9451c5..0000000
--- a/cmds/media/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2013 The Android Open Source Project
-#
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_MODULE := media_cmd
-include $(BUILD_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := media
-LOCAL_SRC_FILES := media
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_PREBUILT)
diff --git a/cmds/media/media b/cmds/media/media
index 5c0eb2f..8ada914 100755
--- a/cmds/media/media
+++ b/cmds/media/media
@@ -3,5 +3,5 @@
# shell.
#
base=/system
-export CLASSPATH=$base/framework/media_cmd.jar
+export CLASSPATH=$base/framework/media.jar
exec app_process $base/bin com.android.commands.media.Media "$@"
diff --git a/cmds/pm/Android.bp b/cmds/pm/Android.bp
new file mode 100644
index 0000000..0644f6e
--- /dev/null
+++ b/cmds/pm/Android.bp
@@ -0,0 +1,7 @@
+// Copyright 2007 The Android Open Source Project
+//
+
+sh_binary {
+ name: "pm",
+ src: "pm",
+}
diff --git a/cmds/pm/Android.mk b/cmds/pm/Android.mk
deleted file mode 100644
index 960c805..0000000
--- a/cmds/pm/Android.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2007 The Android Open Source Project
-#
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := pm
-LOCAL_SRC_FILES := pm
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_PREBUILT)
diff --git a/cmds/requestsync/Android.bp b/cmds/requestsync/Android.bp
new file mode 100644
index 0000000..ef2a8a6
--- /dev/null
+++ b/cmds/requestsync/Android.bp
@@ -0,0 +1,8 @@
+// Copyright 2012 The Android Open Source Project
+//
+
+java_binary {
+ name: "requestsync",
+ wrapper: "requestsync",
+ srcs: ["**/*.java"],
+}
diff --git a/cmds/requestsync/Android.mk b/cmds/requestsync/Android.mk
deleted file mode 100644
index fe2ffd8..0000000
--- a/cmds/requestsync/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2012 The Android Open Source Project
-#
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_MODULE := requestsync
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := requestsync
-LOCAL_SRC_FILES := requestsync
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_PREBUILT)
diff --git a/cmds/settings/Android.bp b/cmds/settings/Android.bp
new file mode 100644
index 0000000..8a78e54
--- /dev/null
+++ b/cmds/settings/Android.bp
@@ -0,0 +1,7 @@
+// Copyright 2011 The Android Open Source Project
+//
+
+sh_binary {
+ name: "settings",
+ src: "settings",
+}
diff --git a/cmds/settings/Android.mk b/cmds/settings/Android.mk
deleted file mode 100644
index 8a8d1bb..0000000
--- a/cmds/settings/Android.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-# Copyright 2011 The Android Open Source Project
-#
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := settings
-LOCAL_SRC_FILES := settings
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_PREBUILT)
-
-
diff --git a/cmds/sm/Android.bp b/cmds/sm/Android.bp
new file mode 100644
index 0000000..11e4e72
--- /dev/null
+++ b/cmds/sm/Android.bp
@@ -0,0 +1,8 @@
+// Copyright 2015 The Android Open Source Project
+//
+
+java_binary {
+ name: "sm",
+ wrapper: "sm",
+ srcs: ["**/*.java"],
+}
diff --git a/cmds/sm/Android.mk b/cmds/sm/Android.mk
deleted file mode 100644
index 7cb1e12..0000000
--- a/cmds/sm/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2015 The Android Open Source Project
-#
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_MODULE := sm
-include $(BUILD_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := sm
-LOCAL_SRC_FILES := sm
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_PREBUILT)
diff --git a/cmds/statsd/src/atom_field_options.proto b/cmds/statsd/src/atom_field_options.proto
index 7dfe7d6..39de357 100644
--- a/cmds/statsd/src/atom_field_options.proto
+++ b/cmds/statsd/src/atom_field_options.proto
@@ -82,4 +82,6 @@
optional bool is_uid = 50001 [default = false];
optional LogMode log_mode = 50002 [default = MODE_AUTOMATIC];
-}
\ No newline at end of file
+
+ optional string log_from_module = 50004;
+}
diff --git a/cmds/svc/Android.bp b/cmds/svc/Android.bp
new file mode 100644
index 0000000..68b48f1
--- /dev/null
+++ b/cmds/svc/Android.bp
@@ -0,0 +1,8 @@
+// Copyright 2007 The Android Open Source Project
+//
+
+java_binary {
+ name: "svc",
+ wrapper: "svc",
+ srcs: ["**/*.java"],
+}
diff --git a/cmds/svc/Android.mk b/cmds/svc/Android.mk
deleted file mode 100644
index a4824c7..0000000
--- a/cmds/svc/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2007 The Android Open Source Project
-#
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_MODULE := svclib
-LOCAL_MODULE_STEM := svc
-include $(BUILD_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := svc
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_SRC_FILES := svc
-LOCAL_REQUIRED_MODULES := svclib
-include $(BUILD_PREBUILT)
diff --git a/cmds/telecom/Android.bp b/cmds/telecom/Android.bp
new file mode 100644
index 0000000..56e147c
--- /dev/null
+++ b/cmds/telecom/Android.bp
@@ -0,0 +1,8 @@
+// Copyright 2015 The Android Open Source Project
+//
+
+java_binary {
+ name: "telecom",
+ wrapper: "telecom",
+ srcs: ["**/*.java"],
+}
diff --git a/cmds/telecom/Android.mk b/cmds/telecom/Android.mk
deleted file mode 100644
index 5f7bdf7..0000000
--- a/cmds/telecom/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2015 The Android Open Source Project
-#
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_MODULE := telecom
-include $(BUILD_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := telecom
-LOCAL_SRC_FILES := telecom
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_PREBUILT)
diff --git a/cmds/uiautomator/Android.bp b/cmds/uiautomator/Android.bp
new file mode 100644
index 0000000..f9cb3dd
--- /dev/null
+++ b/cmds/uiautomator/Android.bp
@@ -0,0 +1,18 @@
+genrule {
+ name: "uiautomator-last-released-api",
+ srcs: ["api/*.txt"],
+ cmd: "cp -f $$(echo $(in) | tr \" \" \"\\n\" | sort -n | tail -1) $(genDir)/last-released-api.txt",
+ out: [
+ "last-released-api.txt",
+ ],
+}
+
+filegroup {
+ name: "uiautomator-current-api",
+ srcs: ["api/current.txt"],
+}
+
+filegroup {
+ name: "uiautomator-removed-api",
+ srcs: ["api/removed.txt"],
+}
diff --git a/cmds/uiautomator/Android.mk b/cmds/uiautomator/Android.mk
deleted file mode 100644
index 5391305..0000000
--- a/cmds/uiautomator/Android.mk
+++ /dev/null
@@ -1,25 +0,0 @@
-#
-# Copyright (C) 2012 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.
-#
-
-# don't build uiautomator in unbundled env
-ifndef TARGET_BUILD_APPS
-include $(call all-subdir-makefiles)
-else
-ifneq ($(filter uiautomator,$(TARGET_BUILD_APPS)),)
-# used by the platform apps build.
-include $(call all-subdir-makefiles)
-endif
-endif
diff --git a/cmds/uiautomator/api/current.txt b/cmds/uiautomator/api/current.txt
index 634ca4d..489c2ea 100644
--- a/cmds/uiautomator/api/current.txt
+++ b/cmds/uiautomator/api/current.txt
@@ -171,7 +171,7 @@
method public com.android.uiautomator.core.UiSelector checked(boolean);
method public com.android.uiautomator.core.UiSelector childSelector(com.android.uiautomator.core.UiSelector);
method public com.android.uiautomator.core.UiSelector className(java.lang.String);
- method public com.android.uiautomator.core.UiSelector className(java.lang.Class<T>);
+ method public <T> com.android.uiautomator.core.UiSelector className(java.lang.Class<T>);
method public com.android.uiautomator.core.UiSelector classNameMatches(java.lang.String);
method public com.android.uiautomator.core.UiSelector clickable(boolean);
method protected com.android.uiautomator.core.UiSelector cloneSelector();
diff --git a/cmds/uiautomator/cmds/Android.mk b/cmds/uiautomator/cmds/Android.mk
deleted file mode 100644
index c141484..0000000
--- a/cmds/uiautomator/cmds/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# Copyright (C) 2012 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-include $(call all-subdir-makefiles)
diff --git a/cmds/uiautomator/cmds/uiautomator/Android.bp b/cmds/uiautomator/cmds/uiautomator/Android.bp
new file mode 100644
index 0000000..68cc5a3
--- /dev/null
+++ b/cmds/uiautomator/cmds/uiautomator/Android.bp
@@ -0,0 +1,22 @@
+//
+// Copyright (C) 2012 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.
+//
+
+java_binary {
+ name: "uiautomator",
+ wrapper: "uiautomator",
+ srcs: ["src/**/*.java"],
+ static_libs: ["uiautomator.core"],
+}
diff --git a/cmds/uiautomator/cmds/uiautomator/Android.mk b/cmds/uiautomator/cmds/uiautomator/Android.mk
deleted file mode 100644
index 5c91b52..0000000
--- a/cmds/uiautomator/cmds/uiautomator/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# Copyright (C) 2012 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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_STATIC_JAVA_LIBRARIES := uiautomator.core
-LOCAL_MODULE := uiautomator
-
-include $(BUILD_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := uiautomator
-LOCAL_SRC_FILES := uiautomator
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_PREBUILT)
diff --git a/cmds/uiautomator/instrumentation/Android.bp b/cmds/uiautomator/instrumentation/Android.bp
new file mode 100644
index 0000000..477f0d1
--- /dev/null
+++ b/cmds/uiautomator/instrumentation/Android.bp
@@ -0,0 +1,33 @@
+//
+// Copyright (C) 2012 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.
+//
+
+java_test {
+ name: "uiautomator-instrumentation",
+
+ srcs: [
+ "testrunner-src/**/*.java",
+ ],
+ libs: [
+ "android.test.runner.stubs",
+ "android.test.base.stubs",
+ ],
+ static_libs: [
+ "junit",
+ "uiautomator.library",
+ ],
+ // TODO: change this to 18 when it's available
+ sdk_version: "test_current",
+}
diff --git a/cmds/uiautomator/instrumentation/Android.mk b/cmds/uiautomator/instrumentation/Android.mk
deleted file mode 100644
index e887539..0000000
--- a/cmds/uiautomator/instrumentation/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-#
-# Copyright (C) 2012 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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_SRC_FILES := $(call all-java-files-under, testrunner-src) \
- $(call all-java-files-under, ../library/core-src)
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs
-LOCAL_STATIC_JAVA_LIBRARIES := junit
-LOCAL_MODULE := uiautomator-instrumentation
-# TODO: change this to 18 when it's available
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/cmds/uiautomator/library/Android.bp b/cmds/uiautomator/library/Android.bp
index 77f17c5..1173d57 100644
--- a/cmds/uiautomator/library/Android.bp
+++ b/cmds/uiautomator/library/Android.bp
@@ -30,6 +30,17 @@
api_tag_name: "UIAUTOMATOR",
api_filename: "uiautomator_api.txt",
removed_api_filename: "uiautomator_removed_api.txt",
+
+ check_api: {
+ current: {
+ api_file: ":uiautomator-current-api",
+ removed_api_file: ":uiautomator-removed-api",
+ },
+ last_released: {
+ api_file: ":uiautomator-last-released-api",
+ removed_api_file: ":uiautomator-removed-api",
+ },
+ },
}
java_library_static {
@@ -57,3 +68,10 @@
"junit",
]
}
+
+java_library_static {
+ name: "uiautomator.library",
+ srcs: [
+ "core-src/**/*.java",
+ ],
+}
diff --git a/cmds/uiautomator/library/Android.mk b/cmds/uiautomator/library/Android.mk
deleted file mode 100644
index 5ca201c..0000000
--- a/cmds/uiautomator/library/Android.mk
+++ /dev/null
@@ -1,76 +0,0 @@
-#
-# Copyright (C) 2012 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.
-#
-
-LOCAL_PATH:= $(call my-dir)
-
-###############################################
-# API check
-# Please refer to build/core/tasks/apicheck.mk.
-uiautomator_api_dir := frameworks/base/cmds/uiautomator/api
-last_released_sdk_version := $(lastword $(call numerically_sort, \
- $(filter-out current, \
- $(patsubst $(uiautomator_api_dir)/%.txt,%, $(wildcard $(uiautomator_api_dir)/*.txt)) \
- )))
-
-checkapi_last_error_level_flags := \
- -hide 2 -hide 3 -hide 4 -hide 5 -hide 6 -hide 24 -hide 25 \
- -error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 \
- -error 16 -error 17 -error 18
-
-# Check that the API we're building hasn't broken the last-released SDK version.
-$(eval $(call check-api, \
- uiautomator-checkapi-last, \
- $(uiautomator_api_dir)/$(last_released_sdk_version).txt, \
- $(INTERNAL_PLATFORM_UIAUTOMATOR_API_FILE), \
- $(uiautomator_api_dir)/removed.txt, \
- $(INTERNAL_PLATFORM_UIAUTOMATOR_REMOVED_API_FILE), \
- $(checkapi_last_error_level_flags), \
- cat $(LOCAL_PATH)/apicheck_msg_last.txt, \
- uiautomator.core, \
- $(OUT_DOCS)/uiautomator-stubs-docs-stubs.srcjar))
-
-checkapi_current_error_level_flags := \
- -error 2 -error 3 -error 4 -error 5 -error 6 \
- -error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 \
- -error 16 -error 17 -error 18 -error 19 -error 20 -error 21 -error 23 -error 24 \
- -error 25
-
-# Check that the API we're building hasn't changed from the not-yet-released
-# SDK version.
-$(eval $(call check-api, \
- uiautomator-checkapi-current, \
- $(uiautomator_api_dir)/current.txt, \
- $(INTERNAL_PLATFORM_UIAUTOMATOR_API_FILE), \
- $(uiautomator_api_dir)/removed.txt, \
- $(INTERNAL_PLATFORM_UIAUTOMATOR_REMOVED_API_FILE), \
- $(checkapi_current_error_level_flags), \
- cat $(LOCAL_PATH)/apicheck_msg_current.txt, \
- uiautomator.core, \
- $(OUT_DOCS)/uiautomator-stubs-docs-stubs.srcjar))
-
-.PHONY: update-uiautomator-api
-update-uiautomator-api: PRIVATE_API_DIR := $(uiautomator_api_dir)
-update-uiautomator-api: PRIVATE_REMOVED_API_FILE := $(INTERNAL_PLATFORM_UIAUTOMATOR_REMOVED_API_FILE)
-update-uiautomator-api: $(INTERNAL_PLATFORM_UIAUTOMATOR_API_FILE)
- @echo Copying uiautomator current.txt
- $(hide) cp $< $(PRIVATE_API_DIR)/current.txt
- @echo Copying uiautomator removed.txt
- $(hide) cp $(PRIVATE_REMOVED_API_FILE) $(PRIVATE_API_DIR)/removed.txt
-###############################################
-# clean up temp vars
-uiautomator_api_dir :=
-checkapi_last_error_level_flags :=
-checkapi_current_error_level_flags :=
diff --git a/cmds/uiautomator/library/apicheck_msg_current.txt b/cmds/uiautomator/library/apicheck_msg_current.txt
deleted file mode 100644
index 989248d..0000000
--- a/cmds/uiautomator/library/apicheck_msg_current.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-
-******************************
-You have tried to change the API from what has been previously approved.
-
-To make these errors go away, you have two choices:
- 1) You can add "@hide" javadoc comments to the methods, etc. listed in the
- errors above.
-
- 2) You can update current.txt by executing the following command:
- make update-uiautomator-api
-
- To submit the revised current.txt to the main Android repository,
- you will need approval.
-******************************
-
-
-
diff --git a/cmds/uiautomator/library/apicheck_msg_last.txt b/cmds/uiautomator/library/apicheck_msg_last.txt
deleted file mode 100644
index 2993157..0000000
--- a/cmds/uiautomator/library/apicheck_msg_last.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-
-******************************
-You have tried to change the API from what has been previously released in
-an SDK. Please fix the errors listed above.
-******************************
-
-
diff --git a/cmds/vr/Android.bp b/cmds/vr/Android.bp
new file mode 100644
index 0000000..cb129bd
--- /dev/null
+++ b/cmds/vr/Android.bp
@@ -0,0 +1,8 @@
+// Copyright 2017 The Android Open Source Project
+//
+
+java_binary {
+ name: "vr",
+ wrapper: "vr",
+ srcs: ["**/*.java"],
+}
diff --git a/cmds/vr/Android.mk b/cmds/vr/Android.mk
deleted file mode 100644
index d0dc25a..0000000
--- a/cmds/vr/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2017 The Android Open Source Project
-#
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_MODULE := vr
-include $(BUILD_JAVA_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := vr
-LOCAL_SRC_FILES := vr
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_PREBUILT)
diff --git a/cmds/wm/Android.bp b/cmds/wm/Android.bp
new file mode 100644
index 0000000..609f84b
--- /dev/null
+++ b/cmds/wm/Android.bp
@@ -0,0 +1,7 @@
+// Copyright 2013 The Android Open Source Project
+//
+
+sh_binary {
+ name: "wm",
+ src: "wm",
+}
diff --git a/cmds/wm/Android.mk b/cmds/wm/Android.mk
deleted file mode 100644
index 693c6e7..0000000
--- a/cmds/wm/Android.mk
+++ /dev/null
@@ -1,10 +0,0 @@
-# Copyright 2013 The Android Open Source Project
-#
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := wm
-LOCAL_SRC_FILES := wm
-LOCAL_MODULE_CLASS := EXECUTABLES
-LOCAL_MODULE_TAGS := optional
-include $(BUILD_PREBUILT)
diff --git a/config/TEST_MAPPING b/config/TEST_MAPPING
new file mode 100644
index 0000000..d09805e
--- /dev/null
+++ b/config/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "PreloadCheck"
+ }
+ ]
+}
diff --git a/config/hiddenapi-greylist-packages.txt b/config/hiddenapi-greylist-packages.txt
new file mode 100644
index 0000000..cae3bd9
--- /dev/null
+++ b/config/hiddenapi-greylist-packages.txt
@@ -0,0 +1,2 @@
+org.ccil.cowan.tagsoup
+org.ccil.cowan.tagsoup.jaxp
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index 7efadf2..eade053e 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -2604,108 +2604,3 @@
Lorg/apache/xpath/XPathContext;->setCurrentNodeStack(Lorg/apache/xml/utils/IntStack;)V
Lorg/apache/xpath/XPathContext;->setSecureProcessing(Z)V
Lorg/apache/xpath/XPathContext;->setVarStack(Lorg/apache/xpath/VariableStack;)V
-Lorg/ccil/cowan/tagsoup/AttributesImpl;-><init>(Lorg/xml/sax/Attributes;)V
-Lorg/ccil/cowan/tagsoup/AttributesImpl;->addAttribute(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
-Lorg/ccil/cowan/tagsoup/AttributesImpl;->data:[Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/AttributesImpl;->length:I
-Lorg/ccil/cowan/tagsoup/AttributesImpl;->setAttribute(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
-Lorg/ccil/cowan/tagsoup/AttributesImpl;->setValue(ILjava/lang/String;)V
-Lorg/ccil/cowan/tagsoup/AutoDetector;->autoDetectingReader(Ljava/io/InputStream;)Ljava/io/Reader;
-Lorg/ccil/cowan/tagsoup/Element;-><init>(Lorg/ccil/cowan/tagsoup/ElementType;Z)V
-Lorg/ccil/cowan/tagsoup/Element;->anonymize()V
-Lorg/ccil/cowan/tagsoup/Element;->atts()Lorg/ccil/cowan/tagsoup/AttributesImpl;
-Lorg/ccil/cowan/tagsoup/Element;->canContain(Lorg/ccil/cowan/tagsoup/Element;)Z
-Lorg/ccil/cowan/tagsoup/Element;->clean()V
-Lorg/ccil/cowan/tagsoup/Element;->flags()I
-Lorg/ccil/cowan/tagsoup/Element;->localName()Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Element;->name()Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Element;->namespace()Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Element;->next()Lorg/ccil/cowan/tagsoup/Element;
-Lorg/ccil/cowan/tagsoup/Element;->parent()Lorg/ccil/cowan/tagsoup/ElementType;
-Lorg/ccil/cowan/tagsoup/Element;->preclosed:Z
-Lorg/ccil/cowan/tagsoup/Element;->setAttribute(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
-Lorg/ccil/cowan/tagsoup/Element;->setNext(Lorg/ccil/cowan/tagsoup/Element;)V
-Lorg/ccil/cowan/tagsoup/Element;->theAtts:Lorg/ccil/cowan/tagsoup/AttributesImpl;
-Lorg/ccil/cowan/tagsoup/Element;->theNext:Lorg/ccil/cowan/tagsoup/Element;
-Lorg/ccil/cowan/tagsoup/Element;->theType:Lorg/ccil/cowan/tagsoup/ElementType;
-Lorg/ccil/cowan/tagsoup/ElementType;-><init>(Ljava/lang/String;IIILorg/ccil/cowan/tagsoup/Schema;)V
-Lorg/ccil/cowan/tagsoup/ElementType;->atts()Lorg/ccil/cowan/tagsoup/AttributesImpl;
-Lorg/ccil/cowan/tagsoup/ElementType;->setAttribute(Lorg/ccil/cowan/tagsoup/AttributesImpl;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
-Lorg/ccil/cowan/tagsoup/ElementType;->theAtts:Lorg/ccil/cowan/tagsoup/AttributesImpl;
-Lorg/ccil/cowan/tagsoup/ElementType;->theFlags:I
-Lorg/ccil/cowan/tagsoup/ElementType;->theLocalName:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/ElementType;->theMemberOf:I
-Lorg/ccil/cowan/tagsoup/ElementType;->theModel:I
-Lorg/ccil/cowan/tagsoup/ElementType;->theName:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/ElementType;->theNamespace:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/ElementType;->theParent:Lorg/ccil/cowan/tagsoup/ElementType;
-Lorg/ccil/cowan/tagsoup/ElementType;->theSchema:Lorg/ccil/cowan/tagsoup/Schema;
-Lorg/ccil/cowan/tagsoup/HTMLScanner;-><init>()V
-Lorg/ccil/cowan/tagsoup/HTMLSchema;-><init>()V
-Lorg/ccil/cowan/tagsoup/jaxp/SAXFactoryImpl;-><init>()V
-Lorg/ccil/cowan/tagsoup/jaxp/SAXParserImpl;-><init>()V
-Lorg/ccil/cowan/tagsoup/jaxp/SAXParserImpl;->newInstance(Ljava/util/Map;)Lorg/ccil/cowan/tagsoup/jaxp/SAXParserImpl;
-Lorg/ccil/cowan/tagsoup/Parser;-><init>()V
-Lorg/ccil/cowan/tagsoup/Parser;->bogonsEmpty:Z
-Lorg/ccil/cowan/tagsoup/Parser;->CDATAElements:Z
-Lorg/ccil/cowan/tagsoup/Parser;->cleanPublicid(Ljava/lang/String;)Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->defaultAttributes:Z
-Lorg/ccil/cowan/tagsoup/Parser;->etagchars:[C
-Lorg/ccil/cowan/tagsoup/Parser;->expandEntities(Ljava/lang/String;)Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->getInputStream(Ljava/lang/String;Ljava/lang/String;)Ljava/io/InputStream;
-Lorg/ccil/cowan/tagsoup/Parser;->ignorableWhitespace:Z
-Lorg/ccil/cowan/tagsoup/Parser;->ignoreBogons:Z
-Lorg/ccil/cowan/tagsoup/Parser;->lookupEntity([CII)I
-Lorg/ccil/cowan/tagsoup/Parser;->makeName([CII)Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->pop()V
-Lorg/ccil/cowan/tagsoup/Parser;->push(Lorg/ccil/cowan/tagsoup/Element;)V
-Lorg/ccil/cowan/tagsoup/Parser;->rectify(Lorg/ccil/cowan/tagsoup/Element;)V
-Lorg/ccil/cowan/tagsoup/Parser;->restart(Lorg/ccil/cowan/tagsoup/Element;)V
-Lorg/ccil/cowan/tagsoup/Parser;->restartablyPop()V
-Lorg/ccil/cowan/tagsoup/Parser;->rootBogons:Z
-Lorg/ccil/cowan/tagsoup/Parser;->schemaProperty:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->split(Ljava/lang/String;)[Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->theAttributeName:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->theAutoDetector:Lorg/ccil/cowan/tagsoup/AutoDetector;
-Lorg/ccil/cowan/tagsoup/Parser;->theContentHandler:Lorg/xml/sax/ContentHandler;
-Lorg/ccil/cowan/tagsoup/Parser;->theDoctypeIsPresent:Z
-Lorg/ccil/cowan/tagsoup/Parser;->theDoctypeSystemId:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->theFeatures:Ljava/util/HashMap;
-Lorg/ccil/cowan/tagsoup/Parser;->theLexicalHandler:Lorg/xml/sax/ext/LexicalHandler;
-Lorg/ccil/cowan/tagsoup/Parser;->theNewElement:Lorg/ccil/cowan/tagsoup/Element;
-Lorg/ccil/cowan/tagsoup/Parser;->thePCDATA:Lorg/ccil/cowan/tagsoup/Element;
-Lorg/ccil/cowan/tagsoup/Parser;->thePITarget:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->theSaved:Lorg/ccil/cowan/tagsoup/Element;
-Lorg/ccil/cowan/tagsoup/Parser;->theScanner:Lorg/ccil/cowan/tagsoup/Scanner;
-Lorg/ccil/cowan/tagsoup/Parser;->theSchema:Lorg/ccil/cowan/tagsoup/Schema;
-Lorg/ccil/cowan/tagsoup/Parser;->theStack:Lorg/ccil/cowan/tagsoup/Element;
-Lorg/ccil/cowan/tagsoup/Parser;->trimquotes(Ljava/lang/String;)Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Parser;->virginStack:Z
-Lorg/ccil/cowan/tagsoup/PYXScanner;-><init>()V
-Lorg/ccil/cowan/tagsoup/PYXWriter;-><init>(Ljava/io/Writer;)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->aname([CII)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->aval([CII)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->entity([CII)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->eof([CII)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->etag([CII)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->gi([CII)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->pcdata([CII)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->pi([CII)V
-Lorg/ccil/cowan/tagsoup/ScanHandler;->stagc([CII)V
-Lorg/ccil/cowan/tagsoup/Scanner;->startCDATA()V
-Lorg/ccil/cowan/tagsoup/Schema;->elementType(Ljava/lang/String;III)V
-Lorg/ccil/cowan/tagsoup/Schema;->getElementType(Ljava/lang/String;)Lorg/ccil/cowan/tagsoup/ElementType;
-Lorg/ccil/cowan/tagsoup/Schema;->getEntity(Ljava/lang/String;)I
-Lorg/ccil/cowan/tagsoup/Schema;->getPrefix()Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Schema;->getURI()Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Schema;->parent(Ljava/lang/String;Ljava/lang/String;)V
-Lorg/ccil/cowan/tagsoup/Schema;->theElementTypes:Ljava/util/HashMap;
-Lorg/ccil/cowan/tagsoup/Schema;->theEntities:Ljava/util/HashMap;
-Lorg/ccil/cowan/tagsoup/Schema;->thePrefix:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/Schema;->theRoot:Lorg/ccil/cowan/tagsoup/ElementType;
-Lorg/ccil/cowan/tagsoup/Schema;->theURI:Ljava/lang/String;
-Lorg/ccil/cowan/tagsoup/XMLWriter;-><init>(Ljava/io/Writer;)V
-Lorg/ccil/cowan/tagsoup/XMLWriter;->htmlMode:Z
-Lorg/ccil/cowan/tagsoup/XMLWriter;->setOutput(Ljava/io/Writer;)V
-Lorg/ccil/cowan/tagsoup/XMLWriter;->setOutputProperty(Ljava/lang/String;Ljava/lang/String;)V
-Lorg/ccil/cowan/tagsoup/XMLWriter;->setPrefix(Ljava/lang/String;Ljava/lang/String;)V
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 9bc719e..a6f19f4 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -5659,6 +5659,11 @@
private void handleBindApplication(AppBindData data) {
// Register the UI Thread as a sensitive thread to the runtime.
VMRuntime.registerSensitiveThread();
+ // In the case the stack depth property exists, pass it down to the runtime.
+ String property = SystemProperties.get("debug.allocTracker.stackDepth");
+ if (property.length() != 0) {
+ VMDebug.setAllocTrackerStackDepth(Integer.parseInt(property));
+ }
if (data.trackAllocation) {
DdmVmInternal.enableRecentAllocations(true);
}
@@ -5689,6 +5694,10 @@
UserHandle.myUserId());
VMRuntime.setProcessPackageName(data.appInfo.packageName);
+ // Pass data directory path to ART. This is used for caching information and
+ // should be set before any application code is loaded.
+ VMRuntime.setProcessDataDirectory(data.appInfo.dataDir);
+
if (mProfiler.profileFd != null) {
mProfiler.startProfiling();
}
diff --git a/core/java/android/app/AppComponentFactory.java b/core/java/android/app/AppComponentFactory.java
index 2cec7f0..5b02817 100644
--- a/core/java/android/app/AppComponentFactory.java
+++ b/core/java/android/app/AppComponentFactory.java
@@ -35,11 +35,22 @@
public class AppComponentFactory {
/**
- * Allows application to override the creation of the default class loader.
- * This can be used to perform things such as dependency injection or setting up
- * a custom class loader hierarchy.
+ * Selects the class loader which will be used by the platform to instantiate app components.
+ * <p>
+ * The default implementation of this method returns the {@code cl} parameter unchanged.
+ * Applications can override this method to set up a custom class loader or a custom class
+ * loader hierarchy and return it to the platform.
+ * <p>
+ * The method is a hook invoked before any application components are instantiated or the
+ * application Context is initialized. It is intended to allow the application's classes to
+ * be loaded from a different source than the base/split APK(s).
+ * <p>
+ * The default class loader {@code cl} is created by the platform and used to load the
+ * application's base or split APK(s). Its parent is typically the boot class loader, unless
+ * running under instrumentation. Its classname is configurable using the
+ * {@link android.R.attr#classLoader} manifest attribute.
*
- * @param cl The default classloader instantiated by platform.
+ * @param cl The default class loader created by the platform.
* @param aInfo Information about the application being loaded.
*/
public @NonNull ClassLoader instantiateClassLoader(@NonNull ClassLoader cl,
diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java
index 9ef24c6..2e59b90 100644
--- a/core/java/android/app/ApplicationLoaders.java
+++ b/core/java/android/app/ApplicationLoaders.java
@@ -17,20 +17,27 @@
package android.app;
import android.annotation.UnsupportedAppUsage;
+import android.content.pm.SharedLibraryInfo;
import android.os.Build;
import android.os.GraphicsEnvironment;
import android.os.Trace;
import android.util.ArrayMap;
+import android.util.Log;
import com.android.internal.os.ClassLoaderFactory;
import dalvik.system.PathClassLoader;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/** @hide */
public class ApplicationLoaders {
+ private static final String TAG = "ApplicationLoaders";
+
@UnsupportedAppUsage
public static ApplicationLoaders getDefault() {
return gApplicationLoaders;
@@ -54,6 +61,26 @@
libraryPermittedPath, parent, zip, classLoaderName, sharedLibraries);
}
+ /**
+ * Gets a class loader for a shared library. Additional dependent shared libraries are allowed
+ * to be specified (sharedLibraries).
+ *
+ * Additionally, as an optimization, this will return a pre-created ClassLoader if one has
+ * been cached by createAndCacheNonBootclasspathSystemClassLoaders.
+ */
+ ClassLoader getSharedLibraryClassLoaderWithSharedLibraries(String zip, int targetSdkVersion,
+ boolean isBundled, String librarySearchPath, String libraryPermittedPath,
+ ClassLoader parent, String classLoaderName, List<ClassLoader> sharedLibraries) {
+ ClassLoader loader = getCachedNonBootclasspathSystemLib(zip, parent, classLoaderName,
+ sharedLibraries);
+ if (loader != null) {
+ return loader;
+ }
+
+ return getClassLoaderWithSharedLibraries(zip, targetSdkVersion, isBundled,
+ librarySearchPath, libraryPermittedPath, parent, classLoaderName, sharedLibraries);
+ }
+
private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
String librarySearchPath, String libraryPermittedPath,
ClassLoader parent, String cacheKey,
@@ -95,7 +122,9 @@
classloader, librarySearchPath, libraryPermittedPath);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
- mLoaders.put(cacheKey, classloader);
+ if (cacheKey != null) {
+ mLoaders.put(cacheKey, classloader);
+ }
return classloader;
}
@@ -108,6 +137,111 @@
}
/**
+ * Caches system library class loaders which are not on the bootclasspath but are still used
+ * by many system apps.
+ *
+ * All libraries in the closure of libraries to be loaded must be in libs. A library can
+ * only depend on libraries that come before it in the list.
+ */
+ public void createAndCacheNonBootclasspathSystemClassLoaders(SharedLibraryInfo[] libs) {
+ if (mSystemLibsCacheMap != null) {
+ throw new IllegalStateException("Already cached.");
+ }
+
+ mSystemLibsCacheMap = new HashMap<String, CachedClassLoader>();
+
+ for (SharedLibraryInfo lib : libs) {
+ createAndCacheNonBootclasspathSystemClassLoader(lib);
+ }
+ }
+
+ /**
+ * Caches a single non-bootclasspath class loader.
+ *
+ * All of this library's dependencies must have previously been cached. Otherwise, an exception
+ * is thrown.
+ */
+ private void createAndCacheNonBootclasspathSystemClassLoader(SharedLibraryInfo lib) {
+ String path = lib.getPath();
+ List<SharedLibraryInfo> dependencies = lib.getDependencies();
+
+ // get cached classloaders for dependencies
+ ArrayList<ClassLoader> sharedLibraries = null;
+ if (dependencies != null) {
+ sharedLibraries = new ArrayList<ClassLoader>(dependencies.size());
+ for (SharedLibraryInfo dependency : dependencies) {
+ String dependencyPath = dependency.getPath();
+ CachedClassLoader cached = mSystemLibsCacheMap.get(dependencyPath);
+
+ if (cached == null) {
+ throw new IllegalStateException("Failed to find dependency " + dependencyPath
+ + " of cachedlibrary " + path);
+ }
+
+ sharedLibraries.add(cached.loader);
+ }
+ }
+
+ // assume cached libraries work with current sdk since they are built-in
+ ClassLoader classLoader = getClassLoader(path, Build.VERSION.SDK_INT, true /*isBundled*/,
+ null /*librarySearchPath*/, null /*libraryPermittedPath*/, null /*parent*/,
+ null /*cacheKey*/, null /*classLoaderName*/, sharedLibraries /*sharedLibraries*/);
+
+ if (classLoader == null) {
+ // bad configuration or break in classloading code
+ throw new IllegalStateException("Failed to cache " + path);
+ }
+
+ CachedClassLoader cached = new CachedClassLoader();
+ cached.loader = classLoader;
+ cached.sharedLibraries = sharedLibraries;
+
+ Log.d(TAG, "Created zygote-cached class loader: " + path);
+ mSystemLibsCacheMap.put(path, cached);
+ }
+
+ private static boolean sharedLibrariesEquals(List<ClassLoader> lhs, List<ClassLoader> rhs) {
+ if (lhs == null) {
+ return rhs == null;
+ }
+
+ return lhs.equals(rhs);
+ }
+
+ /**
+ * Returns lib cached with createAndCacheNonBootclasspathSystemClassLoader. This is called by
+ * the zygote during caching.
+ *
+ * If there is an error or the cache is not available, this returns null.
+ */
+ public ClassLoader getCachedNonBootclasspathSystemLib(String zip, ClassLoader parent,
+ String classLoaderName, List<ClassLoader> sharedLibraries) {
+ if (mSystemLibsCacheMap == null) {
+ return null;
+ }
+
+ // we only cache top-level libs with the default class loader
+ if (parent != null || classLoaderName != null) {
+ return null;
+ }
+
+ CachedClassLoader cached = mSystemLibsCacheMap.get(zip);
+ if (cached == null) {
+ return null;
+ }
+
+ // cached must be built and loaded in the same environment
+ if (!sharedLibrariesEquals(sharedLibraries, cached.sharedLibraries)) {
+ Log.w(TAG, "Unexpected environment for cached library: (" + sharedLibraries + "|"
+ + cached.sharedLibraries + ")");
+ return null;
+ }
+
+ Log.d(TAG, "Returning zygote-cached class loader: " + zip);
+ return cached.loader;
+ }
+
+ /**
* Creates a classloader for the WebView APK and places it in the cache of loaders maintained
* by this class. This is used in the WebView zygote, where its presence in the cache speeds up
* startup and enables memory sharing.
@@ -151,4 +285,18 @@
private final ArrayMap<String, ClassLoader> mLoaders = new ArrayMap<>();
private static final ApplicationLoaders gApplicationLoaders = new ApplicationLoaders();
+
+ private static class CachedClassLoader {
+ ClassLoader loader;
+
+ /**
+ * The shared libraries used when constructing loader for verification.
+ */
+ List<ClassLoader> sharedLibraries;
+ }
+
+ /**
+ * This is a map of zip to associated class loader.
+ */
+ private Map<String, CachedClassLoader> mSystemLibsCacheMap = null;
}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 0f1ba39..3603b56 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -46,6 +46,7 @@
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
+import android.sysprop.ProductProperties;
import android.text.TextUtils;
import android.util.AndroidRuntimeException;
import android.util.ArrayMap;
@@ -675,7 +676,7 @@
// Shared libraries get a null parent: this has the side effect of having canonicalized
// shared libraries using ApplicationLoaders cache, which is the behavior we want.
- return ApplicationLoaders.getDefault().getClassLoaderWithSharedLibraries(jars,
+ return ApplicationLoaders.getDefault().getSharedLibraryClassLoaderWithSharedLibraries(jars,
mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
libraryPermittedPath, /* parent */ null,
/* classLoaderName */ null, sharedLibraries);
@@ -761,10 +762,13 @@
}
// Similar to vendor apks, we should add /product/lib for apks from product partition
- // and not having /product/lib in the default search path
- final boolean treatProductApkAsUnbundled = !defaultSearchPaths.contains("/product/lib");
+ // when product apps are marked as unbundled. We cannot use the same way from vendor
+ // to check if lib path exists because there is possibility that /product/lib would not
+ // exist from legacy device while product apks are bundled. To make this clear, new
+ // property ("ro.product.apps.unbundled") is defined which should be true only when
+ // product apks are unbundled.
if (mApplicationInfo.getCodePath() != null
- && mApplicationInfo.isProduct() && treatProductApkAsUnbundled
+ && mApplicationInfo.isProduct() && ProductProperties.unbundled_apps().orElse(false)
// TODO(b/128557860): Change target SDK version when version code R is available.
&& getTargetSdkVersion() == Build.VERSION_CODES.CUR_DEVELOPMENT) {
isBundledApp = false;
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index b4330fb..70fa5fa 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -324,7 +324,7 @@
throw new ServiceNotFoundException(Context.TEST_NETWORK_SERVICE);
}
ITestNetworkManager tnMgr = ITestNetworkManager.Stub.asInterface(tnBinder);
- return new TestNetworkManager(context, tnMgr);
+ return new TestNetworkManager(tnMgr);
}
});
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index c4c14d1..6af1096 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -535,7 +535,6 @@
/**
* Intent to broadcast silence mode changed.
* Alway contains the extra field {@link #EXTRA_DEVICE}
- * Alway contains the extra field {@link #EXTRA_SILENCE_ENABLED}
*
* @hide
*/
@@ -545,16 +544,6 @@
"android.bluetooth.device.action.SILENCE_MODE_CHANGED";
/**
- * Used as an extra field in {@link #ACTION_SILENCE_MODE_CHANGED} intent,
- * contains whether device is in silence mode as boolean.
- *
- * @hide
- */
- @SystemApi
- public static final String EXTRA_SILENCE_ENABLED =
- "android.bluetooth.device.extra.SILENCE_ENABLED";
-
- /**
* Used as an extra field in {@link #ACTION_CONNECTION_ACCESS_REQUEST} intent.
*
* @hide
@@ -1615,7 +1604,8 @@
}
/**
- * Set the Bluetooth device silence mode.
+ * Sets whether the {@link BluetoothDevice} enters silence mode. Audio will not
+ * be routed to the {@link BluetoothDevice} if set to {@code true}.
*
* When the {@link BluetoothDevice} enters silence mode, and the {@link BluetoothDevice}
* is an active device (for A2DP or HFP), the active device for that profile
@@ -1635,6 +1625,7 @@
*
* @param silence true to enter silence mode, false to exit
* @return true on success, false on error.
+ * @throws IllegalStateException if Bluetooth is not turned ON.
* @hide
*/
@SystemApi
@@ -1642,12 +1633,9 @@
public boolean setSilenceMode(boolean silence) {
final IBluetooth service = sService;
if (service == null) {
- return false;
+ throw new IllegalStateException("Bluetooth is not turned ON");
}
try {
- if (getSilenceMode() == silence) {
- return true;
- }
return service.setSilenceMode(this, silence);
} catch (RemoteException e) {
Log.e(TAG, "setSilenceMode fail", e);
@@ -1656,24 +1644,25 @@
}
/**
- * Get the device silence mode status
+ * Check whether the {@link BluetoothDevice} is in silence mode
*
* <p> Requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}.
*
* @return true on device in silence mode, otherwise false.
+ * @throws IllegalStateException if Bluetooth is not turned ON.
* @hide
*/
@SystemApi
@RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED)
- public boolean getSilenceMode() {
+ public boolean isInSilenceMode() {
final IBluetooth service = sService;
if (service == null) {
- return false;
+ throw new IllegalStateException("Bluetooth is not turned ON");
}
try {
return service.getSilenceMode(this);
} catch (RemoteException e) {
- Log.e(TAG, "getSilenceMode fail", e);
+ Log.e(TAG, "isInSilenceMode fail", e);
return false;
}
}
diff --git a/core/java/android/bluetooth/BluetoothHealth.java b/core/java/android/bluetooth/BluetoothHealth.java
index e2e56fd..5fd60e0 100644
--- a/core/java/android/bluetooth/BluetoothHealth.java
+++ b/core/java/android/bluetooth/BluetoothHealth.java
@@ -99,6 +99,11 @@
@Deprecated
public static final int CHANNEL_TYPE_STREAMING = 11;
+ /**
+ * Hide auto-created default constructor
+ * @hide
+ */
+ BluetoothHealth() {}
/**
* Register an application configuration that acts as a Health SINK.
diff --git a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
index 9788bbf..e960ed6 100644
--- a/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
+++ b/core/java/android/bluetooth/BluetoothHealthAppConfiguration.java
@@ -33,6 +33,13 @@
*/
@Deprecated
public final class BluetoothHealthAppConfiguration implements Parcelable {
+
+ /**
+ * Hide auto-created default constructor
+ * @hide
+ */
+ BluetoothHealthAppConfiguration() {}
+
@Override
public int describeContents() {
return 0;
diff --git a/core/java/android/bluetooth/le/ScanRecord.java b/core/java/android/bluetooth/le/ScanRecord.java
index 2174255..30868bf 100644
--- a/core/java/android/bluetooth/le/ScanRecord.java
+++ b/core/java/android/bluetooth/le/ScanRecord.java
@@ -16,6 +16,7 @@
package android.bluetooth.le;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UnsupportedAppUsage;
import android.bluetooth.BluetoothUuid;
@@ -97,7 +98,7 @@
* Returns a list of service solicitation UUIDs within the advertisement that are used to
* identify the Bluetooth GATT services.
*/
- @Nullable
+ @NonNull
public List<ParcelUuid> getServiceSolicitationUuids() {
return mServiceSolicitationUuids;
}
@@ -297,9 +298,6 @@
if (serviceUuids.isEmpty()) {
serviceUuids = null;
}
- if (serviceSolicitationUuids.isEmpty()) {
- serviceSolicitationUuids = null;
- }
return new ScanRecord(serviceUuids, serviceSolicitationUuids, manufacturerData,
serviceData, advertiseFlag, txPowerLevel, localName, scanRecord);
} catch (Exception e) {
diff --git a/core/java/android/companion/BluetoothLeDeviceFilter.java b/core/java/android/companion/BluetoothLeDeviceFilter.java
index 1de931e..268640e 100644
--- a/core/java/android/companion/BluetoothLeDeviceFilter.java
+++ b/core/java/android/companion/BluetoothLeDeviceFilter.java
@@ -39,6 +39,8 @@
import com.android.internal.util.ObjectUtils;
import com.android.internal.util.Preconditions;
+import libcore.util.HexEncoding;
+
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.Objects;
@@ -152,7 +154,7 @@
int initial = mRenameBytesReverseOrder ? endInclusive : startInclusive;
int step = mRenameBytesReverseOrder ? -1 : 1;
for (int i = initial; startInclusive <= i && i <= endInclusive; i += step) {
- sb.append(Byte.toHexString(bytes[i], true));
+ sb.append(HexEncoding.encodeToString(bytes[i], true));
}
} else {
sb.append(
diff --git a/core/java/android/hardware/location/ContextHubMessage.java b/core/java/android/hardware/location/ContextHubMessage.java
index e1c69d7..f078ff9 100644
--- a/core/java/android/hardware/location/ContextHubMessage.java
+++ b/core/java/android/hardware/location/ContextHubMessage.java
@@ -20,6 +20,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import libcore.util.HexEncoding;
+
import java.util.Arrays;
/**
@@ -146,7 +148,7 @@
ret += "data = 0x";
}
for (int i = 0; i < Math.min(length, DEBUG_LOG_NUM_BYTES); i++) {
- ret += Byte.toHexString(mData[i], true /* upperCase */);
+ ret += HexEncoding.encodeToString(mData[i], true /* upperCase */);
if ((i + 1) % 4 == 0) {
ret += " ";
diff --git a/core/java/android/hardware/location/NanoAppMessage.java b/core/java/android/hardware/location/NanoAppMessage.java
index 6635258..fec1f71 100644
--- a/core/java/android/hardware/location/NanoAppMessage.java
+++ b/core/java/android/hardware/location/NanoAppMessage.java
@@ -19,6 +19,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import libcore.util.HexEncoding;
+
/**
* A class describing messages send to or from nanoapps through the Context Hub Service.
*
@@ -155,7 +157,7 @@
ret += "data = 0x";
}
for (int i = 0; i < Math.min(length, DEBUG_LOG_NUM_BYTES); i++) {
- ret += Byte.toHexString(mMessageBody[i], true /* upperCase */);
+ ret += HexEncoding.encodeToString(mMessageBody[i], true /* upperCase */);
if ((i + 1) % 4 == 0) {
ret += " ";
diff --git a/core/java/android/net/CaptivePortal.java b/core/java/android/net/CaptivePortal.java
index db19515..25e111e 100644
--- a/core/java/android/net/CaptivePortal.java
+++ b/core/java/android/net/CaptivePortal.java
@@ -137,6 +137,8 @@
/**
* Log a captive portal login event.
+ * @param eventId one of the CAPTIVE_PORTAL_LOGIN_* constants in metrics_constants.proto.
+ * @param packageName captive portal application package name.
* @hide
*/
@SystemApi
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 4a64128..2906710 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2617,7 +2617,7 @@
/**
* Start listening to tethering change events. Any new added callback will receive the last
- * tethering status right away. If callback is registered when tethering loses its upstream or
+ * tethering status right away. If callback is registered when tethering has no upstream or
* disabled, {@link OnTetheringEventCallback#onUpstreamChanged} will immediately be called
* with a null argument. The same callback object cannot be registered twice.
*
@@ -3234,7 +3234,7 @@
*
* @hide
*/
- public void onPreCheck(Network network) {}
+ public void onPreCheck(@NonNull Network network) {}
/**
* Called when the framework connects and has declared a new network ready for use.
@@ -3247,8 +3247,9 @@
* @param blocked Whether access to the {@link Network} is blocked due to system policy.
* @hide
*/
- public void onAvailable(Network network, NetworkCapabilities networkCapabilities,
- LinkProperties linkProperties, boolean blocked) {
+ public void onAvailable(@NonNull Network network,
+ @NonNull NetworkCapabilities networkCapabilities,
+ @NonNull LinkProperties linkProperties, boolean blocked) {
// Internally only this method is called when a new network is available, and
// it calls the callback in the same way and order that older versions used
// to call so as not to change the behavior.
@@ -3272,7 +3273,7 @@
*
* @param network The {@link Network} of the satisfying network.
*/
- public void onAvailable(Network network) {}
+ public void onAvailable(@NonNull Network network) {}
/**
* Called when the network is about to be disconnected. Often paired with an
@@ -3288,7 +3289,7 @@
* network connected. Note that the network may suffer a
* hard loss at any time.
*/
- public void onLosing(Network network, int maxMsToLive) {}
+ public void onLosing(@NonNull Network network, int maxMsToLive) {}
/**
* Called when the framework has a hard loss of the network or when the
@@ -3296,7 +3297,7 @@
*
* @param network The {@link Network} lost.
*/
- public void onLost(Network network) {}
+ public void onLost(@NonNull Network network) {}
/**
* Called if no network is found in the timeout time specified in
@@ -3316,8 +3317,8 @@
* @param networkCapabilities The new {@link android.net.NetworkCapabilities} for this
* network.
*/
- public void onCapabilitiesChanged(Network network,
- NetworkCapabilities networkCapabilities) {}
+ public void onCapabilitiesChanged(@NonNull Network network,
+ @NonNull NetworkCapabilities networkCapabilities) {}
/**
* Called when the network the framework connected to for this request
@@ -3326,7 +3327,8 @@
* @param network The {@link Network} whose link properties have changed.
* @param linkProperties The new {@link LinkProperties} for this network.
*/
- public void onLinkPropertiesChanged(Network network, LinkProperties linkProperties) {}
+ public void onLinkPropertiesChanged(@NonNull Network network,
+ @NonNull LinkProperties linkProperties) {}
/**
* Called when the network the framework connected to for this request
@@ -3337,7 +3339,7 @@
* a tunnel, etc.
* @hide
*/
- public void onNetworkSuspended(Network network) {}
+ public void onNetworkSuspended(@NonNull Network network) {}
/**
* Called when the network the framework connected to for this request
@@ -3345,7 +3347,7 @@
* preceded by a matching {@link NetworkCallback#onNetworkSuspended} call.
* @hide
*/
- public void onNetworkResumed(Network network) {}
+ public void onNetworkResumed(@NonNull Network network) {}
/**
* Called when access to the specified network is blocked or unblocked.
diff --git a/core/java/android/net/DhcpResults.java b/core/java/android/net/DhcpResults.java
index 6f9e65f..a33f3fc 100644
--- a/core/java/android/net/DhcpResults.java
+++ b/core/java/android/net/DhcpResults.java
@@ -72,15 +72,12 @@
* Create a {@link StaticIpConfiguration} based on the DhcpResults.
*/
public StaticIpConfiguration toStaticIpConfiguration() {
- final StaticIpConfiguration s = new StaticIpConfiguration();
- // All these except dnsServers are immutable, so no need to make copies.
- s.setIpAddress(ipAddress);
- s.setGateway(gateway);
- for (InetAddress addr : dnsServers) {
- s.addDnsServer(addr);
- }
- s.setDomains(domains);
- return s;
+ return new StaticIpConfiguration.Builder()
+ .setIpAddress(ipAddress)
+ .setGateway(gateway)
+ .setDnsServers(dnsServers)
+ .setDomains(domains)
+ .build();
}
public DhcpResults(StaticIpConfiguration source) {
diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java
index 06c32c6..b6c4fe2 100644
--- a/core/java/android/net/DnsResolver.java
+++ b/core/java/android/net/DnsResolver.java
@@ -93,6 +93,23 @@
public static final int FLAG_NO_CACHE_STORE = 1 << 1;
public static final int FLAG_NO_CACHE_LOOKUP = 1 << 2;
+ @IntDef(prefix = { "ERROR_" }, value = {
+ ERROR_PARSE,
+ ERROR_SYSTEM
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface DnsError {}
+ /**
+ * Indicates that there was an error parsing the response the query.
+ * The cause of this error is available via getCause() and is a ParseException.
+ */
+ public static final int ERROR_PARSE = 0;
+ /**
+ * Indicates that there was an error sending the query.
+ * The cause of this error is available via getCause() and is an ErrnoException.
+ */
+ public static final int ERROR_SYSTEM = 1;
+
private static final int NETID_UNSET = 0;
private static final DnsResolver sInstance = new DnsResolver();
@@ -107,97 +124,57 @@
private DnsResolver() {}
/**
- * Answer parser for parsing raw answers
+ * Base interface for answer callbacks
*
- * @param <T> The type of the parsed answer
+ * @param <T> The type of the answer
*/
- public interface AnswerParser<T> {
- /**
- * Creates a <T> answer by parsing the given raw answer.
- *
- * @param rawAnswer the raw answer to be parsed
- * @return a parsed <T> answer
- * @throws ParseException if parsing failed
- */
- @NonNull T parse(@NonNull byte[] rawAnswer) throws ParseException;
- }
-
- /**
- * Base class for answer callbacks
- *
- * @param <T> The type of the parsed answer
- */
- public abstract static class AnswerCallback<T> {
- /** @hide */
- public final AnswerParser<T> parser;
-
- public AnswerCallback(@NonNull AnswerParser<T> parser) {
- this.parser = parser;
- };
-
+ public interface Callback<T> {
/**
* Success response to
- * {@link android.net.DnsResolver#query query()}.
+ * {@link android.net.DnsResolver#query query()} or
+ * {@link android.net.DnsResolver#rawQuery rawQuery()}.
*
* Invoked when the answer to a query was successfully parsed.
*
- * @param answer parsed answer to the query.
+ * @param answer <T> answer to the query.
+ * @param rcode The response code in the DNS response.
*
* {@see android.net.DnsResolver#query query()}
*/
- public abstract void onAnswer(@NonNull T answer);
-
+ void onAnswer(@NonNull T answer, int rcode);
/**
* Error response to
- * {@link android.net.DnsResolver#query query()}.
+ * {@link android.net.DnsResolver#query query()} or
+ * {@link android.net.DnsResolver#rawQuery rawQuery()}.
*
* Invoked when there is no valid answer to
* {@link android.net.DnsResolver#query query()}
+ * {@link android.net.DnsResolver#rawQuery rawQuery()}.
*
- * @param exception a {@link ParseException} object with additional
+ * @param error a {@link DnsException} object with additional
* detail regarding the failure
*/
- public abstract void onParseException(@NonNull ParseException exception);
-
- /**
- * Error response to
- * {@link android.net.DnsResolver#query query()}.
- *
- * Invoked if an error happens when
- * issuing the DNS query or receiving the result.
- * {@link android.net.DnsResolver#query query()}
- *
- * @param exception an {@link ErrnoException} object with additional detail
- * regarding the failure
- */
- public abstract void onQueryException(@NonNull ErrnoException exception);
+ void onError(@NonNull DnsException error);
}
/**
- * Callback for receiving raw answers
+ * Class to represent DNS error
*/
- public abstract static class RawAnswerCallback extends AnswerCallback<byte[]> {
- public RawAnswerCallback() {
- super(rawAnswer -> rawAnswer);
- }
- }
+ public static class DnsException extends Exception {
+ /**
+ * DNS error code as one of the ERROR_* constants
+ */
+ @DnsError public final int code;
- /**
- * Callback for receiving parsed {@link InetAddress} answers
- *
- * Note that if the answer does not contain any IP addresses,
- * onAnswer will be called with an empty list.
- */
- public abstract static class InetAddressAnswerCallback
- extends AnswerCallback<List<InetAddress>> {
- public InetAddressAnswerCallback() {
- super(rawAnswer -> new DnsAddressAnswer(rawAnswer).getAddresses());
+ DnsException(@DnsError int code, @Nullable Throwable cause) {
+ super(cause);
+ this.code = code;
}
}
/**
* Send a raw DNS query.
- * The answer will be provided asynchronously through the provided {@link AnswerCallback}.
+ * The answer will be provided asynchronously through the provided {@link Callback}.
*
* @param network {@link Network} specifying which network to query on.
* {@code null} for query on default network.
@@ -206,13 +183,13 @@
* @param executor The {@link Executor} that the callback should be executed on.
* @param cancellationSignal used by the caller to signal if the query should be
* cancelled. May be {@code null}.
- * @param callback an {@link AnswerCallback} which will be called to notify the caller
+ * @param callback a {@link Callback} which will be called to notify the caller
* of the result of dns query.
*/
- public <T> void query(@Nullable Network network, @NonNull byte[] query, @QueryFlag int flags,
+ public void rawQuery(@Nullable Network network, @NonNull byte[] query, @QueryFlag int flags,
@NonNull @CallbackExecutor Executor executor,
@Nullable CancellationSignal cancellationSignal,
- @NonNull AnswerCallback<T> callback) {
+ @NonNull Callback<? super byte[]> callback) {
if (cancellationSignal != null && cancellationSignal.isCanceled()) {
return;
}
@@ -222,9 +199,7 @@
queryfd = resNetworkSend((network != null
? network.netId : NETID_UNSET), query, query.length, flags);
} catch (ErrnoException e) {
- executor.execute(() -> {
- callback.onQueryException(e);
- });
+ executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
return;
}
@@ -237,7 +212,7 @@
/**
* Send a DNS query with the specified name, class and query type.
- * The answer will be provided asynchronously through the provided {@link AnswerCallback}.
+ * The answer will be provided asynchronously through the provided {@link Callback}.
*
* @param network {@link Network} specifying which network to query on.
* {@code null} for query on default network.
@@ -248,14 +223,14 @@
* @param executor The {@link Executor} that the callback should be executed on.
* @param cancellationSignal used by the caller to signal if the query should be
* cancelled. May be {@code null}.
- * @param callback an {@link AnswerCallback} which will be called to notify the caller
+ * @param callback a {@link Callback} which will be called to notify the caller
* of the result of dns query.
*/
- public <T> void query(@Nullable Network network, @NonNull String domain,
+ public void rawQuery(@Nullable Network network, @NonNull String domain,
@QueryClass int nsClass, @QueryType int nsType, @QueryFlag int flags,
@NonNull @CallbackExecutor Executor executor,
@Nullable CancellationSignal cancellationSignal,
- @NonNull AnswerCallback<T> callback) {
+ @NonNull Callback<? super byte[]> callback) {
if (cancellationSignal != null && cancellationSignal.isCanceled()) {
return;
}
@@ -265,9 +240,7 @@
queryfd = resNetworkQuery((network != null
? network.netId : NETID_UNSET), domain, nsClass, nsType, flags);
} catch (ErrnoException e) {
- executor.execute(() -> {
- callback.onQueryException(e);
- });
+ executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
return;
}
synchronized (lock) {
@@ -277,27 +250,28 @@
}
}
- private class InetAddressAnswerAccumulator extends InetAddressAnswerCallback {
+ private class InetAddressAnswerAccumulator implements Callback<byte[]> {
private final List<InetAddress> mAllAnswers;
- private ParseException mParseException;
- private ErrnoException mErrnoException;
- private final InetAddressAnswerCallback mUserCallback;
+ private int mRcode;
+ private DnsException mDnsException;
+ private final Callback<? super List<InetAddress>> mUserCallback;
private final int mTargetAnswerCount;
private int mReceivedAnswerCount = 0;
- InetAddressAnswerAccumulator(int size, @NonNull InetAddressAnswerCallback callback) {
+ InetAddressAnswerAccumulator(int size,
+ @NonNull Callback<? super List<InetAddress>> callback) {
mTargetAnswerCount = size;
mAllAnswers = new ArrayList<>();
mUserCallback = callback;
}
- private boolean maybeReportException() {
- if (mErrnoException != null) {
- mUserCallback.onQueryException(mErrnoException);
+ private boolean maybeReportError() {
+ if (mRcode != 0) {
+ mUserCallback.onAnswer(mAllAnswers, mRcode);
return true;
}
- if (mParseException != null) {
- mUserCallback.onParseException(mParseException);
+ if (mDnsException != null) {
+ mUserCallback.onError(mDnsException);
return true;
}
return false;
@@ -305,34 +279,43 @@
private void maybeReportAnswer() {
if (++mReceivedAnswerCount != mTargetAnswerCount) return;
- if (mAllAnswers.isEmpty() && maybeReportException()) return;
+ if (mAllAnswers.isEmpty() && maybeReportError()) return;
// TODO: Do RFC6724 sort.
- mUserCallback.onAnswer(mAllAnswers);
+ mUserCallback.onAnswer(mAllAnswers, mRcode);
}
@Override
- public void onAnswer(@NonNull List<InetAddress> answer) {
- mAllAnswers.addAll(answer);
+ public void onAnswer(@NonNull byte[] answer, int rcode) {
+ // If at least one query succeeded, return an rcode of 0.
+ // Otherwise, arbitrarily return the first rcode received.
+ if (mReceivedAnswerCount == 0 || rcode == 0) {
+ mRcode = rcode;
+ }
+ try {
+ mAllAnswers.addAll(new DnsAddressAnswer(answer).getAddresses());
+ } catch (ParseException e) {
+ mDnsException = new DnsException(ERROR_PARSE, e);
+ }
maybeReportAnswer();
}
@Override
- public void onParseException(@NonNull ParseException e) {
- mParseException = e;
- maybeReportAnswer();
- }
-
- @Override
- public void onQueryException(@NonNull ErrnoException e) {
- mErrnoException = e;
+ public void onError(@NonNull DnsException error) {
+ mDnsException = error;
maybeReportAnswer();
}
}
/**
- * Send a DNS query with the specified name, get back a set of InetAddresses asynchronously.
- * The answer will be provided asynchronously through the provided
- * {@link InetAddressAnswerCallback}.
+ * Send a DNS query with the specified name on a network with both IPv4 and IPv6,
+ * get back a set of InetAddresses asynchronously.
+ *
+ * This method will examine the connection ability on given network, and query IPv4
+ * and IPv6 if connection is available.
+ *
+ * If at least one query succeeded with valid answer, rcode will be 0
+ *
+ * The answer will be provided asynchronously through the provided {@link Callback}.
*
* @param network {@link Network} specifying which network to query on.
* {@code null} for query on default network.
@@ -341,13 +324,13 @@
* @param executor The {@link Executor} that the callback should be executed on.
* @param cancellationSignal used by the caller to signal if the query should be
* cancelled. May be {@code null}.
- * @param callback an {@link InetAddressAnswerCallback} which will be called to notify the
+ * @param callback a {@link Callback} which will be called to notify the
* caller of the result of dns query.
*/
public void query(@Nullable Network network, @NonNull String domain, @QueryFlag int flags,
@NonNull @CallbackExecutor Executor executor,
@Nullable CancellationSignal cancellationSignal,
- @NonNull InetAddressAnswerCallback callback) {
+ @NonNull Callback<? super List<InetAddress>> callback) {
if (cancellationSignal != null && cancellationSignal.isCanceled()) {
return;
}
@@ -365,9 +348,7 @@
v6fd = resNetworkQuery((network != null
? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_AAAA, flags);
} catch (ErrnoException e) {
- executor.execute(() -> {
- callback.onQueryException(e);
- });
+ executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
return;
}
queryCount++;
@@ -377,7 +358,9 @@
// Avoiding gateways drop packets if queries are sent too close together
try {
Thread.sleep(SLEEP_TIME_MS);
- } catch (InterruptedException ex) { }
+ } catch (InterruptedException ex) {
+ Thread.currentThread().interrupt();
+ }
if (queryIpv4) {
try {
@@ -385,9 +368,7 @@
? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_A, flags);
} catch (ErrnoException e) {
if (queryIpv6) resNetworkCancel(v6fd); // Closes fd, marks it invalid.
- executor.execute(() -> {
- callback.onQueryException(e);
- });
+ executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
return;
}
queryCount++;
@@ -413,34 +394,89 @@
}
}
- private <T> void registerFDListener(@NonNull Executor executor,
- @NonNull FileDescriptor queryfd, @NonNull AnswerCallback<T> answerCallback,
+ /**
+ * Send a DNS query with the specified name and query type, get back a set of
+ * InetAddresses asynchronously.
+ *
+ * The answer will be provided asynchronously through the provided {@link Callback}.
+ *
+ * @param network {@link Network} specifying which network to query on.
+ * {@code null} for query on default network.
+ * @param domain domain name to query
+ * @param nsType dns resource record (RR) type as one of the TYPE_* constants
+ * @param flags flags as a combination of the FLAGS_* constants
+ * @param executor The {@link Executor} that the callback should be executed on.
+ * @param cancellationSignal used by the caller to signal if the query should be
+ * cancelled. May be {@code null}.
+ * @param callback a {@link Callback} which will be called to notify the caller
+ * of the result of dns query.
+ */
+ public void query(@Nullable Network network, @NonNull String domain,
+ @QueryType int nsType, @QueryFlag int flags,
+ @NonNull @CallbackExecutor Executor executor,
+ @Nullable CancellationSignal cancellationSignal,
+ @NonNull Callback<? super List<InetAddress>> callback) {
+ if (cancellationSignal != null && cancellationSignal.isCanceled()) {
+ return;
+ }
+ final Object lock = new Object();
+ final FileDescriptor queryfd;
+ try {
+ queryfd = resNetworkQuery((network != null
+ ? network.netId : NETID_UNSET), domain, CLASS_IN, nsType, flags);
+ } catch (ErrnoException e) {
+ executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
+ return;
+ }
+ final InetAddressAnswerAccumulator accumulator =
+ new InetAddressAnswerAccumulator(1, callback);
+ synchronized (lock) {
+ registerFDListener(executor, queryfd, accumulator, cancellationSignal, lock);
+ if (cancellationSignal == null) return;
+ addCancellationSignal(cancellationSignal, queryfd, lock);
+ }
+ }
+
+ /**
+ * Class to retrieve DNS response
+ *
+ * @hide
+ */
+ public static final class DnsResponse {
+ public final @NonNull byte[] answerbuf;
+ public final int rcode;
+ public DnsResponse(@NonNull byte[] answerbuf, int rcode) {
+ this.answerbuf = answerbuf;
+ this.rcode = rcode;
+ }
+ }
+
+ private void registerFDListener(@NonNull Executor executor,
+ @NonNull FileDescriptor queryfd, @NonNull Callback<? super byte[]> answerCallback,
@Nullable CancellationSignal cancellationSignal, @NonNull Object lock) {
Looper.getMainLooper().getQueue().addOnFileDescriptorEventListener(
queryfd,
FD_EVENTS,
(fd, events) -> {
executor.execute(() -> {
+ DnsResponse resp = null;
+ ErrnoException exception = null;
synchronized (lock) {
if (cancellationSignal != null && cancellationSignal.isCanceled()) {
return;
}
- byte[] answerbuf = null;
try {
- answerbuf = resNetworkResult(fd); // Closes fd, marks it invalid.
+ resp = resNetworkResult(fd); // Closes fd, marks it invalid.
} catch (ErrnoException e) {
Log.e(TAG, "resNetworkResult:" + e.toString());
- answerCallback.onQueryException(e);
- return;
- }
-
- try {
- answerCallback.onAnswer(
- answerCallback.parser.parse(answerbuf));
- } catch (ParseException e) {
- answerCallback.onParseException(e);
+ exception = e;
}
}
+ if (exception != null) {
+ answerCallback.onError(new DnsException(ERROR_SYSTEM, exception));
+ return;
+ }
+ answerCallback.onAnswer(resp.answerbuf, resp.rcode);
});
// Unregister this fd listener
return 0;
diff --git a/core/java/android/net/ITestNetworkManager.aidl b/core/java/android/net/ITestNetworkManager.aidl
index 119a30c..bab6ae8 100644
--- a/core/java/android/net/ITestNetworkManager.aidl
+++ b/core/java/android/net/ITestNetworkManager.aidl
@@ -29,6 +29,7 @@
interface ITestNetworkManager
{
TestNetworkInterface createTunInterface(in LinkAddress[] linkAddrs);
+ TestNetworkInterface createTapInterface();
void setupTestNetwork(in String iface, in IBinder binder);
diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java
index b4f3a28..416157c 100644
--- a/core/java/android/net/IpPrefix.java
+++ b/core/java/android/net/IpPrefix.java
@@ -16,6 +16,7 @@
package android.net;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.TestApi;
@@ -71,7 +72,7 @@
*
* @hide
*/
- public IpPrefix(@NonNull byte[] address, int prefixLength) {
+ public IpPrefix(@NonNull byte[] address, @IntRange(from = 0, to = 128) int prefixLength) {
this.address = address.clone();
this.prefixLength = prefixLength;
checkAndMaskAddressAndPrefixLength();
@@ -88,7 +89,7 @@
*/
@SystemApi
@TestApi
- public IpPrefix(@NonNull InetAddress address, int prefixLength) {
+ public IpPrefix(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength) {
// We don't reuse the (byte[], int) constructor because it calls clone() on the byte array,
// which is unnecessary because getAddress() already returns a clone.
this.address = address.getAddress();
@@ -150,13 +151,13 @@
*
* @return the address in the form of a byte array.
*/
- public InetAddress getAddress() {
+ public @NonNull InetAddress getAddress() {
try {
return InetAddress.getByAddress(address);
} catch (UnknownHostException e) {
// Cannot happen. InetAddress.getByAddress can only throw an exception if the byte
// array is the wrong length, but we check that in the constructor.
- return null;
+ throw new IllegalArgumentException("Address is invalid");
}
}
@@ -166,7 +167,7 @@
*
* @return the address in the form of a byte array.
*/
- public byte[] getRawAddress() {
+ public @NonNull byte[] getRawAddress() {
return address.clone();
}
@@ -175,6 +176,7 @@
*
* @return the prefix length.
*/
+ @IntRange(from = 0, to = 128)
public int getPrefixLength() {
return prefixLength;
}
@@ -183,10 +185,10 @@
* Determines whether the prefix contains the specified address.
*
* @param address An {@link InetAddress} to test.
- * @return {@code true} if the prefix covers the given address.
+ * @return {@code true} if the prefix covers the given address. {@code false} otherwise.
*/
- public boolean contains(InetAddress address) {
- byte[] addrBytes = (address == null) ? null : address.getAddress();
+ public boolean contains(@NonNull InetAddress address) {
+ byte[] addrBytes = address.getAddress();
if (addrBytes == null || addrBytes.length != this.address.length) {
return false;
}
@@ -201,7 +203,7 @@
* @param otherPrefix the prefix to test
* @hide
*/
- public boolean containsPrefix(IpPrefix otherPrefix) {
+ public boolean containsPrefix(@NonNull IpPrefix otherPrefix) {
if (otherPrefix.getPrefixLength() < prefixLength) return false;
final byte[] otherAddress = otherPrefix.getRawAddress();
NetworkUtils.maskRawAddress(otherAddress, prefixLength);
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index 78b4665..f17adea 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -25,6 +25,7 @@
import static android.system.OsConstants.RT_SCOPE_SITE;
import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
@@ -170,7 +171,7 @@
* Constructs a new {@code LinkAddress} from an {@code InetAddress} and prefix length, with
* the specified flags and scope. Flags and scope are not checked for validity.
* @param address The IP address.
- * @param prefixLength The prefix length.
+ * @param prefixLength The prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6).
* @param flags A bitmask of {@code IFA_F_*} values representing properties of the address.
* @param scope An integer defining the scope in which the address is unique (e.g.,
* {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}).
@@ -178,7 +179,8 @@
*/
@SystemApi
@TestApi
- public LinkAddress(InetAddress address, int prefixLength, int flags, int scope) {
+ public LinkAddress(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength,
+ int flags, int scope) {
init(address, prefixLength, flags, scope);
}
@@ -186,12 +188,13 @@
* Constructs a new {@code LinkAddress} from an {@code InetAddress} and a prefix length.
* The flags are set to zero and the scope is determined from the address.
* @param address The IP address.
- * @param prefixLength The prefix length.
+ * @param prefixLength The prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6).
* @hide
*/
@SystemApi
@TestApi
- public LinkAddress(@NonNull InetAddress address, int prefixLength) {
+ public LinkAddress(@NonNull InetAddress address,
+ @IntRange(from = 0, to = 128) int prefixLength) {
this(address, prefixLength, 0, 0);
this.scope = scopeForUnicastAddress(address);
}
@@ -202,7 +205,7 @@
* @param interfaceAddress The interface address.
* @hide
*/
- public LinkAddress(InterfaceAddress interfaceAddress) {
+ public LinkAddress(@NonNull InterfaceAddress interfaceAddress) {
this(interfaceAddress.getAddress(),
interfaceAddress.getNetworkPrefixLength());
}
@@ -306,6 +309,7 @@
/**
* Returns the prefix length of this {@code LinkAddress}.
*/
+ @IntRange(from = 0, to = 128)
public int getPrefixLength() {
return prefixLength;
}
@@ -316,6 +320,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @IntRange(from = 0, to = 128)
public int getNetworkPrefixLength() {
return getPrefixLength();
}
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 03d6d48..ad67763 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -316,9 +316,6 @@
@SystemApi
@TestApi
public boolean removeLinkAddress(@NonNull LinkAddress toRemove) {
- if (toRemove == null) {
- return false;
- }
int i = findLinkAddressIndex(toRemove);
if (i >= 0) {
mLinkAddresses.remove(i);
@@ -391,10 +388,7 @@
@TestApi
@SystemApi
public boolean removeDnsServer(@NonNull InetAddress dnsServer) {
- if (dnsServer != null) {
- return mDnses.remove(dnsServer);
- }
- return false;
+ return mDnses.remove(dnsServer);
}
/**
diff --git a/core/java/android/net/NetworkCapabilities.aidl b/core/java/android/net/NetworkCapabilities.aidl
index cd7d71c..01d3286 100644
--- a/core/java/android/net/NetworkCapabilities.aidl
+++ b/core/java/android/net/NetworkCapabilities.aidl
@@ -17,5 +17,5 @@
package android.net;
-parcelable NetworkCapabilities;
+@JavaOnlyStableParcelable parcelable NetworkCapabilities;
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 99375f8..dfd7089 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -822,6 +822,11 @@
mEstablishingVpnAppUid = uid;
}
+ /** @hide */
+ public int getEstablishingVpnAppUid() {
+ return mEstablishingVpnAppUid;
+ }
+
/**
* Value indicating that link bandwidth is unspecified.
* @hide
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 3a41a07..acafa13 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -17,6 +17,7 @@
package android.net;
import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.net.NetworkCapabilities.NetCapability;
@@ -343,10 +344,14 @@
* current value. A value of {@code SIGNAL_STRENGTH_UNSPECIFIED} means no value when
* received and has no effect when requesting a callback.
*
+ * <p>This method requires the caller to hold the
+ * {@link android.Manifest.permission#NETWORK_SIGNAL_STRENGTH_WAKEUP} permission
+ *
* @param signalStrength the bearer-specific signal strength.
* @hide
*/
@SystemApi
+ @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP)
public @NonNull Builder setSignalStrength(int signalStrength) {
mNetworkCapabilities.setSignalStrength(signalStrength);
return this;
diff --git a/core/java/android/net/NetworkStack.java b/core/java/android/net/NetworkStack.java
index dbb894f..a46c410 100644
--- a/core/java/android/net/NetworkStack.java
+++ b/core/java/android/net/NetworkStack.java
@@ -15,9 +15,16 @@
*/
package android.net;
+import static android.Manifest.permission.NETWORK_STACK;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.content.Context;
+import java.util.ArrayList;
+import java.util.Arrays;
/**
*
* Constants for client code communicating with the network stack service.
@@ -37,4 +44,52 @@
"android.permission.MAINLINE_NETWORK_STACK";
private NetworkStack() {}
+
+ /**
+ * If the NetworkStack, MAINLINE_NETWORK_STACK are not allowed for a particular process, throw a
+ * {@link SecurityException}.
+ *
+ * @param context {@link android.content.Context} for the process.
+ *
+ * @hide
+ */
+ public static void checkNetworkStackPermission(final @NonNull Context context) {
+ checkNetworkStackPermissionOr(context);
+ }
+
+ /**
+ * If the NetworkStack, MAINLINE_NETWORK_STACK or other specified permissions are not allowed
+ * for a particular process, throw a {@link SecurityException}.
+ *
+ * @param context {@link android.content.Context} for the process.
+ * @param otherPermissions The set of permissions that could be the candidate permissions , or
+ * empty string if none of other permissions needed.
+ * @hide
+ */
+ public static void checkNetworkStackPermissionOr(final @NonNull Context context,
+ final @NonNull String... otherPermissions) {
+ ArrayList<String> permissions = new ArrayList<String>(Arrays.asList(otherPermissions));
+ permissions.add(NETWORK_STACK);
+ permissions.add(PERMISSION_MAINLINE_NETWORK_STACK);
+ enforceAnyPermissionOf(context, permissions.toArray(new String[0]));
+ }
+
+ private static void enforceAnyPermissionOf(final @NonNull Context context,
+ final @NonNull String... permissions) {
+ if (!checkAnyPermissionOf(context, permissions)) {
+ throw new SecurityException("Requires one of the following permissions: "
+ + String.join(", ", permissions) + ".");
+ }
+ }
+
+ private static boolean checkAnyPermissionOf(final @NonNull Context context,
+ final @NonNull String... permissions) {
+ for (String permission : permissions) {
+ if (context.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
+ return true;
+ }
+ }
+ return false;
+ }
+
}
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index d2d886b..d07ff13 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -24,7 +24,6 @@
import android.util.Pair;
import java.io.FileDescriptor;
-import java.io.IOException;
import java.math.BigInteger;
import java.net.Inet4Address;
import java.net.Inet6Address;
@@ -45,32 +44,6 @@
private static final String TAG = "NetworkUtils";
/**
- * Attaches a socket filter that accepts DHCP packets to the given socket.
- */
- @UnsupportedAppUsage
- public native static void attachDhcpFilter(FileDescriptor fd) throws SocketException;
-
- /**
- * Attaches a socket filter that accepts ICMPv6 router advertisements to the given socket.
- * @param fd the socket's {@link FileDescriptor}.
- * @param packetType the hardware address type, one of ARPHRD_*.
- */
- @UnsupportedAppUsage
- public native static void attachRaFilter(FileDescriptor fd, int packetType) throws SocketException;
-
- /**
- * Attaches a socket filter that accepts L2-L4 signaling traffic required for IP connectivity.
- *
- * This includes: all ARP, ICMPv6 RS/RA/NS/NA messages, and DHCPv4 exchanges.
- *
- * @param fd the socket's {@link FileDescriptor}.
- * @param packetType the hardware address type, one of ARPHRD_*.
- */
- @UnsupportedAppUsage
- public native static void attachControlPacketFilter(FileDescriptor fd, int packetType)
- throws SocketException;
-
- /**
* Attaches a socket filter that drops all of incoming packets.
* @param fd the socket's {@link FileDescriptor}.
*/
@@ -167,9 +140,10 @@
/**
* DNS resolver series jni method.
* Read a result for the query associated with the {@code fd}.
- * @return a byte array containing blob answer
+ * @return DnsResponse containing blob answer and rcode
*/
- public static native byte[] resNetworkResult(FileDescriptor fd) throws ErrnoException;
+ public static native DnsResolver.DnsResponse resNetworkResult(FileDescriptor fd)
+ throws ErrnoException;
/**
* DNS resolver series jni method.
@@ -178,18 +152,6 @@
public static native void resNetworkCancel(FileDescriptor fd);
/**
- * Add an entry into the ARP cache.
- */
- public static void addArpEntry(Inet4Address ipv4Addr, MacAddress ethAddr, String ifname,
- FileDescriptor fd) throws IOException {
- addArpEntry(ethAddr.toByteArray(), ipv4Addr.getAddress(), ifname, fd);
- }
-
- private static native void addArpEntry(byte[] ethAddr, byte[] netAddr, String ifname,
- FileDescriptor fd) throws IOException;
-
-
- /**
* Get the tcp repair window associated with the {@code fd}.
*
* @param fd the tcp socket's {@link FileDescriptor}.
diff --git a/core/java/android/net/ParseException.java b/core/java/android/net/ParseException.java
index 9d4727a..bcfdd7e 100644
--- a/core/java/android/net/ParseException.java
+++ b/core/java/android/net/ParseException.java
@@ -25,12 +25,12 @@
public class ParseException extends RuntimeException {
public String response;
- public ParseException(@NonNull String response) {
+ ParseException(@NonNull String response) {
super(response);
this.response = response;
}
- public ParseException(@NonNull String response, @NonNull Throwable cause) {
+ ParseException(@NonNull String response, @NonNull Throwable cause) {
super(response, cause);
this.response = response;
}
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index 24d9b8e..fdd904a 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -16,6 +16,8 @@
package android.net;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
@@ -24,6 +26,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
@@ -51,20 +55,32 @@
* (IPv4 or IPv6).
*/
public final class RouteInfo implements Parcelable {
+ /** @hide */
+ @IntDef(value = {
+ RTN_UNICAST,
+ RTN_UNREACHABLE,
+ RTN_THROW,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface RouteType {}
+
/**
* The IP destination address for this route.
*/
+ @NonNull
private final IpPrefix mDestination;
/**
* The gateway address for this route.
*/
@UnsupportedAppUsage
+ @Nullable
private final InetAddress mGateway;
/**
* The interface for this route.
*/
+ @Nullable
private final String mInterface;
@@ -108,13 +124,14 @@
* @param destination the destination prefix
* @param gateway the IP address to route packets through
* @param iface the interface name to send packets on
+ * @param type the type of this route
*
* @hide
*/
@SystemApi
@TestApi
public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway,
- @Nullable String iface, int type) {
+ @Nullable String iface, @RouteType int type) {
switch (type) {
case RTN_UNICAST:
case RTN_UNREACHABLE:
@@ -173,10 +190,24 @@
}
/**
- * @hide
+ * Constructs a {@code RouteInfo} object.
+ *
+ * If destination is null, then gateway must be specified and the
+ * constructed route is either the IPv4 default route <code>0.0.0.0</code>
+ * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default
+ * route <code>::/0</code> if gateway is an instance of {@link Inet6Address}.
+ * <p>
+ * Destination and gateway may not both be null.
+ *
+ * @param destination the destination address and prefix in an {@link IpPrefix}
+ * @param gateway the {@link InetAddress} to route packets through
+ * @param iface the interface name to send packets on
+ *
+ * @hide
*/
@UnsupportedAppUsage
- public RouteInfo(IpPrefix destination, InetAddress gateway, String iface) {
+ public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway,
+ @Nullable String iface) {
this(destination, gateway, iface, RTN_UNICAST);
}
@@ -184,7 +215,8 @@
* @hide
*/
@UnsupportedAppUsage
- public RouteInfo(LinkAddress destination, InetAddress gateway, String iface) {
+ public RouteInfo(@Nullable LinkAddress destination, @Nullable InetAddress gateway,
+ @Nullable String iface) {
this(destination == null ? null :
new IpPrefix(destination.getAddress(), destination.getPrefixLength()),
gateway, iface);
@@ -205,7 +237,7 @@
*
* @hide
*/
- public RouteInfo(IpPrefix destination, InetAddress gateway) {
+ public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway) {
this(destination, gateway, null);
}
@@ -215,7 +247,7 @@
* TODO: Remove this.
*/
@UnsupportedAppUsage
- public RouteInfo(LinkAddress destination, InetAddress gateway) {
+ public RouteInfo(@Nullable LinkAddress destination, @Nullable InetAddress gateway) {
this(destination, gateway, null);
}
@@ -227,7 +259,7 @@
* @hide
*/
@UnsupportedAppUsage
- public RouteInfo(InetAddress gateway) {
+ public RouteInfo(@NonNull InetAddress gateway) {
this((IpPrefix) null, gateway, null);
}
@@ -239,35 +271,36 @@
*
* @hide
*/
- public RouteInfo(IpPrefix destination) {
+ public RouteInfo(@NonNull IpPrefix destination) {
this(destination, null, null);
}
/**
* @hide
*/
- public RouteInfo(LinkAddress destination) {
+ public RouteInfo(@NonNull LinkAddress destination) {
this(destination, null, null);
}
/**
* @hide
*/
- public RouteInfo(IpPrefix destination, int type) {
+ public RouteInfo(@NonNull IpPrefix destination, @RouteType int type) {
this(destination, null, null, type);
}
/**
* @hide
*/
- public static RouteInfo makeHostRoute(InetAddress host, String iface) {
+ public static RouteInfo makeHostRoute(@NonNull InetAddress host, @Nullable String iface) {
return makeHostRoute(host, null, iface);
}
/**
* @hide
*/
- public static RouteInfo makeHostRoute(InetAddress host, InetAddress gateway, String iface) {
+ public static RouteInfo makeHostRoute(@Nullable InetAddress host, @Nullable InetAddress gateway,
+ @Nullable String iface) {
if (host == null) return null;
if (host instanceof Inet4Address) {
@@ -290,6 +323,7 @@
*
* @return {@link IpPrefix} specifying the destination. This is never {@code null}.
*/
+ @NonNull
public IpPrefix getDestination() {
return mDestination;
}
@@ -298,6 +332,7 @@
* TODO: Convert callers to use IpPrefix and then remove.
* @hide
*/
+ @NonNull
public LinkAddress getDestinationLinkAddress() {
return new LinkAddress(mDestination.getAddress(), mDestination.getPrefixLength());
}
@@ -308,6 +343,7 @@
* @return {@link InetAddress} specifying the gateway or next hop. This may be
* {@code null} for a directly-connected route."
*/
+ @Nullable
public InetAddress getGateway() {
return mGateway;
}
@@ -317,6 +353,7 @@
*
* @return The name of the interface used for this route.
*/
+ @Nullable
public String getInterface() {
return mInterface;
}
@@ -330,6 +367,7 @@
*/
@TestApi
@SystemApi
+ @RouteType
public int getType() {
return mType;
}
@@ -401,6 +439,7 @@
* @hide
*/
@UnsupportedAppUsage
+ @Nullable
public static RouteInfo selectBestRoute(Collection<RouteInfo> routes, InetAddress dest) {
if ((routes == null) || (dest == null)) return null;
diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java
index 14dbca0..f01e213 100644
--- a/core/java/android/net/StaticIpConfiguration.java
+++ b/core/java/android/net/StaticIpConfiguration.java
@@ -22,6 +22,7 @@
import android.annotation.TestApi;
import android.annotation.UnsupportedAppUsage;
import android.net.shared.InetAddressUtils;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -33,20 +34,19 @@
/**
* Class that describes static IP configuration.
*
- * This class is different from LinkProperties because it represents
+ * <p>This class is different from {@link LinkProperties} because it represents
* configuration intent. The general contract is that if we can represent
* a configuration here, then we should be able to configure it on a network.
* The intent is that it closely match the UI we have for configuring networks.
*
- * In contrast, LinkProperties represents current state. It is much more
+ * <p>In contrast, {@link LinkProperties} represents current state. It is much more
* expressive. For example, it supports multiple IP addresses, multiple routes,
* stacked interfaces, and so on. Because LinkProperties is so expressive,
* using it to represent configuration intent as well as current state causes
* problems. For example, we could unknowingly save a configuration that we are
* not in fact capable of applying, or we could save a configuration that the
* UI cannot display, which has the potential for malicious code to hide
- * hostile or unexpected configuration from the user: see, for example,
- * http://b/12663469 and http://b/16893413 .
+ * hostile or unexpected configuration from the user.
*
* @hide
*/
@@ -54,24 +54,24 @@
@TestApi
public final class StaticIpConfiguration implements Parcelable {
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
@Nullable
public LinkAddress ipAddress;
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
@Nullable
public InetAddress gateway;
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
@NonNull
public final ArrayList<InetAddress> dnsServers;
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
@Nullable
public String domains;
public StaticIpConfiguration() {
- dnsServers = new ArrayList<InetAddress>();
+ dnsServers = new ArrayList<>();
}
public StaticIpConfiguration(@Nullable StaticIpConfiguration source) {
@@ -92,32 +92,96 @@
domains = null;
}
+ /**
+ * Get the static IP address included in the configuration.
+ */
public @Nullable LinkAddress getIpAddress() {
return ipAddress;
}
- public void setIpAddress(@Nullable LinkAddress ipAddress) {
- this.ipAddress = ipAddress;
- }
-
+ /**
+ * Get the gateway included in the configuration.
+ */
public @Nullable InetAddress getGateway() {
return gateway;
}
- public void setGateway(@Nullable InetAddress gateway) {
- this.gateway = gateway;
- }
-
+ /**
+ * Get the DNS servers included in the configuration.
+ */
public @NonNull List<InetAddress> getDnsServers() {
return dnsServers;
}
+ /**
+ * Get a {@link String} containing the comma separated domains to search when resolving host
+ * names on this link, in priority order.
+ */
public @Nullable String getDomains() {
return domains;
}
- public void setDomains(@Nullable String newDomains) {
- domains = newDomains;
+ /**
+ * Helper class to build a new instance of {@link StaticIpConfiguration}.
+ */
+ public static final class Builder {
+ private LinkAddress mIpAddress;
+ private InetAddress mGateway;
+ private Iterable<InetAddress> mDnsServers;
+ private String mDomains;
+
+ /**
+ * Set the IP address to be included in the configuration; null by default.
+ * @return The {@link Builder} for chaining.
+ */
+ public @NonNull Builder setIpAddress(@Nullable LinkAddress ipAddress) {
+ mIpAddress = ipAddress;
+ return this;
+ }
+
+ /**
+ * Set the address of the gateway to be included in the configuration; null by default.
+ * @return The {@link Builder} for chaining.
+ */
+ public @NonNull Builder setGateway(@Nullable InetAddress gateway) {
+ mGateway = gateway;
+ return this;
+ }
+
+ /**
+ * Set the addresses of the DNS servers included in the configuration; empty by default.
+ * @return The {@link Builder} for chaining.
+ */
+ public @NonNull Builder setDnsServers(@NonNull Iterable<InetAddress> dnsServers) {
+ mDnsServers = dnsServers;
+ return this;
+ }
+
+ /**
+ * Sets the DNS domain search path to be used on the link; null by default.
+ * @param newDomains A {@link String} containing the comma separated domains to search when
+ * resolving host names on this link, in priority order.
+ * @return The {@link Builder} for chaining.
+ */
+ public @NonNull Builder setDomains(@Nullable String newDomains) {
+ mDomains = newDomains;
+ return this;
+ }
+
+ /**
+ * Create a {@link StaticIpConfiguration} from the parameters in this {@link Builder}.
+ * @return The newly created StaticIpConfiguration.
+ */
+ public @NonNull StaticIpConfiguration build() {
+ final StaticIpConfiguration config = new StaticIpConfiguration();
+ config.ipAddress = mIpAddress;
+ config.gateway = mGateway;
+ for (InetAddress server : mDnsServers) {
+ config.dnsServers.add(server);
+ }
+ config.domains = mDomains;
+ return config;
+ }
}
/**
@@ -129,16 +193,17 @@
/**
* Returns the network routes specified by this object. Will typically include a
- * directly-connected route for the IP address's local subnet and a default route. If the
- * default gateway is not covered by the directly-connected route, it will also contain a host
- * route to the gateway as well. This configuration is arguably invalid, but it used to work
- * in K and earlier, and other OSes appear to accept it.
+ * directly-connected route for the IP address's local subnet and a default route.
+ * @param iface Interface to include in the routes.
*/
public @NonNull List<RouteInfo> getRoutes(@Nullable String iface) {
List<RouteInfo> routes = new ArrayList<RouteInfo>(3);
if (ipAddress != null) {
RouteInfo connectedRoute = new RouteInfo(ipAddress, null, iface);
routes.add(connectedRoute);
+ // If the default gateway is not covered by the directly-connected route, also add a
+ // host route to the gateway as well. This configuration is arguably invalid, but it
+ // used to work in K and earlier, and other OSes appear to accept it.
if (gateway != null && !connectedRoute.matches(gateway)) {
routes.add(RouteInfo.makeHostRoute(gateway, iface));
}
diff --git a/core/java/android/net/TestNetworkInterface.java b/core/java/android/net/TestNetworkInterface.java
index 30e68f5..8455083 100644
--- a/core/java/android/net/TestNetworkInterface.java
+++ b/core/java/android/net/TestNetworkInterface.java
@@ -27,8 +27,6 @@
*/
@TestApi
public final class TestNetworkInterface implements Parcelable {
- private static final String TAG = "TestNetworkInterface";
-
private final ParcelFileDescriptor mFileDescriptor;
private final String mInterfaceName;
diff --git a/core/java/android/net/TestNetworkManager.java b/core/java/android/net/TestNetworkManager.java
index cd58e66..e274005 100644
--- a/core/java/android/net/TestNetworkManager.java
+++ b/core/java/android/net/TestNetworkManager.java
@@ -17,7 +17,6 @@
import android.annotation.NonNull;
import android.annotation.TestApi;
-import android.content.Context;
import android.os.IBinder;
import android.os.RemoteException;
@@ -33,11 +32,9 @@
@NonNull private static final String TAG = TestNetworkManager.class.getSimpleName();
@NonNull private final ITestNetworkManager mService;
- @NonNull private final Context mContext;
/** @hide */
- public TestNetworkManager(@NonNull Context context, @NonNull ITestNetworkManager service) {
- mContext = Preconditions.checkNotNull(context, "missing Context");
+ public TestNetworkManager(@NonNull ITestNetworkManager service) {
mService = Preconditions.checkNotNull(service, "missing ITestNetworkManager");
}
@@ -88,4 +85,21 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Create a tap interface for testing purposes
+ *
+ * @return A ParcelFileDescriptor of the underlying TAP interface. Close this to tear down the
+ * TAP interface.
+ * @hide
+ */
+ @TestApi
+ public TestNetworkInterface createTapInterface() {
+ try {
+ return mService.createTapInterface();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
}
diff --git a/core/java/android/net/UidRange.java b/core/java/android/net/UidRange.java
index fa0eeb9e..a1ac960 100644
--- a/core/java/android/net/UidRange.java
+++ b/core/java/android/net/UidRange.java
@@ -21,6 +21,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Collection;
+
/**
* An inclusive range of UIDs.
*
@@ -42,10 +44,16 @@
return new UidRange(userId * PER_USER_RANGE, (userId + 1) * PER_USER_RANGE - 1);
}
+ /** Returns the smallest user Id which is contained in this UidRange */
public int getStartUser() {
return start / PER_USER_RANGE;
}
+ /** Returns the largest user Id which is contained in this UidRange */
+ public int getEndUser() {
+ return stop / PER_USER_RANGE;
+ }
+
public boolean contains(int uid) {
return start <= uid && uid <= stop;
}
@@ -117,4 +125,23 @@
return new UidRange[size];
}
};
+
+ /**
+ * Returns whether any of the UidRange in the collection contains the specified uid
+ *
+ * @param ranges The collection of UidRange to check
+ * @param uid the uid in question
+ * @return {@code true} if the uid is contained within the ranges, {@code false} otherwise
+ *
+ * @see UidRange#contains(int)
+ */
+ public static boolean containsUid(Collection<UidRange> ranges, int uid) {
+ if (ranges == null) return false;
+ for (UidRange range : ranges) {
+ if (range.contains(uid)) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java
index ea245a4..ed7cddc 100644
--- a/core/java/android/net/VpnService.java
+++ b/core/java/android/net/VpnService.java
@@ -123,6 +123,11 @@
* app must promote itself to the foreground after it's launched or the system
* will shut down the app.
*
+ * <h3>Developer's guide</h3>
+ *
+ * <p>To learn more about developing VPN apps, read the
+ * <a href="{@docRoot}guide/topics/connectivity/vpn">VPN developer's guide</a>.
+ *
* @see Builder
*/
public class VpnService extends Service {
diff --git a/core/java/android/net/apf/ApfCapabilities.java b/core/java/android/net/apf/ApfCapabilities.java
index 17a03c7c..4dd2ace 100644
--- a/core/java/android/net/apf/ApfCapabilities.java
+++ b/core/java/android/net/apf/ApfCapabilities.java
@@ -19,14 +19,17 @@
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.TestApi;
-import android.content.Context;
+import android.content.res.Resources;
import android.os.Parcel;
import android.os.Parcelable;
import com.android.internal.R;
/**
- * APF program support capabilities.
+ * APF program support capabilities. APF stands for Android Packet Filtering and it is a flexible
+ * way to drop unwanted network packets to save power.
+ *
+ * See documentation at hardware/google/apf/apf.h
*
* This class is immutable.
* @hide
@@ -104,10 +107,11 @@
}
/**
- * Returns true if the APF interpreter advertises support for the data buffer access opcodes
- * LDDW and STDW.
+ * Determines whether the APF interpreter advertises support for the data buffer access opcodes
+ * LDDW (LoaD Data Word) and STDW (STore Data Word). Full LDDW (LoaD Data Word) and
+ * STDW (STore Data Word) support is present from APFv4 on.
*
- * Full LDDW and STDW support is present from APFv4 on.
+ * @return {@code true} if the IWifiStaIface#readApfPacketFilterData is supported.
*/
public boolean hasDataAccess() {
return apfVersionSupported >= 4;
@@ -116,14 +120,14 @@
/**
* @return Whether the APF Filter in the device should filter out IEEE 802.3 Frames.
*/
- public static boolean getApfDrop8023Frames(@NonNull Context context) {
- return context.getResources().getBoolean(R.bool.config_apfDrop802_3Frames);
+ public static boolean getApfDrop8023Frames() {
+ return Resources.getSystem().getBoolean(R.bool.config_apfDrop802_3Frames);
}
/**
* @return An array of blacklisted EtherType, packets with EtherTypes within it will be dropped.
*/
- public static @NonNull int[] getApfEthTypeBlackList(@NonNull Context context) {
- return context.getResources().getIntArray(R.array.config_apfEthTypeBlackList);
+ public static @NonNull int[] getApfEtherTypeBlackList() {
+ return Resources.getSystem().getIntArray(R.array.config_apfEthTypeBlackList);
}
}
diff --git a/core/java/android/net/util/SocketUtils.java b/core/java/android/net/util/SocketUtils.java
index 6f8aece..1364d8c 100644
--- a/core/java/android/net/util/SocketUtils.java
+++ b/core/java/android/net/util/SocketUtils.java
@@ -23,21 +23,17 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
-import android.net.MacAddress;
import android.net.NetworkUtils;
import android.system.ErrnoException;
import android.system.NetlinkSocketAddress;
import android.system.Os;
import android.system.PacketSocketAddress;
-import android.system.StructTimeval;
import libcore.io.IoBridge;
import java.io.FileDescriptor;
import java.io.IOException;
-import java.net.Inet4Address;
import java.net.SocketAddress;
-import java.net.SocketException;
/**
* Collection of utilities to interact with raw sockets.
@@ -85,57 +81,11 @@
}
/**
- * Set an option on a socket that takes a time value argument.
- */
- public static void setSocketTimeValueOption(
- @NonNull FileDescriptor fd, int level, int option, long millis) throws ErrnoException {
- Os.setsockoptTimeval(fd, level, option, StructTimeval.fromMillis(millis));
- }
-
- /**
* @see IoBridge#closeAndSignalBlockedThreads(FileDescriptor)
*/
public static void closeSocket(@Nullable FileDescriptor fd) throws IOException {
IoBridge.closeAndSignalBlockedThreads(fd);
}
- /**
- * Attaches a socket filter that accepts DHCP packets to the given socket.
- */
- public static void attachDhcpFilter(@NonNull FileDescriptor fd) throws SocketException {
- NetworkUtils.attachDhcpFilter(fd);
- }
-
- /**
- * Attaches a socket filter that accepts ICMPv6 router advertisements to the given socket.
- * @param fd the socket's {@link FileDescriptor}.
- * @param packetType the hardware address type, one of ARPHRD_*.
- */
- public static void attachRaFilter(@NonNull FileDescriptor fd, int packetType)
- throws SocketException {
- NetworkUtils.attachRaFilter(fd, packetType);
- }
-
- /**
- * Attaches a socket filter that accepts L2-L4 signaling traffic required for IP connectivity.
- *
- * This includes: all ARP, ICMPv6 RS/RA/NS/NA messages, and DHCPv4 exchanges.
- *
- * @param fd the socket's {@link FileDescriptor}.
- * @param packetType the hardware address type, one of ARPHRD_*.
- */
- public static void attachControlPacketFilter(@NonNull FileDescriptor fd, int packetType)
- throws SocketException {
- NetworkUtils.attachControlPacketFilter(fd, packetType);
- }
-
- /**
- * Add an entry into the ARP cache.
- */
- public static void addArpEntry(@NonNull Inet4Address ipv4Addr, @NonNull MacAddress ethAddr,
- @NonNull String ifname, @NonNull FileDescriptor fd) throws IOException {
- NetworkUtils.addArpEntry(ipv4Addr, ethAddr, ifname, fd);
- }
-
private SocketUtils() {}
}
diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java
index f87abde..0feed68 100644
--- a/core/java/android/os/BugreportManager.java
+++ b/core/java/android/os/BugreportManager.java
@@ -25,12 +25,14 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.content.Context;
+import android.util.Log;
import com.android.internal.util.Preconditions;
import libcore.io.IoUtils;
-import java.io.FileDescriptor;
+import java.io.File;
+import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.Executor;
@@ -43,6 +45,9 @@
@SystemApi
@SystemService(Context.BUGREPORT_SERVICE)
public final class BugreportManager {
+
+ private static final String TAG = "BugreportManager";
+
private final Context mContext;
private final IDumpstate mBinder;
@@ -141,22 +146,35 @@
@NonNull BugreportParams params,
@NonNull @CallbackExecutor Executor executor,
@NonNull BugreportCallback callback) {
+ File tmpScreenshotFile = null;
try {
Preconditions.checkNotNull(bugreportFd);
Preconditions.checkNotNull(params);
Preconditions.checkNotNull(executor);
Preconditions.checkNotNull(callback);
- DumpstateListener dsListener = new DumpstateListener(executor, callback);
+ if (screenshotFd == null) {
+ // Binder needs a valid File Descriptor to be passed
+ tmpScreenshotFile = File.createTempFile("tmp", ".png");
+ screenshotFd = ParcelFileDescriptor.open(tmpScreenshotFile,
+ ParcelFileDescriptor.MODE_READ_ONLY);
+ }
+ DumpstateListener dsListener = new DumpstateListener(executor,
+ callback, tmpScreenshotFile);
+
// Note: mBinder can get callingUid from the binder transaction.
mBinder.startBugreport(-1 /* callingUid */,
mContext.getOpPackageName(),
bugreportFd.getFileDescriptor(),
- (screenshotFd != null
- ? screenshotFd.getFileDescriptor() : new FileDescriptor()),
+ screenshotFd.getFileDescriptor(),
params.getMode(), dsListener);
} catch (RemoteException e) {
+ deleteFile(tmpScreenshotFile);
throw e.rethrowFromSystemServer();
+ } catch (IOException e) {
+ // Need to delete the file if it was created but failed while trying to get fd
+ deleteFile(tmpScreenshotFile);
+ Log.e(TAG, "Not able to create/open temporary screenshot file ", e);
} finally {
// We can close the file descriptors here because binder would have duped them.
IoUtils.closeQuietly(bugreportFd);
@@ -178,13 +196,26 @@
}
}
+ private void deleteFile(@Nullable File tmpScreenshotFile) {
+ try {
+ if (tmpScreenshotFile != null && tmpScreenshotFile.exists()) {
+ tmpScreenshotFile.delete();
+ }
+ } catch (SecurityException e) {
+ Log.e(TAG, "Not able to delete temporary screenshot file ", e);
+ }
+ }
+
private final class DumpstateListener extends IDumpstateListener.Stub {
private final Executor mExecutor;
private final BugreportCallback mCallback;
+ private final File mTmpScreenshotFile;
- DumpstateListener(Executor executor, BugreportCallback callback) {
+ DumpstateListener(Executor executor, BugreportCallback callback,
+ @Nullable File tmpScreenshotFile) {
mExecutor = executor;
mCallback = callback;
+ mTmpScreenshotFile = tmpScreenshotFile;
}
@Override
@@ -208,6 +239,7 @@
});
} finally {
Binder.restoreCallingIdentity(identity);
+ deleteFile(mTmpScreenshotFile);
}
}
@@ -220,6 +252,7 @@
});
} finally {
Binder.restoreCallingIdentity(identity);
+ deleteFile(mTmpScreenshotFile);
}
}
diff --git a/core/java/android/os/SELinux.java b/core/java/android/os/SELinux.java
index 8ffafe4..86d9f89 100644
--- a/core/java/android/os/SELinux.java
+++ b/core/java/android/os/SELinux.java
@@ -31,12 +31,15 @@
public class SELinux {
private static final String TAG = "SELinux";
- /** Keep in sync with ./external/libselinux/include/selinux/android.h */
+ /** Keep in sync with ./external/selinux/libselinux/include/selinux/android.h */
private static final int SELINUX_ANDROID_RESTORECON_NOCHANGE = 1;
private static final int SELINUX_ANDROID_RESTORECON_VERBOSE = 2;
private static final int SELINUX_ANDROID_RESTORECON_RECURSE = 4;
private static final int SELINUX_ANDROID_RESTORECON_FORCE = 8;
private static final int SELINUX_ANDROID_RESTORECON_DATADATA = 16;
+ private static final int SELINUX_ANDROID_RESTORECON_SKIPCE = 32;
+ private static final int SELINUX_ANDROID_RESTORECON_CROSS_FILESYSTEMS = 64;
+ private static final int SELINUX_ANDROID_RESTORECON_SKIP_SEHASH = 128;
/**
* Determine whether SELinux is disabled or enabled.
@@ -175,7 +178,8 @@
@UnsupportedAppUsage
public static boolean restoreconRecursive(File file) {
try {
- return native_restorecon(file.getCanonicalPath(), SELINUX_ANDROID_RESTORECON_RECURSE);
+ return native_restorecon(file.getCanonicalPath(),
+ SELINUX_ANDROID_RESTORECON_RECURSE | SELINUX_ANDROID_RESTORECON_SKIP_SEHASH);
} catch (IOException e) {
Slog.e(TAG, "Error getting canonical path. Restorecon failed for " +
file.getPath(), e);
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 44adc1c..ef28f07 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -35,7 +35,6 @@
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.DataUsageFeedback;
-import android.telecom.CallIdentification;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
@@ -605,69 +604,6 @@
public static final String BLOCK_REASON = "block_reason";
/**
- * The package name of the {@link android.telecom.CallScreeningService} which provided
- * {@link android.telecom.CallIdentification} for this call.
- * <P>Type: TEXT</P>
- */
- public static final String CALL_ID_PACKAGE_NAME = "call_id_package_name";
-
- /**
- * The app name of the {@link android.telecom.CallScreeningService} which provided
- * {@link android.telecom.CallIdentification} for this call.
- * <P>Type: TEXT</P>
- */
- public static final String CALL_ID_APP_NAME = "call_id_app_name";
-
- /**
- * The {@link CallIdentification#getName() name} of a call, as provided by the
- * {@link android.telecom.CallScreeningService}.
- * <p>
- * The name is provided by the app identified by {@link #CALL_ID_PACKAGE_NAME} and
- * {@link #CALL_ID_APP_NAME}.
- * <P>Type: TEXT</P>
- */
- public static final String CALL_ID_NAME = "call_id_name";
-
- /**
- * The {@link CallIdentification#getDescription() description} of a call, as provided by the
- * {@link android.telecom.CallScreeningService}.
- * <p>
- * The description is provided by the app identified by {@link #CALL_ID_PACKAGE_NAME} and
- * {@link #CALL_ID_APP_NAME}.
- * <P>Type: TEXT</P>
- */
- public static final String CALL_ID_DESCRIPTION = "call_id_description";
-
- /**
- * The {@link CallIdentification#getDetails() details} of a call, as provided by the
- * {@link android.telecom.CallScreeningService}.
- * <p>
- * The details field is provided by the app identified by {@link #CALL_ID_PACKAGE_NAME} and
- * {@link #CALL_ID_APP_NAME}.
- * <P>Type: TEXT</P>
- */
- public static final String CALL_ID_DETAILS = "call_id_details";
-
- /**
- * The {@link CallIdentification#getNuisanceConfidence() nuisance confidence} of a call, as
- * provided by the {@link android.telecom.CallScreeningService}.
- * <p>
- * Valid values are defined in {@link CallIdentification}, and include:
- * <ul>
- * <li>{@link CallIdentification#CONFIDENCE_NOT_NUISANCE}</li>
- * <li>{@link CallIdentification#CONFIDENCE_LIKELY_NOT_NUISANCE}</li>
- * <li>{@link CallIdentification#CONFIDENCE_UNKNOWN}</li>
- * <li>{@link CallIdentification#CONFIDENCE_LIKELY_NUISANCE}</li>
- * <li>{@link CallIdentification#CONFIDENCE_NUISANCE}</li>
- * </ul>
- * <p>
- * The nuisance confidence is provided by the app identified by
- * {@link #CALL_ID_PACKAGE_NAME} and {@link #CALL_ID_APP_NAME}.
- * <P>Type: INTEGER</P>
- */
- public static final String CALL_ID_NUISANCE_CONFIDENCE = "call_id_nuisance_confidence";
-
- /**
* Adds a call to the call log.
*
* @param ci the CallerInfo object to get the target contact from. Can be null
@@ -696,8 +632,7 @@
presentation, callType, features, accountHandle, start, duration,
dataUsage, false /* addForAllUsers */, null /* userToBeInsertedTo */,
false /* isRead */, Calls.BLOCK_REASON_NOT_BLOCKED /* callBlockReason */,
- null /* callScreeningAppName */, null /* callScreeningComponentName */,
- null /* callIdentification */);
+ null /* callScreeningAppName */, null /* callScreeningComponentName */);
}
@@ -737,8 +672,7 @@
features, accountHandle, start, duration, dataUsage, addForAllUsers,
userToBeInsertedTo, false /* isRead */ , Calls.BLOCK_REASON_NOT_BLOCKED
/* callBlockReason */, null /* callScreeningAppName */,
- null /* callScreeningComponentName */,
- null /* callIdentification */);
+ null /* callScreeningComponentName */);
}
/**
@@ -784,7 +718,7 @@
int features, PhoneAccountHandle accountHandle, long start, int duration,
Long dataUsage, boolean addForAllUsers, UserHandle userToBeInsertedTo,
boolean isRead, int callBlockReason, CharSequence callScreeningAppName,
- String callScreeningComponentName, CallIdentification callIdentification) {
+ String callScreeningComponentName) {
if (VERBOSE_LOG) {
Log.v(LOG_TAG, String.format("Add call: number=%s, user=%s, for all=%s",
number, userToBeInsertedTo, addForAllUsers));
@@ -839,26 +773,6 @@
values.put(CALL_SCREENING_APP_NAME, charSequenceToString(callScreeningAppName));
values.put(CALL_SCREENING_COMPONENT_NAME, callScreeningComponentName);
- if (callIdentification != null) {
- values.put(CALL_ID_PACKAGE_NAME, callIdentification.getCallScreeningPackageName());
- values.put(CALL_ID_APP_NAME,
- charSequenceToString(callIdentification.getCallScreeningAppName()));
- values.put(CALL_ID_NAME,
- charSequenceToString(callIdentification.getName()));
- values.put(CALL_ID_DESCRIPTION,
- charSequenceToString(callIdentification.getDescription()));
- values.put(CALL_ID_DETAILS,
- charSequenceToString(callIdentification.getDetails()));
- values.put(CALL_ID_NUISANCE_CONFIDENCE, callIdentification.getNuisanceConfidence());
- } else {
- values.putNull(CALL_ID_PACKAGE_NAME);
- values.putNull(CALL_ID_APP_NAME);
- values.putNull(CALL_ID_NAME);
- values.putNull(CALL_ID_DESCRIPTION);
- values.putNull(CALL_ID_DETAILS);
- values.putNull(CALL_ID_NUISANCE_CONFIDENCE);
- }
-
if ((ci != null) && (ci.contactIdOrZero > 0)) {
// Update usage information for the number associated with the contact ID.
// We need to use both the number and the ID for obtaining a data ID since other
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 946d386..34e9eb3 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7319,15 +7319,6 @@
"call_screening_default_component";
/**
- * Specifies the component name currently configured to be the default application to
- * perform the user-defined call redirection service with Telecom.
- * @hide
- */
- @UnsupportedAppUsage
- public static final String CALL_REDIRECTION_DEFAULT_APPLICATION =
- "call_redirection_default_application";
-
- /**
* Specifies the package name currently configured to be the emergency assistance application
*
* @see android.telephony.TelephonyManager#ACTION_EMERGENCY_ASSISTANCE
@@ -10474,62 +10465,6 @@
public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent";
/**
- * The threshold value for the number of consecutive dns timeout events received to be a
- * signal of data stall. The number of consecutive timeouts needs to be {@code >=} this
- * threshold to be considered a data stall. Set the value to {@code <= 0} to disable. Note
- * that the value should be {@code > 0} if the DNS data stall detection is enabled.
- *
- * @hide
- */
- @SystemApi
- @TestApi
- public static final String DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD =
- "data_stall_consecutive_dns_timeout_threshold";
-
- /**
- * The minimal time interval in milliseconds for data stall reevaluation.
- *
- * @hide
- */
- @SystemApi
- @TestApi
- public static final String DATA_STALL_MIN_EVALUATE_INTERVAL =
- "data_stall_min_evaluate_interval";
-
- /**
- * DNS timeouts older than this timeout (in milliseconds) are not considered for detecting
- * a data stall.
- *
- * @hide
- */
- @SystemApi
- @TestApi
- public static final String DATA_STALL_VALID_DNS_TIME_THRESHOLD =
- "data_stall_valid_dns_time_threshold";
-
- /**
- * Which data stall detection signal to use. This is a bitmask constructed by bitwise-or-ing
- * (i.e. {@code |}) the DATA_STALL_EVALUATION_TYPE_* values.
- *
- * Type: int
- * Valid values:
- * {@link #DATA_STALL_EVALUATION_TYPE_DNS} : Use dns as a signal.
- * @hide
- */
- @SystemApi
- @TestApi
- public static final String DATA_STALL_EVALUATION_TYPE = "data_stall_evaluation_type";
-
- /**
- * Use dns timeout counts to detect data stall.
- *
- * @hide
- */
- @SystemApi
- @TestApi
- public static final int DATA_STALL_EVALUATION_TYPE_DNS = 1;
-
- /**
* Whether to try cellular data recovery when a bad network is reported.
*
* @hide
diff --git a/core/java/android/security/keystore/recovery/RecoverySession.java b/core/java/android/security/keystore/recovery/RecoverySession.java
index 6622712..9166e0b 100644
--- a/core/java/android/security/keystore/recovery/RecoverySession.java
+++ b/core/java/android/security/keystore/recovery/RecoverySession.java
@@ -26,6 +26,8 @@
import android.util.ArrayMap;
import android.util.Log;
+import libcore.util.HexEncoding;
+
import java.security.Key;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
@@ -71,11 +73,7 @@
SecureRandom secureRandom = new SecureRandom();
byte[] sessionId = new byte[SESSION_ID_LENGTH_BYTES];
secureRandom.nextBytes(sessionId);
- StringBuilder sb = new StringBuilder();
- for (byte b : sessionId) {
- sb.append(Byte.toHexString(b, /*upperCase=*/ false));
- }
- return sb.toString();
+ return HexEncoding.encodeToString(sessionId, /*upperCase=*/ false);
}
/**
diff --git a/core/java/android/service/carrier/CarrierIdentifier.java b/core/java/android/service/carrier/CarrierIdentifier.java
index 3b71aa7..4b3e7d3 100644
--- a/core/java/android/service/carrier/CarrierIdentifier.java
+++ b/core/java/android/service/carrier/CarrierIdentifier.java
@@ -20,6 +20,7 @@
import android.annotation.Nullable;
import android.os.Parcel;
import android.os.Parcelable;
+import android.telephony.Rlog;
import android.telephony.TelephonyManager;
import com.android.internal.telephony.uicc.IccUtils;
@@ -223,7 +224,7 @@
+ "mcc=" + mMcc
+ ",mnc=" + mMnc
+ ",spn=" + mSpn
- + ",imsi=" + mImsi
+ + ",imsi=" + Rlog.pii(false, mImsi)
+ ",gid1=" + mGid1
+ ",gid2=" + mGid2
+ ",carrierid=" + mCarrierId
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index ff69bcb..a99734d 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -41,7 +41,6 @@
static {
DEFAULT_FLAGS = new HashMap<>();
DEFAULT_FLAGS.put("settings_battery_display_app_list", "false");
- DEFAULT_FLAGS.put("settings_zone_picker_v2", "true");
DEFAULT_FLAGS.put("settings_about_phone_v2", "true");
DEFAULT_FLAGS.put("settings_bluetooth_while_driving", "false");
DEFAULT_FLAGS.put("settings_data_usage_v2", "true");
diff --git a/core/java/android/util/PackageUtils.java b/core/java/android/util/PackageUtils.java
index a5e3818..8061bf3 100644
--- a/core/java/android/util/PackageUtils.java
+++ b/core/java/android/util/PackageUtils.java
@@ -20,6 +20,8 @@
import android.annotation.Nullable;
import android.content.pm.Signature;
+import libcore.util.HexEncoding;
+
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.MessageDigest;
@@ -125,6 +127,10 @@
* @return The digest or null if an error occurs.
*/
public static @Nullable String computeSha256Digest(@NonNull byte[] data) {
- return ByteStringUtils.toHexString(computeSha256DigestBytes(data));
+ byte[] sha256DigestBytes = computeSha256DigestBytes(data);
+ if (sha256DigestBytes == null) {
+ return null;
+ }
+ return HexEncoding.encodeToString(sha256DigestBytes, true /* uppercase */);
}
}
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 2ee72bf..ae2deb9 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -512,7 +512,7 @@
String layout = res.getResourceEntryName(resource);
try {
- Class clazz = mPrecompiledClassLoader.loadClass("" + pkg + ".CompiledView");
+ Class clazz = Class.forName("" + pkg + ".CompiledView", false, mPrecompiledClassLoader);
Method inflater = clazz.getMethod(layout, Context.class, int.class);
View view = (View) inflater.invoke(null, mContext, resource);
@@ -731,8 +731,8 @@
if (constructor == null) {
// Class not found in the cache, see if it's real, and try to add it
- clazz = mContext.getClassLoader().loadClass(
- prefix != null ? (prefix + name) : name).asSubclass(View.class);
+ clazz = Class.forName(prefix != null ? (prefix + name) : name, false,
+ mContext.getClassLoader()).asSubclass(View.class);
if (mFilter != null && clazz != null) {
boolean allowed = mFilter.onLoadClass(clazz);
@@ -750,8 +750,8 @@
Boolean allowedState = mFilterMap.get(name);
if (allowedState == null) {
// New class -- remember whether it is allowed
- clazz = mContext.getClassLoader().loadClass(
- prefix != null ? (prefix + name) : name).asSubclass(View.class);
+ clazz = Class.forName(prefix != null ? (prefix + name) : name, false,
+ mContext.getClassLoader()).asSubclass(View.class);
boolean allowed = clazz != null && mFilter.onLoadClass(clazz);
mFilterMap.put(name, allowed);
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index f98541e..efa1747 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -31,6 +31,8 @@
import android.util.Log;
import android.util.TypedValue;
+import libcore.util.HexEncoding;
+
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
@@ -1301,7 +1303,8 @@
if (type == int.class) {
fieldValue = formatIntToHexString((Integer) fieldValue);
} else if (type == byte.class) {
- fieldValue = "0x" + Byte.toHexString((Byte) fieldValue, true);
+ fieldValue = "0x"
+ + HexEncoding.encodeToString((Byte) fieldValue, true);
}
}
}
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index d4fa5cb..14b511d 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -23,6 +23,7 @@
import android.net.Credentials;
import android.net.LocalServerSocket;
import android.net.LocalSocket;
+import android.os.Build;
import android.os.FactoryTest;
import android.os.IVold;
import android.os.Process;
@@ -215,7 +216,8 @@
*/
public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
- int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir) {
+ int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
+ int targetSdkVersion) {
ZygoteHooks.preFork();
// Resets nice priority for zygote process.
resetNicePriority();
@@ -224,6 +226,7 @@
fdsToIgnore, startChildZygote, instructionSet, appDataDir);
// Enable tracing as soon as possible for the child process.
if (pid == 0) {
+ Zygote.disableExecuteOnly(targetSdkVersion);
Trace.setTracingEnabled(true, runtimeFlags);
// Note that this event ends at the end of handleChildProc,
@@ -568,6 +571,8 @@
args.mSeInfo, args.mNiceName, args.mStartChildZygote,
args.mInstructionSet, args.mAppDataDir);
+ disableExecuteOnly(args.mTargetSdkVersion);
+
if (args.mNiceName != null) {
Process.setArgV0(args.mNiceName);
}
@@ -614,6 +619,17 @@
}
/**
+ * Mark execute-only segments of libraries read+execute for apps with targetSdkVersion<Q.
+ */
+ protected static void disableExecuteOnly(int targetSdkVersion) {
+ if ((targetSdkVersion < Build.VERSION_CODES.Q) && !nativeDisableExecuteOnly()) {
+ Log.e("Zygote", "Failed to set libraries to read+execute.");
+ }
+ }
+
+ private static native boolean nativeDisableExecuteOnly();
+
+ /**
* @return Raw file descriptors for the read-end of blastula reporting pipes.
*/
protected static int[] getBlastulaPipeFDs() {
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 034c37c..ad9f64c 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -243,7 +243,7 @@
pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,
parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
- parsedArgs.mInstructionSet, parsedArgs.mAppDataDir);
+ parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mTargetSdkVersion);
try {
if (pid == 0) {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index ce1ee3d..2abc8c0 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -22,6 +22,8 @@
import android.annotation.UnsupportedAppUsage;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.app.ApplicationLoaders;
+import android.content.pm.SharedLibraryInfo;
import android.os.Build;
import android.os.Environment;
import android.os.IInstalld;
@@ -141,6 +143,9 @@
bootTimingsTraceLog.traceBegin("PreloadClasses");
preloadClasses();
bootTimingsTraceLog.traceEnd(); // PreloadClasses
+ bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders");
+ cacheNonBootClasspathClassLoaders();
+ bootTimingsTraceLog.traceEnd(); // CacheNonBootClasspathClassLoaders
bootTimingsTraceLog.traceBegin("PreloadResources");
preloadResources();
bootTimingsTraceLog.traceEnd(); // PreloadResources
@@ -347,6 +352,32 @@
}
/**
+ * Load in things which are used by many apps but which cannot be put in the boot
+ * classpath.
+ */
+ private static void cacheNonBootClasspathClassLoaders() {
+ // These libraries used to be part of the bootclasspath, but had to be removed.
+ // Old system applications still get them for backwards compatibility reasons,
+ // so they are cached here in order to preserve performance characteristics.
+ SharedLibraryInfo hidlBase = new SharedLibraryInfo(
+ "/system/framework/android.hidl.base-V1.0-java.jar", null /*packageName*/,
+ null /*codePaths*/, null /*name*/, 0 /*version*/, SharedLibraryInfo.TYPE_BUILTIN,
+ null /*declaringPackage*/, null /*dependentPackages*/, null /*dependencies*/);
+ SharedLibraryInfo hidlManager = new SharedLibraryInfo(
+ "/system/framework/android.hidl.manager-V1.0-java.jar", null /*packageName*/,
+ null /*codePaths*/, null /*name*/, 0 /*version*/, SharedLibraryInfo.TYPE_BUILTIN,
+ null /*declaringPackage*/, null /*dependentPackages*/, null /*dependencies*/);
+ hidlManager.addDependency(hidlBase);
+
+ ApplicationLoaders.getDefault().createAndCacheNonBootclasspathSystemClassLoaders(
+ new SharedLibraryInfo[]{
+ // ordered dependencies first
+ hidlBase,
+ hidlManager,
+ });
+ }
+
+ /**
* Load in commonly used resources, so they can be shared across processes.
*
* These tend to be a few Kbytes, but are frequently in the 20-40K range, and occasionally even
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 6024f68..e508b02a 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -196,7 +196,6 @@
"android_content_res_Configuration.cpp",
"android_animation_PropertyValuesHolder.cpp",
"android_security_Scrypt.cpp",
- "com_android_internal_net_NetworkStatsFactory.cpp",
"com_android_internal_os_ClassLoaderFactory.cpp",
"com_android_internal_os_FuseAppLoop.cpp",
"com_android_internal_os_Zygote.cpp",
@@ -288,6 +287,7 @@
"libnativewindow",
"libhwui",
"libdl",
+ "libdl_android",
"libstatslog",
"server_configurable_flags",
],
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 79850d0..a4be784 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -213,7 +213,6 @@
extern int register_android_animation_PropertyValuesHolder(JNIEnv *env);
extern int register_android_security_Scrypt(JNIEnv *env);
extern int register_com_android_internal_content_NativeLibraryHelper(JNIEnv *env);
-extern int register_com_android_internal_net_NetworkStatsFactory(JNIEnv *env);
extern int register_com_android_internal_os_ClassLoaderFactory(JNIEnv* env);
extern int register_com_android_internal_os_FuseAppLoop(JNIEnv* env);
extern int register_com_android_internal_os_Zygote(JNIEnv *env);
@@ -665,6 +664,7 @@
char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:")-1 + PROPERTY_VALUE_MAX];
char nativeBridgeLibrary[sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX];
char cpuAbiListBuf[sizeof("--cpu-abilist=") + PROPERTY_VALUE_MAX];
+ char corePlatformApiPolicyBuf[sizeof("-Xcore-platform-api-policy:") + PROPERTY_VALUE_MAX];
char methodTraceFileBuf[sizeof("-Xmethod-trace-file:") + PROPERTY_VALUE_MAX];
char methodTraceFileSizeBuf[sizeof("-Xmethod-trace-file-size:") + PROPERTY_VALUE_MAX];
std::string fingerprintBuf;
@@ -1011,6 +1011,16 @@
addOption("--generate-mini-debug-info");
}
+ // If set, the property below can be used to enable core platform API violation reporting.
+ property_get("persist.debug.dalvik.vm.core_platform_api_policy", propBuf, "");
+ if (propBuf[0] != '\0') {
+ snprintf(corePlatformApiPolicyBuf,
+ sizeof(corePlatformApiPolicyBuf),
+ "-Xcore-platform-api-policy:%s",
+ propBuf);
+ addOption(corePlatformApiPolicyBuf);
+ }
+
/*
* Retrieve the build fingerprint and provide it to the runtime. That way, ANR dumps will
* contain the fingerprint and can be parsed.
@@ -1538,7 +1548,6 @@
REG_JNI(register_android_animation_PropertyValuesHolder),
REG_JNI(register_android_security_Scrypt),
REG_JNI(register_com_android_internal_content_NativeLibraryHelper),
- REG_JNI(register_com_android_internal_net_NetworkStatsFactory),
REG_JNI(register_com_android_internal_os_FuseAppLoop),
};
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 82acf6f..28c59db 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -48,17 +48,6 @@
namespace android {
-static const uint32_t kEtherTypeOffset = offsetof(ether_header, ether_type);
-static const uint32_t kEtherHeaderLen = sizeof(ether_header);
-static const uint32_t kIPv4Protocol = kEtherHeaderLen + offsetof(iphdr, protocol);
-static const uint32_t kIPv4FlagsOffset = kEtherHeaderLen + offsetof(iphdr, frag_off);
-static const uint32_t kIPv6NextHeader = kEtherHeaderLen + offsetof(ip6_hdr, ip6_nxt);
-static const uint32_t kIPv6PayloadStart = kEtherHeaderLen + sizeof(ip6_hdr);
-static const uint32_t kICMPv6TypeOffset = kIPv6PayloadStart + offsetof(icmp6_hdr, icmp6_type);
-static const uint32_t kUDPSrcPortIndirectOffset = kEtherHeaderLen + offsetof(udphdr, source);
-static const uint32_t kUDPDstPortIndirectOffset = kEtherHeaderLen + offsetof(udphdr, dest);
-static const uint16_t kDhcpClientPort = 68;
-
constexpr int MAXPACKETSIZE = 8 * 1024;
// FrameworkListener limits the size of commands to 1024 bytes. TODO: fix this.
constexpr int MAXCMDSIZE = 1024;
@@ -84,149 +73,6 @@
env->Throw(reinterpret_cast<jthrowable>(exception));
}
-static void android_net_utils_attachDhcpFilter(JNIEnv *env, jobject clazz, jobject javaFd)
-{
- struct sock_filter filter_code[] = {
- // Check the protocol is UDP.
- BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv4Protocol),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_UDP, 0, 6),
-
- // Check this is not a fragment.
- BPF_STMT(BPF_LD | BPF_H | BPF_ABS, kIPv4FlagsOffset),
- BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K, IP_OFFMASK, 4, 0),
-
- // Get the IP header length.
- BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, kEtherHeaderLen),
-
- // Check the destination port.
- BPF_STMT(BPF_LD | BPF_H | BPF_IND, kUDPDstPortIndirectOffset),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, kDhcpClientPort, 0, 1),
-
- // Accept or reject.
- BPF_STMT(BPF_RET | BPF_K, 0xffff),
- BPF_STMT(BPF_RET | BPF_K, 0)
- };
- struct sock_fprog filter = {
- sizeof(filter_code) / sizeof(filter_code[0]),
- filter_code,
- };
-
- int fd = jniGetFDFromFileDescriptor(env, javaFd);
- if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
- }
-}
-
-static void android_net_utils_attachRaFilter(JNIEnv *env, jobject clazz, jobject javaFd,
- jint hardwareAddressType)
-{
- if (hardwareAddressType != ARPHRD_ETHER) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "attachRaFilter only supports ARPHRD_ETHER");
- return;
- }
-
- struct sock_filter filter_code[] = {
- // Check IPv6 Next Header is ICMPv6.
- BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv6NextHeader),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 3),
-
- // Check ICMPv6 type is Router Advertisement.
- BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kICMPv6TypeOffset),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ND_ROUTER_ADVERT, 0, 1),
-
- // Accept or reject.
- BPF_STMT(BPF_RET | BPF_K, 0xffff),
- BPF_STMT(BPF_RET | BPF_K, 0)
- };
- struct sock_fprog filter = {
- sizeof(filter_code) / sizeof(filter_code[0]),
- filter_code,
- };
-
- int fd = jniGetFDFromFileDescriptor(env, javaFd);
- if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
- }
-}
-
-// TODO: Move all this filter code into libnetutils.
-static void android_net_utils_attachControlPacketFilter(
- JNIEnv *env, jobject clazz, jobject javaFd, jint hardwareAddressType) {
- if (hardwareAddressType != ARPHRD_ETHER) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "attachControlPacketFilter only supports ARPHRD_ETHER");
- return;
- }
-
- // Capture all:
- // - ARPs
- // - DHCPv4 packets
- // - Router Advertisements & Solicitations
- // - Neighbor Advertisements & Solicitations
- //
- // tcpdump:
- // arp or
- // '(ip and udp port 68)' or
- // '(icmp6 and ip6[40] >= 133 and ip6[40] <= 136)'
- struct sock_filter filter_code[] = {
- // Load the link layer next payload field.
- BPF_STMT(BPF_LD | BPF_H | BPF_ABS, kEtherTypeOffset),
-
- // Accept all ARP.
- // TODO: Figure out how to better filter ARPs on noisy networks.
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_ARP, 16, 0),
-
- // If IPv4:
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_IP, 0, 9),
-
- // Check the protocol is UDP.
- BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv4Protocol),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_UDP, 0, 14),
-
- // Check this is not a fragment.
- BPF_STMT(BPF_LD | BPF_H | BPF_ABS, kIPv4FlagsOffset),
- BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K, IP_OFFMASK, 12, 0),
-
- // Get the IP header length.
- BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, kEtherHeaderLen),
-
- // Check the source port.
- BPF_STMT(BPF_LD | BPF_H | BPF_IND, kUDPSrcPortIndirectOffset),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, kDhcpClientPort, 8, 0),
-
- // Check the destination port.
- BPF_STMT(BPF_LD | BPF_H | BPF_IND, kUDPDstPortIndirectOffset),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, kDhcpClientPort, 6, 7),
-
- // IPv6 ...
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_IPV6, 0, 6),
- // ... check IPv6 Next Header is ICMPv6 (ignore fragments), ...
- BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv6NextHeader),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 4),
- // ... and check the ICMPv6 type is one of RS/RA/NS/NA.
- BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kICMPv6TypeOffset),
- BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, ND_ROUTER_SOLICIT, 0, 2),
- BPF_JUMP(BPF_JMP | BPF_JGT | BPF_K, ND_NEIGHBOR_ADVERT, 1, 0),
-
- // Accept or reject.
- BPF_STMT(BPF_RET | BPF_K, 0xffff),
- BPF_STMT(BPF_RET | BPF_K, 0)
- };
- struct sock_fprog filter = {
- sizeof(filter_code) / sizeof(filter_code[0]),
- filter_code,
- };
-
- int fd = jniGetFDFromFileDescriptor(env, javaFd);
- if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
- }
-}
-
static void android_net_utils_attachDropAllBPFFilter(JNIEnv *env, jobject clazz, jobject javaFd)
{
struct sock_filter filter_code[] = {
@@ -389,46 +235,6 @@
return true;
}
-static void android_net_utils_addArpEntry(JNIEnv *env, jobject thiz, jbyteArray ethAddr,
- jbyteArray ipv4Addr, jstring ifname, jobject javaFd)
-{
- struct arpreq req = {};
- struct sockaddr_in& netAddrStruct = *reinterpret_cast<sockaddr_in*>(&req.arp_pa);
- struct sockaddr& ethAddrStruct = req.arp_ha;
-
- ethAddrStruct.sa_family = ARPHRD_ETHER;
- if (!checkLenAndCopy(env, ethAddr, ETH_ALEN, ethAddrStruct.sa_data)) {
- jniThrowException(env, "java/io/IOException", "Invalid ethAddr length");
- return;
- }
-
- netAddrStruct.sin_family = AF_INET;
- if (!checkLenAndCopy(env, ipv4Addr, sizeof(in_addr), &netAddrStruct.sin_addr)) {
- jniThrowException(env, "java/io/IOException", "Invalid ipv4Addr length");
- return;
- }
-
- int ifLen = env->GetStringLength(ifname);
- // IFNAMSIZ includes the terminating NULL character
- if (ifLen >= IFNAMSIZ) {
- jniThrowException(env, "java/io/IOException", "ifname too long");
- return;
- }
- env->GetStringUTFRegion(ifname, 0, ifLen, req.arp_dev);
-
- req.arp_flags = ATF_COM; // Completed entry (ha valid)
- int fd = jniGetFDFromFileDescriptor(env, javaFd);
- if (fd < 0) {
- jniThrowExceptionFmt(env, "java/io/IOException", "Invalid file descriptor");
- return;
- }
- // See also: man 7 arp
- if (ioctl(fd, SIOCSARP, &req)) {
- jniThrowExceptionFmt(env, "java/io/IOException", "ioctl error: %s", strerror(errno));
- return;
- }
-}
-
static jobject android_net_utils_resNetworkQuery(JNIEnv *env, jobject thiz, jint netId,
jstring dname, jint ns_class, jint ns_type, jint flags) {
const jsize javaCharsCount = env->GetStringLength(dname);
@@ -464,7 +270,7 @@
return jniCreateFileDescriptor(env, fd);
}
-static jbyteArray android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz, jobject javaFd) {
+static jobject android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz, jobject javaFd) {
int fd = jniGetFDFromFileDescriptor(env, javaFd);
int rcode;
std::vector<uint8_t> buf(MAXPACKETSIZE, 0);
@@ -485,7 +291,10 @@
reinterpret_cast<jbyte*>(buf.data()));
}
- return answer;
+ jclass class_DnsResponse = env->FindClass("android/net/DnsResolver$DnsResponse");
+ jmethodID ctor = env->GetMethodID(class_DnsResponse, "<init>", "([BI)V");
+
+ return env->NewObject(class_DnsResponse, ctor, answer, rcode);
}
static void android_net_utils_resNetworkCancel(JNIEnv *env, jobject thiz, jobject javaFd) {
@@ -542,17 +351,13 @@
{ "bindSocketToNetwork", "(II)I", (void*) android_net_utils_bindSocketToNetwork },
{ "protectFromVpn", "(I)Z", (void*)android_net_utils_protectFromVpn },
{ "queryUserAccess", "(II)Z", (void*)android_net_utils_queryUserAccess },
- { "addArpEntry", "([B[BLjava/lang/String;Ljava/io/FileDescriptor;)V", (void*) android_net_utils_addArpEntry },
- { "attachDhcpFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDhcpFilter },
- { "attachRaFilter", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_attachRaFilter },
- { "attachControlPacketFilter", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_attachControlPacketFilter },
{ "attachDropAllBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDropAllBPFFilter },
{ "detachBPFFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_detachBPFFilter },
{ "getTcpRepairWindow", "(Ljava/io/FileDescriptor;)Landroid/net/TcpRepairWindow;", (void*) android_net_utils_getTcpRepairWindow },
{ "setupRaSocket", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_setupRaSocket },
{ "resNetworkSend", "(I[BII)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkSend },
{ "resNetworkQuery", "(ILjava/lang/String;III)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkQuery },
- { "resNetworkResult", "(Ljava/io/FileDescriptor;)[B", (void*) android_net_utils_resNetworkResult },
+ { "resNetworkResult", "(Ljava/io/FileDescriptor;)Landroid/net/DnsResolver$DnsResponse;", (void*) android_net_utils_resNetworkResult },
{ "resNetworkCancel", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_resNetworkCancel },
};
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index d8c68b4..0e5f53b 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -45,6 +45,7 @@
#include <fcntl.h>
#include <grp.h>
#include <inttypes.h>
+#include <link.h>
#include <malloc.h>
#include <mntent.h>
#include <paths.h>
@@ -53,6 +54,7 @@
#include <sys/capability.h>
#include <sys/cdefs.h>
#include <sys/eventfd.h>
+#include <sys/mman.h>
#include <sys/personality.h>
#include <sys/prctl.h>
#include <sys/resource.h>
@@ -68,7 +70,9 @@
#include <android-base/properties.h>
#include <android-base/file.h>
#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include <android-base/unique_fd.h>
+#include <cutils/ashmem.h>
#include <cutils/fs.h>
#include <cutils/multiuser.h>
#include <private/android_filesystem_config.h>
@@ -1486,6 +1490,11 @@
} else {
ALOGE("Unable to fetch Blastula pool socket file descriptor");
}
+
+ /*
+ * ashmem initialization to avoid dlopen overhead
+ */
+ ashmem_init();
}
/**
@@ -1540,6 +1549,26 @@
return gBlastulaPoolCount;
}
+static int disable_execute_only(struct dl_phdr_info *info, size_t size, void *data) {
+ // Search for any execute-only segments and mark them read+execute.
+ for (int i = 0; i < info->dlpi_phnum; i++) {
+ if ((info->dlpi_phdr[i].p_type == PT_LOAD) && (info->dlpi_phdr[i].p_flags == PF_X)) {
+ mprotect(reinterpret_cast<void*>(info->dlpi_addr + info->dlpi_phdr[i].p_vaddr),
+ info->dlpi_phdr[i].p_memsz, PROT_READ | PROT_EXEC);
+ }
+ }
+ // Return non-zero to exit dl_iterate_phdr.
+ return 0;
+}
+
+/**
+ * @param env Managed runtime environment
+ * @return True if disable was successful.
+ */
+static jboolean com_android_internal_os_Zygote_nativeDisableExecuteOnly(JNIEnv* env, jclass) {
+ return dl_iterate_phdr(disable_execute_only, nullptr) == 0;
+}
+
static const JNINativeMethod gMethods[] = {
{ "nativeSecurityInit", "()V",
(void *) com_android_internal_os_Zygote_nativeSecurityInit },
@@ -1568,7 +1597,9 @@
{ "nativeGetBlastulaPoolEventFD", "()I",
(void *) com_android_internal_os_Zygote_nativeGetBlastulaPoolEventFD },
{ "nativeGetBlastulaPoolCount", "()I",
- (void *) com_android_internal_os_Zygote_nativeGetBlastulaPoolCount }
+ (void *) com_android_internal_os_Zygote_nativeGetBlastulaPoolCount },
+ { "nativeDisableExecuteOnly", "()Z",
+ (void *) com_android_internal_os_Zygote_nativeDisableExecuteOnly }
};
int register_com_android_internal_os_Zygote(JNIEnv* env) {
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 8e6db0b..2071b98 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -453,7 +453,6 @@
}
if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
- LOG(INFO) << "Ignoring open file descriptor " << fd;
continue;
}
@@ -487,7 +486,6 @@
}
if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
- LOG(INFO) << "Ignoring open file descriptor " << fd;
continue;
}
diff --git a/core/res/Android.bp b/core/res/Android.bp
index e66f1a2..4e60f8c 100644
--- a/core/res/Android.bp
+++ b/core/res/Android.bp
@@ -39,3 +39,12 @@
// PRODUCT-agnostic resource data like IDs and type definitions.
export_package_resources: true,
}
+
+// This logic can be removed once robolectric's transition to binary resources is complete
+filegroup {
+ name: "robolectric_framework_raw_res_files",
+ srcs: [
+ "assets/**/*",
+ "res/**/*",
+ ],
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 9aedb76..ccf5199 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -915,6 +915,9 @@
call with the option to redirect the call to a different number or
abort the call altogether.
<p>Protection level: dangerous
+
+ @deprecated Applications should use {@link android.telecom.CallRedirectionService} instead
+ of the {@link android.content.Intent#ACTION_NEW_OUTGOING_CALL} broadcast.
-->
<permission android:name="android.permission.PROCESS_OUTGOING_CALLS"
android:permissionGroup="android.permission-group.CALL_LOG"
@@ -1577,6 +1580,12 @@
<permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"
android:protectionLevel="signature|privileged" />
+ <!-- @SystemApi Allows an internal user to set signal strength in NetworkRequest. This kind of
+ request will wake up device when signal strength meets the given value.
+ @hide -->
+ <permission android:name="android.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP"
+ android:protectionLevel="signature|privileged" />
+
<!-- @SystemApi Allows a system application to access hardware packet offload capabilities.
@hide -->
<permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD"
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 7698d27..f1e9d65 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -302,14 +302,15 @@
Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
<integer translatable="false" name="config_networkAvoidBadWifi">1</integer>
- <!-- The URL returned by ConnectivityManager#getCaptivePortalServerUrl. The actual returned
- value is controlled by Settings.Global.CAPTIVE_PORTAL_HTTP_URL. This is the default value
- used if that setting is unset.
+ <!-- Configuration hook for the URL returned by ConnectivityManager#getCaptivePortalServerUrl.
+ If empty, the returned value is controlled by Settings.Global.CAPTIVE_PORTAL_HTTP_URL,
+ and if that value is empty, the framework will use a hard-coded default.
This is *NOT* a URL that will always be used by the system network validation to detect
captive portals: NetworkMonitor may use different strategies and will not necessarily use
this URL. NetworkMonitor behaviour should be configured with NetworkStack resource overlays
instead. -->
- <string translatable="false" name="config_networkDefaultCaptivePortalServerUrl">http://connectivitycheck.gstatic.com/generate_204</string>
+ <!--suppress CheckTagEmptyBody -->
+ <string translatable="false" name="config_networkCaptivePortalServerUrl"></string>
<!-- If the hardware supports specially marking packets that caused a wakeup of the
main CPU, set this value to the mark used. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 05303c9..e98a984 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1945,7 +1945,7 @@
<java-symbol type="integer" name="config_networkNotifySwitchType" />
<java-symbol type="array" name="config_networkNotifySwitches" />
<java-symbol type="integer" name="config_networkAvoidBadWifi" />
- <java-symbol type="string" name="config_networkDefaultCaptivePortalServerUrl" />
+ <java-symbol type="string" name="config_networkCaptivePortalServerUrl" />
<java-symbol type="integer" name="config_networkWakeupPacketMark" />
<java-symbol type="integer" name="config_networkWakeupPacketMask" />
<java-symbol type="bool" name="config_apfDrop802_3Frames" />
diff --git a/core/tests/BTtraffic/Android.bp b/core/tests/BTtraffic/Android.bp
new file mode 100644
index 0000000..e508570
--- /dev/null
+++ b/core/tests/BTtraffic/Android.bp
@@ -0,0 +1,7 @@
+android_app {
+ name: "bttraffic",
+ srcs: ["src/**/*.java"],
+ resource_dirs: ["res"],
+ sdk_version: "current",
+ certificate: "platform",
+}
diff --git a/core/tests/BTtraffic/Android.mk b/core/tests/BTtraffic/Android.mk
deleted file mode 100644
index f826ae9..0000000
--- a/core/tests/BTtraffic/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_RESOURCE_DIR := \
- $(LOCAL_PATH)/res
-
-LOCAL_PACKAGE_NAME := bttraffic
-LOCAL_SDK_VERSION := current
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/core/tests/BroadcastRadioTests/Android.bp b/core/tests/BroadcastRadioTests/Android.bp
new file mode 100644
index 0000000..1d441f6
--- /dev/null
+++ b/core/tests/BroadcastRadioTests/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "BroadcastRadioTests",
+ privileged: true,
+ certificate: "platform",
+ // TODO(b/13282254): uncomment when b/13282254 is fixed
+ // sdk_version: "current"
+ platform_apis: true,
+ static_libs: [
+ "compatibility-device-util",
+ "android-support-test",
+ "testng",
+ ],
+ libs: ["android.test.base"],
+ srcs: ["src/**/*.java"],
+ dex_preopt: {
+ enabled: false,
+ },
+ optimize: {
+ enabled: false,
+ },
+}
diff --git a/core/tests/BroadcastRadioTests/Android.mk b/core/tests/BroadcastRadioTests/Android.mk
deleted file mode 100644
index 24f0cf0..0000000
--- a/core/tests/BroadcastRadioTests/Android.mk
+++ /dev/null
@@ -1,38 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := BroadcastRadioTests
-
-LOCAL_PRIVILEGED_MODULE := true
-LOCAL_CERTIFICATE := platform
-LOCAL_MODULE_TAGS := tests
-# TODO(b/13282254): uncomment when b/13282254 is fixed
-# LOCAL_SDK_VERSION := current
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util android-support-test testng
-
-LOCAL_JAVA_LIBRARIES := android.test.base
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_DEX_PREOPT := false
-LOCAL_PROGUARD_ENABLED := disabled
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/ConnectivityManagerTest/Android.bp b/core/tests/ConnectivityManagerTest/Android.bp
new file mode 100644
index 0000000..a33d219
--- /dev/null
+++ b/core/tests/ConnectivityManagerTest/Android.bp
@@ -0,0 +1,26 @@
+// Copyright (C) 2010, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "ConnectivityManagerTest",
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ static_libs: ["junit"],
+ // Include all test java files.
+ srcs: ["src/**/*.java"],
+ platform_apis: true,
+ certificate: "platform",
+}
diff --git a/core/tests/ConnectivityManagerTest/Android.mk b/core/tests/ConnectivityManagerTest/Android.mk
deleted file mode 100644
index 8c0a330..0000000
--- a/core/tests/ConnectivityManagerTest/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2010, The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-LOCAL_STATIC_JAVA_LIBRARIES := junit
-
-# Include all test java files.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := ConnectivityManagerTest
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/SvcMonitor/Android.bp b/core/tests/SvcMonitor/Android.bp
new file mode 100644
index 0000000..606e87c
--- /dev/null
+++ b/core/tests/SvcMonitor/Android.bp
@@ -0,0 +1,7 @@
+android_app {
+ name: "svcmonitor",
+ srcs: ["src/**/*.java"],
+ resource_dirs: ["res"],
+ sdk_version: "current",
+ certificate: "platform",
+}
diff --git a/core/tests/SvcMonitor/Android.mk b/core/tests/SvcMonitor/Android.mk
deleted file mode 100644
index 94ddccb..0000000
--- a/core/tests/SvcMonitor/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_RESOURCE_DIR := \
- $(LOCAL_PATH)/res
-
-LOCAL_PACKAGE_NAME := svcmonitor
-LOCAL_SDK_VERSION := current
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/NetworkStackPermissionStub/Android.bp b/core/tests/bandwidthtests/Android.bp
similarity index 60%
copy from packages/NetworkStackPermissionStub/Android.bp
copy to core/tests/bandwidthtests/Android.bp
index 8cee92e..5d881b8 100644
--- a/packages/NetworkStackPermissionStub/Android.bp
+++ b/core/tests/bandwidthtests/Android.bp
@@ -1,5 +1,4 @@
-//
-// Copyright (C) 2019 The Android Open Source Project
+// Copyright (C) 2011 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.
@@ -12,17 +11,16 @@
// 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.
-//
-// Stub APK to define permissions for NetworkStack
-android_app {
- name: "NetworkStackPermissionStub",
- // TODO: mark app as hasCode=false in manifest once soong stops complaining about apps without
- // a classes.dex.
+android_test {
+ name: "BandwidthTests",
+ // Include all test java files.
srcs: ["src/**/*.java"],
+ libs: [
+ "android.test.runner",
+ "org.apache.http.legacy",
+ "android.test.base",
+ ],
+ static_libs: ["junit"],
platform_apis: true,
- min_sdk_version: "28",
- certificate: "networkstack",
- privileged: true,
- manifest: "AndroidManifest.xml",
}
diff --git a/core/tests/bandwidthtests/Android.mk b/core/tests/bandwidthtests/Android.mk
deleted file mode 100644
index dc80d00..0000000
--- a/core/tests/bandwidthtests/Android.mk
+++ /dev/null
@@ -1,36 +0,0 @@
-# Copyright (C) 2011 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.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Include all test java files.
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := \
- android.test.runner \
- org.apache.http.legacy \
- android.test.base \
-
-LOCAL_STATIC_JAVA_LIBRARIES := junit
-LOCAL_PACKAGE_NAME := BandwidthTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/core/tests/benchmarks/Android.bp b/core/tests/benchmarks/Android.bp
new file mode 100644
index 0000000..8dd7928
--- /dev/null
+++ b/core/tests/benchmarks/Android.bp
@@ -0,0 +1,24 @@
+// -*- mode: makefile -*-
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// build framework base core benchmarks
+// ============================================================
+
+java_library {
+ name: "frameworks-base-core-benchmarks",
+ installable: true,
+ srcs: ["src/**/*.java"],
+ libs: ["caliper-api-target"],
+}
diff --git a/core/tests/benchmarks/Android.mk b/core/tests/benchmarks/Android.mk
deleted file mode 100644
index 25181b5..0000000
--- a/core/tests/benchmarks/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-# -*- mode: makefile -*-
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-# build framework base core benchmarks
-# ============================================================
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := frameworks-base-core-benchmarks
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_CLASS := JAVA_LIBRARIES
-LOCAL_SRC_FILES := $(call all-java-files-under, src/)
-
-LOCAL_JAVA_LIBRARIES := \
- caliper-api-target
-
-include $(BUILD_JAVA_LIBRARY)
diff --git a/core/tests/bluetoothtests/Android.bp b/core/tests/bluetoothtests/Android.bp
new file mode 100644
index 0000000..4b6f9db
--- /dev/null
+++ b/core/tests/bluetoothtests/Android.bp
@@ -0,0 +1,12 @@
+android_test {
+ name: "BluetoothTests",
+ // Include all test java files.
+ srcs: ["src/**/*.java"],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ static_libs: ["junit"],
+ platform_apis: true,
+ certificate: "platform",
+}
diff --git a/core/tests/bluetoothtests/Android.mk b/core/tests/bluetoothtests/Android.mk
deleted file mode 100644
index bb4e302..0000000
--- a/core/tests/bluetoothtests/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Include all test java files.
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-LOCAL_STATIC_JAVA_LIBRARIES := junit
-LOCAL_PACKAGE_NAME := BluetoothTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/core/tests/coretests/src/android/app/ApplicationLoadersTest.java b/core/tests/coretests/src/android/app/ApplicationLoadersTest.java
new file mode 100644
index 0000000..5aee4d3
--- /dev/null
+++ b/core/tests/coretests/src/android/app/ApplicationLoadersTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2019 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.app;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.content.pm.SharedLibraryInfo;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ApplicationLoadersTest {
+
+ // a library installed onto the device with no dependencies
+ private static final String LIB_A = "/system/framework/android.hidl.base-V1.0-java.jar";
+ // a library installed onto the device which only depends on A
+ private static final String LIB_DEP_A = "/system/framework/android.hidl.manager-V1.0-java.jar";
+
+ private static SharedLibraryInfo createLib(String zip) {
+ return new SharedLibraryInfo(
+ zip, null /*packageName*/, null /*codePaths*/, null /*name*/, 0 /*version*/,
+ SharedLibraryInfo.TYPE_BUILTIN, null /*declaringPackage*/,
+ null /*dependentPackages*/, null /*dependencies*/);
+ }
+
+ @Test
+ public void testGetNonExistentLib() {
+ ApplicationLoaders loaders = new ApplicationLoaders();
+ assertEquals(null, loaders.getCachedNonBootclasspathSystemLib(
+ "/system/framework/nonexistentlib.jar", null, null, null));
+ }
+
+ @Test
+ public void testCacheExistentLib() {
+ ApplicationLoaders loaders = new ApplicationLoaders();
+ SharedLibraryInfo libA = createLib(LIB_A);
+
+ loaders.createAndCacheNonBootclasspathSystemClassLoaders(new SharedLibraryInfo[]{libA});
+
+ assertNotEquals(null, loaders.getCachedNonBootclasspathSystemLib(
+ LIB_A, null, null, null));
+ }
+
+ @Test
+ public void testNonNullParent() {
+ ApplicationLoaders loaders = new ApplicationLoaders();
+ SharedLibraryInfo libA = createLib(LIB_A);
+
+ ClassLoader parent = ClassLoader.getSystemClassLoader();
+ assertNotEquals(null, parent);
+
+ loaders.createAndCacheNonBootclasspathSystemClassLoaders(new SharedLibraryInfo[]{libA});
+
+ assertEquals(null, loaders.getCachedNonBootclasspathSystemLib(
+ LIB_A, parent, null, null));
+ }
+
+ @Test
+ public void testNonNullClassLoaderNamespace() {
+ ApplicationLoaders loaders = new ApplicationLoaders();
+ SharedLibraryInfo libA = createLib(LIB_A);
+
+ loaders.createAndCacheNonBootclasspathSystemClassLoaders(new SharedLibraryInfo[]{libA});
+
+ assertEquals(null, loaders.getCachedNonBootclasspathSystemLib(
+ LIB_A, null, "other classloader", null));
+ }
+
+ @Test
+ public void testDifferentSharedLibraries() {
+ ApplicationLoaders loaders = new ApplicationLoaders();
+ SharedLibraryInfo libA = createLib(LIB_A);
+
+ // any other existent lib
+ ClassLoader dep = ClassLoader.getSystemClassLoader();
+ ArrayList<ClassLoader> sharedLibraries = new ArrayList<>();
+ sharedLibraries.add(dep);
+
+ loaders.createAndCacheNonBootclasspathSystemClassLoaders(new SharedLibraryInfo[]{libA});
+
+ assertEquals(null, loaders.getCachedNonBootclasspathSystemLib(
+ LIB_A, null, null, sharedLibraries));
+ }
+
+ @Test
+ public void testDependentLibs() {
+ ApplicationLoaders loaders = new ApplicationLoaders();
+ SharedLibraryInfo libA = createLib(LIB_A);
+ SharedLibraryInfo libB = createLib(LIB_DEP_A);
+ libB.addDependency(libA);
+
+ loaders.createAndCacheNonBootclasspathSystemClassLoaders(
+ new SharedLibraryInfo[]{libA, libB});
+
+ ClassLoader loadA = loaders.getCachedNonBootclasspathSystemLib(
+ LIB_A, null, null, null);
+ assertNotEquals(null, loadA);
+
+ ArrayList<ClassLoader> sharedLibraries = new ArrayList<>();
+ sharedLibraries.add(loadA);
+
+ assertNotEquals(null, loaders.getCachedNonBootclasspathSystemLib(
+ LIB_DEP_A, null, null, sharedLibraries));
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void testDependentLibsWrongOrder() {
+ ApplicationLoaders loaders = new ApplicationLoaders();
+ SharedLibraryInfo libA = createLib(LIB_A);
+ SharedLibraryInfo libB = createLib(LIB_DEP_A);
+ libB.addDependency(libA);
+
+ loaders.createAndCacheNonBootclasspathSystemClassLoaders(
+ new SharedLibraryInfo[]{libB, libA});
+ }
+}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index af03aac..8e383a5 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -185,11 +185,7 @@
Settings.Global.DATA_ROAMING,
Settings.Global.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS,
Settings.Global.DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS,
- Settings.Global.DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD,
- Settings.Global.DATA_STALL_EVALUATION_TYPE,
- Settings.Global.DATA_STALL_MIN_EVALUATE_INTERVAL,
Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK,
- Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD,
Settings.Global.DEBUG_APP,
Settings.Global.DEBUG_VIEW_ATTRIBUTES,
Settings.Global.DEFAULT_DNS_SERVER,
@@ -537,7 +533,6 @@
Settings.Secure.BACKUP_ENABLED,
Settings.Secure.BACKUP_PROVISIONED,
Settings.Secure.BACKUP_TRANSPORT,
- Settings.Secure.CALL_REDIRECTION_DEFAULT_APPLICATION,
Settings.Secure.CALL_SCREENING_DEFAULT_COMPONENT,
Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED, // Candidate for backup?
Settings.Secure.CARRIER_APPS_HANDLED,
diff --git a/core/tests/featureflagtests/Android.bp b/core/tests/featureflagtests/Android.bp
new file mode 100644
index 0000000..a910499
--- /dev/null
+++ b/core/tests/featureflagtests/Android.bp
@@ -0,0 +1,19 @@
+android_test {
+ name: "FrameworksCoreFeatureFlagTests",
+ // We only want this apk build for tests.
+ // Include all test java files.
+ srcs: ["src/**/*.java"],
+ dxflags: ["--core-library"],
+ static_libs: [
+ "android-common",
+ "frameworks-core-util-lib",
+ "android-support-test",
+ ],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ platform_apis: true,
+ certificate: "platform",
+ test_suites: ["device-tests"],
+}
diff --git a/core/tests/featureflagtests/Android.mk b/core/tests/featureflagtests/Android.mk
deleted file mode 100644
index 5e518b6..0000000
--- a/core/tests/featureflagtests/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Include all test java files.
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, src)
-
-LOCAL_DX_FLAGS := --core-library
-LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib android-support-test
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-LOCAL_PACKAGE_NAME := FrameworksCoreFeatureFlagTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/AutoLocTestApp/Android.bp b/core/tests/hosttests/test-apps/AutoLocTestApp/Android.bp
new file mode 100644
index 0000000..1442481
--- /dev/null
+++ b/core/tests/hosttests/test-apps/AutoLocTestApp/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "AutoLocTestApp",
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/AutoLocTestApp/Android.mk b/core/tests/hosttests/test-apps/AutoLocTestApp/Android.mk
deleted file mode 100644
index b3cab48..0000000
--- a/core/tests/hosttests/test-apps/AutoLocTestApp/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := AutoLocTestApp
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/Android.bp b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/Android.bp
new file mode 100644
index 0000000..438ed25
--- /dev/null
+++ b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "AutoLocVersionedTestApp_v1",
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/Android.mk b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/Android.mk
deleted file mode 100644
index a887bac..0000000
--- a/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v1/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := AutoLocVersionedTestApp_v1
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/Android.bp b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/Android.bp
new file mode 100644
index 0000000..2ac72a1
--- /dev/null
+++ b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "AutoLocVersionedTestApp_v2",
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/Android.mk b/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/Android.mk
deleted file mode 100644
index 69084bf..0000000
--- a/core/tests/hosttests/test-apps/AutoLocVersionedTestApp_v2/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := AutoLocVersionedTestApp_v2
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/Android.bp b/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/Android.bp
new file mode 100644
index 0000000..e06e82e
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/Android.bp
@@ -0,0 +1,20 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "ExternalLocAllPermsTestApp",
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+ static_libs: ["junit"],
+}
diff --git a/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/Android.mk b/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/Android.mk
deleted file mode 100644
index 5a545e5..0000000
--- a/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/Android.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_STATIC_JAVA_LIBRARIES := junit
-
-LOCAL_PACKAGE_NAME := ExternalLocAllPermsTestApp
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/ExternalLocPermsFLTestApp/Android.bp b/core/tests/hosttests/test-apps/ExternalLocPermsFLTestApp/Android.bp
new file mode 100644
index 0000000..c48dcd5
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalLocPermsFLTestApp/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "ExternalLocPermFLTestApp",
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/ExternalLocPermsFLTestApp/Android.mk b/core/tests/hosttests/test-apps/ExternalLocPermsFLTestApp/Android.mk
deleted file mode 100644
index 9a05fa6..0000000
--- a/core/tests/hosttests/test-apps/ExternalLocPermsFLTestApp/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := ExternalLocPermFLTestApp
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/ExternalLocTestApp/Android.bp b/core/tests/hosttests/test-apps/ExternalLocTestApp/Android.bp
new file mode 100644
index 0000000..5c1c15a
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalLocTestApp/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "ExternalLocTestApp",
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/ExternalLocTestApp/Android.mk b/core/tests/hosttests/test-apps/ExternalLocTestApp/Android.mk
deleted file mode 100644
index 5aec78a..0000000
--- a/core/tests/hosttests/test-apps/ExternalLocTestApp/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := ExternalLocTestApp
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/Android.bp b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/Android.bp
new file mode 100644
index 0000000..13f5066
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "ExternalLocVersionedTestApp_v1",
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/Android.mk b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/Android.mk
deleted file mode 100644
index 05f62cd..0000000
--- a/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v1/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := ExternalLocVersionedTestApp_v1
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/Android.bp b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/Android.bp
new file mode 100644
index 0000000..e02ffb3
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "ExternalLocVersionedTestApp_v2",
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/Android.mk b/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/Android.mk
deleted file mode 100644
index aa31759..0000000
--- a/core/tests/hosttests/test-apps/ExternalLocVersionedTestApp_v2/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := ExternalLocVersionedTestApp_v2
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPerms/Android.bp b/core/tests/hosttests/test-apps/ExternalSharedPerms/Android.bp
new file mode 100644
index 0000000..de09800
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPerms/Android.bp
@@ -0,0 +1,21 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "ExternalSharedPermsTestApp",
+ srcs: ["src/**/*.java"],
+ static_libs: ["junit"],
+ libs: ["android.test.base.stubs"],
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPerms/Android.mk b/core/tests/hosttests/test-apps/ExternalSharedPerms/Android.mk
deleted file mode 100644
index b255c7e..0000000
--- a/core/tests/hosttests/test-apps/ExternalSharedPerms/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := junit
-
-LOCAL_JAVA_LIBRARIES := android.test.base.stubs
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := ExternalSharedPermsTestApp
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.bp b/core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.bp
new file mode 100644
index 0000000..435144f
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.bp
@@ -0,0 +1,21 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "ExternalSharedPermsBTTestApp",
+ srcs: ["src/**/*.java"],
+ static_libs: ["junit"],
+ libs: ["android.test.base.stubs"],
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.mk b/core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.mk
deleted file mode 100644
index 428b1f8..0000000
--- a/core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := junit
-
-LOCAL_JAVA_LIBRARIES := android.test.base.stubs
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := ExternalSharedPermsBTTestApp
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.bp b/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.bp
new file mode 100644
index 0000000..445bac9
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.bp
@@ -0,0 +1,22 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "ExternalSharedPermsDiffKeyTestApp",
+ srcs: ["src/**/*.java"],
+ static_libs: ["junit"],
+ libs: ["android.test.base.stubs"],
+ sdk_version: "current",
+ certificate: "media",
+}
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.mk b/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.mk
deleted file mode 100644
index 93ece86..0000000
--- a/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := junit
-
-LOCAL_JAVA_LIBRARIES := android.test.base.stubs
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := ExternalSharedPermsDiffKeyTestApp
-
-LOCAL_CERTIFICATE := media
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.bp b/core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.bp
new file mode 100644
index 0000000..d1da399
--- /dev/null
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.bp
@@ -0,0 +1,21 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "ExternalSharedPermsFLTestApp",
+ srcs: ["src/**/*.java"],
+ static_libs: ["junit"],
+ libs: ["android.test.base.stubs"],
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.mk b/core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.mk
deleted file mode 100644
index b348966..0000000
--- a/core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := junit
-
-LOCAL_JAVA_LIBRARIES := android.test.base.stubs
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := ExternalSharedPermsFLTestApp
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/InternalLocTestApp/Android.bp b/core/tests/hosttests/test-apps/InternalLocTestApp/Android.bp
new file mode 100644
index 0000000..fab9d43
--- /dev/null
+++ b/core/tests/hosttests/test-apps/InternalLocTestApp/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "InternalLocTestApp",
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/InternalLocTestApp/Android.mk b/core/tests/hosttests/test-apps/InternalLocTestApp/Android.mk
deleted file mode 100644
index 5b58e72..0000000
--- a/core/tests/hosttests/test-apps/InternalLocTestApp/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := InternalLocTestApp
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/Android.bp b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/Android.bp
new file mode 100644
index 0000000..dcf1687
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/Android.bp
@@ -0,0 +1,22 @@
+// Copyright (C) 2014 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.
+
+android_test {
+ name: "MultiDexLegacyTestServicesTests",
+ srcs: ["src/**/*.java"],
+ sdk_version: "9",
+ dex_preopt: {
+ enabled: false,
+ },
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/Android.mk
deleted file mode 100644
index 85304b6..0000000
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServicesTests/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (C) 2014 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := MultiDexLegacyTestServicesTests
-
-LOCAL_SDK_VERSION := 9
-
-LOCAL_DEX_PREOPT := false
-
-include $(BUILD_PACKAGE)
-
diff --git a/core/tests/hosttests/test-apps/NoLocTestApp/Android.bp b/core/tests/hosttests/test-apps/NoLocTestApp/Android.bp
new file mode 100644
index 0000000..50a2de4
--- /dev/null
+++ b/core/tests/hosttests/test-apps/NoLocTestApp/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "NoLocTestApp",
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/NoLocTestApp/Android.mk b/core/tests/hosttests/test-apps/NoLocTestApp/Android.mk
deleted file mode 100644
index 11916b0..0000000
--- a/core/tests/hosttests/test-apps/NoLocTestApp/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := NoLocTestApp
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/Android.bp b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/Android.bp
new file mode 100644
index 0000000..4bc9edc
--- /dev/null
+++ b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "NoLocVersionedTestApp_v1",
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/Android.mk b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/Android.mk
deleted file mode 100644
index 36413ee..0000000
--- a/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v1/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := NoLocVersionedTestApp_v1
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/Android.bp b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/Android.bp
new file mode 100644
index 0000000..dd2952b
--- /dev/null
+++ b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "NoLocVersionedTestApp_v2",
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/Android.mk b/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/Android.mk
deleted file mode 100644
index 27d03b0..0000000
--- a/core/tests/hosttests/test-apps/NoLocVersionedTestApp_v2/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := NoLocVersionedTestApp_v2
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/SharedUid/32/Android.bp b/core/tests/hosttests/test-apps/SharedUid/32/Android.bp
new file mode 100644
index 0000000..f3e3ede
--- /dev/null
+++ b/core/tests/hosttests/test-apps/SharedUid/32/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2014 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.
+//
+
+// This makefile shows how to build a shared library and an activity that
+// bundles the shared library and calls it using JNI.
+
+// Build activity
+
+android_test {
+ name: "PMTest_Java32",
+ srcs: ["**/*.java"],
+ compile_multilib: "32",
+ jni_libs: ["libpmtest32"],
+ optimize: {
+ enabled: false,
+ },
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/SharedUid/32/Android.mk b/core/tests/hosttests/test-apps/SharedUid/32/Android.mk
deleted file mode 100644
index 7b44f9e..0000000
--- a/core/tests/hosttests/test-apps/SharedUid/32/Android.mk
+++ /dev/null
@@ -1,38 +0,0 @@
-#
-# Copyright (C) 2014 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.
-#
-
-# This makefile shows how to build a shared library and an activity that
-# bundles the shared library and calls it using JNI.
-
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-LOCAL_PATH:= $(TOP_LOCAL_PATH)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := PMTest_Java32
-LOCAL_MULTILIB := 32
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_JNI_SHARED_LIBRARIES = libpmtest32
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_SDK_VERSION := current
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/SharedUid/64/Android.bp b/core/tests/hosttests/test-apps/SharedUid/64/Android.bp
new file mode 100644
index 0000000..5d9c0b5
--- /dev/null
+++ b/core/tests/hosttests/test-apps/SharedUid/64/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2014 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.
+//
+
+// This makefile shows how to build a shared library and an activity that
+// bundles the shared library and calls it using JNI.
+
+// Build activity
+
+android_test {
+ name: "PMTest_Java64",
+ srcs: ["**/*.java"],
+ compile_multilib: "64",
+ jni_libs: ["libpmtest64"],
+ optimize: {
+ enabled: false,
+ },
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/SharedUid/64/Android.mk b/core/tests/hosttests/test-apps/SharedUid/64/Android.mk
deleted file mode 100644
index cc088c1a..0000000
--- a/core/tests/hosttests/test-apps/SharedUid/64/Android.mk
+++ /dev/null
@@ -1,38 +0,0 @@
-#
-# Copyright (C) 2014 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.
-#
-
-# This makefile shows how to build a shared library and an activity that
-# bundles the shared library and calls it using JNI.
-
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-LOCAL_PATH:= $(TOP_LOCAL_PATH)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := PMTest_Java64
-LOCAL_MULTILIB := 64
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_JNI_SHARED_LIBRARIES = libpmtest64
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_SDK_VERSION := current
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/SharedUid/Android.mk b/core/tests/hosttests/test-apps/SharedUid/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/core/tests/hosttests/test-apps/SharedUid/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/core/tests/hosttests/test-apps/SharedUid/dual/Android.bp b/core/tests/hosttests/test-apps/SharedUid/dual/Android.bp
new file mode 100644
index 0000000..c42192d
--- /dev/null
+++ b/core/tests/hosttests/test-apps/SharedUid/dual/Android.bp
@@ -0,0 +1,44 @@
+//
+// Copyright (C) 2014 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.
+//
+
+// This makefile shows how to build a shared library and an activity that
+// bundles the shared library and calls it using JNI.
+
+// Build activity
+
+android_test {
+ name: "PMTest_Java_dual",
+ srcs: ["**/*.java"],
+ compile_multilib: "both",
+ jni_libs: ["libpmtestdual"],
+ optimize: {
+ enabled: false,
+ },
+ manifest: "dual/AndroidManifest.xml",
+ sdk_version: "current",
+}
+
+android_test {
+ name: "PMTest_Java_multiarch",
+ srcs: ["**/*.java"],
+ compile_multilib: "both",
+ manifest: "multiarch/AndroidManifest.xml",
+ jni_libs: ["libpmtestdual"],
+ optimize: {
+ enabled: false,
+ },
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/SharedUid/dual/Android.mk b/core/tests/hosttests/test-apps/SharedUid/dual/Android.mk
deleted file mode 100644
index 5bcd078..0000000
--- a/core/tests/hosttests/test-apps/SharedUid/dual/Android.mk
+++ /dev/null
@@ -1,58 +0,0 @@
-#
-# Copyright (C) 2014 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.
-#
-
-# This makefile shows how to build a shared library and an activity that
-# bundles the shared library and calls it using JNI.
-
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-LOCAL_PATH:= $(TOP_LOCAL_PATH)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := PMTest_Java_dual
-LOCAL_MULTILIB := both
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_JNI_SHARED_LIBRARIES = libpmtestdual
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_MANIFEST_FILE := dual/AndroidManifest.xml
-
-LOCAL_SDK_VERSION := current
-include $(BUILD_PACKAGE)
-
-LOCAL_PATH:= $(TOP_LOCAL_PATH)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := PMTest_Java_multiarch
-LOCAL_MULTILIB := both
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_MANIFEST_FILE := multiarch/AndroidManifest.xml
-
-LOCAL_JNI_SHARED_LIBRARIES = libpmtestdual
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_SDK_VERSION := current
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/SharedUid/java_only/Android.bp b/core/tests/hosttests/test-apps/SharedUid/java_only/Android.bp
new file mode 100644
index 0000000..baedc6e
--- /dev/null
+++ b/core/tests/hosttests/test-apps/SharedUid/java_only/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2014 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.
+//
+
+// This makefile shows how to build a shared library and an activity that
+// bundles the shared library and calls it using JNI.
+
+// Build activity
+
+android_test {
+ name: "PMTest_Java",
+ srcs: ["**/*.java"],
+ optimize: {
+ enabled: false,
+ },
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/SharedUid/java_only/Android.mk b/core/tests/hosttests/test-apps/SharedUid/java_only/Android.mk
deleted file mode 100644
index b846756..0000000
--- a/core/tests/hosttests/test-apps/SharedUid/java_only/Android.mk
+++ /dev/null
@@ -1,40 +0,0 @@
-#
-# Copyright (C) 2014 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.
-#
-
-# This makefile shows how to build a shared library and an activity that
-# bundles the shared library and calls it using JNI.
-
-TOP_LOCAL_PATH:= $(call my-dir)
-
-# Build activity
-
-LOCAL_PATH:= $(TOP_LOCAL_PATH)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_PACKAGE_NAME := PMTest_Java
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_SDK_VERSION := current
-include $(BUILD_PACKAGE)
-
-# ============================================================
-
-# Also build all of the sub-targets under this one: the shared library.
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/core/tests/hosttests/test-apps/SimpleTestApp/Android.bp b/core/tests/hosttests/test-apps/SimpleTestApp/Android.bp
new file mode 100644
index 0000000..5f443bd
--- /dev/null
+++ b/core/tests/hosttests/test-apps/SimpleTestApp/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "SimpleTestApp",
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/SimpleTestApp/Android.mk b/core/tests/hosttests/test-apps/SimpleTestApp/Android.mk
deleted file mode 100644
index 82543aa..0000000
--- a/core/tests/hosttests/test-apps/SimpleTestApp/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := SimpleTestApp
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v1_ext/Android.bp b/core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v1_ext/Android.bp
new file mode 100644
index 0000000..800e083
--- /dev/null
+++ b/core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v1_ext/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "UpdateExtToIntLocTestApp_v1_ext",
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v1_ext/Android.mk b/core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v1_ext/Android.mk
deleted file mode 100644
index f2baefe..0000000
--- a/core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v1_ext/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := UpdateExtToIntLocTestApp_v1_ext
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v2_int/Android.bp b/core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v2_int/Android.bp
new file mode 100644
index 0000000..299887c
--- /dev/null
+++ b/core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v2_int/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "UpdateExtToIntLocTestApp_v2_int",
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v2_int/Android.mk b/core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v2_int/Android.mk
deleted file mode 100644
index 492c326..0000000
--- a/core/tests/hosttests/test-apps/UpdateExtToIntLocTestApp_v2_int/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := UpdateExtToIntLocTestApp_v2_int
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v1_ext/Android.bp b/core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v1_ext/Android.bp
new file mode 100644
index 0000000..1530422
--- /dev/null
+++ b/core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v1_ext/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "UpdateExternalLocTestApp_v1_ext",
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v1_ext/Android.mk b/core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v1_ext/Android.mk
deleted file mode 100644
index 45867f7..0000000
--- a/core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v1_ext/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := UpdateExternalLocTestApp_v1_ext
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v2_none/Android.bp b/core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v2_none/Android.bp
new file mode 100644
index 0000000..4c7975e
--- /dev/null
+++ b/core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v2_none/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "UpdateExternalLocTestApp_v2_none",
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v2_none/Android.mk b/core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v2_none/Android.mk
deleted file mode 100644
index 780a9d72..0000000
--- a/core/tests/hosttests/test-apps/UpdateExternalLocTestApp_v2_none/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := UpdateExternalLocTestApp_v2_none
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/VersatileTestApp_Auto/Android.bp b/core/tests/hosttests/test-apps/VersatileTestApp_Auto/Android.bp
new file mode 100644
index 0000000..c6b60c3
--- /dev/null
+++ b/core/tests/hosttests/test-apps/VersatileTestApp_Auto/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "VersatileTestApp_Auto",
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/VersatileTestApp_Auto/Android.mk b/core/tests/hosttests/test-apps/VersatileTestApp_Auto/Android.mk
deleted file mode 100644
index fc42bc4a..0000000
--- a/core/tests/hosttests/test-apps/VersatileTestApp_Auto/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := VersatileTestApp_Auto
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/VersatileTestApp_External/Android.bp b/core/tests/hosttests/test-apps/VersatileTestApp_External/Android.bp
new file mode 100644
index 0000000..db521ef
--- /dev/null
+++ b/core/tests/hosttests/test-apps/VersatileTestApp_External/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "VersatileTestApp_External",
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/VersatileTestApp_External/Android.mk b/core/tests/hosttests/test-apps/VersatileTestApp_External/Android.mk
deleted file mode 100644
index c72a92c..0000000
--- a/core/tests/hosttests/test-apps/VersatileTestApp_External/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := VersatileTestApp_External
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/VersatileTestApp_Internal/Android.bp b/core/tests/hosttests/test-apps/VersatileTestApp_Internal/Android.bp
new file mode 100644
index 0000000..ca059302
--- /dev/null
+++ b/core/tests/hosttests/test-apps/VersatileTestApp_Internal/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "VersatileTestApp_Internal",
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/VersatileTestApp_Internal/Android.mk b/core/tests/hosttests/test-apps/VersatileTestApp_Internal/Android.mk
deleted file mode 100644
index e477825e..0000000
--- a/core/tests/hosttests/test-apps/VersatileTestApp_Internal/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := VersatileTestApp_Internal
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/VersatileTestApp_None/Android.bp b/core/tests/hosttests/test-apps/VersatileTestApp_None/Android.bp
new file mode 100644
index 0000000..6e1aac7
--- /dev/null
+++ b/core/tests/hosttests/test-apps/VersatileTestApp_None/Android.bp
@@ -0,0 +1,19 @@
+// Copyright (C) 2010 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+ name: "VersatileTestApp_None",
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/core/tests/hosttests/test-apps/VersatileTestApp_None/Android.mk b/core/tests/hosttests/test-apps/VersatileTestApp_None/Android.mk
deleted file mode 100644
index 1fc516c4..0000000
--- a/core/tests/hosttests/test-apps/VersatileTestApp_None/Android.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := VersatileTestApp_None
-
-include $(BUILD_PACKAGE)
diff --git a/core/tests/notificationtests/Android.bp b/core/tests/notificationtests/Android.bp
new file mode 100644
index 0000000..e744d5a
--- /dev/null
+++ b/core/tests/notificationtests/Android.bp
@@ -0,0 +1,15 @@
+android_test {
+ name: "NotificationStressTests",
+ // Include all test java files.
+ srcs: ["src/**/*.java"],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ // Could build against SDK if it wasn't for the @RepetitiveTest annotation.
+ platform_apis: true,
+ static_libs: [
+ "junit",
+ "ub-uiautomator",
+ ],
+}
diff --git a/core/tests/notificationtests/Android.mk b/core/tests/notificationtests/Android.mk
deleted file mode 100644
index 73ee8b8..0000000
--- a/core/tests/notificationtests/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Include all test java files.
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-LOCAL_PACKAGE_NAME := NotificationStressTests
-# Could build against SDK if it wasn't for the @RepetitiveTest annotation.
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- junit \
- ub-uiautomator
-
-include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/core/tests/overlaytests/device/Android.mk b/core/tests/overlaytests/device/Android.mk
index 680ebeb..07594b4 100644
--- a/core/tests/overlaytests/device/Android.mk
+++ b/core/tests/overlaytests/device/Android.mk
@@ -21,7 +21,7 @@
LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
LOCAL_COMPATIBILITY_SUITE := device-tests
-LOCAL_TARGET_REQUIRED_MODULES := \
+LOCAL_REQUIRED_MODULES := \
OverlayDeviceTests_AppOverlayOne \
OverlayDeviceTests_AppOverlayTwo \
OverlayDeviceTests_FrameworkOverlay
diff --git a/core/tests/systemproperties/Android.bp b/core/tests/systemproperties/Android.bp
new file mode 100644
index 0000000..7ef1b9b
--- /dev/null
+++ b/core/tests/systemproperties/Android.bp
@@ -0,0 +1,16 @@
+android_test {
+ name: "FrameworksCoreSystemPropertiesTests",
+ // Include all test java files.
+ srcs: ["src/**/*.java"],
+ dxflags: ["--core-library"],
+ static_libs: [
+ "android-common",
+ "frameworks-core-util-lib",
+ ],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ platform_apis: true,
+ certificate: "platform",
+}
diff --git a/core/tests/systemproperties/Android.mk b/core/tests/systemproperties/Android.mk
deleted file mode 100644
index 3458be0..0000000
--- a/core/tests/systemproperties/Android.mk
+++ /dev/null
@@ -1,19 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Include all test java files.
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, src)
-
-LOCAL_DX_FLAGS := --core-library
-LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-LOCAL_PACKAGE_NAME := FrameworksCoreSystemPropertiesTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
diff --git a/core/xsd/permission.xsd b/core/xsd/permission.xsd
index 2ef2d04..9520db7 100644
--- a/core/xsd/permission.xsd
+++ b/core/xsd/permission.xsd
@@ -20,33 +20,33 @@
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="permissions">
<xs:complexType>
- <xs:sequence>
- <xs:element name="group" type="group" maxOccurs="unbounded"/>
- <xs:element name="permission" type="permission" maxOccurs="unbounded"/>
- <xs:element name="assign-permission" type="assign-permission" maxOccurs="unbounded"/>
- <xs:element name="split-permission" type="split-permission" maxOccurs="unbounded"/>
- <xs:element name="library" type="library" maxOccurs="unbounded"/>
- <xs:element name="feature" type="feature" maxOccurs="unbounded"/>
- <xs:element name="unavailable-feature" type="unavailable-feature" maxOccurs="unbounded"/>
- <xs:element name="allow-in-power-save-except-idle" type="allow-in-power-save-except-idle" maxOccurs="unbounded"/>
- <xs:element name="allow-in-power-save" type="allow-in-power-save" maxOccurs="unbounded"/>
- <xs:element name="allow-in-data-usage-save" type="allow-in-data-usage-save" maxOccurs="unbounded"/>
- <xs:element name="allow-unthrottled-location" type="allow-unthrottled-location" maxOccurs="unbounded"/>
- <xs:element name="allow-ignore-location-settings" type="allow-ignore-location-settings" maxOccurs="unbounded"/>
- <xs:element name="allow-implicit-broadcast" type="allow-implicit-broadcast" maxOccurs="unbounded"/>
- <xs:element name="app-link" type="app-link" maxOccurs="unbounded"/>
- <xs:element name="system-user-whitelisted-app" type="system-user-whitelisted-app" maxOccurs="unbounded"/>
- <xs:element name="system-user-blacklisted-app" type="system-user-blacklisted-app" maxOccurs="unbounded"/>
- <xs:element name="default-enabled-vr-app" type="default-enabled-vr-app" maxOccurs="unbounded"/>
- <xs:element name="backup-transport-whitelisted-service" type="backup-transport-whitelisted-service" maxOccurs="unbounded"/>
- <xs:element name="disabled-until-used-preinstalled-carrier-associated-app" type="disabled-until-used-preinstalled-carrier-associated-app" maxOccurs="unbounded"/>
- <xs:element name="disabled-until-used-preinstalled-carrier-app" type="disabled-until-used-preinstalled-carrier-app" maxOccurs="unbounded"/>
- <xs:element name="privapp-permissions" type="privapp-permissions" maxOccurs="unbounded"/>
- <xs:element name="oem-permissions" type="oem-permissions" maxOccurs="unbounded"/>
- <xs:element name="hidden-api-whitelisted-app" type="hidden-api-whitelisted-app" maxOccurs="unbounded"/>
- <xs:element name="allow-association" type="allow-association" maxOccurs="unbounded"/>
- <xs:element name="bugreport-whitelisted" type="bugreport-whitelisted" maxOccurs="unbounded"/>
- </xs:sequence>
+ <xs:choice minOccurs="0" maxOccurs="unbounded">
+ <xs:element name="group" type="group"/>
+ <xs:element name="permission" type="permission"/>
+ <xs:element name="assign-permission" type="assign-permission"/>
+ <xs:element name="split-permission" type="split-permission"/>
+ <xs:element name="library" type="library"/>
+ <xs:element name="feature" type="feature"/>
+ <xs:element name="unavailable-feature" type="unavailable-feature"/>
+ <xs:element name="allow-in-power-save-except-idle" type="allow-in-power-save-except-idle"/>
+ <xs:element name="allow-in-power-save" type="allow-in-power-save"/>
+ <xs:element name="allow-in-data-usage-save" type="allow-in-data-usage-save"/>
+ <xs:element name="allow-unthrottled-location" type="allow-unthrottled-location"/>
+ <xs:element name="allow-ignore-location-settings" type="allow-ignore-location-settings"/>
+ <xs:element name="allow-implicit-broadcast" type="allow-implicit-broadcast"/>
+ <xs:element name="app-link" type="app-link"/>
+ <xs:element name="system-user-whitelisted-app" type="system-user-whitelisted-app"/>
+ <xs:element name="system-user-blacklisted-app" type="system-user-blacklisted-app"/>
+ <xs:element name="default-enabled-vr-app" type="default-enabled-vr-app"/>
+ <xs:element name="backup-transport-whitelisted-service" type="backup-transport-whitelisted-service"/>
+ <xs:element name="disabled-until-used-preinstalled-carrier-associated-app" type="disabled-until-used-preinstalled-carrier-associated-app"/>
+ <xs:element name="disabled-until-used-preinstalled-carrier-app" type="disabled-until-used-preinstalled-carrier-app"/>
+ <xs:element name="privapp-permissions" type="privapp-permissions"/>
+ <xs:element name="oem-permissions" type="oem-permissions"/>
+ <xs:element name="hidden-api-whitelisted-app" type="hidden-api-whitelisted-app"/>
+ <xs:element name="allow-association" type="allow-association"/>
+ <xs:element name="bugreport-whitelisted" type="bugreport-whitelisted"/>
+ </xs:choice>
</xs:complexType>
</xs:element>
<xs:complexType name="group">
diff --git a/core/xsd/schema/current.txt b/core/xsd/schema/current.txt
index c25bc14..771c1df 100644
--- a/core/xsd/schema/current.txt
+++ b/core/xsd/schema/current.txt
@@ -153,31 +153,31 @@
public class Permissions {
ctor public Permissions();
- method public java.util.List<com.android.xml.permission.configfile.AllowAssociation> getAllowAssociation();
- method public java.util.List<com.android.xml.permission.configfile.AllowIgnoreLocationSettings> getAllowIgnoreLocationSettings();
- method public java.util.List<com.android.xml.permission.configfile.AllowImplicitBroadcast> getAllowImplicitBroadcast();
- method public java.util.List<com.android.xml.permission.configfile.AllowInDataUsageSave> getAllowInDataUsageSave();
- method public java.util.List<com.android.xml.permission.configfile.AllowInPowerSave> getAllowInPowerSave();
- method public java.util.List<com.android.xml.permission.configfile.AllowInPowerSaveExceptIdle> getAllowInPowerSaveExceptIdle();
- method public java.util.List<com.android.xml.permission.configfile.AllowUnthrottledLocation> getAllowUnthrottledLocation();
- method public java.util.List<com.android.xml.permission.configfile.AppLink> getAppLink();
- method public java.util.List<com.android.xml.permission.configfile.AssignPermission> getAssignPermission();
- method public java.util.List<com.android.xml.permission.configfile.BackupTransportWhitelistedService> getBackupTransportWhitelistedService();
- method public java.util.List<com.android.xml.permission.configfile.BugreportWhitelisted> getBugreportWhitelisted();
- method public java.util.List<com.android.xml.permission.configfile.DefaultEnabledVrApp> getDefaultEnabledVrApp();
- method public java.util.List<com.android.xml.permission.configfile.DisabledUntilUsedPreinstalledCarrierApp> getDisabledUntilUsedPreinstalledCarrierApp();
- method public java.util.List<com.android.xml.permission.configfile.DisabledUntilUsedPreinstalledCarrierAssociatedApp> getDisabledUntilUsedPreinstalledCarrierAssociatedApp();
- method public java.util.List<com.android.xml.permission.configfile.Feature> getFeature();
- method public java.util.List<com.android.xml.permission.configfile.Group> getGroup();
- method public java.util.List<com.android.xml.permission.configfile.HiddenApiWhitelistedApp> getHiddenApiWhitelistedApp();
- method public java.util.List<com.android.xml.permission.configfile.Library> getLibrary();
- method public java.util.List<com.android.xml.permission.configfile.OemPermissions> getOemPermissions();
- method public java.util.List<com.android.xml.permission.configfile.Permission> getPermission();
- method public java.util.List<com.android.xml.permission.configfile.PrivappPermissions> getPrivappPermissions();
- method public java.util.List<com.android.xml.permission.configfile.SplitPermission> getSplitPermission();
- method public java.util.List<com.android.xml.permission.configfile.SystemUserBlacklistedApp> getSystemUserBlacklistedApp();
- method public java.util.List<com.android.xml.permission.configfile.SystemUserWhitelistedApp> getSystemUserWhitelistedApp();
- method public java.util.List<com.android.xml.permission.configfile.UnavailableFeature> getUnavailableFeature();
+ method public java.util.List<com.android.xml.permission.configfile.AllowAssociation> getAllowAssociation_optional();
+ method public java.util.List<com.android.xml.permission.configfile.AllowIgnoreLocationSettings> getAllowIgnoreLocationSettings_optional();
+ method public java.util.List<com.android.xml.permission.configfile.AllowImplicitBroadcast> getAllowImplicitBroadcast_optional();
+ method public java.util.List<com.android.xml.permission.configfile.AllowInDataUsageSave> getAllowInDataUsageSave_optional();
+ method public java.util.List<com.android.xml.permission.configfile.AllowInPowerSaveExceptIdle> getAllowInPowerSaveExceptIdle_optional();
+ method public java.util.List<com.android.xml.permission.configfile.AllowInPowerSave> getAllowInPowerSave_optional();
+ method public java.util.List<com.android.xml.permission.configfile.AllowUnthrottledLocation> getAllowUnthrottledLocation_optional();
+ method public java.util.List<com.android.xml.permission.configfile.AppLink> getAppLink_optional();
+ method public java.util.List<com.android.xml.permission.configfile.AssignPermission> getAssignPermission_optional();
+ method public java.util.List<com.android.xml.permission.configfile.BackupTransportWhitelistedService> getBackupTransportWhitelistedService_optional();
+ method public java.util.List<com.android.xml.permission.configfile.BugreportWhitelisted> getBugreportWhitelisted_optional();
+ method public java.util.List<com.android.xml.permission.configfile.DefaultEnabledVrApp> getDefaultEnabledVrApp_optional();
+ method public java.util.List<com.android.xml.permission.configfile.DisabledUntilUsedPreinstalledCarrierApp> getDisabledUntilUsedPreinstalledCarrierApp_optional();
+ method public java.util.List<com.android.xml.permission.configfile.DisabledUntilUsedPreinstalledCarrierAssociatedApp> getDisabledUntilUsedPreinstalledCarrierAssociatedApp_optional();
+ method public java.util.List<com.android.xml.permission.configfile.Feature> getFeature_optional();
+ method public java.util.List<com.android.xml.permission.configfile.Group> getGroup_optional();
+ method public java.util.List<com.android.xml.permission.configfile.HiddenApiWhitelistedApp> getHiddenApiWhitelistedApp_optional();
+ method public java.util.List<com.android.xml.permission.configfile.Library> getLibrary_optional();
+ method public java.util.List<com.android.xml.permission.configfile.OemPermissions> getOemPermissions_optional();
+ method public java.util.List<com.android.xml.permission.configfile.Permission> getPermission_optional();
+ method public java.util.List<com.android.xml.permission.configfile.PrivappPermissions> getPrivappPermissions_optional();
+ method public java.util.List<com.android.xml.permission.configfile.SplitPermission> getSplitPermission_optional();
+ method public java.util.List<com.android.xml.permission.configfile.SystemUserBlacklistedApp> getSystemUserBlacklistedApp_optional();
+ method public java.util.List<com.android.xml.permission.configfile.SystemUserWhitelistedApp> getSystemUserWhitelistedApp_optional();
+ method public java.util.List<com.android.xml.permission.configfile.UnavailableFeature> getUnavailableFeature_optional();
}
public class PrivappPermissions {
diff --git a/packages/NetworkStackPermissionStub/Android.bp b/core/xsd/vts/Android.bp
similarity index 60%
copy from packages/NetworkStackPermissionStub/Android.bp
copy to core/xsd/vts/Android.bp
index 8cee92e..9cf68c1 100644
--- a/packages/NetworkStackPermissionStub/Android.bp
+++ b/core/xsd/vts/Android.bp
@@ -14,15 +14,21 @@
// limitations under the License.
//
-// Stub APK to define permissions for NetworkStack
-android_app {
- name: "NetworkStackPermissionStub",
- // TODO: mark app as hasCode=false in manifest once soong stops complaining about apps without
- // a classes.dex.
- srcs: ["src/**/*.java"],
- platform_apis: true,
- min_sdk_version: "28",
- certificate: "networkstack",
- privileged: true,
- manifest: "AndroidManifest.xml",
+cc_test {
+ name: "vts_permission_validate_test",
+ srcs: [
+ "ValidatePermission.cpp"
+ ],
+ static_libs: [
+ "android.hardware.audio.common.test.utility",
+ "libxml2",
+ ],
+ shared_libs: [
+ "liblog",
+ "libbase",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
}
diff --git a/location/Android.mk b/core/xsd/vts/Android.mk
similarity index 77%
rename from location/Android.mk
rename to core/xsd/vts/Android.mk
index 50509c6..a5754a4 100644
--- a/location/Android.mk
+++ b/core/xsd/vts/Android.mk
@@ -1,4 +1,5 @@
-# Copyright (C) 2010 The Android Open Source Project
+#
+# Copyright (C) 2019 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.
@@ -11,7 +12,11 @@
# 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.
+#
LOCAL_PATH := $(call my-dir)
-include $(call all-subdir-makefiles, $(LOCAL_PATH))
\ No newline at end of file
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := VtsValidatePermission
+include test/vts/tools/build/Android.host_config.mk
diff --git a/core/xsd/vts/AndroidTest.xml b/core/xsd/vts/AndroidTest.xml
new file mode 100644
index 0000000..e5cc9a0
--- /dev/null
+++ b/core/xsd/vts/AndroidTest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<configuration description="Config for VTS VtsValidatePermission.">
+ <option name="config-descriptor:metadata" key="plan" value="vts-treble" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="abort-on-push-failure" value="false"/>
+ <option name="push-group" value="HostDrivenTest.push"/>
+ <option name="push" value="DATA/etc/permission.xsd->/data/local/tmp/permission.xsd"/>
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="VtsValidatePermission"/>
+ <option name="binary-test-source" value="_32bit::DATA/nativetest/vts_permission_validate_test/vts_permission_validate_test" />
+ <option name="binary-test-source" value="_64bit::DATA/nativetest64/vts_permission_validate_test/vts_permission_validate_test" />
+ <option name="binary-test-type" value="gtest"/>
+ <option name="test-timeout" value="30s"/>
+ </test>
+</configuration>
diff --git a/core/xsd/vts/ValidatePermission.cpp b/core/xsd/vts/ValidatePermission.cpp
new file mode 100644
index 0000000..3499689
--- /dev/null
+++ b/core/xsd/vts/ValidatePermission.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dirent.h>
+#include <regex>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string>
+
+#include "android-base/logging.h"
+#include "utility/ValidateXml.h"
+
+static void get_files_in_dirs(const char* dir_path, std::vector<std::string>& files) {
+ DIR* d;
+ struct dirent* de;
+
+ d = opendir(dir_path);
+ if (d == nullptr) {
+ return;
+ }
+
+ while ((de = readdir(d))) {
+ if (de->d_type != DT_REG) {
+ continue;
+ }
+ if (std::regex_match(de->d_name, std::regex("(.*)(.xml)"))) {
+ files.push_back(de->d_name);
+ }
+ }
+ closedir(d);
+}
+
+TEST(CheckConfig, permission) {
+ RecordProperty("description",
+ "Verify that the permission file "
+ "is valid according to the schema");
+
+ const char* location = "/vendor/etc/permissions";
+
+ std::vector<std::string> files;
+ get_files_in_dirs(location, files);
+
+ for (std::string file_name : files) {
+ EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS(file_name.c_str(), {location},
+ "/data/local/tmp/permission.xsd");
+ }
+}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index d44f5a9..28099a1 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -261,6 +261,7 @@
<permission name="android.permission.MOUNT_FORMAT_FILESYSTEMS"/>
<permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<permission name="android.permission.MOVE_PACKAGE"/>
+ <permission name="android.permission.NETWORK_SCAN"/>
<permission name="android.permission.PACKAGE_USAGE_STATS" />
<!-- Needed for test only -->
<permission name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
diff --git a/packages/NetworkStackPermissionStub/Android.bp b/keystore/tests/Android.bp
similarity index 60%
copy from packages/NetworkStackPermissionStub/Android.bp
copy to keystore/tests/Android.bp
index 8cee92e..d382dd9 100644
--- a/packages/NetworkStackPermissionStub/Android.bp
+++ b/keystore/tests/Android.bp
@@ -1,5 +1,4 @@
-//
-// Copyright (C) 2019 The Android Open Source Project
+// Copyright (C) 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -12,17 +11,13 @@
// 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.
-//
-// Stub APK to define permissions for NetworkStack
-android_app {
- name: "NetworkStackPermissionStub",
- // TODO: mark app as hasCode=false in manifest once soong stops complaining about apps without
- // a classes.dex.
+android_test {
+ name: "KeystoreTests",
+ // LOCAL_MODULE := keystore
srcs: ["src/**/*.java"],
+ static_libs: ["android-support-test"],
platform_apis: true,
- min_sdk_version: "28",
- certificate: "networkstack",
- privileged: true,
- manifest: "AndroidManifest.xml",
+ libs: ["android.test.runner"],
+ certificate: "platform",
}
diff --git a/keystore/tests/Android.mk b/keystore/tests/Android.mk
deleted file mode 100644
index 596e5f5..0000000
--- a/keystore/tests/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-# LOCAL_MODULE := keystore
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- android-support-test
-
-LOCAL_PACKAGE_NAME := KeystoreTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_JAVA_LIBRARIES := android.test.runner
-
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
-
diff --git a/location/tests/Android.bp b/location/tests/Android.bp
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/location/tests/Android.bp
@@ -0,0 +1 @@
+
diff --git a/location/tests/Android.mk b/location/tests/Android.mk
deleted file mode 100644
index 57848f3..0000000
--- a/location/tests/Android.mk
+++ /dev/null
@@ -1,3 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(call all-makefiles-under, $(LOCAL_PATH))
\ No newline at end of file
diff --git a/location/tests/locationtests/Android.bp b/location/tests/locationtests/Android.bp
new file mode 100644
index 0000000..735ee0e
--- /dev/null
+++ b/location/tests/locationtests/Android.bp
@@ -0,0 +1,19 @@
+android_test {
+ name: "FrameworksLocationTests",
+ // Include all test java files.
+ srcs: ["src/**/*.java"],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ platform_apis: true,
+ static_libs: [
+ "android-support-test",
+ "core-test-rules",
+ "guava",
+ "mockito-target-minus-junit4",
+ "frameworks-base-testutils",
+ "truth-prebuilt",
+ ],
+ test_suites: ["device-tests"],
+}
diff --git a/location/tests/locationtests/Android.mk b/location/tests/locationtests/Android.mk
deleted file mode 100644
index b2fd8ec..0000000
--- a/location/tests/locationtests/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Include all test java files.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-LOCAL_PACKAGE_NAME := FrameworksLocationTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- android-support-test \
- core-test-rules \
- guava \
- mockito-target-minus-junit4 \
- frameworks-base-testutils \
- truth-prebuilt \
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-include $(BUILD_PACKAGE)
diff --git a/media/java/android/media/MediaHTTPConnection.java b/media/java/android/media/MediaHTTPConnection.java
index 3838a999..b5c4cca 100644
--- a/media/java/android/media/MediaHTTPConnection.java
+++ b/media/java/android/media/MediaHTTPConnection.java
@@ -24,6 +24,7 @@
import android.os.StrictMode;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -37,7 +38,6 @@
import java.net.UnknownServiceException;
import java.util.HashMap;
import java.util.Map;
-import java.util.concurrent.atomic.AtomicReference;
/** @hide */
public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
@@ -47,23 +47,42 @@
// connection timeout - 30 sec
private static final int CONNECT_TIMEOUT_MS = 30 * 1000;
+ @GuardedBy("this")
+ @UnsupportedAppUsage
+ private long mCurrentOffset = -1;
+
+ @GuardedBy("this")
+ @UnsupportedAppUsage
+ private URL mURL = null;
+
+ @GuardedBy("this")
+ @UnsupportedAppUsage
+ private Map<String, String> mHeaders = null;
+
+ // volatile so that disconnect() can be called without acquiring a lock.
+ // All other access is @GuardedBy("this").
+ @UnsupportedAppUsage
+ private volatile HttpURLConnection mConnection = null;
+
+ @GuardedBy("this")
+ @UnsupportedAppUsage
+ private long mTotalSize = -1;
+
+ @GuardedBy("this")
+ private InputStream mInputStream = null;
+
+ @GuardedBy("this")
+ @UnsupportedAppUsage
+ private boolean mAllowCrossDomainRedirect = true;
+
+ @GuardedBy("this")
+ @UnsupportedAppUsage
+ private boolean mAllowCrossProtocolRedirect = true;
+
// from com.squareup.okhttp.internal.http
private final static int HTTP_TEMP_REDIRECT = 307;
private final static int MAX_REDIRECTS = 20;
- class ConnectionState {
- public HttpURLConnection mConnection = null;
- public InputStream mInputStream = null;
- public long mCurrentOffset = -1;
- public Map<String, String> mHeaders = null;
- public URL mURL = null;
- public long mTotalSize = -1;
- public boolean mAllowCrossDomainRedirect = true;
- public boolean mAllowCrossProtocolRedirect = true;
- }
- private final AtomicReference<ConnectionState> mConnectionStateHolder =
- new AtomicReference<ConnectionState>();
-
@UnsupportedAppUsage
public MediaHTTPConnection() {
CookieHandler cookieHandler = CookieHandler.getDefault();
@@ -76,34 +95,24 @@
@Override
@UnsupportedAppUsage
- public IBinder connect(String uri, String headers) {
+ public synchronized IBinder connect(String uri, String headers) {
if (VERBOSE) {
Log.d(TAG, "connect: uri=" + uri + ", headers=" + headers);
}
- ConnectionState connectionState = mConnectionStateHolder.get();
- synchronized (this) {
- if (connectionState == null) {
- connectionState = new ConnectionState();
- mConnectionStateHolder.set(connectionState);
- }
- }
-
try {
disconnect();
- connectionState.mAllowCrossDomainRedirect = true;
- connectionState.mURL = new URL(uri);
- connectionState.mHeaders = convertHeaderStringToMap(headers, connectionState);
+ mAllowCrossDomainRedirect = true;
+ mURL = new URL(uri);
+ mHeaders = convertHeaderStringToMap(headers);
} catch (MalformedURLException e) {
return null;
- } finally {
- mConnectionStateHolder.set(connectionState);
}
return native_getIMemory();
}
- private boolean parseBoolean(String val) {
+ private static boolean parseBoolean(String val) {
try {
return Long.parseLong(val) != 0;
} catch (NumberFormatException e) {
@@ -113,21 +122,18 @@
}
/* returns true iff header is internal */
- private boolean filterOutInternalHeaders(
- String key, String val, ConnectionState connectionState) {
+ private synchronized boolean filterOutInternalHeaders(String key, String val) {
if ("android-allow-cross-domain-redirect".equalsIgnoreCase(key)) {
- connectionState.mAllowCrossDomainRedirect = parseBoolean(val);
+ mAllowCrossDomainRedirect = parseBoolean(val);
// cross-protocol redirects are also controlled by this flag
- connectionState.mAllowCrossProtocolRedirect =
- connectionState.mAllowCrossDomainRedirect;
+ mAllowCrossProtocolRedirect = mAllowCrossDomainRedirect;
} else {
return false;
}
return true;
}
- private Map<String, String> convertHeaderStringToMap(String headers,
- ConnectionState connectionState) {
+ private synchronized Map<String, String> convertHeaderStringToMap(String headers) {
HashMap<String, String> map = new HashMap<String, String>();
String[] pairs = headers.split("\r\n");
@@ -137,7 +143,7 @@
String key = pair.substring(0, colonPos);
String val = pair.substring(colonPos + 1);
- if (!filterOutInternalHeaders(key, val, connectionState)) {
+ if (!filterOutInternalHeaders(key, val)) {
map.put(key, val);
}
}
@@ -149,28 +155,36 @@
@Override
@UnsupportedAppUsage
public void disconnect() {
- ConnectionState connectionState = mConnectionStateHolder.getAndSet(null);
- if (connectionState != null) {
- teardownConnection(connectionState);
- connectionState.mHeaders = null;
- connectionState.mURL = null;
+ HttpURLConnection connectionToDisconnect = mConnection;
+ // Call disconnect() before blocking for the lock in order to ensure that any
+ // other thread that is blocked in readAt() will return quickly.
+ if (connectionToDisconnect != null) {
+ connectionToDisconnect.disconnect();
+ }
+ synchronized (this) {
+ // It's unlikely but possible that while we were waiting to acquire the lock, another
+ // thread concurrently started a new connection; if so, we're disconnecting that one
+ // here, too.
+ teardownConnection();
+ mHeaders = null;
+ mURL = null;
}
}
- private void teardownConnection(ConnectionState connectionState) {
- if (connectionState.mConnection != null) {
- if (connectionState.mInputStream != null) {
+ private synchronized void teardownConnection() {
+ if (mConnection != null) {
+ if (mInputStream != null) {
try {
- connectionState.mInputStream.close();
+ mInputStream.close();
} catch (IOException e) {
}
- connectionState.mInputStream = null;
+ mInputStream = null;
}
- connectionState.mConnection.disconnect();
- connectionState.mConnection = null;
+ mConnection.disconnect();
+ mConnection = null;
- connectionState.mCurrentOffset = -1;
+ mCurrentOffset = -1;
}
}
@@ -197,44 +211,42 @@
return false;
}
- private void seekTo(long offset, ConnectionState connectionState) throws IOException {
- teardownConnection(connectionState);
+ private synchronized void seekTo(long offset) throws IOException {
+ teardownConnection();
try {
int response;
int redirectCount = 0;
- URL url = connectionState.mURL;
+ URL url = mURL;
// do not use any proxy for localhost (127.0.0.1)
boolean noProxy = isLocalHost(url);
while (true) {
if (noProxy) {
- connectionState.mConnection =
- (HttpURLConnection) url.openConnection(Proxy.NO_PROXY);
+ mConnection = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
} else {
- connectionState.mConnection = (HttpURLConnection) url.openConnection();
+ mConnection = (HttpURLConnection)url.openConnection();
}
- connectionState.mConnection.setConnectTimeout(CONNECT_TIMEOUT_MS);
+ mConnection.setConnectTimeout(CONNECT_TIMEOUT_MS);
// handle redirects ourselves if we do not allow cross-domain redirect
- connectionState.mConnection.setInstanceFollowRedirects(
- connectionState.mAllowCrossDomainRedirect);
+ mConnection.setInstanceFollowRedirects(mAllowCrossDomainRedirect);
- if (connectionState.mHeaders != null) {
- for (Map.Entry<String, String> entry : connectionState.mHeaders.entrySet()) {
- connectionState.mConnection.setRequestProperty(
+ if (mHeaders != null) {
+ for (Map.Entry<String, String> entry : mHeaders.entrySet()) {
+ mConnection.setRequestProperty(
entry.getKey(), entry.getValue());
}
}
if (offset > 0) {
- connectionState.mConnection.setRequestProperty(
+ mConnection.setRequestProperty(
"Range", "bytes=" + offset + "-");
}
- response = connectionState.mConnection.getResponseCode();
+ response = mConnection.getResponseCode();
if (response != HttpURLConnection.HTTP_MULT_CHOICE &&
response != HttpURLConnection.HTTP_MOVED_PERM &&
response != HttpURLConnection.HTTP_MOVED_TEMP &&
@@ -248,7 +260,7 @@
throw new NoRouteToHostException("Too many redirects: " + redirectCount);
}
- String method = connectionState.mConnection.getRequestMethod();
+ String method = mConnection.getRequestMethod();
if (response == HTTP_TEMP_REDIRECT &&
!method.equals("GET") && !method.equals("HEAD")) {
// "If the 307 status code is received in response to a
@@ -256,35 +268,34 @@
// automatically redirect the request"
throw new NoRouteToHostException("Invalid redirect");
}
- String location = connectionState.mConnection.getHeaderField("Location");
+ String location = mConnection.getHeaderField("Location");
if (location == null) {
throw new NoRouteToHostException("Invalid redirect");
}
- url = new URL(connectionState.mURL /* TRICKY: don't use url! */, location);
+ url = new URL(mURL /* TRICKY: don't use url! */, location);
if (!url.getProtocol().equals("https") &&
!url.getProtocol().equals("http")) {
throw new NoRouteToHostException("Unsupported protocol redirect");
}
- boolean sameProtocol =
- connectionState.mURL.getProtocol().equals(url.getProtocol());
- if (!connectionState.mAllowCrossProtocolRedirect && !sameProtocol) {
+ boolean sameProtocol = mURL.getProtocol().equals(url.getProtocol());
+ if (!mAllowCrossProtocolRedirect && !sameProtocol) {
throw new NoRouteToHostException("Cross-protocol redirects are disallowed");
}
- boolean sameHost = connectionState.mURL.getHost().equals(url.getHost());
- if (!connectionState.mAllowCrossDomainRedirect && !sameHost) {
+ boolean sameHost = mURL.getHost().equals(url.getHost());
+ if (!mAllowCrossDomainRedirect && !sameHost) {
throw new NoRouteToHostException("Cross-domain redirects are disallowed");
}
if (response != HTTP_TEMP_REDIRECT) {
// update effective URL, unless it is a Temporary Redirect
- connectionState.mURL = url;
+ mURL = url;
}
}
- if (connectionState.mAllowCrossDomainRedirect) {
+ if (mAllowCrossDomainRedirect) {
// remember the current, potentially redirected URL if redirects
// were handled by HttpURLConnection
- connectionState.mURL = connectionState.mConnection.getURL();
+ mURL = mConnection.getURL();
}
if (response == HttpURLConnection.HTTP_PARTIAL) {
@@ -292,9 +303,10 @@
// because what we want is not just the length of the range
// returned but the size of the full content if available.
- String contentRange = connectionState.mConnection.getHeaderField("Content-Range");
+ String contentRange =
+ mConnection.getHeaderField("Content-Range");
- connectionState.mTotalSize = -1;
+ mTotalSize = -1;
if (contentRange != null) {
// format is "bytes xxx-yyy/zzz
// where "zzz" is the total number of bytes of the
@@ -306,7 +318,7 @@
contentRange.substring(lastSlashPos + 1);
try {
- connectionState.mTotalSize = Long.parseLong(total);
+ mTotalSize = Long.parseLong(total);
} catch (NumberFormatException e) {
}
}
@@ -314,7 +326,7 @@
} else if (response != HttpURLConnection.HTTP_OK) {
throw new IOException();
} else {
- connectionState.mTotalSize = connectionState.mConnection.getContentLength();
+ mTotalSize = mConnection.getContentLength();
}
if (offset > 0 && response != HttpURLConnection.HTTP_PARTIAL) {
@@ -323,14 +335,14 @@
throw new ProtocolException();
}
- connectionState.mInputStream =
- new BufferedInputStream(connectionState.mConnection.getInputStream());
+ mInputStream =
+ new BufferedInputStream(mConnection.getInputStream());
- connectionState.mCurrentOffset = offset;
+ mCurrentOffset = offset;
} catch (IOException e) {
- connectionState.mTotalSize = -1;
- teardownConnection(connectionState);
- connectionState.mCurrentOffset = -1;
+ mTotalSize = -1;
+ teardownConnection();
+ mCurrentOffset = -1;
throw e;
}
@@ -338,28 +350,22 @@
@Override
@UnsupportedAppUsage
- public int readAt(long offset, int size) {
- ConnectionState connectionState = mConnectionStateHolder.get();
- if (connectionState != null) {
- return native_readAt(offset, size, connectionState);
- }
- return -1;
+ public synchronized int readAt(long offset, int size) {
+ return native_readAt(offset, size);
}
- private int readAt(long offset, byte[] data, int size, ConnectionState connectionState) {
+ private synchronized int readAt(long offset, byte[] data, int size) {
StrictMode.ThreadPolicy policy =
new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
try {
- synchronized(this) {
- if (offset != connectionState.mCurrentOffset) {
- seekTo(offset, connectionState);
- }
+ if (offset != mCurrentOffset) {
+ seekTo(offset);
}
- int n = connectionState.mInputStream.read(data, 0, size);
+ int n = mInputStream.read(data, 0, size);
if (n == -1) {
// InputStream signals EOS using a -1 result, our semantics
@@ -367,7 +373,7 @@
n = 0;
}
- connectionState.mCurrentOffset += n;
+ mCurrentOffset += n;
if (VERBOSE) {
Log.d(TAG, "readAt " + offset + " / " + size + " => " + n);
@@ -399,47 +405,35 @@
@Override
public synchronized long getSize() {
- ConnectionState connectionState = mConnectionStateHolder.get();
- if (connectionState != null) {
- if (connectionState.mConnection == null) {
- try {
- seekTo(0, connectionState);
- } catch (IOException e) {
- return -1;
- }
+ if (mConnection == null) {
+ try {
+ seekTo(0);
+ } catch (IOException e) {
+ return -1;
}
- return connectionState.mTotalSize;
}
- return -1;
+ return mTotalSize;
}
@Override
@UnsupportedAppUsage
public synchronized String getMIMEType() {
- ConnectionState connectionState = mConnectionStateHolder.get();
- if (connectionState != null) {
- if (connectionState.mConnection == null) {
- try {
- seekTo(0, connectionState);
- } catch (IOException e) {
- return "application/octet-stream";
- }
+ if (mConnection == null) {
+ try {
+ seekTo(0);
+ } catch (IOException e) {
+ return "application/octet-stream";
}
- return connectionState.mConnection.getContentType();
}
- return null;
+ return mConnection.getContentType();
}
@Override
@UnsupportedAppUsage
- public String getUri() {
- ConnectionState connectionState = mConnectionStateHolder.get();
- if (connectionState != null) {
- return connectionState.mURL.toString();
- }
- return null;
+ public synchronized String getUri() {
+ return mURL.toString();
}
@Override
@@ -452,7 +446,7 @@
private native final void native_finalize();
private native final IBinder native_getIMemory();
- private native int native_readAt(long offset, int size, ConnectionState connectionState);
+ private native final int native_readAt(long offset, int size);
static {
System.loadLibrary("media_jni");
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 5966192..7a41c77 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -151,6 +151,8 @@
"libutils", // Have to use shared lib to make libandroid_runtime behave correctly.
// Otherwise, AndroidRuntime::getJNIEnv() will return NULL.
+
+ "libcgrouprc", // LL-NDK
],
header_libs: ["libhardware_headers"],
diff --git a/media/jni/android_media_MediaHTTPConnection.cpp b/media/jni/android_media_MediaHTTPConnection.cpp
index d28c15c..365e045 100644
--- a/media/jni/android_media_MediaHTTPConnection.cpp
+++ b/media/jni/android_media_MediaHTTPConnection.cpp
@@ -109,8 +109,7 @@
gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
CHECK(gFields.context != NULL);
- gFields.readAtMethodID = env->GetMethodID(
- clazz.get(), "readAt", "(J[BILandroid/media/MediaHTTPConnection$ConnectionState;)I");
+ gFields.readAtMethodID = env->GetMethodID(clazz.get(), "readAt", "(J[BI)I");
}
static void android_media_MediaHTTPConnection_native_setup(
@@ -133,7 +132,7 @@
}
static jint android_media_MediaHTTPConnection_native_readAt(
- JNIEnv *env, jobject thiz, jlong offset, jint size, jobject connectionState) {
+ JNIEnv *env, jobject thiz, jlong offset, jint size) {
sp<JMediaHTTPConnection> conn = getObject(env, thiz);
if (size > JMediaHTTPConnection::kBufferSize) {
size = JMediaHTTPConnection::kBufferSize;
@@ -142,7 +141,7 @@
jbyteArray byteArrayObj = conn->getByteArrayObj();
jint n = env->CallIntMethod(
- thiz, gFields.readAtMethodID, offset, byteArrayObj, size, connectionState);
+ thiz, gFields.readAtMethodID, offset, byteArrayObj, size);
if (n > 0) {
env->GetByteArrayRegion(
@@ -159,7 +158,7 @@
{ "native_getIMemory", "()Landroid/os/IBinder;",
(void *)android_media_MediaHTTPConnection_native_getIMemory },
- { "native_readAt", "(JILandroid/media/MediaHTTPConnection$ConnectionState;)I",
+ { "native_readAt", "(JI)I",
(void *)android_media_MediaHTTPConnection_native_readAt },
{ "native_init", "()V",
diff --git a/media/tests/MediaFrameworkTest/Android.bp b/media/tests/MediaFrameworkTest/Android.bp
new file mode 100644
index 0000000..4fbd852
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/Android.bp
@@ -0,0 +1,14 @@
+android_test {
+ name: "mediaframeworktest",
+ srcs: ["**/*.java"],
+ libs: [
+ "android.test.runner",
+ "android.test.base",
+ ],
+ static_libs: [
+ "mockito-target-minus-junit4",
+ "android-support-test",
+ "android-ex-camera2",
+ ],
+ platform_apis: true,
+}
diff --git a/media/tests/MediaFrameworkTest/Android.mk b/media/tests/MediaFrameworkTest/Android.mk
deleted file mode 100644
index fb473f0..0000000
--- a/media/tests/MediaFrameworkTest/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- mockito-target-minus-junit4 \
- android-support-test \
- android-ex-camera2
-
-LOCAL_PACKAGE_NAME := mediaframeworktest
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-include $(BUILD_PACKAGE)
diff --git a/media/tests/MtpTests/Android.bp b/media/tests/MtpTests/Android.bp
new file mode 100644
index 0000000..1189430
--- /dev/null
+++ b/media/tests/MtpTests/Android.bp
@@ -0,0 +1,6 @@
+android_test {
+ name: "MtpTests",
+ srcs: ["**/*.java"],
+ static_libs: ["android-support-test"],
+ platform_apis: true,
+}
diff --git a/media/tests/MtpTests/Android.mk b/media/tests/MtpTests/Android.mk
deleted file mode 100644
index 6375ed3..0000000
--- a/media/tests/MtpTests/Android.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
-
-LOCAL_PACKAGE_NAME := MtpTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-include $(BUILD_PACKAGE)
diff --git a/packages/CaptivePortalLogin/Android.bp b/packages/CaptivePortalLogin/Android.bp
index f545a61..732acca 100644
--- a/packages/CaptivePortalLogin/Android.bp
+++ b/packages/CaptivePortalLogin/Android.bp
@@ -23,6 +23,7 @@
static_libs: [
"android-support-v4",
"metrics-constants-protos",
+ "captiveportal-lib",
],
manifest: "AndroidManifest.xml",
}
diff --git a/packages/NetworkStackPermissionStub/Android.bp b/packages/NetworkPermissionConfig/Android.bp
similarity index 95%
rename from packages/NetworkStackPermissionStub/Android.bp
rename to packages/NetworkPermissionConfig/Android.bp
index 8cee92e..d0d3276 100644
--- a/packages/NetworkStackPermissionStub/Android.bp
+++ b/packages/NetworkPermissionConfig/Android.bp
@@ -16,7 +16,7 @@
// Stub APK to define permissions for NetworkStack
android_app {
- name: "NetworkStackPermissionStub",
+ name: "NetworkPermissionConfig",
// TODO: mark app as hasCode=false in manifest once soong stops complaining about apps without
// a classes.dex.
srcs: ["src/**/*.java"],
diff --git a/packages/NetworkStackPermissionStub/AndroidManifest.xml b/packages/NetworkPermissionConfig/AndroidManifest.xml
similarity index 92%
rename from packages/NetworkStackPermissionStub/AndroidManifest.xml
rename to packages/NetworkPermissionConfig/AndroidManifest.xml
index e83f050..34f987c 100644
--- a/packages/NetworkStackPermissionStub/AndroidManifest.xml
+++ b/packages/NetworkPermissionConfig/AndroidManifest.xml
@@ -17,7 +17,7 @@
*/
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.networkstack.permissionstub"
+ package="com.android.networkstack.permissionconfig"
android:sharedUserId="android.uid.networkstack"
android:versionCode="11"
android:versionName="Q-initial">
@@ -36,5 +36,5 @@
<permission android:name="android.permission.MAINLINE_NETWORK_STACK"
android:protectionLevel="signature"/>
- <application android:name="com.android.server.NetworkStackPermissionStub"/>
+ <application android:name="com.android.server.NetworkPermissionConfig"/>
</manifest>
diff --git a/packages/NetworkStackPermissionStub/src/com/android/server/NetworkStackPermissionStub.java b/packages/NetworkPermissionConfig/src/com/android/server/NetworkPermissionConfig.java
similarity index 78%
rename from packages/NetworkStackPermissionStub/src/com/android/server/NetworkStackPermissionStub.java
rename to packages/NetworkPermissionConfig/src/com/android/server/NetworkPermissionConfig.java
index 01e59d2..c904e23 100644
--- a/packages/NetworkStackPermissionStub/src/com/android/server/NetworkStackPermissionStub.java
+++ b/packages/NetworkPermissionConfig/src/com/android/server/NetworkPermissionConfig.java
@@ -19,8 +19,8 @@
import android.app.Application;
/**
- * Empty application for NetworkStackStub that only exists because soong builds complain if APKs
- * have no source file.
+ * Empty application for NetworkPermissionConfig that only exists because
+ * soong builds complain if APKs have no source file.
*/
-public class NetworkStackPermissionStub extends Application {
+public class NetworkPermissionConfig extends Application {
}
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
index 0bd5c5f..5817118 100644
--- a/packages/NetworkStack/Android.bp
+++ b/packages/NetworkStack/Android.bp
@@ -14,6 +14,15 @@
// limitations under the License.
//
+java_library {
+ name: "captiveportal-lib",
+ srcs: ["common/**/*.java"],
+ libs: [
+ "androidx.annotation_annotation",
+ ],
+ sdk_version: "system_current",
+}
+
java_defaults {
name: "NetworkStackCommon",
sdk_version: "system_current",
@@ -30,15 +39,38 @@
":services-networkstack-shared-srcs",
],
static_libs: [
+ "androidx.annotation_annotation",
"ipmemorystore-client",
"netd_aidl_interface-java",
"networkstack-aidl-interfaces-java",
"datastallprotosnano",
"networkstackprotosnano",
+ "captiveportal-lib",
],
manifest: "AndroidManifestBase.xml",
}
+cc_library_shared {
+ name: "libnetworkstackutilsjni",
+ srcs: [
+ "jni/network_stack_utils_jni.cpp"
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libcutils",
+ "libnativehelper",
+ ],
+ static_libs: [
+ "libpcap",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-parameter",
+ ],
+}
+
java_defaults {
name: "NetworkStackAppCommon",
defaults: ["NetworkStackCommon"],
@@ -46,6 +78,7 @@
static_libs: [
"NetworkStackBase",
],
+ jni_libs: ["libnetworkstackutilsjni"],
// Resources already included in NetworkStackBase
resource_dirs: [],
jarjar_rules: "jarjar-rules-shared.txt",
@@ -53,7 +86,7 @@
proguard_flags_files: ["proguard.flags"],
},
// The permission configuration *must* be included to ensure security of the device
- required: ["NetworkStackPermissionStub"],
+ required: ["NetworkPermissionConfig"],
}
// Non-updatable network stack running in the system server process for devices not using the module
diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml
index b0a7923..3fc1e98 100644
--- a/packages/NetworkStack/AndroidManifest.xml
+++ b/packages/NetworkStack/AndroidManifest.xml
@@ -20,6 +20,21 @@
package="com.android.networkstack"
android:sharedUserId="android.uid.networkstack">
<uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
+
+ <!-- Permissions must be defined here, and not in the base manifest, as the network stack
+ running in the system server process does not need any permission, and having privileged
+ permissions added would cause crashes on startup unless they are also added to the
+ privileged permissions whitelist for that package. -->
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+ <!-- Send latency broadcast as current user -->
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+ <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
+ <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
<!-- Signature permission defined in NetworkStackStub -->
<uses-permission android:name="android.permission.MAINLINE_NETWORK_STACK" />
<application>
diff --git a/packages/NetworkStack/AndroidManifestBase.xml b/packages/NetworkStack/AndroidManifestBase.xml
index f69e4b2..d00a551 100644
--- a/packages/NetworkStack/AndroidManifestBase.xml
+++ b/packages/NetworkStack/AndroidManifestBase.xml
@@ -20,19 +20,14 @@
package="com.android.networkstack"
android:versionCode="11"
android:versionName="Q-initial">
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
- <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
- <!-- Send latency broadcast as current user -->
- <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
- <uses-permission android:name="android.permission.WAKE_LOCK" />
- <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
<application
android:label="NetworkStack"
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true"
android:usesCleartextTraffic="true">
+
+ <service android:name="com.android.server.connectivity.ipmemorystore.RegularMaintenanceJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
</application>
</manifest>
diff --git a/core/java/android/net/captiveportal/CaptivePortalProbeResult.java b/packages/NetworkStack/common/CaptivePortalProbeResult.java
similarity index 94%
rename from core/java/android/net/captiveportal/CaptivePortalProbeResult.java
rename to packages/NetworkStack/common/CaptivePortalProbeResult.java
index a1d3de2..48cd48b 100644
--- a/core/java/android/net/captiveportal/CaptivePortalProbeResult.java
+++ b/packages/NetworkStack/common/CaptivePortalProbeResult.java
@@ -16,17 +16,13 @@
package android.net.captiveportal;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.annotation.TestApi;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
/**
* Result of calling isCaptivePortal().
* @hide
*/
-@SystemApi
-@TestApi
public final class CaptivePortalProbeResult {
public static final int SUCCESS_CODE = 204;
public static final int FAILED_CODE = 599;
diff --git a/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java b/packages/NetworkStack/common/CaptivePortalProbeSpec.java
similarity index 94%
rename from core/java/android/net/captiveportal/CaptivePortalProbeSpec.java
rename to packages/NetworkStack/common/CaptivePortalProbeSpec.java
index 6c6a16c..bf983a5 100644
--- a/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java
+++ b/packages/NetworkStack/common/CaptivePortalProbeSpec.java
@@ -19,16 +19,12 @@
import static android.net.captiveportal.CaptivePortalProbeResult.PORTAL_CODE;
import static android.net.captiveportal.CaptivePortalProbeResult.SUCCESS_CODE;
-import static com.android.internal.util.Preconditions.checkNotNull;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.annotation.TestApi;
import android.text.TextUtils;
import android.util.Log;
-import com.android.internal.annotations.VisibleForTesting;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import java.net.MalformedURLException;
import java.net.URL;
@@ -40,8 +36,6 @@
import java.util.regex.PatternSyntaxException;
/** @hide */
-@SystemApi
-@TestApi
public abstract class CaptivePortalProbeSpec {
private static final String TAG = CaptivePortalProbeSpec.class.getSimpleName();
private static final String REGEX_SEPARATOR = "@@/@@";
@@ -50,8 +44,7 @@
private final String mEncodedSpec;
private final URL mUrl;
- CaptivePortalProbeSpec(@NonNull String encodedSpec, @NonNull URL url)
- throws NullPointerException {
+ CaptivePortalProbeSpec(@NonNull String encodedSpec, @NonNull URL url) {
mEncodedSpec = checkNotNull(encodedSpec);
mUrl = checkNotNull(url);
}
@@ -193,4 +186,10 @@
// No value is a match ("no location header" passes the location rule for non-redirects)
return pattern == null || TextUtils.isEmpty(value) || pattern.matcher(value).matches();
}
+
+ // Throws NullPointerException if the input is null.
+ private static <T> T checkNotNull(T object) {
+ if (object == null) throw new NullPointerException();
+ return object;
+ }
}
diff --git a/packages/NetworkStack/jni/network_stack_utils_jni.cpp b/packages/NetworkStack/jni/network_stack_utils_jni.cpp
new file mode 100644
index 0000000..5544eaa
--- /dev/null
+++ b/packages/NetworkStack/jni/network_stack_utils_jni.cpp
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2019, 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.
+ */
+
+#define LOG_TAG "NetworkStackUtils-JNI"
+
+#include <errno.h>
+#include <jni.h>
+#include <linux/filter.h>
+#include <linux/if_arp.h>
+#include <net/if.h>
+#include <netinet/ether.h>
+#include <netinet/icmp6.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/udp.h>
+#include <stdlib.h>
+
+#include <string>
+
+#include <nativehelper/JNIHelp.h>
+#include <utils/Log.h>
+
+namespace android {
+constexpr const char NETWORKSTACKUTILS_PKG_NAME[] = "android/net/util/NetworkStackUtils";
+
+static const uint32_t kEtherTypeOffset = offsetof(ether_header, ether_type);
+static const uint32_t kEtherHeaderLen = sizeof(ether_header);
+static const uint32_t kIPv4Protocol = kEtherHeaderLen + offsetof(iphdr, protocol);
+static const uint32_t kIPv4FlagsOffset = kEtherHeaderLen + offsetof(iphdr, frag_off);
+static const uint32_t kIPv6NextHeader = kEtherHeaderLen + offsetof(ip6_hdr, ip6_nxt);
+static const uint32_t kIPv6PayloadStart = kEtherHeaderLen + sizeof(ip6_hdr);
+static const uint32_t kICMPv6TypeOffset = kIPv6PayloadStart + offsetof(icmp6_hdr, icmp6_type);
+static const uint32_t kUDPSrcPortIndirectOffset = kEtherHeaderLen + offsetof(udphdr, source);
+static const uint32_t kUDPDstPortIndirectOffset = kEtherHeaderLen + offsetof(udphdr, dest);
+static const uint16_t kDhcpClientPort = 68;
+
+static bool checkLenAndCopy(JNIEnv* env, const jbyteArray& addr, int len, void* dst) {
+ if (env->GetArrayLength(addr) != len) {
+ return false;
+ }
+ env->GetByteArrayRegion(addr, 0, len, reinterpret_cast<jbyte*>(dst));
+ return true;
+}
+
+static void network_stack_utils_addArpEntry(JNIEnv *env, jobject thiz, jbyteArray ethAddr,
+ jbyteArray ipv4Addr, jstring ifname, jobject javaFd) {
+ arpreq req = {};
+ sockaddr_in& netAddrStruct = *reinterpret_cast<sockaddr_in*>(&req.arp_pa);
+ sockaddr& ethAddrStruct = req.arp_ha;
+
+ ethAddrStruct.sa_family = ARPHRD_ETHER;
+ if (!checkLenAndCopy(env, ethAddr, ETH_ALEN, ethAddrStruct.sa_data)) {
+ jniThrowException(env, "java/io/IOException", "Invalid ethAddr length");
+ return;
+ }
+
+ netAddrStruct.sin_family = AF_INET;
+ if (!checkLenAndCopy(env, ipv4Addr, sizeof(in_addr), &netAddrStruct.sin_addr)) {
+ jniThrowException(env, "java/io/IOException", "Invalid ipv4Addr length");
+ return;
+ }
+
+ int ifLen = env->GetStringLength(ifname);
+ // IFNAMSIZ includes the terminating NULL character
+ if (ifLen >= IFNAMSIZ) {
+ jniThrowException(env, "java/io/IOException", "ifname too long");
+ return;
+ }
+ env->GetStringUTFRegion(ifname, 0, ifLen, req.arp_dev);
+
+ req.arp_flags = ATF_COM; // Completed entry (ha valid)
+ int fd = jniGetFDFromFileDescriptor(env, javaFd);
+ if (fd < 0) {
+ jniThrowExceptionFmt(env, "java/io/IOException", "Invalid file descriptor");
+ return;
+ }
+ // See also: man 7 arp
+ if (ioctl(fd, SIOCSARP, &req)) {
+ jniThrowExceptionFmt(env, "java/io/IOException", "ioctl error: %s", strerror(errno));
+ return;
+ }
+}
+
+static void network_stack_utils_attachDhcpFilter(JNIEnv *env, jobject clazz, jobject javaFd) {
+ static sock_filter filter_code[] = {
+ // Check the protocol is UDP.
+ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv4Protocol),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_UDP, 0, 6),
+
+ // Check this is not a fragment.
+ BPF_STMT(BPF_LD | BPF_H | BPF_ABS, kIPv4FlagsOffset),
+ BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K, IP_OFFMASK, 4, 0),
+
+ // Get the IP header length.
+ BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, kEtherHeaderLen),
+
+ // Check the destination port.
+ BPF_STMT(BPF_LD | BPF_H | BPF_IND, kUDPDstPortIndirectOffset),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, kDhcpClientPort, 0, 1),
+
+ // Accept or reject.
+ BPF_STMT(BPF_RET | BPF_K, 0xffff),
+ BPF_STMT(BPF_RET | BPF_K, 0)
+ };
+ static const sock_fprog filter = {
+ sizeof(filter_code) / sizeof(filter_code[0]),
+ filter_code,
+ };
+
+ int fd = jniGetFDFromFileDescriptor(env, javaFd);
+ if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
+ jniThrowExceptionFmt(env, "java/net/SocketException",
+ "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
+ }
+}
+
+static void network_stack_utils_attachRaFilter(JNIEnv *env, jobject clazz, jobject javaFd,
+ jint hardwareAddressType) {
+ if (hardwareAddressType != ARPHRD_ETHER) {
+ jniThrowExceptionFmt(env, "java/net/SocketException",
+ "attachRaFilter only supports ARPHRD_ETHER");
+ return;
+ }
+
+ static sock_filter filter_code[] = {
+ // Check IPv6 Next Header is ICMPv6.
+ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv6NextHeader),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 3),
+
+ // Check ICMPv6 type is Router Advertisement.
+ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kICMPv6TypeOffset),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ND_ROUTER_ADVERT, 0, 1),
+
+ // Accept or reject.
+ BPF_STMT(BPF_RET | BPF_K, 0xffff),
+ BPF_STMT(BPF_RET | BPF_K, 0)
+ };
+ static const sock_fprog filter = {
+ sizeof(filter_code) / sizeof(filter_code[0]),
+ filter_code,
+ };
+
+ int fd = jniGetFDFromFileDescriptor(env, javaFd);
+ if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
+ jniThrowExceptionFmt(env, "java/net/SocketException",
+ "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
+ }
+}
+
+// TODO: Move all this filter code into libnetutils.
+static void network_stack_utils_attachControlPacketFilter(
+ JNIEnv *env, jobject clazz, jobject javaFd, jint hardwareAddressType) {
+ if (hardwareAddressType != ARPHRD_ETHER) {
+ jniThrowExceptionFmt(env, "java/net/SocketException",
+ "attachControlPacketFilter only supports ARPHRD_ETHER");
+ return;
+ }
+
+ // Capture all:
+ // - ARPs
+ // - DHCPv4 packets
+ // - Router Advertisements & Solicitations
+ // - Neighbor Advertisements & Solicitations
+ //
+ // tcpdump:
+ // arp or
+ // '(ip and udp port 68)' or
+ // '(icmp6 and ip6[40] >= 133 and ip6[40] <= 136)'
+ static sock_filter filter_code[] = {
+ // Load the link layer next payload field.
+ BPF_STMT(BPF_LD | BPF_H | BPF_ABS, kEtherTypeOffset),
+
+ // Accept all ARP.
+ // TODO: Figure out how to better filter ARPs on noisy networks.
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_ARP, 16, 0),
+
+ // If IPv4:
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_IP, 0, 9),
+
+ // Check the protocol is UDP.
+ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv4Protocol),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_UDP, 0, 14),
+
+ // Check this is not a fragment.
+ BPF_STMT(BPF_LD | BPF_H | BPF_ABS, kIPv4FlagsOffset),
+ BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K, IP_OFFMASK, 12, 0),
+
+ // Get the IP header length.
+ BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, kEtherHeaderLen),
+
+ // Check the source port.
+ BPF_STMT(BPF_LD | BPF_H | BPF_IND, kUDPSrcPortIndirectOffset),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, kDhcpClientPort, 8, 0),
+
+ // Check the destination port.
+ BPF_STMT(BPF_LD | BPF_H | BPF_IND, kUDPDstPortIndirectOffset),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, kDhcpClientPort, 6, 7),
+
+ // IPv6 ...
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_IPV6, 0, 6),
+ // ... check IPv6 Next Header is ICMPv6 (ignore fragments), ...
+ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv6NextHeader),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 4),
+ // ... and check the ICMPv6 type is one of RS/RA/NS/NA.
+ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kICMPv6TypeOffset),
+ BPF_JUMP(BPF_JMP | BPF_JGE | BPF_K, ND_ROUTER_SOLICIT, 0, 2),
+ BPF_JUMP(BPF_JMP | BPF_JGT | BPF_K, ND_NEIGHBOR_ADVERT, 1, 0),
+
+ // Accept or reject.
+ BPF_STMT(BPF_RET | BPF_K, 0xffff),
+ BPF_STMT(BPF_RET | BPF_K, 0)
+ };
+ static const sock_fprog filter = {
+ sizeof(filter_code) / sizeof(filter_code[0]),
+ filter_code,
+ };
+
+ int fd = jniGetFDFromFileDescriptor(env, javaFd);
+ if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
+ jniThrowExceptionFmt(env, "java/net/SocketException",
+ "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
+ }
+}
+
+/*
+ * JNI registration.
+ */
+static const JNINativeMethod gNetworkStackUtilsMethods[] = {
+ /* name, signature, funcPtr */
+ { "addArpEntry", "([B[BLjava/lang/String;Ljava/io/FileDescriptor;)V", (void*) network_stack_utils_addArpEntry },
+ { "attachDhcpFilter", "(Ljava/io/FileDescriptor;)V", (void*) network_stack_utils_attachDhcpFilter },
+ { "attachRaFilter", "(Ljava/io/FileDescriptor;I)V", (void*) network_stack_utils_attachRaFilter },
+ { "attachControlPacketFilter", "(Ljava/io/FileDescriptor;I)V", (void*) network_stack_utils_attachControlPacketFilter },
+};
+
+extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
+ JNIEnv *env;
+ if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+ ALOGE("ERROR: GetEnv failed");
+ return JNI_ERR;
+ }
+
+ if (jniRegisterNativeMethods(env, NETWORKSTACKUTILS_PKG_NAME,
+ gNetworkStackUtilsMethods, NELEM(gNetworkStackUtilsMethods)) < 0) {
+ return JNI_ERR;
+ }
+
+ return JNI_VERSION_1_6;
+
+}
+}; // namespace android
\ No newline at end of file
diff --git a/packages/NetworkStack/res/values-mcc460/config.xml b/packages/NetworkStack/res/values-mcc460/config.xml
new file mode 100644
index 0000000..fd4a848
--- /dev/null
+++ b/packages/NetworkStack/res/values-mcc460/config.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <!-- Network validation URL configuration for devices using a Chinese SIM (MCC 460).
+ The below URLs are often whitelisted by captive portals, so they should not be used in the
+ general case as this could degrade the user experience (portals not detected properly).
+ However in China the default URLs are not accessible in general. The below alternatives
+ should allow users to connect to local networks normally. -->
+ <string name="default_captive_portal_https_url" translatable="false">https://connectivitycheck.gstatic.com/generate_204</string>
+ <string-array name="default_captive_portal_fallback_urls" translatable="false">
+ <item>http://www.googleapis.cn/generate_204</item>
+ </string-array>
+</resources>
diff --git a/packages/NetworkStack/res/values/config.xml b/packages/NetworkStack/res/values/config.xml
index 52425e5..704788d 100644
--- a/packages/NetworkStack/res/values/config.xml
+++ b/packages/NetworkStack/res/values/config.xml
@@ -1,5 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <!-- Captive portal http url -->
- <string name="config_captive_portal_http_url" translatable="false">http://connectivitycheck.gstatic.com/generate_204</string>
-</resources>
\ No newline at end of file
+ <!--
+ OEMs that wish to change the below settings must do so via a runtime resource overlay package
+ and *NOT* by changing this file. This file is part of the NetworkStack mainline module.
+ The overlays must apply to the config_* values, not the default_* values. The default_*
+ values are meant to be the default when no other configuration is specified.
+ -->
+
+ <!-- HTTP URL for network validation, to use for detecting captive portals. -->
+ <string name="default_captive_portal_http_url" translatable="false">http://connectivitycheck.gstatic.com/generate_204</string>
+
+ <!-- HTTPS URL for network validation, to use for confirming internet connectivity. -->
+ <string name="default_captive_portal_https_url" translatable="false">https://www.google.com/generate_204</string>
+
+ <!-- List of fallback URLs to use for detecting captive portals. -->
+ <string-array name="default_captive_portal_fallback_urls" translatable="false">
+ <item>http://www.google.com/gen_204</item>
+ <item>http://play.googleapis.com/generate_204</item>
+ </string-array>
+
+ <!-- List of fallback probe specs to use for detecting captive portals.
+ This is an alternative to fallback URLs that provides more flexibility on detection rules.
+ Empty, so unused by default. -->
+ <string-array name="default_captive_portal_fallback_probe_specs" translatable="false">
+ </string-array>
+
+ <!-- Configuration hooks for the above settings.
+ Empty by default but may be overridden by RROs. -->
+ <!--suppress CheckTagEmptyBody: overlayable resource to use as configuration hook -->
+ <string name="config_captive_portal_http_url" translatable="false"></string>
+ <!--suppress CheckTagEmptyBody: overlayable resource to use as configuration hook -->
+ <string name="config_captive_portal_https_url" translatable="false"></string>
+ <string-array name="config_captive_portal_fallback_urls" translatable="false">
+ </string-array>
+ <string-array name="config_captive_portal_fallback_probe_specs" translatable="false">
+ </string-array>
+
+ <!-- Customized default DNS Servers address. -->
+ <string-array name="config_default_dns_servers" translatable="false">
+ </string-array>
+</resources>
diff --git a/packages/NetworkStack/src/android/net/apf/ApfFilter.java b/packages/NetworkStack/src/android/net/apf/ApfFilter.java
index d2f3259..663e2f1 100644
--- a/packages/NetworkStack/src/android/net/apf/ApfFilter.java
+++ b/packages/NetworkStack/src/android/net/apf/ApfFilter.java
@@ -49,7 +49,6 @@
import android.net.metrics.RaEvent;
import android.net.util.InterfaceParams;
import android.net.util.NetworkStackUtils;
-import android.net.util.SocketUtils;
import android.os.PowerManager;
import android.os.SystemClock;
import android.system.ErrnoException;
@@ -478,7 +477,7 @@
SocketAddress addr = makePacketSocketAddress(
(short) ETH_P_IPV6, mInterfaceParams.index);
Os.bind(socket, addr);
- SocketUtils.attachRaFilter(socket, mApfCapabilities.apfPacketFormat);
+ NetworkStackUtils.attachRaFilter(socket, mApfCapabilities.apfPacketFormat);
} catch(SocketException|ErrnoException e) {
Log.e(TAG, "Error starting filter", e);
return;
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java b/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
index 79d6a55..be44519 100644
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
@@ -45,12 +45,14 @@
import android.content.Context;
import android.net.DhcpResults;
+import android.net.InetAddresses;
import android.net.TrafficStats;
import android.net.ip.IpClient;
import android.net.metrics.DhcpClientEvent;
import android.net.metrics.DhcpErrorEvent;
import android.net.metrics.IpConnectivityLog;
import android.net.util.InterfaceParams;
+import android.net.util.NetworkStackUtils;
import android.net.util.SocketUtils;
import android.os.Message;
import android.os.SystemClock;
@@ -65,6 +67,7 @@
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.internal.util.WakeupMessage;
+import com.android.networkstack.R;
import java.io.FileDescriptor;
import java.io.IOException;
@@ -319,7 +322,7 @@
mPacketSock = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IP);
SocketAddress addr = makePacketSocketAddress((short) ETH_P_IP, mIface.index);
Os.bind(mPacketSock, addr);
- SocketUtils.attachDhcpFilter(mPacketSock);
+ NetworkStackUtils.attachDhcpFilter(mPacketSock);
} catch(SocketException|ErrnoException e) {
Log.e(TAG, "Error creating packet socket", e);
return false;
@@ -497,6 +500,18 @@
private void acceptDhcpResults(DhcpResults results, String msg) {
mDhcpLease = results;
+ if (mDhcpLease.dnsServers.isEmpty()) {
+ // supplement customized dns servers
+ String[] dnsServersList =
+ mContext.getResources().getStringArray(R.array.config_default_dns_servers);
+ for (final String dnsServer : dnsServersList) {
+ try {
+ mDhcpLease.dnsServers.add(InetAddresses.parseNumericAddress(dnsServer));
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Invalid default DNS server: " + dnsServer, e);
+ }
+ }
+ }
mOffer = null;
Log.d(TAG, msg + " lease: " + mDhcpLease);
notifySuccess();
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java b/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java
index cd993e9..8832eaa 100644
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java
@@ -45,6 +45,7 @@
import android.net.INetworkStackStatusCallback;
import android.net.MacAddress;
import android.net.TrafficStats;
+import android.net.util.NetworkStackUtils;
import android.net.util.SharedLog;
import android.net.util.SocketUtils;
import android.os.Handler;
@@ -207,7 +208,7 @@
@Override
public void addArpEntry(@NonNull Inet4Address ipv4Addr, @NonNull MacAddress ethAddr,
@NonNull String ifname, @NonNull FileDescriptor fd) throws IOException {
- SocketUtils.addArpEntry(ipv4Addr, ethAddr, ifname, fd);
+ NetworkStackUtils.addArpEntry(ipv4Addr, ethAddr, ifname, fd);
}
@Override
diff --git a/packages/NetworkStack/src/android/net/ip/ConnectivityPacketTracker.java b/packages/NetworkStack/src/android/net/ip/ConnectivityPacketTracker.java
index de54824..eb49218 100644
--- a/packages/NetworkStack/src/android/net/ip/ConnectivityPacketTracker.java
+++ b/packages/NetworkStack/src/android/net/ip/ConnectivityPacketTracker.java
@@ -25,8 +25,8 @@
import android.net.util.ConnectivityPacketSummary;
import android.net.util.InterfaceParams;
+import android.net.util.NetworkStackUtils;
import android.net.util.PacketReader;
-import android.net.util.SocketUtils;
import android.os.Handler;
import android.system.ErrnoException;
import android.system.Os;
@@ -103,7 +103,7 @@
FileDescriptor s = null;
try {
s = Os.socket(AF_PACKET, SOCK_RAW | SOCK_NONBLOCK, 0);
- SocketUtils.attachControlPacketFilter(s, ARPHRD_ETHER);
+ NetworkStackUtils.attachControlPacketFilter(s, ARPHRD_ETHER);
Os.bind(s, makePacketSocketAddress((short) ETH_P_ALL, mInterface.index));
} catch (ErrnoException | IOException e) {
logError("Failed to create packet tracking socket: ", e);
diff --git a/packages/NetworkStack/src/android/net/ip/IpClient.java b/packages/NetworkStack/src/android/net/ip/IpClient.java
index 7a06af4..80d139c 100644
--- a/packages/NetworkStack/src/android/net/ip/IpClient.java
+++ b/packages/NetworkStack/src/android/net/ip/IpClient.java
@@ -51,6 +51,7 @@
import android.text.TextUtils;
import android.util.LocalLog;
import android.util.Log;
+import android.util.Pair;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
@@ -298,6 +299,7 @@
private static final int EVENT_READ_PACKET_FILTER_COMPLETE = 12;
private static final int CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF = 13;
private static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF = 14;
+ private static final int CMD_UPDATE_L2KEY_GROUPHINT = 15;
// Internal commands to use instead of trying to call transitionTo() inside
// a given State's enter() method. Calling transitionTo() from enter/exit
@@ -364,6 +366,8 @@
private String mTcpBufferSizes;
private ProxyInfo mHttpProxy;
private ApfFilter mApfFilter;
+ private String mL2Key; // The L2 key for this network, for writing into the memory store
+ private String mGroupHint; // The group hint for this network, for writing into the memory store
private boolean mMulticastFiltering;
private long mStartTimeMillis;
@@ -524,6 +528,11 @@
IpClient.this.stop();
}
@Override
+ public void setL2KeyAndGroupHint(String l2Key, String groupHint) {
+ checkNetworkStackCallingPermission();
+ IpClient.this.setL2KeyAndGroupHint(l2Key, groupHint);
+ }
+ @Override
public void setTcpBufferSizes(String tcpBufferSizes) {
checkNetworkStackCallingPermission();
IpClient.this.setTcpBufferSizes(tcpBufferSizes);
@@ -652,6 +661,13 @@
}
/**
+ * Set the L2 key and group hint for storing info into the memory store.
+ */
+ public void setL2KeyAndGroupHint(String l2Key, String groupHint) {
+ sendMessage(CMD_UPDATE_L2KEY_GROUPHINT, new Pair<>(l2Key, groupHint));
+ }
+
+ /**
* Set the HTTP Proxy configuration to use.
*
* This may be called, repeatedly, at any time before or after a call to
@@ -1068,6 +1084,10 @@
return true;
}
final int delta = setLinkProperties(newLp);
+ // Most of the attributes stored in the memory store are deduced from
+ // the link properties, therefore when the properties update the memory
+ // store record should be updated too.
+ maybeSaveNetworkToIpMemoryStore();
if (sendCallbacks) {
dispatchCallback(delta, newLp);
}
@@ -1083,6 +1103,7 @@
Log.d(mTag, "onNewDhcpResults(" + Objects.toString(dhcpResults) + ")");
}
mCallback.onNewDhcpResults(dhcpResults);
+ maybeSaveNetworkToIpMemoryStore();
dispatchCallback(delta, newLp);
}
@@ -1213,6 +1234,10 @@
mInterfaceCtrl.clearAllAddresses();
}
+ private void maybeSaveNetworkToIpMemoryStore() {
+ // TODO : implement this
+ }
+
class StoppedState extends State {
@Override
public void enter() {
@@ -1258,6 +1283,13 @@
handleLinkPropertiesUpdate(NO_CALLBACKS);
break;
+ case CMD_UPDATE_L2KEY_GROUPHINT: {
+ final Pair<String, String> args = (Pair<String, String>) msg.obj;
+ mL2Key = args.first;
+ mGroupHint = args.second;
+ break;
+ }
+
case CMD_SET_MULTICAST_FILTER:
mMulticastFiltering = (boolean) msg.obj;
break;
@@ -1357,6 +1389,20 @@
}
break;
+ case CMD_UPDATE_L2KEY_GROUPHINT: {
+ final Pair<String, String> args = (Pair<String, String>) msg.obj;
+ mL2Key = args.first;
+ mGroupHint = args.second;
+ // TODO : attributes should be saved to the memory store with
+ // these new values if they differ from the previous ones.
+ // If the state machine is in pure StartedState, then the values to input
+ // are not known yet and should be updated when the LinkProperties are updated.
+ // If the state machine is in RunningState (which is a child of StartedState)
+ // then the next NUD check should be used to store the new values to avoid
+ // inputting current values for what may be a different L3 network.
+ break;
+ }
+
case EVENT_PROVISIONING_TIMEOUT:
handleProvisioningFailure();
break;
@@ -1389,8 +1435,8 @@
apfConfig.apfCapabilities = mConfiguration.mApfCapabilities;
apfConfig.multicastFilter = mMulticastFiltering;
// Get the Configuration for ApfFilter from Context
- apfConfig.ieee802_3Filter = ApfCapabilities.getApfDrop8023Frames(mContext);
- apfConfig.ethTypeBlackList = ApfCapabilities.getApfEthTypeBlackList(mContext);
+ apfConfig.ieee802_3Filter = ApfCapabilities.getApfDrop8023Frames();
+ apfConfig.ethTypeBlackList = ApfCapabilities.getApfEtherTypeBlackList();
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.
diff --git a/packages/NetworkStack/src/android/net/util/DataStallUtils.java b/packages/NetworkStack/src/android/net/util/DataStallUtils.java
new file mode 100644
index 0000000..b6dbeb1
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/util/DataStallUtils.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2019 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;
+
+/**
+ * Collection of utilities for data stall.
+ */
+public class DataStallUtils {
+ /**
+ * Detect data stall via using dns timeout counts.
+ */
+ public static final int DATA_STALL_EVALUATION_TYPE_DNS = 1;
+ // Default configuration values for data stall detection.
+ public static final int DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = 5;
+ public static final int DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS = 60 * 1000;
+ public static final int DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS = 30 * 60 * 1000;
+ /**
+ * The threshold value for the number of consecutive dns timeout events received to be a
+ * signal of data stall. The number of consecutive timeouts needs to be {@code >=} this
+ * threshold to be considered a data stall. Set the value to {@code <= 0} to disable. Note
+ * that the value should be {@code > 0} if the DNS data stall detection is enabled.
+ *
+ */
+ public static final String CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD =
+ "data_stall_consecutive_dns_timeout_threshold";
+
+ /**
+ * The minimal time interval in milliseconds for data stall reevaluation.
+ *
+ */
+ public static final String CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL =
+ "data_stall_min_evaluate_interval";
+
+ /**
+ * DNS timeouts older than this timeout (in milliseconds) are not considered for detecting
+ * a data stall.
+ *
+ */
+ public static final String CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD =
+ "data_stall_valid_dns_time_threshold";
+
+ /**
+ * Which data stall detection signal to use. This is a bitmask constructed by bitwise-or-ing
+ * (i.e. {@code |}) the DATA_STALL_EVALUATION_TYPE_* values.
+ *
+ * Type: int
+ * Valid values:
+ * {@link #DATA_STALL_EVALUATION_TYPE_DNS} : Use dns as a signal.
+ */
+ public static final String CONFIG_DATA_STALL_EVALUATION_TYPE = "data_stall_evaluation_type";
+ public static final int DEFAULT_DATA_STALL_EVALUATION_TYPES = DATA_STALL_EVALUATION_TYPE_DNS;
+ // The default number of DNS events kept of the log kept for dns signal evaluation. Each event
+ // is represented by a {@link com.android.server.connectivity.NetworkMonitor#DnsResult} objects.
+ // It's also the size of array of {@link com.android.server.connectivity.nano.DnsEvent} kept in
+ // metrics. Note that increasing the size may cause statsd log buffer bust. Need to check the
+ // design in statsd when you try to increase the size.
+ public static final int DEFAULT_DNS_LOG_SIZE = 20;
+}
diff --git a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
index fedb8d1..547f04d 100644
--- a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
+++ b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
@@ -17,18 +17,26 @@
package android.net.util;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.util.SparseArray;
import java.io.FileDescriptor;
import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.SocketException;
import java.util.List;
import java.util.function.Predicate;
-
/**
* Collection of utilities for the network stack.
*/
public class NetworkStackUtils {
+ // TODO: Refer to DeviceConfig definition.
+ public static final String NAMESPACE_CONNECTIVITY = "connectivity";
+
+ static {
+ System.loadLibrary("networkstackutilsjni");
+ }
/**
* @return True if the array is null or 0-length.
@@ -81,4 +89,71 @@
}
return false;
}
+
+ /**
+ * Look up the value of a property for a particular namespace from {@link DeviceConfig}.
+ * @param namespace The namespace containing the property to look up.
+ * @param name The name of the property to look up.
+ * @param defaultValue The value to return if the property does not exist or has no valid value.
+ * @return the corresponding value, or defaultValue if none exists.
+ */
+ @Nullable
+ public static String getDeviceConfigProperty(@NonNull String namespace, @NonNull String name,
+ @Nullable String defaultValue) {
+ // TODO: Link to DeviceConfig API once it is ready.
+ return defaultValue;
+ }
+
+ /**
+ * Look up the value of a property for a particular namespace from {@link DeviceConfig}.
+ * @param namespace The namespace containing the property to look up.
+ * @param name The name of the property to look up.
+ * @param defaultValue The value to return if the property does not exist or has no non-null
+ * value.
+ * @return the corresponding value, or defaultValue if none exists.
+ */
+ public static int getDeviceConfigPropertyInt(@NonNull String namespace, @NonNull String name,
+ int defaultValue) {
+ String value = getDeviceConfigProperty(namespace, name, null /* defaultValue */);
+ try {
+ return (value != null) ? Integer.parseInt(value) : defaultValue;
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
+ }
+
+ /**
+ * Attaches a socket filter that accepts DHCP packets to the given socket.
+ */
+ public static native void attachDhcpFilter(FileDescriptor fd) throws SocketException;
+
+ /**
+ * Attaches a socket filter that accepts ICMPv6 router advertisements to the given socket.
+ * @param fd the socket's {@link FileDescriptor}.
+ * @param packetType the hardware address type, one of ARPHRD_*.
+ */
+ public static native void attachRaFilter(FileDescriptor fd, int packetType)
+ throws SocketException;
+
+ /**
+ * Attaches a socket filter that accepts L2-L4 signaling traffic required for IP connectivity.
+ *
+ * This includes: all ARP, ICMPv6 RS/RA/NS/NA messages, and DHCPv4 exchanges.
+ *
+ * @param fd the socket's {@link FileDescriptor}.
+ * @param packetType the hardware address type, one of ARPHRD_*.
+ */
+ public static native void attachControlPacketFilter(FileDescriptor fd, int packetType)
+ throws SocketException;
+
+ /**
+ * Add an entry into the ARP cache.
+ */
+ public static void addArpEntry(Inet4Address ipv4Addr, android.net.MacAddress ethAddr,
+ String ifname, FileDescriptor fd) throws IOException {
+ addArpEntry(ethAddr.toByteArray(), ipv4Addr.getAddress(), ifname, fd);
+ }
+
+ private static native void addArpEntry(byte[] ethAddr, byte[] netAddr, String ifname,
+ FileDescriptor fd) throws IOException;
}
diff --git a/packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java b/packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java
index 6fb4b0d..afe166b 100644
--- a/packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java
+++ b/packages/NetworkStack/src/com/android/server/NetworkObserverRegistry.java
@@ -181,4 +181,9 @@
@Override
public void onStrictCleartextDetected(int uid, String hex) {}
+
+ @Override
+ public int getInterfaceVersion() {
+ return INetdUnsolicitedEventListener.VERSION;
+ }
}
diff --git a/packages/NetworkStack/src/com/android/server/NetworkStackService.java b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
index 19e9108..a0a90fd 100644
--- a/packages/NetworkStack/src/com/android/server/NetworkStackService.java
+++ b/packages/NetworkStack/src/com/android/server/NetworkStackService.java
@@ -35,7 +35,9 @@
import android.net.INetworkMonitor;
import android.net.INetworkMonitorCallbacks;
import android.net.INetworkStackConnector;
+import android.net.LinkProperties;
import android.net.Network;
+import android.net.NetworkCapabilities;
import android.net.PrivateDnsConfigParcel;
import android.net.dhcp.DhcpServer;
import android.net.dhcp.DhcpServingParams;
@@ -301,15 +303,9 @@
}
@Override
- public void notifySystemReady() {
+ public void notifyNetworkConnected(LinkProperties lp, NetworkCapabilities nc) {
checkNetworkStackCallingPermission();
- mNm.notifySystemReady();
- }
-
- @Override
- public void notifyNetworkConnected() {
- checkNetworkStackCallingPermission();
- mNm.notifyNetworkConnected();
+ mNm.notifyNetworkConnected(lp, nc);
}
@Override
@@ -319,15 +315,15 @@
}
@Override
- public void notifyLinkPropertiesChanged() {
+ public void notifyLinkPropertiesChanged(LinkProperties lp) {
checkNetworkStackCallingPermission();
- mNm.notifyLinkPropertiesChanged();
+ mNm.notifyLinkPropertiesChanged(lp);
}
@Override
- public void notifyNetworkCapabilitiesChanged() {
+ public void notifyNetworkCapabilitiesChanged(NetworkCapabilities nc) {
checkNetworkStackCallingPermission();
- mNm.notifyNetworkCapabilitiesChanged();
+ mNm.notifyNetworkCapabilitiesChanged(nc);
}
}
}
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
index f3476ed..588dcf2 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -28,12 +28,23 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.captiveportal.CaptivePortalProbeSpec.parseCaptivePortalProbeSpecs;
import static android.net.metrics.ValidationProbeEvent.DNS_FAILURE;
import static android.net.metrics.ValidationProbeEvent.DNS_SUCCESS;
import static android.net.metrics.ValidationProbeEvent.PROBE_FALLBACK;
import static android.net.metrics.ValidationProbeEvent.PROBE_PRIVDNS;
+import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD;
+import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_EVALUATION_TYPE;
+import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL;
+import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD;
+import static android.net.util.DataStallUtils.DATA_STALL_EVALUATION_TYPE_DNS;
+import static android.net.util.DataStallUtils.DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD;
+import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_EVALUATION_TYPES;
+import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS;
+import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS;
+import static android.net.util.DataStallUtils.DEFAULT_DNS_LOG_SIZE;
+import static android.net.util.NetworkStackUtils.NAMESPACE_CONNECTIVITY;
import static android.net.util.NetworkStackUtils.isEmpty;
-import static android.provider.Settings.Global.DATA_STALL_EVALUATION_TYPE_DNS;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -42,6 +53,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.INetworkMonitor;
import android.net.INetworkMonitorCallbacks;
@@ -60,6 +72,7 @@
import android.net.metrics.ValidationProbeEvent;
import android.net.shared.NetworkMonitorUtils;
import android.net.shared.PrivateDnsConfig;
+import android.net.util.NetworkStackUtils;
import android.net.util.SharedLog;
import android.net.util.Stopwatch;
import android.net.wifi.WifiInfo;
@@ -78,6 +91,10 @@
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Pair;
+
+import androidx.annotation.ArrayRes;
+import androidx.annotation.StringRes;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.RingBufferIndices;
@@ -93,7 +110,6 @@
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
@@ -101,6 +117,7 @@
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
/**
* {@hide}
@@ -110,33 +127,12 @@
private static final boolean DBG = true;
private static final boolean VDBG = false;
private static final boolean VDBG_STALL = Log.isLoggable(TAG, Log.DEBUG);
- // TODO: use another permission for CaptivePortalLoginActivity once it has its own certificate
- private static final String PERMISSION_NETWORK_SETTINGS = "android.permission.NETWORK_SETTINGS";
- // Default configuration values for captive portal detection probes.
- // TODO: append a random length parameter to the default HTTPS url.
- // TODO: randomize browser version ids in the default User-Agent String.
- private static final String DEFAULT_HTTPS_URL = "https://www.google.com/generate_204";
- private static final String DEFAULT_FALLBACK_URL = "http://www.google.com/gen_204";
- private static final String DEFAULT_OTHER_FALLBACK_URLS =
- "http://play.googleapis.com/generate_204";
private static final String DEFAULT_USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) "
+ "AppleWebKit/537.36 (KHTML, like Gecko) "
+ "Chrome/60.0.3112.32 Safari/537.36";
private static final int SOCKET_TIMEOUT_MS = 10000;
private static final int PROBE_TIMEOUT_MS = 3000;
-
- // Default configuration values for data stall detection.
- private static final int DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = 5;
- private static final int DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS = 60 * 1000;
- private static final int DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS = 30 * 60 * 1000;
-
- private static final int DEFAULT_DATA_STALL_EVALUATION_TYPES =
- DATA_STALL_EVALUATION_TYPE_DNS;
- // Reevaluate it as intending to increase the number. Larger log size may cause statsd
- // log buffer bust and have stats log lost.
- private static final int DEFAULT_DNS_LOG_SIZE = 20;
-
enum EvaluationResult {
VALIDATED(true),
CAPTIVE_PORTAL(false);
@@ -221,19 +217,31 @@
* Message to self indicating captive portal detection is completed.
* obj = CaptivePortalProbeResult for detection result;
*/
- public static final int CMD_PROBE_COMPLETE = 16;
+ private static final int CMD_PROBE_COMPLETE = 16;
/**
* ConnectivityService notifies NetworkMonitor of DNS query responses event.
* arg1 = returncode in OnDnsEvent which indicates the response code for the DNS query.
*/
- public static final int EVENT_DNS_NOTIFICATION = 17;
+ private static final int EVENT_DNS_NOTIFICATION = 17;
/**
* ConnectivityService notifies NetworkMonitor that the user accepts partial connectivity and
* NetworkMonitor should ignore the https probe.
*/
- public static final int EVENT_ACCEPT_PARTIAL_CONNECTIVITY = 18;
+ private static final int EVENT_ACCEPT_PARTIAL_CONNECTIVITY = 18;
+
+ /**
+ * ConnectivityService notifies NetworkMonitor of changed LinkProperties.
+ * obj = new LinkProperties.
+ */
+ private static final int EVENT_LINK_PROPERTIES_CHANGED = 19;
+
+ /**
+ * ConnectivityService notifies NetworkMonitor of changed NetworkCapabilities.
+ * obj = new NetworkCapabilities.
+ */
+ private static final int EVENT_NETWORK_CAPABILITIES_CHANGED = 20;
// Start mReevaluateDelayMs at this value and double.
private static final int INITIAL_REEVALUATE_DELAY_MS = 1000;
@@ -285,8 +293,6 @@
// Avoids surfacing "Sign in to network" notification.
private boolean mDontDisplaySigninNotification = false;
- private volatile boolean mSystemReady = false;
-
private final State mDefaultState = new DefaultState();
private final State mValidatedState = new ValidatedState();
private final State mMaybeNotifyState = new MaybeNotifyState();
@@ -368,7 +374,7 @@
mUseHttps = getUseHttpsValidation();
mCaptivePortalUserAgent = getCaptivePortalUserAgent();
mCaptivePortalHttpsUrl = makeURL(getCaptivePortalServerHttpsUrl());
- mCaptivePortalHttpUrl = makeURL(deps.getCaptivePortalServerHttpUrl(context));
+ mCaptivePortalHttpUrl = makeURL(getCaptivePortalServerHttpUrl());
mCaptivePortalFallbackUrls = makeCaptivePortalFallbackUrls();
mCaptivePortalFallbackSpecs = makeCaptivePortalFallbackProbeSpecs();
mRandom = deps.getRandom();
@@ -377,12 +383,10 @@
mDnsStallDetector = new DnsStallDetector(mConsecutiveDnsTimeoutThreshold);
mDataStallMinEvaluateTime = getDataStallMinEvaluateTime();
mDataStallValidDnsTimeThreshold = getDataStallValidDnsTimeThreshold();
- mDataStallEvaluationType = getDataStallEvalutionType();
+ mDataStallEvaluationType = getDataStallEvaluationType();
- // mLinkProperties and mNetworkCapbilities must never be null or we will NPE.
- // Provide empty objects in case we are started and the network disconnects before
- // we can ever fetch them.
- // TODO: Delete ASAP.
+ // Provide empty LinkProperties and NetworkCapabilities to make sure they are never null,
+ // even before notifyNetworkConnected.
mLinkProperties = new LinkProperties();
mNetworkCapabilities = new NetworkCapabilities(null);
}
@@ -423,19 +427,18 @@
}
/**
- * Send a notification to NetworkMonitor indicating that the system is ready.
- */
- public void notifySystemReady() {
- // No need to run on the handler thread: mSystemReady is volatile and read only once on the
- // isCaptivePortal() thread.
- mSystemReady = true;
- }
-
- /**
* Send a notification to NetworkMonitor indicating that the network is now connected.
*/
- public void notifyNetworkConnected() {
- sendMessage(CMD_NETWORK_CONNECTED);
+ public void notifyNetworkConnected(LinkProperties lp, NetworkCapabilities nc) {
+ sendMessage(CMD_NETWORK_CONNECTED, new Pair<>(
+ new LinkProperties(lp), new NetworkCapabilities(nc)));
+ }
+
+ private void updateConnectedNetworkAttributes(Message connectedMsg) {
+ final Pair<LinkProperties, NetworkCapabilities> attrs =
+ (Pair<LinkProperties, NetworkCapabilities>) connectedMsg.obj;
+ mLinkProperties = attrs.first;
+ mNetworkCapabilities = attrs.second;
}
/**
@@ -448,37 +451,15 @@
/**
* Send a notification to NetworkMonitor indicating that link properties have changed.
*/
- public void notifyLinkPropertiesChanged() {
- getHandler().post(() -> {
- updateLinkProperties();
- });
- }
-
- private void updateLinkProperties() {
- final LinkProperties lp = mCm.getLinkProperties(mNetwork);
- // If null, we should soon get a message that the network was disconnected, and will stop.
- if (lp != null) {
- // TODO: send LinkProperties parceled in notifyLinkPropertiesChanged() and start().
- mLinkProperties = lp;
- }
+ public void notifyLinkPropertiesChanged(final LinkProperties lp) {
+ sendMessage(EVENT_LINK_PROPERTIES_CHANGED, new LinkProperties(lp));
}
/**
* Send a notification to NetworkMonitor indicating that network capabilities have changed.
*/
- public void notifyNetworkCapabilitiesChanged() {
- getHandler().post(() -> {
- updateNetworkCapabilities();
- });
- }
-
- private void updateNetworkCapabilities() {
- final NetworkCapabilities nc = mCm.getNetworkCapabilities(mNetwork);
- // If null, we should soon get a message that the network was disconnected, and will stop.
- if (nc != null) {
- // TODO: send NetworkCapabilities parceled in notifyNetworkCapsChanged() and start().
- mNetworkCapabilities = nc;
- }
+ public void notifyNetworkCapabilitiesChanged(final NetworkCapabilities nc) {
+ sendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED, new NetworkCapabilities(nc));
}
/**
@@ -547,25 +528,15 @@
// does not entail any real state (hence no enter() or exit() routines).
private class DefaultState extends State {
@Override
- public void enter() {
- // TODO: have those passed parceled in start() and remove this
- updateLinkProperties();
- updateNetworkCapabilities();
- }
-
- @Override
public boolean processMessage(Message message) {
switch (message.what) {
case CMD_NETWORK_CONNECTED:
+ updateConnectedNetworkAttributes(message);
logNetworkEvent(NetworkEvent.NETWORK_CONNECTED);
transitionTo(mEvaluatingState);
return HANDLED;
case CMD_NETWORK_DISCONNECTED:
logNetworkEvent(NetworkEvent.NETWORK_DISCONNECTED);
- if (mLaunchCaptivePortalAppBroadcastReceiver != null) {
- mContext.unregisterReceiver(mLaunchCaptivePortalAppBroadcastReceiver);
- mLaunchCaptivePortalAppBroadcastReceiver = null;
- }
quit();
return HANDLED;
case CMD_FORCE_REEVALUATION:
@@ -660,6 +631,12 @@
case EVENT_ACCEPT_PARTIAL_CONNECTIVITY:
mAcceptPartialConnectivity = true;
break;
+ case EVENT_LINK_PROPERTIES_CHANGED:
+ mLinkProperties = (LinkProperties) message.obj;
+ break;
+ case EVENT_NETWORK_CAPABILITIES_CHANGED:
+ mNetworkCapabilities = (NetworkCapabilities) message.obj;
+ break;
default:
break;
}
@@ -684,6 +661,7 @@
public boolean processMessage(Message message) {
switch (message.what) {
case CMD_NETWORK_CONNECTED:
+ updateConnectedNetworkAttributes(message);
transitionTo(mValidatedState);
break;
case CMD_EVALUATE_PRIVATE_DNS:
@@ -792,6 +770,10 @@
@Override
public void exit() {
+ if (mLaunchCaptivePortalAppBroadcastReceiver != null) {
+ mContext.unregisterReceiver(mLaunchCaptivePortalAppBroadcastReceiver);
+ mLaunchCaptivePortalAppBroadcastReceiver = null;
+ }
hideProvisioningNotification();
}
}
@@ -915,9 +897,10 @@
mLaunchCaptivePortalAppBroadcastReceiver = new CustomIntentReceiver(
ACTION_LAUNCH_CAPTIVE_PORTAL_APP, new Random().nextInt(),
CMD_LAUNCH_CAPTIVE_PORTAL_APP);
+ // Display the sign in notification.
+ // Only do this once for every time we enter MaybeNotifyState. b/122164725
+ showProvisioningNotification(mLaunchCaptivePortalAppBroadcastReceiver.mAction);
}
- // Display the sign in notification.
- showProvisioningNotification(mLaunchCaptivePortalAppBroadcastReceiver.mAction);
// Retest for captive portal occasionally.
sendMessageDelayed(CMD_CAPTIVE_PORTAL_RECHECK, 0 /* no UID */,
CAPTIVE_PORTAL_REEVALUATE_DELAY_MS);
@@ -1191,53 +1174,67 @@
}
private String getCaptivePortalServerHttpsUrl() {
- return mDependencies.getSetting(mContext,
- Settings.Global.CAPTIVE_PORTAL_HTTPS_URL, DEFAULT_HTTPS_URL);
+ return getSettingFromResource(mContext, R.string.config_captive_portal_https_url,
+ R.string.default_captive_portal_https_url,
+ Settings.Global.CAPTIVE_PORTAL_HTTPS_URL);
+ }
+
+ /**
+ * Get the captive portal server HTTP URL that is configured on the device.
+ *
+ * NetworkMonitor does not use {@link ConnectivityManager#getCaptivePortalServerUrl()} as
+ * it has its own updatable strategies to detect captive portals. The framework only advises
+ * on one URL that can be used, while NetworkMonitor may implement more complex logic.
+ */
+ public String getCaptivePortalServerHttpUrl() {
+ return getSettingFromResource(mContext, R.string.config_captive_portal_http_url,
+ R.string.default_captive_portal_http_url,
+ Settings.Global.CAPTIVE_PORTAL_HTTP_URL);
}
private int getConsecutiveDnsTimeoutThreshold() {
- return mDependencies.getSetting(mContext,
- Settings.Global.DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD,
+ return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
+ CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD,
DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD);
}
private int getDataStallMinEvaluateTime() {
- return mDependencies.getSetting(mContext,
- Settings.Global.DATA_STALL_MIN_EVALUATE_INTERVAL,
+ return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
+ CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL,
DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS);
}
private int getDataStallValidDnsTimeThreshold() {
- return mDependencies.getSetting(mContext,
- Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD,
+ return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
+ CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD,
DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS);
}
- private int getDataStallEvalutionType() {
- return mDependencies.getSetting(mContext, Settings.Global.DATA_STALL_EVALUATION_TYPE,
+ private int getDataStallEvaluationType() {
+ return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
+ CONFIG_DATA_STALL_EVALUATION_TYPE,
DEFAULT_DATA_STALL_EVALUATION_TYPES);
}
private URL[] makeCaptivePortalFallbackUrls() {
try {
- String separator = ",";
- String firstUrl = mDependencies.getSetting(mContext,
- Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, DEFAULT_FALLBACK_URL);
- String joinedUrls = firstUrl + separator + mDependencies.getSetting(mContext,
- Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS,
- DEFAULT_OTHER_FALLBACK_URLS);
- List<URL> urls = new ArrayList<>();
- for (String s : joinedUrls.split(separator)) {
- URL u = makeURL(s);
- if (u == null) {
- continue;
- }
- urls.add(u);
+ final String firstUrl = mDependencies.getSetting(mContext,
+ Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, null);
+
+ final URL[] settingProviderUrls;
+ if (!TextUtils.isEmpty(firstUrl)) {
+ final String otherUrls = mDependencies.getSetting(mContext,
+ Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, "");
+ // otherUrls may be empty, but .split() ignores trailing empty strings
+ final String separator = ",";
+ final String[] urls = (firstUrl + separator + otherUrls).split(separator);
+ settingProviderUrls = convertStrings(urls, this::makeURL, new URL[0]);
+ } else {
+ settingProviderUrls = new URL[0];
}
- if (urls.isEmpty()) {
- Log.e(TAG, String.format("could not create any url from %s", joinedUrls));
- }
- return urls.toArray(new URL[urls.size()]);
+
+ return getArrayConfig(settingProviderUrls, R.array.config_captive_portal_fallback_urls,
+ R.array.default_captive_portal_fallback_urls, this::makeURL);
} catch (Exception e) {
// Don't let a misconfiguration bootloop the system.
Log.e(TAG, "Error parsing configured fallback URLs", e);
@@ -1249,15 +1246,14 @@
try {
final String settingsValue = mDependencies.getSetting(
mContext, Settings.Global.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS, null);
- // Probe specs only used if configured in settings
- if (TextUtils.isEmpty(settingsValue)) {
- return null;
- }
+ final CaptivePortalProbeSpec[] emptySpecs = new CaptivePortalProbeSpec[0];
+ final CaptivePortalProbeSpec[] providerValue = TextUtils.isEmpty(settingsValue)
+ ? emptySpecs
+ : parseCaptivePortalProbeSpecs(settingsValue).toArray(emptySpecs);
- final Collection<CaptivePortalProbeSpec> specs =
- CaptivePortalProbeSpec.parseCaptivePortalProbeSpecs(settingsValue);
- final CaptivePortalProbeSpec[] specsArray = new CaptivePortalProbeSpec[specs.size()];
- return specs.toArray(specsArray);
+ return getArrayConfig(providerValue, R.array.config_captive_portal_fallback_probe_specs,
+ R.array.default_captive_portal_fallback_probe_specs,
+ CaptivePortalProbeSpec::parseSpecOrNull);
} catch (Exception e) {
// Don't let a misconfiguration bootloop the system.
Log.e(TAG, "Error parsing configured fallback probe specs", e);
@@ -1265,6 +1261,83 @@
}
}
+ /**
+ * Read a setting from a resource or the settings provider.
+ *
+ * <p>The configuration resource is prioritized, then the provider value, then the default
+ * resource value.
+ * @param context The context
+ * @param configResource The resource id for the configuration parameter
+ * @param defaultResource The resource id for the default value
+ * @param symbol The symbol in the settings provider
+ * @return The best available value
+ */
+ @NonNull
+ private String getSettingFromResource(@NonNull final Context context,
+ @StringRes int configResource, @StringRes int defaultResource,
+ @NonNull String symbol) {
+ final Resources res = context.getResources();
+ String setting = res.getString(configResource);
+
+ if (!TextUtils.isEmpty(setting)) return setting;
+
+ setting = mDependencies.getSetting(context, symbol, null);
+ if (!TextUtils.isEmpty(setting)) return setting;
+
+ return res.getString(defaultResource);
+ }
+
+ /**
+ * Get an array configuration from resources or the settings provider.
+ *
+ * <p>The configuration resource is prioritized, then the provider values, then the default
+ * resource values.
+ * @param providerValue Values obtained from the setting provider.
+ * @param configResId ID of the configuration resource.
+ * @param defaultResId ID of the default resource.
+ * @param resourceConverter Converter from the resource strings to stored setting class. Null
+ * return values are ignored.
+ */
+ private <T> T[] getArrayConfig(@NonNull T[] providerValue, @ArrayRes int configResId,
+ @ArrayRes int defaultResId, @NonNull Function<String, T> resourceConverter) {
+ final Resources res = mContext.getResources();
+ String[] configValue = res.getStringArray(configResId);
+
+ if (configValue.length == 0) {
+ if (providerValue.length > 0) {
+ return providerValue;
+ }
+
+ configValue = res.getStringArray(defaultResId);
+ }
+
+ return convertStrings(configValue, resourceConverter, Arrays.copyOf(providerValue, 0));
+ }
+
+ /**
+ * Convert a String array to an array of some other type using the specified converter.
+ *
+ * <p>Any null value, or value for which the converter throws a {@link RuntimeException}, will
+ * not be added to the output array, so the output array may be smaller than the input.
+ */
+ private <T> T[] convertStrings(
+ @NonNull String[] strings, Function<String, T> converter, T[] emptyArray) {
+ final ArrayList<T> convertedValues = new ArrayList<>(strings.length);
+ for (String configString : strings) {
+ T convertedValue = null;
+ try {
+ convertedValue = converter.apply(configString);
+ } catch (Exception e) {
+ Log.e(TAG, "Error parsing configuration", e);
+ // Fall through
+ }
+ if (convertedValue != null) {
+ convertedValues.add(convertedValue);
+ }
+ }
+ return convertedValues.toArray(emptyArray);
+ }
+
private String getCaptivePortalUserAgent() {
return mDependencies.getSetting(mContext,
Settings.Global.CAPTIVE_PORTAL_USER_AGENT, DEFAULT_USER_AGENT);
@@ -1594,10 +1667,6 @@
*/
private void sendNetworkConditionsBroadcast(boolean responseReceived, boolean isCaptivePortal,
long requestTimestampMs, long responseTimestampMs) {
- if (!mSystemReady) {
- return;
- }
-
Intent latencyBroadcast =
new Intent(NetworkMonitorUtils.ACTION_NETWORK_CONDITIONS_MEASURED);
if (mNetworkCapabilities.hasTransport(TRANSPORT_WIFI)) {
@@ -1710,19 +1779,6 @@
}
/**
- * Get the captive portal server HTTP URL that is configured on the device.
- *
- * NetworkMonitor does not use {@link ConnectivityManager#getCaptivePortalServerUrl()} as
- * it has its own updatable strategies to detect captive portals. The framework only advises
- * on one URL that can be used, while NetworkMonitor may implement more complex logic.
- */
- public String getCaptivePortalServerHttpUrl(Context context) {
- final String defaultUrl =
- context.getResources().getString(R.string.config_captive_portal_http_url);
- return NetworkMonitorUtils.getCaptivePortalServerHttpUrl(context, defaultUrl);
- }
-
- /**
* Get the value of a global integer setting.
* @param symbol Name of the setting
* @param defaultValue Value to return if the setting is not defined.
@@ -1741,6 +1797,33 @@
return value != null ? value : defaultValue;
}
+ /**
+ * Look up the value of a property in DeviceConfig.
+ * @param namespace The namespace containing the property to look up.
+ * @param name The name of the property to look up.
+ * @param defaultValue The value to return if the property does not exist or has no non-null
+ * value.
+ * @return the corresponding value, or defaultValue if none exists.
+ */
+ @Nullable
+ public String getDeviceConfigProperty(@NonNull String namespace, @NonNull String name,
+ @Nullable String defaultValue) {
+ return NetworkStackUtils.getDeviceConfigProperty(namespace, name, defaultValue);
+ }
+
+ /**
+ * Look up the value of a property in DeviceConfig.
+ * @param namespace The namespace containing the property to look up.
+ * @param name The name of the property to look up.
+ * @param defaultValue The value to return if the property does not exist or has no non-null
+ * value.
+ * @return the corresponding value, or defaultValue if none exists.
+ */
+ public int getDeviceConfigPropertyInt(@NonNull String namespace, @NonNull String name,
+ int defaultValue) {
+ return NetworkStackUtils.getDeviceConfigPropertyInt(namespace, name, defaultValue);
+ }
+
public static final Dependencies DEFAULT = new Dependencies();
}
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
index 4d4ceed..764e2d0 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreDatabase.java
@@ -72,6 +72,10 @@
public static final String COLNAME_ASSIGNEDV4ADDRESS = "assignedV4Address";
public static final String COLTYPE_ASSIGNEDV4ADDRESS = "INTEGER";
+ public static final String COLNAME_ASSIGNEDV4ADDRESSEXPIRY = "assignedV4AddressExpiry";
+ // The lease expiry timestamp in uint of milliseconds
+ public static final String COLTYPE_ASSIGNEDV4ADDRESSEXPIRY = "BIGINT";
+
// Please note that the group hint is only a *hint*, hence its name. The client can offer
// this information to nudge the grouping in the decision it thinks is right, but it can't
// decide for the memory store what is the same L3 network.
@@ -86,13 +90,14 @@
public static final String COLTYPE_MTU = "INTEGER DEFAULT -1";
public static final String CREATE_TABLE = "CREATE TABLE IF NOT EXISTS "
- + TABLENAME + " ("
- + COLNAME_L2KEY + " " + COLTYPE_L2KEY + " PRIMARY KEY NOT NULL, "
- + COLNAME_EXPIRYDATE + " " + COLTYPE_EXPIRYDATE + ", "
- + COLNAME_ASSIGNEDV4ADDRESS + " " + COLTYPE_ASSIGNEDV4ADDRESS + ", "
- + COLNAME_GROUPHINT + " " + COLTYPE_GROUPHINT + ", "
- + COLNAME_DNSADDRESSES + " " + COLTYPE_DNSADDRESSES + ", "
- + COLNAME_MTU + " " + COLTYPE_MTU + ")";
+ + TABLENAME + " ("
+ + COLNAME_L2KEY + " " + COLTYPE_L2KEY + " PRIMARY KEY NOT NULL, "
+ + COLNAME_EXPIRYDATE + " " + COLTYPE_EXPIRYDATE + ", "
+ + COLNAME_ASSIGNEDV4ADDRESS + " " + COLTYPE_ASSIGNEDV4ADDRESS + ", "
+ + COLNAME_ASSIGNEDV4ADDRESSEXPIRY + " " + COLTYPE_ASSIGNEDV4ADDRESSEXPIRY + ", "
+ + COLNAME_GROUPHINT + " " + COLTYPE_GROUPHINT + ", "
+ + COLNAME_DNSADDRESSES + " " + COLTYPE_DNSADDRESSES + ", "
+ + COLNAME_MTU + " " + COLTYPE_MTU + ")";
public static final String DROP_TABLE = "DROP TABLE IF EXISTS " + TABLENAME;
}
@@ -134,8 +139,9 @@
/** The SQLite DB helper */
public static class DbHelper extends SQLiteOpenHelper {
// Update this whenever changing the schema.
- private static final int SCHEMA_VERSION = 2;
+ private static final int SCHEMA_VERSION = 4;
private static final String DATABASE_FILENAME = "IpMemoryStore.db";
+ private static final String TRIGGER_NAME = "delete_cascade_to_private";
public DbHelper(@NonNull final Context context) {
super(context, DATABASE_FILENAME, null, SCHEMA_VERSION);
@@ -147,16 +153,38 @@
public void onCreate(@NonNull final SQLiteDatabase db) {
db.execSQL(NetworkAttributesContract.CREATE_TABLE);
db.execSQL(PrivateDataContract.CREATE_TABLE);
+ createTrigger(db);
}
/** Called when the database is upgraded */
@Override
public void onUpgrade(@NonNull final SQLiteDatabase db, final int oldVersion,
final int newVersion) {
- // No upgrade supported yet.
- db.execSQL(NetworkAttributesContract.DROP_TABLE);
- db.execSQL(PrivateDataContract.DROP_TABLE);
- onCreate(db);
+ try {
+ if (oldVersion < 2) {
+ // upgrade from version 1 to version 2
+ // since we starts from version 2, do nothing here
+ }
+
+ if (oldVersion < 3) {
+ // upgrade from version 2 to version 3
+ final String sqlUpgradeAddressExpiry = "alter table"
+ + " " + NetworkAttributesContract.TABLENAME + " ADD"
+ + " " + NetworkAttributesContract.COLNAME_ASSIGNEDV4ADDRESSEXPIRY
+ + " " + NetworkAttributesContract.COLTYPE_ASSIGNEDV4ADDRESSEXPIRY;
+ db.execSQL(sqlUpgradeAddressExpiry);
+ }
+
+ if (oldVersion < 4) {
+ createTrigger(db);
+ }
+ } catch (SQLiteException e) {
+ Log.e(TAG, "Could not upgrade to the new version", e);
+ // create database with new version
+ db.execSQL(NetworkAttributesContract.DROP_TABLE);
+ db.execSQL(PrivateDataContract.DROP_TABLE);
+ onCreate(db);
+ }
}
/** Called when the database is downgraded */
@@ -166,8 +194,20 @@
// Downgrades always nuke all data and recreate an empty table.
db.execSQL(NetworkAttributesContract.DROP_TABLE);
db.execSQL(PrivateDataContract.DROP_TABLE);
+ db.execSQL("DROP TRIGGER " + TRIGGER_NAME);
onCreate(db);
}
+
+ private void createTrigger(@NonNull final SQLiteDatabase db) {
+ final String createTrigger = "CREATE TRIGGER " + TRIGGER_NAME
+ + " DELETE ON " + NetworkAttributesContract.TABLENAME
+ + " BEGIN"
+ + " DELETE FROM " + PrivateDataContract.TABLENAME + " WHERE OLD."
+ + NetworkAttributesContract.COLNAME_L2KEY
+ + "=" + PrivateDataContract.COLNAME_L2KEY
+ + "; END;";
+ db.execSQL(createTrigger);
+ }
}
@NonNull
@@ -204,6 +244,10 @@
values.put(NetworkAttributesContract.COLNAME_ASSIGNEDV4ADDRESS,
inet4AddressToIntHTH(attributes.assignedV4Address));
}
+ if (null != attributes.assignedV4AddressExpiry) {
+ values.put(NetworkAttributesContract.COLNAME_ASSIGNEDV4ADDRESSEXPIRY,
+ attributes.assignedV4AddressExpiry);
+ }
if (null != attributes.groupHint) {
values.put(NetworkAttributesContract.COLNAME_GROUPHINT, attributes.groupHint);
}
@@ -251,6 +295,8 @@
final NetworkAttributes.Builder builder = new NetworkAttributes.Builder();
final int assignedV4AddressInt = getInt(cursor,
NetworkAttributesContract.COLNAME_ASSIGNEDV4ADDRESS, 0);
+ final long assignedV4AddressExpiry = getLong(cursor,
+ NetworkAttributesContract.COLNAME_ASSIGNEDV4ADDRESSEXPIRY, 0);
final String groupHint = getString(cursor, NetworkAttributesContract.COLNAME_GROUPHINT);
final byte[] dnsAddressesBlob =
getBlob(cursor, NetworkAttributesContract.COLNAME_DNSADDRESSES);
@@ -258,6 +304,9 @@
if (0 != assignedV4AddressInt) {
builder.setAssignedV4Address(intToInet4AddressHTH(assignedV4AddressInt));
}
+ if (0 != assignedV4AddressExpiry) {
+ builder.setAssignedV4AddressExpiry(assignedV4AddressExpiry);
+ }
builder.setGroupHint(groupHint);
if (null != dnsAddressesBlob) {
builder.setDnsAddresses(decodeAddressList(dnsAddressesBlob));
@@ -305,7 +354,7 @@
}
// If the attributes are null, this will only write the expiry.
- // Returns an int out of Status.{SUCCESS,ERROR_*}
+ // Returns an int out of Status.{SUCCESS, ERROR_*}
static int storeNetworkAttributes(@NonNull final SQLiteDatabase db, @NonNull final String key,
final long expiry, @Nullable final NetworkAttributes attributes) {
final ContentValues cv = toContentValues(key, attributes, expiry);
@@ -330,7 +379,7 @@
return Status.ERROR_STORAGE;
}
- // Returns an int out of Status.{SUCCESS,ERROR_*}
+ // Returns an int out of Status.{SUCCESS, ERROR_*}
static int storeBlob(@NonNull final SQLiteDatabase db, @NonNull final String key,
@NonNull final String clientId, @NonNull final String name,
@NonNull final byte[] data) {
@@ -493,6 +542,93 @@
return bestKey;
}
+ // Drops all records that are expired. Relevance has decayed to zero of these records. Returns
+ // an int out of Status.{SUCCESS, ERROR_*}
+ static int dropAllExpiredRecords(@NonNull final SQLiteDatabase db) {
+ db.beginTransaction();
+ try {
+ // Deletes NetworkAttributes that have expired.
+ db.delete(NetworkAttributesContract.TABLENAME,
+ NetworkAttributesContract.COLNAME_EXPIRYDATE + " < ?",
+ new String[]{Long.toString(System.currentTimeMillis())});
+ db.setTransactionSuccessful();
+ } catch (SQLiteException e) {
+ Log.e(TAG, "Could not delete data from memory store", e);
+ return Status.ERROR_STORAGE;
+ } finally {
+ db.endTransaction();
+ }
+
+ // Execute vacuuming here if above operation has no exception. If above operation got
+ // exception, vacuuming can be ignored for reducing unnecessary consumption.
+ try {
+ db.execSQL("VACUUM");
+ } catch (SQLiteException e) {
+ // Do nothing.
+ }
+ return Status.SUCCESS;
+ }
+
+ // Drops number of records that start from the lowest expiryDate. Returns an int out of
+ // Status.{SUCCESS, ERROR_*}
+ static int dropNumberOfRecords(@NonNull final SQLiteDatabase db, int number) {
+ if (number <= 0) {
+ return Status.ERROR_ILLEGAL_ARGUMENT;
+ }
+
+ // Queries number of NetworkAttributes that start from the lowest expiryDate.
+ final Cursor cursor = db.query(NetworkAttributesContract.TABLENAME,
+ new String[] {NetworkAttributesContract.COLNAME_EXPIRYDATE}, // columns
+ null, // selection
+ null, // selectionArgs
+ null, // groupBy
+ null, // having
+ NetworkAttributesContract.COLNAME_EXPIRYDATE, // orderBy
+ Integer.toString(number)); // limit
+ if (cursor == null || cursor.getCount() <= 0) return Status.ERROR_GENERIC;
+ cursor.moveToLast();
+
+ //Get the expiryDate from last record.
+ final long expiryDate = getLong(cursor, NetworkAttributesContract.COLNAME_EXPIRYDATE, 0);
+ cursor.close();
+
+ db.beginTransaction();
+ try {
+ // Deletes NetworkAttributes that expiryDate are lower than given value.
+ db.delete(NetworkAttributesContract.TABLENAME,
+ NetworkAttributesContract.COLNAME_EXPIRYDATE + " <= ?",
+ new String[]{Long.toString(expiryDate)});
+ db.setTransactionSuccessful();
+ } catch (SQLiteException e) {
+ Log.e(TAG, "Could not delete data from memory store", e);
+ return Status.ERROR_STORAGE;
+ } finally {
+ db.endTransaction();
+ }
+
+ // Execute vacuuming here if above operation has no exception. If above operation got
+ // exception, vacuuming can be ignored for reducing unnecessary consumption.
+ try {
+ db.execSQL("VACUUM");
+ } catch (SQLiteException e) {
+ // Do nothing.
+ }
+ return Status.SUCCESS;
+ }
+
+ static int getTotalRecordNumber(@NonNull final SQLiteDatabase db) {
+ // Query the total number of NetworkAttributes
+ final Cursor cursor = db.query(NetworkAttributesContract.TABLENAME,
+ new String[] {"COUNT(*)"}, // columns
+ null, // selection
+ null, // selectionArgs
+ null, // groupBy
+ null, // having
+ null); // orderBy
+ cursor.moveToFirst();
+ return cursor == null ? 0 : cursor.getInt(0);
+ }
+
// Helper methods
private static String getString(final Cursor cursor, final String columnName) {
final int columnIndex = cursor.getColumnIndex(columnName);
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
index f801b35..5650f21 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreService.java
@@ -22,6 +22,7 @@
import static android.net.ipmemorystore.Status.SUCCESS;
import static com.android.server.connectivity.ipmemorystore.IpMemoryStoreDatabase.EXPIRY_ERROR;
+import static com.android.server.connectivity.ipmemorystore.RegularMaintenanceJobService.InterruptMaintenance;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -43,6 +44,9 @@
import android.os.RemoteException;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.File;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -57,8 +61,17 @@
public class IpMemoryStoreService extends IIpMemoryStore.Stub {
private static final String TAG = IpMemoryStoreService.class.getSimpleName();
private static final int MAX_CONCURRENT_THREADS = 4;
+ private static final int DATABASE_SIZE_THRESHOLD = 10 * 1024 * 1024; //10MB
+ private static final int MAX_DROP_RECORD_TIMES = 500;
+ private static final int MIN_DELETE_NUM = 5;
private static final boolean DBG = true;
+ // Error codes below are internal and used for notifying status beteween IpMemoryStore modules.
+ static final int ERROR_INTERNAL_BASE = -1_000_000_000;
+ // This error code is used for maintenance only to notify RegularMaintenanceJobService that
+ // full maintenance job has been interrupted.
+ static final int ERROR_INTERNAL_INTERRUPTED = ERROR_INTERNAL_BASE - 1;
+
@NonNull
final Context mContext;
@Nullable
@@ -111,6 +124,7 @@
// with judicious subclassing of ThreadPoolExecutor, but that's a lot of dangerous
// complexity for little benefit in this case.
mExecutor = Executors.newWorkStealingPool(MAX_CONCURRENT_THREADS);
+ RegularMaintenanceJobService.schedule(mContext, this);
}
/**
@@ -125,6 +139,7 @@
// guarantee the threads can be terminated in any given amount of time.
mExecutor.shutdownNow();
if (mDb != null) mDb.close();
+ RegularMaintenanceJobService.unschedule(mContext);
}
/** Helper function to make a status object */
@@ -394,4 +409,89 @@
}
});
}
+
+ /** Get db size threshold. */
+ @VisibleForTesting
+ protected int getDbSizeThreshold() {
+ return DATABASE_SIZE_THRESHOLD;
+ }
+
+ private long getDbSize() {
+ final File dbFile = new File(mDb.getPath());
+ try {
+ return dbFile.length();
+ } catch (final SecurityException e) {
+ if (DBG) Log.e(TAG, "Read db size access deny.", e);
+ // Return zero value if can't get disk usage exactly.
+ return 0;
+ }
+ }
+
+ /** Check if db size is over the threshold. */
+ @VisibleForTesting
+ boolean isDbSizeOverThreshold() {
+ return getDbSize() > getDbSizeThreshold();
+ }
+
+ /**
+ * Full maintenance.
+ *
+ * @param listener A listener to inform of the completion of this call.
+ */
+ void fullMaintenance(@NonNull final IOnStatusListener listener,
+ @NonNull final InterruptMaintenance interrupt) {
+ mExecutor.execute(() -> {
+ try {
+ if (null == mDb) {
+ listener.onComplete(makeStatus(ERROR_DATABASE_CANNOT_BE_OPENED));
+ return;
+ }
+
+ // Interrupt maintenance because the scheduling job has been canceled.
+ if (checkForInterrupt(listener, interrupt)) return;
+
+ int result = SUCCESS;
+ // Drop all records whose relevance has decayed to zero.
+ // This is the first step to decrease memory store size.
+ result = IpMemoryStoreDatabase.dropAllExpiredRecords(mDb);
+
+ if (checkForInterrupt(listener, interrupt)) return;
+
+ // Aggregate historical data in passes
+ // TODO : Waiting for historical data implement.
+
+ // Check if db size meets the storage goal(10MB). If not, keep dropping records and
+ // aggregate historical data until the storage goal is met. Use for loop with 500
+ // times restriction to prevent infinite loop (Deleting records always fail and db
+ // size is still over the threshold)
+ for (int i = 0; isDbSizeOverThreshold() && i < MAX_DROP_RECORD_TIMES; i++) {
+ if (checkForInterrupt(listener, interrupt)) return;
+
+ final int totalNumber = IpMemoryStoreDatabase.getTotalRecordNumber(mDb);
+ final long dbSize = getDbSize();
+ final float decreaseRate = (dbSize == 0)
+ ? 0 : (float) (dbSize - getDbSizeThreshold()) / (float) dbSize;
+ final int deleteNumber = Math.max(
+ (int) (totalNumber * decreaseRate), MIN_DELETE_NUM);
+
+ result = IpMemoryStoreDatabase.dropNumberOfRecords(mDb, deleteNumber);
+
+ if (checkForInterrupt(listener, interrupt)) return;
+
+ // Aggregate historical data
+ // TODO : Waiting for historical data implement.
+ }
+ listener.onComplete(makeStatus(result));
+ } catch (final RemoteException e) {
+ // Client at the other end died
+ }
+ });
+ }
+
+ private boolean checkForInterrupt(@NonNull final IOnStatusListener listener,
+ @NonNull final InterruptMaintenance interrupt) throws RemoteException {
+ if (!interrupt.isInterrupted()) return false;
+ listener.onComplete(makeStatus(ERROR_INTERNAL_INTERRUPTED));
+ return true;
+ }
}
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RegularMaintenanceJobService.java b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RegularMaintenanceJobService.java
new file mode 100644
index 0000000..2775fde
--- /dev/null
+++ b/packages/NetworkStack/src/com/android/server/connectivity/ipmemorystore/RegularMaintenanceJobService.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2019 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.ipmemorystore;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.net.ipmemorystore.IOnStatusListener;
+import android.net.ipmemorystore.Status;
+import android.net.ipmemorystore.StatusParcelable;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Regular maintenance job service.
+ * @hide
+ */
+public final class RegularMaintenanceJobService extends JobService {
+ // Must be unique within the system server uid.
+ public static final int REGULAR_MAINTENANCE_ID = 3345678;
+
+ /**
+ * Class for interrupt check of maintenance job.
+ */
+ public static final class InterruptMaintenance {
+ private volatile boolean mIsInterrupted;
+ private final int mJobId;
+
+ public InterruptMaintenance(int jobId) {
+ mJobId = jobId;
+ mIsInterrupted = false;
+ }
+
+ public int getJobId() {
+ return mJobId;
+ }
+
+ public void setInterrupted(boolean interrupt) {
+ mIsInterrupted = interrupt;
+ }
+
+ public boolean isInterrupted() {
+ return mIsInterrupted;
+ }
+ }
+
+ private static final ArrayList<InterruptMaintenance> sInterruptList = new ArrayList<>();
+ private static IpMemoryStoreService sIpMemoryStoreService;
+
+ @Override
+ public boolean onStartJob(JobParameters params) {
+ if (sIpMemoryStoreService == null) {
+ Log.wtf("RegularMaintenanceJobService",
+ "Can not start job because sIpMemoryStoreService is null.");
+ return false;
+ }
+ final InterruptMaintenance im = new InterruptMaintenance(params.getJobId());
+ sInterruptList.add(im);
+
+ sIpMemoryStoreService.fullMaintenance(new IOnStatusListener() {
+ @Override
+ public void onComplete(final StatusParcelable statusParcelable) throws RemoteException {
+ final Status result = new Status(statusParcelable);
+ if (!result.isSuccess()) {
+ Log.e("RegularMaintenanceJobService", "Regular maintenance failed."
+ + " Error is " + result.resultCode);
+ }
+ sInterruptList.remove(im);
+ jobFinished(params, !result.isSuccess());
+ }
+
+ @Override
+ public IBinder asBinder() {
+ return null;
+ }
+ }, im);
+ return true;
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ final int jobId = params.getJobId();
+ for (InterruptMaintenance im : sInterruptList) {
+ if (im.getJobId() == jobId) {
+ im.setInterrupted(true);
+ }
+ }
+ return true;
+ }
+
+ /** Schedule regular maintenance job */
+ static void schedule(Context context, IpMemoryStoreService ipMemoryStoreService) {
+ final JobScheduler jobScheduler =
+ (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+
+ final ComponentName maintenanceJobName =
+ new ComponentName(context, RegularMaintenanceJobService.class);
+
+ // Regular maintenance is scheduled for when the device is idle with access power and a
+ // minimum interval of one day.
+ final JobInfo regularMaintenanceJob =
+ new JobInfo.Builder(REGULAR_MAINTENANCE_ID, maintenanceJobName)
+ .setRequiresDeviceIdle(true)
+ .setRequiresCharging(true)
+ .setRequiresBatteryNotLow(true)
+ .setPeriodic(TimeUnit.HOURS.toMillis(24)).build();
+
+ jobScheduler.schedule(regularMaintenanceJob);
+ sIpMemoryStoreService = ipMemoryStoreService;
+ }
+
+ /** Unschedule regular maintenance job */
+ static void unschedule(Context context) {
+ final JobScheduler jobScheduler =
+ (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+ jobScheduler.cancel(REGULAR_MAINTENANCE_ID);
+ sIpMemoryStoreService = null;
+ }
+}
diff --git a/packages/NetworkStack/tests/Android.bp b/packages/NetworkStack/tests/Android.bp
index aadf99e..fe3c1e8 100644
--- a/packages/NetworkStack/tests/Android.bp
+++ b/packages/NetworkStack/tests/Android.bp
@@ -42,9 +42,12 @@
"libbinder",
"libbinderthreadstate",
"libc++",
+ "libcgrouprc",
"libcrypto",
"libcutils",
"libdexfile",
+ "ld-android",
+ "libdl_android",
"libhidl-gen-utils",
"libhidlbase",
"libhidltransport",
@@ -54,6 +57,7 @@
"liblzma",
"libnativehelper",
"libnetworkstacktestsjni",
+ "libnetworkstackutilsjni",
"libpackagelistparser",
"libpcre2",
"libprocessgroup",
diff --git a/tests/net/java/android/net/captiveportal/CaptivePortalProbeSpecTest.java b/packages/NetworkStack/tests/src/android/net/captiveportal/CaptivePortalProbeSpecTest.java
similarity index 100%
rename from tests/net/java/android/net/captiveportal/CaptivePortalProbeSpecTest.java
rename to packages/NetworkStack/tests/src/android/net/captiveportal/CaptivePortalProbeSpecTest.java
diff --git a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
index eee12d6..5f80006 100644
--- a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
+++ b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
@@ -28,6 +28,7 @@
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.app.AlarmManager;
@@ -40,7 +41,9 @@
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.MacAddress;
+import android.net.NetworkStackIpMemoryStore;
import android.net.RouteInfo;
+import android.net.ipmemorystore.NetworkAttributes;
import android.net.shared.InitialConfiguration;
import android.net.shared.ProvisioningConfiguration;
import android.net.util.InterfaceParams;
@@ -81,6 +84,8 @@
// See RFC 7042#section-2.1.2 for EUI-48 documentation values.
private static final MacAddress TEST_MAC = MacAddress.fromString("00:00:5E:00:53:01");
private static final int TEST_TIMEOUT_MS = 400;
+ private static final String TEST_L2KEY = "some l2key";
+ private static final String TEST_GROUPHINT = "some grouphint";
@Mock private Context mContext;
@Mock private ConnectivityManager mCm;
@@ -92,6 +97,7 @@
@Mock private IpClient.Dependencies mDependencies;
@Mock private ContentResolver mContentResolver;
@Mock private NetworkStackService.NetworkStackServiceManager mNetworkStackServiceManager;
+ @Mock private NetworkStackIpMemoryStore mIpMemoryStore;
private NetworkObserver mObserver;
private InterfaceParams mIfParams;
@@ -141,6 +147,12 @@
return empty;
}
+ private void verifyNetworkAttributesStored(final String l2Key,
+ final NetworkAttributes attributes) {
+ // TODO : when storing is implemented, turn this on
+ // verify(mIpMemoryStore).storeNetworkAttributes(eq(l2Key), eq(attributes), any());
+ }
+
@Test
public void testNullInterfaceNameMostDefinitelyThrows() throws Exception {
setTestInterfaceParams(null);
@@ -173,6 +185,7 @@
setTestInterfaceParams(TEST_IFNAME);
final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mObserverRegistry,
mNetworkStackServiceManager, mDependencies);
+ verifyNoMoreInteractions(mIpMemoryStore);
ipc.shutdown();
}
@@ -183,6 +196,7 @@
mNetworkStackServiceManager, mDependencies);
ipc.startProvisioning(new ProvisioningConfiguration());
verify(mCb, times(1)).onProvisioningFailure(any());
+ verify(mIpMemoryStore, never()).storeNetworkAttributes(any(), any(), any());
ipc.shutdown();
}
@@ -202,6 +216,7 @@
verify(mCb, times(1)).setNeighborDiscoveryOffload(true);
verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setFallbackMulticastFilter(false);
verify(mCb, never()).onProvisioningFailure(any());
+ verify(mIpMemoryStore, never()).storeNetworkAttributes(any(), any(), any());
ipc.shutdown();
verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(iface, false);
@@ -214,6 +229,8 @@
public void testProvisioningWithInitialConfiguration() throws Exception {
final String iface = TEST_IFNAME;
final IpClient ipc = makeIpClient(iface);
+ final String l2Key = TEST_L2KEY;
+ final String groupHint = TEST_GROUPHINT;
String[] addresses = {
"fe80::a4be:f92:e1f7:22d1/64",
@@ -232,6 +249,7 @@
verify(mCb, times(1)).setNeighborDiscoveryOffload(true);
verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setFallbackMulticastFilter(false);
verify(mCb, never()).onProvisioningFailure(any());
+ ipc.setL2KeyAndGroupHint(l2Key, groupHint);
for (String addr : addresses) {
String[] parts = addr.split("/");
@@ -253,12 +271,16 @@
LinkProperties want = linkproperties(links(addresses), routes(prefixes));
want.setInterfaceName(iface);
verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).onProvisioningSuccess(want);
+ verifyNetworkAttributesStored(l2Key, new NetworkAttributes.Builder()
+ .setGroupHint(groupHint)
+ .build());
ipc.shutdown();
verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(iface, false);
verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(iface);
verify(mCb, timeout(TEST_TIMEOUT_MS).times(1))
.onLinkPropertiesChange(makeEmptyLinkProperties(iface));
+ verifyNoMoreInteractions(mIpMemoryStore);
}
@Test
diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
index d732c4e..fa41284 100644
--- a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -21,14 +21,19 @@
import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY;
import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_VALID;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.provider.Settings.Global.DATA_STALL_EVALUATION_TYPE_DNS;
+import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD;
+import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_EVALUATION_TYPE;
+import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL;
+import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD;
+import static android.net.util.DataStallUtils.DATA_STALL_EVALUATION_TYPE_DNS;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
@@ -42,7 +47,10 @@
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.INetworkMonitorCallbacks;
import android.net.InetAddresses;
@@ -60,6 +68,7 @@
import android.os.Bundle;
import android.os.ConditionVariable;
import android.os.Handler;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.provider.Settings;
import android.telephony.CellSignalStrength;
@@ -69,10 +78,12 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
@@ -81,6 +92,7 @@
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.URL;
+import java.util.HashSet;
import java.util.Random;
import javax.net.ssl.SSLHandshakeException;
@@ -91,6 +103,7 @@
private static final String LOCATION_HEADER = "location";
private @Mock Context mContext;
+ private @Mock Resources mResources;
private @Mock IpConnectivityLog mLogger;
private @Mock SharedLog mValidationLogger;
private @Mock NetworkInfo mNetworkInfo;
@@ -107,9 +120,12 @@
private @Spy Network mNetwork = new Network(TEST_NETID);
private @Mock DataStallStatsUtils mDataStallStatsUtils;
private @Mock WifiInfo mWifiInfo;
+ private @Captor ArgumentCaptor<String> mNetworkTestedRedirectUrlCaptor;
+
+ private HashSet<WrappedNetworkMonitor> mCreatedNetworkMonitors;
+ private HashSet<BroadcastReceiver> mRegisteredReceivers;
private static final int TEST_NETID = 4242;
-
private static final String TEST_HTTP_URL = "http://www.google.com/gen_204";
private static final String TEST_HTTPS_URL = "https://www.google.com/gen_204";
private static final String TEST_FALLBACK_URL = "http://fallback.google.com/gen_204";
@@ -122,7 +138,7 @@
private static final int HANDLER_TIMEOUT_MS = 1000;
- private static final LinkProperties TEST_LINKPROPERTIES = new LinkProperties();
+ private static final LinkProperties TEST_LINK_PROPERTIES = new LinkProperties();
private static final NetworkCapabilities METERED_CAPABILITIES = new NetworkCapabilities()
.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR)
@@ -145,14 +161,20 @@
.thenReturn(Settings.Global.CAPTIVE_PORTAL_MODE_PROMPT);
when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_USE_HTTPS),
anyInt())).thenReturn(1);
- when(mDependencies.getCaptivePortalServerHttpUrl(any())).thenReturn(TEST_HTTP_URL);
- when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTPS_URL),
- anyString())).thenReturn(TEST_HTTPS_URL);
+ when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTP_URL), any()))
+ .thenReturn(TEST_HTTP_URL);
+ when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTPS_URL), any()))
+ .thenReturn(TEST_HTTPS_URL);
+
doReturn(mNetwork).when(mNetwork).getPrivateDnsBypassingCopy();
when(mContext.getSystemService(Context.CONNECTIVITY_SERVICE)).thenReturn(mCm);
when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephony);
when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifi);
+ when(mContext.getResources()).thenReturn(mResources);
+
+ when(mResources.getString(anyInt())).thenReturn("");
+ when(mResources.getStringArray(anyInt())).thenReturn(new String[0]);
when(mNetworkInfo.getType()).thenReturn(ConnectivityManager.TYPE_WIFI);
setFallbackUrl(TEST_FALLBACK_URL);
@@ -182,23 +204,49 @@
InetAddresses.parseNumericAddress("192.168.0.0")
}).when(mNetwork).getAllByName(any());
- // Default values. Individual tests can override these.
- when(mCm.getLinkProperties(any())).thenReturn(TEST_LINKPROPERTIES);
- when(mCm.getNetworkCapabilities(any())).thenReturn(METERED_CAPABILITIES);
+ when(mContext.registerReceiver(any(BroadcastReceiver.class), any())).then((invocation) -> {
+ mRegisteredReceivers.add(invocation.getArgument(0));
+ return new Intent();
+ });
+
+ doAnswer((invocation) -> {
+ mRegisteredReceivers.remove(invocation.getArgument(0));
+ return null;
+ }).when(mContext).unregisterReceiver(any());
setMinDataStallEvaluateInterval(500);
setDataStallEvaluationType(DATA_STALL_EVALUATION_TYPE_DNS);
setValidDataStallDnsTimeThreshold(500);
setConsecutiveDnsTimeoutThreshold(5);
+
+ mCreatedNetworkMonitors = new HashSet<>();
+ mRegisteredReceivers = new HashSet<>();
+ }
+
+ @After
+ public void tearDown() {
+ assertTrue(mCreatedNetworkMonitors.size() > 0);
+ // Make a local copy of mCreatedNetworkMonitors because during the iteration below,
+ // WrappedNetworkMonitor#onQuitting will delete elements from it on the handler threads.
+ WrappedNetworkMonitor[] networkMonitors = mCreatedNetworkMonitors.toArray(
+ new WrappedNetworkMonitor[0]);
+ for (WrappedNetworkMonitor nm : networkMonitors) {
+ nm.notifyNetworkDisconnected();
+ nm.awaitQuit();
+ }
+ assertEquals("NetworkMonitor still running after disconnect",
+ 0, mCreatedNetworkMonitors.size());
+ assertEquals("BroadcastReceiver still registered after disconnect",
+ 0, mRegisteredReceivers.size());
}
private class WrappedNetworkMonitor extends NetworkMonitor {
private long mProbeTime = 0;
+ private final ConditionVariable mQuitCv = new ConditionVariable(false);
- WrappedNetworkMonitor(Context context, Network network, IpConnectivityLog logger,
- Dependencies deps, DataStallStatsUtils statsUtils) {
- super(context, mCallbacks, network, logger,
- new SharedLog("test_nm"), deps, statsUtils);
+ WrappedNetworkMonitor() {
+ super(mContext, mCallbacks, mNetwork, mLogger, mValidationLogger, mDependencies,
+ mDataStallStatsUtils);
}
@Override
@@ -214,35 +262,44 @@
protected void addDnsEvents(@NonNull final DataStallDetectionStats.Builder stats) {
generateTimeoutDnsEvent(stats, DEFAULT_DNS_TIMEOUT_THRESHOLD);
}
+
+ @Override
+ protected void onQuitting() {
+ assertTrue(mCreatedNetworkMonitors.remove(this));
+ mQuitCv.open();
+ }
+
+ protected void awaitQuit() {
+ assertTrue("NetworkMonitor did not quit after " + HANDLER_TIMEOUT_MS + "ms",
+ mQuitCv.block(HANDLER_TIMEOUT_MS));
+ }
}
- private WrappedNetworkMonitor makeMeteredWrappedNetworkMonitor() {
- final WrappedNetworkMonitor nm = new WrappedNetworkMonitor(
- mContext, mNetwork, mLogger, mDependencies, mDataStallStatsUtils);
- when(mCm.getNetworkCapabilities(any())).thenReturn(METERED_CAPABILITIES);
+ private WrappedNetworkMonitor makeMonitor() {
+ final WrappedNetworkMonitor nm = new WrappedNetworkMonitor();
nm.start();
waitForIdle(nm.getHandler());
+ mCreatedNetworkMonitors.add(nm);
return nm;
}
- private WrappedNetworkMonitor makeNotMeteredWrappedNetworkMonitor() {
- final WrappedNetworkMonitor nm = new WrappedNetworkMonitor(
- mContext, mNetwork, mLogger, mDependencies, mDataStallStatsUtils);
- when(mCm.getNetworkCapabilities(any())).thenReturn(NOT_METERED_CAPABILITIES);
- nm.start();
- waitForIdle(nm.getHandler());
+ private WrappedNetworkMonitor makeMeteredNetworkMonitor() {
+ final WrappedNetworkMonitor nm = makeMonitor();
+ setNetworkCapabilities(nm, METERED_CAPABILITIES);
return nm;
}
- private NetworkMonitor makeMonitor() {
- final NetworkMonitor nm = new NetworkMonitor(
- mContext, mCallbacks, mNetwork, mLogger, mValidationLogger,
- mDependencies, mDataStallStatsUtils);
- nm.start();
- waitForIdle(nm.getHandler());
+ private WrappedNetworkMonitor makeNotMeteredNetworkMonitor() {
+ final WrappedNetworkMonitor nm = makeMonitor();
+ setNetworkCapabilities(nm, NOT_METERED_CAPABILITIES);
return nm;
}
+ private void setNetworkCapabilities(NetworkMonitor nm, NetworkCapabilities nc) {
+ nm.notifyNetworkCapabilitiesChanged(nc);
+ waitForIdle(nm.getHandler());
+ }
+
private void waitForIdle(Handler handler) {
final ConditionVariable cv = new ConditionVariable(false);
handler.post(cv::open);
@@ -256,7 +313,7 @@
setSslException(mHttpsConnection);
setPortal302(mHttpConnection);
- assertPortal(makeMonitor().isCaptivePortal());
+ runPortalNetworkTest();
}
@Test
@@ -264,17 +321,7 @@
setStatus(mHttpsConnection, 204);
setStatus(mHttpConnection, 500);
- assertNotPortal(makeMonitor().isCaptivePortal());
- }
-
- @Test
- public void testIsCaptivePortal_HttpsProbeFailedHttpSuccessNotUsed() throws IOException {
- setSslException(mHttpsConnection);
- // Even if HTTP returns a 204, do not use the result unless HTTPS succeeded
- setStatus(mHttpConnection, 204);
- setStatus(mFallbackConnection, 500);
-
- assertFailed(makeMonitor().isCaptivePortal());
+ runNotPortalNetworkTest();
}
@Test
@@ -283,17 +330,17 @@
setStatus(mHttpConnection, 500);
setPortal302(mFallbackConnection);
- assertPortal(makeMonitor().isCaptivePortal());
+ runPortalNetworkTest();
}
@Test
public void testIsCaptivePortal_FallbackProbeIsNotPortal() throws IOException {
setSslException(mHttpsConnection);
setStatus(mHttpConnection, 500);
- setStatus(mFallbackConnection, 204);
+ setStatus(mFallbackConnection, 500);
// Fallback probe did not see portal, HTTPS failed -> inconclusive
- assertFailed(makeMonitor().isCaptivePortal());
+ runFailedNetworkTest();
}
@Test
@@ -310,15 +357,15 @@
// TEST_OTHER_FALLBACK_URL is third
when(mRandom.nextInt()).thenReturn(2);
- final NetworkMonitor monitor = makeMonitor();
-
// First check always uses the first fallback URL: inconclusive
- assertFailed(monitor.isCaptivePortal());
+ final NetworkMonitor monitor = runNetworkTest(NETWORK_TEST_RESULT_INVALID);
+ assertNull(mNetworkTestedRedirectUrlCaptor.getValue());
verify(mFallbackConnection, times(1)).getResponseCode();
verify(mOtherFallbackConnection, never()).getResponseCode();
// Second check uses the URL chosen by Random
- assertPortal(monitor.isCaptivePortal());
+ final CaptivePortalProbeResult result = monitor.isCaptivePortal();
+ assertTrue(result.isPortal());
verify(mOtherFallbackConnection, times(1)).getResponseCode();
}
@@ -328,7 +375,7 @@
setStatus(mHttpConnection, 500);
setStatus(mFallbackConnection, 404);
- assertFailed(makeMonitor().isCaptivePortal());
+ runFailedNetworkTest();
verify(mFallbackConnection, times(1)).getResponseCode();
verify(mOtherFallbackConnection, never()).getResponseCode();
}
@@ -342,7 +389,7 @@
setStatus(mHttpConnection, 500);
setPortal302(mOtherFallbackConnection);
- assertPortal(makeMonitor().isCaptivePortal());
+ runPortalNetworkTest();
verify(mOtherFallbackConnection, times(1)).getResponseCode();
verify(mFallbackConnection, never()).getResponseCode();
}
@@ -360,12 +407,12 @@
}
@Test
- public void testIsCaptivePortal_FallbackSpecIsNotPortal() throws IOException {
+ public void testIsCaptivePortal_FallbackSpecIsPartial() throws IOException {
setupFallbackSpec();
set302(mOtherFallbackConnection, "https://www.google.com/test?q=3");
- // HTTPS failed, fallback spec did not see a portal -> inconclusive
- assertFailed(makeMonitor().isCaptivePortal());
+ // HTTPS failed, fallback spec went through -> partial connectivity
+ runPartialConnectivityNetworkTest();
verify(mOtherFallbackConnection, times(1)).getResponseCode();
verify(mFallbackConnection, never()).getResponseCode();
}
@@ -375,7 +422,7 @@
setupFallbackSpec();
set302(mOtherFallbackConnection, "http://login.portal.example.com");
- assertPortal(makeMonitor().isCaptivePortal());
+ runPortalNetworkTest();
}
@Test
@@ -384,20 +431,20 @@
setSslException(mHttpsConnection);
setPortal302(mHttpConnection);
- assertNotPortal(makeMonitor().isCaptivePortal());
+ runNotPortalNetworkTest();
}
@Test
public void testIsDataStall_EvaluationDisabled() {
setDataStallEvaluationType(0);
- WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor();
+ WrappedNetworkMonitor wrappedMonitor = makeMeteredNetworkMonitor();
wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
assertFalse(wrappedMonitor.isDataStall());
}
@Test
public void testIsDataStall_EvaluationDnsOnNotMeteredNetwork() {
- WrappedNetworkMonitor wrappedMonitor = makeNotMeteredWrappedNetworkMonitor();
+ WrappedNetworkMonitor wrappedMonitor = makeNotMeteredNetworkMonitor();
wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
assertTrue(wrappedMonitor.isDataStall());
@@ -405,7 +452,7 @@
@Test
public void testIsDataStall_EvaluationDnsOnMeteredNetwork() {
- WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor();
+ WrappedNetworkMonitor wrappedMonitor = makeMeteredNetworkMonitor();
wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
assertFalse(wrappedMonitor.isDataStall());
@@ -416,7 +463,7 @@
@Test
public void testIsDataStall_EvaluationDnsWithDnsTimeoutCount() {
- WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor();
+ WrappedNetworkMonitor wrappedMonitor = makeMeteredNetworkMonitor();
wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
makeDnsTimeoutEvent(wrappedMonitor, 3);
assertFalse(wrappedMonitor.isDataStall());
@@ -430,7 +477,7 @@
// Set the value to larger than the default dns log size.
setConsecutiveDnsTimeoutThreshold(51);
- wrappedMonitor = makeMeteredWrappedNetworkMonitor();
+ wrappedMonitor = makeMeteredNetworkMonitor();
wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
makeDnsTimeoutEvent(wrappedMonitor, 50);
assertFalse(wrappedMonitor.isDataStall());
@@ -442,7 +489,7 @@
@Test
public void testIsDataStall_EvaluationDnsWithDnsTimeThreshold() {
// Test dns events happened in valid dns time threshold.
- WrappedNetworkMonitor wrappedMonitor = makeMeteredWrappedNetworkMonitor();
+ WrappedNetworkMonitor wrappedMonitor = makeMeteredNetworkMonitor();
wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
assertFalse(wrappedMonitor.isDataStall());
@@ -451,7 +498,7 @@
// Test dns events happened before valid dns time threshold.
setValidDataStallDnsTimeThreshold(0);
- wrappedMonitor = makeMeteredWrappedNetworkMonitor();
+ wrappedMonitor = makeMeteredNetworkMonitor();
wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 100);
makeDnsTimeoutEvent(wrappedMonitor, DEFAULT_DNS_TIMEOUT_THRESHOLD);
assertFalse(wrappedMonitor.isDataStall());
@@ -464,24 +511,13 @@
setSslException(mHttpsConnection);
setStatus(mHttpConnection, 500);
setStatus(mFallbackConnection, 404);
- when(mCm.getNetworkCapabilities(any())).thenReturn(METERED_CAPABILITIES);
- final NetworkMonitor nm = makeMonitor();
- nm.notifyNetworkConnected();
-
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
- .notifyNetworkTested(NETWORK_TEST_RESULT_INVALID, null);
+ runFailedNetworkTest();
}
@Test
public void testNoInternetCapabilityValidated() throws Exception {
- when(mCm.getNetworkCapabilities(any())).thenReturn(NO_INTERNET_CAPABILITIES);
-
- final NetworkMonitor nm = makeMonitor();
- nm.notifyNetworkConnected();
-
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
- .notifyNetworkTested(NETWORK_TEST_RESULT_VALID, null);
+ runNetworkTest(NO_INTERNET_CAPABILITIES, NETWORK_TEST_RESULT_VALID);
verify(mNetwork, never()).openConnection(any());
}
@@ -491,11 +527,13 @@
setPortal302(mHttpConnection);
final NetworkMonitor nm = makeMonitor();
- nm.notifyNetworkConnected();
+ nm.notifyNetworkConnected(TEST_LINK_PROPERTIES, METERED_CAPABILITIES);
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
.showProvisioningNotification(any(), any());
+ assertEquals(1, mRegisteredReceivers.size());
+
// Check that startCaptivePortalApp sends the expected intent.
nm.launchCaptivePortalApp();
@@ -518,11 +556,13 @@
nm.notifyCaptivePortalAppFinished(APP_RETURN_DISMISSED);
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
.notifyNetworkTested(NETWORK_TEST_RESULT_VALID, null);
+
+ assertEquals(0, mRegisteredReceivers.size());
}
@Test
public void testDataStall_StallSuspectedAndSendMetrics() throws IOException {
- WrappedNetworkMonitor wrappedMonitor = makeNotMeteredWrappedNetworkMonitor();
+ WrappedNetworkMonitor wrappedMonitor = makeNotMeteredNetworkMonitor();
wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
makeDnsTimeoutEvent(wrappedMonitor, 5);
assertTrue(wrappedMonitor.isDataStall());
@@ -531,7 +571,7 @@
@Test
public void testDataStall_NoStallSuspectedAndSendMetrics() throws IOException {
- WrappedNetworkMonitor wrappedMonitor = makeNotMeteredWrappedNetworkMonitor();
+ WrappedNetworkMonitor wrappedMonitor = makeNotMeteredNetworkMonitor();
wrappedMonitor.setLastProbeTime(SystemClock.elapsedRealtime() - 1000);
makeDnsTimeoutEvent(wrappedMonitor, 3);
assertFalse(wrappedMonitor.isDataStall());
@@ -540,7 +580,7 @@
@Test
public void testCollectDataStallMetrics() {
- WrappedNetworkMonitor wrappedMonitor = makeNotMeteredWrappedNetworkMonitor();
+ WrappedNetworkMonitor wrappedMonitor = makeNotMeteredNetworkMonitor();
when(mTelephony.getDataNetworkType()).thenReturn(TelephonyManager.NETWORK_TYPE_LTE);
when(mTelephony.getNetworkOperator()).thenReturn(TEST_MCCMNC);
@@ -578,14 +618,11 @@
setSslException(mHttpsConnection);
setStatus(mHttpConnection, 204);
- final NetworkMonitor nm = makeMonitor();
- nm.notifyNetworkConnected();
- verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
- .notifyNetworkTested(NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY, null);
+ final NetworkMonitor nm = runNetworkTest(NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY);
nm.setAcceptPartialConnectivity();
verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
- .notifyNetworkTested(NETWORK_TEST_RESULT_VALID, null);
+ .notifyNetworkTested(eq(NETWORK_TEST_RESULT_VALID), any());
}
@Test
@@ -593,12 +630,12 @@
setStatus(mHttpsConnection, 500);
setStatus(mHttpConnection, 204);
setStatus(mFallbackConnection, 500);
- assertPartialConnectivity(makeMonitor().isCaptivePortal());
+ runPartialConnectivityNetworkTest();
setStatus(mHttpsConnection, 500);
setStatus(mHttpConnection, 500);
setStatus(mFallbackConnection, 204);
- assertPartialConnectivity(makeMonitor().isCaptivePortal());
+ runPartialConnectivityNetworkTest();
}
private void makeDnsTimeoutEvent(WrappedNetworkMonitor wrappedMonitor, int count) {
@@ -620,24 +657,23 @@
}
private void setDataStallEvaluationType(int type) {
- when(mDependencies.getSetting(any(),
- eq(Settings.Global.DATA_STALL_EVALUATION_TYPE), anyInt())).thenReturn(type);
+ when(mDependencies.getDeviceConfigPropertyInt(any(),
+ eq(CONFIG_DATA_STALL_EVALUATION_TYPE), anyInt())).thenReturn(type);
}
private void setMinDataStallEvaluateInterval(int time) {
- when(mDependencies.getSetting(any(),
- eq(Settings.Global.DATA_STALL_MIN_EVALUATE_INTERVAL), anyInt())).thenReturn(time);
+ when(mDependencies.getDeviceConfigPropertyInt(any(),
+ eq(CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL), anyInt())).thenReturn(time);
}
private void setValidDataStallDnsTimeThreshold(int time) {
- when(mDependencies.getSetting(any(),
- eq(Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD), anyInt())).thenReturn(time);
+ when(mDependencies.getDeviceConfigPropertyInt(any(),
+ eq(CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD), anyInt())).thenReturn(time);
}
private void setConsecutiveDnsTimeoutThreshold(int num) {
- when(mDependencies.getSetting(any(),
- eq(Settings.Global.DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD), anyInt()))
- .thenReturn(num);
+ when(mDependencies.getDeviceConfigPropertyInt(any(),
+ eq(CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD), anyInt())).thenReturn(num);
}
private void setFallbackUrl(String url) {
@@ -660,26 +696,46 @@
eq(Settings.Global.CAPTIVE_PORTAL_MODE), anyInt())).thenReturn(mode);
}
- private void assertPortal(CaptivePortalProbeResult result) {
- assertTrue(result.isPortal());
- assertFalse(result.isFailed());
- assertFalse(result.isSuccessful());
+ private void runPortalNetworkTest() {
+ runNetworkTest(NETWORK_TEST_RESULT_INVALID);
+ assertEquals(1, mRegisteredReceivers.size());
+ assertNotNull(mNetworkTestedRedirectUrlCaptor.getValue());
}
- private void assertNotPortal(CaptivePortalProbeResult result) {
- assertFalse(result.isPortal());
- assertFalse(result.isFailed());
- assertTrue(result.isSuccessful());
+ private void runNotPortalNetworkTest() {
+ runNetworkTest(NETWORK_TEST_RESULT_VALID);
+ assertEquals(0, mRegisteredReceivers.size());
+ assertNull(mNetworkTestedRedirectUrlCaptor.getValue());
}
- private void assertFailed(CaptivePortalProbeResult result) {
- assertFalse(result.isPortal());
- assertTrue(result.isFailed());
- assertFalse(result.isSuccessful());
+ private void runFailedNetworkTest() {
+ runNetworkTest(NETWORK_TEST_RESULT_INVALID);
+ assertEquals(0, mRegisteredReceivers.size());
+ assertNull(mNetworkTestedRedirectUrlCaptor.getValue());
}
- private void assertPartialConnectivity(CaptivePortalProbeResult result) {
- assertTrue(result.isPartialConnectivity());
+ private void runPartialConnectivityNetworkTest() {
+ runNetworkTest(NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY);
+ assertEquals(0, mRegisteredReceivers.size());
+ assertNull(mNetworkTestedRedirectUrlCaptor.getValue());
+ }
+
+ private NetworkMonitor runNetworkTest(int testResult) {
+ return runNetworkTest(METERED_CAPABILITIES, testResult);
+ }
+
+ private NetworkMonitor runNetworkTest(NetworkCapabilities nc, int testResult) {
+ final NetworkMonitor monitor = makeMonitor();
+ monitor.notifyNetworkConnected(TEST_LINK_PROPERTIES, nc);
+ try {
+ verify(mCallbacks, timeout(HANDLER_TIMEOUT_MS).times(1))
+ .notifyNetworkTested(eq(testResult), mNetworkTestedRedirectUrlCaptor.capture());
+ } catch (RemoteException e) {
+ fail("Unexpected exception: " + e);
+ }
+ waitForIdle(monitor.getHandler());
+
+ return monitor;
}
private void setSslException(HttpURLConnection connection) throws IOException {
diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
index d0e58b8..94cc589 100644
--- a/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/ipmemorystore/IpMemoryStoreServiceTest.java
@@ -16,6 +16,8 @@
package com.android.server.connectivity.ipmemorystore;
+import static com.android.server.connectivity.ipmemorystore.RegularMaintenanceJobService.InterruptMaintenance;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
@@ -24,6 +26,7 @@
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
+import android.app.job.JobScheduler;
import android.content.Context;
import android.net.ipmemorystore.Blob;
import android.net.ipmemorystore.IOnBlobRetrievedListener;
@@ -37,6 +40,7 @@
import android.net.ipmemorystore.SameL3NetworkResponseParcelable;
import android.net.ipmemorystore.Status;
import android.net.ipmemorystore.StatusParcelable;
+import android.os.ConditionVariable;
import android.os.IBinder;
import android.os.RemoteException;
@@ -69,6 +73,9 @@
private static final String TEST_CLIENT_ID = "testClientId";
private static final String TEST_DATA_NAME = "testData";
+ private static final int TEST_DATABASE_SIZE_THRESHOLD = 100 * 1024; //100KB
+ private static final int DEFAULT_TIMEOUT_MS = 5000;
+ private static final int LONG_TIMEOUT_MS = 30000;
private static final int FAKE_KEY_COUNT = 20;
private static final String[] FAKE_KEYS;
static {
@@ -80,6 +87,8 @@
@Mock
private Context mMockContext;
+ @Mock
+ private JobScheduler mMockJobScheduler;
private File mDbFile;
private IpMemoryStoreService mService;
@@ -91,7 +100,22 @@
final File dir = context.getFilesDir();
mDbFile = new File(dir, "test.db");
doReturn(mDbFile).when(mMockContext).getDatabasePath(anyString());
- mService = new IpMemoryStoreService(mMockContext);
+ doReturn(mMockJobScheduler).when(mMockContext)
+ .getSystemService(Context.JOB_SCHEDULER_SERVICE);
+ mService = new IpMemoryStoreService(mMockContext) {
+ @Override
+ protected int getDbSizeThreshold() {
+ return TEST_DATABASE_SIZE_THRESHOLD;
+ }
+
+ @Override
+ boolean isDbSizeOverThreshold() {
+ // Add a 100ms delay here for pausing maintenance job a while. Interrupted flag can
+ // be set at this time.
+ waitForMs(100);
+ return super.isDbSizeOverThreshold();
+ }
+ };
}
@After
@@ -200,10 +224,15 @@
// Helper method to factorize some boilerplate
private void doLatched(final String timeoutMessage, final Consumer<CountDownLatch> functor) {
+ doLatched(timeoutMessage, functor, DEFAULT_TIMEOUT_MS);
+ }
+
+ private void doLatched(final String timeoutMessage, final Consumer<CountDownLatch> functor,
+ final int timeout) {
final CountDownLatch latch = new CountDownLatch(1);
functor.accept(latch);
try {
- if (!latch.await(5000, TimeUnit.MILLISECONDS)) {
+ if (!latch.await(timeout, TimeUnit.MILLISECONDS)) {
fail(timeoutMessage);
}
} catch (InterruptedException e) {
@@ -224,10 +253,51 @@
})));
}
+ /** Insert large data that db size will be over threshold for maintenance test usage. */
+ private void insertFakeDataAndOverThreshold() {
+ try {
+ final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
+ na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
+ na.setGroupHint("hint1");
+ na.setMtu(219);
+ na.setDnsAddresses(Arrays.asList(Inet6Address.getByName("0A1C:2E40:480A::1CA6")));
+ final byte[] data = new byte[]{-3, 6, 8, -9, 12, -128, 0, 89, 112, 91, -34};
+ final long time = System.currentTimeMillis() - 1;
+ for (int i = 0; i < 1000; i++) {
+ int errorCode = IpMemoryStoreDatabase.storeNetworkAttributes(
+ mService.mDb,
+ "fakeKey" + i,
+ // Let first 100 records get expiry.
+ i < 100 ? time : time + TimeUnit.HOURS.toMillis(i),
+ na.build());
+ assertEquals(errorCode, Status.SUCCESS);
+
+ errorCode = IpMemoryStoreDatabase.storeBlob(
+ mService.mDb, "fakeKey" + i, TEST_CLIENT_ID, TEST_DATA_NAME, data);
+ assertEquals(errorCode, Status.SUCCESS);
+ }
+
+ // After added 5000 records, db size is larger than fake threshold(100KB).
+ assertTrue(mService.isDbSizeOverThreshold());
+ } catch (final UnknownHostException e) {
+ fail("Insert fake data fail");
+ }
+ }
+
+ /** Wait for assigned time. */
+ private void waitForMs(long ms) {
+ try {
+ Thread.sleep(ms);
+ } catch (final InterruptedException e) {
+ fail("Thread was interrupted");
+ }
+ }
+
@Test
public void testNetworkAttributes() throws UnknownHostException {
final NetworkAttributes.Builder na = new NetworkAttributes.Builder();
na.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
+ na.setAssignedV4AddressExpiry(System.currentTimeMillis() + 7_200_000);
na.setGroupHint("hint1");
na.setMtu(219);
final String l2Key = FAKE_KEYS[0];
@@ -257,6 +327,8 @@
+ status.resultCode, status.isSuccess());
assertEquals(l2Key, key);
assertEquals(attributes.assignedV4Address, attr.assignedV4Address);
+ assertEquals(attributes.assignedV4AddressExpiry,
+ attr.assignedV4AddressExpiry);
assertEquals(attributes.groupHint, attr.groupHint);
assertEquals(attributes.mtu, attr.mtu);
assertEquals(attributes2.dnsAddresses, attr.dnsAddresses);
@@ -278,7 +350,7 @@
// Verify that this test does not miss any new field added later.
// If any field is added to NetworkAttributes it must be tested here for storing
// and retrieving.
- assertEquals(4, Arrays.stream(NetworkAttributes.class.getDeclaredFields())
+ assertEquals(5, Arrays.stream(NetworkAttributes.class.getDeclaredFields())
.filter(f -> !Modifier.isStatic(f.getModifiers())).count());
}
@@ -341,7 +413,7 @@
status.isSuccess());
assertEquals(l2Key, key);
assertEquals(name, TEST_DATA_NAME);
- Arrays.equals(b.data, data);
+ assertTrue(Arrays.equals(b.data, data));
latch.countDown();
})));
@@ -503,4 +575,64 @@
latch.countDown();
})));
}
+
+
+ @Test
+ public void testFullMaintenance() {
+ insertFakeDataAndOverThreshold();
+
+ final InterruptMaintenance im = new InterruptMaintenance(0/* Fake JobId */);
+ // Do full maintenance and then db size should go down and meet the threshold.
+ doLatched("Maintenance unexpectedly completed successfully", latch ->
+ mService.fullMaintenance(onStatus((status) -> {
+ assertTrue("Execute full maintenance failed: "
+ + status.resultCode, status.isSuccess());
+ latch.countDown();
+ }), im), LONG_TIMEOUT_MS);
+
+ // Assume that maintenance is successful, db size shall meet the threshold.
+ assertFalse(mService.isDbSizeOverThreshold());
+ }
+
+ @Test
+ public void testInterruptMaintenance() {
+ insertFakeDataAndOverThreshold();
+
+ final InterruptMaintenance im = new InterruptMaintenance(0/* Fake JobId */);
+
+ // Test interruption immediately.
+ im.setInterrupted(true);
+ // Do full maintenance and the expectation is not completed by interruption.
+ doLatched("Maintenance unexpectedly completed successfully", latch ->
+ mService.fullMaintenance(onStatus((status) -> {
+ assertFalse(status.isSuccess());
+ latch.countDown();
+ }), im), LONG_TIMEOUT_MS);
+
+ // Assume that no data are removed, db size shall be over the threshold.
+ assertTrue(mService.isDbSizeOverThreshold());
+
+ // Reset the flag and test interruption during maintenance.
+ im.setInterrupted(false);
+
+ final ConditionVariable latch = new ConditionVariable();
+ // Do full maintenance and the expectation is not completed by interruption.
+ mService.fullMaintenance(onStatus((status) -> {
+ assertFalse(status.isSuccess());
+ latch.open();
+ }), im);
+
+ // Give a little bit of time for maintenance to start up for realism
+ waitForMs(50);
+ // Interrupt maintenance job.
+ im.setInterrupted(true);
+
+ if (!latch.block(LONG_TIMEOUT_MS)) {
+ fail("Maintenance unexpectedly completed successfully");
+ }
+
+ // Assume that only do dropAllExpiredRecords method in previous maintenance, db size shall
+ // still be over the threshold.
+ assertTrue(mService.isDbSizeOverThreshold());
+ }
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 960d305..b389e04 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -70,7 +70,6 @@
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.ByteStringUtils;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -83,6 +82,8 @@
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
+import libcore.util.HexEncoding;
+
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
@@ -96,7 +97,6 @@
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
-import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
@@ -2144,7 +2144,7 @@
rand.nextBytes(keyBytes);
// Convert to string for storage in settings table.
- final String userKey = ByteStringUtils.toHexString(keyBytes);
+ final String userKey = HexEncoding.encodeToString(keyBytes, true /* upperCase */);
// Store the key in the ssaid table.
final SettingsState ssaidSettings = getSettingsLocked(SETTINGS_TYPE_SSAID, userId);
@@ -2174,13 +2174,16 @@
}
}
final String userKey = userKeySetting.getValue();
+ if (userKey == null || userKey.length() % 2 != 0) {
+ throw new IllegalStateException("User key invalid");
+ }
// Convert the user's key back to a byte array.
- final byte[] keyBytes = ByteStringUtils.fromHexToByteArray(userKey);
+ final byte[] keyBytes = HexEncoding.decode(userKey);
// Validate that the key is of expected length.
// Keys are currently 32 bytes, but were once 16 bytes during Android O development.
- if (keyBytes == null || (keyBytes.length != 16 && keyBytes.length != 32)) {
+ if (keyBytes.length != 16 && keyBytes.length != 32) {
throw new IllegalStateException("User key invalid");
}
@@ -2202,8 +2205,8 @@
}
// Convert result to a string for storage in settings table. Only want first 64 bits.
- final String ssaid = ByteStringUtils.toHexString(m.doFinal()).substring(0, 16)
- .toLowerCase(Locale.US);
+ final String ssaid = HexEncoding.encodeToString(m.doFinal(), false /* upperCase */)
+ .substring(0, 16);
// Save the ssaid in the ssaid table.
final String uid = Integer.toString(callingPkg.applicationInfo.uid);
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 8778e30..8428797 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -118,6 +118,8 @@
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS" />
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
+ <!-- Shell only holds android.permission.NETWORK_SCAN in order to to enable CTS testing -->
+ <uses-permission android:name="android.permission.NETWORK_SCAN" />
<uses-permission android:name="android.permission.REGISTER_CALL_PROVIDER" />
<uses-permission android:name="android.permission.REGISTER_CONNECTION_MANAGER" />
<uses-permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION" />
@@ -164,6 +166,9 @@
<!-- Permission needed to test tcp keepalive offload. -->
<uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
+ <!-- Permission required to test ContentResolver caching. -->
+ <uses-permission android:name="android.permission.CACHE_CONTENT" />
+
<application android:label="@string/app_label"
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true">
diff --git a/services/backup/java/com/android/server/backup/utils/PasswordUtils.java b/services/backup/java/com/android/server/backup/utils/PasswordUtils.java
index a7eb644..0a7e551 100644
--- a/services/backup/java/com/android/server/backup/utils/PasswordUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/PasswordUtils.java
@@ -20,6 +20,8 @@
import android.util.Slog;
+import libcore.util.HexEncoding;
+
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
@@ -74,11 +76,7 @@
* Creates hex string representation of the byte array.
*/
public static String byteArrayToHex(byte[] data) {
- StringBuilder buf = new StringBuilder(data.length * 2);
- for (int i = 0; i < data.length; i++) {
- buf.append(Byte.toHexString(data[i], true));
- }
- return buf.toString();
+ return HexEncoding.encodeToString(data, true);
}
/**
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index f79a51b..47b646c 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -48,6 +48,7 @@
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
@@ -1288,9 +1289,13 @@
// because kernel doesn't keep this after reboot
setTimeZoneImpl(SystemProperties.get(TIMEZONE_PROPERTY));
- // Also sure that we're booting with a halfway sensible current time
if (mNativeData != 0) {
- final long systemBuildTime = Environment.getRootDirectory().lastModified();
+ // Ensure that we're booting with a halfway sensible current time. Use the
+ // most recent of Build.TIME, the root file system's timestamp, and the
+ // value of the ro.build.date.utc system property (which is in seconds).
+ final long systemBuildTime = Long.max(
+ 1000L * SystemProperties.getLong("ro.build.date.utc", -1L),
+ Long.max(Environment.getRootDirectory().lastModified(), Build.TIME));
if (System.currentTimeMillis() < systemBuildTime) {
Slog.i(TAG, "Current time only " + System.currentTimeMillis()
+ ", advancing to build time " + systemBuildTime);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 699cf60..c1aff75 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -47,6 +47,7 @@
import static com.android.internal.util.Preconditions.checkNotNull;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.BroadcastOptions;
import android.app.NotificationManager;
@@ -108,7 +109,6 @@
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.NetworkEvent;
import android.net.netlink.InetDiagMessage;
-import android.net.shared.NetworkMonitorUtils;
import android.net.shared.PrivateDnsConfig;
import android.net.util.MultinetworkPolicyTracker;
import android.net.util.NetdService;
@@ -133,6 +133,7 @@
import android.os.ShellCallback;
import android.os.ShellCommand;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -237,6 +238,16 @@
private static final boolean LOGD_BLOCKED_NETWORKINFO = true;
+ /**
+ * Default URL to use for {@link #getCaptivePortalServerUrl()}. This should not be changed
+ * by OEMs for configuration purposes, as this value is overridden by
+ * Settings.Global.CAPTIVE_PORTAL_HTTP_URL.
+ * R.string.config_networkCaptivePortalServerUrl should be overridden instead for this purpose
+ * (preferably via runtime resource overlays).
+ */
+ private static final String DEFAULT_CAPTIVE_PORTAL_HTTP_URL =
+ "http://connectivitycheck.gstatic.com/generate_204";
+
// TODO: create better separation between radio types and network types
// how long to wait before switching back to a radio's default network
@@ -266,7 +277,8 @@
private Tethering mTethering;
- private final PermissionMonitor mPermissionMonitor;
+ @VisibleForTesting
+ protected final PermissionMonitor mPermissionMonitor;
private KeyStore mKeyStore;
@@ -819,13 +831,13 @@
public ConnectivityService(Context context, INetworkManagementService netManager,
INetworkStatsService statsService, INetworkPolicyManager policyManager) {
this(context, netManager, statsService, policyManager,
- getDnsResolver(), new IpConnectivityLog());
+ getDnsResolver(), new IpConnectivityLog(), NetdService.getInstance());
}
@VisibleForTesting
protected ConnectivityService(Context context, INetworkManagementService netManager,
INetworkStatsService statsService, INetworkPolicyManager policyManager,
- IDnsResolver dnsresolver, IpConnectivityLog logger) {
+ IDnsResolver dnsresolver, IpConnectivityLog logger, INetd netd) {
if (DBG) log("ConnectivityService starting up");
mSystemProperties = getSystemProperties();
@@ -865,7 +877,7 @@
mDnsResolver = checkNotNull(dnsresolver, "missing IDnsResolver");
mProxyTracker = makeProxyTracker();
- mNetd = NetdService.getInstance();
+ mNetd = netd;
mKeyStore = KeyStore.getInstance();
mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
@@ -951,7 +963,7 @@
mTethering = makeTethering();
- mPermissionMonitor = new PermissionMonitor(mContext, mNMS);
+ mPermissionMonitor = new PermissionMonitor(mContext, mNetd);
// Set up the listener for user state for creating user VPNs.
// Should run on mHandler to avoid any races.
@@ -1628,8 +1640,11 @@
*/
private boolean disallowedBecauseSystemCaller() {
// TODO: start throwing a SecurityException when GnssLocationProvider stops calling
- // requestRouteToHost.
- if (isSystem(Binder.getCallingUid())) {
+ // requestRouteToHost. In Q, GnssLocationProvider is changed to not call requestRouteToHost
+ // for devices launched with Q and above. However, existing devices upgrading to Q and
+ // above must continued to be supported for few more releases.
+ if (isSystem(Binder.getCallingUid()) && SystemProperties.getInt(
+ "ro.product.first_api_level", 0) > Build.VERSION_CODES.P) {
log("This method exists only for app backwards compatibility"
+ " and must not be called by system services.");
return true;
@@ -1761,17 +1776,12 @@
// the caller thread of registerNetworkAgent. Thus, it's not allowed to register netd
// event callback for certain nai. e.g. cellular. Register here to pass to
// NetworkMonitor instead.
- // TODO: Move the Dns Event to NetworkMonitor. Use Binder.clearCallingIdentity() in
- // registerNetworkAgent to have NetworkMonitor created with system process as design
- // expectation. Also, NetdEventListenerService only allow one callback from each
- // caller type. Need to re-factor NetdEventListenerService to allow multiple
- // NetworkMonitor registrants.
+ // TODO: Move the Dns Event to NetworkMonitor. NetdEventListenerService only allow one
+ // callback from each caller type. Need to re-factor NetdEventListenerService to allow
+ // multiple NetworkMonitor registrants.
if (nai != null && nai.satisfies(mDefaultRequest)) {
- try {
- nai.networkMonitor().notifyDnsResponse(returnCode);
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
+ Binder.withCleanCallingIdentity(() ->
+ nai.networkMonitor().notifyDnsResponse(returnCode));
}
}
@@ -1892,6 +1902,15 @@
return false;
}
+ private boolean checkAnyPermissionOf(int pid, int uid, String... permissions) {
+ for (String permission : permissions) {
+ if (mContext.checkPermission(permission, pid, uid) == PERMISSION_GRANTED) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private void enforceAnyPermissionOf(String... permissions) {
if (!checkAnyPermissionOf(permissions)) {
throw new SecurityException("Requires one of the following permissions: "
@@ -1966,6 +1985,12 @@
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
}
+ private boolean checkNetworkSignalStrengthWakeupPermission(int pid, int uid) {
+ return checkAnyPermissionOf(pid, uid,
+ android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
+ }
+
private void enforceConnectivityRestrictedNetworksPermission() {
try {
mContext.enforceCallingOrSelfPermission(
@@ -2418,6 +2443,13 @@
pw.println("NetworkStackClient logs:");
pw.increaseIndent();
NetworkStackClient.getInstance().dump(pw);
+ pw.decreaseIndent();
+
+ pw.println();
+ pw.println("Permission Monitor:");
+ pw.increaseIndent();
+ mPermissionMonitor.dump(pw);
+ pw.decreaseIndent();
}
private void dumpNetworks(IndentingPrintWriter pw) {
@@ -3738,16 +3770,6 @@
break;
}
case EVENT_SYSTEM_READY: {
- for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
- // Might have been called already in handleRegisterNetworkAgent since
- // mSystemReady is set before sending EVENT_SYSTEM_READY, but calling
- // this several times is fine.
- try {
- nai.networkMonitor().notifySystemReady();
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
- }
mMultipathPolicyTracker.start();
break;
}
@@ -4969,13 +4991,19 @@
}
}
- // This checks that the passed capabilities either do not request a specific SSID, or the
- // calling app has permission to do so.
+ // This checks that the passed capabilities either do not request a specific SSID/SignalStrength
+ // , or the calling app has permission to do so.
private void ensureSufficientPermissionsForRequest(NetworkCapabilities nc,
int callerPid, int callerUid) {
if (null != nc.getSSID() && !checkSettingsPermission(callerPid, callerUid)) {
throw new SecurityException("Insufficient permissions to request a specific SSID");
}
+
+ if (nc.hasSignalStrength()
+ && !checkNetworkSignalStrengthWakeupPermission(callerPid, callerUid)) {
+ throw new SecurityException(
+ "Insufficient permissions to request a specific signal strength");
+ }
}
private ArrayList<Integer> getSignalStrengthThresholds(NetworkAgentInfo nai) {
@@ -5392,7 +5420,7 @@
mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, mDnsResolver,
mNMS, factorySerialNumber);
// Make sure the network capabilities reflect what the agent info says.
- nai.networkCapabilities = mixInCapabilities(nai, nc);
+ nai.setNetworkCapabilities(mixInCapabilities(nai, nc));
final String extraInfo = networkInfo.getExtraInfo();
final String name = TextUtils.isEmpty(extraInfo)
? nai.networkCapabilities.getSSID() : extraInfo;
@@ -5423,15 +5451,6 @@
synchronized (mNetworkForNetId) {
mNetworkForNetId.put(nai.network.netId, nai);
}
- synchronized (this) {
- if (mSystemReady) {
- try {
- networkMonitor.notifySystemReady();
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
- }
- }
try {
networkMonitor.start();
@@ -5455,6 +5474,11 @@
networkAgent.clatd.fixupLinkProperties(oldLp, newLp);
updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities);
+
+ // update filtering rules, need to happen after the interface update so netd knows about the
+ // new interface (the interface name -> index map becomes initialized)
+ updateVpnFiltering(newLp, oldLp, networkAgent);
+
updateMtu(newLp, oldLp);
// TODO - figure out what to do for clat
// for (LinkProperties lp : newLp.getStackedLinks()) {
@@ -5485,12 +5509,12 @@
// Start or stop DNS64 detection and 464xlat according to network state.
networkAgent.clatd.update();
notifyIfacesChangedForNetworkStats();
+ try {
+ networkAgent.networkMonitor().notifyLinkPropertiesChanged(newLp);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
if (networkAgent.everConnected) {
- try {
- networkAgent.networkMonitor().notifyLinkPropertiesChanged();
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
}
}
@@ -5620,6 +5644,37 @@
}
}
+ private void updateVpnFiltering(LinkProperties newLp, LinkProperties oldLp,
+ NetworkAgentInfo nai) {
+ final String oldIface = oldLp != null ? oldLp.getInterfaceName() : null;
+ final String newIface = newLp != null ? newLp.getInterfaceName() : null;
+ final boolean wasFiltering = requiresVpnIsolation(nai, nai.networkCapabilities, oldLp);
+ final boolean needsFiltering = requiresVpnIsolation(nai, nai.networkCapabilities, newLp);
+
+ if (!wasFiltering && !needsFiltering) {
+ // Nothing to do.
+ return;
+ }
+
+ if (Objects.equals(oldIface, newIface) && (wasFiltering == needsFiltering)) {
+ // Nothing changed.
+ return;
+ }
+
+ final Set<UidRange> ranges = nai.networkCapabilities.getUids();
+ final int vpnAppUid = nai.networkCapabilities.getEstablishingVpnAppUid();
+ // TODO: this create a window of opportunity for apps to receive traffic between the time
+ // when the old rules are removed and the time when new rules are added. To fix this,
+ // make eBPF support two whitelisted interfaces so here new rules can be added before the
+ // old rules are being removed.
+ if (wasFiltering) {
+ mPermissionMonitor.onVpnUidRangesRemoved(oldIface, ranges, vpnAppUid);
+ }
+ if (needsFiltering) {
+ mPermissionMonitor.onVpnUidRangesAdded(newIface, ranges, vpnAppUid);
+ }
+ }
+
private int getNetworkPermission(NetworkCapabilities nc) {
if (!nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) {
return INetd.PERMISSION_SYSTEM;
@@ -5718,7 +5773,7 @@
final NetworkCapabilities prevNc;
synchronized (nai) {
prevNc = nai.networkCapabilities;
- nai.networkCapabilities = newNc;
+ nai.setNetworkCapabilities(newNc);
}
updateUids(nai, prevNc, newNc);
@@ -5733,11 +5788,6 @@
// If the requestable capabilities have changed or the score changed, we can't have been
// called by rematchNetworkAndRequests, so it's safe to start a rematch.
rematchAllNetworksAndRequests(nai, oldScore);
- try {
- nai.networkMonitor().notifyNetworkCapabilitiesChanged();
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
}
@@ -5767,6 +5817,34 @@
}
}
+ /**
+ * Returns whether VPN isolation (ingress interface filtering) should be applied on the given
+ * network.
+ *
+ * Ingress interface filtering enforces that all apps under the given network can only receive
+ * packets from the network's interface (and loopback). This is important for VPNs because
+ * apps that cannot bypass a fully-routed VPN shouldn't be able to receive packets from any
+ * non-VPN interfaces.
+ *
+ * As a result, this method should return true iff
+ * 1. the network is an app VPN (not legacy VPN)
+ * 2. the VPN does not allow bypass
+ * 3. the VPN is fully-routed
+ * 4. the VPN interface is non-null
+ *
+ * @See INetd#firewallAddUidInterfaceRules
+ * @See INetd#firewallRemoveUidInterfaceRules
+ */
+ private boolean requiresVpnIsolation(@NonNull NetworkAgentInfo nai, NetworkCapabilities nc,
+ LinkProperties lp) {
+ if (nc == null || lp == null) return false;
+ return nai.isVPN()
+ && !nai.networkMisc.allowBypass
+ && nc.getEstablishingVpnAppUid() != Process.SYSTEM_UID
+ && lp.getInterfaceName() != null
+ && (lp.hasIPv4DefaultRoute() || lp.hasIPv6DefaultRoute());
+ }
+
private void updateUids(NetworkAgentInfo nai, NetworkCapabilities prevNc,
NetworkCapabilities newNc) {
Set<UidRange> prevRanges = null == prevNc ? null : prevNc.getUids();
@@ -5779,6 +5857,12 @@
newRanges.removeAll(prevRangesCopy);
try {
+ // When updating the VPN uid routing rules, add the new range first then remove the old
+ // range. If old range were removed first, there would be a window between the old
+ // range being removed and the new range being added, during which UIDs contained
+ // in both ranges are not subject to any VPN routing rules. Adding new range before
+ // removing old range works because, unlike the filtering rules below, it's possible to
+ // add duplicate UID routing rules.
if (!newRanges.isEmpty()) {
final UidRange[] addedRangesArray = new UidRange[newRanges.size()];
newRanges.toArray(addedRangesArray);
@@ -5789,9 +5873,31 @@
prevRanges.toArray(removedRangesArray);
mNMS.removeVpnUidRanges(nai.network.netId, removedRangesArray);
}
+ final boolean wasFiltering = requiresVpnIsolation(nai, prevNc, nai.linkProperties);
+ final boolean shouldFilter = requiresVpnIsolation(nai, newNc, nai.linkProperties);
+ final String iface = nai.linkProperties.getInterfaceName();
+ // For VPN uid interface filtering, old ranges need to be removed before new ranges can
+ // be added, due to the range being expanded and stored as invidiual UIDs. For example
+ // the UIDs might be updated from [0, 99999] to ([0, 10012], [10014, 99999]) which means
+ // prevRanges = [0, 99999] while newRanges = [0, 10012], [10014, 99999]. If prevRanges
+ // were added first and then newRanges got removed later, there would be only one uid
+ // 10013 left. A consequence of removing old ranges before adding new ranges is that
+ // there is now a window of opportunity when the UIDs are not subject to any filtering.
+ // Note that this is in contrast with the (more robust) update of VPN routing rules
+ // above, where the addition of new ranges happens before the removal of old ranges.
+ // TODO Fix this window by computing an accurate diff on Set<UidRange>, so the old range
+ // to be removed will never overlap with the new range to be added.
+ if (wasFiltering && !prevRanges.isEmpty()) {
+ mPermissionMonitor.onVpnUidRangesRemoved(iface, prevRanges,
+ prevNc.getEstablishingVpnAppUid());
+ }
+ if (shouldFilter && !newRanges.isEmpty()) {
+ mPermissionMonitor.onVpnUidRangesAdded(iface, newRanges,
+ newNc.getEstablishingVpnAppUid());
+ }
} catch (Exception e) {
// Never crash!
- loge("Exception in updateUids: " + e);
+ loge("Exception in updateUids: ", e);
}
}
@@ -5996,11 +6102,6 @@
}
if (capabilitiesChanged) {
- try {
- nai.networkMonitor().notifyNetworkCapabilitiesChanged();
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
}
@@ -6397,6 +6498,11 @@
Slog.wtf(TAG, networkAgent.name() + " connected with null LinkProperties");
}
+ // NetworkCapabilities need to be set before sending the private DNS config to
+ // NetworkMonitor, otherwise NetworkMonitor cannot determine if validation is required.
+ synchronized (networkAgent) {
+ networkAgent.setNetworkCapabilities(networkAgent.networkCapabilities);
+ }
handlePerNetworkPrivateDnsConfig(networkAgent, mDnsManager.getPrivateDnsConfig());
updateLinkProperties(networkAgent, new LinkProperties(networkAgent.linkProperties),
null);
@@ -6409,7 +6515,8 @@
if (networkAgent.networkMisc.acceptPartialConnectivity) {
networkAgent.networkMonitor().setAcceptPartialConnectivity();
}
- networkAgent.networkMonitor().notifyNetworkConnected();
+ networkAgent.networkMonitor().notifyNetworkConnected(
+ networkAgent.linkProperties, networkAgent.networkCapabilities);
} catch (RemoteException e) {
e.rethrowFromSystemServer();
}
@@ -6551,7 +6658,7 @@
uid, newRules, metered, mRestrictBackground);
}
if (oldBlocked == newBlocked) {
- return;
+ continue;
}
final int arg = encodeBool(newBlocked);
for (int i = 0; i < nai.numNetworkRequests(); i++) {
@@ -6709,9 +6816,20 @@
@Override
public String getCaptivePortalServerUrl() {
enforceConnectivityInternalPermission();
- final String defaultUrl = mContext.getResources().getString(
- R.string.config_networkDefaultCaptivePortalServerUrl);
- return NetworkMonitorUtils.getCaptivePortalServerHttpUrl(mContext, defaultUrl);
+ String settingUrl = mContext.getResources().getString(
+ R.string.config_networkCaptivePortalServerUrl);
+
+ if (!TextUtils.isEmpty(settingUrl)) {
+ return settingUrl;
+ }
+
+ settingUrl = Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.CAPTIVE_PORTAL_HTTP_URL);
+ if (!TextUtils.isEmpty(settingUrl)) {
+ return settingUrl;
+ }
+
+ return DEFAULT_CAPTIVE_PORTAL_HTTP_URL;
}
@Override
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 126bf65..2055b64 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -96,9 +96,10 @@
new int[] {OsConstants.AF_INET, OsConstants.AF_INET6};
private static final int NETD_FETCH_TIMEOUT_MS = 5000; // ms
- private static final int MAX_PORT_BIND_ATTEMPTS = 10;
private static final InetAddress INADDR_ANY;
+ @VisibleForTesting static final int MAX_PORT_BIND_ATTEMPTS = 10;
+
static {
try {
INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0});
@@ -207,6 +208,7 @@
mBinder.linkToDeath(this, 0);
} catch (RemoteException e) {
binderDied();
+ e.rethrowFromSystemServer();
}
}
}
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 0a91721..1ff50b2 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -88,10 +88,10 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
-import com.android.internal.net.NetworkStatsFactory;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.HexDump;
import com.android.internal.util.Preconditions;
+import com.android.server.net.NetworkStatsFactory;
import com.google.android.collect.Maps;
@@ -725,6 +725,11 @@
ActivityManager.getService().notifyCleartextNetwork(uid,
HexDump.hexStringToByteArray(hex));
}
+
+ @Override
+ public int getInterfaceVersion() {
+ return INetdUnsolicitedEventListener.VERSION;
+ }
}
//
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 7a8d23a..85787f2 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -248,6 +248,8 @@
private final LocalLog mLocalLog = new LocalLog(100);
+ private final LocalLog mListenLog = new LocalLog(100);
+
private PreciseDataConnectionState mPreciseDataConnectionState =
new PreciseDataConnectionState();
@@ -305,6 +307,8 @@
}
mDefaultSubId = newDefaultSubId;
mDefaultPhoneId = newDefaultPhoneId;
+ mLocalLog.log("Default subscription updated: mDefaultPhoneId="
+ + mDefaultPhoneId + ", mDefaultSubId" + mDefaultSubId);
}
}
}
@@ -598,10 +602,12 @@
boolean notifyNow, int subId) {
int callerUserId = UserHandle.getCallingUserId();
mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
- if (VDBG) {
- log("listen: E pkg=" + callingPackage + " events=0x" + Integer.toHexString(events)
+ String str = "listen: E pkg=" + callingPackage + " events=0x" + Integer.toHexString(events)
+ " notifyNow=" + notifyNow + " subId=" + subId + " myUserId="
- + UserHandle.myUserId() + " callerUserId=" + callerUserId);
+ + UserHandle.myUserId() + " callerUserId=" + callerUserId;
+ mListenLog.log(str);
+ if (VDBG) {
+ log(str);
}
if (events != PhoneStateListener.LISTEN_NONE) {
@@ -1399,8 +1405,10 @@
if (PhoneConstants.APN_TYPE_DEFAULT.equals(apnType)
&& (mDataConnectionState[phoneId] != state
|| mDataConnectionNetworkType[phoneId] != networkType)) {
- String str = "onDataConnectionStateChanged(" + state
- + ", " + networkType + ")";
+ String str = "onDataConnectionStateChanged("
+ + TelephonyManager.dataStateToString(state)
+ + ", " + TelephonyManager.getNetworkTypeName(networkType)
+ + ") subId=" + subId + ", phoneId=" + phoneId;
log(str);
mLocalLog.log(str);
for (Record r : mRecords) {
@@ -1916,12 +1924,16 @@
pw.println("mEmergencyNumberList=" + mEmergencyNumberList);
pw.println("mCallQuality=" + mCallQuality);
pw.println("mCallAttributes=" + mCallAttributes);
+ pw.println("mDefaultPhoneId" + mDefaultPhoneId);
+ pw.println("mDefaultSubId" + mDefaultSubId);
pw.decreaseIndent();
pw.println("local logs:");
pw.increaseIndent();
mLocalLog.dump(fd, pw, args);
+ pw.println("listen logs:");
+ mListenLog.dump(fd, pw, args);
pw.decreaseIndent();
pw.println("registrations: count=" + recordCount);
pw.increaseIndent();
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index e64ab78..40bf7bc 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -60,6 +60,7 @@
@NonNull private static final String TAG = TestNetworkService.class.getSimpleName();
@NonNull private static final String TEST_NETWORK_TYPE = "TEST_NETWORK";
@NonNull private static final String TEST_TUN_PREFIX = "testtun";
+ @NonNull private static final String TEST_TAP_PREFIX = "testtap";
@NonNull private static final AtomicInteger sTestTunIndex = new AtomicInteger();
@NonNull private final Context mContext;
@@ -70,7 +71,7 @@
@NonNull private final Handler mHandler;
// Native method stubs
- private static native int jniCreateTun(@NonNull String iface);
+ private static native int jniCreateTunTap(boolean isTun, @NonNull String iface);
@VisibleForTesting
protected TestNetworkService(
@@ -85,23 +86,23 @@
}
/**
- * Create a TUN interface with the given interface name and link addresses
+ * Create a TUN or TAP interface with the given interface name and link addresses
*
- * <p>This method will return the FileDescriptor to the TUN interface. Close it to tear down the
- * TUN interface.
+ * <p>This method will return the FileDescriptor to the interface. Close it to tear down the
+ * interface.
*/
- @Override
- public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) {
+ private TestNetworkInterface createInterface(boolean isTun, LinkAddress[] linkAddrs) {
enforceTestNetworkPermissions(mContext);
checkNotNull(linkAddrs, "missing linkAddrs");
- String iface = TEST_TUN_PREFIX + sTestTunIndex.getAndIncrement();
+ String ifacePrefix = isTun ? TEST_TUN_PREFIX : TEST_TAP_PREFIX;
+ String iface = ifacePrefix + sTestTunIndex.getAndIncrement();
return Binder.withCleanCallingIdentity(
() -> {
try {
ParcelFileDescriptor tunIntf =
- ParcelFileDescriptor.adoptFd(jniCreateTun(iface));
+ ParcelFileDescriptor.adoptFd(jniCreateTunTap(isTun, iface));
for (LinkAddress addr : linkAddrs) {
mNetd.interfaceAddAddress(
iface,
@@ -116,6 +117,28 @@
});
}
+ /**
+ * Create a TUN interface with the given interface name and link addresses
+ *
+ * <p>This method will return the FileDescriptor to the TUN interface. Close it to tear down the
+ * TUN interface.
+ */
+ @Override
+ public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) {
+ return createInterface(true, linkAddrs);
+ }
+
+ /**
+ * Create a TAP interface with the given interface name
+ *
+ * <p>This method will return the FileDescriptor to the TAP interface. Close it to tear down the
+ * TAP interface.
+ */
+ @Override
+ public TestNetworkInterface createTapInterface() {
+ return createInterface(false, new LinkAddress[0]);
+ }
+
// Tracker for TestNetworkAgents
@GuardedBy("mTestNetworkTracker")
@NonNull
@@ -310,7 +333,7 @@
public void teardownTestNetwork(int netId) {
enforceTestNetworkPermissions(mContext);
- TestNetworkAgent agent;
+ final TestNetworkAgent agent;
synchronized (mTestNetworkTracker) {
agent = mTestNetworkTracker.get(netId);
}
@@ -325,14 +348,10 @@
agent.teardown();
}
- // STOPSHIP: Change this back to android.Manifest.permission.MANAGE_TEST_NETWORKS
- private static final String PERMISSION_NAME = "dummy";
+ private static final String PERMISSION_NAME =
+ android.Manifest.permission.MANAGE_TEST_NETWORKS;
public static void enforceTestNetworkPermissions(@NonNull Context context) {
- // STOPSHIP: Re-enable these checks. Disabled until adoptShellPermissionIdentity() can be
- // called from CTS test code.
- if (false) {
- context.enforceCallingOrSelfPermission(PERMISSION_NAME, "TestNetworkService");
- }
+ context.enforceCallingOrSelfPermission(PERMISSION_NAME, "TestNetworkService");
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index b036289..3399a76 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -787,7 +787,7 @@
return -1;
}
}
- process = getNextArg();
+ process = getNextArgRequired();
} else {
// Compatibility with old syntax: process is specified first.
process = cmd;
@@ -2919,15 +2919,22 @@
pw.println(" start: start tracing IPC transactions.");
pw.println(" stop: stop tracing IPC transactions and dump the results to file.");
pw.println(" --dump-file <FILE>: Specify the file the trace should be dumped to.");
- pw.println(" profile [start|stop] [--user <USER_ID> current] [--sampling INTERVAL]");
- pw.println(" [--streaming] <PROCESS> <FILE>");
- pw.println(" Start and stop profiler on a process. The given <PROCESS> argument");
+ pw.println(" profile start [--user <USER_ID> current]");
+ pw.println(" [--sampling INTERVAL | --streaming] <PROCESS> <FILE>");
+ pw.println(" Start profiler on a process. The given <PROCESS> argument");
pw.println(" may be either a process name or pid. Options are:");
pw.println(" --user <USER_ID> | current: When supplying a process name,");
- pw.println(" specify user of process to profile; uses current user if not specified.");
+ pw.println(" specify user of process to profile; uses current user if not");
+ pw.println(" specified.");
pw.println(" --sampling INTERVAL: use sample profiling with INTERVAL microseconds");
- pw.println(" between samples");
- pw.println(" --streaming: stream the profiling output to the specified file");
+ pw.println(" between samples.");
+ pw.println(" --streaming: stream the profiling output to the specified file.");
+ pw.println(" profile stop [--user <USER_ID> current] <PROCESS>");
+ pw.println(" Stop profiler on a process. The given <PROCESS> argument");
+ pw.println(" may be either a process name or pid. Options are:");
+ pw.println(" --user <USER_ID> | current: When supplying a process name,");
+ pw.println(" specify user of process to profile; uses current user if not");
+ pw.println(" specified.");
pw.println(" dumpheap [--user <USER_ID> current] [-n] [-g] <PROCESS> <FILE>");
pw.println(" Dump the heap of a process. The given <PROCESS> argument may");
pw.println(" be either a process name or pid. Options are:");
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index d7a57b9..35f7ea3 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -132,6 +132,7 @@
private static final int NOT_STARTED = 1;
private static final int STARTING = 2;
private static final int STARTED = 3;
+ private static final int STOPPING = 4;
private int mStartedState = NOT_STARTED;
KeepaliveInfo(@NonNull ISocketKeepaliveCallback callback,
@@ -314,6 +315,7 @@
}
}
if (NOT_STARTED != mStartedState) {
+ mStartedState = STOPPING;
Log.d(TAG, "Stopping keepalive " + mSlot + " on " + mNai.name());
if (mType == TYPE_NATT) {
mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot);
@@ -456,8 +458,8 @@
ki = mKeepalives.get(nai).get(slot);
} catch(NullPointerException e) {}
if (ki == null) {
- Log.e(TAG, "Event " + message.what + " for unknown keepalive " + slot + " on "
- + nai.name());
+ Log.e(TAG, "Event " + message.what + "," + slot + "," + reason
+ + " for unknown keepalive " + slot + " on " + nai.name());
return;
}
@@ -476,27 +478,30 @@
// messages in order.
// TODO : clarify this code and get rid of mStartedState. Using a StateMachine is an
// option.
- if (reason == SUCCESS && KeepaliveInfo.STARTING == ki.mStartedState) {
- // Keepalive successfully started.
- if (DBG) Log.d(TAG, "Started keepalive " + slot + " on " + nai.name());
- ki.mStartedState = KeepaliveInfo.STARTED;
- try {
- ki.mCallback.onStarted(slot);
- } catch (RemoteException e) {
- Log.w(TAG, "Discarded onStarted(" + slot + ") callback");
- }
- } else {
- // Keepalive successfully stopped, or error.
- if (reason == SUCCESS) {
- // The message indicated success stopping : don't call handleStopKeepalive.
- if (DBG) Log.d(TAG, "Successfully stopped keepalive " + slot + " on " + nai.name());
+ if (KeepaliveInfo.STARTING == ki.mStartedState) {
+ if (SUCCESS == reason) {
+ // Keepalive successfully started.
+ if (DBG) Log.d(TAG, "Started keepalive " + slot + " on " + nai.name());
+ ki.mStartedState = KeepaliveInfo.STARTED;
+ try {
+ ki.mCallback.onStarted(slot);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Discarded onStarted(" + slot + ") callback");
+ }
} else {
- // The message indicated some error trying to start or during the course of
- // keepalive : do call handleStopKeepalive.
+ Log.d(TAG, "Failed to start keepalive " + slot + " on " + nai.name()
+ + ": " + reason);
+ // The message indicated some error trying to start: do call handleStopKeepalive.
handleStopKeepalive(nai, slot, reason);
- if (DBG) Log.d(TAG, "Keepalive " + slot + " on " + nai.name() + " error " + reason);
}
+ } else if (KeepaliveInfo.STOPPING == ki.mStartedState) {
+ // The message indicated result of stopping : don't call handleStopKeepalive.
+ Log.d(TAG, "Stopped keepalive " + slot + " on " + nai.name()
+ + " stopped: " + reason);
ki.mStartedState = KeepaliveInfo.NOT_STARTED;
+ } else {
+ Log.wtf(TAG, "Event " + message.what + "," + slot + "," + reason
+ + " for keepalive in wrong state: " + ki.toString());
}
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index e3fdbe8..cfa9131 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -30,6 +30,7 @@
import android.os.Handler;
import android.os.INetworkManagementService;
import android.os.Messenger;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.util.Log;
import android.util.SparseArray;
@@ -121,7 +122,8 @@
// This Network object is always valid.
public final Network network;
public LinkProperties linkProperties;
- // This should only be modified via ConnectivityService.updateCapabilities().
+ // This should only be modified by ConnectivityService, via setNetworkCapabilities().
+ // TODO: make this private with a getter.
public NetworkCapabilities networkCapabilities;
public final NetworkMisc networkMisc;
// Indicates if netd has been told to create this Network. From this point on the appropriate
@@ -279,6 +281,25 @@
mNetworkMonitor = networkMonitor;
}
+ /**
+ * Set the NetworkCapabilities on this NetworkAgentInfo. Also attempts to notify NetworkMonitor
+ * of the new capabilities, if NetworkMonitor has been created.
+ *
+ * <p>If {@link NetworkMonitor#notifyNetworkCapabilitiesChanged(NetworkCapabilities)} fails,
+ * the exception is logged but not reported to callers.
+ */
+ public void setNetworkCapabilities(NetworkCapabilities nc) {
+ networkCapabilities = nc;
+ final INetworkMonitor nm = mNetworkMonitor;
+ if (nm != null) {
+ try {
+ nm.notifyNetworkCapabilitiesChanged(nc);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error notifying NetworkMonitor of updated NetworkCapabilities", e);
+ }
+ }
+ }
+
public ConnectivityService connService() {
return mConnService;
}
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index 0c55934..f8582cd 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -37,23 +37,27 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.UserInfo;
import android.net.INetd;
-import android.net.util.NetdService;
+import android.net.UidRange;
import android.os.Build;
-import android.os.INetworkManagementService;
import android.os.RemoteException;
+import android.os.ServiceSpecificException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.system.OsConstants;
import android.util.ArraySet;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseIntArray;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.server.LocalServices;
import com.android.server.SystemConfig;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -61,6 +65,7 @@
import java.util.Map.Entry;
import java.util.Set;
+
/**
* A utility class to inform Netd of UID permisisons.
* Does a mass update at boot and then monitors for app install/remove.
@@ -74,17 +79,29 @@
protected static final Boolean NETWORK = Boolean.FALSE;
private static final int VERSION_Q = Build.VERSION_CODES.Q;
- private final Context mContext;
private final PackageManager mPackageManager;
private final UserManager mUserManager;
- private final INetworkManagementService mNetd;
+ private final INetd mNetd;
// Values are User IDs.
+ @GuardedBy("this")
private final Set<Integer> mUsers = new HashSet<>();
- // Keys are App IDs. Values are true for SYSTEM permission and false for NETWORK permission.
+ // Keys are app uids. Values are true for SYSTEM permission and false for NETWORK permission.
+ @GuardedBy("this")
private final Map<Integer, Boolean> mApps = new HashMap<>();
+ // Keys are active non-bypassable and fully-routed VPN's interface name, Values are uid ranges
+ // for apps under the VPN
+ @GuardedBy("this")
+ private final Map<String, Set<UidRange>> mVpnUidRanges = new HashMap<>();
+
+ // A set of appIds for apps across all users on the device. We track appIds instead of uids
+ // directly to reduce its size and also eliminate the need to update this set when user is
+ // added/removed.
+ @GuardedBy("this")
+ private final Set<Integer> mAllApps = new HashSet<>();
+
private class PackageListObserver implements PackageManagerInternal.PackageListObserver {
private int getPermissionForUid(int uid) {
@@ -100,6 +117,9 @@
app.requestedPermissionsFlags);
}
}
+ } else {
+ // The last package of this uid is removed from device. Clean the package up.
+ permission = INetd.PERMISSION_UNINSTALLED;
}
return permission;
}
@@ -115,10 +135,9 @@
}
}
- public PermissionMonitor(Context context, INetworkManagementService netd) {
- mContext = context;
+ public PermissionMonitor(Context context, INetd netd) {
mPackageManager = context.getPackageManager();
- mUserManager = UserManager.get(context);
+ mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
mNetd = netd;
}
@@ -147,6 +166,7 @@
if (uid < 0) {
continue;
}
+ mAllApps.add(UserHandle.getAppId(uid));
boolean isNetwork = hasNetworkPermission(app);
boolean hasRestrictedPermission = hasRestrictedNetworkPermission(app);
@@ -266,10 +286,11 @@
}
}
- private int[] toIntArray(List<Integer> list) {
+ private int[] toIntArray(Collection<Integer> list) {
int[] array = new int[list.size()];
- for (int i = 0; i < list.size(); i++) {
- array[i] = list.get(i);
+ int i = 0;
+ for (Integer item : list) {
+ array[i++] = item;
}
return array;
}
@@ -285,11 +306,11 @@
}
try {
if (add) {
- mNetd.setPermission("NETWORK", toIntArray(network));
- mNetd.setPermission("SYSTEM", toIntArray(system));
+ mNetd.networkSetPermissionForUser(INetd.PERMISSION_NETWORK, toIntArray(network));
+ mNetd.networkSetPermissionForUser(INetd.PERMISSION_SYSTEM, toIntArray(system));
} else {
- mNetd.clearPermission(toIntArray(network));
- mNetd.clearPermission(toIntArray(system));
+ mNetd.networkClearPermissionForUser(toIntArray(network));
+ mNetd.networkClearPermissionForUser(toIntArray(system));
}
} catch (RemoteException e) {
loge("Exception when updating permissions: " + e);
@@ -372,6 +393,19 @@
apps.put(uid, permission);
update(mUsers, apps, true);
}
+
+ // If the newly-installed package falls within some VPN's uid range, update Netd with it.
+ // This needs to happen after the mApps update above, since removeBypassingUids() depends
+ // on mApps to check if the package can bypass VPN.
+ for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) {
+ if (UidRange.containsUid(vpn.getValue(), uid)) {
+ final Set<Integer> changedUids = new HashSet<>();
+ changedUids.add(uid);
+ removeBypassingUids(changedUids, /* vpnAppUid */ -1);
+ updateVpnUids(vpn.getKey(), changedUids, true);
+ }
+ }
+ mAllApps.add(UserHandle.getAppId(uid));
}
/**
@@ -382,8 +416,23 @@
* @hide
*/
public synchronized void onPackageRemoved(int uid) {
- Map<Integer, Boolean> apps = new HashMap<>();
+ // If the newly-removed package falls within some VPN's uid range, update Netd with it.
+ // This needs to happen before the mApps update below, since removeBypassingUids() depends
+ // on mApps to check if the package can bypass VPN.
+ for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) {
+ if (UidRange.containsUid(vpn.getValue(), uid)) {
+ final Set<Integer> changedUids = new HashSet<>();
+ changedUids.add(uid);
+ removeBypassingUids(changedUids, /* vpnAppUid */ -1);
+ updateVpnUids(vpn.getKey(), changedUids, false);
+ }
+ }
+ // If the package has been removed from all users on the device, clear it form mAllApps.
+ if (mPackageManager.getNameForUid(uid) == null) {
+ mAllApps.remove(UserHandle.getAppId(uid));
+ }
+ Map<Integer, Boolean> apps = new HashMap<>();
Boolean permission = null;
String[] packages = mPackageManager.getPackagesForUid(uid);
if (packages != null && packages.length > 0) {
@@ -439,6 +488,121 @@
}
/**
+ * Called when a new set of UID ranges are added to an active VPN network
+ *
+ * @param iface The active VPN network's interface name
+ * @param rangesToAdd The new UID ranges to be added to the network
+ * @param vpnAppUid The uid of the VPN app
+ */
+ public synchronized void onVpnUidRangesAdded(@NonNull String iface, Set<UidRange> rangesToAdd,
+ int vpnAppUid) {
+ // Calculate the list of new app uids under the VPN due to the new UID ranges and update
+ // Netd about them. Because mAllApps only contains appIds instead of uids, the result might
+ // be an overestimation if an app is not installed on the user on which the VPN is running,
+ // but that's safe.
+ final Set<Integer> changedUids = intersectUids(rangesToAdd, mAllApps);
+ removeBypassingUids(changedUids, vpnAppUid);
+ updateVpnUids(iface, changedUids, true);
+ if (mVpnUidRanges.containsKey(iface)) {
+ mVpnUidRanges.get(iface).addAll(rangesToAdd);
+ } else {
+ mVpnUidRanges.put(iface, new HashSet<UidRange>(rangesToAdd));
+ }
+ }
+
+ /**
+ * Called when a set of UID ranges are removed from an active VPN network
+ *
+ * @param iface The VPN network's interface name
+ * @param rangesToRemove Existing UID ranges to be removed from the VPN network
+ * @param vpnAppUid The uid of the VPN app
+ */
+ public synchronized void onVpnUidRangesRemoved(@NonNull String iface,
+ Set<UidRange> rangesToRemove, int vpnAppUid) {
+ // Calculate the list of app uids that are no longer under the VPN due to the removed UID
+ // ranges and update Netd about them.
+ final Set<Integer> changedUids = intersectUids(rangesToRemove, mAllApps);
+ removeBypassingUids(changedUids, vpnAppUid);
+ updateVpnUids(iface, changedUids, false);
+ Set<UidRange> existingRanges = mVpnUidRanges.getOrDefault(iface, null);
+ if (existingRanges == null) {
+ loge("Attempt to remove unknown vpn uid Range iface = " + iface);
+ return;
+ }
+ existingRanges.removeAll(rangesToRemove);
+ if (existingRanges.size() == 0) {
+ mVpnUidRanges.remove(iface);
+ }
+ }
+
+ /**
+ * Compute the intersection of a set of UidRanges and appIds. Returns a set of uids
+ * that satisfies:
+ * 1. falls into one of the UidRange
+ * 2. matches one of the appIds
+ */
+ private Set<Integer> intersectUids(Set<UidRange> ranges, Set<Integer> appIds) {
+ Set<Integer> result = new HashSet<>();
+ for (UidRange range : ranges) {
+ for (int userId = range.getStartUser(); userId <= range.getEndUser(); userId++) {
+ for (int appId : appIds) {
+ final int uid = UserHandle.getUid(userId, appId);
+ if (range.contains(uid)) {
+ result.add(uid);
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Remove all apps which can elect to bypass the VPN from the list of uids
+ *
+ * An app can elect to bypass the VPN if it hold SYSTEM permission, or if its the active VPN
+ * app itself.
+ *
+ * @param uids The list of uids to operate on
+ * @param vpnAppUid The uid of the VPN app
+ */
+ private void removeBypassingUids(Set<Integer> uids, int vpnAppUid) {
+ uids.remove(vpnAppUid);
+ uids.removeIf(uid -> mApps.getOrDefault(uid, NETWORK) == SYSTEM);
+ }
+
+ /**
+ * Update netd about the list of uids that are under an active VPN connection which they cannot
+ * bypass.
+ *
+ * This is to instruct netd to set up appropriate filtering rules for these uids, such that they
+ * can only receive ingress packets from the VPN's tunnel interface (and loopback).
+ *
+ * @param iface the interface name of the active VPN connection
+ * @param add {@code true} if the uids are to be added to the interface, {@code false} if they
+ * are to be removed from the interface.
+ */
+ private void updateVpnUids(String iface, Set<Integer> uids, boolean add) {
+ if (uids.size() == 0) {
+ return;
+ }
+ try {
+ if (add) {
+ mNetd.firewallAddUidInterfaceRules(iface, toIntArray(uids));
+ } else {
+ mNetd.firewallRemoveUidInterfaceRules(toIntArray(uids));
+ }
+ } catch (ServiceSpecificException e) {
+ // Silently ignore exception when device does not support eBPF, otherwise just log
+ // the exception and do not crash
+ if (e.errorCode != OsConstants.EOPNOTSUPP) {
+ loge("Exception when updating permissions: ", e);
+ }
+ } catch (RemoteException e) {
+ loge("Exception when updating permissions: ", e);
+ }
+ }
+
+ /**
* Called by PackageListObserver when a package is installed/uninstalled. Send the updated
* permission information to netd.
*
@@ -447,7 +611,8 @@
*
* @hide
*/
- private void sendPackagePermissionsForUid(int uid, int permissions) {
+ @VisibleForTesting
+ void sendPackagePermissionsForUid(int uid, int permissions) {
SparseIntArray netdPermissionsAppIds = new SparseIntArray();
netdPermissionsAppIds.put(uid, permissions);
sendPackagePermissionsToNetd(netdPermissionsAppIds);
@@ -462,15 +627,16 @@
*
* @hide
*/
- private void sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds) {
- INetd netdService = NetdService.getInstance();
- if (netdService == null) {
+ @VisibleForTesting
+ void sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds) {
+ if (mNetd == null) {
Log.e(TAG, "Failed to get the netd service");
return;
}
ArrayList<Integer> allPermissionAppIds = new ArrayList<>();
ArrayList<Integer> internetPermissionAppIds = new ArrayList<>();
ArrayList<Integer> updateStatsPermissionAppIds = new ArrayList<>();
+ ArrayList<Integer> noPermissionAppIds = new ArrayList<>();
ArrayList<Integer> uninstalledAppIds = new ArrayList<>();
for (int i = 0; i < netdPermissionsAppIds.size(); i++) {
int permissions = netdPermissionsAppIds.valueAt(i);
@@ -485,8 +651,10 @@
updateStatsPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
break;
case INetd.NO_PERMISSIONS:
- uninstalledAppIds.add(netdPermissionsAppIds.keyAt(i));
+ noPermissionAppIds.add(netdPermissionsAppIds.keyAt(i));
break;
+ case INetd.PERMISSION_UNINSTALLED:
+ uninstalledAppIds.add(netdPermissionsAppIds.keyAt(i));
default:
Log.e(TAG, "unknown permission type: " + permissions + "for uid: "
+ netdPermissionsAppIds.keyAt(i));
@@ -495,20 +663,24 @@
try {
// TODO: add a lock inside netd to protect IPC trafficSetNetPermForUids()
if (allPermissionAppIds.size() != 0) {
- netdService.trafficSetNetPermForUids(
+ mNetd.trafficSetNetPermForUids(
INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS,
ArrayUtils.convertToIntArray(allPermissionAppIds));
}
if (internetPermissionAppIds.size() != 0) {
- netdService.trafficSetNetPermForUids(INetd.PERMISSION_INTERNET,
+ mNetd.trafficSetNetPermForUids(INetd.PERMISSION_INTERNET,
ArrayUtils.convertToIntArray(internetPermissionAppIds));
}
if (updateStatsPermissionAppIds.size() != 0) {
- netdService.trafficSetNetPermForUids(INetd.PERMISSION_UPDATE_DEVICE_STATS,
+ mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UPDATE_DEVICE_STATS,
ArrayUtils.convertToIntArray(updateStatsPermissionAppIds));
}
+ if (noPermissionAppIds.size() != 0) {
+ mNetd.trafficSetNetPermForUids(INetd.NO_PERMISSIONS,
+ ArrayUtils.convertToIntArray(noPermissionAppIds));
+ }
if (uninstalledAppIds.size() != 0) {
- netdService.trafficSetNetPermForUids(INetd.NO_PERMISSIONS,
+ mNetd.trafficSetNetPermForUids(INetd.PERMISSION_UNINSTALLED,
ArrayUtils.convertToIntArray(uninstalledAppIds));
}
} catch (RemoteException e) {
@@ -516,6 +688,24 @@
}
}
+ /** Should only be used by unit tests */
+ @VisibleForTesting
+ public Set<UidRange> getVpnUidRanges(String iface) {
+ return mVpnUidRanges.get(iface);
+ }
+
+ /** Dump info to dumpsys */
+ public void dump(IndentingPrintWriter pw) {
+ pw.println("Interface filtering rules:");
+ pw.increaseIndent();
+ for (Map.Entry<String, Set<UidRange>> vpn : mVpnUidRanges.entrySet()) {
+ pw.println("Interface: " + vpn.getKey());
+ pw.println("UIDs: " + vpn.getValue().toString());
+ pw.println();
+ }
+ pw.decreaseIndent();
+ }
+
private static void log(String s) {
if (DBG) {
Log.d(TAG, s);
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 8005dda..0271d3b 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -1604,12 +1604,7 @@
if (mNetworkInfo.isConnected()) {
return !appliesToUid(uid);
} else {
- for (UidRange uidRange : mBlockedUsers) {
- if (uidRange.contains(uid)) {
- return true;
- }
- }
- return false;
+ return UidRange.containsUid(mBlockedUsers, uid);
}
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java b/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java
index 764a6eb..b0bbd72 100644
--- a/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java
+++ b/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java
@@ -52,7 +52,6 @@
import android.provider.Settings;
import android.telephony.CarrierConfigManager;
import android.util.ArraySet;
-import android.util.Log;
import android.util.SparseIntArray;
import com.android.internal.annotations.VisibleForTesting;
@@ -231,7 +230,7 @@
private void handleNotifyUpstream(boolean isCellular) {
if (DBG) {
- Log.d(TAG, "notifyUpstream: " + isCellular
+ mLog.i("notifyUpstream: " + isCellular
+ ", mCellularUpstreamPermitted: " + mCellularUpstreamPermitted
+ ", mNeedReRunProvisioningUi: " + mNeedReRunProvisioningUi);
}
@@ -294,7 +293,7 @@
* masterHandler to avoid race conditions.
*/
public void reevaluateSimCardProvisioning() {
- if (DBG) Log.d(TAG, "reevaluateSimCardProvisioning");
+ if (DBG) mLog.i("reevaluateSimCardProvisioning");
if (!mHandler.getLooper().isCurrentThread()) {
// Except for test, this log should not appear in normal flow.
@@ -351,7 +350,7 @@
* @param type tethering type from ConnectivityManager.TETHERING_{@code *}
*/
protected void runSilentTetherProvisioning(int type) {
- if (DBG) Log.d(TAG, "runSilentTetherProvisioning: " + type);
+ if (DBG) mLog.i("runSilentTetherProvisioning: " + type);
// For silent provisioning, settings would stop tethering when entitlement fail.
ResultReceiver receiver = buildProxyReceiver(type,
false/* notifyFail */, null);
@@ -382,7 +381,7 @@
@VisibleForTesting
protected void runUiTetherProvisioning(int type, ResultReceiver receiver) {
- if (DBG) Log.d(TAG, "runUiTetherProvisioning: " + type);
+ if (DBG) mLog.i("runUiTetherProvisioning: " + type);
Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING);
intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
@@ -428,7 +427,7 @@
|| mCellularPermitted.indexOfValue(TETHER_ERROR_NO_ERROR) > -1);
if (DBG) {
- Log.d(TAG, "Cellular permission change from " + oldPermitted
+ mLog.i("Cellular permission change from " + oldPermitted
+ " to " + mCellularUpstreamPermitted);
}
@@ -453,10 +452,8 @@
* @param resultCode Provisioning result
*/
protected void addDownstreamMapping(int type, int resultCode) {
- if (DBG) {
- Log.d(TAG, "addDownstreamMapping: " + type + ", result: " + resultCode
- + " ,TetherTypeRequested: " + mCurrentTethers.contains(type));
- }
+ mLog.i("addDownstreamMapping: " + type + ", result: " + resultCode
+ + " ,TetherTypeRequested: " + mCurrentTethers.contains(type));
if (!mCurrentTethers.contains(type)) return;
mCellularPermitted.put(type, resultCode);
@@ -468,7 +465,7 @@
* @param type tethering type from ConnectivityManager.TETHERING_{@code *}
*/
protected void removeDownstreamMapping(int type) {
- if (DBG) Log.d(TAG, "removeDownstreamMapping: " + type);
+ mLog.i("removeDownstreamMapping: " + type);
mCellularPermitted.delete(type);
evaluateCellularPermission();
}
@@ -617,7 +614,7 @@
*/
private int updateEntitlementCacheValue(int type, int resultCode) {
if (DBG) {
- Log.d(TAG, "updateEntitlementCacheValue: " + type + ", result: " + resultCode);
+ mLog.i("updateEntitlementCacheValue: " + type + ", result: " + resultCode);
}
if (resultCode == TETHER_ERROR_NO_ERROR) {
mEntitlementCacheValue.put(type, resultCode);
diff --git a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
index 648c782..603d7cf 100644
--- a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
+++ b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
@@ -18,14 +18,11 @@
import android.annotation.NonNull;
import android.content.Context;
+import android.media.AudioManager;
import android.media.AudioPlaybackConfiguration;
-import android.media.IAudioService;
-import android.media.IPlaybackConfigDispatcher;
-import android.os.Binder;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -42,11 +39,11 @@
/**
* Monitors the state changes of audio players.
*/
-class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub {
+class AudioPlayerStateMonitor {
private static boolean DEBUG = MediaSessionService.DEBUG;
private static String TAG = "AudioPlayerStateMonitor";
- private static AudioPlayerStateMonitor sInstance = new AudioPlayerStateMonitor();
+ private static AudioPlayerStateMonitor sInstance;
/**
* Listener for handling the active state changes of audio players.
@@ -96,96 +93,33 @@
private final Map<OnAudioPlayerActiveStateChangedListener, MessageHandler> mListenerMap =
new ArrayMap<>();
@GuardedBy("mLock")
- private final Set<Integer> mActiveAudioUids = new ArraySet<>();
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ final Set<Integer> mActiveAudioUids = new ArraySet<>();
@GuardedBy("mLock")
- private ArrayMap<Integer, AudioPlaybackConfiguration> mPrevActiveAudioPlaybackConfigs =
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ ArrayMap<Integer, AudioPlaybackConfiguration> mPrevActiveAudioPlaybackConfigs =
new ArrayMap<>();
// Sorted array of UIDs that had active audio playback. (i.e. playing an audio/video)
// The UID whose audio playback becomes active at the last comes first.
// TODO(b/35278867): Find and use unique identifier for apps because apps may share the UID.
@GuardedBy("mLock")
- private final IntArray mSortedAudioPlaybackClientUids = new IntArray();
+ @SuppressWarnings("WeakerAccess") /* synthetic access */
+ final IntArray mSortedAudioPlaybackClientUids = new IntArray();
- @GuardedBy("mLock")
- private boolean mRegisteredToAudioService;
-
- static AudioPlayerStateMonitor getInstance() {
- return sInstance;
- }
-
- private AudioPlayerStateMonitor() {
- }
-
- /**
- * Called when the {@link AudioPlaybackConfiguration} is updated.
- * <p>If an app starts audio playback, the app's local media session will be the media button
- * session. If the app has multiple media sessions, the playback active local session will be
- * picked.
- *
- * @param configs List of the current audio playback configuration
- */
- @Override
- public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
- boolean flush) {
- if (flush) {
- Binder.flushPendingCommands();
- }
- final long token = Binder.clearCallingIdentity();
- try {
- synchronized (mLock) {
- // Update mActiveAudioUids
- mActiveAudioUids.clear();
- ArrayMap<Integer, AudioPlaybackConfiguration> activeAudioPlaybackConfigs =
- new ArrayMap<>();
- for (AudioPlaybackConfiguration config : configs) {
- if (config.isActive()) {
- mActiveAudioUids.add(config.getClientUid());
- activeAudioPlaybackConfigs.put(config.getPlayerInterfaceId(), config);
- }
- }
-
- // Update mSortedAuioPlaybackClientUids.
- for (int i = 0; i < activeAudioPlaybackConfigs.size(); ++i) {
- AudioPlaybackConfiguration config = activeAudioPlaybackConfigs.valueAt(i);
- final int uid = config.getClientUid();
- if (!mPrevActiveAudioPlaybackConfigs.containsKey(
- config.getPlayerInterfaceId())) {
- if (DEBUG) {
- Log.d(TAG, "Found a new active media playback. " +
- AudioPlaybackConfiguration.toLogFriendlyString(config));
- }
- // New active audio playback.
- int index = mSortedAudioPlaybackClientUids.indexOf(uid);
- if (index == 0) {
- // It's the lastly played music app already. Skip updating.
- continue;
- } else if (index > 0) {
- mSortedAudioPlaybackClientUids.remove(index);
- }
- mSortedAudioPlaybackClientUids.add(0, uid);
- }
- }
- // Notify the active state change of audio players.
- for (AudioPlaybackConfiguration config : configs) {
- final int pii = config.getPlayerInterfaceId();
- boolean wasActive = mPrevActiveAudioPlaybackConfigs.remove(pii) != null;
- if (wasActive != config.isActive()) {
- sendAudioPlayerActiveStateChangedMessageLocked(
- config, /* isRemoved */ false);
- }
- }
- for (AudioPlaybackConfiguration config : mPrevActiveAudioPlaybackConfigs.values()) {
- sendAudioPlayerActiveStateChangedMessageLocked(config, /* isRemoved */ true);
- }
-
- // Update mPrevActiveAudioPlaybackConfigs
- mPrevActiveAudioPlaybackConfigs = activeAudioPlaybackConfigs;
+ static AudioPlayerStateMonitor getInstance(Context context) {
+ synchronized (AudioPlayerStateMonitor.class) {
+ if (sInstance == null) {
+ sInstance = new AudioPlayerStateMonitor(context);
}
- } finally {
- Binder.restoreCallingIdentity(token);
+ return sInstance;
}
}
+ private AudioPlayerStateMonitor(Context context) {
+ AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ am.registerAudioPlaybackCallback(new AudioManagerPlaybackListener(), null);
+ }
+
/**
* Registers OnAudioPlayerActiveStateChangedListener.
*/
@@ -275,20 +209,6 @@
}
}
- public void registerSelfIntoAudioServiceIfNeeded(IAudioService audioService) {
- synchronized (mLock) {
- try {
- if (!mRegisteredToAudioService) {
- audioService.registerPlaybackCallback(this);
- mRegisteredToAudioService = true;
- }
- } catch (RemoteException e) {
- Log.wtf(TAG, "Failed to register playback callback", e);
- mRegisteredToAudioService = false;
- }
- }
- }
-
@GuardedBy("mLock")
private void sendAudioPlayerActiveStateChangedMessageLocked(
final AudioPlaybackConfiguration config, final boolean isRemoved) {
@@ -296,4 +216,59 @@
messageHandler.sendAudioPlayerActiveStateChangedMessage(config, isRemoved);
}
}
+
+ private class AudioManagerPlaybackListener extends AudioManager.AudioPlaybackCallback {
+ @Override
+ public void onPlaybackConfigChanged(List<AudioPlaybackConfiguration> configs) {
+ synchronized (mLock) {
+ // Update mActiveAudioUids
+ mActiveAudioUids.clear();
+ ArrayMap<Integer, AudioPlaybackConfiguration> activeAudioPlaybackConfigs =
+ new ArrayMap<>();
+ for (AudioPlaybackConfiguration config : configs) {
+ if (config.isActive()) {
+ mActiveAudioUids.add(config.getClientUid());
+ activeAudioPlaybackConfigs.put(config.getPlayerInterfaceId(), config);
+ }
+ }
+
+ // Update mSortedAuioPlaybackClientUids.
+ for (int i = 0; i < activeAudioPlaybackConfigs.size(); ++i) {
+ AudioPlaybackConfiguration config = activeAudioPlaybackConfigs.valueAt(i);
+ final int uid = config.getClientUid();
+ if (!mPrevActiveAudioPlaybackConfigs.containsKey(
+ config.getPlayerInterfaceId())) {
+ if (DEBUG) {
+ Log.d(TAG, "Found a new active media playback. "
+ + AudioPlaybackConfiguration.toLogFriendlyString(config));
+ }
+ // New active audio playback.
+ int index = mSortedAudioPlaybackClientUids.indexOf(uid);
+ if (index == 0) {
+ // It's the lastly played music app already. Skip updating.
+ continue;
+ } else if (index > 0) {
+ mSortedAudioPlaybackClientUids.remove(index);
+ }
+ mSortedAudioPlaybackClientUids.add(0, uid);
+ }
+ }
+ // Notify the active state change of audio players.
+ for (AudioPlaybackConfiguration config : configs) {
+ final int pii = config.getPlayerInterfaceId();
+ boolean wasActive = mPrevActiveAudioPlaybackConfigs.remove(pii) != null;
+ if (wasActive != config.isActive()) {
+ sendAudioPlayerActiveStateChangedMessageLocked(
+ config, /* isRemoved */ false);
+ }
+ }
+ for (AudioPlaybackConfiguration config : mPrevActiveAudioPlaybackConfigs.values()) {
+ sendAudioPlayerActiveStateChangedMessageLocked(config, /* isRemoved */ true);
+ }
+
+ // Update mPrevActiveAudioPlaybackConfigs
+ mPrevActiveAudioPlaybackConfigs = activeAudioPlaybackConfigs;
+ }
+ }
+ }
}
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index a7df0e2..47f2270 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -16,14 +16,10 @@
package com.android.server.media;
-import com.android.internal.util.DumpUtils;
-import com.android.server.Watchdog;
-
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.bluetooth.BluetoothA2dp;
import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothProfile;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -57,6 +53,9 @@
import android.util.SparseArray;
import android.util.TimeUtils;
+import com.android.internal.util.DumpUtils;
+import com.android.server.Watchdog;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -115,7 +114,7 @@
mAudioService = IAudioService.Stub.asInterface(
ServiceManager.getService(Context.AUDIO_SERVICE));
- mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance();
+ mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance(context);
mAudioPlayerStateMonitor.registerListener(
new AudioPlayerStateMonitor.OnAudioPlayerActiveStateChangedListener() {
static final long WAIT_MS = 500;
@@ -166,7 +165,6 @@
}
}
}, mHandler);
- mAudioPlayerStateMonitor.registerSelfIntoAudioServiceIfNeeded(mAudioService);
AudioRoutesInfo audioRoutes = null;
try {
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 442354b..29529b8 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -669,6 +669,9 @@
PlaybackState state;
long duration = -1;
synchronized (mLock) {
+ if (mDestroyed) {
+ return null;
+ }
state = mPlaybackState;
if (mMetadata != null && mMetadata.containsKey(MediaMetadata.METADATA_KEY_DURATION)) {
duration = mMetadata.getLong(MediaMetadata.METADATA_KEY_DURATION);
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 68b2a58..67f605c 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -93,8 +93,8 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.NoSuchElementException;
+import java.util.Set;
/**
* System implementation of MediaSessionManager
@@ -164,7 +164,7 @@
mKeyguardManager =
(KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
mAudioService = getAudioService();
- mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance();
+ mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance(getContext());
mAudioPlayerStateMonitor.registerListener(
(config, isRemoved) -> {
if (isRemoved || !config.isActive() || config.getPlayerType()
@@ -179,7 +179,6 @@
}
}
}, null /* handler */);
- mAudioPlayerStateMonitor.registerSelfIntoAudioServiceIfNeeded(mAudioService);
mContentResolver = getContext().getContentResolver();
mSettingsObserver = new SettingsObserver();
mSettingsObserver.observe();
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 863ef67..ca0fbe1 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -3462,9 +3462,9 @@
/**
* Process state of UID changed; if needed, will trigger
* {@link #updateRulesForDataUsageRestrictionsUL(int)} and
- * {@link #updateRulesForPowerRestrictionsUL(int)}
+ * {@link #updateRulesForPowerRestrictionsUL(int)}. Returns true if the state was updated.
*/
- private void updateUidStateUL(int uid, int uidState) {
+ private boolean updateUidStateUL(int uid, int uidState) {
Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateUidStateUL");
try {
final int oldUidState = mUidState.get(uid, ActivityManager.PROCESS_STATE_CACHED_EMPTY);
@@ -3483,14 +3483,15 @@
}
updateRulesForPowerRestrictionsUL(uid);
}
- updateNetworkStats(uid, isUidStateForeground(uidState));
+ return true;
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
}
+ return false;
}
- private void removeUidStateUL(int uid) {
+ private boolean removeUidStateUL(int uid) {
final int index = mUidState.indexOfKey(uid);
if (index >= 0) {
final int oldUidState = mUidState.valueAt(index);
@@ -3505,9 +3506,10 @@
updateRuleForRestrictPowerUL(uid);
}
updateRulesForPowerRestrictionsUL(uid);
- updateNetworkStats(uid, false);
+ return true;
}
}
+ return false;
}
// adjust stats accounting based on foreground status
@@ -4419,21 +4421,26 @@
}
}
}
-
};
void handleUidChanged(int uid, int procState, long procStateSeq) {
Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "onUidStateChanged");
try {
+ boolean updated;
synchronized (mUidRulesFirstLock) {
// We received a uid state change callback, add it to the history so that it
// will be useful for debugging.
mLogger.uidStateChanged(uid, procState, procStateSeq);
// Now update the network policy rules as per the updated uid state.
- updateUidStateUL(uid, procState);
+ updated = updateUidStateUL(uid, procState);
// Updating the network rules is done, so notify AMS about this.
mActivityManagerInternal.notifyNetworkPolicyRulesUpdated(uid, procStateSeq);
}
+ // Do this without the lock held. handleUidChanged() and handleUidGone() are
+ // called from the handler, so there's no multi-threading issue.
+ if (updated) {
+ updateNetworkStats(uid, isUidStateForeground(procState));
+ }
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
}
@@ -4442,8 +4449,14 @@
void handleUidGone(int uid) {
Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "onUidGone");
try {
+ boolean updated;
synchronized (mUidRulesFirstLock) {
- removeUidStateUL(uid);
+ updated = removeUidStateUL(uid);
+ }
+ // Do this without the lock held. handleUidChanged() and handleUidGone() are
+ // called from the handler, so there's no multi-threading issue.
+ if (updated) {
+ updateNetworkStats(uid, false);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_NETWORK);
diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java
similarity index 94%
rename from core/java/com/android/internal/net/NetworkStatsFactory.java
rename to services/core/java/com/android/server/net/NetworkStatsFactory.java
index 1f3b4c4..bd11d46 100644
--- a/core/java/com/android/internal/net/NetworkStatsFactory.java
+++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.net;
+package com.android.server.net;
import static android.net.NetworkStats.SET_ALL;
import static android.net.NetworkStats.TAG_ALL;
@@ -28,6 +28,7 @@
import android.os.StrictMode;
import android.os.SystemClock;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ProcFileReader;
@@ -65,6 +66,7 @@
private boolean mUseBpfStats;
// A persistent Snapshot since device start for eBPF stats
+ @GuardedBy("mPersistSnapshot")
private final NetworkStats mPersistSnapshot;
// TODO: only do adjustments in NetworkStatsService and remove this.
@@ -289,15 +291,17 @@
stats = new NetworkStats(SystemClock.elapsedRealtime(), -1);
}
if (mUseBpfStats) {
- if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL,
- null, TAG_ALL, mUseBpfStats) != 0) {
- throw new IOException("Failed to parse network stats");
+ synchronized (mPersistSnapshot) {
+ if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL,
+ null, TAG_ALL, mUseBpfStats) != 0) {
+ throw new IOException("Failed to parse network stats");
+ }
+ mPersistSnapshot.setElapsedRealtime(stats.getElapsedRealtime());
+ mPersistSnapshot.combineAllValues(stats);
+ NetworkStats result = mPersistSnapshot.clone();
+ result.filter(limitUid, limitIfaces, limitTag);
+ return result;
}
- mPersistSnapshot.setElapsedRealtime(stats.getElapsedRealtime());
- mPersistSnapshot.combineAllValues(stats);
- NetworkStats result = mPersistSnapshot.clone();
- result.filter(limitUid, limitIfaces, limitTag);
- return result;
} else {
if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid,
limitIfaces, limitTag, mUseBpfStats) != 0) {
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 4c07678..484efd6 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -25,6 +25,7 @@
import static android.content.Intent.EXTRA_UID;
import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
import static android.net.ConnectivityManager.isNetworkTypeMobile;
+import static android.net.NetworkStack.checkNetworkStackPermission;
import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
import static android.net.NetworkStats.IFACE_ALL;
import static android.net.NetworkStats.INTERFACES_ALL;
@@ -129,7 +130,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.net.NetworkStatsFactory;
import com.android.internal.net.VpnInfo;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.DumpUtils;
@@ -900,7 +900,7 @@
VpnInfo[] vpnArray,
NetworkState[] networkStates,
String activeIface) {
- mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
+ checkNetworkStackPermission(mContext);
assertBandwidthControlEnabled();
final long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 8018c2b..6623526 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -150,51 +150,6 @@
}
}
- int performDexOpt(SharedLibraryInfo info, String[] instructionSets, DexoptOptions options) {
- String classLoaderContext = DexoptUtils.getClassLoaderContext(info);
- final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
- String compilerFilter = PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
- PackageManagerService.REASON_SHARED);
- int result = DEX_OPT_SKIPPED;
- for (String instructionSet : dexCodeInstructionSets) {
- int dexoptNeeded = getDexoptNeeded(
- info.getPath(), instructionSet, compilerFilter,
- classLoaderContext, false /* newProfile */,
- false /* downgrade */);
- if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) {
- continue;
- }
- // Special string recognized by installd.
- final String packageName = "*";
- final String outputPath = null;
- int dexFlags = DEXOPT_PUBLIC
- | (options.isBootComplete() ? DEXOPT_BOOTCOMPLETE : 0)
- | (options.isDexoptIdleBackgroundJob() ? DEXOPT_IDLE_BACKGROUND_JOB : 0);
- dexFlags = adjustDexoptFlags(dexFlags);
- final String uuid = StorageManager.UUID_SYSTEM;
- final String seInfo = null;
- final int targetSdkVersion = 0; // Builtin libraries targets the system's SDK version
- try {
- mInstaller.dexopt(info.getPath(), Process.SYSTEM_UID, packageName,
- instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter,
- uuid, classLoaderContext, seInfo, false /* downgrade */,
- targetSdkVersion, /*profileName*/ null, /*dexMetadataPath*/ null,
- getReasonName(options.getCompilationReason()));
- // The end result is:
- // - FAILED if any path failed,
- // - PERFORMED if at least one path needed compilation,
- // - SKIPPED when all paths are up to date
- if (result != DEX_OPT_FAILED) {
- result = DEX_OPT_PERFORMED;
- }
- } catch (InstallerException e) {
- Slog.w(TAG, "Failed to dexopt", e);
- result = DEX_OPT_FAILED;
- }
- }
- return result;
- }
-
/**
* Performs dexopt on all code paths of the given package.
* It assumes the install lock is held.
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 790e6e1..54a7e2a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -9463,7 +9463,7 @@
mDexManager.getPackageUseInfoOrDefault(depPackage.packageName),
libraryOptions);
} else {
- pdo.performDexOpt(info, instructionSets, libraryOptions);
+ // TODO(ngeoffray): Support dexopting system shared libraries.
}
}
}
@@ -23934,6 +23934,21 @@
}
return 0;
}
+
+ @Override
+ public int getLocationFlags(String packageName) throws RemoteException {
+ int callingUser = UserHandle.getUserId(Binder.getCallingUid());
+ ApplicationInfo appInfo = getApplicationInfo(packageName,
+ /*flags*/ 0,
+ /*userId*/ callingUser);
+ if (appInfo == null) {
+ throw new RemoteException(
+ "Couldn't get ApplicationInfo for package " + packageName);
+ }
+ return ((appInfo.isSystemApp() ? IPackageManagerNative.LOCATION_SYSTEM : 0)
+ | (appInfo.isVendor() ? IPackageManagerNative.LOCATION_VENDOR : 0)
+ | (appInfo.isProduct() ? IPackageManagerNative.LOCATION_PRODUCT : 0));
+ }
}
private class PackageManagerInternalImpl extends PackageManagerInternal {
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index c30babd..b2677cb 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -67,6 +67,7 @@
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.Process;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -128,8 +129,6 @@
private final WatchLogHandler mWatchLogHandler;
- private IBinder.DeathRecipient mDeathRecipient;
-
public TvInputManagerService(Context context) {
super(context);
@@ -484,7 +483,7 @@
userState.packageSet.clear();
userState.contentRatingSystemList.clear();
userState.clientStateMap.clear();
- userState.callbackSet.clear();
+ userState.mCallbacks.kill();
userState.mainSessionToken = null;
mUserStates.remove(userId);
@@ -749,39 +748,45 @@
if (DEBUG) {
Slog.d(TAG, "notifyInputAddedLocked(inputId=" + inputId + ")");
}
- for (ITvInputManagerCallback callback : userState.callbackSet) {
+ int n = userState.mCallbacks.beginBroadcast();
+ for (int i = 0; i < n; ++i) {
try {
- callback.onInputAdded(inputId);
+ userState.mCallbacks.getBroadcastItem(i).onInputAdded(inputId);
} catch (RemoteException e) {
Slog.e(TAG, "failed to report added input to callback", e);
}
}
+ userState.mCallbacks.finishBroadcast();
}
private void notifyInputRemovedLocked(UserState userState, String inputId) {
if (DEBUG) {
Slog.d(TAG, "notifyInputRemovedLocked(inputId=" + inputId + ")");
}
- for (ITvInputManagerCallback callback : userState.callbackSet) {
+ int n = userState.mCallbacks.beginBroadcast();
+ for (int i = 0; i < n; ++i) {
try {
- callback.onInputRemoved(inputId);
+ userState.mCallbacks.getBroadcastItem(i).onInputRemoved(inputId);
} catch (RemoteException e) {
Slog.e(TAG, "failed to report removed input to callback", e);
}
}
+ userState.mCallbacks.finishBroadcast();
}
private void notifyInputUpdatedLocked(UserState userState, String inputId) {
if (DEBUG) {
Slog.d(TAG, "notifyInputUpdatedLocked(inputId=" + inputId + ")");
}
- for (ITvInputManagerCallback callback : userState.callbackSet) {
+ int n = userState.mCallbacks.beginBroadcast();
+ for (int i = 0; i < n; ++i) {
try {
- callback.onInputUpdated(inputId);
+ userState.mCallbacks.getBroadcastItem(i).onInputUpdated(inputId);
} catch (RemoteException e) {
Slog.e(TAG, "failed to report updated input to callback", e);
}
}
+ userState.mCallbacks.finishBroadcast();
}
private void notifyInputStateChangedLocked(UserState userState, String inputId,
@@ -791,13 +796,15 @@
+ ", state=" + state + ")");
}
if (targetCallback == null) {
- for (ITvInputManagerCallback callback : userState.callbackSet) {
+ int n = userState.mCallbacks.beginBroadcast();
+ for (int i = 0; i < n; ++i) {
try {
- callback.onInputStateChanged(inputId, state);
+ userState.mCallbacks.getBroadcastItem(i).onInputStateChanged(inputId, state);
} catch (RemoteException e) {
Slog.e(TAG, "failed to report state change to callback", e);
}
}
+ userState.mCallbacks.finishBroadcast();
} else {
try {
targetCallback.onInputStateChanged(inputId, state);
@@ -819,13 +826,15 @@
}
inputState.info = inputInfo;
- for (ITvInputManagerCallback callback : userState.callbackSet) {
+ int n = userState.mCallbacks.beginBroadcast();
+ for (int i = 0; i < n; ++i) {
try {
- callback.onTvInputInfoUpdated(inputInfo);
+ userState.mCallbacks.getBroadcastItem(i).onTvInputInfoUpdated(inputInfo);
} catch (RemoteException e) {
Slog.e(TAG, "failed to report updated input info to callback", e);
}
}
+ userState.mCallbacks.finishBroadcast();
}
private void setStateLocked(String inputId, int state, int userId) {
@@ -1003,22 +1012,8 @@
try {
synchronized (mLock) {
final UserState userState = getOrCreateUserStateLocked(resolvedUserId);
- userState.callbackSet.add(callback);
- mDeathRecipient = new IBinder.DeathRecipient() {
- @Override
- public void binderDied() {
- synchronized (mLock) {
- if (userState.callbackSet != null) {
- userState.callbackSet.remove(callback);
- }
- }
- }
- };
-
- try {
- callback.asBinder().linkToDeath(mDeathRecipient, 0);
- } catch (RemoteException e) {
- Slog.e(TAG, "client process has already died", e);
+ if (!userState.mCallbacks.register(callback)) {
+ Slog.e(TAG, "client process has already died");
}
}
} finally {
@@ -1034,8 +1029,7 @@
try {
synchronized (mLock) {
UserState userState = getOrCreateUserStateLocked(resolvedUserId);
- userState.callbackSet.remove(callback);
- callback.asBinder().unlinkToDeath(mDeathRecipient, 0);
+ userState.mCallbacks.unregister(callback);
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -2104,11 +2098,13 @@
}
pw.decreaseIndent();
- pw.println("callbackSet:");
+ pw.println("mCallbacks:");
pw.increaseIndent();
- for (ITvInputManagerCallback callback : userState.callbackSet) {
- pw.println(callback.toString());
+ int n = userState.mCallbacks.beginBroadcast();
+ for (int j = 0; j < n; ++j) {
+ pw.println(userState.mCallbacks.getRegisteredCallbackItem(j).toString());
}
+ userState.mCallbacks.finishBroadcast();
pw.decreaseIndent();
pw.println("mainSessionToken: " + userState.mainSessionToken);
@@ -2139,8 +2135,9 @@
// A mapping from the token of a TV input session to its state.
private final Map<IBinder, SessionState> sessionStateMap = new HashMap<>();
- // A set of callbacks.
- private final Set<ITvInputManagerCallback> callbackSet = new HashSet<>();
+ // A list of callbacks.
+ private final RemoteCallbackList<ITvInputManagerCallback> mCallbacks =
+ new RemoteCallbackList<ITvInputManagerCallback>();
// The token of a "main" TV input session.
private IBinder mainSessionToken = null;
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 07a6c70..b5381ae 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -51,6 +51,7 @@
"com_android_server_PersistentDataBlockService.cpp",
"com_android_server_GraphicsStatsService.cpp",
"onload.cpp",
+ ":lib_networkStatsFactory_native",
],
include_dirs: [
@@ -140,3 +141,10 @@
}
}
}
+
+filegroup {
+ name: "lib_networkStatsFactory_native",
+ srcs: [
+ "com_android_server_net_NetworkStatsFactory.cpp",
+ ],
+}
diff --git a/services/core/jni/com_android_server_TestNetworkService.cpp b/services/core/jni/com_android_server_TestNetworkService.cpp
index b90ff23..36a6fde 100644
--- a/services/core/jni/com_android_server_TestNetworkService.cpp
+++ b/services/core/jni/com_android_server_TestNetworkService.cpp
@@ -54,12 +54,12 @@
jniThrowException(env, "java/lang/IllegalStateException", msg.c_str());
}
-static int createTunInterface(JNIEnv* env, const char* iface) {
+static int createTunTapInterface(JNIEnv* env, bool isTun, const char* iface) {
base::unique_fd tun(open("/dev/tun", O_RDWR | O_NONBLOCK));
ifreq ifr{};
// Allocate interface.
- ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
+ ifr.ifr_flags = (isTun ? IFF_TUN : IFF_TAP) | IFF_NO_PI;
strlcpy(ifr.ifr_name, iface, IFNAMSIZ);
if (ioctl(tun.get(), TUNSETIFF, &ifr)) {
throwException(env, errno, "allocating", ifr.ifr_name);
@@ -80,23 +80,23 @@
//------------------------------------------------------------------------------
-static jint create(JNIEnv* env, jobject /* thiz */, jstring jIface) {
+static jint create(JNIEnv* env, jobject /* thiz */, jboolean isTun, jstring jIface) {
ScopedUtfChars iface(env, jIface);
if (!iface.c_str()) {
jniThrowNullPointerException(env, "iface");
return -1;
}
- int tun = createTunInterface(env, iface.c_str());
+ int tun = createTunTapInterface(env, isTun, iface.c_str());
- // Any exceptions will be thrown from the createTunInterface call
+ // Any exceptions will be thrown from the createTunTapInterface call
return tun;
}
//------------------------------------------------------------------------------
static const JNINativeMethod gMethods[] = {
- {"jniCreateTun", "(Ljava/lang/String;)I", (void*)create},
+ {"jniCreateTunTap", "(ZLjava/lang/String;)I", (void*)create},
};
int register_android_server_TestNetworkService(JNIEnv* env) {
diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp
similarity index 87%
rename from core/jni/com_android_internal_net_NetworkStatsFactory.cpp
rename to services/core/jni/com_android_server_net_NetworkStatsFactory.cpp
index 8259ffc..9cd743b 100644
--- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
+++ b/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp
@@ -21,9 +21,9 @@
#include <sys/stat.h>
#include <sys/types.h>
-#include <core_jni_helpers.h>
#include <jni.h>
+#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedUtfChars.h>
#include <nativehelper/ScopedLocalRef.h>
#include <nativehelper/ScopedPrimitiveArray.h>
@@ -333,29 +333,27 @@
(void*) readNetworkStatsDev },
};
-int register_com_android_internal_net_NetworkStatsFactory(JNIEnv* env) {
- int err = RegisterMethodsOrDie(env,
- "com/android/internal/net/NetworkStatsFactory", gMethods,
+int register_android_server_net_NetworkStatsFactory(JNIEnv* env) {
+ int err = jniRegisterNativeMethods(env, "com/android/server/net/NetworkStatsFactory", gMethods,
NELEM(gMethods));
+ gStringClass = env->FindClass("java/lang/String");
+ gStringClass = static_cast<jclass>(env->NewGlobalRef(gStringClass));
- gStringClass = FindClassOrDie(env, "java/lang/String");
- gStringClass = MakeGlobalRefOrDie(env, gStringClass);
-
- jclass clazz = FindClassOrDie(env, "android/net/NetworkStats");
- gNetworkStatsClassInfo.size = GetFieldIDOrDie(env, clazz, "size", "I");
- gNetworkStatsClassInfo.capacity = GetFieldIDOrDie(env, clazz, "capacity", "I");
- gNetworkStatsClassInfo.iface = GetFieldIDOrDie(env, clazz, "iface", "[Ljava/lang/String;");
- gNetworkStatsClassInfo.uid = GetFieldIDOrDie(env, clazz, "uid", "[I");
- gNetworkStatsClassInfo.set = GetFieldIDOrDie(env, clazz, "set", "[I");
- gNetworkStatsClassInfo.tag = GetFieldIDOrDie(env, clazz, "tag", "[I");
- gNetworkStatsClassInfo.metered = GetFieldIDOrDie(env, clazz, "metered", "[I");
- gNetworkStatsClassInfo.roaming = GetFieldIDOrDie(env, clazz, "roaming", "[I");
- gNetworkStatsClassInfo.defaultNetwork = GetFieldIDOrDie(env, clazz, "defaultNetwork", "[I");
- gNetworkStatsClassInfo.rxBytes = GetFieldIDOrDie(env, clazz, "rxBytes", "[J");
- gNetworkStatsClassInfo.rxPackets = GetFieldIDOrDie(env, clazz, "rxPackets", "[J");
- gNetworkStatsClassInfo.txBytes = GetFieldIDOrDie(env, clazz, "txBytes", "[J");
- gNetworkStatsClassInfo.txPackets = GetFieldIDOrDie(env, clazz, "txPackets", "[J");
- gNetworkStatsClassInfo.operations = GetFieldIDOrDie(env, clazz, "operations", "[J");
+ jclass clazz = env->FindClass("android/net/NetworkStats");
+ gNetworkStatsClassInfo.size = env->GetFieldID(clazz, "size", "I");
+ gNetworkStatsClassInfo.capacity = env->GetFieldID(clazz, "capacity", "I");
+ gNetworkStatsClassInfo.iface = env->GetFieldID(clazz, "iface", "[Ljava/lang/String;");
+ gNetworkStatsClassInfo.uid = env->GetFieldID(clazz, "uid", "[I");
+ gNetworkStatsClassInfo.set = env->GetFieldID(clazz, "set", "[I");
+ gNetworkStatsClassInfo.tag = env->GetFieldID(clazz, "tag", "[I");
+ gNetworkStatsClassInfo.metered = env->GetFieldID(clazz, "metered", "[I");
+ gNetworkStatsClassInfo.roaming = env->GetFieldID(clazz, "roaming", "[I");
+ gNetworkStatsClassInfo.defaultNetwork = env->GetFieldID(clazz, "defaultNetwork", "[I");
+ gNetworkStatsClassInfo.rxBytes = env->GetFieldID(clazz, "rxBytes", "[J");
+ gNetworkStatsClassInfo.rxPackets = env->GetFieldID(clazz, "rxPackets", "[J");
+ gNetworkStatsClassInfo.txBytes = env->GetFieldID(clazz, "txBytes", "[J");
+ gNetworkStatsClassInfo.txPackets = env->GetFieldID(clazz, "txPackets", "[J");
+ gNetworkStatsClassInfo.operations = env->GetFieldID(clazz, "operations", "[J");
return err;
}
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 83347bb..4b0bbae 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -54,6 +54,7 @@
int register_android_server_SyntheticPasswordManager(JNIEnv* env);
int register_android_server_GraphicsStatsService(JNIEnv* env);
int register_android_hardware_display_DisplayViewport(JNIEnv* env);
+int register_android_server_net_NetworkStatsFactory(JNIEnv* env);
int register_android_server_net_NetworkStatsService(JNIEnv* env);
};
@@ -102,6 +103,7 @@
register_android_server_SyntheticPasswordManager(env);
register_android_server_GraphicsStatsService(env);
register_android_hardware_display_DisplayViewport(env);
+ register_android_server_net_NetworkStatsFactory(env);
register_android_server_net_NetworkStatsService(env);
return JNI_VERSION_1_4;
}
diff --git a/packages/NetworkStackPermissionStub/Android.bp b/services/core/xsd/vts/Android.bp
similarity index 60%
copy from packages/NetworkStackPermissionStub/Android.bp
copy to services/core/xsd/vts/Android.bp
index 8cee92e..967750d 100644
--- a/packages/NetworkStackPermissionStub/Android.bp
+++ b/services/core/xsd/vts/Android.bp
@@ -14,15 +14,20 @@
// limitations under the License.
//
-// Stub APK to define permissions for NetworkStack
-android_app {
- name: "NetworkStackPermissionStub",
- // TODO: mark app as hasCode=false in manifest once soong stops complaining about apps without
- // a classes.dex.
- srcs: ["src/**/*.java"],
- platform_apis: true,
- min_sdk_version: "28",
- certificate: "networkstack",
- privileged: true,
- manifest: "AndroidManifest.xml",
+cc_test {
+ name: "vts_defaultPermissions_validate_test",
+ srcs: [
+ "ValidateDefaultPermissions.cpp"
+ ],
+ static_libs: [
+ "android.hardware.audio.common.test.utility",
+ "libxml2",
+ ],
+ shared_libs: [
+ "liblog",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
}
diff --git a/location/Android.mk b/services/core/xsd/vts/Android.mk
similarity index 76%
copy from location/Android.mk
copy to services/core/xsd/vts/Android.mk
index 50509c6..6dc2c43 100644
--- a/location/Android.mk
+++ b/services/core/xsd/vts/Android.mk
@@ -1,4 +1,5 @@
-# Copyright (C) 2010 The Android Open Source Project
+#
+# Copyright (C) 2019 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.
@@ -11,7 +12,11 @@
# 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.
+#
LOCAL_PATH := $(call my-dir)
-include $(call all-subdir-makefiles, $(LOCAL_PATH))
\ No newline at end of file
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := VtsValidateDefaultPermissions
+include test/vts/tools/build/Android.host_config.mk
diff --git a/services/core/xsd/vts/AndroidTest.xml b/services/core/xsd/vts/AndroidTest.xml
new file mode 100644
index 0000000..4f3b2ef
--- /dev/null
+++ b/services/core/xsd/vts/AndroidTest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<configuration description="Config for VTS VtsValidateDefaultPermissions.">
+ <option name="config-descriptor:metadata" key="plan" value="vts-treble" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.VtsFilePusher">
+ <option name="abort-on-push-failure" value="false"/>
+ <option name="push-group" value="HostDrivenTest.push"/>
+ <option name="push" value="DATA/etc/default-permissions.xsd->/data/local/tmp/default-permissions.xsd"/>
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.VtsMultiDeviceTest">
+ <option name="test-module-name" value="VtsValidateDefaultPermissions"/>
+ <option name="binary-test-source" value="_32bit::DATA/nativetest/vts_defaultPermissions_validate_test/vts_defaultPermissions_validate_test" />
+ <option name="binary-test-source" value="_64bit::DATA/nativetest64/vts_defaultPermissions_validate_test/vts_defaultPermissions_validate_test" />
+ <option name="binary-test-type" value="gtest"/>
+ <option name="test-timeout" value="30s"/>
+ </test>
+</configuration>
diff --git a/services/core/xsd/vts/ValidateDefaultPermissions.cpp b/services/core/xsd/vts/ValidateDefaultPermissions.cpp
new file mode 100644
index 0000000..54c115b
--- /dev/null
+++ b/services/core/xsd/vts/ValidateDefaultPermissions.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "utility/ValidateXml.h"
+
+TEST(CheckConfig, mediaDefaultPermissions) {
+ RecordProperty("description",
+ "Verify that the default-permissions file "
+ "is valid according to the schema");
+
+ const char* location = "/vendor/etc/default-permissions";
+
+ EXPECT_ONE_VALID_XML_MULTIPLE_LOCATIONS("default-permissions.xml", {location},
+ "/data/local/tmp/default-permissions.xsd");
+}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index ed5928f..7be7ab2 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1924,6 +1924,11 @@
traceBeginAndSlog("StartNetworkStack");
try {
+ // Note : the network stack is creating on-demand objects that need to send
+ // broadcasts, which means it currently depends on being started after
+ // ActivityManagerService.mSystemReady and ActivityManagerService.mProcessesReady
+ // are set to true. Be careful if moving this to a different place in the
+ // startup sequence.
NetworkStackClient.getInstance().start(context);
} catch (Throwable e) {
reportWtf("starting Network Stack", e);
diff --git a/services/net/java/android/net/INetworkMonitor.aidl b/services/net/java/android/net/INetworkMonitor.aidl
index 1b0e1d7..b32ef12 100644
--- a/services/net/java/android/net/INetworkMonitor.aidl
+++ b/services/net/java/android/net/INetworkMonitor.aidl
@@ -15,6 +15,8 @@
*/
package android.net;
+import android.net.LinkProperties;
+import android.net.NetworkCapabilities;
import android.net.PrivateDnsConfigParcel;
/** @hide */
@@ -45,9 +47,8 @@
void forceReevaluation(int uid);
void notifyPrivateDnsChanged(in PrivateDnsConfigParcel config);
void notifyDnsResponse(int returnCode);
- void notifySystemReady();
- void notifyNetworkConnected();
+ void notifyNetworkConnected(in LinkProperties lp, in NetworkCapabilities nc);
void notifyNetworkDisconnected();
- void notifyLinkPropertiesChanged();
- void notifyNetworkCapabilitiesChanged();
-}
\ No newline at end of file
+ void notifyLinkPropertiesChanged(in LinkProperties lp);
+ void notifyNetworkCapabilitiesChanged(in NetworkCapabilities nc);
+}
diff --git a/services/net/java/android/net/NetworkStackClient.java b/services/net/java/android/net/NetworkStackClient.java
index 7befd087..6b5842f 100644
--- a/services/net/java/android/net/NetworkStackClient.java
+++ b/services/net/java/android/net/NetworkStackClient.java
@@ -32,6 +32,7 @@
import android.net.ip.IIpClientCallbacks;
import android.net.util.SharedLog;
import android.os.Binder;
+import android.os.Build;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
@@ -148,14 +149,18 @@
private class NetworkStackConnection implements ServiceConnection {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
- log("Network stack service connected");
+ logi("Network stack service connected");
registerNetworkStackService(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
- // TODO: crash/reboot the system ?
- logWtf("Lost network stack connector", null);
+ // The system has lost its network stack (probably due to a crash in the
+ // network stack process): better crash rather than stay in a bad state where all
+ // networking is broken.
+ // onServiceDisconnected is not being called on device shutdown, so this method being
+ // called always indicates a bad state for the system server.
+ maybeCrashWithTerribleFailure("Lost network stack");
}
};
@@ -211,8 +216,7 @@
}
if (intent == null) {
- logWtf("Could not resolve the network stack", null);
- // TODO: crash/reboot system server ?
+ maybeCrashWithTerribleFailure("Could not resolve the network stack");
return;
}
@@ -220,9 +224,9 @@
// NetworkStackConnection.onServiceConnected().
if (!context.bindServiceAsUser(intent, new NetworkStackConnection(),
Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, UserHandle.SYSTEM)) {
- logWtf("Could not bind to network stack with " + intent, null);
+ maybeCrashWithTerribleFailure(
+ "Could not bind to network stack in-process, or in app with " + intent);
return;
- // TODO: crash/reboot system server if no network stack after a timeout ?
}
log("Network stack service start requested");
@@ -270,6 +274,16 @@
}
}
+ private void maybeCrashWithTerribleFailure(@NonNull String message) {
+ logWtf(message, null);
+ if (Build.IS_DEBUGGABLE) {
+ throw new IllegalStateException(message);
+ }
+ }
+
+ /**
+ * Log a message in the local log.
+ */
private void log(@NonNull String message) {
synchronized (mLog) {
mLog.log(message);
@@ -290,6 +304,15 @@
}
/**
+ * Log a message in the local and system logs.
+ */
+ private void logi(@NonNull String message) {
+ synchronized (mLog) {
+ mLog.i(message);
+ }
+ }
+
+ /**
* For non-system server clients, get the connector registered by the system server.
*/
private INetworkStackConnector getRemoteConnector() {
diff --git a/services/net/java/android/net/ip/IIpClient.aidl b/services/net/java/android/net/ip/IIpClient.aidl
index b834e45..1e77264 100644
--- a/services/net/java/android/net/ip/IIpClient.aidl
+++ b/services/net/java/android/net/ip/IIpClient.aidl
@@ -32,4 +32,5 @@
void setMulticastFilter(boolean enabled);
void addKeepalivePacketFilter(int slot, in TcpKeepalivePacketDataParcelable pkt);
void removeKeepalivePacketFilter(int slot);
+ void setL2KeyAndGroupHint(in String l2Key, in String groupHint);
}
diff --git a/services/net/java/android/net/ipmemorystore/NetworkAttributes.java b/services/net/java/android/net/ipmemorystore/NetworkAttributes.java
index 6a9eae0..e769769 100644
--- a/services/net/java/android/net/ipmemorystore/NetworkAttributes.java
+++ b/services/net/java/android/net/ipmemorystore/NetworkAttributes.java
@@ -60,6 +60,13 @@
public final Inet4Address assignedV4Address;
private static final float WEIGHT_ASSIGNEDV4ADDR = 300.0f;
+ // The lease expiry timestamp of v4 address allocated from DHCP server, in milliseconds.
+ @Nullable
+ public final Long assignedV4AddressExpiry;
+ // lease expiry doesn't imply any correlation between "the same lease expiry value" and "the
+ // same L3 network".
+ private static final float WEIGHT_ASSIGNEDV4ADDREXPIRY = 0.0f;
+
// Optionally supplied by the client if it has an opinion on L3 network. For example, this
// could be a hash of the SSID + security type on WiFi.
@Nullable
@@ -81,6 +88,7 @@
/** @hide */
@VisibleForTesting
public static final float TOTAL_WEIGHT = WEIGHT_ASSIGNEDV4ADDR
+ + WEIGHT_ASSIGNEDV4ADDREXPIRY
+ WEIGHT_GROUPHINT
+ WEIGHT_DNSADDRESSES
+ WEIGHT_MTU;
@@ -89,11 +97,16 @@
@VisibleForTesting
public NetworkAttributes(
@Nullable final Inet4Address assignedV4Address,
+ @Nullable final Long assignedV4AddressExpiry,
@Nullable final String groupHint,
@Nullable final List<InetAddress> dnsAddresses,
@Nullable final Integer mtu) {
if (mtu != null && mtu < 0) throw new IllegalArgumentException("MTU can't be negative");
+ if (assignedV4AddressExpiry != null && assignedV4AddressExpiry <= 0) {
+ throw new IllegalArgumentException("lease expiry can't be negative or zero");
+ }
this.assignedV4Address = assignedV4Address;
+ this.assignedV4AddressExpiry = assignedV4AddressExpiry;
this.groupHint = groupHint;
this.dnsAddresses = null == dnsAddresses ? null :
Collections.unmodifiableList(new ArrayList<>(dnsAddresses));
@@ -105,6 +118,8 @@
// The call to the other constructor must be the first statement of this constructor,
// so everything has to be inline
this((Inet4Address) getByAddressOrNull(parcelable.assignedV4Address),
+ parcelable.assignedV4AddressExpiry > 0
+ ? parcelable.assignedV4AddressExpiry : null,
parcelable.groupHint,
blobArrayToInetAddressList(parcelable.dnsAddresses),
parcelable.mtu >= 0 ? parcelable.mtu : null);
@@ -150,6 +165,8 @@
final NetworkAttributesParcelable parcelable = new NetworkAttributesParcelable();
parcelable.assignedV4Address =
(null == assignedV4Address) ? null : assignedV4Address.getAddress();
+ parcelable.assignedV4AddressExpiry =
+ (null == assignedV4AddressExpiry) ? 0 : assignedV4AddressExpiry;
parcelable.groupHint = groupHint;
parcelable.dnsAddresses = inetAddressListToBlobArray(dnsAddresses);
parcelable.mtu = (null == mtu) ? -1 : mtu;
@@ -168,6 +185,8 @@
public float getNetworkGroupSamenessConfidence(@NonNull final NetworkAttributes o) {
final float samenessScore =
samenessContribution(WEIGHT_ASSIGNEDV4ADDR, assignedV4Address, o.assignedV4Address)
+ + samenessContribution(WEIGHT_ASSIGNEDV4ADDREXPIRY, assignedV4AddressExpiry,
+ o.assignedV4AddressExpiry)
+ samenessContribution(WEIGHT_GROUPHINT, groupHint, o.groupHint)
+ samenessContribution(WEIGHT_DNSADDRESSES, dnsAddresses, o.dnsAddresses)
+ samenessContribution(WEIGHT_MTU, mtu, o.mtu);
@@ -189,6 +208,8 @@
@Nullable
private Inet4Address mAssignedAddress;
@Nullable
+ private Long mAssignedAddressExpiry;
+ @Nullable
private String mGroupHint;
@Nullable
private List<InetAddress> mDnsAddresses;
@@ -206,6 +227,20 @@
}
/**
+ * Set the lease expiry timestamp of assigned v4 address.
+ * @param assignedV4AddressExpiry The lease expiry timestamp of assigned v4 address.
+ * @return This builder.
+ */
+ public Builder setAssignedV4AddressExpiry(
+ @Nullable final Long assignedV4AddressExpiry) {
+ if (null != assignedV4AddressExpiry && assignedV4AddressExpiry <= 0) {
+ throw new IllegalArgumentException("lease expiry can't be negative or zero");
+ }
+ mAssignedAddressExpiry = assignedV4AddressExpiry;
+ return this;
+ }
+
+ /**
* Set the group hint.
* @param groupHint The group hint.
* @return This builder.
@@ -248,14 +283,15 @@
* @return The built NetworkAttributes object.
*/
public NetworkAttributes build() {
- return new NetworkAttributes(mAssignedAddress, mGroupHint, mDnsAddresses, mMtu);
+ return new NetworkAttributes(mAssignedAddress, mAssignedAddressExpiry,
+ mGroupHint, mDnsAddresses, mMtu);
}
}
/** @hide */
public boolean isEmpty() {
- return (null == assignedV4Address) && (null == groupHint)
- && (null == dnsAddresses) && (null == mtu);
+ return (null == assignedV4Address) && (null == assignedV4AddressExpiry)
+ && (null == groupHint) && (null == dnsAddresses) && (null == mtu);
}
@Override
@@ -263,6 +299,7 @@
if (!(o instanceof NetworkAttributes)) return false;
final NetworkAttributes other = (NetworkAttributes) o;
return Objects.equals(assignedV4Address, other.assignedV4Address)
+ && Objects.equals(assignedV4AddressExpiry, other.assignedV4AddressExpiry)
&& Objects.equals(groupHint, other.groupHint)
&& Objects.equals(dnsAddresses, other.dnsAddresses)
&& Objects.equals(mtu, other.mtu);
@@ -270,7 +307,8 @@
@Override
public int hashCode() {
- return Objects.hash(assignedV4Address, groupHint, dnsAddresses, mtu);
+ return Objects.hash(assignedV4Address, assignedV4AddressExpiry,
+ groupHint, dnsAddresses, mtu);
}
/** Pretty print */
@@ -286,6 +324,13 @@
nullFields.add("assignedV4Addr");
}
+ if (null != assignedV4AddressExpiry) {
+ resultJoiner.add("assignedV4AddressExpiry :");
+ resultJoiner.add(assignedV4AddressExpiry.toString());
+ } else {
+ nullFields.add("assignedV4AddressExpiry");
+ }
+
if (null != groupHint) {
resultJoiner.add("groupHint :");
resultJoiner.add(groupHint);
diff --git a/services/net/java/android/net/ipmemorystore/NetworkAttributesParcelable.aidl b/services/net/java/android/net/ipmemorystore/NetworkAttributesParcelable.aidl
index 0894d72..997eb2b 100644
--- a/services/net/java/android/net/ipmemorystore/NetworkAttributesParcelable.aidl
+++ b/services/net/java/android/net/ipmemorystore/NetworkAttributesParcelable.aidl
@@ -30,6 +30,7 @@
*/
parcelable NetworkAttributesParcelable {
byte[] assignedV4Address;
+ long assignedV4AddressExpiry;
String groupHint;
Blob[] dnsAddresses;
int mtu;
diff --git a/services/net/java/android/net/netlink/NetlinkSocket.java b/services/net/java/android/net/netlink/NetlinkSocket.java
index 4240d24..7311fc5 100644
--- a/services/net/java/android/net/netlink/NetlinkSocket.java
+++ b/services/net/java/android/net/netlink/NetlinkSocket.java
@@ -30,6 +30,7 @@
import android.net.util.SocketUtils;
import android.system.ErrnoException;
import android.system.Os;
+import android.system.StructTimeval;
import android.util.Log;
import java.io.FileDescriptor;
@@ -128,7 +129,7 @@
throws ErrnoException, IllegalArgumentException, InterruptedIOException {
checkTimeout(timeoutMs);
- SocketUtils.setSocketTimeValueOption(fd, SOL_SOCKET, SO_RCVTIMEO, timeoutMs);
+ Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(timeoutMs));
ByteBuffer byteBuffer = ByteBuffer.allocate(bufsize);
int length = Os.read(fd, byteBuffer);
@@ -151,7 +152,7 @@
FileDescriptor fd, byte[] bytes, int offset, int count, long timeoutMs)
throws ErrnoException, IllegalArgumentException, InterruptedIOException {
checkTimeout(timeoutMs);
- SocketUtils.setSocketTimeValueOption(fd, SOL_SOCKET, SO_SNDTIMEO, timeoutMs);
+ Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(timeoutMs));
return Os.write(fd, bytes, offset, count);
}
}
diff --git a/services/net/java/android/net/shared/NetworkMonitorUtils.java b/services/net/java/android/net/shared/NetworkMonitorUtils.java
index a17cb464..bb4a603 100644
--- a/services/net/java/android/net/shared/NetworkMonitorUtils.java
+++ b/services/net/java/android/net/shared/NetworkMonitorUtils.java
@@ -21,9 +21,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
-import android.content.Context;
import android.net.NetworkCapabilities;
-import android.provider.Settings;
/** @hide */
public class NetworkMonitorUtils {
@@ -45,16 +43,6 @@
"android.permission.ACCESS_NETWORK_CONDITIONS";
/**
- * Get the captive portal server HTTP URL that is configured on the device.
- */
- public static String getCaptivePortalServerHttpUrl(Context context, String defaultUrl) {
- final String settingUrl = Settings.Global.getString(
- context.getContentResolver(),
- Settings.Global.CAPTIVE_PORTAL_HTTP_URL);
- return settingUrl != null ? settingUrl : defaultUrl;
- }
-
- /**
* Return whether validation is required for a network.
* @param dfltNetCap Default requested network capabilities.
* @param nc Network capabilities of the network to test.
diff --git a/startop/iorap/tests/Android.bp b/startop/iorap/tests/Android.bp
index 7605784..2b810f3 100644
--- a/startop/iorap/tests/Android.bp
+++ b/startop/iorap/tests/Android.bp
@@ -16,7 +16,6 @@
java_library {
name: "libiorap-java-test-lib",
srcs: ["src/**/*.kt"],
-
static_libs: [
// non-test dependencies
"libiorap-java",
@@ -28,13 +27,33 @@
// "mockito-target-minus-junit4",
// Mockito also requires JNI (see Android.mk)
// and android:debuggable=true (see AndroidManifest.xml)
- "truth-prebuilt",
+ "truth-prebuilt",
],
-
// sdk_version: "current",
// certificate: "platform",
-
- libs: ["android.test.base", "android.test.runner"],
-
+ libs: [
+ "android.test.base",
+ "android.test.runner",
+ ],
// test_suites: ["device-tests"],
}
+
+android_test {
+ name: "libiorap-java-tests",
+ dxflags: ["--multi-dex"],
+ test_suites: ["device-tests"],
+ static_libs: ["libiorap-java-test-lib"],
+ compile_multilib: "both",
+ jni_libs: [
+ "libdexmakerjvmtiagent",
+ "libstaticjvmtiagent",
+ "libmultiplejvmtiagentsinterferenceagent",
+ ],
+ libs: [
+ "android.test.base",
+ "android.test.runner",
+ ],
+ // Use private APIs
+ certificate: "platform",
+ platform_apis: true,
+}
diff --git a/startop/iorap/tests/Android.mk b/startop/iorap/tests/Android.mk
deleted file mode 100644
index 1b2aa46..0000000
--- a/startop/iorap/tests/Android.mk
+++ /dev/null
@@ -1,46 +0,0 @@
-# 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.
-
-# android_test does not support JNI libraries
-# TODO: once b/80095087 is fixed, rewrite this back to android_test
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_JACK_FLAGS := --multi-dex native
-LOCAL_DX_FLAGS := --multi-dex
-
-LOCAL_PACKAGE_NAME := libiorap-java-tests
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- libiorap-java-test-lib
-
-LOCAL_MULTILIB := both
-
-LOCAL_JNI_SHARED_LIBRARIES := \
- libdexmakerjvmtiagent \
- libstaticjvmtiagent \
- libmultiplejvmtiagentsinterferenceagent
-
-LOCAL_JAVA_LIBRARIES := \
- android.test.base \
- android.test.runner
-
-# Use private APIs
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-include $(BUILD_PACKAGE)
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index dcaa499..9adeea0 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -542,7 +542,6 @@
private final Bundle mExtras;
private final Bundle mIntentExtras;
private final long mCreationTimeMillis;
- private final CallIdentification mCallIdentification;
private final @CallDirection int mCallDirection;
/**
@@ -728,8 +727,6 @@
* The display name for the caller.
* <p>
* This is the name as reported by the {@link ConnectionService} associated with this call.
- * The name reported by a {@link CallScreeningService} can be retrieved using
- * {@link CallIdentification#getName()}.
*
* @return The display name for the caller.
*/
@@ -847,23 +844,6 @@
}
/**
- * Returns {@link CallIdentification} information provided by a
- * {@link CallScreeningService} for this call.
- * <p>
- * {@link InCallService} implementations should display the {@link CallIdentification} for
- * calls. The name of the call screening service is provided in
- * {@link CallIdentification#getCallScreeningAppName()} and should be used to attribute the
- * call identification information.
- *
- * @return The {@link CallIdentification} if it was provided by a
- * {@link CallScreeningService}, or {@code null} if no {@link CallScreeningService} has
- * provided {@link CallIdentification} information for the call.
- */
- public @Nullable CallIdentification getCallIdentification() {
- return mCallIdentification;
- }
-
- /**
* Indicates whether the call is an incoming or outgoing call.
* @return The call's direction.
*/
@@ -892,7 +872,6 @@
areBundlesEqual(mExtras, d.mExtras) &&
areBundlesEqual(mIntentExtras, d.mIntentExtras) &&
Objects.equals(mCreationTimeMillis, d.mCreationTimeMillis) &&
- Objects.equals(mCallIdentification, d.mCallIdentification) &&
Objects.equals(mCallDirection, d.mCallDirection);
}
return false;
@@ -915,7 +894,6 @@
mExtras,
mIntentExtras,
mCreationTimeMillis,
- mCallIdentification,
mCallDirection);
}
@@ -937,7 +915,6 @@
Bundle extras,
Bundle intentExtras,
long creationTimeMillis,
- CallIdentification callIdentification,
int callDirection) {
mTelecomCallId = telecomCallId;
mHandle = handle;
@@ -955,7 +932,6 @@
mExtras = extras;
mIntentExtras = intentExtras;
mCreationTimeMillis = creationTimeMillis;
- mCallIdentification = callIdentification;
mCallDirection = callDirection;
}
@@ -978,7 +954,6 @@
parcelableCall.getExtras(),
parcelableCall.getIntentExtras(),
parcelableCall.getCreationTimeMillis(),
- parcelableCall.getCallIdentification(),
parcelableCall.getCallDirection());
}
diff --git a/telecomm/java/android/telecom/CallIdentification.aidl b/telecomm/java/android/telecom/CallIdentification.aidl
deleted file mode 100644
index 532535c..0000000
--- a/telecomm/java/android/telecom/CallIdentification.aidl
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright 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.telecom;
-
-/**
- * {@hide}
- */
-parcelable CallIdentification;
diff --git a/telecomm/java/android/telecom/CallIdentification.java b/telecomm/java/android/telecom/CallIdentification.java
deleted file mode 100644
index fffc123..0000000
--- a/telecomm/java/android/telecom/CallIdentification.java
+++ /dev/null
@@ -1,451 +0,0 @@
-/*
- * 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.telecom;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.pm.ApplicationInfo;
-import android.graphics.drawable.Icon;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.Objects;
-
-/**
- * Encapsulates information about an incoming or outgoing {@link Call} provided by a
- * {@link CallScreeningService}.
- * <p>
- * Call identified information is consumed by the {@link InCallService dialer} app to provide the
- * user with more information about a call. This can include information such as the name of the
- * caller, address, etc. Call identification information is persisted to the
- * {@link android.provider.CallLog}.
- */
-public final class CallIdentification implements Parcelable {
- /**
- * Builder for {@link CallIdentification} instances.
- * <p>
- * A {@link CallScreeningService} uses this class to create new instances of
- * {@link CallIdentification} for a screened call.
- */
- public final static class Builder {
- private CharSequence mName;
- private CharSequence mDescription;
- private CharSequence mDetails;
- private Icon mPhoto;
- private int mNuisanceConfidence = CallIdentification.CONFIDENCE_UNKNOWN;
- private String mPackageName;
- private CharSequence mAppName;
-
- /**
- * Default builder constructor.
- */
- public Builder() {
- // Default constructor
- }
-
- /**
- * Create instance of call identification with specified package/app name.
- *
- * @param callIdPackageName The package name.
- * @param callIdAppName The app name.
- * @hide
- */
- public Builder(@NonNull String callIdPackageName, @NonNull CharSequence callIdAppName) {
- mPackageName = callIdPackageName;
- mAppName = callIdAppName;
- }
-
- /**
- * Sets the name associated with the {@link CallIdentification} being built.
- * <p>
- * Could be a business name, for example.
- *
- * @param name The name associated with the call, or {@code null} if none is provided.
- * @return Builder instance.
- */
- public @NonNull Builder setName(@Nullable CharSequence name) {
- mName = name;
- return this;
- }
-
- /**
- * Sets the description associated with the {@link CallIdentification} being built.
- * <p>
- * A description of the call as identified by a {@link CallScreeningService}. The
- * description is typically presented by Dialer apps after the
- * {@link CallIdentification#getName() name} to provide a short piece of relevant
- * information about the call. This could include a location, address, or a message
- * regarding the potential nature of the call (e.g. potential telemarketer).
- *
- * @param description The call description, or {@code null} if none is provided.
- * @return Builder instance.
- */
- public @NonNull Builder setDescription(@Nullable CharSequence description) {
- mDescription = description;
- return this;
- }
-
- /**
- * Sets the details associated with the {@link CallIdentification} being built.
- * <p>
- * The details is typically presented by Dialer apps after the
- * {@link CallIdentification#getName() name} and
- * {@link CallIdentification#getDescription() description} to provide further clarifying
- * information about the call. This could include, for example, the opening hours of a
- * business, or a stats about the number of times a call has been reported as spam.
- *
- * @param details The call details, or {@code null} if none is provided.
- * @return Builder instance.
- */
-
- public @NonNull Builder setDetails(@Nullable CharSequence details) {
- mDetails = details;
- return this;
- }
-
- /**
- * Sets the photo associated with the {@link CallIdentification} being built.
- * <p>
- * This could be, for example, a business logo, or a photo of the caller.
- *
- * @param photo The photo associated with the call, or {@code null} if none was provided.
- * @return Builder instance.
- */
- public @NonNull Builder setPhoto(@Nullable Icon photo) {
- mPhoto = photo;
- return this;
- }
-
- /**
- * Sets the nuisance confidence with the {@link CallIdentification} being built.
- * <p>
- * This can be used to specify how confident the {@link CallScreeningService} is that a call
- * is or is not a nuisance call.
- *
- * @param nuisanceConfidence The nuisance confidence.
- * @return The builder.
- */
- public @NonNull Builder setNuisanceConfidence(@NuisanceConfidence int nuisanceConfidence) {
- mNuisanceConfidence = nuisanceConfidence;
- return this;
- }
-
- /**
- * Creates a new instance of {@link CallIdentification} based on the parameters set in this
- * builder.
- *
- * @return {@link CallIdentification} instance.
- */
- public @NonNull CallIdentification build() {
- return new CallIdentification(mName, mDescription, mDetails, mPhoto,
- mNuisanceConfidence, mPackageName, mAppName);
- }
- }
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(
- prefix = { "CONFIDENCE_" },
- value = {CONFIDENCE_NUISANCE, CONFIDENCE_LIKELY_NUISANCE, CONFIDENCE_UNKNOWN,
- CONFIDENCE_LIKELY_NOT_NUISANCE, CONFIDENCE_NOT_NUISANCE})
- public @interface NuisanceConfidence {}
-
- /**
- * Call has been identified as a nuisance call.
- * <p>
- * Returned from {@link #getNuisanceConfidence()} to indicate that a
- * {@link CallScreeningService} to indicate how confident it is that a call is or is not a
- * nuisance call.
- */
- public static final int CONFIDENCE_NUISANCE = 2;
-
- /**
- * Call has been identified as a likely nuisance call.
- * <p>
- * Returned from {@link #getNuisanceConfidence()} to indicate that a
- * {@link CallScreeningService} to indicate how confident it is that a call is or is not a
- * nuisance call.
- */
- public static final int CONFIDENCE_LIKELY_NUISANCE = 1;
-
- /**
- * Call could not be classified as nuisance or non-nuisance.
- * <p>
- * Returned from {@link #getNuisanceConfidence()} to indicate that a
- * {@link CallScreeningService} to indicate how confident it is that a call is or is not a
- * nuisance call.
- */
- public static final int CONFIDENCE_UNKNOWN = 0;
-
- /**
- * Call has been identified as not likely to be a nuisance call.
- * <p>
- * Returned from {@link #getNuisanceConfidence()} to indicate that a
- * {@link CallScreeningService} to indicate how confident it is that a call is or is not a
- * nuisance call.
- */
- public static final int CONFIDENCE_LIKELY_NOT_NUISANCE = -1;
-
- /**
- * Call has been identified as not a nuisance call.
- * <p>
- * Returned from {@link #getNuisanceConfidence()} to indicate that a
- * {@link CallScreeningService} to indicate how confident it is that a call is or is not a
- * nuisance call.
- */
- public static final int CONFIDENCE_NOT_NUISANCE = -2;
-
- /**
- * Default constructor for {@link CallIdentification}.
- *
- * @param name The name.
- * @param description The description.
- * @param details The details.
- * @param photo The photo.
- * @param nuisanceConfidence Confidence that this is a nuisance call.
- * @hide
- */
- private CallIdentification(@Nullable String name, @Nullable String description,
- @Nullable String details, @Nullable Icon photo,
- @NuisanceConfidence int nuisanceConfidence) {
- this(name, description, details, photo, nuisanceConfidence, null, null);
- }
-
- /**
- * Default constructor for {@link CallIdentification}.
- *
- * @param name The name.
- * @param description The description.
- * @param details The details.
- * @param photo The photo.
- * @param nuisanceConfidence Confidence that this is a nuisance call.
- * @param callScreeningPackageName Package name of the {@link CallScreeningService} which
- * provided the call identification.
- * @param callScreeningAppName App name of the {@link CallScreeningService} which provided the
- * call identification.
- * @hide
- */
- private CallIdentification(@Nullable CharSequence name, @Nullable CharSequence description,
- @Nullable CharSequence details, @Nullable Icon photo,
- @NuisanceConfidence int nuisanceConfidence, @NonNull String callScreeningPackageName,
- @NonNull CharSequence callScreeningAppName) {
- mName = name;
- mDescription = description;
- mDetails = details;
- mPhoto = photo;
- mNuisanceConfidence = nuisanceConfidence;
- mCallScreeningAppName = callScreeningAppName;
- mCallScreeningPackageName = callScreeningPackageName;
- }
-
- private CharSequence mName;
- private CharSequence mDescription;
- private CharSequence mDetails;
- private Icon mPhoto;
- private int mNuisanceConfidence;
- private String mCallScreeningPackageName;
- private CharSequence mCallScreeningAppName;
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel parcel, int i) {
- parcel.writeCharSequence(mName);
- parcel.writeCharSequence(mDescription);
- parcel.writeCharSequence(mDetails);
- parcel.writeParcelable(mPhoto, 0);
- parcel.writeInt(mNuisanceConfidence);
- parcel.writeString(mCallScreeningPackageName);
- parcel.writeCharSequence(mCallScreeningAppName);
- }
-
- /**
- * Responsible for creating CallIdentification objects for deserialized Parcels.
- */
- public static final Parcelable.Creator<CallIdentification> CREATOR =
- new Parcelable.Creator<CallIdentification> () {
-
- @Override
- public CallIdentification createFromParcel(Parcel source) {
- CharSequence name = source.readCharSequence();
- CharSequence description = source.readCharSequence();
- CharSequence details = source.readCharSequence();
- Icon photo = source.readParcelable(ClassLoader.getSystemClassLoader());
- int nuisanceConfidence = source.readInt();
- String callScreeningPackageName = source.readString();
- CharSequence callScreeningAppName = source.readCharSequence();
- return new CallIdentification(name, description, details, photo,
- nuisanceConfidence, callScreeningPackageName, callScreeningAppName);
- }
-
- @Override
- public CallIdentification[] newArray(int size) {
- return new CallIdentification[size];
- }
- };
-
- /**
- * The name associated with the number.
- * <p>
- * The name of the call as identified by a {@link CallScreeningService}. Could be a business
- * name, for example.
- *
- * @return The name associated with the number, or {@code null} if none was provided.
- */
- public final @Nullable CharSequence getName() {
- return mName;
- }
-
- /**
- * Description of the call.
- * <p>
- * A description of the call as identified by a {@link CallScreeningService}. The description
- * is typically presented by Dialer apps after the {@link #getName() name} to provide a short
- * piece of relevant information about the call. This could include a location, address, or a
- * message regarding the potential nature of the call (e.g. potential telemarketer).
- *
- * @return The call description, or {@code null} if none was provided.
- */
- public final @Nullable CharSequence getDescription() {
- return mDescription;
- }
-
- /**
- * Details of the call.
- * <p>
- * Details of the call as identified by a {@link CallScreeningService}. The details
- * are typically presented by Dialer apps after the {@link #getName() name} and
- * {@link #getDescription() description} to provide further clarifying information about the
- * call. This could include, for example, the opening hours of a business, or stats about
- * the number of times a call has been reported as spam.
- *
- * @return The call details, or {@code null} if none was provided.
- */
- public final @Nullable CharSequence getDetails() {
- return mDetails;
- }
-
- /**
- * Photo associated with the call.
- * <p>
- * A photo associated with the call as identified by a {@link CallScreeningService}. This
- * could be, for example, a business logo, or a photo of the caller.
- *
- * @return The photo associated with the call, or {@code null} if none was provided.
- */
- public final @Nullable Icon getPhoto() {
- return mPhoto;
- }
-
- /**
- * Indicates the likelihood that this call is a nuisance call.
- * <p>
- * How likely the call is a nuisance call, as identified by a {@link CallScreeningService}.
- *
- * @return The nuisance confidence.
- */
- public final @NuisanceConfidence int getNuisanceConfidence() {
- return mNuisanceConfidence;
- }
-
- /**
- * The package name of the {@link CallScreeningService} which provided the
- * {@link CallIdentification}.
- * <p>
- * A {@link CallScreeningService} may not set this property; it is set by the system.
- * @return the package name
- */
- public final @NonNull String getCallScreeningPackageName() {
- return mCallScreeningPackageName;
- }
-
- /**
- * The {@link android.content.pm.PackageManager#getApplicationLabel(ApplicationInfo) name} of
- * the {@link CallScreeningService} which provided the {@link CallIdentification}.
- * <p>
- * A {@link CallScreeningService} may not set this property; it is set by the system.
- *
- * @return The name of the app.
- */
- public final @NonNull CharSequence getCallScreeningAppName() {
- return mCallScreeningAppName;
- }
-
- /**
- * Set the package name of the {@link CallScreeningService} which provided this information.
- *
- * @param callScreeningPackageName The package name.
- * @hide
- */
- public void setCallScreeningPackageName(@NonNull String callScreeningPackageName) {
- mCallScreeningPackageName = callScreeningPackageName;
- }
-
- /**
- * Set the app name of the {@link CallScreeningService} which provided this information.
- *
- * @param callScreeningAppName The app name.
- * @hide
- */
- public void setCallScreeningAppName(@NonNull CharSequence callScreeningAppName) {
- mCallScreeningAppName = callScreeningAppName;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- CallIdentification that = (CallIdentification) o;
- // Note: mPhoto purposely omit as no good comparison exists.
- return mNuisanceConfidence == that.mNuisanceConfidence
- && Objects.equals(mName, that.mName)
- && Objects.equals(mDescription, that.mDescription)
- && Objects.equals(mDetails, that.mDetails)
- && Objects.equals(mCallScreeningAppName, that.mCallScreeningAppName)
- && Objects.equals(mCallScreeningPackageName, that.mCallScreeningPackageName);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mName, mDescription, mDetails, mPhoto, mNuisanceConfidence,
- mCallScreeningAppName, mCallScreeningPackageName);
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("[CallId mName=");
- sb.append(Log.pii(mName));
- sb.append(", mDesc=");
- sb.append(mDescription);
- sb.append(", mDet=");
- sb.append(mDetails);
- sb.append(", conf=");
- sb.append(mNuisanceConfidence);
- sb.append(", appName=");
- sb.append(mCallScreeningAppName);
- sb.append(", pkgName=");
- sb.append(mCallScreeningPackageName);
- return sb.toString();
- }
-}
diff --git a/telecomm/java/android/telecom/CallRedirectionService.java b/telecomm/java/android/telecom/CallRedirectionService.java
index d01c889..36c6377 100644
--- a/telecomm/java/android/telecom/CallRedirectionService.java
+++ b/telecomm/java/android/telecom/CallRedirectionService.java
@@ -119,20 +119,18 @@
* {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}. The response corresponds to the
* latest request via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
*
- * @param handle the new phone number to dial
+ * @param gatewayUri the gateway uri for call redirection.
* @param targetPhoneAccount the {@link PhoneAccountHandle} to use when placing the call.
- * If {@code null}, no change will be made to the
- * {@link PhoneAccountHandle} used to place the call.
* @param confirmFirst Telecom will ask users to confirm the redirection via a yes/no dialog
* if the confirmFirst is true, and if the redirection request of this
* response was sent with a true flag of allowInteractiveResponse via
* {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}
*/
- public final void redirectCall(@NonNull Uri handle,
+ public final void redirectCall(@NonNull Uri gatewayUri,
@NonNull PhoneAccountHandle targetPhoneAccount,
boolean confirmFirst) {
try {
- mCallRedirectionAdapter.redirectCall(handle, targetPhoneAccount, confirmFirst);
+ mCallRedirectionAdapter.redirectCall(gatewayUri, targetPhoneAccount, confirmFirst);
} catch (RemoteException e) {
e.rethrowAsRuntimeException();
}
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
index 818ebd9..27a8638 100644
--- a/telecomm/java/android/telecom/CallScreeningService.java
+++ b/telecomm/java/android/telecom/CallScreeningService.java
@@ -39,8 +39,8 @@
/**
* This service can be implemented by the default dialer (see
* {@link TelecomManager#getDefaultDialerPackage()}) or a third party app to allow or disallow
- * incoming calls before they are shown to a user. This service can also provide
- * {@link CallIdentification} information for calls.
+ * incoming calls before they are shown to a user. A {@link CallScreeningService} can also see
+ * outgoing calls for the purpose of providing caller ID services for those calls.
* <p>
* Below is an example manifest registration for a {@code CallScreeningService}.
* <pre>
@@ -58,9 +58,9 @@
* <ol>
* <li>Call blocking/screening - the service can choose which calls will ring on the user's
* device, and which will be silently sent to voicemail.</li>
- * <li>Call identification - the service can optionally provide {@link CallIdentification}
- * information about a {@link Call.Details call} which will be shown to the user in the
- * Dialer app.</li>
+ * <li>Call identification - services which provide call identification functionality can
+ * display a user-interface of their choosing which contains identifying information for a call.
+ * </li>
* </ol>
* <p>
* <h2>Becoming the {@link CallScreeningService}</h2>
@@ -92,128 +92,6 @@
* </pre>
*/
public abstract class CallScreeningService extends Service {
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(
- prefix = { "CALL_DURATION_" },
- value = {CALL_DURATION_VERY_SHORT, CALL_DURATION_SHORT, CALL_DURATION_MEDIUM,
- CALL_DURATION_LONG})
- public @interface CallDuration {}
-
- /**
- * Call duration reported with {@link #EXTRA_CALL_DURATION} to indicate to the
- * {@link CallScreeningService} the duration of a call for which the user reported the nuisance
- * status (see {@link TelecomManager#reportNuisanceCallStatus(Uri, boolean)}). The
- * {@link CallScreeningService} can use this as a signal for training nuisance detection
- * algorithms. The call duration is reported in coarse grained buckets to minimize exposure of
- * identifying call log information to the {@link CallScreeningService}.
- * <p>
- * Indicates the call was < 3 seconds in duration.
- */
- public static final int CALL_DURATION_VERY_SHORT = 1;
-
- /**
- * Call duration reported with {@link #EXTRA_CALL_DURATION} to indicate to the
- * {@link CallScreeningService} the duration of a call for which the user reported the nuisance
- * status (see {@link TelecomManager#reportNuisanceCallStatus(Uri, boolean)}). The
- * {@link CallScreeningService} can use this as a signal for training nuisance detection
- * algorithms. The call duration is reported in coarse grained buckets to minimize exposure of
- * identifying call log information to the {@link CallScreeningService}.
- * <p>
- * Indicates the call was greater than 3 seconds, but less than 60 seconds in duration.
- */
- public static final int CALL_DURATION_SHORT = 2;
-
- /**
- * Call duration reported with {@link #EXTRA_CALL_DURATION} to indicate to the
- * {@link CallScreeningService} the duration of a call for which the user reported the nuisance
- * status (see {@link TelecomManager#reportNuisanceCallStatus(Uri, boolean)}). The
- * {@link CallScreeningService} can use this as a signal for training nuisance detection
- * algorithms. The call duration is reported in coarse grained buckets to minimize exposure of
- * identifying call log information to the {@link CallScreeningService}.
- * <p>
- * Indicates the call was greater than 60 seconds, but less than 120 seconds in duration.
- */
- public static final int CALL_DURATION_MEDIUM = 3;
-
- /**
- * Call duration reported with {@link #EXTRA_CALL_DURATION} to indicate to the
- * {@link CallScreeningService} the duration of a call for which the user reported the nuisance
- * status (see {@link TelecomManager#reportNuisanceCallStatus(Uri, boolean)}). The
- * {@link CallScreeningService} can use this as a signal for training nuisance detection
- * algorithms. The call duration is reported in coarse grained buckets to minimize exposure of
- * identifying call log information to the {@link CallScreeningService}.
- * <p>
- * Indicates the call was greater than 120 seconds.
- */
- public static final int CALL_DURATION_LONG = 4;
-
- /**
- * Telecom sends this intent to the {@link CallScreeningService} which the user has chosen to
- * fill the call screening role when the user indicates through the default dialer whether a
- * call is a nuisance call or not (see
- * {@link TelecomManager#reportNuisanceCallStatus(Uri, boolean)}).
- * <p>
- * The following extra values are provided for the call:
- * <ol>
- * <li>{@link #EXTRA_CALL_HANDLE} - the handle of the call.</li>
- * <li>{@link #EXTRA_IS_NUISANCE} - {@code true} if the user reported the call as a nuisance
- * call, {@code false} otherwise.</li>
- * <li>{@link #EXTRA_CALL_TYPE} - reports the type of call (incoming, rejected, missed,
- * blocked).</li>
- * <li>{@link #EXTRA_CALL_DURATION} - the duration of the call (see
- * {@link #EXTRA_CALL_DURATION} for valid values).</li>
- * </ol>
- * <p>
- * {@link CallScreeningService} implementations which want to track whether the user reports
- * calls are nuisance calls should use declare a broadcast receiver in their manifest for this
- * intent.
- * <p>
- * Note: Only {@link CallScreeningService} implementations which have provided
- * {@link CallIdentification} information for calls at some point will receive this intent.
- */
- public static final String ACTION_NUISANCE_CALL_STATUS_CHANGED =
- "android.telecom.action.NUISANCE_CALL_STATUS_CHANGED";
-
- /**
- * Extra used to provide the handle of the call for
- * {@link #ACTION_NUISANCE_CALL_STATUS_CHANGED}. The call handle is reported as a
- * {@link Uri}.
- */
- public static final String EXTRA_CALL_HANDLE = "android.telecom.extra.CALL_HANDLE";
-
- /**
- * Boolean extra used to indicate whether the user reported a call as a nuisance call.
- * When {@code true}, the user reported that a call was a nuisance call, {@code false}
- * otherwise. Sent with {@link #ACTION_NUISANCE_CALL_STATUS_CHANGED}.
- */
- public static final String EXTRA_IS_NUISANCE = "android.telecom.extra.IS_NUISANCE";
-
- /**
- * Integer extra used with {@link #ACTION_NUISANCE_CALL_STATUS_CHANGED} to report the type of
- * call. Valid values are:
- * <UL>
- * <li>{@link android.provider.CallLog.Calls#MISSED_TYPE}</li>
- * <li>{@link android.provider.CallLog.Calls#INCOMING_TYPE}</li>
- * <li>{@link android.provider.CallLog.Calls#BLOCKED_TYPE}</li>
- * <li>{@link android.provider.CallLog.Calls#REJECTED_TYPE}</li>
- * </UL>
- */
- public static final String EXTRA_CALL_TYPE = "android.telecom.extra.CALL_TYPE";
-
- /**
- * Integer extra used to with {@link #ACTION_NUISANCE_CALL_STATUS_CHANGED} to report how long
- * the call lasted. Valid values are:
- * <UL>
- * <LI>{@link #CALL_DURATION_VERY_SHORT}</LI>
- * <LI>{@link #CALL_DURATION_SHORT}</LI>
- * <LI>{@link #CALL_DURATION_MEDIUM}</LI>
- * <LI>{@link #CALL_DURATION_LONG}</LI>
- * </UL>
- */
- public static final String EXTRA_CALL_DURATION = "android.telecom.extra.CALL_DURATION";
-
/**
* The {@link Intent} that must be declared as handled by the service.
*/
@@ -386,10 +264,6 @@
* Your app can tell if a call is an incoming call by checking to see if
* {@link Call.Details#getCallDirection()} is {@link Call.Details#DIRECTION_INCOMING}.
* <p>
- * For incoming or outgoing calls, the {@link CallScreeningService} can call
- * {@link #provideCallIdentification(Call.Details, CallIdentification)} in order to provide
- * {@link CallIdentification} for the call.
- * <p>
* Note: The {@link Call.Details} instance provided to a call screening service will only have
* the following properties set. The rest of the {@link Call.Details} properties will be set to
* their default value or {@code null}.
@@ -442,32 +316,4 @@
} catch (RemoteException e) {
}
}
-
- /**
- * Provide {@link CallIdentification} information about a {@link Call.Details call}.
- * <p>
- * The {@link CallScreeningService} calls this method to provide information it has identified
- * about a {@link Call.Details call}. This information will potentially be shown to the user
- * in the {@link InCallService dialer} app. It will be logged to the
- * {@link android.provider.CallLog}.
- * <p>
- * A {@link CallScreeningService} should only call this method for calls for which it is able to
- * provide some {@link CallIdentification} for. {@link CallIdentification} instances with no
- * fields set will be ignored by the system.
- *
- * @param callDetails The call to provide information for.
- * <p>
- * Must be the same {@link Call.Details call} which was provided to the
- * {@link CallScreeningService} via {@link #onScreenCall(Call.Details)}.
- * @param identification An instance of {@link CallIdentification} with information about the
- * {@link Call.Details call}.
- */
- public final void provideCallIdentification(@NonNull Call.Details callDetails,
- @NonNull CallIdentification identification) {
- try {
- mCallScreeningAdapter.provideCallIdentification(callDetails.getTelecomCallId(),
- identification);
- } catch (RemoteException e) {
- }
- }
}
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index f7dec83..22348ac 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -64,7 +64,6 @@
private final Bundle mIntentExtras;
private final Bundle mExtras;
private final long mCreationTimeMillis;
- private final CallIdentification mCallIdentification;
private final int mCallDirection;
public ParcelableCall(
@@ -94,7 +93,6 @@
Bundle intentExtras,
Bundle extras,
long creationTimeMillis,
- CallIdentification callIdentification,
int callDirection) {
mId = id;
mState = state;
@@ -122,7 +120,6 @@
mIntentExtras = intentExtras;
mExtras = extras;
mCreationTimeMillis = creationTimeMillis;
- mCallIdentification = callIdentification;
mCallDirection = callDirection;
}
@@ -314,15 +311,6 @@
}
/**
- * Contains call identification information returned by a {@link CallScreeningService}.
- * @return The {@link CallIdentification} for this call, or {@code null} if a
- * {@link CallScreeningService} did not provide information.
- */
- public @Nullable CallIdentification getCallIdentification() {
- return mCallIdentification;
- }
-
- /**
* Indicates whether the call is an incoming or outgoing call.
*/
public @CallDirection int getCallDirection() {
@@ -366,7 +354,6 @@
boolean isRttCallChanged = source.readByte() == 1;
ParcelableRttCall rttCall = source.readParcelable(classLoader);
long creationTimeMillis = source.readLong();
- CallIdentification callIdentification = source.readParcelable(classLoader);
int callDirection = source.readInt();
return new ParcelableCall(
id,
@@ -395,7 +382,6 @@
intentExtras,
extras,
creationTimeMillis,
- callIdentification,
callDirection);
}
@@ -441,7 +427,6 @@
destination.writeByte((byte) (mIsRttCallChanged ? 1 : 0));
destination.writeParcelable(mRttCall, 0);
destination.writeLong(mCreationTimeMillis);
- destination.writeParcelable(mCallIdentification, 0);
destination.writeInt(mCallDirection);
}
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 06c85d2..6a2037f 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -2004,33 +2004,6 @@
}
/**
- * Called by the default dialer to report to Telecom when the user has marked a previous
- * incoming call as a nuisance call or not.
- * <p>
- * Where the user has chosen a {@link CallScreeningService} to fill the call screening role,
- * Telecom will notify that {@link CallScreeningService} of the user's report.
- * <p>
- * Requires that the caller is the default dialer app.
- *
- * @param handle The phone number of an incoming call which the user is reporting as either a
- * nuisance of non-nuisance call.
- * @param isNuisanceCall {@code true} if the user is reporting the call as a nuisance call,
- * {@code false} if the user is reporting the call as a non-nuisance call.
- */
- @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
- public void reportNuisanceCallStatus(@NonNull Uri handle, boolean isNuisanceCall) {
- ITelecomService service = getTelecomService();
- if (service != null) {
- try {
- service.reportNuisanceCallStatus(handle, isNuisanceCall,
- mContext.getOpPackageName());
- } catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelecomService#showCallScreen", e);
- }
- }
- }
-
- /**
* Handles {@link Intent#ACTION_CALL} intents trampolined from UserCallActivity.
* @param intent The {@link Intent#ACTION_CALL} intent to handle.
* @hide
diff --git a/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl b/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
index a86c830..d255ed1 100644
--- a/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl
@@ -17,7 +17,6 @@
package com.android.internal.telecom;
import android.content.ComponentName;
-import android.telecom.CallIdentification;
/**
* Internal remote callback interface for call screening services.
@@ -35,8 +34,4 @@
boolean shouldAddToCallLog,
boolean shouldShowNotification,
in ComponentName componentName);
-
- void provideCallIdentification(
- String callId,
- in CallIdentification callIdentification);
}
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index 93eea56..a814c03 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -286,8 +286,6 @@
*/
boolean isInEmergencyCall();
- oneway void reportNuisanceCallStatus(in Uri address, boolean isNuisance, String callingPackage);
-
/**
* @see TelecomServiceImpl#handleCallIntent
*/
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 983d134..6dd683a 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -35,6 +35,7 @@
import android.database.sqlite.SqliteWrapper;
import android.net.Uri;
import android.os.Build;
+import android.os.Parcel;
import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.SmsMessage;
@@ -4066,32 +4067,24 @@
*/
public static ContentValues getContentValuesForServiceState(ServiceState state) {
ContentValues values = new ContentValues();
- values.put(VOICE_REG_STATE, state.getVoiceRegState());
- values.put(DATA_REG_STATE, state.getDataRegState());
- values.put(VOICE_ROAMING_TYPE, state.getVoiceRoamingType());
- values.put(DATA_ROAMING_TYPE, state.getDataRoamingType());
- values.put(VOICE_OPERATOR_ALPHA_LONG, state.getVoiceOperatorAlphaLong());
- values.put(VOICE_OPERATOR_ALPHA_SHORT, state.getVoiceOperatorAlphaShort());
- values.put(VOICE_OPERATOR_NUMERIC, state.getVoiceOperatorNumeric());
- values.put(DATA_OPERATOR_ALPHA_LONG, state.getDataOperatorAlphaLong());
- values.put(DATA_OPERATOR_ALPHA_SHORT, state.getDataOperatorAlphaShort());
- values.put(DATA_OPERATOR_NUMERIC, state.getDataOperatorNumeric());
- values.put(IS_MANUAL_NETWORK_SELECTION, state.getIsManualSelection());
- values.put(RIL_VOICE_RADIO_TECHNOLOGY, state.getRilVoiceRadioTechnology());
- values.put(RIL_DATA_RADIO_TECHNOLOGY, state.getRilDataRadioTechnology());
- values.put(CSS_INDICATOR, state.getCssIndicator());
- values.put(NETWORK_ID, state.getCdmaNetworkId());
- values.put(SYSTEM_ID, state.getCdmaSystemId());
- values.put(CDMA_ROAMING_INDICATOR, state.getCdmaRoamingIndicator());
- values.put(CDMA_DEFAULT_ROAMING_INDICATOR, state.getCdmaDefaultRoamingIndicator());
- values.put(CDMA_ERI_ICON_INDEX, state.getCdmaEriIconIndex());
- values.put(CDMA_ERI_ICON_MODE, state.getCdmaEriIconMode());
- values.put(IS_EMERGENCY_ONLY, state.isEmergencyOnly());
- values.put(IS_USING_CARRIER_AGGREGATION, state.isUsingCarrierAggregation());
+ final Parcel p = Parcel.obtain();
+ state.writeToParcel(p, 0);
+ // Turn the parcel to byte array. Safe to do this because the content values were never
+ // written into a persistent storage. ServiceStateProvider keeps values in the memory.
+ values.put(SERVICE_STATE, p.marshall());
return values;
}
/**
+ * The current service state.
+ *
+ * This is the entire {@link ServiceState} object in byte array.
+ *
+ * @hide
+ */
+ public static final String SERVICE_STATE = "service_state";
+
+ /**
* An integer value indicating the current voice service state.
* <p>
* Valid values: {@link ServiceState#STATE_IN_SERVICE},
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 4776aa1..c2b8661 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2524,6 +2524,14 @@
"cdma_enhanced_roaming_indicator_for_home_network_int_array";
/**
+ * Determines whether wifi calling location privacy policy is shown.
+ *
+ * @hide
+ */
+ public static final String KEY_SHOW_WFC_LOCATION_PRIVACY_POLICY_BOOL =
+ "show_wfc_location_privacy_policy_bool";
+
+ /**
* This configuration allow the system UI to display different 5G icon for different 5G status.
*
* There are four 5G status:
@@ -2549,6 +2557,61 @@
public static final String KEY_5G_ICON_CONFIGURATION_STRING =
"5g_icon_configuration_string";
+ /**
+ * Passing this value as {@link KEY_SUBSCRIPTION_GROUP_UUID_STRING} will remove the
+ * subscription from a group instead of adding it to a group.
+ *
+ * TODO: Expose in a future release.
+ *
+ * @hide
+ */
+ public static final String REMOVE_GROUP_UUID_STRING = "00000000-0000-0000-0000-000000000000";
+
+ /**
+ * The UUID of a Group of related subscriptions in which to place the current subscription.
+ *
+ * A grouped subscription will behave for billing purposes and other UI purposes as though it
+ * is a transparent extension of other subscriptions in the group.
+ *
+ * <p>If set to {@link #REMOVE_GROUP_UUID_STRING}, then the subscription will be removed from
+ * its current group.
+ *
+ * TODO: unhide this key.
+ *
+ * @hide
+ */
+ public static final String KEY_SUBSCRIPTION_GROUP_UUID_STRING =
+ "key_subscription_group_uuid_string";
+
+ /**
+ * A boolean property indicating whether this subscription should be managed as an opportunistic
+ * subscription.
+ *
+ * If true, then this subscription will be selected based on available coverage and will not be
+ * available for a user in settings menus for selecting macro network providers. If unset,
+ * defaults to “false”.
+ *
+ * TODO: unhide this key.
+ *
+ * @hide
+ */
+ public static final String KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL =
+ "key_is_opportunistic_subscription_bool";
+
+ /**
+ * A list of 4 GSM RSSI thresholds above which a signal level is considered POOR,
+ * MODERATE, GOOD, or EXCELLENT, to be used in SignalStrength reporting.
+ *
+ * Note that the min and max thresholds are fixed at -113 and -51, as set in 3GPP TS 27.007
+ * section 8.5.
+ * <p>
+ * See CellSignalStrengthGsm#GSM_RSSI_MAX and CellSignalStrengthGsm#GSM_RSSI_MIN. Any signal
+ * level outside these boundaries is considered invalid.
+ * @hide
+ */
+ public static final String KEY_GSM_RSSI_THRESHOLDS_INT_ARRAY =
+ "gsm_rssi_thresholds_int_array";
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -2587,7 +2650,7 @@
sDefaults.putBoolean(KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL, false);
- sDefaults.putBoolean(KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL, true);
+ sDefaults.putBoolean(KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL, false);
sDefaults.putBoolean(KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, true);
sDefaults.putBoolean(KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL, true);
@@ -2915,14 +2978,14 @@
sDefaults.putBoolean(KEY_SUPPORT_CLIR_NETWORK_DEFAULT_BOOL, true);
sDefaults.putBoolean(KEY_SUPPORT_EMERGENCY_DIALER_SHORTCUT_BOOL, true);
sDefaults.putBoolean(KEY_ASCII_7_BIT_SUPPORT_FOR_LONG_MESSAGE_BOOL, false);
+ /* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_GOOD */
+ sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT, -108);
/* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_MODERATE */
- sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT, -118);
- /* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_POOR */
- sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT, -128);
+ sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT, -118);
+ /* Default value is minimum RSSNR level needed for SIGNAL_STRENGTH_GOOD */
+ sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT, 45);
/* Default value is minimum RSSNR level needed for SIGNAL_STRENGTH_MODERATE */
- sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT, 10);
- /* Default value is minimum RSSNR level needed for SIGNAL_STRENGTH_POOR */
- sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT, -30);
+ sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT, 10);
/* Default value is 1024 kbps */
sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_BANDWIDTH_INT, 1024);
/* Default value is 10 seconds */
@@ -2934,11 +2997,21 @@
1 /* Roaming Indicator Off */
});
sDefaults.putStringArray(KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY, new String[0]);
+ sDefaults.putBoolean(KEY_SHOW_WFC_LOCATION_PRIVACY_POLICY_BOOL, true);
sDefaults.putString(KEY_5G_ICON_CONFIGURATION_STRING,
"connected_mmwave:None,connected:5G,not_restricted:None,restricted:None");
sDefaults.putBoolean(KEY_AUTO_CANCEL_CS_REJECT_NOTIFICATION, false);
sDefaults.putBoolean(KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN,
false);
+ sDefaults.putString(KEY_SUBSCRIPTION_GROUP_UUID_STRING, "");
+ sDefaults.putBoolean(KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL, false);
+ sDefaults.putIntArray(KEY_GSM_RSSI_THRESHOLDS_INT_ARRAY,
+ new int[] {
+ -107, /* SIGNAL_STRENGTH_POOR */
+ -103, /* SIGNAL_STRENGTH_MODERATE */
+ -97, /* SIGNAL_STRENGTH_GOOD */
+ -89, /* SIGNAL_STRENGTH_GREAT */
+ });
}
/**
diff --git a/telephony/java/android/telephony/CarrierRestrictionRules.java b/telephony/java/android/telephony/CarrierRestrictionRules.java
index b627788..cb15d7b 100644
--- a/telephony/java/android/telephony/CarrierRestrictionRules.java
+++ b/telephony/java/android/telephony/CarrierRestrictionRules.java
@@ -336,7 +336,6 @@
public static final class Builder {
private final CarrierRestrictionRules mRules;
- /** {@hide} */
public Builder() {
mRules = new CarrierRestrictionRules();
}
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index bda8812..a83d8f0 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -110,6 +110,22 @@
}
/**
+ * @return MCC or null for CDMA
+ * @hide
+ */
+ public String getMccString() {
+ return mMccStr;
+ }
+
+ /**
+ * @return MNC or null for CDMA
+ * @hide
+ */
+ public String getMncString() {
+ return mMncStr;
+ }
+
+ /**
* Returns the channel number of the cell identity.
*
* @hide
@@ -213,4 +229,23 @@
protected void log(String s) {
Rlog.w(mTag, s);
}
+
+ /** @hide */
+ protected static final int inRangeOrUnavailable(int value, int rangeMin, int rangeMax) {
+ if (value < rangeMin || value > rangeMax) return CellInfo.UNAVAILABLE;
+ return value;
+ }
+
+ /** @hide */
+ protected static final long inRangeOrUnavailable(long value, long rangeMin, long rangeMax) {
+ if (value < rangeMin || value > rangeMax) return CellInfo.UNAVAILABLE_LONG;
+ return value;
+ }
+
+ /** @hide */
+ protected static final int inRangeOrUnavailable(
+ int value, int rangeMin, int rangeMax, int special) {
+ if ((value < rangeMin || value > rangeMax) && value != special) return CellInfo.UNAVAILABLE;
+ return value;
+ }
}
diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java
index fa19867..0897e0f 100644
--- a/telephony/java/android/telephony/CellIdentityCdma.java
+++ b/telephony/java/android/telephony/CellIdentityCdma.java
@@ -28,12 +28,25 @@
private static final String TAG = CellIdentityCdma.class.getSimpleName();
private static final boolean DBG = false;
+ private static final int NETWORK_ID_MAX = 65535;
+ private static final int SYSTEM_ID_MAX = 32767;
+ private static final int BASESTATION_ID_MAX = 65535;
+
+ private static final int LONGITUDE_MIN = -2592000;
+ private static final int LONGITUDE_MAX = 2592000;
+
+ private static final int LATITUDE_MIN = -1296000;
+ private static final int LATITUDE_MAX = 1296000;
+
// Network Id 0..65535
private final int mNetworkId;
+
// CDMA System Id 0..32767
private final int mSystemId;
+
// Base Station Id 0..65535
private final int mBasestationId;
+
/**
* Longitude is a decimal number as specified in 3GPP2 C.S0005-A v6.0.
* It is represented in units of 0.25 seconds and ranges from -2592000
@@ -41,6 +54,7 @@
* to +180 degrees).
*/
private final int mLongitude;
+
/**
* Latitude is a decimal number as specified in 3GPP2 C.S0005-A v6.0.
* It is represented in units of 0.25 seconds and ranges from -1296000
@@ -78,9 +92,12 @@
public CellIdentityCdma(
int nid, int sid, int bid, int lon, int lat, String alphal, String alphas) {
super(TAG, CellInfo.TYPE_CDMA, null, null, alphal, alphas);
- mNetworkId = nid;
- mSystemId = sid;
- mBasestationId = bid;
+ mNetworkId = inRangeOrUnavailable(nid, 0, NETWORK_ID_MAX);
+ mSystemId = inRangeOrUnavailable(sid, 0, SYSTEM_ID_MAX);
+ mBasestationId = inRangeOrUnavailable(bid, 0, BASESTATION_ID_MAX);
+ lat = inRangeOrUnavailable(lat, LATITUDE_MIN, LATITUDE_MAX);
+ lon = inRangeOrUnavailable(lon, LONGITUDE_MIN, LONGITUDE_MAX);
+
if (!isNullIsland(lat, lon)) {
mLongitude = lon;
mLatitude = lat;
@@ -109,6 +126,13 @@
return new CellIdentityCdma(this);
}
+ /** @hide */
+ public CellIdentityCdma sanitizeLocationInfo() {
+ return new CellIdentityCdma(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
+ CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
+ mAlphaLong, mAlphaShort);
+ }
+
/**
* Take the latitude and longitude in 1/4 seconds and see if
* the reported location is on Null Island.
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index 9a24e47..4b7c9e4 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -31,6 +31,11 @@
private static final String TAG = CellIdentityGsm.class.getSimpleName();
private static final boolean DBG = false;
+ private static final int MAX_LAC = 65535;
+ private static final int MAX_CID = 65535;
+ private static final int MAX_ARFCN = 65535;
+ private static final int MAX_BSIC = 63;
+
// 16-bit Location Area Code, 0..65535
private final int mLac;
// 16-bit GSM Cell Identity described in TS 27.007, 0..65535
@@ -68,10 +73,10 @@
public CellIdentityGsm(int lac, int cid, int arfcn, int bsic, String mccStr,
String mncStr, String alphal, String alphas) {
super(TAG, CellInfo.TYPE_GSM, mccStr, mncStr, alphal, alphas);
- mLac = lac;
- mCid = cid;
- mArfcn = arfcn;
- mBsic = bsic;
+ mLac = inRangeOrUnavailable(lac, 0, MAX_LAC);
+ mCid = inRangeOrUnavailable(cid, 0, MAX_CID);
+ mArfcn = inRangeOrUnavailable(arfcn, 0, MAX_ARFCN);
+ mBsic = inRangeOrUnavailable(bsic, 0, MAX_BSIC);
}
/** @hide */
@@ -97,6 +102,12 @@
return new CellIdentityGsm(this);
}
+ /** @hide */
+ public CellIdentityGsm sanitizeLocationInfo() {
+ return new CellIdentityGsm(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
+ CellInfo.UNAVAILABLE, mMccStr, mMncStr, mAlphaLong, mAlphaShort);
+ }
+
/**
* @return 3-digit Mobile Country Code, 0..999,
* {@link android.telephony.CellInfo#UNAVAILABLE UNAVAILABLE} if unavailable.
@@ -160,6 +171,7 @@
/**
* @return Mobile Country Code in string format, null if unavailable.
*/
+ @Nullable
public String getMccString() {
return mMccStr;
}
@@ -167,6 +179,7 @@
/**
* @return Mobile Network Code in string format, null if unavailable.
*/
+ @Nullable
public String getMncString() {
return mMncStr;
}
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 51393b9..d81f98f 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -32,6 +32,12 @@
private static final String TAG = CellIdentityLte.class.getSimpleName();
private static final boolean DBG = false;
+ private static final int MAX_CI = 268435455;
+ private static final int MAX_PCI = 503;
+ private static final int MAX_TAC = 65535;
+ private static final int MAX_EARFCN = 262143;
+ private static final int MAX_BANDWIDTH = 20000;
+
// 28-bit cell identity
private final int mCi;
// physical cell id 0..503
@@ -89,11 +95,11 @@
public CellIdentityLte(int ci, int pci, int tac, int earfcn, int bandwidth, String mccStr,
String mncStr, String alphal, String alphas) {
super(TAG, CellInfo.TYPE_LTE, mccStr, mncStr, alphal, alphas);
- mCi = ci;
- mPci = pci;
- mTac = tac;
- mEarfcn = earfcn;
- mBandwidth = bandwidth;
+ mCi = inRangeOrUnavailable(ci, 0, MAX_CI);
+ mPci = inRangeOrUnavailable(pci, 0, MAX_PCI);
+ mTac = inRangeOrUnavailable(tac, 0, MAX_TAC);
+ mEarfcn = inRangeOrUnavailable(earfcn, 0, MAX_EARFCN);
+ mBandwidth = inRangeOrUnavailable(bandwidth, 0, MAX_BANDWIDTH);
}
/** @hide */
@@ -113,6 +119,13 @@
cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort);
}
+ /** @hide */
+ public CellIdentityLte sanitizeLocationInfo() {
+ return new CellIdentityLte(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
+ CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
+ mMccStr, mMncStr, mAlphaLong, mAlphaShort);
+ }
+
CellIdentityLte copy() {
return new CellIdentityLte(this);
}
@@ -180,6 +193,7 @@
/**
* @return Mobile Country Code in string format, null if unavailable.
*/
+ @Nullable
public String getMccString() {
return mMccStr;
}
@@ -187,6 +201,7 @@
/**
* @return Mobile Network Code in string format, null if unavailable.
*/
+ @Nullable
public String getMncString() {
return mMncStr;
}
diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java
index 771e7b9..05e5c75 100644
--- a/telephony/java/android/telephony/CellIdentityNr.java
+++ b/telephony/java/android/telephony/CellIdentityNr.java
@@ -29,6 +29,11 @@
public final class CellIdentityNr extends CellIdentity {
private static final String TAG = "CellIdentityNr";
+ private static final int MAX_PCI = 1007;
+ private static final int MAX_TAC = 65535;
+ private static final int MAX_NRARFCN = 3279165;
+ private static final long MAX_NCI = 68719476735L;
+
private final int mNrArfcn;
private final int mPci;
private final int mTac;
@@ -41,18 +46,25 @@
* @param nrArfcn NR Absolute Radio Frequency Channel Number, in range [0, 3279165].
* @param mccStr 3-digit Mobile Country Code in string format.
* @param mncStr 2 or 3-digit Mobile Network Code in string format.
+ * @param nci The 36-bit NR Cell Identity in range [0, 68719476735].
* @param alphal long alpha Operator Name String or Enhanced Operator Name String.
* @param alphas short alpha Operator Name String or Enhanced Operator Name String.
*
* @hide
*/
- public CellIdentityNr(int pci, int tac, int nrArfcn, String mccStr, String mncStr,
+ public CellIdentityNr(int pci, int tac, int nrArfcn, String mccStr, String mncStr,
long nci, String alphal, String alphas) {
super(TAG, CellInfo.TYPE_NR, mccStr, mncStr, alphal, alphas);
- mPci = pci;
- mTac = tac;
- mNrArfcn = nrArfcn;
- mNci = nci;
+ mPci = inRangeOrUnavailable(pci, 0, MAX_PCI);
+ mTac = inRangeOrUnavailable(tac, 0, MAX_TAC);
+ mNrArfcn = inRangeOrUnavailable(nrArfcn, 0, MAX_NRARFCN);
+ mNci = inRangeOrUnavailable(nci, 0, MAX_NCI);
+ }
+
+ /** @hide */
+ public CellIdentityNr sanitizeLocationInfo() {
+ return new CellIdentityNr(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
+ mMccStr, mMncStr, CellInfo.UNAVAILABLE, mAlphaLong, mAlphaShort);
}
/**
diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java
index 19b11b6..558e346 100644
--- a/telephony/java/android/telephony/CellIdentityTdscdma.java
+++ b/telephony/java/android/telephony/CellIdentityTdscdma.java
@@ -30,12 +30,18 @@
private static final String TAG = CellIdentityTdscdma.class.getSimpleName();
private static final boolean DBG = false;
+ private static final int MAX_LAC = 65535;
+ private static final int MAX_CID = 268435455;
+ private static final int MAX_CPID = 127;
+ private static final int MAX_UARFCN = 65535;
+
// 16-bit Location Area Code, 0..65535, CellInfo.UNAVAILABLE if unknown.
private final int mLac;
// 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, CellInfo.UNAVAILABLE
// if unknown.
private final int mCid;
- // 8-bit Cell Parameters ID described in TS 25.331, 0..127, CellInfo.UNAVAILABLE if unknown.
+ // 8-bit Cell Parameters ID described in TS 25.331 sec 10.3.6.9,
+ // 0..127, CellInfo.UNAVAILABLE if unknown.
private final int mCpid;
// 16-bit UMTS Absolute RF Channel Number described in TS 25.101 sec. 5.4.3
private final int mUarfcn;
@@ -68,10 +74,10 @@
public CellIdentityTdscdma(String mcc, String mnc, int lac, int cid, int cpid, int uarfcn,
String alphal, String alphas) {
super(TAG, CellInfo.TYPE_TDSCDMA, mcc, mnc, alphal, alphas);
- mLac = lac;
- mCid = cid;
- mCpid = cpid;
- mUarfcn = uarfcn;
+ mLac = inRangeOrUnavailable(lac, 0, MAX_LAC);
+ mCid = inRangeOrUnavailable(cid, 0, MAX_CID);
+ mCpid = inRangeOrUnavailable(cpid, 0, MAX_CPID);
+ mUarfcn = inRangeOrUnavailable(uarfcn, 0, MAX_UARFCN);
}
private CellIdentityTdscdma(CellIdentityTdscdma cid) {
@@ -90,6 +96,12 @@
cid.uarfcn, cid.operatorNames.alphaLong, cid.operatorNames.alphaShort);
}
+ /** @hide */
+ public CellIdentityTdscdma sanitizeLocationInfo() {
+ return new CellIdentityTdscdma(mMccStr, mMncStr, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
+ CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, mAlphaLong, mAlphaShort);
+ }
+
CellIdentityTdscdma copy() {
return new CellIdentityTdscdma(this);
}
@@ -98,6 +110,7 @@
* Get Mobile Country Code in string format
* @return Mobile Country Code in string format, null if unknown
*/
+ @Nullable
public String getMccString() {
return mMccStr;
}
@@ -106,6 +119,7 @@
* Get Mobile Network Code in string format
* @return Mobile Network Code in string format, null if unknown
*/
+ @Nullable
public String getMncString() {
return mMncStr;
}
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index 6e09784..e500c92 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -31,6 +31,11 @@
private static final String TAG = CellIdentityWcdma.class.getSimpleName();
private static final boolean DBG = false;
+ private static final int MAX_LAC = 65535;
+ private static final int MAX_CID = 268435455;
+ private static final int MAX_PSC = 511;
+ private static final int MAX_UARFCN = 16383; // a 14 bit number; TS 25.331 ex sec 10.3.8.15
+
// 16-bit Location Area Code, 0..65535
private final int mLac;
// 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455
@@ -68,10 +73,10 @@
public CellIdentityWcdma (int lac, int cid, int psc, int uarfcn,
String mccStr, String mncStr, String alphal, String alphas) {
super(TAG, CellInfo.TYPE_WCDMA, mccStr, mncStr, alphal, alphas);
- mLac = lac;
- mCid = cid;
- mPsc = psc;
- mUarfcn = uarfcn;
+ mLac = inRangeOrUnavailable(lac, 0, MAX_LAC);
+ mCid = inRangeOrUnavailable(cid, 0, MAX_CID);
+ mPsc = inRangeOrUnavailable(psc, 0, MAX_PSC);
+ mUarfcn = inRangeOrUnavailable(uarfcn, 0, MAX_UARFCN);
}
/** @hide */
@@ -91,6 +96,13 @@
cid.mMncStr, cid.mAlphaLong, cid.mAlphaShort);
}
+ /** @hide */
+ public CellIdentityWcdma sanitizeLocationInfo() {
+ return new CellIdentityWcdma(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
+ CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE, mMccStr, mMncStr,
+ mAlphaLong, mAlphaShort);
+ }
+
CellIdentityWcdma copy() {
return new CellIdentityWcdma(this);
}
@@ -143,6 +155,7 @@
/**
* @return Mobile Country Code in string version, null if unavailable.
*/
+ @Nullable
public String getMccString() {
return mMccStr;
}
@@ -150,6 +163,7 @@
/**
* @return Mobile Network Code in string version, null if unavailable.
*/
+ @Nullable
public String getMncString() {
return mMncStr;
}
diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java
index cdaf6ed..2142feb 100644
--- a/telephony/java/android/telephony/CellInfo.java
+++ b/telephony/java/android/telephony/CellInfo.java
@@ -197,6 +197,11 @@
@NonNull
public abstract CellSignalStrength getCellSignalStrength();
+ /** @hide */
+ public CellInfo sanitizeLocationInfo() {
+ return null;
+ }
+
/**
* Gets the connection status of this cell.
*
diff --git a/telephony/java/android/telephony/CellInfoCdma.java b/telephony/java/android/telephony/CellInfoCdma.java
index 359c8be..73421a6 100644
--- a/telephony/java/android/telephony/CellInfoCdma.java
+++ b/telephony/java/android/telephony/CellInfoCdma.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.NonNull;
import android.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Parcel;
@@ -76,20 +77,36 @@
new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
}
+ /**
+ * @return a {@link CellIdentityCdma} instance.
+ */
@Override
- public CellIdentityCdma getCellIdentity() {
+ public @NonNull CellIdentityCdma getCellIdentity() {
return mCellIdentityCdma;
}
+
/** @hide */
@UnsupportedAppUsage
public void setCellIdentity(CellIdentityCdma cid) {
mCellIdentityCdma = cid;
}
+ /**
+ * @return a {@link CellSignalStrengthCdma} instance.
+ */
@Override
- public CellSignalStrengthCdma getCellSignalStrength() {
+ public @NonNull CellSignalStrengthCdma getCellSignalStrength() {
return mCellSignalStrengthCdma;
}
+
+ /** @hide */
+ @Override
+ public CellInfo sanitizeLocationInfo() {
+ CellInfoCdma result = new CellInfoCdma(this);
+ result.mCellIdentityCdma = mCellIdentityCdma.sanitizeLocationInfo();
+ return result;
+ }
+
/** @hide */
public void setCellSignalStrength(CellSignalStrengthCdma css) {
mCellSignalStrengthCdma = css;
diff --git a/telephony/java/android/telephony/CellInfoGsm.java b/telephony/java/android/telephony/CellInfoGsm.java
index dc2779f..5be7667 100644
--- a/telephony/java/android/telephony/CellInfoGsm.java
+++ b/telephony/java/android/telephony/CellInfoGsm.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.NonNull;
import android.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
@@ -71,19 +72,35 @@
mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
}
+ /**
+ * @return a {@link CellIdentityGsm} instance.
+ */
@Override
- public CellIdentityGsm getCellIdentity() {
+ public @NonNull CellIdentityGsm getCellIdentity() {
return mCellIdentityGsm;
}
+
/** @hide */
public void setCellIdentity(CellIdentityGsm cid) {
mCellIdentityGsm = cid;
}
+ /**
+ * @return a {@link CellSignalStrengthGsm} instance.
+ */
@Override
- public CellSignalStrengthGsm getCellSignalStrength() {
+ public @NonNull CellSignalStrengthGsm getCellSignalStrength() {
return mCellSignalStrengthGsm;
}
+
+ /** @hide */
+ @Override
+ public CellInfo sanitizeLocationInfo() {
+ CellInfoGsm result = new CellInfoGsm(this);
+ result.mCellIdentityGsm = mCellIdentityGsm.sanitizeLocationInfo();
+ return result;
+ }
+
/** @hide */
public void setCellSignalStrength(CellSignalStrengthGsm css) {
mCellSignalStrengthGsm = css;
diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java
index 0e9623d..d236196 100644
--- a/telephony/java/android/telephony/CellInfoLte.java
+++ b/telephony/java/android/telephony/CellInfoLte.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.NonNull;
import android.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Parcel;
@@ -79,11 +80,15 @@
mCellConfig = new CellConfigLte(cil.cellConfig);
}
+ /**
+ * @return a {@link CellIdentityLte} instance.
+ */
@Override
- public CellIdentityLte getCellIdentity() {
+ public @NonNull CellIdentityLte getCellIdentity() {
if (DBG) log("getCellIdentity: " + mCellIdentityLte);
return mCellIdentityLte;
}
+
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void setCellIdentity(CellIdentityLte cid) {
@@ -91,11 +96,23 @@
mCellIdentityLte = cid;
}
+ /**
+ * @return a {@link CellSignalStrengthLte} instance.
+ */
@Override
- public CellSignalStrengthLte getCellSignalStrength() {
+ public @NonNull CellSignalStrengthLte getCellSignalStrength() {
if (DBG) log("getCellSignalStrength: " + mCellSignalStrengthLte);
return mCellSignalStrengthLte;
}
+
+ /** @hide */
+ @Override
+ public CellInfo sanitizeLocationInfo() {
+ CellInfoLte result = new CellInfoLte(this);
+ result.mCellIdentityLte = mCellIdentityLte.sanitizeLocationInfo();
+ return result;
+ }
+
/** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public void setCellSignalStrength(CellSignalStrengthLte css) {
diff --git a/telephony/java/android/telephony/CellInfoNr.java b/telephony/java/android/telephony/CellInfoNr.java
index 7f7902c..85a7de3 100644
--- a/telephony/java/android/telephony/CellInfoNr.java
+++ b/telephony/java/android/telephony/CellInfoNr.java
@@ -36,18 +36,37 @@
mCellSignalStrength = CellSignalStrengthNr.CREATOR.createFromParcel(in);
}
+ private CellInfoNr(CellInfoNr other, boolean sanitizeLocationInfo) {
+ super(other);
+ mCellIdentity = sanitizeLocationInfo ? other.mCellIdentity.sanitizeLocationInfo()
+ : other.mCellIdentity;
+ mCellSignalStrength = other.mCellSignalStrength;
+ }
+
+ /**
+ * @return a {@link CellIdentityNr} instance.
+ */
@Override
@NonNull
public CellIdentity getCellIdentity() {
return mCellIdentity;
}
+ /**
+ * @return a {@link CellSignalStrengthNr} instance.
+ */
@Override
@NonNull
public CellSignalStrength getCellSignalStrength() {
return mCellSignalStrength;
}
+ /** @hide */
+ @Override
+ public CellInfo sanitizeLocationInfo() {
+ return new CellInfoNr(this, true);
+ }
+
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), mCellIdentity, mCellSignalStrength);
diff --git a/telephony/java/android/telephony/CellInfoTdscdma.java b/telephony/java/android/telephony/CellInfoTdscdma.java
index 1830086..f1305f5 100644
--- a/telephony/java/android/telephony/CellInfoTdscdma.java
+++ b/telephony/java/android/telephony/CellInfoTdscdma.java
@@ -75,6 +75,9 @@
mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
}
+ /**
+ * @return a {@link CellIdentityTdscdma} instance.
+ */
@Override
public @NonNull CellIdentityTdscdma getCellIdentity() {
return mCellIdentityTdscdma;
@@ -85,12 +88,23 @@
mCellIdentityTdscdma = cid;
}
+ /**
+ * @return a {@link CellSignalStrengthTdscdma} instance.
+ */
@Override
public @NonNull CellSignalStrengthTdscdma getCellSignalStrength() {
return mCellSignalStrengthTdscdma;
}
/** @hide */
+ @Override
+ public CellInfo sanitizeLocationInfo() {
+ CellInfoTdscdma result = new CellInfoTdscdma(this);
+ result.mCellIdentityTdscdma = mCellIdentityTdscdma.sanitizeLocationInfo();
+ return result;
+ }
+
+ /** @hide */
public void setCellSignalStrength(CellSignalStrengthTdscdma css) {
mCellSignalStrengthTdscdma = css;
}
diff --git a/telephony/java/android/telephony/CellInfoWcdma.java b/telephony/java/android/telephony/CellInfoWcdma.java
index fe06c78..df66314 100644
--- a/telephony/java/android/telephony/CellInfoWcdma.java
+++ b/telephony/java/android/telephony/CellInfoWcdma.java
@@ -71,19 +71,35 @@
mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
}
+ /**
+ * @return a {@link CellIdentityWcdma} instance.
+ */
@Override
public CellIdentityWcdma getCellIdentity() {
return mCellIdentityWcdma;
}
+
/** @hide */
public void setCellIdentity(CellIdentityWcdma cid) {
mCellIdentityWcdma = cid;
}
+ /**
+ * @return a {@link CellSignalStrengthWcdma} instance.
+ */
@Override
public CellSignalStrengthWcdma getCellSignalStrength() {
return mCellSignalStrengthWcdma;
}
+
+ /** @hide */
+ @Override
+ public CellInfo sanitizeLocationInfo() {
+ CellInfoWcdma result = new CellInfoWcdma(this);
+ result.mCellIdentityWcdma = mCellIdentityWcdma.sanitizeLocationInfo();
+ return result;
+ }
+
/** @hide */
public void setCellSignalStrength(CellSignalStrengthWcdma css) {
mCellSignalStrengthWcdma = css;
diff --git a/telephony/java/android/telephony/CellSignalStrength.java b/telephony/java/android/telephony/CellSignalStrength.java
index aaf6c71..e65b048ec 100644
--- a/telephony/java/android/telephony/CellSignalStrength.java
+++ b/telephony/java/android/telephony/CellSignalStrength.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.IntRange;
import android.os.PersistableBundle;
/**
@@ -57,23 +58,24 @@
public abstract void setDefaultValues();
/**
- * Get signal level as an int from 0..4
- * <p>
- * @see SIGNAL_STRENGTH_NONE_OR_UNKNOWN
- * @see SIGNAL_STRENGTH_POOR
- * @see SIGNAL_STRENGTH_MODERATE
- * @see SIGNAL_STRENGTH_GOOD
- * @see SIGNAL_STRENGTH_GREAT
+ * Retrieve an abstract level value for the overall signal quality.
+ *
+ * @return a single integer from 0 to 4 representing the general signal quality.
+ * 0 represents very poor or unknown signal quality while 4 represents excellent
+ * signal quality.
*/
+ @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT)
public abstract int getLevel();
/**
- * Get the signal level as an asu value between 0..31, 99 is unknown
+ * Get the technology-specific signal strength in Arbitrary Strength Units, calculated from the
+ * strength of the pilot signal or equivalent.
*/
public abstract int getAsuLevel();
/**
- * Get the signal strength as dBm
+ * Get the technology-specific signal strength in dBm, which is the signal strength of the
+ * pilot signal or equivalent.
*/
public abstract int getDbm();
diff --git a/telephony/java/android/telephony/CellSignalStrengthCdma.java b/telephony/java/android/telephony/CellSignalStrengthCdma.java
index 47faf1e..4879896 100644
--- a/telephony/java/android/telephony/CellSignalStrengthCdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthCdma.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.IntRange;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
@@ -114,13 +115,9 @@
mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
}
- /**
- * Retrieve an abstract level value for the overall signal strength.
- *
- * @return a single integer from 0 to 4 representing the general signal quality.
- * 0 represents very poor signal strength while 4 represents a very strong signal strength.
- */
+ /** {@inheritDoc} */
@Override
+ @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT)
public int getLevel() {
return mLevel;
}
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index e0f1690..591f972 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.IntRange;
import android.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
@@ -37,6 +38,10 @@
private static final int GSM_RSSI_GOOD = -97;
private static final int GSM_RSSI_MODERATE = -103;
private static final int GSM_RSSI_POOR = -107;
+ private static final int GSM_RSSI_MIN = -113;
+
+ private static final int[] sRssiThresholds = new int[] {
+ GSM_RSSI_POOR, GSM_RSSI_MODERATE, GSM_RSSI_GOOD, GSM_RSSI_GREAT};
private int mRssi; // in dBm [-113, -51] or UNAVAILABLE
@UnsupportedAppUsage
@@ -53,7 +58,7 @@
/** @hide */
public CellSignalStrengthGsm(int rssi, int ber, int ta) {
- mRssi = inRangeOrUnavailable(rssi, -113, -51);
+ mRssi = inRangeOrUnavailable(rssi, GSM_RSSI_MIN, GSM_RSSI_MAX);
mBitErrorRate = inRangeOrUnavailable(ber, 0, 7, 99);
mTimingAdvance = inRangeOrUnavailable(ta, 0, 219);
updateLevel(null, null);
@@ -97,13 +102,9 @@
mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
}
- /**
- * Retrieve an abstract level value for the overall signal strength.
- *
- * @return a single integer from 0 to 4 representing the general signal quality.
- * 0 represents very poor signal strength while 4 represents a very strong signal strength.
- */
+ /** {@inheritDoc} */
@Override
+ @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT)
public int getLevel() {
return mLevel;
}
@@ -111,12 +112,22 @@
/** @hide */
@Override
public void updateLevel(PersistableBundle cc, ServiceState ss) {
- if (mRssi > GSM_RSSI_MAX) mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
- else if (mRssi >= GSM_RSSI_GREAT) mLevel = SIGNAL_STRENGTH_GREAT;
- else if (mRssi >= GSM_RSSI_GOOD) mLevel = SIGNAL_STRENGTH_GOOD;
- else if (mRssi >= GSM_RSSI_MODERATE) mLevel = SIGNAL_STRENGTH_MODERATE;
- else if (mRssi >= GSM_RSSI_POOR) mLevel = SIGNAL_STRENGTH_POOR;
- else mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+ int[] rssiThresholds;
+ if (cc == null) {
+ rssiThresholds = sRssiThresholds;
+ } else {
+ rssiThresholds = cc.getIntArray(CarrierConfigManager.KEY_GSM_RSSI_THRESHOLDS_INT_ARRAY);
+ if (rssiThresholds == null || rssiThresholds.length != NUM_SIGNAL_STRENGTH_THRESHOLDS) {
+ rssiThresholds = sRssiThresholds;
+ }
+ }
+ int level = NUM_SIGNAL_STRENGTH_THRESHOLDS;
+ if (mRssi < GSM_RSSI_MIN || mRssi > GSM_RSSI_MAX) {
+ mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+ return;
+ }
+ while (level > 0 && mRssi < rssiThresholds[level - 1]) level--;
+ mLevel = level;
}
/**
@@ -141,7 +152,7 @@
/**
* Get the RSSI in ASU.
*
- * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
+ * Asu is calculated based on 3GPP RSSI. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
*
* @return RSSI in ASU 0..31, 99, or UNAVAILABLE
*/
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index 61c6b48..d829309 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.IntRange;
import android.annotation.UnsupportedAppUsage;
import android.os.Parcel;
import android.os.Parcelable;
@@ -145,13 +146,9 @@
mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
}
- /**
- * Retrieve an abstract level value for the overall signal strength.
- *
- * @return a single integer from 0 to 4 representing the general signal quality.
- * 0 represents very poor signal strength while 4 represents a very strong signal strength.
- */
+ /** {@inheritDoc} */
@Override
+ @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT)
public int getLevel() {
return mLevel;
}
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index 6f84ec5..85bce93 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.IntRange;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
@@ -183,7 +184,9 @@
mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
}
+ /** {@inheritDoc} */
@Override
+ @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT)
public int getLevel() {
return mLevel;
}
@@ -227,6 +230,9 @@
return asuLevel;
}
+ /**
+ * Get the CSI-RSRP as dBm value -140..-44dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}.
+ */
@Override
public int getDbm() {
return mCsiRsrp;
diff --git a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
index ddbd851..f4a3dbb 100644
--- a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
@@ -34,14 +35,14 @@
private static final String LOG_TAG = "CellSignalStrengthTdscdma";
private static final boolean DBG = false;
- private static final int TDSCDMA_RSSI_MAX = -51;
- private static final int TDSCDMA_RSSI_GREAT = -77;
- private static final int TDSCDMA_RSSI_GOOD = -87;
- private static final int TDSCDMA_RSSI_MODERATE = -97;
- private static final int TDSCDMA_RSSI_POOR = -107;
-
- private static final int TDSCDMA_RSCP_MIN = -120;
+ // These levels are arbitrary but carried over from SignalStrength.java for consistency.
private static final int TDSCDMA_RSCP_MAX = -24;
+ private static final int TDSCDMA_RSCP_GREAT = -49;
+ private static final int TDSCDMA_RSCP_GOOD = -73;
+ private static final int TDSCDMA_RSCP_MODERATE = -97;
+ private static final int TDSCDMA_RSCP_POOR = -110;
+ private static final int TDSCDMA_RSCP_MIN = -120;
+
private int mRssi; // in dBm [-113, -51], CellInfo.UNAVAILABLE
@@ -121,13 +122,10 @@
mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
}
- /**
- * Retrieve an abstract level value for the overall signal strength.
- *
- * @return a single integer from 0 to 4 representing the general signal quality.
- * 0 represents very poor signal strength while 4 represents a very strong signal strength.
- */
+
+ /** {@inheritDoc} */
@Override
+ @IntRange(from = 0, to = 4)
public int getLevel() {
return mLevel;
}
@@ -135,16 +133,16 @@
/** @hide */
@Override
public void updateLevel(PersistableBundle cc, ServiceState ss) {
- if (mRssi > TDSCDMA_RSSI_MAX) mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
- else if (mRssi >= TDSCDMA_RSSI_GREAT) mLevel = SIGNAL_STRENGTH_GREAT;
- else if (mRssi >= TDSCDMA_RSSI_GOOD) mLevel = SIGNAL_STRENGTH_GOOD;
- else if (mRssi >= TDSCDMA_RSSI_MODERATE) mLevel = SIGNAL_STRENGTH_MODERATE;
- else if (mRssi >= TDSCDMA_RSSI_POOR) mLevel = SIGNAL_STRENGTH_POOR;
+ if (mRscp > TDSCDMA_RSCP_MAX) mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+ else if (mRscp >= TDSCDMA_RSCP_GREAT) mLevel = SIGNAL_STRENGTH_GREAT;
+ else if (mRscp >= TDSCDMA_RSCP_GOOD) mLevel = SIGNAL_STRENGTH_GOOD;
+ else if (mRscp >= TDSCDMA_RSCP_MODERATE) mLevel = SIGNAL_STRENGTH_MODERATE;
+ else if (mRscp >= TDSCDMA_RSCP_POOR) mLevel = SIGNAL_STRENGTH_POOR;
else mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
}
/**
- * Get the signal strength as dBm
+ * Get the RSCP as dBm value -120..-24dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}.
*/
@Override
public int getDbm() {
@@ -159,6 +157,23 @@
}
/**
+ * Get the RSSI as dBm value -113..-51dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}.
+ *
+ * @hide
+ */
+ public int getRssi() {
+ return mRssi;
+ }
+
+ /**
+ * Get the BER as an ASU value 0..7, 99, or {@link CellInfo#UNAVAILABLE UNAVAILABLE}.
+ * @hide
+ */
+ public int getBitErrorRate() {
+ return mBitErrorRate;
+ }
+
+ /**
* Get the RSCP in ASU.
*
* Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
diff --git a/telephony/java/android/telephony/CellSignalStrengthWcdma.java b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
index efa3647..2120066 100644
--- a/telephony/java/android/telephony/CellSignalStrengthWcdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
@@ -16,6 +16,7 @@
package android.telephony;
+import android.annotation.IntRange;
import android.annotation.StringDef;
import android.os.Parcel;
import android.os.Parcelable;
@@ -66,7 +67,7 @@
public static final String LEVEL_CALCULATION_METHOD_RSCP = "rscp";
// Default to RSSI for backwards compatibility with older devices
- private static final String sLevelCalculationMethod = LEVEL_CALCULATION_METHOD_RSSI;
+ private static final String DEFAULT_LEVEL_CALCULATION_METHOD = LEVEL_CALCULATION_METHOD_RSSI;
private int mRssi; // in dBm [-113, 51] or CellInfo.UNAVAILABLE if unknown
private int mBitErrorRate; // bit error rate (0-7, 99) as defined in TS 27.007 8.5 or
@@ -143,13 +144,9 @@
mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
}
- /**
- * Retrieve an abstract level value for the overall signal strength.
- *
- * @return a single integer from 0 to 4 representing the general signal quality.
- * 0 represents very poor signal strength while 4 represents a very strong signal strength.
- */
+ /** {@inheritDoc} */
@Override
+ @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT)
public int getLevel() {
return mLevel;
}
@@ -161,14 +158,14 @@
int[] rscpThresholds;
if (cc == null) {
- calcMethod = sLevelCalculationMethod;
+ calcMethod = DEFAULT_LEVEL_CALCULATION_METHOD;
rscpThresholds = sRscpThresholds;
} else {
// TODO: abstract this entire thing into a series of functions
calcMethod = cc.getString(
CarrierConfigManager.KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING,
- sLevelCalculationMethod);
- if (TextUtils.isEmpty(calcMethod)) calcMethod = sLevelCalculationMethod;
+ DEFAULT_LEVEL_CALCULATION_METHOD);
+ if (TextUtils.isEmpty(calcMethod)) calcMethod = DEFAULT_LEVEL_CALCULATION_METHOD;
rscpThresholds = cc.getIntArray(
CarrierConfigManager.KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY);
if (rscpThresholds == null || rscpThresholds.length != NUM_SIGNAL_STRENGTH_THRESHOLDS) {
@@ -202,7 +199,7 @@
}
/**
- * Get the signal strength as dBm
+ * Get the RSCP as dBm value -120..-24dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}.
*/
@Override
public int getDbm() {
diff --git a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
index fbf488e..2cb369d 100644
--- a/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
+++ b/telephony/java/android/telephony/DataSpecificRegistrationInfo.java
@@ -74,16 +74,25 @@
private final LteVopsSupportInfo mLteVopsSupportInfo;
/**
+ * Indicates if it's using carrier aggregation
+ *
+ * @hide
+ */
+ public boolean mIsUsingCarrierAggregation;
+
+ /**
* @hide
*/
DataSpecificRegistrationInfo(
int maxDataCalls, boolean isDcNrRestricted, boolean isNrAvailable,
- boolean isEnDcAvailable, LteVopsSupportInfo lteVops) {
+ boolean isEnDcAvailable, LteVopsSupportInfo lteVops,
+ boolean isUsingCarrierAggregation) {
this.maxDataCalls = maxDataCalls;
this.isDcNrRestricted = isDcNrRestricted;
this.isNrAvailable = isNrAvailable;
this.isEnDcAvailable = isEnDcAvailable;
this.mLteVopsSupportInfo = lteVops;
+ this.mIsUsingCarrierAggregation = isUsingCarrierAggregation;
}
private DataSpecificRegistrationInfo(Parcel source) {
@@ -92,6 +101,7 @@
isNrAvailable = source.readBoolean();
isEnDcAvailable = source.readBoolean();
mLteVopsSupportInfo = LteVopsSupportInfo.CREATOR.createFromParcel(source);
+ mIsUsingCarrierAggregation = source.readBoolean();
}
@Override
@@ -101,6 +111,7 @@
dest.writeBoolean(isNrAvailable);
dest.writeBoolean(isEnDcAvailable);
mLteVopsSupportInfo.writeToParcel(dest, flags);
+ dest.writeBoolean(mIsUsingCarrierAggregation);
}
@Override
@@ -116,7 +127,8 @@
.append(" isDcNrRestricted = " + isDcNrRestricted)
.append(" isNrAvailable = " + isNrAvailable)
.append(" isEnDcAvailable = " + isEnDcAvailable)
- .append(mLteVopsSupportInfo.toString())
+ .append(" " + mLteVopsSupportInfo.toString())
+ .append(" mIsUsingCarrierAggregation = " + mIsUsingCarrierAggregation)
.append(" }")
.toString();
}
@@ -124,7 +136,7 @@
@Override
public int hashCode() {
return Objects.hash(maxDataCalls, isDcNrRestricted, isNrAvailable, isEnDcAvailable,
- mLteVopsSupportInfo);
+ mLteVopsSupportInfo, mIsUsingCarrierAggregation);
}
@Override
@@ -138,7 +150,8 @@
&& this.isDcNrRestricted == other.isDcNrRestricted
&& this.isNrAvailable == other.isNrAvailable
&& this.isEnDcAvailable == other.isEnDcAvailable
- && this.mLteVopsSupportInfo.equals(other.mLteVopsSupportInfo);
+ && this.mLteVopsSupportInfo.equals(other.mLteVopsSupportInfo)
+ && this.mIsUsingCarrierAggregation == other.mIsUsingCarrierAggregation;
}
public static final @NonNull Parcelable.Creator<DataSpecificRegistrationInfo> CREATOR =
@@ -161,4 +174,22 @@
public LteVopsSupportInfo getLteVopsSupportInfo() {
return mLteVopsSupportInfo;
}
+
+ /**
+ * Set the flag indicating if using carrier aggregation.
+ *
+ * @param isUsingCarrierAggregation {@code true} if using carrier aggregation.
+ * @hide
+ */
+ public void setIsUsingCarrierAggregation(boolean isUsingCarrierAggregation) {
+ mIsUsingCarrierAggregation = isUsingCarrierAggregation;
+ }
+
+ /**
+ * @return {@code true} if using carrier aggregation.
+ * @hide
+ */
+ public boolean isUsingCarrierAggregation() {
+ return mIsUsingCarrierAggregation;
+ }
}
diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java
index 1dc2997..7b9f6d5 100644
--- a/telephony/java/android/telephony/NetworkRegistrationInfo.java
+++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java
@@ -251,12 +251,13 @@
@Nullable CellIdentity cellIdentity, int maxDataCalls,
boolean isDcNrRestricted, boolean isNrAvailable,
boolean isEndcAvailable,
- LteVopsSupportInfo lteVopsSupportInfo) {
+ LteVopsSupportInfo lteVopsSupportInfo,
+ boolean isUsingCarrierAggregation) {
this(domain, transportType, registrationState, accessNetworkTechnology, rejectCause,
emergencyOnly, availableServices, cellIdentity);
-
mDataSpecificInfo = new DataSpecificRegistrationInfo(
- maxDataCalls, isDcNrRestricted, isNrAvailable, isEndcAvailable, lteVopsSupportInfo);
+ maxDataCalls, isDcNrRestricted, isNrAvailable, isEndcAvailable, lteVopsSupportInfo,
+ isUsingCarrierAggregation);
updateNrState(mDataSpecificInfo);
}
@@ -367,6 +368,13 @@
* @hide
*/
public void setAccessNetworkTechnology(@NetworkType int tech) {
+ if (tech == TelephonyManager.NETWORK_TYPE_LTE_CA) {
+ // For old device backward compatibility support
+ tech = TelephonyManager.NETWORK_TYPE_LTE;
+ if (mDataSpecificInfo != null) {
+ mDataSpecificInfo.setIsUsingCarrierAggregation(true);
+ }
+ }
mAccessNetworkTechnology = tech;
}
diff --git a/telephony/java/android/telephony/PhoneCapability.java b/telephony/java/android/telephony/PhoneCapability.java
index 21dad77..c1906eb 100644
--- a/telephony/java/android/telephony/PhoneCapability.java
+++ b/telephony/java/android/telephony/PhoneCapability.java
@@ -30,6 +30,25 @@
* @hide
*/
public class PhoneCapability implements Parcelable {
+ // Hardcoded default DSDS capability.
+ public static final PhoneCapability DEFAULT_DSDS_CAPABILITY;
+ // Hardcoded default Single SIM single standby capability.
+ public static final PhoneCapability DEFAULT_SSSS_CAPABILITY;
+
+ static {
+ ModemInfo modemInfo1 = new ModemInfo(0, 0, true, true);
+ ModemInfo modemInfo2 = new ModemInfo(1, 0, true, true);
+
+ List<ModemInfo> logicalModemList = new ArrayList<>();
+ logicalModemList.add(modemInfo1);
+ logicalModemList.add(modemInfo2);
+ DEFAULT_DSDS_CAPABILITY = new PhoneCapability(1, 1, 0, logicalModemList, false);
+
+ logicalModemList = new ArrayList<>();
+ logicalModemList.add(modemInfo1);
+ DEFAULT_SSSS_CAPABILITY = new PhoneCapability(1, 1, 0, logicalModemList, false);
+ }
+
public final int maxActiveVoiceCalls;
public final int maxActiveData;
public final int max5G;
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 549c044..b75e515 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -2016,7 +2016,16 @@
private static boolean isEmergencyNumberInternal(int subId, String number,
String defaultCountryIso,
boolean useExactMatch) {
- return TelephonyManager.getDefault().isEmergencyNumber(number);
+ try {
+ if (useExactMatch) {
+ return TelephonyManager.getDefault().isEmergencyNumber(number);
+ } else {
+ return TelephonyManager.getDefault().isPotentialEmergencyNumber(number);
+ }
+ } catch (RuntimeException ex) {
+ Rlog.e(LOG_TAG, "isEmergencyNumberInternal: RuntimeException: " + ex);
+ }
+ return false;
}
/**
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index caf27b7..f4a6984 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -312,18 +312,6 @@
private boolean mIsManualNetworkSelection;
private boolean mIsEmergencyOnly;
- /**
- * TODO: remove mRilVoiceRadioTechnology after completely migrate to
- * {@link TelephonyManager.NetworkType}
- */
- @RilRadioTechnology
- private int mRilVoiceRadioTechnology;
- /**
- * TODO: remove mRilDataRadioTechnology after completely migrate to
- * {@link TelephonyManager.NetworkType}
- */
- @RilRadioTechnology
- private int mRilDataRadioTechnology;
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private boolean mCssIndicator;
@@ -340,9 +328,6 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
private int mCdmaEriIconMode;
- @UnsupportedAppUsage
- private boolean mIsUsingCarrierAggregation;
-
@FrequencyRange
private int mNrFrequencyRange;
private int mChannelNumber;
@@ -420,8 +405,6 @@
mDataOperatorAlphaShort = s.mDataOperatorAlphaShort;
mDataOperatorNumeric = s.mDataOperatorNumeric;
mIsManualNetworkSelection = s.mIsManualNetworkSelection;
- mRilVoiceRadioTechnology = s.mRilVoiceRadioTechnology;
- mRilDataRadioTechnology = s.mRilDataRadioTechnology;
mCssIndicator = s.mCssIndicator;
mNetworkId = s.mNetworkId;
mSystemId = s.mSystemId;
@@ -430,7 +413,6 @@
mCdmaEriIconIndex = s.mCdmaEriIconIndex;
mCdmaEriIconMode = s.mCdmaEriIconMode;
mIsEmergencyOnly = s.mIsEmergencyOnly;
- mIsUsingCarrierAggregation = s.mIsUsingCarrierAggregation;
mChannelNumber = s.mChannelNumber;
mCellBandwidths = s.mCellBandwidths == null ? null :
Arrays.copyOf(s.mCellBandwidths, s.mCellBandwidths.length);
@@ -457,8 +439,6 @@
mDataOperatorAlphaShort = in.readString();
mDataOperatorNumeric = in.readString();
mIsManualNetworkSelection = in.readInt() != 0;
- mRilVoiceRadioTechnology = in.readInt();
- mRilDataRadioTechnology = in.readInt();
mCssIndicator = (in.readInt() != 0);
mNetworkId = in.readInt();
mSystemId = in.readInt();
@@ -467,7 +447,6 @@
mCdmaEriIconIndex = in.readInt();
mCdmaEriIconMode = in.readInt();
mIsEmergencyOnly = in.readInt() != 0;
- mIsUsingCarrierAggregation = in.readInt() != 0;
mLteEarfcnRsrpBoost = in.readInt();
mNetworkRegistrationInfos = new ArrayList<>();
in.readList(mNetworkRegistrationInfos, NetworkRegistrationInfo.class.getClassLoader());
@@ -486,8 +465,6 @@
out.writeString(mDataOperatorAlphaShort);
out.writeString(mDataOperatorNumeric);
out.writeInt(mIsManualNetworkSelection ? 1 : 0);
- out.writeInt(mRilVoiceRadioTechnology);
- out.writeInt(mRilDataRadioTechnology);
out.writeInt(mCssIndicator ? 1 : 0);
out.writeInt(mNetworkId);
out.writeInt(mSystemId);
@@ -496,7 +473,6 @@
out.writeInt(mCdmaEriIconIndex);
out.writeInt(mCdmaEriIconMode);
out.writeInt(mIsEmergencyOnly ? 1 : 0);
- out.writeInt(mIsUsingCarrierAggregation ? 1 : 0);
out.writeInt(mLteEarfcnRsrpBoost);
out.writeList(mNetworkRegistrationInfos);
out.writeInt(mChannelNumber);
@@ -568,7 +544,7 @@
@DuplexMode
public int getDuplexMode() {
// only support LTE duplex mode
- if (!isLte(mRilDataRadioTechnology)) {
+ if (!isLte(getRilDataRadioTechnology())) {
return DUPLEX_MODE_UNKNOWN;
}
@@ -850,8 +826,6 @@
mDataOperatorAlphaShort,
mDataOperatorNumeric,
mIsManualNetworkSelection,
- mRilVoiceRadioTechnology,
- mRilDataRadioTechnology,
mCssIndicator,
mNetworkId,
mSystemId,
@@ -860,7 +834,6 @@
mCdmaEriIconIndex,
mCdmaEriIconMode,
mIsEmergencyOnly,
- mIsUsingCarrierAggregation,
mLteEarfcnRsrpBoost,
mNetworkRegistrationInfos,
mNrFrequencyRange);
@@ -871,7 +844,7 @@
if (!(o instanceof ServiceState)) return false;
ServiceState s = (ServiceState) o;
- return (mVoiceRegState == s.mVoiceRegState
+ return mVoiceRegState == s.mVoiceRegState
&& mDataRegState == s.mDataRegState
&& mIsManualNetworkSelection == s.mIsManualNetworkSelection
&& mChannelNumber == s.mChannelNumber
@@ -882,8 +855,6 @@
&& equalsHandlesNulls(mDataOperatorAlphaLong, s.mDataOperatorAlphaLong)
&& equalsHandlesNulls(mDataOperatorAlphaShort, s.mDataOperatorAlphaShort)
&& equalsHandlesNulls(mDataOperatorNumeric, s.mDataOperatorNumeric)
- && equalsHandlesNulls(mRilVoiceRadioTechnology, s.mRilVoiceRadioTechnology)
- && equalsHandlesNulls(mRilDataRadioTechnology, s.mRilDataRadioTechnology)
&& equalsHandlesNulls(mCssIndicator, s.mCssIndicator)
&& equalsHandlesNulls(mNetworkId, s.mNetworkId)
&& equalsHandlesNulls(mSystemId, s.mSystemId)
@@ -891,7 +862,6 @@
&& equalsHandlesNulls(mCdmaDefaultRoamingIndicator,
s.mCdmaDefaultRoamingIndicator)
&& mIsEmergencyOnly == s.mIsEmergencyOnly
- && mIsUsingCarrierAggregation == s.mIsUsingCarrierAggregation)
&& (mNetworkRegistrationInfos == null
? s.mNetworkRegistrationInfos == null : s.mNetworkRegistrationInfos != null
&& mNetworkRegistrationInfos.containsAll(s.mNetworkRegistrationInfos))
@@ -1035,27 +1005,27 @@
.append(", mDataOperatorAlphaShort=").append(mDataOperatorAlphaShort)
.append(", isManualNetworkSelection=").append(mIsManualNetworkSelection)
.append(mIsManualNetworkSelection ? "(manual)" : "(automatic)")
- .append(", mRilVoiceRadioTechnology=").append(mRilVoiceRadioTechnology)
- .append("(" + rilRadioTechnologyToString(mRilVoiceRadioTechnology) + ")")
- .append(", mRilDataRadioTechnology=").append(mRilDataRadioTechnology)
- .append("(" + rilRadioTechnologyToString(mRilDataRadioTechnology) + ")")
+ .append(", getRilVoiceRadioTechnology=").append(getRilVoiceRadioTechnology())
+ .append("(" + rilRadioTechnologyToString(getRilVoiceRadioTechnology()) + ")")
+ .append(", getRilDataRadioTechnology=").append(getRilDataRadioTechnology())
+ .append("(" + rilRadioTechnologyToString(getRilDataRadioTechnology()) + ")")
.append(", mCssIndicator=").append(mCssIndicator ? "supported" : "unsupported")
.append(", mNetworkId=").append(mNetworkId)
.append(", mSystemId=").append(mSystemId)
.append(", mCdmaRoamingIndicator=").append(mCdmaRoamingIndicator)
.append(", mCdmaDefaultRoamingIndicator=").append(mCdmaDefaultRoamingIndicator)
.append(", mIsEmergencyOnly=").append(mIsEmergencyOnly)
- .append(", mIsUsingCarrierAggregation=").append(mIsUsingCarrierAggregation)
+ .append(", isUsingCarrierAggregation=").append(isUsingCarrierAggregation())
.append(", mLteEarfcnRsrpBoost=").append(mLteEarfcnRsrpBoost)
.append(", mNetworkRegistrationInfos=").append(mNetworkRegistrationInfos)
.append(", mNrFrequencyRange=").append(mNrFrequencyRange)
.append("}").toString();
}
- private void setNullState(int state) {
- if (DBG) Rlog.d(LOG_TAG, "[ServiceState] setNullState=" + state);
- mVoiceRegState = state;
- mDataRegState = state;
+ private void init() {
+ if (DBG) Rlog.d(LOG_TAG, "init");
+ mVoiceRegState = STATE_OUT_OF_SERVICE;
+ mDataRegState = STATE_OUT_OF_SERVICE;
mChannelNumber = -1;
mCellBandwidths = new int[0];
mVoiceOperatorAlphaLong = null;
@@ -1065,8 +1035,6 @@
mDataOperatorAlphaShort = null;
mDataOperatorNumeric = null;
mIsManualNetworkSelection = false;
- mRilVoiceRadioTechnology = 0;
- mRilDataRadioTechnology = 0;
mCssIndicator = false;
mNetworkId = -1;
mSystemId = -1;
@@ -1075,18 +1043,29 @@
mCdmaEriIconIndex = -1;
mCdmaEriIconMode = -1;
mIsEmergencyOnly = false;
- mIsUsingCarrierAggregation = false;
mLteEarfcnRsrpBoost = 0;
- mNetworkRegistrationInfos = new ArrayList<>();
mNrFrequencyRange = FREQUENCY_RANGE_UNKNOWN;
+ mNetworkRegistrationInfos.clear();
+ addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
+ .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
+ .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+ .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN)
+ .build());
+ addNetworkRegistrationInfo(new NetworkRegistrationInfo.Builder()
+ .setDomain(NetworkRegistrationInfo.DOMAIN_PS)
+ .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
+ .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN)
+ .build());
}
public void setStateOutOfService() {
- setNullState(STATE_OUT_OF_SERVICE);
+ init();
}
public void setStateOff() {
- setNullState(STATE_POWER_OFF);
+ init();
+ mVoiceRegState = STATE_POWER_OFF;
+ mDataRegState = STATE_POWER_OFF;
}
public void setState(int state) {
@@ -1304,8 +1283,8 @@
m.putString("data-operator-alpha-short", mDataOperatorAlphaShort);
m.putString("data-operator-numeric", mDataOperatorNumeric);
m.putBoolean("manual", mIsManualNetworkSelection);
- m.putInt("radioTechnology", mRilVoiceRadioTechnology);
- m.putInt("dataRadioTechnology", mRilDataRadioTechnology);
+ m.putInt("radioTechnology", getRilVoiceRadioTechnology());
+ m.putInt("dataRadioTechnology", getRadioTechnology());
m.putBoolean("cssIndicator", mCssIndicator);
m.putInt("networkId", mNetworkId);
m.putInt("systemId", mSystemId);
@@ -1313,7 +1292,7 @@
m.putInt("cdmaDefaultRoamingIndicator", mCdmaDefaultRoamingIndicator);
m.putBoolean("emergencyOnly", mIsEmergencyOnly);
m.putBoolean("isDataRoamingFromRegistration", getDataRoamingFromRegistration());
- m.putBoolean("isUsingCarrierAggregation", mIsUsingCarrierAggregation);
+ m.putBoolean("isUsingCarrierAggregation", isUsingCarrierAggregation());
m.putInt("LteEarfcnRsrpBoost", mLteEarfcnRsrpBoost);
m.putInt("ChannelNumber", mChannelNumber);
m.putIntArray("CellBandwidths", mCellBandwidths);
@@ -1323,13 +1302,9 @@
/** @hide */
@TestApi
public void setRilVoiceRadioTechnology(@RilRadioTechnology int rt) {
- if (rt == RIL_RADIO_TECHNOLOGY_LTE_CA) {
- rt = RIL_RADIO_TECHNOLOGY_LTE;
- }
-
- this.mRilVoiceRadioTechnology = rt;
-
- // sync to network registration state
+ Rlog.e(LOG_TAG, "ServiceState.setRilVoiceRadioTechnology() called. It's encouraged to "
+ + "use addNetworkRegistrationInfo() instead *******");
+ // Sync to network registration state
NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
if (regState == null) {
@@ -1339,24 +1314,18 @@
.build();
addNetworkRegistrationInfo(regState);
}
- regState.setAccessNetworkTechnology(
- rilRadioTechnologyToNetworkType(mRilVoiceRadioTechnology));
+ regState.setAccessNetworkTechnology(rilRadioTechnologyToNetworkType(rt));
}
+
/** @hide */
@TestApi
public void setRilDataRadioTechnology(@RilRadioTechnology int rt) {
- if (rt == RIL_RADIO_TECHNOLOGY_LTE_CA) {
- rt = RIL_RADIO_TECHNOLOGY_LTE;
- this.mIsUsingCarrierAggregation = true;
- } else {
- this.mIsUsingCarrierAggregation = false;
- }
- this.mRilDataRadioTechnology = rt;
- if (VDBG) Rlog.d(LOG_TAG, "[ServiceState] setRilDataRadioTechnology=" +
- mRilDataRadioTechnology);
-
- // sync to network registration state
+ Rlog.e(LOG_TAG, "ServiceState.setRilDataRadioTechnology() called. It's encouraged to "
+ + "use addNetworkRegistrationInfo() instead *******");
+ // Sync to network registration state. Always write down the WWAN transport. For AP-assisted
+ // mode device, use addNetworkRegistrationInfo() to set the correct transport if RAT
+ // is IWLAN.
NetworkRegistrationInfo regState = getNetworkRegistrationInfo(
NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
@@ -1367,18 +1336,32 @@
.build();
addNetworkRegistrationInfo(regState);
}
- regState.setAccessNetworkTechnology(
- rilRadioTechnologyToNetworkType(mRilDataRadioTechnology));
+ regState.setAccessNetworkTechnology(rilRadioTechnologyToNetworkType(rt));
}
/** @hide */
public boolean isUsingCarrierAggregation() {
- return mIsUsingCarrierAggregation;
+ NetworkRegistrationInfo nri = getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+ if (nri != null) {
+ DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo();
+ if (dsri != null) {
+ return dsri.isUsingCarrierAggregation();
+ }
+ }
+ return false;
}
/** @hide */
public void setIsUsingCarrierAggregation(boolean ca) {
- mIsUsingCarrierAggregation = ca;
+ NetworkRegistrationInfo nri = getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+ if (nri != null) {
+ DataSpecificRegistrationInfo dsri = nri.getDataSpecificInfo();
+ if (dsri != null) {
+ dsri.setIsUsingCarrierAggregation(ca);
+ }
+ }
}
/**
@@ -1435,12 +1418,29 @@
/** @hide */
@UnsupportedAppUsage
public int getRilVoiceRadioTechnology() {
- return this.mRilVoiceRadioTechnology;
+ NetworkRegistrationInfo wwanRegInfo = getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_CS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+ if (wwanRegInfo != null) {
+ return networkTypeToRilRadioTechnology(wwanRegInfo.getAccessNetworkTechnology());
+ }
+ return RIL_RADIO_TECHNOLOGY_UNKNOWN;
}
/** @hide */
@UnsupportedAppUsage
public int getRilDataRadioTechnology() {
- return this.mRilDataRadioTechnology;
+ NetworkRegistrationInfo wwanRegInfo = getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
+ NetworkRegistrationInfo wlanRegInfo = getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+ if (wlanRegInfo != null
+ && wlanRegInfo.getAccessNetworkTechnology() == TelephonyManager.NETWORK_TYPE_IWLAN
+ && wlanRegInfo.getRegistrationState()
+ == NetworkRegistrationInfo.REGISTRATION_STATE_HOME) {
+ return RIL_RADIO_TECHNOLOGY_IWLAN;
+ } else if (wwanRegInfo != null) {
+ return networkTypeToRilRadioTechnology(wwanRegInfo.getAccessNetworkTechnology());
+ }
+ return RIL_RADIO_TECHNOLOGY_UNKNOWN;
}
/**
* @hide
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 4d1b89c..def7fbe 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -941,8 +941,7 @@
* @return associated subscription id
*/
public int getSubscriptionId() {
- final int subId = (mSubId == DEFAULT_SUBSCRIPTION_ID)
- ? getDefaultSmsSubscriptionId() : mSubId;
+ final int subId = getSubIdOrDefault();
boolean isSmsSimPickActivityNeeded = false;
final Context context = ActivityThread.currentApplication().getApplicationContext();
try {
@@ -975,6 +974,17 @@
}
/**
+ * @return the subscription ID associated with this {@link SmsManager} or the default set by the
+ * user if this instance was created using {@link SmsManager#getDefault}.
+ *
+ * If there is no default set by the user, this method returns
+ * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}.
+ */
+ private int getSubIdOrDefault() {
+ return (mSubId == DEFAULT_SUBSCRIPTION_ID) ? getDefaultSmsSubscriptionId() : mSubId;
+ }
+
+ /**
* Returns the ISms service, or throws an UnsupportedOperationException if
* the service does not exist.
*/
@@ -1141,8 +1151,9 @@
try {
ISms iSms = getISmsService();
if (iSms != null) {
- success = iSms.enableCellBroadcastForSubscriber(
- getSubscriptionId(), messageIdentifier, ranType);
+ // If getSubIdOrDefault() returns INVALID, we will use the default phone internally.
+ success = iSms.enableCellBroadcastForSubscriber(getSubIdOrDefault(),
+ messageIdentifier, ranType);
}
} catch (RemoteException ex) {
// ignore it
@@ -1177,8 +1188,9 @@
try {
ISms iSms = getISmsService();
if (iSms != null) {
- success = iSms.disableCellBroadcastForSubscriber(
- getSubscriptionId(), messageIdentifier, ranType);
+ // If getSubIdOrDefault() returns INVALID, we will use the default phone internally.
+ success = iSms.disableCellBroadcastForSubscriber(getSubIdOrDefault(),
+ messageIdentifier, ranType);
}
} catch (RemoteException ex) {
// ignore it
@@ -1220,7 +1232,8 @@
try {
ISms iSms = getISmsService();
if (iSms != null) {
- success = iSms.enableCellBroadcastRangeForSubscriber(getSubscriptionId(),
+ // If getSubIdOrDefault() returns INVALID, we will use the default phone internally.
+ success = iSms.enableCellBroadcastRangeForSubscriber(getSubIdOrDefault(),
startMessageId, endMessageId, ranType);
}
} catch (RemoteException ex) {
@@ -1263,7 +1276,8 @@
try {
ISms iSms = getISmsService();
if (iSms != null) {
- success = iSms.disableCellBroadcastRangeForSubscriber(getSubscriptionId(),
+ // If getSubIdOrDefault() returns INVALID, we will use the default phone internally.
+ success = iSms.disableCellBroadcastRangeForSubscriber(getSubIdOrDefault(),
startMessageId, endMessageId, ranType);
}
} catch (RemoteException ex) {
diff --git a/telephony/java/android/telephony/SubscriptionInfo.java b/telephony/java/android/telephony/SubscriptionInfo.java
index b781b10..d636918 100644
--- a/telephony/java/android/telephony/SubscriptionInfo.java
+++ b/telephony/java/android/telephony/SubscriptionInfo.java
@@ -32,6 +32,7 @@
import android.graphics.Typeface;
import android.os.Build;
import android.os.Parcel;
+import android.os.ParcelUuid;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.DisplayMetrics;
@@ -154,16 +155,11 @@
private boolean mIsOpportunistic;
/**
- * A UUID assigned to the subscription group. It returns
- * null if not assigned.
+ * A UUID assigned to the subscription group. It returns null if not assigned.
+ * Check {@link SubscriptionManager#createSubscriptionGroup(List)} for more details.
*/
@Nullable
- private String mGroupUUID;
-
- /**
- * A property in opportunistic subscription to indicate whether it is metered or not.
- */
- private boolean mIsMetered;
+ private ParcelUuid mGroupUUID;
/**
* Whether group of the subscription is disabled.
@@ -197,7 +193,7 @@
@Nullable UiccAccessRule[] accessRules, String cardString) {
this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, cardString,
- false, null, true, TelephonyManager.UNKNOWN_CARRIER_ID,
+ false, null, TelephonyManager.UNKNOWN_CARRIER_ID,
SubscriptionManager.PROFILE_CLASS_DEFAULT);
}
@@ -208,10 +204,10 @@
CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded,
@Nullable UiccAccessRule[] accessRules, String cardString, boolean isOpportunistic,
- @Nullable String groupUUID, boolean isMetered, int carrierId, int profileClass) {
+ @Nullable String groupUUID, int carrierId, int profileClass) {
this(id, iccId, simSlotIndex, displayName, carrierName, nameSource, iconTint, number,
roaming, icon, mcc, mnc, countryIso, isEmbedded, accessRules, cardString, -1,
- isOpportunistic, groupUUID, isMetered, false, carrierId, profileClass,
+ isOpportunistic, groupUUID, false, carrierId, profileClass,
SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM);
}
@@ -222,7 +218,7 @@
CharSequence carrierName, int nameSource, int iconTint, String number, int roaming,
Bitmap icon, String mcc, String mnc, String countryIso, boolean isEmbedded,
@Nullable UiccAccessRule[] accessRules, String cardString, int cardId,
- boolean isOpportunistic, @Nullable String groupUUID, boolean isMetered,
+ boolean isOpportunistic, @Nullable String groupUUID,
boolean isGroupDisabled, int carrierId, int profileClass, int subType) {
this.mId = id;
this.mIccId = iccId;
@@ -242,8 +238,7 @@
this.mCardString = cardString;
this.mCardId = cardId;
this.mIsOpportunistic = isOpportunistic;
- this.mGroupUUID = groupUUID;
- this.mIsMetered = isMetered;
+ this.mGroupUUID = groupUUID == null ? null : ParcelUuid.fromString(groupUUID);
this.mIsGroupDisabled = isGroupDisabled;
this.mCarrierId = carrierId;
this.mProfileClass = profileClass;
@@ -467,23 +462,11 @@
* @return group UUID a String of group UUID if it belongs to a group. Otherwise
* it will return null.
*/
- public @Nullable String getGroupUuid() {
+ public @Nullable ParcelUuid getGroupUuid() {
return mGroupUUID;
}
/**
- * Used in opportunistic subscription ({@link #isOpportunistic()}) to indicate whether it's
- * metered or not.This is one of the factors when deciding to switch to the subscription.
- * (a non-metered subscription, for example, would likely be preferred over a metered one).
- *
- * @return whether subscription is metered.
- * @hide
- */
- public boolean isMetered() {
- return mIsMetered;
- }
-
- /**
* @return the profile class of this subscription.
* @hide
*/
@@ -623,7 +606,6 @@
int cardId = source.readInt();
boolean isOpportunistic = source.readBoolean();
String groupUUID = source.readString();
- boolean isMetered = source.readBoolean();
boolean isGroupDisabled = source.readBoolean();
int carrierid = source.readInt();
int profileClass = source.readInt();
@@ -632,7 +614,7 @@
return new SubscriptionInfo(id, iccId, simSlotIndex, displayName, carrierName,
nameSource, iconTint, number, dataRoaming, iconBitmap, mcc, mnc, countryIso,
isEmbedded, accessRules, cardString, cardId, isOpportunistic, groupUUID,
- isMetered, isGroupDisabled, carrierid, profileClass, subType);
+ isGroupDisabled, carrierid, profileClass, subType);
}
@Override
@@ -661,8 +643,7 @@
dest.writeString(mCardString);
dest.writeInt(mCardId);
dest.writeBoolean(mIsOpportunistic);
- dest.writeString(mGroupUUID);
- dest.writeBoolean(mIsMetered);
+ dest.writeString(mGroupUUID == null ? null : mGroupUUID.toString());
dest.writeBoolean(mIsGroupDisabled);
dest.writeInt(mCarrierId);
dest.writeInt(mProfileClass);
@@ -702,7 +683,7 @@
+ " accessRules " + Arrays.toString(mAccessRules)
+ " cardString=" + cardStringToPrint + " cardId=" + mCardId
+ " isOpportunistic " + mIsOpportunistic + " mGroupUUID=" + mGroupUUID
- + " isMetered=" + mIsMetered + " mIsGroupDisabled=" + mIsGroupDisabled
+ + " mIsGroupDisabled=" + mIsGroupDisabled
+ " profileClass=" + mProfileClass
+ " subscriptionType=" + mSubscriptionType + "}";
}
@@ -710,7 +691,7 @@
@Override
public int hashCode() {
return Objects.hash(mId, mSimSlotIndex, mNameSource, mIconTint, mDataRoaming, mIsEmbedded,
- mIsOpportunistic, mGroupUUID, mIsMetered, mIccId, mNumber, mMcc, mMnc,
+ mIsOpportunistic, mGroupUUID, mIccId, mNumber, mMcc, mMnc,
mCountryIso, mCardString, mCardId, mDisplayName, mCarrierName, mAccessRules,
mIsGroupDisabled, mCarrierId, mProfileClass);
}
@@ -736,7 +717,6 @@
&& mIsOpportunistic == toCompare.mIsOpportunistic
&& mIsGroupDisabled == toCompare.mIsGroupDisabled
&& mCarrierId == toCompare.mCarrierId
- && mIsMetered == toCompare.mIsMetered
&& Objects.equals(mGroupUUID, toCompare.mGroupUUID)
&& Objects.equals(mIccId, toCompare.mIccId)
&& Objects.equals(mNumber, toCompare.mNumber)
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index d586228..801f937 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -50,11 +50,12 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.ParcelUuid;
+import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.telephony.euicc.EuiccManager;
import android.telephony.ims.ImsMmTelManager;
-import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
@@ -1753,6 +1754,10 @@
Rlog.d(LOG_TAG, msg);
}
+ private static void loge(String msg) {
+ Rlog.e(LOG_TAG, msg);
+ }
+
/**
* Returns the system's default subscription id.
*
@@ -1992,24 +1997,6 @@
}
/**
- * If a default is set to subscription which is not active, this will reset that default back to
- * an invalid subscription id, i.e. < 0.
- * @hide
- */
- @UnsupportedAppUsage
- public void clearDefaultsForInactiveSubIds() {
- if (VDBG) logd("clearDefaultsForInactiveSubIds");
- try {
- ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
- if (iSub != null) {
- iSub.clearDefaultsForInactiveSubIds();
- }
- } catch (RemoteException ex) {
- // ignore it
- }
- }
-
- /**
* Check if the supplied subscription ID is valid.
*
* <p>A valid subscription ID is not necessarily an active subscription ID
@@ -2596,11 +2583,12 @@
* {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID}, it means
* it's unset and {@link SubscriptionManager#getDefaultDataSubscriptionId()}
* is used to determine which modem is preferred.
- * @param needValidation whether validation is needed before switch happens.
+ * @param needValidation whether Telephony will wait until the network is validated by
+ * connectivity service before switching data to it. More details see
+ * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED}.
* @param executor The executor of where the callback will execute.
* @param callback Callback will be triggered once it succeeds or failed.
- * See {@link TelephonyManager.SetOpportunisticSubscriptionResult}
- * for more details. Pass null if don't care about the result.
+ * Pass null if don't care about the result.
*
* @hide
*
@@ -2608,7 +2596,8 @@
@SystemApi
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void setPreferredDataSubscriptionId(int subId, boolean needValidation,
- @Nullable @CallbackExecutor Executor executor, @Nullable Consumer<Integer> callback) {
+ @Nullable @CallbackExecutor Executor executor, @Nullable
+ @TelephonyManager.SetOpportunisticSubscriptionResult Consumer<Integer> callback) {
if (VDBG) logd("[setPreferredDataSubscriptionId]+ subId:" + subId);
try {
ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
@@ -2739,11 +2728,20 @@
/**
* Inform SubscriptionManager that subscriptions in the list are bundled
- * as a group. Typically it's a primary subscription and an opportunistic
- * subscription. It should only affect multi-SIM scenarios where primary
- * and opportunistic subscriptions can be activated together.
- * Being in the same group means they might be activated or deactivated
- * together, some of them may be invisible to the users, etc.
+ * as a group. It can be multiple primary (non-opportunistic) subscriptions,
+ * or one or more primary plus one or more opportunistic subscriptions.
+ *
+ * This API will always create a new immutable group and assign group UUID to all the
+ * subscriptions, regardless whether they are in a group already or not.
+ *
+ * Grouped subscriptions will have below behaviors:
+ * 1) They will share the same user settings.
+ * 2) The opportunistic subscriptions in the group is considered invisible and will not
+ * return from {@link #getActiveSubscriptionInfoList()}, unless caller has carrier
+ * privilege permission of the subscriptions.
+ * 3) The opportunistic subscriptions in the group can't be active by itself. If all other
+ * non-opportunistic ones are deactivated (unplugged or disabled in Settings),
+ * the opportunistic ones will be deactivated automatically.
*
* Caller will either have {@link android.Manifest.permission#MODIFY_PHONE_STATE}
* permission or had carrier privilege permission on the subscriptions:
@@ -2754,34 +2752,42 @@
* outlined above.
*
* @param subIdList list of subId that will be in the same group
- * @return groupUUID a UUID assigned to the subscription group. It returns
- * null if fails.
+ * @return groupUUID a UUID assigned to the subscription group.
*
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public @Nullable String setSubscriptionGroup(@NonNull int[] subIdList) {
+ public @NonNull ParcelUuid createSubscriptionGroup(@NonNull List<Integer> subIdList) {
+ Preconditions.checkNotNull(subIdList, "can't create group for null subId list");
String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
if (VDBG) {
- logd("[setSubscriptionGroup]+ subIdList:" + Arrays.toString(subIdList));
+ logd("[createSubscriptionGroup]");
}
- String groupUUID = null;
+ ParcelUuid groupUuid = null;
+ int[] subIdArray = subIdList.stream().mapToInt(i->i).toArray();
try {
ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
if (iSub != null) {
- groupUUID = iSub.setSubscriptionGroup(subIdList, pkgForDebug);
+ groupUuid = iSub.createSubscriptionGroup(subIdArray, pkgForDebug);
+ } else {
+ if (!isSystemProcess()) {
+ throw new IllegalStateException("telephony service is null.");
+ }
}
} catch (RemoteException ex) {
- // ignore it
+ loge("createSubscriptionGroup RemoteException " + ex);
+ if (!isSystemProcess()) {
+ ex.rethrowAsRuntimeException();
+ }
}
- return groupUUID;
+ return groupUuid;
}
/**
- * Remove a list of subscriptions from their subscription group.
- * See {@link #setSubscriptionGroup(int[])} for more details.
+ * Add a list of subscriptions into a group.
+ * See {@link #createSubscriptionGroup(List)} for more details.
*
* Caller will either have {@link android.Manifest.permission#MODIFY_PHONE_STATE}
* permission or had carrier privilege permission on the subscriptions:
@@ -2790,34 +2796,97 @@
*
* @throws SecurityException if the caller doesn't meet the requirements
* outlined above.
+ * @throws IllegalArgumentException if the some subscriptions in the list doesn't exist,
+ * or the groupUuid doesn't exist.
*
- * @param subIdList list of subId that need removing from their groups.
- * @return whether the operation succeeds.
+ * @param subIdList list of subId that need adding into the group
+ * @param groupUuid the groupUuid the subscriptions are being added to.
*
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
- public boolean removeSubscriptionsFromGroup(@NonNull int[] subIdList) {
+ public void addSubscriptionsIntoGroup(@NonNull List<Integer> subIdList,
+ @NonNull ParcelUuid groupUuid) {
+ Preconditions.checkNotNull(subIdList, "subIdList can't be null.");
+ Preconditions.checkNotNull(groupUuid, "groupUuid can't be null.");
String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
if (VDBG) {
- logd("[removeSubscriptionsFromGroup]+ subIdList:" + Arrays.toString(subIdList));
+ logd("[addSubscriptionsIntoGroup]");
}
+ int[] subIdArray = subIdList.stream().mapToInt(i->i).toArray();
+
try {
ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
if (iSub != null) {
- return iSub.removeSubscriptionsFromGroup(subIdList, pkgForDebug);
+ iSub.addSubscriptionsIntoGroup(subIdArray, groupUuid, pkgForDebug);
+ } else {
+ if (!isSystemProcess()) {
+ throw new IllegalStateException("telephony service is null.");
+ }
}
} catch (RemoteException ex) {
- // ignore it
+ loge("addSubscriptionsIntoGroup RemoteException " + ex);
+ if (!isSystemProcess()) {
+ ex.rethrowAsRuntimeException();
+ }
+ }
+ }
+
+ private boolean isSystemProcess() {
+ return Process.myUid() == Process.SYSTEM_UID;
+ }
+
+ /**
+ * Remove a list of subscriptions from their subscription group.
+ * See {@link #createSubscriptionGroup(List)} for more details.
+ *
+ * Caller will either have {@link android.Manifest.permission#MODIFY_PHONE_STATE}
+ * permission or had carrier privilege permission on the subscriptions:
+ * {@link TelephonyManager#hasCarrierPrivileges()} or
+ * {@link #canManageSubscription(SubscriptionInfo)}
+ *
+ * @throws SecurityException if the caller doesn't meet the requirements
+ * outlined above.
+ * @throws IllegalArgumentException if the some subscriptions in the list doesn't belong
+ * the specified group.
+ *
+ * @param subIdList list of subId that need removing from their groups.
+ *
+ */
+ @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
+ public void removeSubscriptionsFromGroup(@NonNull List<Integer> subIdList,
+ @NonNull ParcelUuid groupUuid) {
+ Preconditions.checkNotNull(subIdList, "subIdList can't be null.");
+ Preconditions.checkNotNull(groupUuid, "groupUuid can't be null.");
+ String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
+ if (VDBG) {
+ logd("[removeSubscriptionsFromGroup]");
}
- return false;
+ int[] subIdArray = subIdList.stream().mapToInt(i->i).toArray();
+
+ try {
+ ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+ if (iSub != null) {
+ iSub.removeSubscriptionsFromGroup(subIdArray, groupUuid, pkgForDebug);
+ } else {
+ if (!isSystemProcess()) {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ }
+ } catch (RemoteException ex) {
+ loge("removeSubscriptionsFromGroup RemoteException " + ex);
+ if (!isSystemProcess()) {
+ ex.rethrowAsRuntimeException();
+ }
+ }
}
/**
* Get subscriptionInfo list of subscriptions that are in the same group of given subId.
- * See {@link #setSubscriptionGroup(int[])} for more details.
+ * See {@link #createSubscriptionGroup(List)} for more details.
*
* Caller will either have {@link android.Manifest.permission#READ_PHONE_STATE}
* permission or had carrier privilege permission on the subscription.
@@ -2826,57 +2895,41 @@
* @throws SecurityException if the caller doesn't meet the requirements
* outlined above.
*
- * @param subId of which list of subInfo from the same group will be returned.
+ * @param groupUuid of which list of subInfo will be returned.
* @return list of subscriptionInfo that belong to the same group, including the given
- * subscription itself. It will return null if the subscription doesn't exist or it
- * doesn't belong to any group.
+ * subscription itself. It will return an empty list if no subscription belongs to the group.
*
*/
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
@RequiresPermission(Manifest.permission.READ_PHONE_STATE)
- public @Nullable List<SubscriptionInfo> getSubscriptionsInGroup(int subId) {
+ public @NonNull List<SubscriptionInfo> getSubscriptionsInGroup(@NonNull ParcelUuid groupUuid) {
+ Preconditions.checkNotNull(groupUuid, "groupUuid can't be null");
String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
if (VDBG) {
- logd("[getSubscriptionsInGroup]+ subId:" + subId);
+ logd("[getSubscriptionsInGroup]+ groupUuid:" + groupUuid);
}
List<SubscriptionInfo> result = null;
try {
ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
if (iSub != null) {
- result = iSub.getSubscriptionsInGroup(subId, pkgForDebug);
+ result = iSub.getSubscriptionsInGroup(groupUuid, pkgForDebug);
+ } else {
+ if (!isSystemProcess()) {
+ throw new IllegalStateException("telephony service is null.");
+ }
}
} catch (RemoteException ex) {
- // ignore it
+ loge("removeSubscriptionsFromGroup RemoteException " + ex);
+ if (!isSystemProcess()) {
+ ex.rethrowAsRuntimeException();
+ }
}
return result;
}
/**
- * Set if a subscription is metered or not. Similar to Wi-Fi, metered means
- * user may be charged more if more data is used.
- *
- * By default all Cellular networks are considered metered. System or carrier privileged apps
- * can set a subscription un-metered which will be considered when system switches data between
- * primary subscription and opportunistic subscription.
- *
- * Caller will either have {@link android.Manifest.permission#MODIFY_PHONE_STATE} or carrier
- * privilege permission of the subscription.
- *
- * @param isMetered whether it’s a metered subscription.
- * @param subId the unique SubscriptionInfo index in database
- * @return {@code true} if the operation is succeed, {@code false} otherwise.
- */
- @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
- public boolean setMetered(boolean isMetered, int subId) {
- if (VDBG) logd("[setIsMetered]+ isMetered:" + isMetered + " subId:" + subId);
- return setSubscriptionPropertyHelper(subId, "setIsMetered",
- (iSub)-> iSub.setMetered(isMetered, subId, mContext.getOpPackageName())) == 1;
- }
-
- /**
* Whether a subscription is visible to API caller. If it's a bundled opportunistic
* subscription, it should be hidden anywhere in Settings, dialer, status bar etc.
* Exception is if caller owns carrier privilege, in which case they will
@@ -2890,7 +2943,7 @@
if (info == null) return false;
// If subscription is NOT grouped opportunistic subscription, it's visible.
- if (TextUtils.isEmpty(info.getGroupUuid()) || !info.isOpportunistic()) return true;
+ if (info.getGroupUuid() == null || !info.isOpportunistic()) return true;
// If the caller is the carrier app and owns the subscription, it should be visible
// to the caller.
@@ -2920,14 +2973,14 @@
// It should be the current active primary subscription if any, or any
// primary subscription.
List<SubscriptionInfo> selectableList = new ArrayList<>();
- Map<String, SubscriptionInfo> groupMap = new HashMap<>();
+ Map<ParcelUuid, SubscriptionInfo> groupMap = new HashMap<>();
for (SubscriptionInfo info : availableList) {
// Opportunistic subscriptions are considered invisible
// to users so they should never be returned.
if (!isSubscriptionVisible(info)) continue;
- String groupUuid = info.getGroupUuid();
+ ParcelUuid groupUuid = info.getGroupUuid();
if (groupUuid == null) {
// Doesn't belong to any group. Add in the list.
selectableList.add(info);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 4ea613c..12acf9d 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1321,7 +1321,7 @@
/**
* An int extra used with {@link #ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED} to indicate the
- * subscription which has changed.
+ * subscription which has changed; or in general whenever a subscription ID needs specified.
*/
public static final String EXTRA_SUBSCRIPTION_ID = "android.telephony.extra.SUBSCRIPTION_ID";
@@ -1417,6 +1417,72 @@
public static final String EXTRA_ANOMALY_DESCRIPTION =
"android.telephony.extra.ANOMALY_DESCRIPTION";
+ /**
+ * Broadcast intent sent to indicate primary (non-opportunistic) subscription list has changed.
+ *
+ * @hide
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_PRIMARY_SUBSCRIPTION_LIST_CHANGED =
+ "android.telephony.action.PRIMARY_SUBSCRIPTION_LIST_CHANGED";
+
+ /**
+ * Integer intent extra to be used with {@link #ACTION_PRIMARY_SUBSCRIPTION_LIST_CHANGED}
+ * to indicate what type of SIM selection is needed.
+ *
+ * @hide
+ */
+ public static final String EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE =
+ "android.telephony.extra.DEFAULT_SUBSCRIPTION_SELECT_TYPE";
+
+ /** @hide */
+ @IntDef({
+ EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE,
+ EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DATA,
+ EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_VOICE,
+ EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_SMS,
+ EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_ALL
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DefaultSubscriptionSelectType{}
+
+ /**
+ * Used as an int value for {@link #EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE}
+ * to indicate there's no need to re-select any default subscription.
+ * @hide
+ */
+ public static final int EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_NONE = 0;
+
+ /**
+ * Used as an int value for {@link #EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE}
+ * to indicate there's a need to select default data subscription.
+ * @hide
+ */
+ public static final int EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_DATA = 1;
+
+ /**
+ * Used as an int value for {@link #EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE}
+ * to indicate there's a need to select default voice call subscription.
+ * @hide
+ */
+ public static final int EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_VOICE = 2;
+
+ /**
+ * Used as an int value for {@link #EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE}
+ * to indicate there's a need to select default sms subscription.
+ * @hide
+ */
+ public static final int EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_SMS = 3;
+
+ /**
+ * Used as an int value for {@link #EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE}
+ * to indicate user to decide whether current SIM should be preferred for all
+ * data / voice / sms. {@link #EXTRA_SUBSCRIPTION_ID} will specified to indicate
+ * which subscription should be the default subscription.
+ * @hide
+ */
+ public static final int EXTRA_DEFAULT_SUBSCRIPTION_SELECT_TYPE_ALL = 4;
+
//
//
// Device Info
@@ -2581,7 +2647,7 @@
*/
/** {@hide} */
@UnsupportedAppUsage
- public static String getNetworkTypeName(int type) {
+ public static String getNetworkTypeName(@NetworkType int type) {
switch (type) {
case NETWORK_TYPE_GPRS:
return "GPRS";
@@ -3667,6 +3733,7 @@
* @hide
* nobody seems to call this.
*/
+ @TestApi
@RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
public String getLine1AlphaTag() {
return getLine1AlphaTag(getSubId());
@@ -4722,6 +4789,22 @@
}
}
+ /**
+ * Convert data state to string
+ *
+ * @return The data state in string format.
+ * @hide
+ */
+ public static String dataStateToString(@DataState int state) {
+ switch (state) {
+ case DATA_DISCONNECTED: return "DISCONNECTED";
+ case DATA_CONNECTING: return "CONNECTING";
+ case DATA_CONNECTED: return "CONNECTED";
+ case DATA_SUSPENDED: return "SUSPENDED";
+ }
+ return "UNKNOWN(" + state + ")";
+ }
+
/**
* @hide
*/
@@ -5177,6 +5260,18 @@
* Use this method when no subscriptions are available on the SIM and the operation must be
* performed using the physical slot index.
*
+ * This operation wraps two APDU instructions:
+ * <ul>
+ * <li>MANAGE CHANNEL to open a logical channel</li>
+ * <li>SELECT the given {@code AID} using the given {@code p2}</li>
+ * </ul>
+ *
+ * Per Open Mobile API Specification v3.2 section 6.2.7.h, only p2 values of 0x00, 0x04, 0x08,
+ * and 0x0C are guaranteed to be supported.
+ *
+ * If the SELECT command's status word is not '9000', '62xx', or '63xx', the status word will be
+ * considered an error and the channel shall not be opened.
+ *
* Input parameters equivalent to TS 27.007 AT+CCHO command.
*
* <p>Requires Permission:
@@ -5208,6 +5303,18 @@
/**
* Opens a logical channel to the ICC card.
*
+ * This operation wraps two APDU instructions:
+ * <ul>
+ * <li>MANAGE CHANNEL to open a logical channel</li>
+ * <li>SELECT the given {@code AID} using the given {@code p2}</li>
+ * </ul>
+ *
+ * Per Open Mobile API Specification v3.2 section 6.2.7.h, only p2 values of 0x00, 0x04, 0x08,
+ * and 0x0C are guaranteed to be supported.
+ *
+ * If the SELECT command's status word is not '9000', '62xx', or '63xx', the status word will be
+ * considered an error and the channel shall not be opened.
+ *
* Input parameters equivalent to TS 27.007 AT+CCHO command.
*
* <p>Requires Permission:
@@ -5225,6 +5332,18 @@
/**
* Opens a logical channel to the ICC card.
*
+ * This operation wraps two APDU instructions:
+ * <ul>
+ * <li>MANAGE CHANNEL to open a logical channel</li>
+ * <li>SELECT the given {@code AID} using the given {@code p2}</li>
+ * </ul>
+ *
+ * Per Open Mobile API Specification v3.2 section 6.2.7.h, only p2 values of 0x00, 0x04, 0x08,
+ * and 0x0C are guaranteed to be supported.
+ *
+ * If the SELECT command's status word is not '9000', '62xx', or '63xx', the status word will be
+ * considered an error and the channel shall not be opened.
+ *
* Input parameters equivalent to TS 27.007 AT+CCHO command.
*
* <p>Requires Permission:
@@ -6864,6 +6983,17 @@
* app has carrier privileges (see {@link #hasCarrierPrivileges})
* and {@link android.Manifest.permission#ACCESS_FINE_LOCATION}.
*
+ * If the system-wide location switch is off, apps may still call this API, with the
+ * following constraints:
+ * <ol>
+ * <li>The app must hold the {@code android.permission.NETWORK_SCAN} permission.</li>
+ * <li>The app must not supply any specific bands or channels to scan.</li>
+ * <li>The app must only specify MCC/MNC pairs that are
+ * associated to a SIM in the device.</li>
+ * <li>Returned results will have no meaningful info other than signal strength
+ * and MCC/MNC info.</li>
+ * </ol>
+ *
* @param request Contains all the RAT with bands/channels that need to be scanned.
* @param executor The executor through which the callback should be invoked. Since the scan
* request may trigger multiple callbacks and they must be invoked in the same order as
@@ -8836,6 +8966,27 @@
return retval;
}
+ /**
+ * Determines the {@link PhoneAccountHandle} associated with a subscription Id.
+ *
+ * @param subscriptionId The subscription Id to check.
+ * @return The {@link PhoneAccountHandle} associated with a subscription Id, or {@code null} if
+ * there is no associated {@link PhoneAccountHandle}.
+ * @hide
+ */
+ public @Nullable PhoneAccountHandle getPhoneAccountHandleForSubscriptionId(int subscriptionId) {
+ PhoneAccountHandle returnValue = null;
+ try {
+ ITelephony service = getITelephony();
+ if (service != null) {
+ returnValue = service.getPhoneAccountHandleForSubscriptionId(subscriptionId);
+ }
+ } catch (RemoteException e) {
+ }
+
+ return returnValue;
+ }
+
private int getSubIdForPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle) {
int retval = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
try {
@@ -10334,7 +10485,7 @@
@IntDef(prefix = {"SET_OPPORTUNISTIC_SUB"}, value = {
SET_OPPORTUNISTIC_SUB_SUCCESS,
SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED,
- SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER})
+ SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION})
public @interface SetOpportunisticSubscriptionResult {}
/**
@@ -10348,9 +10499,9 @@
public static final int SET_OPPORTUNISTIC_SUB_VALIDATION_FAILED = 1;
/**
- * The parameter passed in is invalid.
+ * The subscription is not valid. It must be an active opportunistic subscription.
*/
- public static final int SET_OPPORTUNISTIC_SUB_INVALID_PARAMETER = 2;
+ public static final int SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION = 2;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -10546,6 +10697,25 @@
}
/**
+ * It indicates whether modem is enabled or not per slot.
+ * It's the corresponding status of {@link #enableModemForSlot}.
+ *
+ * @param slotIndex which slot it's checking.
+ * @hide
+ */
+ public boolean isModemEnabledForSlot(int slotIndex) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.isModemEnabledForSlot(slotIndex, mContext.getOpPackageName());
+ }
+ } catch (RemoteException ex) {
+ Log.e(TAG, "enableModem RemoteException", ex);
+ }
+ return false;
+ }
+
+ /**
* Indicate if the user is allowed to use multiple SIM cards at the same time to register
* on the network (e.g. Dual Standby or Dual Active) when the device supports it, or if the
* usage is restricted. This API is used to prevent usage of multiple SIM card, based on
diff --git a/telephony/java/android/telephony/TelephonyScanManager.java b/telephony/java/android/telephony/TelephonyScanManager.java
index 91f74b8..28747da 100644
--- a/telephony/java/android/telephony/TelephonyScanManager.java
+++ b/telephony/java/android/telephony/TelephonyScanManager.java
@@ -53,6 +53,11 @@
public static final int CALLBACK_SCAN_ERROR = 2;
/** @hide */
public static final int CALLBACK_SCAN_COMPLETE = 3;
+ /** @hide */
+ public static final int CALLBACK_RESTRICTED_SCAN_RESULTS = 4;
+
+ /** @hide */
+ public static final int INVALID_SCAN_ID = -1;
/**
* The caller of
@@ -129,6 +134,7 @@
}
switch (message.what) {
+ case CALLBACK_RESTRICTED_SCAN_RESULTS:
case CALLBACK_SCAN_RESULTS:
try {
final Bundle b = message.getData();
@@ -137,9 +143,9 @@
for (int i = 0; i < parcelables.length; i++) {
ci[i] = (CellInfo) parcelables[i];
}
- executor.execute(() ->{
+ executor.execute(() -> {
Rlog.d(TAG, "onResults: " + ci.toString());
- callback.onResults((List<CellInfo>) Arrays.asList(ci));
+ callback.onResults(Arrays.asList(ci));
});
} catch (Exception e) {
Rlog.e(TAG, "Exception in networkscan callback onResults", e);
@@ -200,6 +206,10 @@
if (telephony != null) {
int scanId = telephony.requestNetworkScan(
subId, request, mMessenger, new Binder(), callingPackage);
+ if (scanId == INVALID_SCAN_ID) {
+ Rlog.e(TAG, "Failed to initiate network scan");
+ return null;
+ }
saveScanInfo(scanId, request, executor, callback);
return new NetworkScan(scanId, subId);
}
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 4b9abc1..4a7585d 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -78,10 +78,11 @@
*/
public static final int TYPE_NONE = ApnTypes.NONE;
/**
- * APN type for all APNs.
+ * APN type for all APNs (except wild-cardable types).
* @hide
*/
- public static final int TYPE_ALL = ApnTypes.ALL | ApnTypes.MCX;
+ public static final int TYPE_ALL = ApnTypes.DEFAULT | ApnTypes.HIPRI | ApnTypes.MMS
+ | ApnTypes.SUPL | ApnTypes.DUN | ApnTypes.FOTA | ApnTypes.IMS | ApnTypes.CBS;
/** APN type for default data traffic. */
public static final int TYPE_DEFAULT = ApnTypes.DEFAULT | ApnTypes.HIPRI;
/** APN type for MMS traffic. */
diff --git a/telephony/java/android/telephony/ims/RcsGroupThread.java b/telephony/java/android/telephony/ims/RcsGroupThread.java
index 8cd633b..baec19a 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThread.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThread.java
@@ -169,8 +169,9 @@
RcsParticipantQueryParams queryParameters =
new RcsParticipantQueryParams.Builder().setThread(this).build();
- RcsParticipantQueryResult queryResult = RcsControllerCall.call(
- iRcs -> iRcs.getParticipants(queryParameters));
+ RcsParticipantQueryResult queryResult = new RcsParticipantQueryResult(
+ RcsControllerCall.call(
+ iRcs -> iRcs.getParticipants(queryParameters)));
List<RcsParticipant> participantList = queryResult.getParticipants();
Set<RcsParticipant> participantSet = new LinkedHashSet<>(participantList);
diff --git a/telephony/java/android/telephony/ims/RcsMessageStore.java b/telephony/java/android/telephony/ims/RcsMessageStore.java
index 3111652..6fcb62b 100644
--- a/telephony/java/android/telephony/ims/RcsMessageStore.java
+++ b/telephony/java/android/telephony/ims/RcsMessageStore.java
@@ -41,7 +41,8 @@
@NonNull
public RcsThreadQueryResult getRcsThreads(@Nullable RcsThreadQueryParams queryParameters)
throws RcsMessageStoreException {
- return RcsControllerCall.call(iRcs -> iRcs.getRcsThreads(queryParameters));
+ return new RcsThreadQueryResult(
+ RcsControllerCall.call(iRcs -> iRcs.getRcsThreads(queryParameters)));
}
/**
@@ -55,7 +56,8 @@
@NonNull
public RcsThreadQueryResult getRcsThreads(@NonNull RcsQueryContinuationToken continuationToken)
throws RcsMessageStoreException {
- return RcsControllerCall.call(iRcs -> iRcs.getRcsThreadsWithToken(continuationToken));
+ return new RcsThreadQueryResult(
+ RcsControllerCall.call(iRcs -> iRcs.getRcsThreadsWithToken(continuationToken)));
}
/**
@@ -70,7 +72,8 @@
public RcsParticipantQueryResult getRcsParticipants(
@Nullable RcsParticipantQueryParams queryParameters)
throws RcsMessageStoreException {
- return RcsControllerCall.call(iRcs -> iRcs.getParticipants(queryParameters));
+ return new RcsParticipantQueryResult(
+ RcsControllerCall.call(iRcs -> iRcs.getParticipants(queryParameters)));
}
/**
@@ -86,7 +89,8 @@
public RcsParticipantQueryResult getRcsParticipants(
@NonNull RcsQueryContinuationToken continuationToken)
throws RcsMessageStoreException {
- return RcsControllerCall.call(iRcs -> iRcs.getParticipantsWithToken(continuationToken));
+ return new RcsParticipantQueryResult(
+ RcsControllerCall.call(iRcs -> iRcs.getParticipantsWithToken(continuationToken)));
}
/**
@@ -121,7 +125,7 @@
* Returns the first chunk of existing {@link RcsEvent}s in the common storage.
*
* @param queryParams Parameters to specify to return a subset of all RcsEvents.
- * Passing a value of null will return all events.
+ * Passing a value of null will return all events.
* @throws RcsMessageStoreException if the query could not be completed on the storage
*/
@WorkerThread
@@ -152,7 +156,6 @@
*
* @param persistableEvent The {@link RcsEvent} to persist into storage.
* @throws RcsMessageStoreException if the query could not be completed on the storage
- *
* @see RcsGroupThreadNameChangedEvent
* @see RcsGroupThreadIconChangedEvent
* @see RcsGroupThreadParticipantJoinedEvent
diff --git a/telephony/java/android/telephony/ims/RcsParticipantQueryResult.java b/telephony/java/android/telephony/ims/RcsParticipantQueryResult.java
index 3e5c231..731c94e 100644
--- a/telephony/java/android/telephony/ims/RcsParticipantQueryResult.java
+++ b/telephony/java/android/telephony/ims/RcsParticipantQueryResult.java
@@ -18,11 +18,9 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-import java.util.ArrayList;
import java.util.List;
+import java.util.stream.Collectors;
/**
* The result of a {@link RcsMessageStore#getRcsParticipants(RcsParticipantQueryParams)}
@@ -31,23 +29,12 @@
*
* @hide
*/
-public final class RcsParticipantQueryResult implements Parcelable {
- // A token for the caller to continue their query for the next batch of results
- private RcsQueryContinuationToken mContinuationToken;
- // The list of participant IDs returned with this query
- private List<Integer> mParticipants;
+public final class RcsParticipantQueryResult {
+ private final RcsParticipantQueryResultParcelable mRcsParticipantQueryResultParcelable;
- /**
- * Internal constructor for {@link com.android.internal.telephony.ims.RcsMessageStoreController}
- * to create query results
- *
- * @hide
- */
- public RcsParticipantQueryResult(
- RcsQueryContinuationToken continuationToken,
- List<Integer> participants) {
- mContinuationToken = continuationToken;
- mParticipants = participants;
+ RcsParticipantQueryResult(
+ RcsParticipantQueryResultParcelable rcsParticipantQueryResultParcelable) {
+ mRcsParticipantQueryResultParcelable = rcsParticipantQueryResultParcelable;
}
/**
@@ -57,7 +44,7 @@
*/
@Nullable
public RcsQueryContinuationToken getContinuationToken() {
- return mContinuationToken;
+ return mRcsParticipantQueryResultParcelable.mContinuationToken;
}
/**
@@ -67,39 +54,8 @@
*/
@NonNull
public List<RcsParticipant> getParticipants() {
- List<RcsParticipant> participantList = new ArrayList<>();
- for (Integer participantId : mParticipants) {
- participantList.add(new RcsParticipant(participantId));
- }
-
- return participantList;
- }
-
- private RcsParticipantQueryResult(Parcel in) {
- mContinuationToken = in.readParcelable(
- RcsQueryContinuationToken.class.getClassLoader());
- }
-
- public static final @android.annotation.NonNull Creator<RcsParticipantQueryResult> CREATOR =
- new Creator<RcsParticipantQueryResult>() {
- @Override
- public RcsParticipantQueryResult createFromParcel(Parcel in) {
- return new RcsParticipantQueryResult(in);
- }
-
- @Override
- public RcsParticipantQueryResult[] newArray(int size) {
- return new RcsParticipantQueryResult[size];
- }
- };
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeParcelable(mContinuationToken, flags);
+ return mRcsParticipantQueryResultParcelable.mParticipantIds.stream()
+ .map(RcsParticipant::new)
+ .collect(Collectors.toList());
}
}
diff --git a/telephony/java/android/telephony/ims/RcsParticipantQueryResult.aidl b/telephony/java/android/telephony/ims/RcsParticipantQueryResultParcelable.aidl
similarity index 92%
copy from telephony/java/android/telephony/ims/RcsParticipantQueryResult.aidl
copy to telephony/java/android/telephony/ims/RcsParticipantQueryResultParcelable.aidl
index db5c00c..54c72e7 100644
--- a/telephony/java/android/telephony/ims/RcsParticipantQueryResult.aidl
+++ b/telephony/java/android/telephony/ims/RcsParticipantQueryResultParcelable.aidl
@@ -17,4 +17,4 @@
package android.telephony.ims;
-parcelable RcsParticipantQueryResult;
+parcelable RcsParticipantQueryResultParcelable;
diff --git a/telephony/java/android/telephony/ims/RcsParticipantQueryResultParcelable.java b/telephony/java/android/telephony/ims/RcsParticipantQueryResultParcelable.java
new file mode 100644
index 0000000..239b0e9
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsParticipantQueryResultParcelable.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2019 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.telephony.ims;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @hide
+ */
+public final class RcsParticipantQueryResultParcelable implements Parcelable {
+ final RcsQueryContinuationToken mContinuationToken;
+ final List<Integer> mParticipantIds;
+
+ public RcsParticipantQueryResultParcelable(
+ RcsQueryContinuationToken continuationToken,
+ List<Integer> participantIds) {
+ mContinuationToken = continuationToken;
+ mParticipantIds = participantIds;
+ }
+
+ private RcsParticipantQueryResultParcelable(Parcel in) {
+ mContinuationToken = in.readParcelable(RcsQueryContinuationToken.class.getClassLoader());
+ mParticipantIds = new ArrayList<>();
+ in.readList(mParticipantIds, Integer.class.getClassLoader());
+ }
+
+ public static final Parcelable.Creator<RcsParticipantQueryResultParcelable> CREATOR =
+ new Parcelable.Creator<RcsParticipantQueryResultParcelable>() {
+ @Override
+ public RcsParticipantQueryResultParcelable createFromParcel(Parcel in) {
+ return new RcsParticipantQueryResultParcelable(in);
+ }
+
+ @Override
+ public RcsParticipantQueryResultParcelable[] newArray(int size) {
+ return new RcsParticipantQueryResultParcelable[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(mContinuationToken, flags);
+ dest.writeList(mParticipantIds);
+ }
+}
diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryResult.aidl b/telephony/java/android/telephony/ims/RcsThreadQueryResult.aidl
deleted file mode 100644
index b1d5cf4..0000000
--- a/telephony/java/android/telephony/ims/RcsThreadQueryResult.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *
- * Copyright 2019, 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.telephony.ims;
-
-parcelable RcsThreadQueryResult;
diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryResult.java b/telephony/java/android/telephony/ims/RcsThreadQueryResult.java
index c2c2d3a..c77bdb3 100644
--- a/telephony/java/android/telephony/ims/RcsThreadQueryResult.java
+++ b/telephony/java/android/telephony/ims/RcsThreadQueryResult.java
@@ -20,13 +20,10 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-import com.android.ims.RcsTypeIdPair;
-
-import java.util.ArrayList;
import java.util.List;
+import java.util.stream.Collectors;
+
/**
* The result of a {@link RcsMessageStore#getRcsThreads(RcsThreadQueryParams)}
@@ -35,23 +32,11 @@
*
* @hide
*/
-public final class RcsThreadQueryResult implements Parcelable {
- // A token for the caller to continue their query for the next batch of results
- private RcsQueryContinuationToken mContinuationToken;
- // The list of thread IDs returned with this query
- private List<RcsTypeIdPair> mRcsThreadIds;
+public final class RcsThreadQueryResult {
+ private final RcsThreadQueryResultParcelable mRcsThreadQueryResultParcelable;
- /**
- * Internal constructor for {@link com.android.internal.telephony.ims.RcsMessageStoreController}
- * to create query results
- *
- * @hide
- */
- public RcsThreadQueryResult(
- RcsQueryContinuationToken continuationToken,
- List<RcsTypeIdPair> rcsThreadIds) {
- mContinuationToken = continuationToken;
- mRcsThreadIds = rcsThreadIds;
+ RcsThreadQueryResult(RcsThreadQueryResultParcelable rcsThreadQueryResultParcelable) {
+ mRcsThreadQueryResultParcelable = rcsThreadQueryResultParcelable;
}
/**
@@ -61,7 +46,7 @@
*/
@Nullable
public RcsQueryContinuationToken getContinuationToken() {
- return mContinuationToken;
+ return mRcsThreadQueryResultParcelable.mContinuationToken;
}
/**
@@ -71,47 +56,10 @@
*/
@NonNull
public List<RcsThread> getThreads() {
- List<RcsThread> rcsThreads = new ArrayList<>();
-
- for (RcsTypeIdPair typeIdPair : mRcsThreadIds) {
- if (typeIdPair.getType() == THREAD_TYPE_1_TO_1) {
- rcsThreads.add(new Rcs1To1Thread(typeIdPair.getId()));
- } else {
- rcsThreads.add(new RcsGroupThread(typeIdPair.getId()));
- }
- }
-
- return rcsThreads;
- }
-
- private RcsThreadQueryResult(Parcel in) {
- mContinuationToken = in.readParcelable(
- RcsQueryContinuationToken.class.getClassLoader());
- mRcsThreadIds = new ArrayList<>();
- in.readList(mRcsThreadIds, Integer.class.getClassLoader());
- }
-
- public static final @android.annotation.NonNull Creator<RcsThreadQueryResult> CREATOR =
- new Creator<RcsThreadQueryResult>() {
- @Override
- public RcsThreadQueryResult createFromParcel(Parcel in) {
- return new RcsThreadQueryResult(in);
- }
-
- @Override
- public RcsThreadQueryResult[] newArray(int size) {
- return new RcsThreadQueryResult[size];
- }
- };
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeParcelable(mContinuationToken, flags);
- dest.writeList(mRcsThreadIds);
+ return mRcsThreadQueryResultParcelable.mRcsThreadIds.stream()
+ .map(typeIdPair -> typeIdPair.getType() == THREAD_TYPE_1_TO_1
+ ? new Rcs1To1Thread(typeIdPair.getId())
+ : new RcsGroupThread(typeIdPair.getId()))
+ .collect(Collectors.toList());
}
}
diff --git a/telephony/java/android/telephony/ims/RcsParticipantQueryResult.aidl b/telephony/java/android/telephony/ims/RcsThreadQueryResultParcelable.aidl
similarity index 93%
rename from telephony/java/android/telephony/ims/RcsParticipantQueryResult.aidl
rename to telephony/java/android/telephony/ims/RcsThreadQueryResultParcelable.aidl
index db5c00c..05bd61d 100644
--- a/telephony/java/android/telephony/ims/RcsParticipantQueryResult.aidl
+++ b/telephony/java/android/telephony/ims/RcsThreadQueryResultParcelable.aidl
@@ -17,4 +17,4 @@
package android.telephony.ims;
-parcelable RcsParticipantQueryResult;
+parcelable RcsThreadQueryResultParcelable;
diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryResultParcelable.java b/telephony/java/android/telephony/ims/RcsThreadQueryResultParcelable.java
new file mode 100644
index 0000000..89dd1d4
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadQueryResultParcelable.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2019 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.telephony.ims;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.ims.RcsTypeIdPair;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @hide
+ */
+public final class RcsThreadQueryResultParcelable implements Parcelable {
+ final RcsQueryContinuationToken mContinuationToken;
+ final List<RcsTypeIdPair> mRcsThreadIds;
+
+ public RcsThreadQueryResultParcelable(
+ RcsQueryContinuationToken continuationToken,
+ List<RcsTypeIdPair> rcsThreadIds) {
+ mContinuationToken = continuationToken;
+ mRcsThreadIds = rcsThreadIds;
+ }
+
+ private RcsThreadQueryResultParcelable(Parcel in) {
+ mContinuationToken = in.readParcelable(RcsQueryContinuationToken.class.getClassLoader());
+ mRcsThreadIds = new ArrayList<>();
+ in.readList(mRcsThreadIds, RcsTypeIdPair.class.getClassLoader());
+ }
+
+ public static final Parcelable.Creator<RcsThreadQueryResultParcelable> CREATOR =
+ new Parcelable.Creator<RcsThreadQueryResultParcelable>() {
+ @Override
+ public RcsThreadQueryResultParcelable createFromParcel(Parcel in) {
+ return new RcsThreadQueryResultParcelable(in);
+ }
+
+ @Override
+ public RcsThreadQueryResultParcelable[] newArray(int size) {
+ return new RcsThreadQueryResultParcelable[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(mContinuationToken, flags);
+ dest.writeList(mRcsThreadIds);
+ }
+}
diff --git a/telephony/java/android/telephony/ims/aidl/IRcs.aidl b/telephony/java/android/telephony/ims/aidl/IRcs.aidl
index 6ab01c2..50dc587 100644
--- a/telephony/java/android/telephony/ims/aidl/IRcs.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IRcs.aidl
@@ -26,10 +26,10 @@
import android.telephony.ims.RcsMessageQueryResult;
import android.telephony.ims.RcsOutgoingMessageCreationParams;
import android.telephony.ims.RcsParticipantQueryParams;
-import android.telephony.ims.RcsParticipantQueryResult;
+import android.telephony.ims.RcsParticipantQueryResultParcelable;
import android.telephony.ims.RcsQueryContinuationToken;
import android.telephony.ims.RcsThreadQueryParams;
-import android.telephony.ims.RcsThreadQueryResult;
+import android.telephony.ims.RcsThreadQueryResultParcelable;
/**
* RPC definition between RCS storage APIs and phone process.
@@ -39,14 +39,14 @@
/////////////////////////
// RcsMessageStore APIs
/////////////////////////
- RcsThreadQueryResult getRcsThreads(in RcsThreadQueryParams queryParams);
+ RcsThreadQueryResultParcelable getRcsThreads(in RcsThreadQueryParams queryParams);
- RcsThreadQueryResult getRcsThreadsWithToken(
+ RcsThreadQueryResultParcelable getRcsThreadsWithToken(
in RcsQueryContinuationToken continuationToken);
- RcsParticipantQueryResult getParticipants(in RcsParticipantQueryParams queryParams);
+ RcsParticipantQueryResultParcelable getParticipants(in RcsParticipantQueryParams queryParams);
- RcsParticipantQueryResult getParticipantsWithToken(
+ RcsParticipantQueryResultParcelable getParticipantsWithToken(
in RcsQueryContinuationToken continuationToken);
RcsMessageQueryResult getMessages(in RcsMessageQueryParams queryParams);
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index c08da44..d7ac4525 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -17,6 +17,7 @@
package com.android.internal.telephony;
import android.telephony.SubscriptionInfo;
+import android.os.ParcelUuid;
import com.android.internal.telephony.ISetOpportunisticDataCallback;
interface ISub {
@@ -202,16 +203,7 @@
* null if fails.
*
*/
- String setSubscriptionGroup(in int[] subIdList, String callingPackage);
-
- /**
- * Set whether a subscription is metered
- *
- * @param isMetered whether it’s a metered subscription.
- * @param subId the unique SubscriptionInfo index in database
- * @return the number of records updated
- */
- int setMetered(boolean isMetered, int subId, String callingPackage);
+ ParcelUuid createSubscriptionGroup(in int[] subIdList, String callingPackage);
/**
* Set which subscription is preferred for cellular data. It's
@@ -243,9 +235,13 @@
*/
List<SubscriptionInfo> getOpportunisticSubscriptions(String callingPackage);
- boolean removeSubscriptionsFromGroup(in int[] subIdList, String callingPackage);
+ void removeSubscriptionsFromGroup(in int[] subIdList, in ParcelUuid groupUuid,
+ String callingPackage);
- List<SubscriptionInfo> getSubscriptionsInGroup(int subId, String callingPackage);
+ void addSubscriptionsIntoGroup(in int[] subIdList, in ParcelUuid groupUuid,
+ String callingPackage);
+
+ List<SubscriptionInfo> getSubscriptionsInGroup(in ParcelUuid groupUuid, String callingPackage);
int getSlotIndex(int subId);
@@ -276,8 +272,6 @@
void setDefaultSmsSubId(int subId);
- void clearDefaultsForInactiveSubIds();
-
@UnsupportedAppUsage
int[] getActiveSubIdList(boolean visibleOnly);
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index c8dab27..d173cc9 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1265,6 +1265,11 @@
*/
int getSubIdForPhoneAccount(in PhoneAccount phoneAccount);
+ /**
+ * Returns the PhoneAccountHandle associated with a subscription ID.
+ */
+ PhoneAccountHandle getPhoneAccountHandleForSubscriptionId(int subscriptionId);
+
void factoryReset(int subId);
/**
@@ -1950,5 +1955,7 @@
/**
* Get the IRadio HAL Version encoded as 100 * MAJOR_VERSION + MINOR_VERSION or -1 if unknown
*/
- int getRadioHalVersion();
+ int getRadioHalVersion();
+
+ boolean isModemEnabledForSlot(int slotIndex, String callingPackage);
}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 2a648bd..134f585 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -56,6 +56,7 @@
* by the system.
* @deprecated use {@link Intent#ACTION_SERVICE_STATE}
*/
+ @Deprecated
public static final String ACTION_SERVICE_STATE_CHANGED = Intent.ACTION_SERVICE_STATE;
/**
diff --git a/tests/benchmarks/Android.bp b/tests/benchmarks/Android.bp
new file mode 100644
index 0000000..f16ddb9
--- /dev/null
+++ b/tests/benchmarks/Android.bp
@@ -0,0 +1,29 @@
+// Copyright (C) 2015 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// build framework base core benchmarks
+// ============================================================
+
+java_library {
+ name: "networkStatsFactory-benchmarks",
+ installable: true,
+
+ srcs: ["src/**/*.java"],
+
+ libs: [
+ "caliper-api-target",
+ "services.core",
+ ],
+
+}
diff --git a/core/tests/benchmarks/src/com/android/internal/net/NetworkStatsFactoryBenchmark.java b/tests/benchmarks/src/com/android/server/net/NetworkStatsFactoryBenchmark.java
similarity index 95%
rename from core/tests/benchmarks/src/com/android/internal/net/NetworkStatsFactoryBenchmark.java
rename to tests/benchmarks/src/com/android/server/net/NetworkStatsFactoryBenchmark.java
index c213464..ef014f0 100644
--- a/core/tests/benchmarks/src/com/android/internal/net/NetworkStatsFactoryBenchmark.java
+++ b/tests/benchmarks/src/com/android/server/net/NetworkStatsFactoryBenchmark.java
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-package com.android.internal.net;
+package com.android.server.net;
import android.net.NetworkStats;
import android.os.SystemClock;
+import com.android.server.net.NetworkStatsFactory;
import com.google.caliper.AfterExperiment;
import com.google.caliper.BeforeExperiment;
import java.io.File;
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index c62d85e..9098f90 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -1,12 +1,10 @@
//########################################################################
// Build FrameworksNetTests package
//########################################################################
-
-android_test {
- name: "FrameworksNetTests",
- // Include all test java files.
- srcs: ["java/**/*.java"],
+java_defaults {
+ name: "FrameworksNetTests-jni-defaults",
static_libs: [
+ "FrameworksNetCommonTests",
"frameworks-base-testutils",
"framework-protos",
"androidx.test.rules",
@@ -20,6 +18,52 @@
"android.test.base",
"android.test.mock",
],
+ jni_libs: [
+ "ld-android",
+ "libartbase",
+ "libbacktrace",
+ "libbase",
+ "libbinder",
+ "libbinderthreadstate",
+ "libbpf",
+ "libbpf_android",
+ "libc++",
+ "libcgrouprc",
+ "libcrypto",
+ "libcutils",
+ "libdexfile",
+ "libdl_android",
+ "libhidl-gen-utils",
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libjsoncpp",
+ "liblog",
+ "liblzma",
+ "libnativehelper",
+ "libnetdbpf",
+ "libnetdutils",
+ "libpackagelistparser",
+ "libpcre2",
+ "libprocessgroup",
+ "libselinux",
+ "libui",
+ "libutils",
+ "libvndksupport",
+ "libtinyxml2",
+ "libunwindstack",
+ "libutilscallstack",
+ "libziparchive",
+ "libz",
+ "netd_aidl_interface-cpp",
+ "libnetworkstatsfactorytestjni",
+ ],
+}
+
+android_test {
+ name: "FrameworksNetTests",
+ defaults: ["FrameworksNetTests-jni-defaults"],
+ srcs: ["java/**/*.java"],
platform_apis: true,
test_suites: ["device-tests"],
certificate: "platform",
diff --git a/packages/NetworkStackPermissionStub/Android.bp b/tests/net/common/Android.bp
similarity index 60%
copy from packages/NetworkStackPermissionStub/Android.bp
copy to tests/net/common/Android.bp
index 8cee92e..0a1ac75 100644
--- a/packages/NetworkStackPermissionStub/Android.bp
+++ b/tests/net/common/Android.bp
@@ -14,15 +14,16 @@
// limitations under the License.
//
-// Stub APK to define permissions for NetworkStack
-android_app {
- name: "NetworkStackPermissionStub",
- // TODO: mark app as hasCode=false in manifest once soong stops complaining about apps without
- // a classes.dex.
- srcs: ["src/**/*.java"],
- platform_apis: true,
- min_sdk_version: "28",
- certificate: "networkstack",
- privileged: true,
- manifest: "AndroidManifest.xml",
-}
+// Tests in this folder are included both in unit tests and CTS.
+// They must be fast and stable, and exercise public or test APIs.
+java_library {
+ name: "FrameworksNetCommonTests",
+ srcs: ["java/**/*.java"],
+ static_libs: [
+ "androidx.test.rules",
+ "junit",
+ ],
+ libs: [
+ "android.test.base.stubs",
+ ],
+}
\ No newline at end of file
diff --git a/tests/net/java/android/net/IpPrefixTest.java b/tests/net/common/java/android/net/IpPrefixTest.java
similarity index 84%
rename from tests/net/java/android/net/IpPrefixTest.java
rename to tests/net/common/java/android/net/IpPrefixTest.java
index 3cc0e36..719960d 100644
--- a/tests/net/java/android/net/IpPrefixTest.java
+++ b/tests/net/common/java/android/net/IpPrefixTest.java
@@ -39,7 +39,7 @@
@SmallTest
public class IpPrefixTest {
- private static InetAddress Address(String addr) {
+ private static InetAddress address(String addr) {
return InetAddress.parseNumericAddress(addr);
}
@@ -58,59 +58,59 @@
try {
p = new IpPrefix((byte[]) null, 9);
fail("Expected NullPointerException: null byte array");
- } catch(RuntimeException expected) {}
+ } catch (RuntimeException expected) { }
try {
p = new IpPrefix((InetAddress) null, 10);
fail("Expected NullPointerException: null InetAddress");
- } catch(RuntimeException expected) {}
+ } catch (RuntimeException expected) { }
try {
p = new IpPrefix((String) null);
fail("Expected NullPointerException: null String");
- } catch(RuntimeException expected) {}
+ } catch (RuntimeException expected) { }
try {
byte[] b2 = {1, 2, 3, 4, 5};
p = new IpPrefix(b2, 29);
fail("Expected IllegalArgumentException: invalid array length");
- } catch(IllegalArgumentException expected) {}
+ } catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("1.2.3.4");
fail("Expected IllegalArgumentException: no prefix length");
- } catch(IllegalArgumentException expected) {}
+ } catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("1.2.3.4/");
fail("Expected IllegalArgumentException: empty prefix length");
- } catch(IllegalArgumentException expected) {}
+ } catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("foo/32");
fail("Expected IllegalArgumentException: invalid address");
- } catch(IllegalArgumentException expected) {}
+ } catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("1/32");
fail("Expected IllegalArgumentException: deprecated IPv4 format");
- } catch(IllegalArgumentException expected) {}
+ } catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("1.2.3.256/32");
fail("Expected IllegalArgumentException: invalid IPv4 address");
- } catch(IllegalArgumentException expected) {}
+ } catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("foo/32");
fail("Expected IllegalArgumentException: non-address");
- } catch(IllegalArgumentException expected) {}
+ } catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("f00:::/32");
fail("Expected IllegalArgumentException: invalid IPv6 address");
- } catch(IllegalArgumentException expected) {}
+ } catch (IllegalArgumentException expected) { }
}
@Test
@@ -132,17 +132,17 @@
try {
p = new IpPrefix(IPV4_BYTES, 33);
fail("Expected IllegalArgumentException: invalid prefix length");
- } catch(RuntimeException expected) {}
+ } catch (RuntimeException expected) { }
try {
p = new IpPrefix(IPV4_BYTES, 128);
fail("Expected IllegalArgumentException: invalid prefix length");
- } catch(RuntimeException expected) {}
+ } catch (RuntimeException expected) { }
try {
p = new IpPrefix(IPV4_BYTES, -1);
fail("Expected IllegalArgumentException: negative prefix length");
- } catch(RuntimeException expected) {}
+ } catch (RuntimeException expected) { }
p = new IpPrefix(IPV6_BYTES, 128);
assertEquals("2001:db8:dead:beef:f00::a0/128", p.toString());
@@ -162,12 +162,12 @@
try {
p = new IpPrefix(IPV6_BYTES, -1);
fail("Expected IllegalArgumentException: negative prefix length");
- } catch(RuntimeException expected) {}
+ } catch (RuntimeException expected) { }
try {
p = new IpPrefix(IPV6_BYTES, 129);
fail("Expected IllegalArgumentException: negative prefix length");
- } catch(RuntimeException expected) {}
+ } catch (RuntimeException expected) { }
}
@@ -226,29 +226,28 @@
@Test
public void testContainsInetAddress() {
IpPrefix p = new IpPrefix("2001:db8:f00::ace:d00d/127");
- assertTrue(p.contains(Address("2001:db8:f00::ace:d00c")));
- assertTrue(p.contains(Address("2001:db8:f00::ace:d00d")));
- assertFalse(p.contains(Address("2001:db8:f00::ace:d00e")));
- assertFalse(p.contains(Address("2001:db8:f00::bad:d00d")));
- assertFalse(p.contains(Address("2001:4868:4860::8888")));
- assertFalse(p.contains((InetAddress)null));
- assertFalse(p.contains(Address("8.8.8.8")));
+ assertTrue(p.contains(address("2001:db8:f00::ace:d00c")));
+ assertTrue(p.contains(address("2001:db8:f00::ace:d00d")));
+ assertFalse(p.contains(address("2001:db8:f00::ace:d00e")));
+ assertFalse(p.contains(address("2001:db8:f00::bad:d00d")));
+ assertFalse(p.contains(address("2001:4868:4860::8888")));
+ assertFalse(p.contains(address("8.8.8.8")));
p = new IpPrefix("192.0.2.0/23");
- assertTrue(p.contains(Address("192.0.2.43")));
- assertTrue(p.contains(Address("192.0.3.21")));
- assertFalse(p.contains(Address("192.0.0.21")));
- assertFalse(p.contains(Address("8.8.8.8")));
- assertFalse(p.contains(Address("2001:4868:4860::8888")));
+ assertTrue(p.contains(address("192.0.2.43")));
+ assertTrue(p.contains(address("192.0.3.21")));
+ assertFalse(p.contains(address("192.0.0.21")));
+ assertFalse(p.contains(address("8.8.8.8")));
+ assertFalse(p.contains(address("2001:4868:4860::8888")));
IpPrefix ipv6Default = new IpPrefix("::/0");
- assertTrue(ipv6Default.contains(Address("2001:db8::f00")));
- assertFalse(ipv6Default.contains(Address("192.0.2.1")));
+ assertTrue(ipv6Default.contains(address("2001:db8::f00")));
+ assertFalse(ipv6Default.contains(address("192.0.2.1")));
IpPrefix ipv4Default = new IpPrefix("0.0.0.0/0");
- assertTrue(ipv4Default.contains(Address("255.255.255.255")));
- assertTrue(ipv4Default.contains(Address("192.0.2.1")));
- assertFalse(ipv4Default.contains(Address("2001:db8::f00")));
+ assertTrue(ipv4Default.contains(address("255.255.255.255")));
+ assertTrue(ipv4Default.contains(address("192.0.2.1")));
+ assertFalse(ipv4Default.contains(address("2001:db8::f00")));
}
@Test
@@ -316,10 +315,10 @@
p = new IpPrefix(b, random.nextInt(129));
}
if (p.equals(oldP)) {
- assertEquals(p.hashCode(), oldP.hashCode());
+ assertEquals(p.hashCode(), oldP.hashCode());
}
if (p.hashCode() != oldP.hashCode()) {
- assertNotEquals(p, oldP);
+ assertNotEquals(p, oldP);
}
}
}
@@ -333,9 +332,9 @@
new IpPrefix("0.0.0.0/0"),
};
for (int i = 0; i < prefixes.length; i++) {
- for (int j = i + 1; j < prefixes.length; j++) {
- assertNotEquals(prefixes[i].hashCode(), prefixes[j].hashCode());
- }
+ for (int j = i + 1; j < prefixes.length; j++) {
+ assertNotEquals(prefixes[i].hashCode(), prefixes[j].hashCode());
+ }
}
}
@@ -372,8 +371,8 @@
}
public void assertParcelingIsLossless(IpPrefix p) {
- IpPrefix p2 = passThroughParcel(p);
- assertEquals(p, p2);
+ IpPrefix p2 = passThroughParcel(p);
+ assertEquals(p, p2);
}
@Test
diff --git a/tests/net/java/android/net/NetworkStackTest.java b/tests/net/java/android/net/NetworkStackTest.java
new file mode 100644
index 0000000..f7c6c99
--- /dev/null
+++ b/tests/net/java/android/net/NetworkStackTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2019 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;
+
+import static android.Manifest.permission.NETWORK_STACK;
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
+import static android.net.NetworkStack.checkNetworkStackPermission;
+import static android.net.NetworkStack.checkNetworkStackPermissionOr;
+
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class NetworkStackTest {
+ private static final String [] OTHER_PERMISSION = {"otherpermission1", "otherpermission2"};
+
+ @Mock Context mCtx;
+
+ @Before public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ public void testCheckNetworkStackPermission() throws Exception {
+ when(mCtx.checkCallingOrSelfPermission(eq(NETWORK_STACK))).thenReturn(PERMISSION_GRANTED);
+ when(mCtx.checkCallingOrSelfPermission(eq(PERMISSION_MAINLINE_NETWORK_STACK)))
+ .thenReturn(PERMISSION_DENIED);
+ checkNetworkStackPermission(mCtx);
+ checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION);
+
+ when(mCtx.checkCallingOrSelfPermission(eq(NETWORK_STACK))).thenReturn(PERMISSION_DENIED);
+ when(mCtx.checkCallingOrSelfPermission(eq(PERMISSION_MAINLINE_NETWORK_STACK)))
+ .thenReturn(PERMISSION_GRANTED);
+ checkNetworkStackPermission(mCtx);
+ checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION);
+
+ when(mCtx.checkCallingOrSelfPermission(any())).thenReturn(PERMISSION_DENIED);
+
+ try {
+ checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION);
+ } catch (SecurityException e) {
+ // Expect to get a SecurityException
+ return;
+ }
+
+ fail("Expect fail but permission granted.");
+ }
+}
diff --git a/tests/net/java/android/net/RouteInfoTest.java b/tests/net/java/android/net/RouteInfoTest.java
index 831fefd..2edbd40 100644
--- a/tests/net/java/android/net/RouteInfoTest.java
+++ b/tests/net/java/android/net/RouteInfoTest.java
@@ -16,15 +16,16 @@
package android.net;
-import java.lang.reflect.Method;
-import java.net.InetAddress;
+import static android.net.RouteInfo.RTN_UNREACHABLE;
-import android.net.IpPrefix;
-import android.net.RouteInfo;
import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
import junit.framework.TestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
public class RouteInfoTest extends TestCase {
@@ -152,67 +153,85 @@
}
public void testHostAndDefaultRoutes() {
- RouteInfo r;
+ RouteInfo r;
- r = new RouteInfo(Prefix("0.0.0.0/0"), Address("0.0.0.0"), "wlan0");
- assertFalse(r.isHostRoute());
- assertTrue(r.isDefaultRoute());
- assertTrue(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
+ r = new RouteInfo(Prefix("0.0.0.0/0"), Address("0.0.0.0"), "wlan0");
+ assertFalse(r.isHostRoute());
+ assertTrue(r.isDefaultRoute());
+ assertTrue(r.isIPv4Default());
+ assertFalse(r.isIPv6Default());
- r = new RouteInfo(Prefix("::/0"), Address("::"), "wlan0");
- assertFalse(r.isHostRoute());
- assertTrue(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertTrue(r.isIPv6Default());
+ r = new RouteInfo(Prefix("::/0"), Address("::"), "wlan0");
+ assertFalse(r.isHostRoute());
+ assertTrue(r.isDefaultRoute());
+ assertFalse(r.isIPv4Default());
+ assertTrue(r.isIPv6Default());
- r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0");
- assertFalse(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
+ r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0");
+ assertFalse(r.isHostRoute());
+ assertFalse(r.isDefaultRoute());
+ assertFalse(r.isIPv4Default());
+ assertFalse(r.isIPv6Default());
- r = new RouteInfo(Prefix("2001:db8::/48"), null, "wlan0");
- assertFalse(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
+ r = new RouteInfo(Prefix("2001:db8::/48"), null, "wlan0");
+ assertFalse(r.isHostRoute());
+ assertFalse(r.isDefaultRoute());
+ assertFalse(r.isIPv4Default());
+ assertFalse(r.isIPv6Default());
- r = new RouteInfo(Prefix("192.0.2.0/32"), Address("0.0.0.0"), "wlan0");
- assertTrue(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
+ r = new RouteInfo(Prefix("192.0.2.0/32"), Address("0.0.0.0"), "wlan0");
+ assertTrue(r.isHostRoute());
+ assertFalse(r.isDefaultRoute());
+ assertFalse(r.isIPv4Default());
+ assertFalse(r.isIPv6Default());
- r = new RouteInfo(Prefix("2001:db8::/128"), Address("::"), "wlan0");
- assertTrue(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
+ r = new RouteInfo(Prefix("2001:db8::/128"), Address("::"), "wlan0");
+ assertTrue(r.isHostRoute());
+ assertFalse(r.isDefaultRoute());
+ assertFalse(r.isIPv4Default());
+ assertFalse(r.isIPv6Default());
- r = new RouteInfo(Prefix("192.0.2.0/32"), null, "wlan0");
- assertTrue(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
+ r = new RouteInfo(Prefix("192.0.2.0/32"), null, "wlan0");
+ assertTrue(r.isHostRoute());
+ assertFalse(r.isDefaultRoute());
+ assertFalse(r.isIPv4Default());
+ assertFalse(r.isIPv6Default());
- r = new RouteInfo(Prefix("2001:db8::/128"), null, "wlan0");
- assertTrue(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
+ r = new RouteInfo(Prefix("2001:db8::/128"), null, "wlan0");
+ assertTrue(r.isHostRoute());
+ assertFalse(r.isDefaultRoute());
+ assertFalse(r.isIPv4Default());
+ assertFalse(r.isIPv6Default());
- r = new RouteInfo(Prefix("::/128"), Address("fe80::"), "wlan0");
- assertTrue(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
+ r = new RouteInfo(Prefix("::/128"), Address("fe80::"), "wlan0");
+ assertTrue(r.isHostRoute());
+ assertFalse(r.isDefaultRoute());
+ assertFalse(r.isIPv4Default());
+ assertFalse(r.isIPv6Default());
- r = new RouteInfo(Prefix("0.0.0.0/32"), Address("192.0.2.1"), "wlan0");
- assertTrue(r.isHostRoute());
- assertFalse(r.isDefaultRoute());
- assertFalse(r.isIPv4Default());
- assertFalse(r.isIPv6Default());
+ r = new RouteInfo(Prefix("0.0.0.0/32"), Address("192.0.2.1"), "wlan0");
+ assertTrue(r.isHostRoute());
+ assertFalse(r.isDefaultRoute());
+ assertFalse(r.isIPv4Default());
+ assertFalse(r.isIPv6Default());
+
+ r = new RouteInfo(Prefix("0.0.0.0/32"), Address("192.0.2.1"), "wlan0");
+ assertTrue(r.isHostRoute());
+ assertFalse(r.isDefaultRoute());
+ assertFalse(r.isIPv4Default());
+ assertFalse(r.isIPv6Default());
+
+ r = new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE);
+ assertFalse(r.isHostRoute());
+ assertFalse(r.isDefaultRoute());
+ assertFalse(r.isIPv4Default());
+ assertFalse(r.isIPv6Default());
+
+ r = new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE);
+ assertFalse(r.isHostRoute());
+ assertFalse(r.isDefaultRoute());
+ assertFalse(r.isIPv4Default());
+ assertFalse(r.isIPv6Default());
}
public void testTruncation() {
diff --git a/tests/net/java/android/net/ipmemorystore/ParcelableTests.java b/tests/net/java/android/net/ipmemorystore/ParcelableTests.java
index 76cccc9..1a3ea609 100644
--- a/tests/net/java/android/net/ipmemorystore/ParcelableTests.java
+++ b/tests/net/java/android/net/ipmemorystore/ParcelableTests.java
@@ -44,6 +44,8 @@
assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
builder.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
+ // lease will expire in two hours
+ builder.setAssignedV4AddressExpiry(System.currentTimeMillis() + 7_200_000);
// groupHint stays null this time around
builder.setDnsAddresses(Collections.emptyList());
builder.setMtu(18);
@@ -51,6 +53,7 @@
assertEquals(in, new NetworkAttributes(parcelingRoundTrip(in.toParcelable())));
builder.setAssignedV4Address((Inet4Address) Inet4Address.getByName("6.7.8.9"));
+ builder.setAssignedV4AddressExpiry(System.currentTimeMillis() + 3_600_000);
builder.setGroupHint("groupHint");
builder.setDnsAddresses(Arrays.asList(
InetAddress.getByName("ACA1:652B:0911:DE8F:1200:115E:913B:AA2A"),
@@ -66,7 +69,7 @@
// Verify that this test does not miss any new field added later.
// If any field is added to NetworkAttributes it must be tested here for parceling
// roundtrip.
- assertEquals(4, Arrays.stream(NetworkAttributes.class.getDeclaredFields())
+ assertEquals(5, Arrays.stream(NetworkAttributes.class.getDeclaredFields())
.filter(f -> !Modifier.isStatic(f.getModifiers())).count());
}
diff --git a/tests/net/java/android/net/netlink/InetDiagSocketTest.java b/tests/net/java/android/net/netlink/InetDiagSocketTest.java
index b6038ab..2adbb06 100644
--- a/tests/net/java/android/net/netlink/InetDiagSocketTest.java
+++ b/tests/net/java/android/net/netlink/InetDiagSocketTest.java
@@ -45,6 +45,7 @@
import libcore.util.HexEncoding;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -189,6 +190,7 @@
udp.close();
}
+ @Ignore
@Test
public void testGetConnectionOwnerUid() throws Exception {
checkGetConnectionOwnerUid("::", null);
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index afefd5e..ed93da1 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -60,11 +60,13 @@
import static android.net.NetworkPolicyManager.RULE_NONE;
import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
+import static android.net.RouteInfo.RTN_UNREACHABLE;
import static com.android.internal.util.TestUtils.waitForIdleHandler;
import static com.android.internal.util.TestUtils.waitForIdleLooper;
import static com.android.internal.util.TestUtils.waitForIdleSerialExecutor;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -72,12 +74,14 @@
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
@@ -97,6 +101,9 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
@@ -151,6 +158,7 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
import android.system.Os;
import android.test.mock.MockContentResolver;
@@ -186,6 +194,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
@@ -194,6 +203,7 @@
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.Inet4Address;
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
@@ -261,6 +271,7 @@
@Mock IDnsResolver mMockDnsResolver;
@Mock INetd mMockNetd;
@Mock NetworkStackClient mNetworkStack;
+ @Mock UserManager mUserManager;
private ArgumentCaptor<String[]> mStringArrayCaptor = ArgumentCaptor.forClass(String[].class);
@@ -331,6 +342,7 @@
if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm;
if (Context.NOTIFICATION_SERVICE.equals(name)) return mock(NotificationManager.class);
if (Context.NETWORK_STACK_SERVICE.equals(name)) return mNetworkStack;
+ if (Context.USER_SERVICE.equals(name)) return mUserManager;
return super.getSystemService(name);
}
@@ -499,7 +511,7 @@
};
try {
- doAnswer(validateAnswer).when(mNetworkMonitor).notifyNetworkConnected();
+ doAnswer(validateAnswer).when(mNetworkMonitor).notifyNetworkConnected(any(), any());
doAnswer(validateAnswer).when(mNetworkMonitor).forceReevaluation(anyInt());
} catch (RemoteException e) {
fail(e.getMessage());
@@ -1057,7 +1069,7 @@
public WrappedConnectivityService(Context context, INetworkManagementService netManager,
INetworkStatsService statsService, INetworkPolicyManager policyManager,
IpConnectivityLog log, INetd netd, IDnsResolver dnsResolver) {
- super(context, netManager, statsService, policyManager, dnsResolver, log);
+ super(context, netManager, statsService, policyManager, dnsResolver, log, netd);
mNetd = netd;
mLingerDelayMs = TEST_LINGER_DELAY_MS;
}
@@ -1196,6 +1208,11 @@
fail("ConditionVariable was blocked for more than " + TIMEOUT_MS + "ms");
}
+ private static final int VPN_USER = 0;
+ private static final int APP1_UID = UserHandle.getUid(VPN_USER, 10100);
+ private static final int APP2_UID = UserHandle.getUid(VPN_USER, 10101);
+ private static final int VPN_UID = UserHandle.getUid(VPN_USER, 10043);
+
@Before
public void setUp() throws Exception {
mContext = InstrumentationRegistry.getContext();
@@ -1203,6 +1220,11 @@
MockitoAnnotations.initMocks(this);
when(mMetricsService.defaultNetworkMetrics()).thenReturn(mDefaultNetworkMetrics);
+ when(mUserManager.getUsers(eq(true))).thenReturn(
+ Arrays.asList(new UserInfo[] {
+ new UserInfo(VPN_USER, "", 0),
+ }));
+
// InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not.
// http://b/25897652 .
if (Looper.myLooper() == null) {
@@ -3047,6 +3069,47 @@
}
@Test
+ public void testInvalidSignalStrength() {
+ NetworkRequest r = new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addTransportType(TRANSPORT_WIFI)
+ .setSignalStrength(-75)
+ .build();
+ // Registering a NetworkCallback with signal strength but w/o NETWORK_SIGNAL_STRENGTH_WAKEUP
+ // permission should get SecurityException.
+ try {
+ mCm.registerNetworkCallback(r, new NetworkCallback());
+ fail("Expected SecurityException filing a callback with signal strength");
+ } catch (SecurityException expected) {
+ // expected
+ }
+
+ try {
+ mCm.registerNetworkCallback(r, PendingIntent.getService(
+ mServiceContext, 0, new Intent(), 0));
+ fail("Expected SecurityException filing a callback with signal strength");
+ } catch (SecurityException expected) {
+ // expected
+ }
+
+ // Requesting a Network with signal strength should get IllegalArgumentException.
+ try {
+ mCm.requestNetwork(r, new NetworkCallback());
+ fail("Expected IllegalArgumentException filing a request with signal strength");
+ } catch (IllegalArgumentException expected) {
+ // expected
+ }
+
+ try {
+ mCm.requestNetwork(r, PendingIntent.getService(
+ mServiceContext, 0, new Intent(), 0));
+ fail("Expected IllegalArgumentException filing a request with signal strength");
+ } catch (IllegalArgumentException expected) {
+ // expected
+ }
+ }
+
+ @Test
public void testRegisterDefaultNetworkCallback() throws Exception {
final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
@@ -6088,4 +6151,171 @@
assertEquals(testProxyInfo, mService.getProxyForNetwork(mWiFiNetworkAgent.getNetwork()));
assertEquals(testProxyInfo, mService.getProxyForNetwork(null));
}
+
+ @Test
+ @Ignore
+ public void testFullyRoutedVpnResultsInInterfaceFilteringRules() throws Exception {
+ LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName("tun0");
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
+ // The uid range needs to cover the test app so the network is visible to it.
+ final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
+ final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, VPN_UID, vpnRange);
+
+ // Connected VPN should have interface rules set up. There are two expected invocations,
+ // one during VPN uid update, one during VPN LinkProperties update
+ ArgumentCaptor<int[]> uidCaptor = ArgumentCaptor.forClass(int[].class);
+ verify(mMockNetd, times(2)).firewallAddUidInterfaceRules(eq("tun0"), uidCaptor.capture());
+ assertContainsExactly(uidCaptor.getAllValues().get(0), APP1_UID, APP2_UID);
+ assertContainsExactly(uidCaptor.getAllValues().get(1), APP1_UID, APP2_UID);
+ assertTrue(mService.mPermissionMonitor.getVpnUidRanges("tun0").equals(vpnRange));
+
+ vpnNetworkAgent.disconnect();
+ waitForIdle();
+
+ // Disconnected VPN should have interface rules removed
+ verify(mMockNetd).firewallRemoveUidInterfaceRules(uidCaptor.capture());
+ assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID);
+ assertNull(mService.mPermissionMonitor.getVpnUidRanges("tun0"));
+ }
+
+ @Test
+ @Ignore
+ public void testLegacyVpnDoesNotResultInInterfaceFilteringRule() throws Exception {
+ LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName("tun0");
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
+ // The uid range needs to cover the test app so the network is visible to it.
+ final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
+ final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, Process.SYSTEM_UID, vpnRange);
+
+ // Legacy VPN should not have interface rules set up
+ verify(mMockNetd, never()).firewallAddUidInterfaceRules(any(), any());
+ }
+
+ @Test
+ @Ignore
+ public void testLocalIpv4OnlyVpnDoesNotResultInInterfaceFilteringRule()
+ throws Exception {
+ LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName("tun0");
+ lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun0"));
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
+ // The uid range needs to cover the test app so the network is visible to it.
+ final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
+ final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, Process.SYSTEM_UID, vpnRange);
+
+ // IPv6 unreachable route should not be misinterpreted as a default route
+ verify(mMockNetd, never()).firewallAddUidInterfaceRules(any(), any());
+ }
+
+ @Test
+ @Ignore
+ public void testVpnHandoverChangesInterfaceFilteringRule() throws Exception {
+ LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName("tun0");
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
+ // The uid range needs to cover the test app so the network is visible to it.
+ final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
+ final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, VPN_UID, vpnRange);
+
+ // Connected VPN should have interface rules set up. There are two expected invocations,
+ // one during VPN uid update, one during VPN LinkProperties update
+ ArgumentCaptor<int[]> uidCaptor = ArgumentCaptor.forClass(int[].class);
+ verify(mMockNetd, times(2)).firewallAddUidInterfaceRules(eq("tun0"), uidCaptor.capture());
+ assertContainsExactly(uidCaptor.getAllValues().get(0), APP1_UID, APP2_UID);
+ assertContainsExactly(uidCaptor.getAllValues().get(1), APP1_UID, APP2_UID);
+
+ reset(mMockNetd);
+ InOrder inOrder = inOrder(mMockNetd);
+ lp.setInterfaceName("tun1");
+ vpnNetworkAgent.sendLinkProperties(lp);
+ waitForIdle();
+ // VPN handover (switch to a new interface) should result in rules being updated (old rules
+ // removed first, then new rules added)
+ inOrder.verify(mMockNetd).firewallRemoveUidInterfaceRules(uidCaptor.capture());
+ assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID);
+ inOrder.verify(mMockNetd).firewallAddUidInterfaceRules(eq("tun1"), uidCaptor.capture());
+ assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID);
+
+ reset(mMockNetd);
+ lp = new LinkProperties();
+ lp.setInterfaceName("tun1");
+ lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun1"));
+ vpnNetworkAgent.sendLinkProperties(lp);
+ waitForIdle();
+ // VPN not routing everything should no longer have interface filtering rules
+ verify(mMockNetd).firewallRemoveUidInterfaceRules(uidCaptor.capture());
+ assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID);
+
+ reset(mMockNetd);
+ lp = new LinkProperties();
+ lp.setInterfaceName("tun1");
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
+ vpnNetworkAgent.sendLinkProperties(lp);
+ waitForIdle();
+ // Back to routing all IPv6 traffic should have filtering rules
+ verify(mMockNetd).firewallAddUidInterfaceRules(eq("tun1"), uidCaptor.capture());
+ assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID);
+ }
+
+ @Test
+ @Ignore
+ public void testUidUpdateChangesInterfaceFilteringRule() throws Exception {
+ LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName("tun0");
+ lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
+ // The uid range needs to cover the test app so the network is visible to it.
+ final UidRange vpnRange = UidRange.createForUser(VPN_USER);
+ final MockNetworkAgent vpnNetworkAgent = establishVpn(lp, VPN_UID,
+ Collections.singleton(vpnRange));
+
+ reset(mMockNetd);
+ InOrder inOrder = inOrder(mMockNetd);
+
+ // Update to new range which is old range minus APP1, i.e. only APP2
+ final Set<UidRange> newRanges = new HashSet<>(Arrays.asList(
+ new UidRange(vpnRange.start, APP1_UID - 1),
+ new UidRange(APP1_UID + 1, vpnRange.stop)));
+ vpnNetworkAgent.setUids(newRanges);
+ waitForIdle();
+
+ ArgumentCaptor<int[]> uidCaptor = ArgumentCaptor.forClass(int[].class);
+ // Verify old rules are removed before new rules are added
+ inOrder.verify(mMockNetd).firewallRemoveUidInterfaceRules(uidCaptor.capture());
+ assertContainsExactly(uidCaptor.getValue(), APP1_UID, APP2_UID);
+ inOrder.verify(mMockNetd).firewallAddUidInterfaceRules(eq("tun0"), uidCaptor.capture());
+ assertContainsExactly(uidCaptor.getValue(), APP2_UID);
+ }
+
+
+ private MockNetworkAgent establishVpn(LinkProperties lp, int establishingUid,
+ Set<UidRange> vpnRange) {
+ final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN, lp);
+ vpnNetworkAgent.getNetworkCapabilities().setEstablishingVpnAppUid(establishingUid);
+ mMockVpn.setNetworkAgent(vpnNetworkAgent);
+ mMockVpn.connect();
+ mMockVpn.setUids(vpnRange);
+ vpnNetworkAgent.connect(true);
+ waitForIdle();
+ return vpnNetworkAgent;
+ }
+
+ private void assertContainsExactly(int[] actual, int... expected) {
+ int[] sortedActual = Arrays.copyOf(actual, actual.length);
+ int[] sortedExpected = Arrays.copyOf(expected, expected.length);
+ Arrays.sort(sortedActual);
+ Arrays.sort(sortedExpected);
+ assertArrayEquals(sortedExpected, sortedActual);
+ }
+
+ private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid) {
+ final PackageInfo packageInfo = new PackageInfo();
+ packageInfo.requestedPermissions = new String[0];
+ packageInfo.applicationInfo = new ApplicationInfo();
+ packageInfo.applicationInfo.privateFlags = 0;
+ packageInfo.applicationInfo.uid = UserHandle.getUid(UserHandle.USER_SYSTEM,
+ UserHandle.getAppId(uid));
+ return packageInfo;
+ }
}
diff --git a/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java b/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
index 68ff777..22a2c94 100644
--- a/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.eq;
@@ -134,11 +135,11 @@
IBinder binderMock = mock(IBinder.class);
doThrow(new RemoteException()).when(binderMock).linkToDeath(anyObject(), anyInt());
- RefcountedResource<IResource> refcountedResource = getTestRefcountedResource(binderMock);
-
- // Verify that cleanup is performed (Spy limitations prevent verification of method calls
- // for binder death scenario; check refcount to determine if cleanup was performed.)
- assertEquals(-1, refcountedResource.mRefCount);
+ try {
+ getTestRefcountedResource(binderMock);
+ fail("Expected exception to propogate when binder fails to link to death");
+ } catch (RuntimeException expected) {
+ }
}
@Test
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index b5c3e92..4a35015 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -156,10 +156,21 @@
@Test
public void testOpenAndCloseUdpEncapsulationSocket() throws Exception {
- int localport = findUnusedPort();
+ int localport = -1;
+ IpSecUdpEncapResponse udpEncapResp = null;
- IpSecUdpEncapResponse udpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+ for (int i = 0; i < IpSecService.MAX_PORT_BIND_ATTEMPTS; i++) {
+ localport = findUnusedPort();
+
+ udpEncapResp = mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+ assertNotNull(udpEncapResp);
+ if (udpEncapResp.status == IpSecManager.Status.OK) {
+ break;
+ }
+
+ // Else retry to reduce possibility for port-bind failures.
+ }
+
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
assertEquals(localport, udpEncapResp.port);
@@ -204,12 +215,11 @@
@Test
public void testOpenUdpEncapsulationSocketAfterClose() throws Exception {
- int localport = findUnusedPort();
IpSecUdpEncapResponse udpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+ mIpSecService.openUdpEncapsulationSocket(0, new Binder());
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
- assertEquals(localport, udpEncapResp.port);
+ int localport = udpEncapResp.port;
mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
udpEncapResp.fileDescriptor.close();
@@ -226,12 +236,11 @@
*/
@Test
public void testUdpEncapPortNotReleased() throws Exception {
- int localport = findUnusedPort();
IpSecUdpEncapResponse udpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+ mIpSecService.openUdpEncapsulationSocket(0, new Binder());
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
- assertEquals(localport, udpEncapResp.port);
+ int localport = udpEncapResp.port;
udpEncapResp.fileDescriptor.close();
@@ -273,14 +282,11 @@
@Test
public void testOpenUdpEncapsulationSocketTwice() throws Exception {
- int localport = findUnusedPort();
-
IpSecUdpEncapResponse udpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+ mIpSecService.openUdpEncapsulationSocket(0, new Binder());
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
- assertEquals(localport, udpEncapResp.port);
- mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+ int localport = udpEncapResp.port;
IpSecUdpEncapResponse testUdpEncapResp =
mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index 354c08f..62a4718 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -20,11 +20,15 @@
import static android.Manifest.permission.CHANGE_WIFI_STATE;
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
+import static android.Manifest.permission.INTERNET;
import static android.Manifest.permission.NETWORK_STACK;
+import static android.Manifest.permission.UPDATE_DEVICE_STATS;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_OEM;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_PRODUCT;
import static android.content.pm.ApplicationInfo.PRIVATE_FLAG_VENDOR;
+import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
+import static android.content.pm.PackageManager.MATCH_ANY_USER;
import static android.os.Process.SYSTEM_UID;
import static com.android.server.connectivity.PermissionMonitor.NETWORK;
@@ -33,35 +37,54 @@
import static junit.framework.Assert.fail;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.AdditionalMatchers.aryEq;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.anyInt;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageList;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
+import android.content.pm.UserInfo;
+import android.net.INetd;
+import android.net.UidRange;
import android.os.Build;
-import android.os.INetworkManagementService;
import android.os.UserHandle;
+import android.os.UserManager;
+import android.util.SparseIntArray;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.LocalServices;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Set;
+
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -69,9 +92,15 @@
private static final int MOCK_USER1 = 0;
private static final int MOCK_USER2 = 1;
private static final int MOCK_UID1 = 10001;
+ private static final int MOCK_UID2 = 10086;
+ private static final int SYSTEM_UID1 = 1000;
+ private static final int SYSTEM_UID2 = 1008;
+ private static final int VPN_UID = 10002;
private static final String MOCK_PACKAGE1 = "appName1";
+ private static final String MOCK_PACKAGE2 = "appName2";
private static final String SYSTEM_PACKAGE1 = "sysName1";
private static final String SYSTEM_PACKAGE2 = "sysName2";
+ private static final String VPN_PACKAGE = "vpnApp";
private static final String PARTITION_SYSTEM = "system";
private static final String PARTITION_OEM = "oem";
private static final String PARTITION_PRODUCT = "product";
@@ -81,15 +110,37 @@
@Mock private Context mContext;
@Mock private PackageManager mPackageManager;
- @Mock private INetworkManagementService mNMS;
+ @Mock private INetd mNetdService;
+ @Mock private PackageManagerInternal mMockPmi;
+ @Mock private UserManager mUserManager;
+ private PackageManagerInternal.PackageListObserver mObserver;
private PermissionMonitor mPermissionMonitor;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
- mPermissionMonitor = spy(new PermissionMonitor(mContext, mNMS));
+ when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
+ when(mUserManager.getUsers(eq(true))).thenReturn(
+ Arrays.asList(new UserInfo[] {
+ new UserInfo(MOCK_USER1, "", 0),
+ new UserInfo(MOCK_USER2, "", 0),
+ }));
+
+ mPermissionMonitor = spy(new PermissionMonitor(mContext, mNetdService));
+
+ LocalServices.removeServiceForTest(PackageManagerInternal.class);
+ LocalServices.addService(PackageManagerInternal.class, mMockPmi);
+ when(mMockPmi.getPackageList(any())).thenReturn(new PackageList(new ArrayList<String>(),
+ /* observer */ null));
+ when(mPackageManager.getInstalledPackages(anyInt())).thenReturn(/* empty app list */ null);
+ mPermissionMonitor.startMonitoring();
+
+ final ArgumentCaptor<PackageManagerInternal.PackageListObserver> observerCaptor =
+ ArgumentCaptor.forClass(PackageManagerInternal.PackageListObserver.class);
+ verify(mMockPmi).getPackageList(observerCaptor.capture());
+ mObserver = observerCaptor.getValue();
}
private boolean hasBgPermission(String partition, int targetSdkVersion, int uid,
@@ -103,10 +154,21 @@
return mPermissionMonitor.hasUseBackgroundNetworksPermission(uid);
}
- private PackageInfo packageInfoWithPermissions(String[] permissions, String partition) {
+ private static PackageInfo packageInfoWithPermissions(String[] permissions, String partition) {
+ int[] requestedPermissionsFlags = new int[permissions.length];
+ for (int i = 0; i < permissions.length; i++) {
+ requestedPermissionsFlags[i] = REQUESTED_PERMISSION_GRANTED;
+ }
+ return packageInfoWithPermissions(permissions, partition,
+ requestedPermissionsFlags);
+ }
+
+ private static PackageInfo packageInfoWithPermissions(String[] permissions, String partition,
+ int[] requestedPermissionsFlags) {
final PackageInfo packageInfo = new PackageInfo();
packageInfo.requestedPermissions = permissions;
packageInfo.applicationInfo = new ApplicationInfo();
+ packageInfo.requestedPermissionsFlags = requestedPermissionsFlags;
int privateFlags = 0;
switch (partition) {
case PARTITION_OEM:
@@ -123,6 +185,18 @@
return packageInfo;
}
+ private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid, int userId) {
+ final PackageInfo pkgInfo;
+ if (hasSystemPermission) {
+ pkgInfo = packageInfoWithPermissions(new String[] {CHANGE_NETWORK_STATE, NETWORK_STACK},
+ PARTITION_SYSTEM);
+ } else {
+ pkgInfo = packageInfoWithPermissions(new String[] {}, "");
+ }
+ pkgInfo.applicationInfo.uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
+ return pkgInfo;
+ }
+
@Test
public void testHasPermission() {
PackageInfo app = packageInfoWithPermissions(new String[] {}, PARTITION_SYSTEM);
@@ -203,14 +277,14 @@
assertFalse(hasBgPermission(PARTITION_VENDOR, VERSION_Q, MOCK_UID1, CHANGE_WIFI_STATE));
}
- private class NMSMonitor {
+ private class NetdMonitor {
private final HashMap<Integer, Boolean> mApps = new HashMap<>();
- NMSMonitor(INetworkManagementService mockNMS) throws Exception {
+ NetdMonitor(INetd mockNetd) throws Exception {
// Add hook to verify and track result of setPermission.
doAnswer((InvocationOnMock invocation) -> {
final Object[] args = invocation.getArguments();
- final Boolean isSystem = args[0].equals("SYSTEM");
+ final Boolean isSystem = args[0].equals(INetd.PERMISSION_SYSTEM);
for (final int uid : (int[]) args[1]) {
// TODO: Currently, permission monitor will send duplicate commands for each uid
// corresponding to each user. Need to fix that and uncomment below test.
@@ -220,7 +294,7 @@
mApps.put(uid, isSystem);
}
return null;
- }).when(mockNMS).setPermission(anyString(), any(int[].class));
+ }).when(mockNetd).networkSetPermissionForUser(anyInt(), any(int[].class));
// Add hook to verify and track result of clearPermission.
doAnswer((InvocationOnMock invocation) -> {
@@ -234,7 +308,7 @@
mApps.remove(uid);
}
return null;
- }).when(mockNMS).clearPermission(any(int[].class));
+ }).when(mockNetd).networkClearPermissionForUser(any(int[].class));
}
public void expectPermission(Boolean permission, int[] users, int[] apps) {
@@ -265,7 +339,7 @@
@Test
public void testUserAndPackageAddRemove() throws Exception {
- final NMSMonitor mNMSMonitor = new NMSMonitor(mNMS);
+ final NetdMonitor mNetdMonitor = new NetdMonitor(mNetdService);
// MOCK_UID1: MOCK_PACKAGE1 only has network permission.
// SYSTEM_UID: SYSTEM_PACKAGE1 has system permission.
@@ -281,48 +355,123 @@
// Add SYSTEM_PACKAGE2, expect only have network permission.
mPermissionMonitor.onUserAdded(MOCK_USER1);
addPackageForUsers(new int[]{MOCK_USER1}, SYSTEM_PACKAGE2, SYSTEM_UID);
- mNMSMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1}, new int[]{SYSTEM_UID});
+ mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1}, new int[]{SYSTEM_UID});
// Add SYSTEM_PACKAGE1, expect permission escalate.
addPackageForUsers(new int[]{MOCK_USER1}, SYSTEM_PACKAGE1, SYSTEM_UID);
- mNMSMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1}, new int[]{SYSTEM_UID});
+ mNetdMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1}, new int[]{SYSTEM_UID});
mPermissionMonitor.onUserAdded(MOCK_USER2);
- mNMSMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1, MOCK_USER2},
+ mNetdMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1, MOCK_USER2},
new int[]{SYSTEM_UID});
addPackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, MOCK_PACKAGE1, MOCK_UID1);
- mNMSMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1, MOCK_USER2},
+ mNetdMonitor.expectPermission(SYSTEM, new int[]{MOCK_USER1, MOCK_USER2},
new int[]{SYSTEM_UID});
- mNMSMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2},
+ mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2},
new int[]{MOCK_UID1});
// Remove MOCK_UID1, expect no permission left for all user.
mPermissionMonitor.onPackageRemoved(MOCK_UID1);
removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, MOCK_UID1);
- mNMSMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2}, new int[]{MOCK_UID1});
+ mNetdMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2}, new int[]{MOCK_UID1});
// Remove SYSTEM_PACKAGE1, expect permission downgrade.
when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{SYSTEM_PACKAGE2});
removePackageForUsers(new int[]{MOCK_USER1, MOCK_USER2}, SYSTEM_UID);
- mNMSMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2},
+ mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER1, MOCK_USER2},
new int[]{SYSTEM_UID});
mPermissionMonitor.onUserRemoved(MOCK_USER1);
- mNMSMonitor.expectPermission(NETWORK, new int[]{MOCK_USER2}, new int[]{SYSTEM_UID});
+ mNetdMonitor.expectPermission(NETWORK, new int[]{MOCK_USER2}, new int[]{SYSTEM_UID});
// Remove all packages, expect no permission left.
when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{});
removePackageForUsers(new int[]{MOCK_USER2}, SYSTEM_UID);
- mNMSMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2},
+ mNetdMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2},
new int[]{SYSTEM_UID, MOCK_UID1});
// Remove last user, expect no redundant clearPermission is invoked.
mPermissionMonitor.onUserRemoved(MOCK_USER2);
- mNMSMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2},
+ mNetdMonitor.expectNoPermission(new int[]{MOCK_USER1, MOCK_USER2},
new int[]{SYSTEM_UID, MOCK_UID1});
}
+ @Test
+ public void testUidFilteringDuringVpnConnectDisconnectAndUidUpdates() throws Exception {
+ when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
+ Arrays.asList(new PackageInfo[] {
+ buildPackageInfo(/* SYSTEM */ true, SYSTEM_UID1, MOCK_USER1),
+ buildPackageInfo(/* SYSTEM */ false, MOCK_UID1, MOCK_USER1),
+ buildPackageInfo(/* SYSTEM */ false, MOCK_UID2, MOCK_USER1),
+ buildPackageInfo(/* SYSTEM */ false, VPN_UID, MOCK_USER1)
+ }));
+ when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS))).thenReturn(
+ buildPackageInfo(false, MOCK_UID1, MOCK_USER1));
+ mPermissionMonitor.startMonitoring();
+ // Every app on user 0 except MOCK_UID2 are under VPN.
+ final Set<UidRange> vpnRange1 = new HashSet<>(Arrays.asList(new UidRange[] {
+ new UidRange(0, MOCK_UID2 - 1),
+ new UidRange(MOCK_UID2 + 1, UserHandle.PER_USER_RANGE - 1)}));
+ final Set<UidRange> vpnRange2 = Collections.singleton(new UidRange(MOCK_UID2, MOCK_UID2));
+
+ // When VPN is connected, expect a rule to be set up for user app MOCK_UID1
+ mPermissionMonitor.onVpnUidRangesAdded("tun0", vpnRange1, VPN_UID);
+ verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
+ aryEq(new int[] {MOCK_UID1}));
+
+ reset(mNetdService);
+
+ // When MOCK_UID1 package is uninstalled and reinstalled, expect Netd to be updated
+ mPermissionMonitor.onPackageRemoved(UserHandle.getUid(MOCK_USER1, MOCK_UID1));
+ verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1}));
+ mPermissionMonitor.onPackageAdded(MOCK_PACKAGE1, UserHandle.getUid(MOCK_USER1, MOCK_UID1));
+ verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
+ aryEq(new int[] {MOCK_UID1}));
+
+ reset(mNetdService);
+
+ // During VPN uid update (vpnRange1 -> vpnRange2), ConnectivityService first deletes the
+ // old UID rules then adds the new ones. Expect netd to be updated
+ mPermissionMonitor.onVpnUidRangesRemoved("tun0", vpnRange1, VPN_UID);
+ verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1}));
+ mPermissionMonitor.onVpnUidRangesAdded("tun0", vpnRange2, VPN_UID);
+ verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
+ aryEq(new int[] {MOCK_UID2}));
+
+ reset(mNetdService);
+
+ // When VPN is disconnected, expect rules to be torn down
+ mPermissionMonitor.onVpnUidRangesRemoved("tun0", vpnRange2, VPN_UID);
+ verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID2}));
+ assertNull(mPermissionMonitor.getVpnUidRanges("tun0"));
+ }
+
+ @Test
+ public void testUidFilteringDuringPackageInstallAndUninstall() throws Exception {
+ when(mPackageManager.getInstalledPackages(eq(GET_PERMISSIONS | MATCH_ANY_USER))).thenReturn(
+ Arrays.asList(new PackageInfo[] {
+ buildPackageInfo(true, SYSTEM_UID1, MOCK_USER1),
+ buildPackageInfo(false, VPN_UID, MOCK_USER1)
+ }));
+ when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE1), eq(GET_PERMISSIONS))).thenReturn(
+ buildPackageInfo(false, MOCK_UID1, MOCK_USER1));
+
+ mPermissionMonitor.startMonitoring();
+ final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(MOCK_USER1));
+ mPermissionMonitor.onVpnUidRangesAdded("tun0", vpnRange, VPN_UID);
+
+ // Newly-installed package should have uid rules added
+ mPermissionMonitor.onPackageAdded(MOCK_PACKAGE1, UserHandle.getUid(MOCK_USER1, MOCK_UID1));
+ verify(mNetdService).firewallAddUidInterfaceRules(eq("tun0"),
+ aryEq(new int[] {MOCK_UID1}));
+
+ // Removed package should have its uid rules removed
+ mPermissionMonitor.onPackageRemoved(UserHandle.getUid(MOCK_USER1, MOCK_UID1));
+ verify(mNetdService).firewallRemoveUidInterfaceRules(aryEq(new int[] {MOCK_UID1}));
+ }
+
+
// Normal package add/remove operations will trigger multiple intent for uids corresponding to
// each user. To simulate generic package operations, the onPackageAdded/Removed will need to be
// called multiple times with the uid corresponding to each user.
@@ -337,4 +486,164 @@
mPermissionMonitor.onPackageRemoved(UserHandle.getUid(user, uid));
}
}
+
+ private class NetdServiceMonitor {
+ private final HashMap<Integer, Integer> mPermissions = new HashMap<>();
+
+ NetdServiceMonitor(INetd mockNetdService) throws Exception {
+ // Add hook to verify and track result of setPermission.
+ doAnswer((InvocationOnMock invocation) -> {
+ final Object[] args = invocation.getArguments();
+ final int permission = (int) args[0];
+ for (final int uid : (int[]) args[1]) {
+ mPermissions.put(uid, permission);
+ }
+ return null;
+ }).when(mockNetdService).trafficSetNetPermForUids(anyInt(), any(int[].class));
+ }
+
+ public void expectPermission(int permission, int[] apps) {
+ for (final int app : apps) {
+ if (!mPermissions.containsKey(app)) {
+ fail("uid " + app + " does not exist.");
+ }
+ if (mPermissions.get(app) != permission) {
+ fail("uid " + app + " has wrong permission: " + mPermissions.get(app));
+ }
+ }
+ }
+ }
+
+ @Test
+ public void testPackagePermissionUpdate() throws Exception {
+ final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+ // MOCK_UID1: MOCK_PACKAGE1 only has internet permission.
+ // MOCK_UID2: MOCK_PACKAGE2 does not have any permission.
+ // SYSTEM_UID1: SYSTEM_PACKAGE1 has internet permission and update device stats permission.
+ // SYSTEM_UID2: SYSTEM_PACKAGE2 has only update device stats permission.
+
+ SparseIntArray netdPermissionsAppIds = new SparseIntArray();
+ netdPermissionsAppIds.put(MOCK_UID1, INetd.PERMISSION_INTERNET);
+ netdPermissionsAppIds.put(MOCK_UID2, INetd.NO_PERMISSIONS);
+ netdPermissionsAppIds.put(SYSTEM_UID1, INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS);
+ netdPermissionsAppIds.put(SYSTEM_UID2, INetd.PERMISSION_UPDATE_DEVICE_STATS);
+
+ // Send the permission information to netd, expect permission updated.
+ mPermissionMonitor.sendPackagePermissionsToNetd(netdPermissionsAppIds);
+
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET,
+ new int[]{MOCK_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.NO_PERMISSIONS, new int[]{MOCK_UID2});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{SYSTEM_UID1});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UPDATE_DEVICE_STATS,
+ new int[]{SYSTEM_UID2});
+
+ // Update permission of MOCK_UID1, expect new permission show up.
+ mPermissionMonitor.sendPackagePermissionsForUid(MOCK_UID1,
+ INetd.PERMISSION_INTERNET | INetd.PERMISSION_UPDATE_DEVICE_STATS);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+
+ // Change permissions of SYSTEM_UID2, expect new permission show up and old permission
+ // revoked.
+ mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID2,
+ INetd.PERMISSION_INTERNET);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{SYSTEM_UID2});
+
+ // Revoke permission from SYSTEM_UID1, expect no permission stored.
+ mPermissionMonitor.sendPackagePermissionsForUid(SYSTEM_UID1, INetd.NO_PERMISSIONS);
+ mNetdServiceMonitor.expectPermission(INetd.NO_PERMISSIONS, new int[]{SYSTEM_UID1});
+ }
+
+ private PackageInfo addPackage(String packageName, int uid, String[] permissions)
+ throws Exception {
+ PackageInfo packageInfo = packageInfoWithPermissions(permissions, PARTITION_SYSTEM);
+ when(mPackageManager.getPackageInfo(eq(packageName), anyInt())).thenReturn(packageInfo);
+ when(mPackageManager.getPackagesForUid(eq(uid))).thenReturn(new String[]{packageName});
+ mObserver.onPackageAdded(packageName, uid);
+ return packageInfo;
+ }
+
+ @Test
+ public void testPackageInstall() throws Exception {
+ final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+
+ addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+
+ addPackage(MOCK_PACKAGE2, MOCK_UID2, new String[] {INTERNET});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID2});
+ }
+
+ @Test
+ public void testPackageInstallSharedUid() throws Exception {
+ final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+
+ PackageInfo packageInfo1 = addPackage(MOCK_PACKAGE1, MOCK_UID1,
+ new String[] {INTERNET, UPDATE_DEVICE_STATS});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+
+ // Install another package with the same uid and no permissions should not cause the UID to
+ // lose permissions.
+ PackageInfo packageInfo2 = packageInfoWithPermissions(new String[]{}, PARTITION_SYSTEM);
+ when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
+ when(mPackageManager.getPackagesForUid(MOCK_UID1))
+ .thenReturn(new String[]{MOCK_PACKAGE1, MOCK_PACKAGE2});
+ mObserver.onPackageAdded(MOCK_PACKAGE2, MOCK_UID1);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+ }
+
+ @Test
+ public void testPackageUninstallBasic() throws Exception {
+ final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+
+ addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+
+ when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
+ mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
+ }
+
+ @Test
+ public void testPackageUpdate() throws Exception {
+ final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+
+ addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+
+ // Remove and install the same package to simulate the update action
+ when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{});
+ mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_UNINSTALLED, new int[]{MOCK_UID1});
+
+ addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
+ }
+
+ @Test
+ public void testPackageUninstallWithMultiplePackages() throws Exception {
+ final NetdServiceMonitor mNetdServiceMonitor = new NetdServiceMonitor(mNetdService);
+
+ addPackage(MOCK_PACKAGE1, MOCK_UID1, new String[] {INTERNET, UPDATE_DEVICE_STATS});
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET
+ | INetd.PERMISSION_UPDATE_DEVICE_STATS, new int[]{MOCK_UID1});
+
+ // Mock another package with the same uid but different permissions.
+ PackageInfo packageInfo2 = packageInfoWithPermissions(new String[] {INTERNET},
+ PARTITION_SYSTEM);
+ when(mPackageManager.getPackageInfo(eq(MOCK_PACKAGE2), anyInt())).thenReturn(packageInfo2);
+ when(mPackageManager.getPackagesForUid(MOCK_UID1)).thenReturn(new String[]{
+ MOCK_PACKAGE2});
+
+ mObserver.onPackageRemoved(MOCK_PACKAGE1, MOCK_UID1);
+ mNetdServiceMonitor.expectPermission(INetd.PERMISSION_INTERNET, new int[]{MOCK_UID1});
+ }
}
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
index 36a1b7c..2140322 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
@@ -122,7 +122,7 @@
mMockContext = new MockContext(mContext);
}
- private TetheringConfiguration getTetheringConfiguration(int[] legacyTetherUpstreamTypes) {
+ private TetheringConfiguration getTetheringConfiguration(int... legacyTetherUpstreamTypes) {
when(mResources.getIntArray(config_tether_upstream_types)).thenReturn(
legacyTetherUpstreamTypes);
return new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID);
@@ -143,13 +143,13 @@
public void testDunFromTelephonyManagerMeansDun() {
when(mTelephonyManager.getTetherApnRequired()).thenReturn(true);
- final TetheringConfiguration cfgWifi = getTetheringConfiguration(new int[]{TYPE_WIFI});
+ final TetheringConfiguration cfgWifi = getTetheringConfiguration(TYPE_WIFI);
final TetheringConfiguration cfgMobileWifiHipri = getTetheringConfiguration(
- new int[]{TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI});
+ TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI);
final TetheringConfiguration cfgWifiDun = getTetheringConfiguration(
- new int[]{TYPE_WIFI, TYPE_MOBILE_DUN});
+ TYPE_WIFI, TYPE_MOBILE_DUN);
final TetheringConfiguration cfgMobileWifiHipriDun = getTetheringConfiguration(
- new int[]{TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI, TYPE_MOBILE_DUN});
+ TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI, TYPE_MOBILE_DUN);
for (TetheringConfiguration cfg : Arrays.asList(cfgWifi, cfgMobileWifiHipri,
cfgWifiDun, cfgMobileWifiHipriDun)) {
@@ -167,20 +167,20 @@
public void testDunNotRequiredFromTelephonyManagerMeansNoDun() {
when(mTelephonyManager.getTetherApnRequired()).thenReturn(false);
- final TetheringConfiguration cfgWifi = getTetheringConfiguration(new int[]{TYPE_WIFI});
+ final TetheringConfiguration cfgWifi = getTetheringConfiguration(TYPE_WIFI);
final TetheringConfiguration cfgMobileWifiHipri = getTetheringConfiguration(
- new int[]{TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI});
+ TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI);
final TetheringConfiguration cfgWifiDun = getTetheringConfiguration(
- new int[]{TYPE_WIFI, TYPE_MOBILE_DUN});
+ TYPE_WIFI, TYPE_MOBILE_DUN);
final TetheringConfiguration cfgWifiMobile = getTetheringConfiguration(
- new int[]{TYPE_WIFI, TYPE_MOBILE});
+ TYPE_WIFI, TYPE_MOBILE);
final TetheringConfiguration cfgWifiHipri = getTetheringConfiguration(
- new int[]{TYPE_WIFI, TYPE_MOBILE_HIPRI});
+ TYPE_WIFI, TYPE_MOBILE_HIPRI);
final TetheringConfiguration cfgMobileWifiHipriDun = getTetheringConfiguration(
- new int[]{TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI, TYPE_MOBILE_DUN});
+ TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI, TYPE_MOBILE_DUN);
String msg;
- // TYPE_MOBILE_DUN should not be present in all of the combinations.
+ // TYPE_MOBILE_DUN should be present in none of the combinations.
// TYPE_WIFI should not be affected.
for (TetheringConfiguration cfg : Arrays.asList(cfgWifi, cfgMobileWifiHipri, cfgWifiDun,
cfgWifiMobile, cfgWifiHipri, cfgMobileWifiHipriDun)) {
diff --git a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
similarity index 96%
rename from tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
rename to tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
index 4ec4fdd..95bc7d9 100644
--- a/tests/net/java/com/android/internal/net/NetworkStatsFactoryTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.internal.net;
+package com.android.server.net;
import static android.net.NetworkStats.DEFAULT_NETWORK_NO;
import static android.net.NetworkStats.METERED_NO;
@@ -70,6 +70,10 @@
IoUtils.deleteContents(mTestProc);
}
+ // The libandroid_servers which have the native method is not available to
+ // applications. So in order to have a test support native library, the native code
+ // related to networkStatsFactory is compiled to a minimal native library and loaded here.
+ System.loadLibrary("networkstatsfactorytestjni");
mFactory = new NetworkStatsFactory(mTestProc, false);
}
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java b/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java
index dc20185..fb84611 100644
--- a/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java
+++ b/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java
@@ -57,6 +57,7 @@
final NetworkAttributes na =
new NetworkAttributes(
(Inet4Address) Inet4Address.getByAddress(new byte[] {1, 2, 3, 4}),
+ System.currentTimeMillis() + 7_200_000,
"some hint",
Arrays.asList(Inet4Address.getByAddress(new byte[] {5, 6, 7, 8}),
Inet4Address.getByAddress(new byte[] {9, 0, 1, 2})),
diff --git a/tests/net/jni/Android.bp b/tests/net/jni/Android.bp
new file mode 100644
index 0000000..9225ffb
--- /dev/null
+++ b/tests/net/jni/Android.bp
@@ -0,0 +1,23 @@
+cc_library_shared {
+ name: "libnetworkstatsfactorytestjni",
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-unused-parameter",
+ "-Wthread-safety",
+ ],
+
+ srcs: [
+ ":lib_networkStatsFactory_native",
+ "test_onload.cpp",
+ ],
+
+ shared_libs: [
+ "libbpf_android",
+ "liblog",
+ "libnativehelper",
+ "libnetdbpf",
+ "libnetdutils",
+ ],
+}
diff --git a/tests/net/jni/test_onload.cpp b/tests/net/jni/test_onload.cpp
new file mode 100644
index 0000000..5194ddb
--- /dev/null
+++ b/tests/net/jni/test_onload.cpp
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+/*
+ * this is a mini native libaray for NetworkStatsFactoryTest to run properly. It
+ * load all the native method related to NetworkStatsFactory when test run
+ */
+#include <nativehelper/JNIHelp.h>
+#include "jni.h"
+#include "utils/Log.h"
+#include "utils/misc.h"
+
+namespace android {
+int register_android_server_net_NetworkStatsFactory(JNIEnv* env);
+};
+
+using namespace android;
+
+extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
+{
+ JNIEnv* env = NULL;
+ jint result = -1;
+
+ if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
+ ALOGE("GetEnv failed!");
+ return result;
+ }
+ ALOG_ASSERT(env, "Could not retrieve the env!");
+ register_android_server_net_NetworkStatsFactory(env);
+ return JNI_VERSION_1_4;
+}
diff --git a/tests/net/smoketest/Android.bp b/tests/net/smoketest/Android.bp
new file mode 100644
index 0000000..ef1ad2c
--- /dev/null
+++ b/tests/net/smoketest/Android.bp
@@ -0,0 +1,17 @@
+// This test exists only because the jni_libs list for these tests is difficult to
+// maintain: the test itself only depends on libnetworkstatsfactorytestjni, but the test
+// fails to load that library unless *all* the dependencies of that library are explicitly
+// listed in jni_libs. This means that whenever any of the dependencies changes the test
+// starts failing and breaking presubmits in frameworks/base. We cannot easily put
+// FrameworksNetTests into global presubmit because they are at times flaky, but this
+// test is effectively empty beyond validating that the libraries load correctly, and
+// thus should be stable enough to put in global presubmit.
+//
+// TODO: remove this hack when there is a better solution for jni_libs that includes
+// dependent libraries.
+android_test {
+ name: "FrameworksNetSmokeTests",
+ defaults: ["FrameworksNetTests-jni-defaults"],
+ srcs: ["java/SmokeTest.java"],
+ test_suites: ["device-tests"],
+}
diff --git a/tests/net/smoketest/AndroidManifest.xml b/tests/net/smoketest/AndroidManifest.xml
new file mode 100644
index 0000000..f1b9feb
--- /dev/null
+++ b/tests/net/smoketest/AndroidManifest.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.tests.net.smoketest">
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.frameworks.tests.net.smoketest"
+ android:label="Frameworks Networking Smoke Tests" />
+</manifest>
diff --git a/tests/net/smoketest/AndroidTest.xml b/tests/net/smoketest/AndroidTest.xml
new file mode 100644
index 0000000..ac366e4
--- /dev/null
+++ b/tests/net/smoketest/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<configuration description="Runs Frameworks Networking Smoke Tests.">
+ <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+ <option name="test-file-name" value="FrameworksNetSmokeTests.apk" />
+ </target_preparer>
+
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-tag" value="FrameworksNetSmokeTests" />
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.frameworks.tests.net.smoketest" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration>
diff --git a/packages/NetworkStackPermissionStub/src/com/android/server/NetworkStackPermissionStub.java b/tests/net/smoketest/java/SmokeTest.java
similarity index 62%
copy from packages/NetworkStackPermissionStub/src/com/android/server/NetworkStackPermissionStub.java
copy to tests/net/smoketest/java/SmokeTest.java
index 01e59d2..7d6655f 100644
--- a/packages/NetworkStackPermissionStub/src/com/android/server/NetworkStackPermissionStub.java
+++ b/tests/net/smoketest/java/SmokeTest.java
@@ -14,13 +14,20 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.server.net;
-import android.app.Application;
+import static org.junit.Assert.assertEquals;
-/**
- * Empty application for NetworkStackStub that only exists because soong builds complain if APKs
- * have no source file.
- */
-public class NetworkStackPermissionStub extends Application {
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public final class SmokeTest {
+
+ @Test
+ public void testLoadJni() {
+ System.loadLibrary("networkstatsfactorytestjni");
+ assertEquals(0, 0x00);
+ }
}
diff --git a/tools/hiddenapi/generate_hiddenapi_lists.py b/tools/hiddenapi/generate_hiddenapi_lists.py
index 6781eba..c856cc3 100755
--- a/tools/hiddenapi/generate_hiddenapi_lists.py
+++ b/tools/hiddenapi/generate_hiddenapi_lists.py
@@ -21,6 +21,7 @@
import os
import sys
import re
+import functools
# Names of flags recognized by the `hiddenapi` tool.
FLAG_WHITELIST = "whitelist"
@@ -58,6 +59,10 @@
# script to skip any entries which do not exist any more.
FLAG_IGNORE_CONFLICTS_SUFFIX = "-ignore-conflicts"
+# Suffix used in command line args to express that all apis within a given set
+# of packages should be assign the given flag.
+FLAG_PACKAGES_SUFFIX = "-packages"
+
# Regex patterns of fields/methods used in serialization. These are
# considered public API despite being hidden.
SERIALIZATION_PATTERNS = [
@@ -91,12 +96,16 @@
for flag in ALL_FLAGS:
ignore_conflicts_flag = flag + FLAG_IGNORE_CONFLICTS_SUFFIX
+ packages_flag = flag + FLAG_PACKAGES_SUFFIX
parser.add_argument('--' + flag, dest=flag, nargs='*', default=[], metavar='TXT_FILE',
help='lists of entries with flag "' + flag + '"')
parser.add_argument('--' + ignore_conflicts_flag, dest=ignore_conflicts_flag, nargs='*',
default=[], metavar='TXT_FILE',
help='lists of entries with flag "' + flag +
'". skip entry if missing or flag conflict.')
+ parser.add_argument('--' + packages_flag, dest=packages_flag, nargs='*',
+ default=[], metavar='TXT_FILE',
+ help='lists of packages to be added to ' + flag + ' list')
return parser.parse_args()
@@ -128,6 +137,19 @@
with open(filename, 'w') as f:
f.writelines(lines)
+def extract_package(signature):
+ """Extracts the package from a signature.
+
+ Args:
+ signature (string): JNI signature of a method or field.
+
+ Returns:
+ The package name of the class containing the field/method.
+ """
+ full_class_name = signature.split(";->")[0]
+ package_name = full_class_name[1:full_class_name.rindex("/")]
+ return package_name.replace('/', '.')
+
class FlagsDict:
def __init__(self):
self._dict_keyset = set()
@@ -206,7 +228,10 @@
self._dict_keyset.update([ csv[0] for csv in csv_values ])
# Check that all flags are known.
- csv_flags = set(reduce(lambda x, y: set(x).union(y), [ csv[1:] for csv in csv_values ], []))
+ csv_flags = set(functools.reduce(
+ lambda x, y: set(x).union(y),
+ [ csv[1:] for csv in csv_values ],
+ []))
self._check_flags_set(csv_flags, source)
# Iterate over all CSV lines, find entry in dict and append flags to it.
@@ -273,6 +298,15 @@
valid_entries = flags.get_valid_subset_of_unassigned_apis(read_lines(filename))
flags.assign_flag(flag, valid_entries, filename)
+ # All members in the specified packages will be assigned the appropriate flag.
+ for flag in ALL_FLAGS:
+ for filename in args[flag + FLAG_PACKAGES_SUFFIX]:
+ packages_needing_list = set(read_lines(filename))
+ should_add_signature_to_list = lambda sig,lists: extract_package(
+ sig) in packages_needing_list and not lists
+ valid_entries = flags.filter_apis(should_add_signature_to_list)
+ flags.assign_flag(flag, valid_entries)
+
# Assign all remaining entries to the blacklist.
flags.assign_flag(FLAG_BLACKLIST, flags.filter_apis(HAS_NO_API_LIST_ASSIGNED))
diff --git a/tools/hiddenapi/generate_hiddenapi_lists_test.py b/tools/hiddenapi/generate_hiddenapi_lists_test.py
index 249f37d..4dc880b 100755
--- a/tools/hiddenapi/generate_hiddenapi_lists_test.py
+++ b/tools/hiddenapi/generate_hiddenapi_lists_test.py
@@ -18,33 +18,23 @@
from generate_hiddenapi_lists import *
class TestHiddenapiListGeneration(unittest.TestCase):
- def test_init(self):
- # Check empty lists
- flags = FlagsDict([], [])
- self.assertEquals(flags.generate_csv(), [])
-
- # Check valid input - two public and two private API signatures.
- flags = FlagsDict(['A', 'B'], ['C', 'D'])
- self.assertEquals(flags.generate_csv(),
- [ 'A,' + FLAG_WHITELIST, 'B,' + FLAG_WHITELIST, 'C', 'D' ])
-
- # Check invalid input - overlapping public/private API signatures.
- with self.assertRaises(AssertionError):
- flags = FlagsDict(['A', 'B'], ['B', 'C', 'D'])
def test_filter_apis(self):
# Initialize flags so that A and B are put on the whitelist and
# C, D, E are left unassigned. Try filtering for the unassigned ones.
- flags = FlagsDict(['A', 'B'], ['C', 'D', 'E'])
+ flags = FlagsDict()
+ flags.parse_and_merge_csv(['A,' + FLAG_WHITELIST, 'B,' + FLAG_WHITELIST,
+ 'C', 'D', 'E'])
filter_set = flags.filter_apis(lambda api, flags: not flags)
self.assertTrue(isinstance(filter_set, set))
self.assertEqual(filter_set, set([ 'C', 'D', 'E' ]))
def test_get_valid_subset_of_unassigned_keys(self):
# Create flags where only A is unassigned.
- flags = FlagsDict(['A'], ['B', 'C'])
+ flags = FlagsDict()
+ flags.parse_and_merge_csv(['A,' + FLAG_WHITELIST, 'B', 'C'])
flags.assign_flag(FLAG_GREYLIST, set(['C']))
- self.assertEquals(flags.generate_csv(),
+ self.assertEqual(flags.generate_csv(),
[ 'A,' + FLAG_WHITELIST, 'B', 'C,' + FLAG_GREYLIST ])
# Check three things:
@@ -55,44 +45,30 @@
flags.get_valid_subset_of_unassigned_apis(set(['A', 'B', 'D'])), set([ 'B' ]))
def test_parse_and_merge_csv(self):
- flags = FlagsDict(['A'], ['B'])
- self.assertEquals(flags.generate_csv(), [ 'A,' + FLAG_WHITELIST, 'B' ])
+ flags = FlagsDict()
# Test empty CSV entry.
- flags.parse_and_merge_csv(['B'])
- self.assertEquals(flags.generate_csv(), [ 'A,' + FLAG_WHITELIST, 'B' ])
-
- # Test assigning an already assigned flag.
- flags.parse_and_merge_csv(['A,' + FLAG_WHITELIST])
- self.assertEquals(flags.generate_csv(), [ 'A,' + FLAG_WHITELIST, 'B' ])
+ self.assertEqual(flags.generate_csv(), [])
# Test new additions.
flags.parse_and_merge_csv([
'A,' + FLAG_GREYLIST,
'B,' + FLAG_BLACKLIST + ',' + FLAG_GREYLIST_MAX_O ])
self.assertEqual(flags.generate_csv(),
- [ 'A,' + FLAG_GREYLIST + "," + FLAG_WHITELIST,
+ [ 'A,' + FLAG_GREYLIST,
'B,' + FLAG_BLACKLIST + "," + FLAG_GREYLIST_MAX_O ])
- # Test unknown API signature.
- with self.assertRaises(AssertionError):
- flags.parse_and_merge_csv([ 'C' ])
-
# Test unknown flag.
with self.assertRaises(AssertionError):
- flags.parse_and_merge_csv([ 'A,foo' ])
+ flags.parse_and_merge_csv([ 'C,foo' ])
def test_assign_flag(self):
- flags = FlagsDict(['A'], ['B'])
- self.assertEquals(flags.generate_csv(), [ 'A,' + FLAG_WHITELIST, 'B' ])
-
- # Test assigning an already assigned flag.
- flags.assign_flag(FLAG_WHITELIST, set([ 'A' ]))
- self.assertEquals(flags.generate_csv(), [ 'A,' + FLAG_WHITELIST, 'B' ])
+ flags = FlagsDict()
+ flags.parse_and_merge_csv(['A,' + FLAG_WHITELIST, 'B'])
# Test new additions.
flags.assign_flag(FLAG_GREYLIST, set([ 'A', 'B' ]))
- self.assertEquals(flags.generate_csv(),
+ self.assertEqual(flags.generate_csv(),
[ 'A,' + FLAG_GREYLIST + "," + FLAG_WHITELIST, 'B,' + FLAG_GREYLIST ])
# Test invalid API signature.
@@ -103,5 +79,18 @@
with self.assertRaises(AssertionError):
flags.assign_flag('foo', set([ 'A' ]))
+ def test_extract_package(self):
+ signature = 'Lcom/foo/bar/Baz;->method1()Lcom/bar/Baz;'
+ expected_package = 'com.foo.bar'
+ self.assertEqual(extract_package(signature), expected_package)
+
+ signature = 'Lcom/foo1/bar/MyClass;->method2()V'
+ expected_package = 'com.foo1.bar'
+ self.assertEqual(extract_package(signature), expected_package)
+
+ signature = 'Lcom/foo_bar/baz/MyClass;->method3()V'
+ expected_package = 'com.foo_bar.baz'
+ self.assertEqual(extract_package(signature), expected_package)
+
if __name__ == '__main__':
unittest.main()
diff --git a/tools/preload-check/Android.bp b/tools/preload-check/Android.bp
new file mode 100644
index 0000000..c84567b
--- /dev/null
+++ b/tools/preload-check/Android.bp
@@ -0,0 +1,21 @@
+// Copyright (C) 2019 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.
+
+java_test_host {
+ name: "PreloadCheck",
+ srcs: ["src/**/*.java"],
+ libs: ["tradefed"],
+ test_suites: ["general-tests"],
+ required: ["preload-check-device"],
+}
diff --git a/tools/preload-check/AndroidTest.xml b/tools/preload-check/AndroidTest.xml
new file mode 100644
index 0000000..a0645d5
--- /dev/null
+++ b/tools/preload-check/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.
+-->
+<configuration description="Config for PreloadCheck">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="cleanup" value="true" />
+ <option name="push" value="preload-check-device.jar->/data/local/tmp/preload-check-device.jar" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.HostTest" >
+ <option name="class" value="com.android.preload.check.PreloadCheck" />
+ </test>
+</configuration>
diff --git a/tools/preload-check/TEST_MAPPING b/tools/preload-check/TEST_MAPPING
new file mode 100644
index 0000000..d09805e
--- /dev/null
+++ b/tools/preload-check/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "PreloadCheck"
+ }
+ ]
+}
diff --git a/tools/preload-check/device/Android.bp b/tools/preload-check/device/Android.bp
new file mode 100644
index 0000000..7782b0d
--- /dev/null
+++ b/tools/preload-check/device/Android.bp
@@ -0,0 +1,27 @@
+// Copyright (C) 2019 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.
+
+java_test_helper_library {
+ name: "preload-check-device",
+ host_supported: false,
+ device_supported: true,
+ compile_dex: true,
+
+ sdk_version: "current",
+ srcs: ["src/**/*.java"],
+ test_suites: ["general-tests"],
+ dex_preopt: {
+ enabled: false,
+ },
+}
diff --git a/packages/NetworkStackPermissionStub/src/com/android/server/NetworkStackPermissionStub.java b/tools/preload-check/device/src/com/android/preload/check/Initialized.java
similarity index 70%
copy from packages/NetworkStackPermissionStub/src/com/android/server/NetworkStackPermissionStub.java
copy to tools/preload-check/device/src/com/android/preload/check/Initialized.java
index 01e59d2..b21b5f6 100644
--- a/packages/NetworkStackPermissionStub/src/com/android/server/NetworkStackPermissionStub.java
+++ b/tools/preload-check/device/src/com/android/preload/check/Initialized.java
@@ -14,13 +14,11 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.preload.check;
-import android.app.Application;
-
-/**
- * Empty application for NetworkStackStub that only exists because soong builds complain if APKs
- * have no source file.
- */
-public class NetworkStackPermissionStub extends Application {
+public class Initialized {
+ public static void main(String[] args) throws Exception {
+ Util.assertInitialized(args[0], null);
+ System.out.println("OK");
+ }
}
diff --git a/tools/preload-check/device/src/com/android/preload/check/IntegrityCheck.java b/tools/preload-check/device/src/com/android/preload/check/IntegrityCheck.java
new file mode 100644
index 0000000..6cc3946
--- /dev/null
+++ b/tools/preload-check/device/src/com/android/preload/check/IntegrityCheck.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 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.preload.check;
+
+public class IntegrityCheck {
+ public static void main(String[] args) throws Exception {
+ ClassLoader loader = IntegrityCheck.class.getClassLoader();
+
+ Util.assertNotInitialized("com.android.preload.check.IntegrityCheck$StatusHelper", loader);
+
+ Class<?> klass = Class.forName("com.android.preload.check.IntegrityCheck$StatusHelper",
+ /* initialize */ true, loader);
+
+ Util.assertInitialized("com.android.preload.check.IntegrityCheck$StatusHelper", loader);
+
+ System.out.println("OK");
+ }
+
+ private static class StatusHelper {
+ private final static Object defer = new Object();
+ }
+}
diff --git a/packages/NetworkStackPermissionStub/src/com/android/server/NetworkStackPermissionStub.java b/tools/preload-check/device/src/com/android/preload/check/NotInitialized.java
similarity index 70%
copy from packages/NetworkStackPermissionStub/src/com/android/server/NetworkStackPermissionStub.java
copy to tools/preload-check/device/src/com/android/preload/check/NotInitialized.java
index 01e59d2..d2e98fe 100644
--- a/packages/NetworkStackPermissionStub/src/com/android/server/NetworkStackPermissionStub.java
+++ b/tools/preload-check/device/src/com/android/preload/check/NotInitialized.java
@@ -14,13 +14,11 @@
* limitations under the License.
*/
-package com.android.server;
+package com.android.preload.check;
-import android.app.Application;
-
-/**
- * Empty application for NetworkStackStub that only exists because soong builds complain if APKs
- * have no source file.
- */
-public class NetworkStackPermissionStub extends Application {
+public class NotInitialized {
+ public static void main(String[] args) throws Exception {
+ Util.assertNotInitialized(args[0], null);
+ System.out.println("OK");
+ }
}
diff --git a/tools/preload-check/device/src/com/android/preload/check/Util.java b/tools/preload-check/device/src/com/android/preload/check/Util.java
new file mode 100644
index 0000000..662f67a
--- /dev/null
+++ b/tools/preload-check/device/src/com/android/preload/check/Util.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2019 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.preload.check;
+
+import java.lang.reflect.Field;
+
+public class Util {
+ private static Field statusField;
+
+ static {
+ try {
+ Class<?> klass = Class.class;
+ statusField = klass.getDeclaredField("status");
+ statusField.setAccessible(true);
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ }
+
+ public static boolean isInitialized(Class<?> klass) throws Exception {
+ Object val = statusField.get(klass);
+ if (val == null || !(val instanceof Integer)) {
+ throw new IllegalStateException(String.valueOf(val));
+ }
+ int intVal = (int)val;
+ intVal = (intVal >> (32-4)) & 0xf;
+ return intVal >= 14;
+ }
+
+ public static void assertTrue(boolean val, String msg) {
+ if (!val) {
+ throw new RuntimeException(msg);
+ }
+ }
+
+ public static void assertInitializedState(String className, boolean expected,
+ ClassLoader loader) {
+ boolean initialized;
+ try {
+ Class<?> klass = Class.forName(className, /* initialize */ false, loader);
+ initialized = isInitialized(klass);
+ } catch (Throwable t) {
+ throw new RuntimeException(t);
+ }
+ assertTrue(expected == initialized, className);
+ }
+
+ public static void assertNotInitialized(String className, ClassLoader loader) {
+ assertInitializedState(className, false, loader);
+ }
+
+ public static void assertInitialized(String className, ClassLoader loader) {
+ assertInitializedState(className, true, loader);
+ }
+}
diff --git a/tools/preload-check/src/com/android/preload/check/PreloadCheck.java b/tools/preload-check/src/com/android/preload/check/PreloadCheck.java
new file mode 100644
index 0000000..dbdecdb
--- /dev/null
+++ b/tools/preload-check/src/com/android/preload/check/PreloadCheck.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2019 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.preload.check;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.IDeviceTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class PreloadCheck implements IDeviceTest {
+ private ITestDevice mTestDevice;
+
+ private static final String TEST_CLASSPATH = "/data/local/tmp/preload-check-device.jar";
+
+ @Override
+ public void setDevice(ITestDevice testDevice) {
+ mTestDevice = testDevice;
+ }
+
+ @Override
+ public ITestDevice getDevice() {
+ return mTestDevice;
+ }
+
+ /**
+ * Test that checks work as expected.
+ */
+ @Test
+ public void testStatus() throws Exception {
+ run("com.android.preload.check.IntegrityCheck");
+ }
+
+ /**
+ * b/130206915.
+ */
+ @Test
+ public void testAsyncTask() throws Exception {
+ run("com.android.preload.check.NotInitialized", "android.os.AsyncTask");
+ }
+
+ /**
+ * Just a check for something we expect to see initialized.
+ */
+ @Test
+ public void testAnimator() throws Exception {
+ run("com.android.preload.check.Initialized", "android.animation.Animator");
+ }
+
+ private void run(String cmd, String... args) throws Exception {
+ StringBuilder sb = new StringBuilder();
+ sb.append("app_process ")
+ .append("-cp ").append(TEST_CLASSPATH)
+ .append(" /system/bin ")
+ .append(cmd);
+ for (String arg : args) {
+ sb.append(' ').append(arg);
+ }
+ String res = mTestDevice.executeShellCommand(sb.toString());
+ assertEquals(sb.toString(), "OK", res.trim());
+ }
+}
diff --git a/tools/stats_log_api_gen/Android.bp b/tools/stats_log_api_gen/Android.bp
index 5725f0c..4ce4406 100644
--- a/tools/stats_log_api_gen/Android.bp
+++ b/tools/stats_log_api_gen/Android.bp
@@ -31,6 +31,7 @@
shared_libs: [
"libstats_proto_host",
"libprotobuf-cpp-full",
+ "libbase",
],
proto: {
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index 61174d9..49eee07 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -48,7 +48,9 @@
primaryFields(that.primaryFields),
exclusiveField(that.exclusiveField),
uidField(that.uidField),
- binaryFields(that.binaryFields) {}
+ binaryFields(that.binaryFields),
+ hasModule(that.hasModule),
+ moduleName(that.moduleName) {}
AtomDecl::AtomDecl(int c, const string& n, const string& m)
:code(c),
@@ -375,30 +377,60 @@
const Descriptor *atom = atomField->message_type();
AtomDecl atomDecl(atomField->number(), atomField->name(), atom->name());
+
+ if (atomField->options().HasExtension(os::statsd::log_from_module)) {
+ atomDecl.hasModule = true;
+ atomDecl.moduleName = atomField->options().GetExtension(os::statsd::log_from_module);
+ }
+
vector<java_type_t> signature;
errorCount += collate_atom(atom, &atomDecl, &signature);
if (atomDecl.primaryFields.size() != 0 && atomDecl.exclusiveField == 0) {
errorCount++;
}
- atoms->signatures.insert(signature);
+
+ // Add the signature if does not already exist.
+ auto signature_to_modules_it = atoms->signatures_to_modules.find(signature);
+ if (signature_to_modules_it == atoms->signatures_to_modules.end()) {
+ set<string> modules;
+ if (atomDecl.hasModule) {
+ modules.insert(atomDecl.moduleName);
+ }
+ atoms->signatures_to_modules[signature] = modules;
+ } else {
+ if (atomDecl.hasModule) {
+ signature_to_modules_it->second.insert(atomDecl.moduleName);
+ }
+ }
atoms->decls.insert(atomDecl);
AtomDecl nonChainedAtomDecl(atomField->number(), atomField->name(), atom->name());
vector<java_type_t> nonChainedSignature;
if (get_non_chained_node(atom, &nonChainedAtomDecl, &nonChainedSignature)) {
- atoms->non_chained_signatures.insert(nonChainedSignature);
+ auto it = atoms->non_chained_signatures_to_modules.find(signature);
+ if (it == atoms->non_chained_signatures_to_modules.end()) {
+ set<string> modules_non_chained;
+ if (atomDecl.hasModule) {
+ modules_non_chained.insert(atomDecl.moduleName);
+ }
+ atoms->non_chained_signatures_to_modules[nonChainedSignature] = modules_non_chained;
+ } else {
+ if (atomDecl.hasModule) {
+ it->second.insert(atomDecl.moduleName);
+ }
+ }
atoms->non_chained_decls.insert(nonChainedAtomDecl);
}
}
if (dbg) {
printf("signatures = [\n");
- for (set<vector<java_type_t>>::const_iterator it =
- atoms->signatures.begin();
- it != atoms->signatures.end(); it++) {
+ for (map<vector<java_type_t>, set<string>>::const_iterator it =
+ atoms->signatures_to_modules.begin();
+ it != atoms->signatures_to_modules.end(); it++) {
printf(" ");
- for (vector<java_type_t>::const_iterator jt = it->begin();
- jt != it->end(); jt++) {
+ for (vector<java_type_t>::const_iterator jt = it->first.begin();
+ jt != it->first.end(); jt++) {
printf(" %d", (int)*jt);
}
printf("\n");
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index a8b270c..e0ea2077 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -88,6 +88,9 @@
vector<int> binaryFields;
+ bool hasModule = false;
+ string moduleName;
+
AtomDecl();
AtomDecl(const AtomDecl& that);
AtomDecl(int code, const string& name, const string& message);
@@ -99,10 +102,10 @@
};
struct Atoms {
- set<vector<java_type_t>> signatures;
+ map<vector<java_type_t>, set<string>> signatures_to_modules;
set<AtomDecl> decls;
set<AtomDecl> non_chained_decls;
- set<vector<java_type_t>> non_chained_signatures;
+ map<vector<java_type_t>, set<string>> non_chained_signatures_to_modules;
};
/**
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 27e77fe..73a0fe1 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -12,6 +12,8 @@
#include <stdlib.h>
#include <string.h>
+#include "android-base/strings.h"
+
using namespace google::protobuf;
using namespace std;
@@ -22,6 +24,10 @@
int maxPushedAtomId = 2;
+const string DEFAULT_MODULE_NAME = "DEFAULT";
+const string DEFAULT_CPP_NAMESPACE = "android,util";
+const string DEFAULT_CPP_HEADER_IMPORT = "statslog.h";
+
using android::os::statsd::Atom;
/**
@@ -99,40 +105,27 @@
}
}
-static int write_stats_log_cpp(FILE *out, const Atoms &atoms,
- const AtomDecl &attributionDecl) {
- // Print prelude
- fprintf(out, "// This file is autogenerated\n");
- fprintf(out, "\n");
+static bool atom_needed_for_module(const AtomDecl& atomDecl, const string& moduleName) {
+ if (moduleName == DEFAULT_MODULE_NAME) {
+ return true;
+ }
+ return atomDecl.hasModule && (moduleName == atomDecl.moduleName);
+}
- fprintf(out, "#include <mutex>\n");
- fprintf(out, "#include <chrono>\n");
- fprintf(out, "#include <thread>\n");
- fprintf(out, "#ifdef __ANDROID__\n");
- fprintf(out, "#include <cutils/properties.h>\n");
- fprintf(out, "#endif\n");
- fprintf(out, "#include <stats_event_list.h>\n");
- fprintf(out, "#include <log/log.h>\n");
- fprintf(out, "#include <statslog.h>\n");
- fprintf(out, "#include <utils/SystemClock.h>\n");
- fprintf(out, "\n");
+static bool signature_needed_for_module(const set<string>& modules, const string& moduleName) {
+ if (moduleName == DEFAULT_MODULE_NAME) {
+ return true;
+ }
+ return modules.find(moduleName) != modules.end();
+}
- fprintf(out, "namespace android {\n");
- fprintf(out, "namespace util {\n");
- fprintf(out, "// the single event tag id for all stats logs\n");
- fprintf(out, "const static int kStatsEventTag = 1937006964;\n");
- fprintf(out, "#ifdef __ANDROID__\n");
- fprintf(out, "const static bool kStatsdEnabled = property_get_bool(\"ro.statsd.enable\", true);\n");
- fprintf(out, "#else\n");
- fprintf(out, "const static bool kStatsdEnabled = false;\n");
- fprintf(out, "#endif\n");
-
+static void write_atoms_info_cpp(FILE *out, const Atoms &atoms) {
std::set<string> kTruncatingAtomNames = {"mobile_radio_power_state_changed",
- "audio_state_changed",
- "call_state_changed",
- "phone_signal_strength_changed",
- "mobile_bytes_transfer_by_fg_bg",
- "mobile_bytes_transfer"};
+ "audio_state_changed",
+ "call_state_changed",
+ "phone_signal_strength_changed",
+ "mobile_bytes_transfer_by_fg_bg",
+ "mobile_bytes_transfer"};
fprintf(out,
"const std::set<int> "
"AtomsInfo::kNotTruncatingTimestampAtomWhiteList = {\n");
@@ -244,6 +237,56 @@
"const std::map<int, std::vector<int>> "
"AtomsInfo::kBytesFieldAtoms = "
"getBinaryFieldAtoms();\n");
+}
+
+// Writes namespaces for the cpp and header files, returning the number of namespaces written.
+void write_namespace(FILE* out, const string& cppNamespaces) {
+ vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
+ for (string cppNamespace : cppNamespaceVec) {
+ fprintf(out, "namespace %s {\n", cppNamespace.c_str());
+ }
+}
+
+// Writes namespace closing brackets for cpp and header files.
+void write_closing_namespace(FILE* out, const string& cppNamespaces) {
+ vector<string> cppNamespaceVec = android::base::Split(cppNamespaces, ",");
+ for (auto it = cppNamespaceVec.rbegin(); it != cppNamespaceVec.rend(); ++it) {
+ fprintf(out, "} // namespace %s\n", it->c_str());
+ }
+}
+
+static int write_stats_log_cpp(FILE *out, const Atoms &atoms, const AtomDecl &attributionDecl,
+ const string& moduleName, const string& cppNamespace,
+ const string& importHeader) {
+ // Print prelude
+ fprintf(out, "// This file is autogenerated\n");
+ fprintf(out, "\n");
+
+ fprintf(out, "#include <mutex>\n");
+ fprintf(out, "#include <chrono>\n");
+ fprintf(out, "#include <thread>\n");
+ fprintf(out, "#ifdef __ANDROID__\n");
+ fprintf(out, "#include <cutils/properties.h>\n");
+ fprintf(out, "#endif\n");
+ fprintf(out, "#include <stats_event_list.h>\n");
+ fprintf(out, "#include <log/log.h>\n");
+ fprintf(out, "#include <%s>\n", importHeader.c_str());
+ fprintf(out, "#include <utils/SystemClock.h>\n");
+ fprintf(out, "\n");
+
+ write_namespace(out, cppNamespace);
+ fprintf(out, "// the single event tag id for all stats logs\n");
+ fprintf(out, "const static int kStatsEventTag = 1937006964;\n");
+ fprintf(out, "#ifdef __ANDROID__\n");
+ fprintf(out, "const static bool kStatsdEnabled = property_get_bool(\"ro.statsd.enable\", true);\n");
+ fprintf(out, "#else\n");
+ fprintf(out, "const static bool kStatsdEnabled = false;\n");
+ fprintf(out, "#endif\n");
+
+ // AtomsInfo is only used by statsd internally and is not needed for other modules.
+ if (moduleName == DEFAULT_MODULE_NAME) {
+ write_atoms_info_cpp(out, atoms);
+ }
fprintf(out, "int64_t lastRetryTimestampNs = -1;\n");
fprintf(out, "const int64_t kMinRetryIntervalNs = NS_PER_SEC * 60 * 20; // 20 minutes\n");
@@ -251,15 +294,19 @@
// Print write methods
fprintf(out, "\n");
- for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
- signature != atoms.signatures.end(); signature++) {
+ for (auto signature_to_modules_it = atoms.signatures_to_modules.begin();
+ signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) {
+ if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
+ continue;
+ }
+ vector<java_type_t> signature = signature_to_modules_it->first;
int argIndex;
fprintf(out, "int\n");
fprintf(out, "try_stats_write(int32_t code");
argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature->begin();
- arg != signature->end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
for (auto chainField : attributionDecl.fields) {
if (chainField.javaType == JAVA_TYPE_STRING) {
@@ -285,8 +332,8 @@
fprintf(out, " stats_event_list event(kStatsEventTag);\n");
fprintf(out, " event << android::elapsedRealtimeNano();\n\n");
fprintf(out, " event << code;\n\n");
- for (vector<java_type_t>::const_iterator arg = signature->begin();
- arg != signature->end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
for (const auto &chainField : attributionDecl.fields) {
if (chainField.javaType == JAVA_TYPE_STRING) {
@@ -338,15 +385,19 @@
fprintf(out, "\n");
}
- for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
- signature != atoms.signatures.end(); signature++) {
+ for (auto signature_to_modules_it = atoms.signatures_to_modules.begin();
+ signature_to_modules_it != atoms.signatures_to_modules.end(); signature_to_modules_it++) {
+ if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
+ continue;
+ }
+ vector<java_type_t> signature = signature_to_modules_it->first;
int argIndex;
fprintf(out, "int \n");
fprintf(out, "stats_write(int32_t code");
argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature->begin();
- arg != signature->end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
for (auto chainField : attributionDecl.fields) {
if (chainField.javaType == JAVA_TYPE_STRING) {
@@ -373,8 +424,8 @@
fprintf(out, " ret = try_stats_write(code");
argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature->begin();
- arg != signature->end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
for (auto chainField : attributionDecl.fields) {
if (chainField.javaType == JAVA_TYPE_STRING) {
@@ -407,15 +458,19 @@
fprintf(out, "\n");
}
- for (set<vector<java_type_t>>::const_iterator signature = atoms.non_chained_signatures.begin();
- signature != atoms.non_chained_signatures.end(); signature++) {
+ for (auto signature_it = atoms.non_chained_signatures_to_modules.begin();
+ signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) {
+ if (!signature_needed_for_module(signature_it->second, moduleName)) {
+ continue;
+ }
+ vector<java_type_t> signature = signature_it->first;
int argIndex;
fprintf(out, "int\n");
fprintf(out, "try_stats_write_non_chained(int32_t code");
argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature->begin();
- arg != signature->end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
argIndex++;
}
@@ -427,8 +482,8 @@
fprintf(out, " stats_event_list event(kStatsEventTag);\n");
fprintf(out, " event << android::elapsedRealtimeNano();\n\n");
fprintf(out, " event << code;\n\n");
- for (vector<java_type_t>::const_iterator arg = signature->begin();
- arg != signature->end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
if (argIndex == 1) {
fprintf(out, " event.begin();\n\n");
fprintf(out, " event.begin();\n");
@@ -461,15 +516,19 @@
fprintf(out, "\n");
}
- for (set<vector<java_type_t>>::const_iterator signature = atoms.non_chained_signatures.begin();
- signature != atoms.non_chained_signatures.end(); signature++) {
+ for (auto signature_it = atoms.non_chained_signatures_to_modules.begin();
+ signature_it != atoms.non_chained_signatures_to_modules.end(); signature_it++) {
+ if (!signature_needed_for_module(signature_it->second, moduleName)) {
+ continue;
+ }
+ vector<java_type_t> signature = signature_it->first;
int argIndex;
fprintf(out, "int\n");
fprintf(out, "stats_write_non_chained(int32_t code");
argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature->begin();
- arg != signature->end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
fprintf(out, ", %s arg%d", cpp_type_name(*arg), argIndex);
argIndex++;
}
@@ -482,8 +541,8 @@
fprintf(out, " ret = try_stats_write_non_chained(code");
argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature->begin();
- arg != signature->end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
fprintf(out, ", arg%d", argIndex);
argIndex++;
}
@@ -508,8 +567,7 @@
// Print footer
fprintf(out, "\n");
- fprintf(out, "} // namespace util\n");
- fprintf(out, "} // namespace android\n");
+ write_closing_namespace(out, cppNamespace);
return 0;
}
@@ -550,14 +608,23 @@
}
static void write_cpp_method_header(
- FILE* out, const string& method_name, const set<vector<java_type_t>>& signatures,
- const AtomDecl &attributionDecl) {
- for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
- signature != signatures.end(); signature++) {
- fprintf(out, "int %s(int32_t code ", method_name.c_str());
+ FILE* out,
+ const string& method_name,
+ const map<vector<java_type_t>, set<string>>& signatures_to_modules,
+ const AtomDecl &attributionDecl, const string& moduleName) {
+
+ for (auto signature_to_modules_it = signatures_to_modules.begin();
+ signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
+ // Skip if this signature is not needed for the module.
+ if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
+ continue;
+ }
+
+ vector<java_type_t> signature = signature_to_modules_it->first;
+ fprintf(out, "int %s(int32_t code", method_name.c_str());
int argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature->begin();
- arg != signature->end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
for (auto chainField : attributionDecl.fields) {
if (chainField.javaType == JAVA_TYPE_STRING) {
@@ -580,7 +647,8 @@
}
static int
-write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
+write_stats_log_header(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
+ const string& moduleName, const string& cppNamespace)
{
// Print prelude
fprintf(out, "// This file is autogenerated\n");
@@ -593,8 +661,7 @@
fprintf(out, "#include <set>\n");
fprintf(out, "\n");
- fprintf(out, "namespace android {\n");
- fprintf(out, "namespace util {\n");
+ write_namespace(out, cppNamespace);
fprintf(out, "\n");
fprintf(out, "/*\n");
fprintf(out, " * API For logging statistics events.\n");
@@ -612,6 +679,10 @@
// Print constants
for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
atom != atoms.decls.end(); atom++) {
+ // Skip if the atom is not needed for the module.
+ if (!atom_needed_for_module(*atom, moduleName)) {
+ continue;
+ }
string constant = make_constant_name(atom->name);
fprintf(out, "\n");
fprintf(out, " /**\n");
@@ -644,45 +715,49 @@
fprintf(out, "};\n");
fprintf(out, "\n");
- fprintf(out, "struct StateAtomFieldOptions {\n");
- fprintf(out, " std::vector<int> primaryFields;\n");
- fprintf(out, " int exclusiveField;\n");
- fprintf(out, "};\n");
- fprintf(out, "\n");
+ // This metadata is only used by statsd, which uses the default libstatslog.
+ if (moduleName == DEFAULT_MODULE_NAME) {
- fprintf(out, "struct AtomsInfo {\n");
- fprintf(out,
- " const static std::set<int> "
- "kNotTruncatingTimestampAtomWhiteList;\n");
- fprintf(out, " const static std::map<int, int> kAtomsWithUidField;\n");
- fprintf(out,
- " const static std::set<int> kAtomsWithAttributionChain;\n");
- fprintf(out,
- " const static std::map<int, StateAtomFieldOptions> "
- "kStateAtomsFieldOptions;\n");
- fprintf(out,
- " const static std::map<int, std::vector<int>> "
- "kBytesFieldAtoms;");
- fprintf(out, "};\n");
+ fprintf(out, "struct StateAtomFieldOptions {\n");
+ fprintf(out, " std::vector<int> primaryFields;\n");
+ fprintf(out, " int exclusiveField;\n");
+ fprintf(out, "};\n");
+ fprintf(out, "\n");
- fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n",
- maxPushedAtomId);
+ fprintf(out, "struct AtomsInfo {\n");
+ fprintf(out,
+ " const static std::set<int> "
+ "kNotTruncatingTimestampAtomWhiteList;\n");
+ fprintf(out, " const static std::map<int, int> kAtomsWithUidField;\n");
+ fprintf(out,
+ " const static std::set<int> kAtomsWithAttributionChain;\n");
+ fprintf(out,
+ " const static std::map<int, StateAtomFieldOptions> "
+ "kStateAtomsFieldOptions;\n");
+ fprintf(out,
+ " const static std::map<int, std::vector<int>> "
+ "kBytesFieldAtoms;");
+ fprintf(out, "};\n");
+
+ fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n",
+ maxPushedAtomId);
+ }
// Print write methods
fprintf(out, "//\n");
fprintf(out, "// Write methods\n");
fprintf(out, "//\n");
- write_cpp_method_header(out, "stats_write", atoms.signatures, attributionDecl);
+ write_cpp_method_header(out, "stats_write", atoms.signatures_to_modules, attributionDecl,
+ moduleName);
fprintf(out, "//\n");
fprintf(out, "// Write flattened methods\n");
fprintf(out, "//\n");
- write_cpp_method_header(out, "stats_write_non_chained", atoms.non_chained_signatures,
- attributionDecl);
+ write_cpp_method_header(out, "stats_write_non_chained", atoms.non_chained_signatures_to_modules,
+ attributionDecl, moduleName);
fprintf(out, "\n");
- fprintf(out, "} // namespace util\n");
- fprintf(out, "} // namespace android\n");
+ write_closing_namespace(out, cppNamespace);
return 0;
}
@@ -705,15 +780,19 @@
}
static void write_java_method(
- FILE* out, const string& method_name, const set<vector<java_type_t>>& signatures,
- const AtomDecl &attributionDecl) {
- for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
- signature != signatures.end(); signature++) {
+ FILE* out,
+ const string& method_name,
+ const map<vector<java_type_t>, set<string>>& signatures_to_modules,
+ const AtomDecl &attributionDecl) {
+
+ for (auto signature_to_modules_it = signatures_to_modules.begin();
+ signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
+ vector<java_type_t> signature = signature_to_modules_it->first;
fprintf(out, " /** @hide */\n");
fprintf(out, " public static native int %s(int code", method_name.c_str());
int argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature->begin();
- arg != signature->end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
for (auto chainField : attributionDecl.fields) {
fprintf(out, ", %s[] %s",
@@ -728,15 +807,17 @@
}
}
-static void write_java_work_source_method(FILE* out, const set<vector<java_type_t>>& signatures) {
+static void write_java_work_source_method(FILE* out,
+ const map<vector<java_type_t>, set<string>>& signatures_to_modules) {
fprintf(out, "\n // WorkSource methods.\n");
- for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
- signature != signatures.end(); signature++) {
+ for (auto signature_to_modules_it = signatures_to_modules.begin();
+ signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
+ vector<java_type_t> signature = signature_to_modules_it->first;
// Determine if there is Attribution in this signature.
int attributionArg = -1;
int argIndexMax = 0;
- for (vector<java_type_t>::const_iterator arg = signature->begin();
- arg != signature->end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
argIndexMax++;
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
if (attributionArg > -1) {
@@ -756,8 +837,8 @@
fprintf(out, " /** @hide */\n");
fprintf(out, " public static void write(int code");
int argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature->begin();
- arg != signature->end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
fprintf(out, ", WorkSource ws");
} else {
@@ -864,9 +945,10 @@
// Print write methods
fprintf(out, " // Write methods\n");
- write_java_method(out, "write", atoms.signatures, attributionDecl);
- write_java_method(out, "write_non_chained", atoms.non_chained_signatures, attributionDecl);
- write_java_work_source_method(out, atoms.signatures);
+ write_java_method(out, "write", atoms.signatures_to_modules, attributionDecl);
+ write_java_method(out, "write_non_chained", atoms.non_chained_signatures_to_modules,
+ attributionDecl);
+ write_java_work_source_method(out, atoms.signatures_to_modules);
fprintf(out, "}\n");
@@ -995,19 +1077,20 @@
static int
write_stats_log_jni(FILE* out, const string& java_method_name, const string& cpp_method_name,
- const set<vector<java_type_t>>& signatures, const AtomDecl &attributionDecl)
-{
+ const map<vector<java_type_t>, set<string>>& signatures_to_modules,
+ const AtomDecl &attributionDecl) {
// Print write methods
- for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
- signature != signatures.end(); signature++) {
+ for (auto signature_to_modules_it = signatures_to_modules.begin();
+ signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
+ vector<java_type_t> signature = signature_to_modules_it->first;
int argIndex;
fprintf(out, "static int\n");
fprintf(out, "%s(JNIEnv* env, jobject clazz UNUSED, jint code",
- jni_function_name(java_method_name, *signature).c_str());
+ jni_function_name(java_method_name, signature).c_str());
argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature->begin();
- arg != signature->end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
for (auto chainField : attributionDecl.fields) {
fprintf(out, ", %s %s", jni_array_type_name(chainField.javaType),
@@ -1025,8 +1108,8 @@
// Prepare strings
argIndex = 1;
bool hadStringOrChain = false;
- for (vector<java_type_t>::const_iterator arg = signature->begin();
- arg != signature->end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
if (*arg == JAVA_TYPE_STRING) {
hadStringOrChain = true;
fprintf(out, " const char* str%d;\n", argIndex);
@@ -1121,8 +1204,8 @@
argIndex = 1;
fprintf(out, "\n int ret = android::util::%s(code",
cpp_method_name.c_str());
- for (vector<java_type_t>::const_iterator arg = signature->begin();
- arg != signature->end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
for (auto chainField : attributionDecl.fields) {
if (chainField.javaType == JAVA_TYPE_INT) {
@@ -1147,8 +1230,8 @@
// Clean up strings
argIndex = 1;
- for (vector<java_type_t>::const_iterator arg = signature->begin();
- arg != signature->end(); arg++) {
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
if (*arg == JAVA_TYPE_STRING) {
fprintf(out, " if (str%d != NULL) {\n", argIndex);
fprintf(out, " env->ReleaseStringUTFChars(arg%d, str%d);\n",
@@ -1187,13 +1270,15 @@
}
void write_jni_registration(FILE* out, const string& java_method_name,
- const set<vector<java_type_t>>& signatures, const AtomDecl &attributionDecl) {
- for (set<vector<java_type_t>>::const_iterator signature = signatures.begin();
- signature != signatures.end(); signature++) {
+ const map<vector<java_type_t>, set<string>>& signatures_to_modules,
+ const AtomDecl &attributionDecl) {
+ for (auto signature_to_modules_it = signatures_to_modules.begin();
+ signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
+ vector<java_type_t> signature = signature_to_modules_it->first;
fprintf(out, " { \"%s\", \"%s\", (void*)%s },\n",
java_method_name.c_str(),
- jni_function_signature(*signature, attributionDecl).c_str(),
- jni_function_name(java_method_name, *signature).c_str());
+ jni_function_signature(signature, attributionDecl).c_str(),
+ jni_function_name(java_method_name, signature).c_str());
}
}
@@ -1218,17 +1303,18 @@
fprintf(out, "namespace android {\n");
fprintf(out, "\n");
- write_stats_log_jni(out, "write", "stats_write", atoms.signatures, attributionDecl);
+ write_stats_log_jni(out, "write", "stats_write", atoms.signatures_to_modules, attributionDecl);
write_stats_log_jni(out, "write_non_chained", "stats_write_non_chained",
- atoms.non_chained_signatures, attributionDecl);
+ atoms.non_chained_signatures_to_modules, attributionDecl);
// Print registration function table
fprintf(out, "/*\n");
fprintf(out, " * JNI registration.\n");
fprintf(out, " */\n");
fprintf(out, "static const JNINativeMethod gRegisterMethods[] = {\n");
- write_jni_registration(out, "write", atoms.signatures, attributionDecl);
- write_jni_registration(out, "write_non_chained", atoms.non_chained_signatures, attributionDecl);
+ write_jni_registration(out, "write", atoms.signatures_to_modules, attributionDecl);
+ write_jni_registration(out, "write_non_chained", atoms.non_chained_signatures_to_modules,
+ attributionDecl);
fprintf(out, "};\n");
fprintf(out, "\n");
@@ -1256,6 +1342,10 @@
fprintf(stderr, " --help this message\n");
fprintf(stderr, " --java FILENAME the java file to output\n");
fprintf(stderr, " --jni FILENAME the jni file to output\n");
+ fprintf(stderr, " --module NAME optional, module name to generate outputs for\n");
+ fprintf(stderr, " --namespace COMMA,SEP,NAMESPACE required for cpp/header with module\n");
+ fprintf(stderr, " comma separated namespace of the files\n");
+ fprintf(stderr, " --importHeader NAME required for cpp/jni to say which header to import\n");
}
/**
@@ -1269,6 +1359,10 @@
string javaFilename;
string jniFilename;
+ string moduleName = DEFAULT_MODULE_NAME;
+ string cppNamespace = DEFAULT_CPP_NAMESPACE;
+ string cppHeaderImport = DEFAULT_CPP_HEADER_IMPORT;
+
int index = 1;
while (index < argc) {
if (0 == strcmp("--help", argv[index])) {
@@ -1302,6 +1396,27 @@
return 1;
}
jniFilename = argv[index];
+ } else if (0 == strcmp("--module", argv[index])) {
+ index++;
+ if (index >= argc) {
+ print_usage();
+ return 1;
+ }
+ moduleName = argv[index];
+ } else if (0 == strcmp("--namespace", argv[index])) {
+ index++;
+ if (index >= argc) {
+ print_usage();
+ return 1;
+ }
+ cppNamespace = argv[index];
+ } else if (0 == strcmp("--importHeader", argv[index])) {
+ index++;
+ if (index >= argc) {
+ print_usage();
+ return 1;
+ }
+ cppHeaderImport = argv[index];
}
index++;
}
@@ -1333,8 +1448,18 @@
fprintf(stderr, "Unable to open file for write: %s\n", cppFilename.c_str());
return 1;
}
+ // If this is for a specific module, the namespace must also be provided.
+ if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) {
+ fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
+ return 1;
+ }
+ // If this is for a specific module, the header file to import must also be provided.
+ if (moduleName != DEFAULT_MODULE_NAME && cppHeaderImport == DEFAULT_CPP_HEADER_IMPORT) {
+ fprintf(stderr, "Must supply --headerImport if supplying a specific module\n");
+ return 1;
+ }
errorCount = android::stats_log_api_gen::write_stats_log_cpp(
- out, atoms, attributionDecl);
+ out, atoms, attributionDecl, moduleName, cppNamespace, cppHeaderImport);
fclose(out);
}
@@ -1345,8 +1470,12 @@
fprintf(stderr, "Unable to open file for write: %s\n", headerFilename.c_str());
return 1;
}
+ // If this is for a specific module, the namespace must also be provided.
+ if (moduleName != DEFAULT_MODULE_NAME && cppNamespace == DEFAULT_CPP_NAMESPACE) {
+ fprintf(stderr, "Must supply --namespace if supplying a specific module\n");
+ }
errorCount = android::stats_log_api_gen::write_stats_log_header(
- out, atoms, attributionDecl);
+ out, atoms, attributionDecl, moduleName, cppNamespace);
fclose(out);
}
diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto
index 188b765..6922e9c 100644
--- a/tools/stats_log_api_gen/test.proto
+++ b/tools/stats_log_api_gen/test.proto
@@ -195,4 +195,24 @@
[(android.os.statsd.stateFieldOption).option = PRIMARY];
optional int32 state = 3
[(android.os.statsd.stateFieldOption).option = EXCLUSIVE];
-}
\ No newline at end of file
+}
+
+message ModuleOneAtom {
+ optional int32 field = 1;
+}
+
+message ModuleTwoAtom {
+ optional int32 field = 1;
+}
+
+message NoModuleAtom {
+ optional string field = 1;
+}
+
+message ModuleAtoms {
+ oneof event {
+ ModuleOneAtom module_one_atom = 1 [(android.os.statsd.log_from_module) = "module1"];
+ ModuleTwoAtom module_two_atom = 2 [(android.os.statsd.log_from_module) = "module2"];
+ NoModuleAtom no_module_atom = 3;
+ }
+}
diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp
index ad3bffac..f59bb6f 100644
--- a/tools/stats_log_api_gen/test_collation.cpp
+++ b/tools/stats_log_api_gen/test_collation.cpp
@@ -32,7 +32,7 @@
* Return whether the set contains a vector of the elements provided.
*/
static bool
-set_contains_vector(const set<vector<java_type_t>>& s, int count, ...)
+set_contains_vector(const map<vector<java_type_t>, set<string>>& s, int count, ...)
{
va_list args;
vector<java_type_t> v;
@@ -86,17 +86,17 @@
int errorCount = collate_atoms(Event::descriptor(), &atoms);
EXPECT_EQ(0, errorCount);
- EXPECT_EQ(3ul, atoms.signatures.size());
+ EXPECT_EQ(3ul, atoms.signatures_to_modules.size());
// IntAtom, AnotherIntAtom
- EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures, JAVA_TYPE_INT);
+ EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures_to_modules, JAVA_TYPE_INT);
// OutOfOrderAtom
- EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures, JAVA_TYPE_INT, JAVA_TYPE_INT);
+ EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures_to_modules, JAVA_TYPE_INT, JAVA_TYPE_INT);
// AllTypesAtom
EXPECT_SET_CONTAINS_SIGNATURE(
- atoms.signatures,
+ atoms.signatures_to_modules,
JAVA_TYPE_ATTRIBUTION_CHAIN, // AttributionChain
JAVA_TYPE_DOUBLE, // double
JAVA_TYPE_FLOAT, // float
@@ -226,5 +226,46 @@
EXPECT_TRUE(errorCount > 0);
}
+TEST(CollationTest, PassOnLogFromModuleAtom) {
+ Atoms atoms;
+ int errorCount = collate_atoms(ModuleAtoms::descriptor(), &atoms);
+ EXPECT_EQ(errorCount, 0);
+ EXPECT_EQ(atoms.decls.size(), 3ul);
+}
+
+TEST(CollationTest, RecognizeModuleAtom) {
+ Atoms atoms;
+ int errorCount = collate_atoms(ModuleAtoms::descriptor(), &atoms);
+ EXPECT_EQ(errorCount, 0);
+ EXPECT_EQ(atoms.decls.size(), 3ul);
+ for (const auto& atomDecl: atoms.decls) {
+ if (atomDecl.code == 1) {
+ EXPECT_TRUE(atomDecl.hasModule);
+ EXPECT_EQ(atomDecl.moduleName, "module1");
+ } else if (atomDecl.code == 2) {
+ EXPECT_TRUE(atomDecl.hasModule);
+ EXPECT_EQ(atomDecl.moduleName, "module2");
+ } else {
+ EXPECT_FALSE(atomDecl.hasModule);
+ }
+ }
+
+ EXPECT_EQ(atoms.signatures_to_modules.size(), 2u);
+ EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures_to_modules, JAVA_TYPE_INT);
+ EXPECT_SET_CONTAINS_SIGNATURE(atoms.signatures_to_modules, JAVA_TYPE_STRING);
+ for (auto signature_to_modules_it : atoms.signatures_to_modules) {
+ vector<java_type_t> signature = signature_to_modules_it.first;
+ if (signature[0] == JAVA_TYPE_STRING) {
+ EXPECT_EQ(signature_to_modules_it.second.size(), 0u);
+ } else if (signature[0] == JAVA_TYPE_INT) {
+ set<string> modules = signature_to_modules_it.second;
+ EXPECT_EQ(modules.size(), 2u);
+ // Assert that the set contains "module1" and "module2".
+ EXPECT_NE(modules.find("module1"), modules.end());
+ EXPECT_NE(modules.find("module2"), modules.end());
+ }
+ }
+}
+
} // namespace stats_log_api_gen
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/tools/streaming_proto/Android.bp b/tools/streaming_proto/Android.bp
index 1121ead..14eead8 100644
--- a/tools/streaming_proto/Android.bp
+++ b/tools/streaming_proto/Android.bp
@@ -49,3 +49,18 @@
defaults: ["protoc-gen-stream-defaults"],
}
+
+// ==========================================================
+// Build the java test
+// ==========================================================
+java_library {
+ name: "StreamingProtoTest",
+ srcs: [
+ "test/**/*.java",
+ "test/**/*.proto",
+ ],
+ proto: {
+ plugin: "javastream",
+ },
+ static_libs: ["libprotobuf-java-lite"],
+}
diff --git a/tools/streaming_proto/Android.mk b/tools/streaming_proto/Android.mk
deleted file mode 100644
index ebb77a1..0000000
--- a/tools/streaming_proto/Android.mk
+++ /dev/null
@@ -1,28 +0,0 @@
-#
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-LOCAL_PATH:= $(call my-dir)
-
-# ==========================================================
-# Build the java test
-# ==========================================================
-include $(CLEAR_VARS)
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, test) \
- $(call all-proto-files-under, test)
-LOCAL_MODULE := StreamingProtoTest
-LOCAL_PROTOC_OPTIMIZE_TYPE := stream
-include $(BUILD_JAVA_LIBRARY)
-