diff options
300 files changed, 9531 insertions, 2349 deletions
diff --git a/Android.bp b/Android.bp index 3f1fc4d8a65e..3046b20c7096 100644 --- a/Android.bp +++ b/Android.bp @@ -53,6 +53,7 @@ filegroup { "core/java/android/view/DisplayAdjustments.java", ], path: "core/java", + visibility: ["//frameworks/base/test-mock"], } filegroup { @@ -73,6 +74,14 @@ filegroup { } filegroup { + name: "framework-identity-sources", + srcs: [ + "identity/java/**/*.java", + ], + path: "identity/java", +} + +filegroup { name: "framework-keystore-sources", srcs: [ "keystore/java/**/*.java", @@ -216,6 +225,7 @@ filegroup { ":framework-drm-sources", ":framework-graphics-sources", ":framework-keystore-sources", + ":framework-identity-sources", ":framework-location-sources", ":framework-lowpan-sources", ":framework-media-sources", @@ -238,6 +248,7 @@ filegroup { ":platform-compat-native-aidl", // AIDL sources from external directories + ":credstore_aidl", ":dumpstate_aidl", ":framework_native_aidl", ":gatekeeper_aidl", @@ -289,6 +300,7 @@ java_defaults { "core/java", "drm/java", "graphics/java", + "identity/java", "keystore/java", "location/java", "lowpan/java", @@ -595,6 +607,7 @@ filegroup { name: "framework-ike-shared-srcs", visibility: ["//frameworks/opt/net/ike"], srcs: [ + "core/java/android/annotation/StringDef.java", "core/java/android/net/annotations/PolicyDirection.java", "core/java/com/android/internal/util/IState.java", "core/java/com/android/internal/util/State.java", @@ -1025,6 +1038,7 @@ filegroup { "core/java/android/util/TimeUtils.java", "core/java/com/android/internal/os/SomeArgs.java", "core/java/com/android/internal/util/AsyncChannel.java", + "core/java/com/android/internal/util/AsyncService.java", "core/java/com/android/internal/util/BitwiseInputStream.java", "core/java/com/android/internal/util/FastXmlSerializer.java", "core/java/com/android/internal/util/HexDump.java", diff --git a/api/current.txt b/api/current.txt index bdb0c8ac486d..0e517e67c151 100644 --- a/api/current.txt +++ b/api/current.txt @@ -16637,7 +16637,9 @@ package android.hardware.biometrics { ctor public BiometricPrompt.CryptoObject(@NonNull java.security.Signature); ctor public BiometricPrompt.CryptoObject(@NonNull javax.crypto.Cipher); ctor public BiometricPrompt.CryptoObject(@NonNull javax.crypto.Mac); + ctor public BiometricPrompt.CryptoObject(@NonNull android.security.identity.IdentityCredential); method public javax.crypto.Cipher getCipher(); + method @Nullable public android.security.identity.IdentityCredential getIdentityCredential(); method public javax.crypto.Mac getMac(); method public java.security.Signature getSignature(); } @@ -17575,7 +17577,9 @@ package android.hardware.fingerprint { ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull java.security.Signature); ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull javax.crypto.Cipher); ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull javax.crypto.Mac); + ctor @Deprecated public FingerprintManager.CryptoObject(@NonNull android.security.identity.IdentityCredential); method @Deprecated public javax.crypto.Cipher getCipher(); + method @Deprecated @Nullable public android.security.identity.IdentityCredential getIdentityCredential(); method @Deprecated public javax.crypto.Mac getMac(); method @Deprecated public java.security.Signature getSignature(); } @@ -17964,6 +17968,7 @@ package android.icu.lang { field public static final int RIGHT = 7; // 0x7 field public static final int TOP = 8; // 0x8 field public static final int TOP_AND_BOTTOM = 9; // 0x9 + field public static final int TOP_AND_BOTTOM_AND_LEFT = 15; // 0xf field public static final int TOP_AND_BOTTOM_AND_RIGHT = 10; // 0xa field public static final int TOP_AND_LEFT = 11; // 0xb field public static final int TOP_AND_LEFT_AND_RIGHT = 12; // 0xc @@ -18286,6 +18291,8 @@ package android.icu.lang { field public static final int CHEROKEE_SUPPLEMENT_ID = 255; // 0xff field public static final android.icu.lang.UCharacter.UnicodeBlock CHESS_SYMBOLS; field public static final int CHESS_SYMBOLS_ID = 281; // 0x119 + field public static final android.icu.lang.UCharacter.UnicodeBlock CHORASMIAN; + field public static final int CHORASMIAN_ID = 301; // 0x12d field public static final android.icu.lang.UCharacter.UnicodeBlock CJK_COMPATIBILITY; field public static final android.icu.lang.UCharacter.UnicodeBlock CJK_COMPATIBILITY_FORMS; field public static final int CJK_COMPATIBILITY_FORMS_ID = 83; // 0x53 @@ -18313,6 +18320,8 @@ package android.icu.lang { field public static final int CJK_UNIFIED_IDEOGRAPHS_EXTENSION_E_ID = 256; // 0x100 field public static final android.icu.lang.UCharacter.UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_F; field public static final int CJK_UNIFIED_IDEOGRAPHS_EXTENSION_F_ID = 274; // 0x112 + field public static final android.icu.lang.UCharacter.UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_G; + field public static final int CJK_UNIFIED_IDEOGRAPHS_EXTENSION_G_ID = 302; // 0x12e field public static final int CJK_UNIFIED_IDEOGRAPHS_ID = 71; // 0x47 field public static final android.icu.lang.UCharacter.UnicodeBlock COMBINING_DIACRITICAL_MARKS; field public static final android.icu.lang.UCharacter.UnicodeBlock COMBINING_DIACRITICAL_MARKS_EXTENDED; @@ -18362,6 +18371,8 @@ package android.icu.lang { field public static final int DEVANAGARI_ID = 15; // 0xf field public static final android.icu.lang.UCharacter.UnicodeBlock DINGBATS; field public static final int DINGBATS_ID = 56; // 0x38 + field public static final android.icu.lang.UCharacter.UnicodeBlock DIVES_AKURU; + field public static final int DIVES_AKURU_ID = 303; // 0x12f field public static final android.icu.lang.UCharacter.UnicodeBlock DOGRA; field public static final int DOGRA_ID = 282; // 0x11a field public static final android.icu.lang.UCharacter.UnicodeBlock DOMINO_TILES; @@ -18490,6 +18501,8 @@ package android.icu.lang { field public static final int KAYAH_LI_ID = 162; // 0xa2 field public static final android.icu.lang.UCharacter.UnicodeBlock KHAROSHTHI; field public static final int KHAROSHTHI_ID = 137; // 0x89 + field public static final android.icu.lang.UCharacter.UnicodeBlock KHITAN_SMALL_SCRIPT; + field public static final int KHITAN_SMALL_SCRIPT_ID = 304; // 0x130 field public static final android.icu.lang.UCharacter.UnicodeBlock KHMER; field public static final int KHMER_ID = 36; // 0x24 field public static final android.icu.lang.UCharacter.UnicodeBlock KHMER_SYMBOLS; @@ -18528,6 +18541,8 @@ package android.icu.lang { field public static final int LINEAR_B_SYLLABARY_ID = 117; // 0x75 field public static final android.icu.lang.UCharacter.UnicodeBlock LISU; field public static final int LISU_ID = 176; // 0xb0 + field public static final android.icu.lang.UCharacter.UnicodeBlock LISU_SUPPLEMENT; + field public static final int LISU_SUPPLEMENT_ID = 305; // 0x131 field public static final android.icu.lang.UCharacter.UnicodeBlock LOW_SURROGATES; field public static final int LOW_SURROGATES_ID = 77; // 0x4d field public static final android.icu.lang.UCharacter.UnicodeBlock LYCIAN; @@ -18739,6 +18754,8 @@ package android.icu.lang { field public static final int SYLOTI_NAGRI_ID = 143; // 0x8f field public static final android.icu.lang.UCharacter.UnicodeBlock SYMBOLS_AND_PICTOGRAPHS_EXTENDED_A; field public static final int SYMBOLS_AND_PICTOGRAPHS_EXTENDED_A_ID = 298; // 0x12a + field public static final android.icu.lang.UCharacter.UnicodeBlock SYMBOLS_FOR_LEGACY_COMPUTING; + field public static final int SYMBOLS_FOR_LEGACY_COMPUTING_ID = 306; // 0x132 field public static final android.icu.lang.UCharacter.UnicodeBlock SYRIAC; field public static final int SYRIAC_ID = 13; // 0xd field public static final android.icu.lang.UCharacter.UnicodeBlock SYRIAC_SUPPLEMENT; @@ -18767,6 +18784,8 @@ package android.icu.lang { field public static final android.icu.lang.UCharacter.UnicodeBlock TANGUT_COMPONENTS; field public static final int TANGUT_COMPONENTS_ID = 273; // 0x111 field public static final int TANGUT_ID = 272; // 0x110 + field public static final android.icu.lang.UCharacter.UnicodeBlock TANGUT_SUPPLEMENT; + field public static final int TANGUT_SUPPLEMENT_ID = 307; // 0x133 field public static final android.icu.lang.UCharacter.UnicodeBlock TELUGU; field public static final int TELUGU_ID = 21; // 0x15 field public static final android.icu.lang.UCharacter.UnicodeBlock THAANA; @@ -18801,6 +18820,8 @@ package android.icu.lang { field public static final int WANCHO_ID = 300; // 0x12c field public static final android.icu.lang.UCharacter.UnicodeBlock WARANG_CITI; field public static final int WARANG_CITI_ID = 252; // 0xfc + field public static final android.icu.lang.UCharacter.UnicodeBlock YEZIDI; + field public static final int YEZIDI_ID = 308; // 0x134 field public static final android.icu.lang.UCharacter.UnicodeBlock YIJING_HEXAGRAM_SYMBOLS; field public static final int YIJING_HEXAGRAM_SYMBOLS_ID = 116; // 0x74 field public static final android.icu.lang.UCharacter.UnicodeBlock YI_RADICALS; @@ -19097,6 +19118,7 @@ package android.icu.lang { field public static final int CHAKMA = 118; // 0x76 field public static final int CHAM = 66; // 0x42 field public static final int CHEROKEE = 6; // 0x6 + field public static final int CHORASMIAN = 189; // 0xbd field public static final int CIRTH = 67; // 0x43 field public static final int COMMON = 0; // 0x0 field public static final int COPTIC = 7; // 0x7 @@ -19106,6 +19128,7 @@ package android.icu.lang { field public static final int DEMOTIC_EGYPTIAN = 69; // 0x45 field public static final int DESERET = 9; // 0x9 field public static final int DEVANAGARI = 10; // 0xa + field public static final int DIVES_AKURU = 190; // 0xbe field public static final int DOGRA = 178; // 0xb2 field public static final int DUPLOYAN = 135; // 0x87 field public static final int EASTERN_SYRIAC = 97; // 0x61 @@ -19147,6 +19170,7 @@ package android.icu.lang { field public static final int KATAKANA_OR_HIRAGANA = 54; // 0x36 field public static final int KAYAH_LI = 79; // 0x4f field public static final int KHAROSHTHI = 57; // 0x39 + field public static final int KHITAN_SMALL_SCRIPT = 191; // 0xbf field public static final int KHMER = 23; // 0x17 field public static final int KHOJKI = 157; // 0x9d field public static final int KHUDAWADI = 145; // 0x91 @@ -19264,6 +19288,7 @@ package android.icu.lang { field public static final int WARANG_CITI = 146; // 0x92 field public static final int WESTERN_SYRIAC = 96; // 0x60 field public static final int WOLEAI = 155; // 0x9b + field public static final int YEZIDI = 192; // 0xc0 field public static final int YI = 41; // 0x29 field public static final int ZANABAZAR_SQUARE = 177; // 0xb1 } @@ -22519,6 +22544,7 @@ package android.icu.util { field public static final android.icu.util.VersionInfo UNICODE_11_0; field public static final android.icu.util.VersionInfo UNICODE_12_0; field public static final android.icu.util.VersionInfo UNICODE_12_1; + field public static final android.icu.util.VersionInfo UNICODE_13_0; field public static final android.icu.util.VersionInfo UNICODE_1_0; field public static final android.icu.util.VersionInfo UNICODE_1_0_1; field public static final android.icu.util.VersionInfo UNICODE_1_1_0; @@ -29167,7 +29193,7 @@ package android.net { method @NonNull public android.net.NetworkRequest.Builder clearCapabilities(); method public android.net.NetworkRequest.Builder removeCapability(int); method public android.net.NetworkRequest.Builder removeTransportType(int); - method public android.net.NetworkRequest.Builder setNetworkSpecifier(String); + method @Deprecated public android.net.NetworkRequest.Builder setNetworkSpecifier(String); method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier); } @@ -29266,6 +29292,19 @@ package android.net { method public void onStopped(); } + public final class TelephonyNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable { + method public int describeContents(); + method public int getSubscriptionId(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.net.TelephonyNetworkSpecifier> CREATOR; + } + + public static final class TelephonyNetworkSpecifier.Builder { + ctor public TelephonyNetworkSpecifier.Builder(); + method @NonNull public android.net.TelephonyNetworkSpecifier build(); + method @NonNull public android.net.TelephonyNetworkSpecifier.Builder setSubscriptionId(int); + } + public class TrafficStats { ctor public TrafficStats(); method public static void clearThreadStatsTag(); @@ -29679,6 +29718,7 @@ package android.net.sip { method public void close(); method public void continueCall(int) throws android.net.sip.SipException; method public void endCall() throws android.net.sip.SipException; + method @Nullable public android.net.rtp.AudioGroup getAudioGroup(); method public android.net.sip.SipProfile getLocalProfile(); method public android.net.sip.SipProfile getPeerProfile(); method public int getState(); @@ -29689,6 +29729,7 @@ package android.net.sip { method public void makeCall(android.net.sip.SipProfile, android.net.sip.SipSession, int) throws android.net.sip.SipException; method public void sendDtmf(int); method public void sendDtmf(int, android.os.Message); + method public void setAudioGroup(@NonNull android.net.rtp.AudioGroup); method public void setListener(android.net.sip.SipAudioCall.Listener); method public void setListener(android.net.sip.SipAudioCall.Listener, boolean); method public void setSpeakerMode(boolean); @@ -29737,6 +29778,7 @@ package android.net.sip { method public void close(String) throws android.net.sip.SipException; method public android.net.sip.SipSession createSipSession(android.net.sip.SipProfile, android.net.sip.SipSession.Listener) throws android.net.sip.SipException; method public static String getCallId(android.content.Intent); + method @NonNull public java.util.List<android.net.sip.SipProfile> getListOfProfiles() throws android.net.sip.SipException; method public static String getOfferSessionDescription(android.content.Intent); method public android.net.sip.SipSession getSessionFor(android.content.Intent) throws android.net.sip.SipException; method public static boolean isApiSupported(android.content.Context); @@ -29754,6 +29796,11 @@ package android.net.sip { method public void setRegistrationListener(String, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException; method public android.net.sip.SipAudioCall takeAudioCall(android.content.Intent, android.net.sip.SipAudioCall.Listener) throws android.net.sip.SipException; method public void unregister(android.net.sip.SipProfile, android.net.sip.SipRegistrationListener) throws android.net.sip.SipException; + field public static final String ACTION_SIP_CALL_OPTION_CHANGED = "android.net.sip.action.SIP_CALL_OPTION_CHANGED"; + field public static final String ACTION_SIP_INCOMING_CALL = "android.net.sip.action.SIP_INCOMING_CALL"; + field public static final String ACTION_SIP_REMOVE_PROFILE = "android.net.sip.action.SIP_REMOVE_PROFILE"; + field public static final String ACTION_SIP_SERVICE_UP = "android.net.sip.action.SIP_SERVICE_UP"; + field public static final String ACTION_START_SIP = "android.net.sip.action.START_SIP"; field public static final String EXTRA_CALL_ID = "android:sipCallID"; field public static final String EXTRA_OFFER_SD = "android:sipOfferSD"; field public static final int INCOMING_CALL_RESULT_CODE = 101; // 0x65 @@ -29763,6 +29810,7 @@ package android.net.sip { method public int describeContents(); method public String getAuthUserName(); method public boolean getAutoRegistration(); + method public int getCallingUid(); method public String getDisplayName(); method public String getPassword(); method public int getPort(); @@ -29773,6 +29821,7 @@ package android.net.sip { method public String getSipDomain(); method public String getUriString(); method public String getUserName(); + method public void setCallingUid(int); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator<android.net.sip.SipProfile> CREATOR; } @@ -40880,6 +40929,7 @@ package android.se.omapi { public final class SEService { ctor public SEService(@NonNull android.content.Context, @NonNull java.util.concurrent.Executor, @NonNull android.se.omapi.SEService.OnConnectedListener); method @NonNull public android.se.omapi.Reader[] getReaders(); + method @NonNull public android.se.omapi.Reader getUiccReader(int); method @NonNull public String getVersion(); method public boolean isConnected(); method public void shutdown(); @@ -41017,6 +41067,139 @@ package android.security { } +package android.security.identity { + + public class AccessControlProfile { + } + + public static final class AccessControlProfile.Builder { + ctor public AccessControlProfile.Builder(@NonNull android.security.identity.AccessControlProfileId); + method @NonNull public android.security.identity.AccessControlProfile build(); + method @NonNull public android.security.identity.AccessControlProfile.Builder setReaderCertificate(@NonNull java.security.cert.X509Certificate); + method @NonNull public android.security.identity.AccessControlProfile.Builder setUserAuthenticationRequired(boolean); + method @NonNull public android.security.identity.AccessControlProfile.Builder setUserAuthenticationTimeout(long); + } + + public class AccessControlProfileId { + ctor public AccessControlProfileId(int); + method public int getId(); + } + + public class AlreadyPersonalizedException extends android.security.identity.IdentityCredentialException { + ctor public AlreadyPersonalizedException(@NonNull String); + ctor public AlreadyPersonalizedException(@NonNull String, @NonNull Throwable); + } + + public class CipherSuiteNotSupportedException extends android.security.identity.IdentityCredentialException { + ctor public CipherSuiteNotSupportedException(@NonNull String); + ctor public CipherSuiteNotSupportedException(@NonNull String, @NonNull Throwable); + } + + public class DocTypeNotSupportedException extends android.security.identity.IdentityCredentialException { + ctor public DocTypeNotSupportedException(@NonNull String); + ctor public DocTypeNotSupportedException(@NonNull String, @NonNull Throwable); + } + + public class EphemeralPublicKeyNotFoundException extends android.security.identity.IdentityCredentialException { + ctor public EphemeralPublicKeyNotFoundException(@NonNull String); + ctor public EphemeralPublicKeyNotFoundException(@NonNull String, @NonNull Throwable); + } + + public abstract class IdentityCredential { + method @NonNull public abstract java.security.KeyPair createEphemeralKeyPair(); + method @NonNull public abstract byte[] decryptMessageFromReader(@NonNull byte[]) throws android.security.identity.MessageDecryptionException; + method @NonNull public abstract byte[] encryptMessageToReader(@NonNull byte[]); + method @NonNull public abstract java.util.Collection<java.security.cert.X509Certificate> getAuthKeysNeedingCertification(); + method @NonNull public abstract int[] getAuthenticationDataUsageCount(); + method @NonNull public abstract java.util.Collection<java.security.cert.X509Certificate> getCredentialKeyCertificateChain(); + method @NonNull public abstract android.security.identity.ResultData getEntries(@Nullable byte[], @NonNull java.util.Map<java.lang.String,java.util.Collection<java.lang.String>>, @Nullable byte[], @Nullable byte[]) throws android.security.identity.EphemeralPublicKeyNotFoundException, android.security.identity.InvalidReaderSignatureException, android.security.identity.InvalidRequestMessageException, android.security.identity.NoAuthenticationKeyAvailableException, android.security.identity.SessionTranscriptMismatchException; + method public abstract void setAllowUsingExhaustedKeys(boolean); + method public abstract void setAvailableAuthenticationKeys(int, int); + method public abstract void setReaderEphemeralPublicKey(@NonNull java.security.PublicKey) throws java.security.InvalidKeyException; + method public abstract void storeStaticAuthenticationData(@NonNull java.security.cert.X509Certificate, @NonNull byte[]) throws android.security.identity.UnknownAuthenticationKeyException; + } + + public class IdentityCredentialException extends java.lang.Exception { + ctor public IdentityCredentialException(@NonNull String); + ctor public IdentityCredentialException(@NonNull String, @NonNull Throwable); + } + + public abstract class IdentityCredentialStore { + method @NonNull public abstract android.security.identity.WritableIdentityCredential createCredential(@NonNull String, @NonNull String) throws android.security.identity.AlreadyPersonalizedException, android.security.identity.DocTypeNotSupportedException; + method @Nullable public abstract byte[] deleteCredentialByName(@NonNull String); + method @Nullable public abstract android.security.identity.IdentityCredential getCredentialByName(@NonNull String, int) throws android.security.identity.CipherSuiteNotSupportedException; + method @Nullable public static android.security.identity.IdentityCredentialStore getDirectAccessInstance(@NonNull android.content.Context); + method @Nullable public static android.security.identity.IdentityCredentialStore getInstance(@NonNull android.content.Context); + method @NonNull public abstract String[] getSupportedDocTypes(); + field public static final int CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256 = 1; // 0x1 + } + + public class InvalidReaderSignatureException extends android.security.identity.IdentityCredentialException { + ctor public InvalidReaderSignatureException(@NonNull String); + ctor public InvalidReaderSignatureException(@NonNull String, @NonNull Throwable); + } + + public class InvalidRequestMessageException extends android.security.identity.IdentityCredentialException { + ctor public InvalidRequestMessageException(@NonNull String); + ctor public InvalidRequestMessageException(@NonNull String, @NonNull Throwable); + } + + public class MessageDecryptionException extends android.security.identity.IdentityCredentialException { + ctor public MessageDecryptionException(@NonNull String); + ctor public MessageDecryptionException(@NonNull String, @NonNull Throwable); + } + + public class NoAuthenticationKeyAvailableException extends android.security.identity.IdentityCredentialException { + ctor public NoAuthenticationKeyAvailableException(@NonNull String); + ctor public NoAuthenticationKeyAvailableException(@NonNull String, @NonNull Throwable); + } + + public class PersonalizationData { + } + + public static final class PersonalizationData.Builder { + ctor public PersonalizationData.Builder(); + method @NonNull public android.security.identity.PersonalizationData.Builder addAccessControlProfile(@NonNull android.security.identity.AccessControlProfile); + method @NonNull public android.security.identity.PersonalizationData build(); + method @NonNull public android.security.identity.PersonalizationData.Builder setEntry(@NonNull String, @NonNull String, @NonNull java.util.Collection<android.security.identity.AccessControlProfileId>, @NonNull byte[]); + } + + public abstract class ResultData { + method @NonNull public abstract byte[] getAuthenticatedData(); + method @Nullable public abstract byte[] getEntry(@NonNull String, @NonNull String); + method @Nullable public abstract java.util.Collection<java.lang.String> getEntryNames(@NonNull String); + method @Nullable public abstract byte[] getMessageAuthenticationCode(); + method @NonNull public abstract java.util.Collection<java.lang.String> getNamespaceNames(); + method @Nullable public abstract java.util.Collection<java.lang.String> getRetrievedEntryNames(@NonNull String); + method @NonNull public abstract byte[] getStaticAuthenticationData(); + method public abstract int getStatus(@NonNull String, @NonNull String); + field public static final int STATUS_NOT_IN_REQUEST_MESSAGE = 3; // 0x3 + field public static final int STATUS_NOT_REQUESTED = 2; // 0x2 + field public static final int STATUS_NO_ACCESS_CONTROL_PROFILES = 6; // 0x6 + field public static final int STATUS_NO_SUCH_ENTRY = 1; // 0x1 + field public static final int STATUS_OK = 0; // 0x0 + field public static final int STATUS_READER_AUTHENTICATION_FAILED = 5; // 0x5 + field public static final int STATUS_USER_AUTHENTICATION_FAILED = 4; // 0x4 + } + + public class SessionTranscriptMismatchException extends android.security.identity.IdentityCredentialException { + ctor public SessionTranscriptMismatchException(@NonNull String); + ctor public SessionTranscriptMismatchException(@NonNull String, @NonNull Throwable); + } + + public class UnknownAuthenticationKeyException extends android.security.identity.IdentityCredentialException { + ctor public UnknownAuthenticationKeyException(@NonNull String); + ctor public UnknownAuthenticationKeyException(@NonNull String, @NonNull Throwable); + } + + public abstract class WritableIdentityCredential { + ctor public WritableIdentityCredential(); + method @NonNull public abstract java.util.Collection<java.security.cert.X509Certificate> getCredentialKeyCertificateChain(@NonNull byte[]); + method @NonNull public abstract byte[] personalize(@NonNull android.security.identity.PersonalizationData); + } + +} + package android.security.keystore { public class KeyExpiredException extends java.security.InvalidKeyException { @@ -43300,6 +43483,7 @@ package android.telecom { method public java.util.List<android.telecom.Call> getChildren(); method public java.util.List<android.telecom.Call> getConferenceableCalls(); method public android.telecom.Call.Details getDetails(); + method @Nullable public android.telecom.Call getGenericConferenceActiveChildCall(); method public android.telecom.Call getParent(); method public String getRemainingPostDialSequence(); method @Nullable public android.telecom.Call.RttCall getRttCall(); @@ -43383,6 +43567,7 @@ package android.telecom { method public int getCallerDisplayNamePresentation(); method public int getCallerNumberVerificationStatus(); method public final long getConnectTimeMillis(); + method @Nullable public String getContactDisplayName(); method public long getCreationTimeMillis(); method public android.telecom.DisconnectCause getDisconnectCause(); method public android.os.Bundle getExtras(); @@ -44229,6 +44414,8 @@ package android.telecom { package android.telephony { public final class AccessNetworkConstants { + field public static final int TRANSPORT_TYPE_WLAN = 2; // 0x2 + field public static final int TRANSPORT_TYPE_WWAN = 1; // 0x1 } public static final class AccessNetworkConstants.AccessNetworkType { @@ -44403,6 +44590,9 @@ package android.telephony { field public static final int DATA_CYCLE_USE_PLATFORM_DEFAULT = -1; // 0xffffffff field public static final String EXTRA_SLOT_INDEX = "android.telephony.extra.SLOT_INDEX"; field public static final String EXTRA_SUBSCRIPTION_INDEX = "android.telephony.extra.SUBSCRIPTION_INDEX"; + field public static final String IMSI_KEY_AVAILABILITY_INT = "imsi_key_availability_int"; + field public static final String KEY_5G_ICON_CONFIGURATION_STRING = "5g_icon_configuration_string"; + field public static final String KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT = "5g_icon_display_grace_period_sec_int"; field public static final String KEY_5G_NR_SSRSRP_THRESHOLDS_INT_ARRAY = "5g_nr_ssrsrp_thresholds_int_array"; field public static final String KEY_5G_NR_SSRSRQ_THRESHOLDS_INT_ARRAY = "5g_nr_ssrsrq_thresholds_int_array"; field public static final String KEY_5G_NR_SSSINR_THRESHOLDS_INT_ARRAY = "5g_nr_sssinr_thresholds_int_array"; @@ -44416,18 +44606,32 @@ package android.telephony { field public static final String KEY_ALLOW_LOCAL_DTMF_TONES_BOOL = "allow_local_dtmf_tones_bool"; field public static final String KEY_ALLOW_MERGE_WIFI_CALLS_WHEN_VOWIFI_OFF_BOOL = "allow_merge_wifi_calls_when_vowifi_off_bool"; field public static final String KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL = "allow_non_emergency_calls_in_ecm_bool"; + field public static final String KEY_ALLOW_VIDEO_CALLING_FALLBACK_BOOL = "allow_video_calling_fallback_bool"; + field public static final String KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL = "always_show_data_rat_icon_bool"; field @Deprecated public static final String KEY_ALWAYS_SHOW_EMERGENCY_ALERT_ONOFF_BOOL = "always_show_emergency_alert_onoff_bool"; + field public static final String KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN = "always_show_primary_signal_bar_in_opportunistic_network_boolean"; field public static final String KEY_APN_EXPAND_BOOL = "apn_expand_bool"; + field public static final String KEY_APN_SETTINGS_DEFAULT_APN_TYPES_STRING_ARRAY = "apn_settings_default_apn_types_string_array"; field public static final String KEY_AUTO_RETRY_ENABLED_BOOL = "auto_retry_enabled_bool"; field public static final String KEY_CALL_BARRING_SUPPORTS_DEACTIVATE_ALL_BOOL = "call_barring_supports_deactivate_all_bool"; field public static final String KEY_CALL_BARRING_SUPPORTS_PASSWORD_CHANGE_BOOL = "call_barring_supports_password_change_bool"; field public static final String KEY_CALL_BARRING_VISIBILITY_BOOL = "call_barring_visibility_bool"; field public static final String KEY_CALL_FORWARDING_BLOCKS_WHILE_ROAMING_STRING_ARRAY = "call_forwarding_blocks_while_roaming_string_array"; + field public static final String KEY_CALL_REDIRECTION_SERVICE_COMPONENT_NAME_STRING = "call_redirection_service_component_name_string"; + field public static final String KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL = "carrier_allow_deflect_ims_call_bool"; field public static final String KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL = "carrier_allow_turnoff_ims_bool"; field public static final String KEY_CARRIER_APP_REQUIRED_DURING_SIM_SETUP_BOOL = "carrier_app_required_during_setup_bool"; field public static final String KEY_CARRIER_CALL_SCREENING_APP_STRING = "call_screening_app"; + field public static final String KEY_CARRIER_CERTIFICATE_STRING_ARRAY = "carrier_certificate_string_array"; + field public static final String KEY_CARRIER_CONFIG_APPLIED_BOOL = "carrier_config_applied_bool"; field public static final String KEY_CARRIER_CONFIG_VERSION_STRING = "carrier_config_version_string"; field public static final String KEY_CARRIER_DATA_CALL_PERMANENT_FAILURE_STRINGS = "carrier_data_call_permanent_failure_strings"; + field public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_DCFAILURE_STRING_ARRAY = "carrier_default_actions_on_dcfailure_string_array"; + field public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_DEFAULT_NETWORK_AVAILABLE = "carrier_default_actions_on_default_network_available_string_array"; + field public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_REDIRECTION_STRING_ARRAY = "carrier_default_actions_on_redirection_string_array"; + field public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_RESET = "carrier_default_actions_on_reset_string_array"; + field public static final String KEY_CARRIER_DEFAULT_REDIRECTION_URL_STRING_ARRAY = "carrier_default_redirection_url_string_array"; + field public static final String KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL = "carrier_default_wfc_ims_enabled_bool"; field public static final String KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT = "carrier_default_wfc_ims_mode_int"; field public static final String KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT = "carrier_default_wfc_ims_roaming_mode_int"; field @Deprecated public static final String KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL = "carrier_force_disable_etws_cmas_test_bool"; @@ -44440,11 +44644,13 @@ package android.telephony { field public static final String KEY_CARRIER_NAME_OVERRIDE_BOOL = "carrier_name_override_bool"; field public static final String KEY_CARRIER_NAME_STRING = "carrier_name_string"; field public static final String KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL = "carrier_rcs_provisioning_required_bool"; + field public static final String KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING = "carrier_settings_activity_component_name_string"; field public static final String KEY_CARRIER_SETTINGS_ENABLE_BOOL = "carrier_settings_enable_bool"; field public static final String KEY_CARRIER_SUPPORTS_SS_OVER_UT_BOOL = "carrier_supports_ss_over_ut_bool"; field public static final String KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL = "carrier_use_ims_first_for_emergency_bool"; field public static final String KEY_CARRIER_UT_PROVISIONING_REQUIRED_BOOL = "carrier_ut_provisioning_required_bool"; field public static final String KEY_CARRIER_VOLTE_AVAILABLE_BOOL = "carrier_volte_available_bool"; + field public static final String KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL = "carrier_volte_override_wfc_provisioning_bool"; field public static final String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool"; field public static final String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool"; field public static final String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool"; @@ -44458,6 +44664,7 @@ package android.telephony { field public static final String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array"; field public static final String KEY_CDMA_ROAMING_MODE_INT = "cdma_roaming_mode_int"; field public static final String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array"; + field public static final String KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL = "check_pricing_with_carrier_data_roaming_bool"; field public static final String KEY_CI_ACTION_ON_SYS_UPDATE_BOOL = "ci_action_on_sys_update_bool"; field public static final String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING = "ci_action_on_sys_update_extra_string"; field public static final String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING = "ci_action_on_sys_update_extra_val_string"; @@ -44467,6 +44674,7 @@ package android.telephony { field public static final String KEY_CONFIG_IMS_RCS_PACKAGE_OVERRIDE_STRING = "config_ims_rcs_package_override_string"; field public static final String KEY_CONFIG_PLANS_PACKAGE_OVERRIDE_STRING = "config_plans_package_override_string"; field public static final String KEY_CONFIG_TELEPHONY_USE_OWN_NUMBER_FOR_VOICEMAIL_BOOL = "config_telephony_use_own_number_for_voicemail_bool"; + field public static final String KEY_CONFIG_WIFI_DISABLE_IN_ECBM = "config_wifi_disable_in_ecbm"; field public static final String KEY_CSP_ENABLED_BOOL = "csp_enabled_bool"; field public static final String KEY_DATA_LIMIT_NOTIFICATION_BOOL = "data_limit_notification_bool"; field public static final String KEY_DATA_LIMIT_THRESHOLD_BYTES_LONG = "data_limit_threshold_bytes_long"; @@ -44478,6 +44686,7 @@ package android.telephony { field public static final String KEY_DEFAULT_VM_NUMBER_STRING = "default_vm_number_string"; field public static final String KEY_DIAL_STRING_REPLACE_STRING_ARRAY = "dial_string_replace_string_array"; field public static final String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool"; + field public static final String KEY_DISABLE_CHARGE_INDICATION_BOOL = "disable_charge_indication_bool"; field public static final String KEY_DISABLE_SUPPLEMENTARY_SERVICES_IN_AIRPLANE_MODE_BOOL = "disable_supplementary_services_in_airplane_mode_bool"; field public static final String KEY_DISCONNECT_CAUSE_PLAY_BUSYTONE_INT_ARRAY = "disconnect_cause_play_busytone_int_array"; field public static final String KEY_DISPLAY_HD_AUDIO_PROPERTY_BOOL = "display_hd_audio_property_bool"; @@ -44487,9 +44696,13 @@ package android.telephony { field public static final String KEY_EDITABLE_ENHANCED_4G_LTE_BOOL = "editable_enhanced_4g_lte_bool"; field public static final String KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL = "editable_voicemail_number_bool"; field public static final String KEY_EDITABLE_VOICEMAIL_NUMBER_SETTING_BOOL = "editable_voicemail_number_setting_bool"; + field public static final String KEY_EDITABLE_WFC_MODE_BOOL = "editable_wfc_mode_bool"; + field public static final String KEY_EDITABLE_WFC_ROAMING_MODE_BOOL = "editable_wfc_roaming_mode_bool"; + field public static final String KEY_EMERGENCY_NOTIFICATION_DELAY_INT = "emergency_notification_delay_int"; field public static final String KEY_EMERGENCY_NUMBER_PREFIX_STRING_ARRAY = "emergency_number_prefix_string_array"; field public static final String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_key_vibration_bool"; field public static final String KEY_ENHANCED_4G_LTE_ON_BY_DEFAULT_BOOL = "enhanced_4g_lte_on_by_default_bool"; + field public static final String KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT = "enhanced_4g_lte_title_variant_int"; field public static final String KEY_FORCE_HOME_NETWORK_BOOL = "force_home_network_bool"; field public static final String KEY_GSM_DTMF_TONE_DELAY_INT = "gsm_dtmf_tone_delay_int"; field public static final String KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY = "gsm_nonroaming_networks_string_array"; @@ -44498,13 +44711,17 @@ package android.telephony { field public static final String KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool"; field public static final String KEY_HIDE_ENHANCED_4G_LTE_BOOL = "hide_enhanced_4g_lte_bool"; field public static final String KEY_HIDE_IMS_APN_BOOL = "hide_ims_apn_bool"; + field public static final String KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL = "hide_lte_plus_data_icon_bool"; field public static final String KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL = "hide_preferred_network_type_bool"; field public static final String KEY_HIDE_PRESET_APN_DETAILS_BOOL = "hide_preset_apn_details_bool"; field public static final String KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool"; + field public static final String KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS = "ignore_data_enabled_changed_for_video_calls"; + field public static final String KEY_IGNORE_RTT_MODE_SETTING_BOOL = "ignore_rtt_mode_setting_bool"; field public static final String KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL = "ignore_sim_network_locked_events_bool"; field public static final String KEY_IMS_CONFERENCE_SIZE_LIMIT_INT = "ims_conference_size_limit_int"; field public static final String KEY_IMS_DTMF_TONE_DELAY_INT = "ims_dtmf_tone_delay_int"; field public static final String KEY_IS_IMS_CONFERENCE_SIZE_ENFORCED_BOOL = "is_ims_conference_size_enforced_bool"; + field public static final String KEY_LTE_ENABLED_BOOL = "lte_enabled_bool"; field public static final String KEY_LTE_RSRQ_THRESHOLDS_INT_ARRAY = "lte_rsrq_thresholds_int_array"; field public static final String KEY_LTE_RSSNR_THRESHOLDS_INT_ARRAY = "lte_rssnr_thresholds_int_array"; field public static final String KEY_MDN_IS_ADDITIONAL_VOICEMAIL_NUMBER_BOOL = "mdn_is_additional_voicemail_number_bool"; @@ -44513,6 +44730,7 @@ package android.telephony { field public static final String KEY_MMS_ALIAS_MIN_CHARS_INT = "aliasMinChars"; field public static final String KEY_MMS_ALLOW_ATTACH_AUDIO_BOOL = "allowAttachAudio"; field public static final String KEY_MMS_APPEND_TRANSACTION_ID_BOOL = "enabledTransID"; + field public static final String KEY_MMS_CLOSE_CONNECTION_BOOL = "mmsCloseConnection"; field public static final String KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING = "emailGatewayNumber"; field public static final String KEY_MMS_GROUP_MMS_ENABLED_BOOL = "enableGroupMms"; field public static final String KEY_MMS_HTTP_PARAMS_STRING = "httpParams"; @@ -44540,6 +44758,7 @@ package android.telephony { field public static final String KEY_MMS_UA_PROF_URL_STRING = "uaProfUrl"; field public static final String KEY_MMS_USER_AGENT_STRING = "userAgent"; field public static final String KEY_MONTHLY_DATA_CYCLE_DAY_INT = "monthly_data_cycle_day_int"; + field public static final String KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL = "only_auto_select_in_home_network"; field public static final String KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY = "only_single_dc_allowed_int_array"; field public static final String KEY_OPERATOR_SELECTION_EXPAND_BOOL = "operator_selection_expand_bool"; field public static final String KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_HYSTERESIS_TIME_LONG = "opportunistic_network_data_switch_hysteresis_time_long"; @@ -44553,15 +44772,24 @@ package android.telephony { field public static final String KEY_PREVENT_CLIR_ACTIVATION_AND_DEACTIVATION_CODE_BOOL = "prevent_clir_activation_and_deactivation_code_bool"; field public static final String KEY_RADIO_RESTART_FAILURE_CAUSES_INT_ARRAY = "radio_restart_failure_causes_int_array"; field public static final String KEY_RCS_CONFIG_SERVER_URL_STRING = "rcs_config_server_url_string"; + field public static final String KEY_READ_ONLY_APN_FIELDS_STRING_ARRAY = "read_only_apn_fields_string_array"; + field public static final String KEY_READ_ONLY_APN_TYPES_STRING_ARRAY = "read_only_apn_types_string_array"; field public static final String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool"; field @Deprecated public static final String KEY_RESTART_RADIO_ON_PDP_FAIL_REGULAR_DEACTIVATION_BOOL = "restart_radio_on_pdp_fail_regular_deactivation_bool"; field public static final String KEY_RTT_SUPPORTED_BOOL = "rtt_supported_bool"; + field public static final String KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL = "show_4g_for_3g_data_icon_bool"; + field public static final String KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL = "show_4g_for_lte_data_icon_bool"; field public static final String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool"; + field public static final String KEY_SHOW_BLOCKING_PAY_PHONE_OPTION_BOOL = "show_blocking_pay_phone_option_bool"; field public static final String KEY_SHOW_CALL_BLOCKING_DISABLED_NOTIFICATION_ALWAYS_BOOL = "show_call_blocking_disabled_notification_always_bool"; + field public static final String KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING = "show_carrier_data_icon_pattern_string"; field public static final String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool"; field public static final String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool"; + field public static final String KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL = "show_ims_registration_status_bool"; field public static final String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool"; field public static final String KEY_SHOW_SIGNAL_STRENGTH_IN_SIM_STATUS_BOOL = "show_signal_strength_in_sim_status_bool"; + field public static final String KEY_SHOW_VIDEO_CALL_CHARGES_ALERT_DIALOG_BOOL = "show_video_call_charges_alert_dialog_bool"; + field public static final String KEY_SHOW_WFC_LOCATION_PRIVACY_POLICY_BOOL = "show_wfc_location_privacy_policy_bool"; field public static final String KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool"; field public static final String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool"; field public static final String KEY_SMS_REQUIRES_DESTINATION_NUMBER_CONVERSION_BOOL = "sms_requires_destination_number_conversion_bool"; @@ -44569,14 +44797,20 @@ package android.telephony { field public static final String KEY_SUPPORT_CLIR_NETWORK_DEFAULT_BOOL = "support_clir_network_default_bool"; field public static final String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool"; field public static final String KEY_SUPPORT_EMERGENCY_SMS_OVER_IMS_BOOL = "support_emergency_sms_over_ims_bool"; + field public static final String KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL = "support_enhanced_call_blocking_bool"; + field public static final String KEY_SUPPORT_IMS_CONFERENCE_EVENT_PACKAGE_BOOL = "support_ims_conference_event_package_bool"; field public static final String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool"; field public static final String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool"; + field public static final String KEY_SUPPORT_TDSCDMA_BOOL = "support_tdscdma_bool"; + field public static final String KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY = "support_tdscdma_roaming_networks_string_array"; field public static final String KEY_TREAT_DOWNGRADED_VIDEO_CALLS_AS_VIDEO_CALLS_BOOL = "treat_downgraded_video_calls_as_video_calls_bool"; field public static final String KEY_TTY_SUPPORTED_BOOL = "tty_supported_bool"; + field public static final String KEY_UNLOGGABLE_NUMBERS_STRING_ARRAY = "unloggable_numbers_string_array"; field public static final String KEY_USE_HFA_FOR_PROVISIONING_BOOL = "use_hfa_for_provisioning_bool"; field public static final String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool"; field public static final String KEY_USE_RCS_PRESENCE_BOOL = "use_rcs_presence_bool"; field public static final String KEY_USE_RCS_SIP_OPTIONS_BOOL = "use_rcs_sip_options_bool"; + field public static final String KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL = "use_wfc_home_network_mode_in_roaming_network_bool"; field public static final String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool"; field public static final String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool"; field public static final String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int"; @@ -44589,6 +44823,8 @@ package android.telephony { field public static final String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch_bool"; field public static final String KEY_VVM_SSL_ENABLED_BOOL = "vvm_ssl_enabled_bool"; field public static final String KEY_VVM_TYPE_STRING = "vvm_type_string"; + field public static final String KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING = "wfc_emergency_address_carrier_app_string"; + field public static final String KEY_WORLD_MODE_ENABLED_BOOL = "world_mode_enabled_bool"; field public static final String KEY_WORLD_PHONE_BOOL = "world_phone_bool"; } @@ -44691,7 +44927,8 @@ package android.telephony { method public int getCellConnectionStatus(); method @NonNull public abstract android.telephony.CellIdentity getCellIdentity(); method @NonNull public abstract android.telephony.CellSignalStrength getCellSignalStrength(); - method public long getTimeStamp(); + method @Deprecated public long getTimeStamp(); + method public long getTimestampNanos(); method public boolean isRegistered(); field public static final int CONNECTION_NONE = 0; // 0x0 field public static final int CONNECTION_PRIMARY_SERVING = 1; // 0x1 @@ -44926,6 +45163,35 @@ package android.telephony { field @Deprecated public static final int UNKNOWN_RSSI = 99; // 0x63 } + public final class NetworkRegistrationInfo implements android.os.Parcelable { + method public int describeContents(); + method public int getAccessNetworkTechnology(); + method @NonNull public java.util.List<java.lang.Integer> getAvailableServices(); + method @Nullable public android.telephony.CellIdentity getCellIdentity(); + method public int getDomain(); + method public int getNrState(); + method public int getTransportType(); + method public boolean isRegistered(); + method public boolean isRoaming(); + method public boolean isSearching(); + method public void writeToParcel(android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.telephony.NetworkRegistrationInfo> CREATOR; + field public static final int DOMAIN_CS = 1; // 0x1 + field public static final int DOMAIN_CS_PS = 3; // 0x3 + field public static final int DOMAIN_PS = 2; // 0x2 + field public static final int DOMAIN_UNKNOWN = 0; // 0x0 + field public static final int NR_STATE_CONNECTED = 3; // 0x3 + field public static final int NR_STATE_NONE = 0; // 0x0 + field public static final int NR_STATE_NOT_RESTRICTED = 2; // 0x2 + field public static final int NR_STATE_RESTRICTED = 1; // 0x1 + field public static final int SERVICE_TYPE_DATA = 2; // 0x2 + field public static final int SERVICE_TYPE_EMERGENCY = 5; // 0x5 + field public static final int SERVICE_TYPE_SMS = 3; // 0x3 + field public static final int SERVICE_TYPE_UNKNOWN = 0; // 0x0 + field public static final int SERVICE_TYPE_VIDEO = 4; // 0x4 + field public static final int SERVICE_TYPE_VOICE = 1; // 0x1 + } + public class NetworkScan { method public void stopScan(); field public static final int ERROR_INTERRUPTED = 10002; // 0x2712 @@ -45098,6 +45364,7 @@ package android.telephony { method public int getChannelNumber(); method public int getDuplexMode(); method public boolean getIsManualSelection(); + method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoList(); method public String getOperatorAlphaLong(); method public String getOperatorAlphaShort(); method public String getOperatorNumeric(); @@ -45134,6 +45401,7 @@ package android.telephony { method @Deprecated public int getGsmBitErrorRate(); method @Deprecated public int getGsmSignalStrength(); method public int getLevel(); + method public long getTimestampNanos(); method @Deprecated public boolean isGsm(); method public void writeToParcel(android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.telephony.SignalStrength> CREATOR; @@ -45637,6 +45905,7 @@ package android.telephony { field public static final int NETWORK_TYPE_UNKNOWN = 0; // 0x0 field public static final int PHONE_TYPE_CDMA = 2; // 0x2 field public static final int PHONE_TYPE_GSM = 1; // 0x1 + field public static final int PHONE_TYPE_IMS = 5; // 0x5 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_INACTIVE_SUBSCRIPTION = 2; // 0x2 @@ -46025,6 +46294,37 @@ package android.telephony.gsm { package android.telephony.ims { + public final class ImsException extends java.lang.Exception { + method public int getCode(); + field public static final int CODE_ERROR_SERVICE_UNAVAILABLE = 1; // 0x1 + field public static final int CODE_ERROR_UNSPECIFIED = 0; // 0x0 + field public static final int CODE_ERROR_UNSUPPORTED_OPERATION = 2; // 0x2 + } + + public class ImsMmTelManager implements android.telephony.ims.RegistrationManager { + method @NonNull @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int); + method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); + method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); + method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public int getVoWiFiModeSetting(); + method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isAdvancedCallingSettingEnabled(); + method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isTtyOverVolteEnabled(); + method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isVoWiFiRoamingSettingEnabled(); + method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isVoWiFiSettingEnabled(); + method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isVtSettingEnabled(); + method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException; + method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void registerMmTelCapabilityCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback) throws android.telephony.ims.ImsException; + method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback); + method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void unregisterMmTelCapabilityCallback(@NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback); + field public static final int WIFI_MODE_CELLULAR_PREFERRED = 1; // 0x1 + field public static final int WIFI_MODE_WIFI_ONLY = 0; // 0x0 + field public static final int WIFI_MODE_WIFI_PREFERRED = 2; // 0x2 + } + + public static class ImsMmTelManager.CapabilityCallback { + ctor public ImsMmTelManager.CapabilityCallback(); + method public void onCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.MmTelFeature.MmTelCapabilities); + } + public final class ImsReasonInfo implements android.os.Parcelable { ctor public ImsReasonInfo(int, int, @Nullable String); method public int describeContents(); @@ -46208,6 +46508,38 @@ package android.telephony.ims { field public static final int EXTRA_CODE_CALL_RETRY_SILENT_REDIAL = 2; // 0x2 } + public interface RegistrationManager { + method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); + method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); + method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException; + method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback); + field public static final int REGISTRATION_STATE_NOT_REGISTERED = 0; // 0x0 + field public static final int REGISTRATION_STATE_REGISTERED = 2; // 0x2 + field public static final int REGISTRATION_STATE_REGISTERING = 1; // 0x1 + } + + public static class RegistrationManager.RegistrationCallback { + ctor public RegistrationManager.RegistrationCallback(); + method public void onRegistered(int); + method public void onRegistering(int); + method public void onTechnologyChangeFailed(int, @Nullable android.telephony.ims.ImsReasonInfo); + method public void onUnregistered(@Nullable android.telephony.ims.ImsReasonInfo); + } + +} + +package android.telephony.ims.feature { + + public class MmTelFeature { + } + + public static class MmTelFeature.MmTelCapabilities { + field public static final int CAPABILITY_TYPE_SMS = 8; // 0x8 + field public static final int CAPABILITY_TYPE_UT = 4; // 0x4 + field public static final int CAPABILITY_TYPE_VIDEO = 2; // 0x2 + field public static final int CAPABILITY_TYPE_VOICE = 1; // 0x1 + } + } package android.telephony.mbms { @@ -70726,6 +71058,18 @@ package java.util { method public int lastIndexOf(@Nullable Object); method @NonNull public java.util.ListIterator<E> listIterator(); method @NonNull public java.util.ListIterator<E> listIterator(int); + method @NonNull public static <E> java.util.List<E> of(); + method @NonNull public static <E> java.util.List<E> of(@NonNull E); + method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E); + method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.List<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull @java.lang.SafeVarargs public static <E> java.util.List<E> of(@NonNull E...); method public E remove(int); method public default void replaceAll(@NonNull java.util.function.UnaryOperator<E>); method public E set(int, E); @@ -70880,6 +71224,7 @@ package java.util { method @Nullable public default V computeIfPresent(K, @NonNull java.util.function.BiFunction<? super K,? super V,? extends V>); method public boolean containsKey(@Nullable Object); method public boolean containsValue(@Nullable Object); + method @NonNull public static <K, V> java.util.Map.Entry<K,V> entry(@NonNull K, @NonNull V); method @NonNull public java.util.Set<java.util.Map.Entry<K,V>> entrySet(); method public boolean equals(@Nullable Object); method public default void forEach(@NonNull java.util.function.BiConsumer<? super K,? super V>); @@ -70889,6 +71234,18 @@ package java.util { method public boolean isEmpty(); method @NonNull public java.util.Set<K> keySet(); method @Nullable public default V merge(K, @NonNull V, @NonNull java.util.function.BiFunction<? super V,? super V,? extends V>); + method @NonNull public static <K, V> java.util.Map<K,V> of(); + method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V); + method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V); + method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V); + method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V); + method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V); + method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V); + method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V); + method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V); + method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V); + method @NonNull public static <K, V> java.util.Map<K,V> of(@NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V, @NonNull K, @NonNull V); + method @NonNull @java.lang.SafeVarargs public static <K, V> java.util.Map<K,V> ofEntries(@NonNull java.util.Map.Entry<? extends K,? extends V>...); method @Nullable public V put(K, V); method public void putAll(@NonNull java.util.Map<? extends K,? extends V>); method @Nullable public default V putIfAbsent(K, V); @@ -70970,6 +71327,9 @@ package java.util { } public final class Objects { + method public static int checkFromIndexSize(int, int, int); + method public static int checkFromToIndex(int, int, int); + method public static int checkIndex(int, int); method public static <T> int compare(T, T, @NonNull java.util.Comparator<? super T>); method public static boolean deepEquals(@Nullable Object, @Nullable Object); method public static boolean equals(@Nullable Object, @Nullable Object); @@ -70980,6 +71340,8 @@ package java.util { method @NonNull public static <T> T requireNonNull(@Nullable T); method @NonNull public static <T> T requireNonNull(@Nullable T, @NonNull String); method @NonNull public static <T> T requireNonNull(@Nullable T, @NonNull java.util.function.Supplier<java.lang.String>); + method @NonNull public static <T> T requireNonNullElse(@Nullable T, @NonNull T); + method @NonNull public static <T> T requireNonNullElseGet(@Nullable T, @NonNull java.util.function.Supplier<? extends T>); method @NonNull public static String toString(@Nullable Object); method @NonNull public static String toString(@Nullable Object, @NonNull String); } @@ -71284,6 +71646,18 @@ package java.util { } public interface Set<E> extends java.util.Collection<E> { + method @NonNull public static <E> java.util.Set<E> of(); + method @NonNull public static <E> java.util.Set<E> of(@NonNull E); + method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E); + method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull public static <E> java.util.Set<E> of(@NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E, @NonNull E); + method @NonNull @java.lang.SafeVarargs public static <E> java.util.Set<E> of(@NonNull E...); } public class SimpleTimeZone extends java.util.TimeZone { @@ -72222,6 +72596,29 @@ package java.util.concurrent { method public static java.util.concurrent.ScheduledExecutorService unconfigurableScheduledExecutorService(java.util.concurrent.ScheduledExecutorService); } + public final class Flow { + method public static int defaultBufferSize(); + } + + public static interface Flow.Processor<T, R> extends java.util.concurrent.Flow.Subscriber<T> java.util.concurrent.Flow.Publisher<R> { + } + + @java.lang.FunctionalInterface public static interface Flow.Publisher<T> { + method public void subscribe(java.util.concurrent.Flow.Subscriber<? super T>); + } + + public static interface Flow.Subscriber<T> { + method public void onComplete(); + method public void onError(Throwable); + method public void onNext(T); + method public void onSubscribe(java.util.concurrent.Flow.Subscription); + } + + public static interface Flow.Subscription { + method public void cancel(); + method public void request(long); + } + public class ForkJoinPool extends java.util.concurrent.AbstractExecutorService { ctor public ForkJoinPool(); ctor public ForkJoinPool(int); diff --git a/api/lint-baseline.txt b/api/lint-baseline.txt index 27204985d8d9..5c31f41e2e3c 100644 --- a/api/lint-baseline.txt +++ b/api/lint-baseline.txt @@ -485,10 +485,20 @@ HiddenSuperclass: android.util.StatsLog: +MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#CHORASMIAN: + Missing nullability on field `CHORASMIAN` in class `class android.icu.lang.UCharacter.UnicodeBlock` +MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#CJK_UNIFIED_IDEOGRAPHS_EXTENSION_G: + Missing nullability on field `CJK_UNIFIED_IDEOGRAPHS_EXTENSION_G` in class `class android.icu.lang.UCharacter.UnicodeBlock` +MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#DIVES_AKURU: + Missing nullability on field `DIVES_AKURU` in class `class android.icu.lang.UCharacter.UnicodeBlock` MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#EGYPTIAN_HIEROGLYPH_FORMAT_CONTROLS: MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#ELYMAIC: +MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#KHITAN_SMALL_SCRIPT: + +MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#LISU_SUPPLEMENT: + MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#NANDINAGARI: MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#NYIAKENG_PUACHUE_HMONG: @@ -499,26 +509,34 @@ MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#SMALL_KANA_EXTENSIO MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#SYMBOLS_AND_PICTOGRAPHS_EXTENDED_A: +MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#SYMBOLS_FOR_LEGACY_COMPUTING: + MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#TAMIL_SUPPLEMENT: +MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#TANGUT_SUPPLEMENT: + MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#WANCHO: +MissingNullability: android.icu.lang.UCharacter.UnicodeBlock#YEZIDI: + MissingNullability: android.icu.text.DateTimePatternGenerator#getFieldDisplayName(int, android.icu.text.DateTimePatternGenerator.DisplayWidth): MissingNullability: android.icu.text.DateTimePatternGenerator#getFieldDisplayName(int, android.icu.text.DateTimePatternGenerator.DisplayWidth) parameter #1: MissingNullability: android.icu.util.MeasureUnit#ATMOSPHERE: - Missing nullability on field `ATMOSPHERE` in class `class android.icu.util.MeasureUnit` + MissingNullability: android.icu.util.MeasureUnit#PERCENT: - Missing nullability on field `PERCENT` in class `class android.icu.util.MeasureUnit` + MissingNullability: android.icu.util.MeasureUnit#PERMILLE: - Missing nullability on field `PERMILLE` in class `class android.icu.util.MeasureUnit` + MissingNullability: android.icu.util.MeasureUnit#PETABYTE: - Missing nullability on field `PETABYTE` in class `class android.icu.util.MeasureUnit` + MissingNullability: android.icu.util.VersionInfo#UNICODE_12_0: MissingNullability: android.icu.util.VersionInfo#UNICODE_12_1: +MissingNullability: android.icu.util.VersionInfo#UNICODE_13_0: + Missing nullability on field `UNICODE_13_0` in class `class android.icu.util.VersionInfo` RequiresPermission: android.accounts.AccountManager#getAccountsByTypeAndFeatures(String, String[], android.accounts.AccountManagerCallback<android.accounts.Account[]>, android.os.Handler): diff --git a/api/module-app-current.txt b/api/module-app-current.txt index d802177e249b..4307e675e431 100644 --- a/api/module-app-current.txt +++ b/api/module-app-current.txt @@ -1 +1,9 @@ // Signature format: 2.0 +package android.app { + + public final class NotificationChannel implements android.os.Parcelable { + method public void setBlockableSystem(boolean); + } + +} + diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt index d802177e249b..c8253a0b9e88 100644 --- a/api/module-lib-current.txt +++ b/api/module-lib-current.txt @@ -1 +1,126 @@ // Signature format: 2.0 +package android.app.timedetector { + + public final class PhoneTimeSuggestion implements android.os.Parcelable { + method public void addDebugInfo(@NonNull String); + method public void addDebugInfo(@NonNull java.util.List<java.lang.String>); + method public int describeContents(); + method @NonNull public java.util.List<java.lang.String> getDebugInfo(); + method public int getPhoneId(); + method @Nullable public android.os.TimestampedValue<java.lang.Long> getUtcTime(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.app.timedetector.PhoneTimeSuggestion> CREATOR; + } + + public static final class PhoneTimeSuggestion.Builder { + ctor public PhoneTimeSuggestion.Builder(int); + method @NonNull public android.app.timedetector.PhoneTimeSuggestion.Builder addDebugInfo(@NonNull String); + method @NonNull public android.app.timedetector.PhoneTimeSuggestion build(); + method @NonNull public android.app.timedetector.PhoneTimeSuggestion.Builder setUtcTime(@Nullable android.os.TimestampedValue<java.lang.Long>); + } + + public class TimeDetector { + method @RequiresPermission("android.permission.SUGGEST_PHONE_TIME_AND_ZONE") public void suggestPhoneTime(@NonNull android.app.timedetector.PhoneTimeSuggestion); + } + +} + +package android.app.timezonedetector { + + public final class PhoneTimeZoneSuggestion implements android.os.Parcelable { + method public void addDebugInfo(@NonNull String); + method public void addDebugInfo(@NonNull java.util.List<java.lang.String>); + method @NonNull public static android.app.timezonedetector.PhoneTimeZoneSuggestion createEmptySuggestion(int, @NonNull String); + method public int describeContents(); + method @NonNull public java.util.List<java.lang.String> getDebugInfo(); + method public int getMatchType(); + method public int getPhoneId(); + method public int getQuality(); + method @Nullable public String getZoneId(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.app.timezonedetector.PhoneTimeZoneSuggestion> CREATOR; + field public static final int MATCH_TYPE_EMULATOR_ZONE_ID = 4; // 0x4 + field public static final int MATCH_TYPE_NA = 0; // 0x0 + field public static final int MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET = 3; // 0x3 + field public static final int MATCH_TYPE_NETWORK_COUNTRY_ONLY = 2; // 0x2 + field public static final int MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY = 5; // 0x5 + field public static final int QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS = 3; // 0x3 + field public static final int QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET = 2; // 0x2 + field public static final int QUALITY_NA = 0; // 0x0 + field public static final int QUALITY_SINGLE_ZONE = 1; // 0x1 + } + + public static final class PhoneTimeZoneSuggestion.Builder { + ctor public PhoneTimeZoneSuggestion.Builder(int); + method @NonNull public android.app.timezonedetector.PhoneTimeZoneSuggestion.Builder addDebugInfo(@NonNull String); + method @NonNull public android.app.timezonedetector.PhoneTimeZoneSuggestion build(); + method @NonNull public android.app.timezonedetector.PhoneTimeZoneSuggestion.Builder setMatchType(int); + method @NonNull public android.app.timezonedetector.PhoneTimeZoneSuggestion.Builder setQuality(int); + method @NonNull public android.app.timezonedetector.PhoneTimeZoneSuggestion.Builder setZoneId(@Nullable String); + } + + public class TimeZoneDetector { + method @RequiresPermission("android.permission.SUGGEST_PHONE_TIME_AND_ZONE") public void suggestPhoneTimeZone(@NonNull android.app.timezonedetector.PhoneTimeZoneSuggestion); + } + +} + +package android.os { + + public final class TimestampedValue<T> implements android.os.Parcelable { + ctor public TimestampedValue(long, @Nullable T); + method public int describeContents(); + method public long getReferenceTimeMillis(); + method @Nullable public T getValue(); + method public static long referenceTimeDifference(@NonNull android.os.TimestampedValue<?>, @NonNull android.os.TimestampedValue<?>); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.os.TimestampedValue<?>> CREATOR; + } + +} + +package android.timezone { + + public final class CountryTimeZones { + method @Nullable public android.icu.util.TimeZone getDefaultTimeZone(); + method @Nullable public String getDefaultTimeZoneId(); + method @NonNull public java.util.List<android.timezone.CountryTimeZones.TimeZoneMapping> getEffectiveTimeZoneMappingsAt(long); + method public boolean hasUtcZone(long); + method public boolean isDefaultTimeZoneBoosted(); + method public boolean isForCountryCode(@NonNull String); + method @Nullable public android.timezone.CountryTimeZones.OffsetResult lookupByOffsetWithBias(int, @Nullable Boolean, @Nullable Integer, long, @Nullable android.icu.util.TimeZone); + } + + public static final class CountryTimeZones.OffsetResult { + ctor public CountryTimeZones.OffsetResult(@NonNull android.icu.util.TimeZone, boolean); + method @NonNull public android.icu.util.TimeZone getTimeZone(); + method public boolean isOnlyMatch(); + } + + public static final class CountryTimeZones.TimeZoneMapping { + method @Nullable public android.icu.util.TimeZone getTimeZone(); + method @NonNull public String getTimeZoneId(); + } + + public class TelephonyLookup { + method @NonNull public static android.timezone.TelephonyLookup getInstance(); + method @Nullable public android.timezone.TelephonyNetworkFinder getTelephonyNetworkFinder(); + } + + public class TelephonyNetwork { + method @NonNull public String getCountryIsoCode(); + method @NonNull public String getMcc(); + method @NonNull public String getMnc(); + } + + public class TelephonyNetworkFinder { + method @Nullable public android.timezone.TelephonyNetwork findNetworkByMccMnc(@NonNull String, @NonNull String); + } + + public final class TimeZoneFinder { + method @NonNull public static android.timezone.TimeZoneFinder getInstance(); + method @Nullable public android.timezone.CountryTimeZones lookupCountryTimeZones(@NonNull String); + } + +} + diff --git a/api/system-current.txt b/api/system-current.txt index 5c2278cb78e5..b752bcb506c0 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -200,6 +200,7 @@ package android { field public static final String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES"; field public static final String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"; field public static final String SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON = "android.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON"; + field public static final String SUGGEST_PHONE_TIME_AND_ZONE = "android.permission.SUGGEST_PHONE_TIME_AND_ZONE"; field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS"; field public static final String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED"; field public static final String TV_INPUT_HARDWARE = "android.permission.TV_INPUT_HARDWARE"; @@ -683,6 +684,7 @@ package android.app { package android.app.admin { public class DevicePolicyManager { + method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public boolean getBluetoothContactSharingDisabled(@NonNull android.os.UserHandle); method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwner(); method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.content.ComponentName getDeviceOwnerComponentOnAnyUser(); method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getDeviceOwnerNameOnAnyUser(); @@ -1651,6 +1653,7 @@ package android.content { field public static final String EXTRA_PERMISSION_GROUP_NAME = "android.intent.extra.PERMISSION_GROUP_NAME"; field public static final String EXTRA_PERMISSION_NAME = "android.intent.extra.PERMISSION_NAME"; field public static final String EXTRA_REASON = "android.intent.extra.REASON"; + field @Deprecated public static final String EXTRA_REBROADCAST_ON_UNLOCK = "rebroadcastOnUnlock"; field public static final String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK"; field public static final String EXTRA_RESULT_NEEDED = "android.intent.extra.RESULT_NEEDED"; field public static final String EXTRA_ROLE_NAME = "android.intent.extra.ROLE_NAME"; @@ -4299,6 +4302,7 @@ package android.net { method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported(); method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public int registerNetworkProvider(@NonNull android.net.NetworkProvider); method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback); + method @Deprecated public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, int, int, @NonNull android.os.Handler); method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void setAirplaneMode(boolean); method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, "android.permission.NETWORK_STACK"}) public boolean shouldAvoidBadWifi(); method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle); @@ -4316,6 +4320,7 @@ package android.net { field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0 field public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb field public static final int TYPE_NONE = -1; // 0xffffffff + field @Deprecated public static final int TYPE_WIFI_P2P = 13; // 0xd } public abstract static class ConnectivityManager.OnStartTetheringCallback { @@ -4502,6 +4507,10 @@ package android.net { method public abstract void onRequestScores(android.net.NetworkKey[]); } + public class NetworkRequest implements android.os.Parcelable { + method public boolean satisfiedBy(@Nullable android.net.NetworkCapabilities); + } + public static class NetworkRequest.Builder { method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int); } @@ -4522,6 +4531,9 @@ package android.net { field @Deprecated public static final String EXTRA_NETWORKS_TO_SCORE = "networksToScore"; field public static final String EXTRA_NEW_SCORER = "newScorer"; field @Deprecated public static final String EXTRA_PACKAGE_NAME = "packageName"; + field public static final int SCORE_FILTER_CURRENT_NETWORK = 1; // 0x1 + field public static final int SCORE_FILTER_NONE = 0; // 0x0 + field public static final int SCORE_FILTER_SCAN_RESULTS = 2; // 0x2 } public static interface NetworkScoreManager.NetworkScoreCallback { @@ -4605,6 +4617,10 @@ package android.net { field public final android.net.RssiCurve rssiCurve; } + public abstract class SocketKeepalive implements java.lang.AutoCloseable { + field public static final int SUCCESS = 0; // 0x0 + } + public final class StaticIpConfiguration implements android.os.Parcelable { ctor public StaticIpConfiguration(); ctor public StaticIpConfiguration(@Nullable android.net.StaticIpConfiguration); @@ -4638,6 +4654,10 @@ package android.net { field @NonNull public final String specifier; } + public final class TelephonyNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable { + method public boolean satisfiedBy(android.net.NetworkSpecifier); + } + public class TrafficStats { method public static void setThreadStatsTagApp(); method public static void setThreadStatsTagBackup(); @@ -4763,9 +4783,11 @@ package android.net.ipsec.ike { } public abstract class ChildSessionParams { + method public long getHardLifetime(); method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getLocalTrafficSelectors(); method @NonNull public java.util.List<android.net.ipsec.ike.IkeTrafficSelector> getRemoteTrafficSelectors(); method @NonNull public java.util.List<android.net.ipsec.ike.ChildSaProposal> getSaProposals(); + method public long getSoftLifetime(); } public class IkeFqdnIdentification extends android.net.ipsec.ike.IkeIdentification { @@ -4834,12 +4856,14 @@ package android.net.ipsec.ike { } public final class IkeSessionParams { + method public long getHardLifetime(); method @NonNull public android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig getLocalAuthConfig(); method @NonNull public android.net.ipsec.ike.IkeIdentification getLocalIdentification(); method @NonNull public android.net.ipsec.ike.IkeSessionParams.IkeAuthConfig getRemoteAuthConfig(); method @NonNull public android.net.ipsec.ike.IkeIdentification getRemoteIdentification(); method @NonNull public java.util.List<android.net.ipsec.ike.IkeSaProposal> getSaProposals(); method @NonNull public java.net.InetAddress getServerAddress(); + method public long getSoftLifetime(); method @NonNull public android.net.IpSecManager.UdpEncapsulationSocket getUdpEncapsulationSocket(); } @@ -4851,6 +4875,7 @@ package android.net.ipsec.ike { method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthDigitalSignature(@Nullable java.security.cert.X509Certificate, @NonNull java.security.cert.X509Certificate, @NonNull java.util.List<java.security.cert.X509Certificate>, @NonNull java.security.PrivateKey); method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthEap(@Nullable java.security.cert.X509Certificate, @NonNull android.net.eap.EapSessionConfig); method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setAuthPsk(@NonNull byte[]); + method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setLifetime(long, long); method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setLocalIdentification(@NonNull android.net.ipsec.ike.IkeIdentification); method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setRemoteIdentification(@NonNull android.net.ipsec.ike.IkeIdentification); method @NonNull public android.net.ipsec.ike.IkeSessionParams.Builder setServerAddress(@NonNull java.net.InetAddress); @@ -4921,6 +4946,7 @@ package android.net.ipsec.ike { method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector); method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal); method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams build(); + method @NonNull public android.net.ipsec.ike.TransportModeChildSessionParams.Builder setLifetime(long, long); } public final class TunnelModeChildSessionParams extends android.net.ipsec.ike.ChildSessionParams { @@ -4938,6 +4964,7 @@ package android.net.ipsec.ike { method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addOutboundTrafficSelectors(@NonNull android.net.ipsec.ike.IkeTrafficSelector); method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder addSaProposal(@NonNull android.net.ipsec.ike.ChildSaProposal); method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams build(); + method @NonNull public android.net.ipsec.ike.TunnelModeChildSessionParams.Builder setLifetime(long, long); } public static interface TunnelModeChildSessionParams.ConfigRequest { @@ -8099,8 +8126,6 @@ package android.telephony { public final class AccessNetworkConstants { field public static final int TRANSPORT_TYPE_INVALID = -1; // 0xffffffff - field public static final int TRANSPORT_TYPE_WLAN = 2; // 0x2 - field public static final int TRANSPORT_TYPE_WWAN = 1; // 0x1 } public final class CallAttributes implements android.os.Parcelable { @@ -8728,37 +8753,18 @@ package android.telephony { } public final class NetworkRegistrationInfo implements android.os.Parcelable { - method public int describeContents(); - method public int getAccessNetworkTechnology(); - method @NonNull public java.util.List<java.lang.Integer> getAvailableServices(); - method @Nullable public android.telephony.CellIdentity getCellIdentity(); method @Nullable public android.telephony.DataSpecificRegistrationInfo getDataSpecificInfo(); - method public int getDomain(); - method public int getNrState(); method public int getRegistrationState(); method public int getRejectCause(); method public int getRoamingType(); - method public int getTransportType(); method public boolean isEmergencyEnabled(); - method public boolean isRoaming(); method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.NetworkRegistrationInfo> CREATOR; - field public static final int DOMAIN_CS = 1; // 0x1 - field public static final int DOMAIN_CS_PS = 3; // 0x3 - field public static final int DOMAIN_PS = 2; // 0x2 - field public static final int DOMAIN_UNKNOWN = 0; // 0x0 field public static final int REGISTRATION_STATE_DENIED = 3; // 0x3 field public static final int REGISTRATION_STATE_HOME = 1; // 0x1 field public static final int REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING = 0; // 0x0 field public static final int REGISTRATION_STATE_NOT_REGISTERED_SEARCHING = 2; // 0x2 field public static final int REGISTRATION_STATE_ROAMING = 5; // 0x5 field public static final int REGISTRATION_STATE_UNKNOWN = 4; // 0x4 - field public static final int SERVICE_TYPE_DATA = 2; // 0x2 - field public static final int SERVICE_TYPE_EMERGENCY = 5; // 0x5 - field public static final int SERVICE_TYPE_SMS = 3; // 0x3 - field public static final int SERVICE_TYPE_UNKNOWN = 0; // 0x0 - field public static final int SERVICE_TYPE_VIDEO = 4; // 0x4 - field public static final int SERVICE_TYPE_VOICE = 1; // 0x1 } public static final class NetworkRegistrationInfo.Builder { @@ -8863,6 +8869,7 @@ package android.telephony { } public final class PreciseDataConnectionState implements android.os.Parcelable { + ctor public PreciseDataConnectionState(int, int, int, @NonNull String, @Nullable android.net.LinkProperties, int, @Nullable android.telephony.data.ApnSetting); method @Deprecated @NonNull public String getDataConnectionApn(); method @Deprecated public int getDataConnectionApnTypeBitMask(); method @Deprecated public int getDataConnectionFailCause(); @@ -8971,9 +8978,9 @@ package android.telephony { public class ServiceState implements android.os.Parcelable { method @NonNull public android.telephony.ServiceState createLocationInfoSanitizedCopy(boolean); method public void fillInNotifierBundle(@NonNull android.os.Bundle); + method public int getDataNetworkType(); method public int getDataRegistrationState(); method @Nullable public android.telephony.NetworkRegistrationInfo getNetworkRegistrationInfo(int, int); - method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoList(); method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoListForDomain(int); method @NonNull public java.util.List<android.telephony.NetworkRegistrationInfo> getNetworkRegistrationInfoListForTransportType(int); method public int getNrFrequencyRange(); @@ -8986,6 +8993,10 @@ package android.telephony { field public static final int ROAMING_TYPE_UNKNOWN = 1; // 0x1 } + public class SignalStrength implements android.os.Parcelable { + ctor public SignalStrength(@NonNull android.telephony.SignalStrength); + } + public final class SmsCbCmasInfo implements android.os.Parcelable { ctor public SmsCbCmasInfo(int, int, int, int, int, int); method public int describeContents(); @@ -9118,6 +9129,11 @@ package android.telephony { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void sendMultipartTextMessageWithoutPersisting(String, String, java.util.List<java.lang.String>, java.util.List<android.app.PendingIntent>, java.util.List<android.app.PendingIntent>); } + public class SmsMessage { + method @Nullable public static android.telephony.SmsMessage createFromNativeSmsSubmitPdu(@NonNull byte[], boolean); + method @NonNull @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public static byte[] getSubmitPduEncodedMessage(boolean, @NonNull String, @NonNull String, int, int, int, int, int, int); + } + public class SubscriptionInfo implements android.os.Parcelable { method public boolean areUiccApplicationsEnabled(); method @Nullable public java.util.List<android.telephony.UiccAccessRule> getAccessRules(); @@ -9196,6 +9212,7 @@ package android.telephony { method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.ImsiEncryptionInfo getCarrierInfoForImsiEncryption(int); method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent); method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int); + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getCarrierPrivilegeStatus(int); method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public java.util.List<java.lang.String> getCarrierPrivilegedPackagesForAllActiveSubscriptions(); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public android.telephony.CarrierRestrictionRules getCarrierRestrictionRules(); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public String getCdmaMdn(); @@ -9297,6 +9314,9 @@ package android.telephony { field public static final String ACTION_SIM_APPLICATION_STATE_CHANGED = "android.telephony.action.SIM_APPLICATION_STATE_CHANGED"; field public static final String ACTION_SIM_CARD_STATE_CHANGED = "android.telephony.action.SIM_CARD_STATE_CHANGED"; field public static final String ACTION_SIM_SLOT_STATUS_CHANGED = "android.telephony.action.SIM_SLOT_STATUS_CHANGED"; + field public static final int CARD_POWER_DOWN = 0; // 0x0 + field public static final int CARD_POWER_UP = 1; // 0x1 + field public static final int CARD_POWER_UP_PASS_THROUGH = 2; // 0x2 field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1 field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0 @@ -9329,6 +9349,7 @@ package android.telephony { field public static final long NETWORK_TYPE_BITMASK_TD_SCDMA = 65536L; // 0x10000L field public static final long NETWORK_TYPE_BITMASK_UMTS = 4L; // 0x4L field public static final long NETWORK_TYPE_BITMASK_UNKNOWN = 0L; // 0x0L + field public static final int PHONE_TYPE_THIRD_PARTY = 4; // 0x4 field public static final int RADIO_POWER_OFF = 0; // 0x0 field public static final int RADIO_POWER_ON = 1; // 0x1 field public static final int RADIO_POWER_UNAVAILABLE = 2; // 0x2 @@ -9730,6 +9751,7 @@ package android.telephony.ims { method public int getEmergencyServiceCategories(); method @NonNull public java.util.List<java.lang.String> getEmergencyUrns(); method public android.telephony.ims.ImsStreamMediaProfile getMediaProfile(); + method @Nullable public android.os.Bundle getProprietaryCallExtras(); method public int getRestrictCause(); method public int getServiceType(); method public static int getVideoStateFromCallType(int); @@ -9867,10 +9889,6 @@ package android.telephony.ims { ctor public ImsException(@Nullable String); ctor public ImsException(@Nullable String, int); ctor public ImsException(@Nullable String, int, @Nullable Throwable); - method public int getCode(); - field public static final int CODE_ERROR_SERVICE_UNAVAILABLE = 1; // 0x1 - field public static final int CODE_ERROR_UNSPECIFIED = 0; // 0x0 - field public static final int CODE_ERROR_UNSUPPORTED_OPERATION = 2; // 0x2 } public final class ImsExternalCallState implements android.os.Parcelable { @@ -9896,23 +9914,13 @@ package android.telephony.ims { } public class ImsMmTelManager implements android.telephony.ims.RegistrationManager { - method @NonNull public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiModeSetting(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public int getVoWiFiRoamingModeSetting(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAdvancedCallingSettingEnabled(); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAvailable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCapable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void isSupported(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>) throws android.telephony.ims.ImsException; - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isTtyOverVolteEnabled(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVoWiFiRoamingSettingEnabled(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVoWiFiSettingEnabled(); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isVtSettingEnabled(); method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback) throws android.telephony.ims.ImsException; - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException; - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerMmTelCapabilityCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAdvancedCallingSettingEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRttCapabilitySetting(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiModeSetting(int); @@ -9922,16 +9930,6 @@ package android.telephony.ims { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiSettingEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVtSettingEnabled(boolean); method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterMmTelCapabilityCallback(@NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback); - field public static final int WIFI_MODE_CELLULAR_PREFERRED = 1; // 0x1 - field public static final int WIFI_MODE_WIFI_ONLY = 0; // 0x0 - field public static final int WIFI_MODE_WIFI_PREFERRED = 2; // 0x2 - } - - public static class ImsMmTelManager.CapabilityCallback { - ctor public ImsMmTelManager.CapabilityCallback(); - method public void onCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.MmTelFeature.MmTelCapabilities); } @Deprecated public static class ImsMmTelManager.RegistrationCallback extends android.telephony.ims.RegistrationManager.RegistrationCallback { @@ -10188,6 +10186,7 @@ package android.telephony.ims { method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean getProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int); method @Nullable @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public String getProvisioningStringValue(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) @WorkerThread public boolean getRcsProvisioningStatusForCapability(int); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyRcsAutoConfigurationReceived(@NonNull byte[], boolean); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerProvisioningChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.Callback) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningIntValue(int, int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, boolean); @@ -10230,6 +10229,9 @@ package android.telephony.ims { method public boolean isCapable(int); method public boolean isCapable(@NonNull String); method public void writeToParcel(@NonNull android.os.Parcel, int); + field public static final int CAPABILITY_CALL_COMPOSER = 4194304; // 0x400000 + field public static final int CAPABILITY_CHAT_BOT = 67108864; // 0x4000000 + field public static final int CAPABILITY_CHAT_BOT_ROLE = 134217728; // 0x8000000 field public static final int CAPABILITY_CHAT_SESSION = 2; // 0x2 field public static final int CAPABILITY_CHAT_SESSION_STORE_FORWARD = 4; // 0x4 field public static final int CAPABILITY_CHAT_STANDALONE = 1; // 0x1 @@ -10246,9 +10248,13 @@ package android.telephony.ims { field public static final int CAPABILITY_IMAGE_SHARE = 256; // 0x100 field public static final int CAPABILITY_IP_VIDEO_CALL = 16384; // 0x4000 field public static final int CAPABILITY_IP_VOICE_CALL = 8192; // 0x2000 + field public static final int CAPABILITY_PLUG_IN = 268435456; // 0x10000000 + field public static final int CAPABILITY_POST_CALL = 8388608; // 0x800000 field public static final int CAPABILITY_RCS_VIDEO_CALL = 1048576; // 0x100000 field public static final int CAPABILITY_RCS_VIDEO_ONLY_CALL = 2097152; // 0x200000 field public static final int CAPABILITY_RCS_VOICE_CALL = 524288; // 0x80000 + field public static final int CAPABILITY_SHARED_MAP = 16777216; // 0x1000000 + field public static final int CAPABILITY_SHARED_SKETCH = 33554432; // 0x2000000 field public static final int CAPABILITY_SOCIAL_PRESENCE = 2048; // 0x800 field public static final int CAPABILITY_VIDEO_SHARE = 1024; // 0x400 field public static final int CAPABILITY_VIDEO_SHARE_DURING_CS_CALL = 512; // 0x200 @@ -10263,24 +10269,6 @@ package android.telephony.ims { method @NonNull public android.telephony.ims.RcsContactUceCapability build(); } - public interface RegistrationManager { - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException; - method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback); - field public static final int REGISTRATION_STATE_NOT_REGISTERED = 0; // 0x0 - field public static final int REGISTRATION_STATE_REGISTERED = 2; // 0x2 - field public static final int REGISTRATION_STATE_REGISTERING = 1; // 0x1 - } - - public static class RegistrationManager.RegistrationCallback { - ctor public RegistrationManager.RegistrationCallback(); - method public void onRegistered(int); - method public void onRegistering(int); - method public void onTechnologyChangeFailed(int, @Nullable android.telephony.ims.ImsReasonInfo); - method public void onUnregistered(@Nullable android.telephony.ims.ImsReasonInfo); - } - } package android.telephony.ims.feature { @@ -10304,6 +10292,7 @@ package android.telephony.ims.feature { public abstract class ImsFeature { ctor public ImsFeature(); method public abstract void changeEnabledCapabilities(android.telephony.ims.feature.CapabilityChangeRequest, android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy); + method public int getFeatureState(); method public final int getSlotIndex(); method public abstract void onFeatureReady(); method public abstract void onFeatureRemoved(); @@ -10342,7 +10331,7 @@ package android.telephony.ims.feature { method public void onFeatureReady(); method public void onFeatureRemoved(); method public boolean queryCapabilityConfiguration(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int); - method public final android.telephony.ims.feature.MmTelFeature.MmTelCapabilities queryCapabilityStatus(); + method @NonNull public final android.telephony.ims.feature.MmTelFeature.MmTelCapabilities queryCapabilityStatus(); method public void setUiTtyMode(int, @Nullable android.os.Message); method @android.telephony.ims.feature.MmTelFeature.ProcessCallResult public int shouldProcessCall(@NonNull String[]); field public static final String EXTRA_IS_UNKNOWN_CALL = "android.telephony.ims.feature.extra.IS_UNKNOWN_CALL"; @@ -10358,10 +10347,6 @@ package android.telephony.ims.feature { method public final void addCapabilities(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int); method public final boolean isCapable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int); method public final void removeCapabilities(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int); - field public static final int CAPABILITY_TYPE_SMS = 8; // 0x8 - field public static final int CAPABILITY_TYPE_UT = 4; // 0x4 - field public static final int CAPABILITY_TYPE_VIDEO = 2; // 0x2 - field public static final int CAPABILITY_TYPE_VOICE = 1; // 0x1 } @IntDef(flag=true, value={android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_SMS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface MmTelFeature.MmTelCapabilities.MmTelCapability { @@ -10452,6 +10437,7 @@ package android.telephony.ims.stub { method public String getConfigString(int); method public final void notifyProvisionedValueChanged(int, int); method public final void notifyProvisionedValueChanged(int, String); + method public void notifyRcsAutoConfigurationReceived(@NonNull byte[], boolean); method public int setConfig(int, int); method public int setConfig(int, String); field public static final int CONFIG_RESULT_FAILED = 1; // 0x1 @@ -10550,6 +10536,17 @@ package android.telephony.ims.stub { method public int updateClir(int); method public int updateColp(boolean); method public int updateColr(int); + field public static final int CALL_BARRING_ALL = 7; // 0x7 + field public static final int CALL_BARRING_ALL_INCOMING = 1; // 0x1 + field public static final int CALL_BARRING_ALL_OUTGOING = 2; // 0x2 + field public static final int CALL_BARRING_ANONYMOUS_INCOMING = 6; // 0x6 + field public static final int CALL_BARRING_INCOMING_ALL_SERVICES = 9; // 0x9 + field public static final int CALL_BARRING_OUTGOING_ALL_SERVICES = 8; // 0x8 + field public static final int CALL_BARRING_OUTGOING_INTL = 3; // 0x3 + field public static final int CALL_BARRING_OUTGOING_INTL_EXCL_HOME = 4; // 0x4 + field public static final int CALL_BARRING_SPECIFIC_INCOMING_CALLS = 10; // 0xa + field public static final int CALL_BLOCKING_INCOMING_WHEN_ROAMING = 5; // 0x5 + field public static final int INVALID_RESULT = -1; // 0xffffffff } } diff --git a/api/test-current.txt b/api/test-current.txt index a20b75c3355b..e4997b76c1b9 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -320,8 +320,10 @@ package android.app { } public final class NotificationChannel implements android.os.Parcelable { + method public boolean isBlockableSystem(); method public boolean isImportanceLockedByCriticalDeviceFunction(); method public boolean isImportanceLockedByOEM(); + method public void setBlockableSystem(boolean); method public void setImportanceLockedByCriticalDeviceFunction(boolean); method public void setImportanceLockedByOEM(boolean); } @@ -2888,8 +2890,6 @@ package android.telephony { public final class AccessNetworkConstants { field public static final int TRANSPORT_TYPE_INVALID = -1; // 0xffffffff - field public static final int TRANSPORT_TYPE_WLAN = 2; // 0x2 - field public static final int TRANSPORT_TYPE_WWAN = 1; // 0x1 } public final class CallQuality implements android.os.Parcelable { @@ -2952,36 +2952,18 @@ package android.telephony { } public final class NetworkRegistrationInfo implements android.os.Parcelable { - method public int describeContents(); - method public int getAccessNetworkTechnology(); - method @NonNull public java.util.List<java.lang.Integer> getAvailableServices(); - method @Nullable public android.telephony.CellIdentity getCellIdentity(); method @Nullable public android.telephony.DataSpecificRegistrationInfo getDataSpecificInfo(); - method public int getDomain(); method public int getRegistrationState(); method public int getRejectCause(); method public int getRoamingType(); - method public int getTransportType(); method public boolean isEmergencyEnabled(); - method public boolean isRoaming(); method public void writeToParcel(android.os.Parcel, int); - field @NonNull public static final android.os.Parcelable.Creator<android.telephony.NetworkRegistrationInfo> CREATOR; - field public static final int DOMAIN_CS = 1; // 0x1 - field public static final int DOMAIN_CS_PS = 3; // 0x3 - field public static final int DOMAIN_PS = 2; // 0x2 - field public static final int DOMAIN_UNKNOWN = 0; // 0x0 field public static final int REGISTRATION_STATE_DENIED = 3; // 0x3 field public static final int REGISTRATION_STATE_HOME = 1; // 0x1 field public static final int REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING = 0; // 0x0 field public static final int REGISTRATION_STATE_NOT_REGISTERED_SEARCHING = 2; // 0x2 field public static final int REGISTRATION_STATE_ROAMING = 5; // 0x5 field public static final int REGISTRATION_STATE_UNKNOWN = 4; // 0x4 - field public static final int SERVICE_TYPE_DATA = 2; // 0x2 - field public static final int SERVICE_TYPE_EMERGENCY = 5; // 0x5 - field public static final int SERVICE_TYPE_SMS = 3; // 0x3 - field public static final int SERVICE_TYPE_UNKNOWN = 0; // 0x0 - field public static final int SERVICE_TYPE_VIDEO = 4; // 0x4 - field public static final int SERVICE_TYPE_VOICE = 1; // 0x1 } public static final class NetworkRegistrationInfo.Builder { @@ -3018,6 +3000,7 @@ package android.telephony { public class ServiceState implements android.os.Parcelable { method public void addNetworkRegistrationInfo(android.telephony.NetworkRegistrationInfo); + method public int getDataNetworkType(); method public void setCdmaSystemAndNetworkId(int, int); method public void setCellBandwidths(int[]); method public void setChannelNumber(int); @@ -3126,6 +3109,7 @@ package android.telephony.ims { method public int getEmergencyServiceCategories(); method @NonNull public java.util.List<java.lang.String> getEmergencyUrns(); method public android.telephony.ims.ImsStreamMediaProfile getMediaProfile(); + method @Nullable public android.os.Bundle getProprietaryCallExtras(); method public int getRestrictCause(); method public int getServiceType(); method public static int getVideoStateFromCallType(int); @@ -3178,6 +3162,7 @@ package android.telephony.ims { field public static final String EXTRA_DISPLAY_TEXT = "DisplayText"; field public static final String EXTRA_EMERGENCY_CALL = "e_call"; field public static final String EXTRA_IS_CALL_PULL = "CallPull"; + field public static final String EXTRA_OEM_EXTRAS = "android.telephony.ims.extra.OEM_EXTRAS"; field public static final String EXTRA_OI = "oi"; field public static final String EXTRA_OIR = "oir"; field public static final String EXTRA_REMOTE_URI = "remote_uri"; @@ -3263,10 +3248,6 @@ package android.telephony.ims { ctor public ImsException(@Nullable String); ctor public ImsException(@Nullable String, int); ctor public ImsException(@Nullable String, int, @Nullable Throwable); - method public int getCode(); - field public static final int CODE_ERROR_SERVICE_UNAVAILABLE = 1; // 0x1 - field public static final int CODE_ERROR_UNSPECIFIED = 0; // 0x0 - field public static final int CODE_ERROR_UNSUPPORTED_OPERATION = 2; // 0x2 } public final class ImsExternalCallState implements android.os.Parcelable { @@ -3292,23 +3273,13 @@ package android.telephony.ims { } public class ImsMmTelManager implements android.telephony.ims.RegistrationManager { - method @NonNull public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>) throws android.telephony.ims.ImsException; method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getVoWiFiModeSetting(); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getVoWiFiRoamingModeSetting(); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isAdvancedCallingSettingEnabled(); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isAvailable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isCapable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void isSupported(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>) throws android.telephony.ims.ImsException; - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isTtyOverVolteEnabled(); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isVoWiFiRoamingSettingEnabled(); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isVoWiFiSettingEnabled(); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public boolean isVtSettingEnabled(); method @Deprecated @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback) throws android.telephony.ims.ImsException; - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException; - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void registerMmTelCapabilityCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setAdvancedCallingSettingEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setRttCapabilitySetting(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiModeSetting(int); @@ -3318,16 +3289,6 @@ package android.telephony.ims { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiSettingEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setVtSettingEnabled(boolean); method @Deprecated @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.ImsMmTelManager.RegistrationCallback); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void unregisterMmTelCapabilityCallback(@NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback); - field public static final int WIFI_MODE_CELLULAR_PREFERRED = 1; // 0x1 - field public static final int WIFI_MODE_WIFI_ONLY = 0; // 0x0 - field public static final int WIFI_MODE_WIFI_PREFERRED = 2; // 0x2 - } - - public static class ImsMmTelManager.CapabilityCallback { - ctor public ImsMmTelManager.CapabilityCallback(); - method public void onCapabilitiesStatusChanged(@NonNull android.telephony.ims.feature.MmTelFeature.MmTelCapabilities); } @Deprecated public static class ImsMmTelManager.RegistrationCallback extends android.telephony.ims.RegistrationManager.RegistrationCallback { @@ -3580,6 +3541,7 @@ package android.telephony.ims { method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @WorkerThread public boolean getProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int); method @Nullable @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @WorkerThread public String getProvisioningStringValue(int); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") @WorkerThread public boolean getRcsProvisioningStatusForCapability(int); + method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void notifyRcsAutoConfigurationReceived(@NonNull byte[], boolean); method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void registerProvisioningChangedCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ProvisioningManager.Callback) throws android.telephony.ims.ImsException; method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public int setProvisioningIntValue(int, int); method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) @WorkerThread public void setProvisioningStatusForCapability(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int, boolean); @@ -3614,24 +3576,6 @@ package android.telephony.ims { method public void onProvisioningStringChanged(int, @NonNull String); } - public interface RegistrationManager { - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>); - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException; - method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback); - field public static final int REGISTRATION_STATE_NOT_REGISTERED = 0; // 0x0 - field public static final int REGISTRATION_STATE_REGISTERED = 2; // 0x2 - field public static final int REGISTRATION_STATE_REGISTERING = 1; // 0x1 - } - - public static class RegistrationManager.RegistrationCallback { - ctor public RegistrationManager.RegistrationCallback(); - method public void onRegistered(int); - method public void onRegistering(int); - method public void onTechnologyChangeFailed(int, @Nullable android.telephony.ims.ImsReasonInfo); - method public void onUnregistered(@Nullable android.telephony.ims.ImsReasonInfo); - } - } package android.telephony.ims.feature { @@ -3655,6 +3599,7 @@ package android.telephony.ims.feature { public abstract class ImsFeature { ctor public ImsFeature(); method public abstract void changeEnabledCapabilities(android.telephony.ims.feature.CapabilityChangeRequest, android.telephony.ims.feature.ImsFeature.CapabilityCallbackProxy); + method public int getFeatureState(); method public final int getSlotIndex(); method public abstract void onFeatureReady(); method public abstract void onFeatureRemoved(); @@ -3693,7 +3638,7 @@ package android.telephony.ims.feature { method public void onFeatureReady(); method public void onFeatureRemoved(); method public boolean queryCapabilityConfiguration(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int, int); - method public final android.telephony.ims.feature.MmTelFeature.MmTelCapabilities queryCapabilityStatus(); + method @NonNull public final android.telephony.ims.feature.MmTelFeature.MmTelCapabilities queryCapabilityStatus(); method public void setUiTtyMode(int, @Nullable android.os.Message); method @android.telephony.ims.feature.MmTelFeature.ProcessCallResult public int shouldProcessCall(@NonNull String[]); field public static final String EXTRA_IS_UNKNOWN_CALL = "android.telephony.ims.feature.extra.IS_UNKNOWN_CALL"; @@ -3709,10 +3654,6 @@ package android.telephony.ims.feature { method public final void addCapabilities(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int); method public final boolean isCapable(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int); method public final void removeCapabilities(@android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.MmTelCapability int); - field public static final int CAPABILITY_TYPE_SMS = 8; // 0x8 - field public static final int CAPABILITY_TYPE_UT = 4; // 0x4 - field public static final int CAPABILITY_TYPE_VIDEO = 2; // 0x2 - field public static final int CAPABILITY_TYPE_VOICE = 1; // 0x1 } @IntDef(flag=true, value={android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_UT, android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_SMS}) @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.SOURCE) public static @interface MmTelFeature.MmTelCapabilities.MmTelCapability { @@ -3803,6 +3744,7 @@ package android.telephony.ims.stub { method public String getConfigString(int); method public final void notifyProvisionedValueChanged(int, int); method public final void notifyProvisionedValueChanged(int, String); + method public void notifyRcsAutoConfigurationReceived(@NonNull byte[], boolean); method public int setConfig(int, int); method public int setConfig(int, String); field public static final int CONFIG_RESULT_FAILED = 1; // 0x1 @@ -3901,6 +3843,17 @@ package android.telephony.ims.stub { method public int updateClir(int); method public int updateColp(boolean); method public int updateColr(int); + field public static final int CALL_BARRING_ALL = 7; // 0x7 + field public static final int CALL_BARRING_ALL_INCOMING = 1; // 0x1 + field public static final int CALL_BARRING_ALL_OUTGOING = 2; // 0x2 + field public static final int CALL_BARRING_ANONYMOUS_INCOMING = 6; // 0x6 + field public static final int CALL_BARRING_INCOMING_ALL_SERVICES = 9; // 0x9 + field public static final int CALL_BARRING_OUTGOING_ALL_SERVICES = 8; // 0x8 + field public static final int CALL_BARRING_OUTGOING_INTL = 3; // 0x3 + field public static final int CALL_BARRING_OUTGOING_INTL_EXCL_HOME = 4; // 0x4 + field public static final int CALL_BARRING_SPECIFIC_INCOMING_CALLS = 10; // 0xa + field public static final int CALL_BLOCKING_INCOMING_WHEN_ROAMING = 5; // 0x5 + field public static final int INVALID_RESULT = -1; // 0xffffffff } } diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java index 6033655c8513..c2ee6dcd13b2 100644 --- a/cmds/sm/src/com/android/commands/sm/Sm.java +++ b/cmds/sm/src/com/android/commands/sm/Sm.java @@ -103,6 +103,10 @@ public final class Sm { runSetVirtualDisk(); } else if ("set-isolated-storage".equals(op)) { runIsolatedStorage(); + } else if ("start-checkpoint".equals(op)) { + runStartCheckpoint(); + } else if ("supports-checkpoint".equals(op)) { + runSupportsCheckpoint(); } else { throw new IllegalArgumentException(); } @@ -313,6 +317,27 @@ public final class Sm { } } + private void runStartCheckpoint() throws RemoteException { + final String numRetriesString = nextArg(); + if (numRetriesString == null) { + throw new IllegalArgumentException("Expected <num-retries>"); + } + int numRetries; + try { + numRetries = Integer.parseInt(numRetriesString); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("<num-retries> must be a positive integer"); + } + if (numRetries <= 0) { + throw new IllegalArgumentException("<num-retries> must be a positive integer"); + } + mSm.startCheckpoint(numRetries); + } + + private void runSupportsCheckpoint() throws RemoteException { + System.out.println(mSm.supportsCheckpoint()); + } + private String nextArg() { if (mNextArg >= mArgs.length) { return null; @@ -344,6 +369,10 @@ public final class Sm { System.err.println(""); System.err.println(" sm set-isolated-storage [on|off|default]"); System.err.println(""); + System.err.println(" sm start-checkpoint <num-retries>"); + System.err.println(""); + System.err.println(" sm supports-checkpoint"); + System.err.println(""); return 1; } } diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index c92315687e71..d9083886f817 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -50,6 +50,7 @@ import "frameworks/base/core/proto/android/stats/intelligence/enums.proto"; import "frameworks/base/core/proto/android/stats/launcher/launcher.proto"; import "frameworks/base/core/proto/android/stats/location/location_enums.proto"; import "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.proto"; +import "frameworks/base/core/proto/android/stats/otaupdate/updateengine_enums.proto"; import "frameworks/base/core/proto/android/stats/storage/storage_enums.proto"; import "frameworks/base/core/proto/android/stats/style/style_enums.proto"; import "frameworks/base/core/proto/android/telecomm/enums.proto"; @@ -123,10 +124,10 @@ message Atom { AppStartOccurred app_start_occurred = 48; AppStartCanceled app_start_canceled = 49; AppStartFullyDrawn app_start_fully_drawn = 50; - LmkKillOccurred lmk_kill_occurred = 51; + LmkKillOccurred lmk_kill_occurred = 51 [(log_from_module) = "lmkd"]; PictureInPictureStateChanged picture_in_picture_state_changed = 52; WifiMulticastLockStateChanged wifi_multicast_lock_state_changed = 53; - LmkStateChanged lmk_state_changed = 54; + LmkStateChanged lmk_state_changed = 54 [(log_from_module) = "lmkd"]; AppStartMemoryStateCaptured app_start_memory_state_captured = 55; ShutdownSequenceReported shutdown_sequence_reported = 56; BootSequenceReported boot_sequence_reported = 57; @@ -322,6 +323,8 @@ message Atom { ExclusionRectStateChanged exclusion_rect_state_changed = 223; BackGesture back_gesture_reported_reported = 224; + UpdateEngineUpdateAttemptReported update_engine_update_attempt_reported = 225; + UpdateEngineSuccessfulUpdateReported update_engine_successful_update_reported = 226; AppCompatibilityChangeReported app_compatibility_change_reported = 228 [(allow_from_any_uid) = true]; PerfettoUploaded perfetto_uploaded = @@ -6894,3 +6897,70 @@ message PerfettoUploaded { optional int64 trace_uuid_lsb = 2; optional int64 trace_uuid_msb = 3; } + +/** + * Information about an OTA update attempt by update_engine. + * Logged from platform/system/update_engine/metrics_reporter_android.cc + */ +message UpdateEngineUpdateAttemptReported { + // The number of attempts for the update engine to apply a given payload. + optional int32 attempt_number = 1; + + optional android.stats.otaupdate.PayloadType payload_type = 2; + + // The total time in minutes for the update engine to apply a given payload. + // The time is calculated by calling clock_gettime() / CLOCK_BOOTTIME; and + // it's increased when the system is sleeping. + optional int32 duration_boottime_in_minutes = 3; + + // The total time in minutes for the update engine to apply a given payload. + // The time is calculated by calling clock_gettime() / CLOCK_MONOTONIC_RAW; + // and it's not increased when the system is sleeping. + optional int32 duration_monotonic_in_minutes = 4; + + // The size of the payload in MiBs. + optional int32 payload_size_mib = 5; + + // The attempt result reported by the update engine for an OTA update. + optional android.stats.otaupdate.AttemptResult attempt_result = 6; + + // The error code reported by the update engine after an OTA update attempt + // on A/B devices. + optional android.stats.otaupdate.ErrorCode error_code = 7; + + // The build fingerprint of the source system. The value is read from a + // system property when the device takes the update. e.g. + // Android/aosp_sailfish/sailfish:10/QP1A.190425.004/5507117:userdebug/test-keys + optional string source_fingerprint = 8; +} + +/** + * Information about all the attempts the device make before finishing the + * successful update. + * Logged from platform/system/update_engine/metrics_reporter_android.cc + */ +message UpdateEngineSuccessfulUpdateReported { + // The number of attempts for the update engine to apply the payload for a + // successful update. + optional int32 attempt_count = 1; + + optional android.stats.otaupdate.PayloadType payload_type = 2; + + optional int32 payload_size_mib = 3; + + // The total number of bytes downloaded by update_engine since the last + // successful update. + optional int32 total_bytes_downloaded_mib = 4; + + // The ratio in percentage of the over-downloaded bytes compared to the + // total bytes needed to successfully install the update. e.g. 200 if we + // download 200MiB in total for a 100MiB package. + optional int32 download_overhead_percentage = 5; + + // The total time in minutes for the update engine to apply the payload for a + // successful update. + optional int32 total_duration_minutes = 6; + + // The number of reboot of the device during a successful update. + optional int32 reboot_count = 7; +} diff --git a/core/java/android/app/AppOpsManagerInternal.java b/core/java/android/app/AppOpsManagerInternal.java index 08cad04401e9..996939eb9ee1 100644 --- a/core/java/android/app/AppOpsManagerInternal.java +++ b/core/java/android/app/AppOpsManagerInternal.java @@ -16,7 +16,6 @@ package android.app; -import android.annotation.NonNull; import android.util.SparseIntArray; import com.android.internal.util.function.QuadFunction; @@ -77,38 +76,10 @@ public abstract class AppOpsManagerInternal { public abstract void setDeviceAndProfileOwners(SparseIntArray owners); /** - * Sets the app-ops mode for a certain app-op and uid. - * - * <p>Similar as {@link AppOpsManager#setUidMode} but does not require the package manager to be - * working. Hence this can be used very early during boot. - * - * <p>Only for internal callers. Does <u>not</u> verify that package name belongs to uid. - * - * @param code The op code to set. - * @param uid The UID for which to set. - * @param mode The new mode to set. - */ - public abstract void setUidMode(int code, int uid, int mode); - - /** * Set all {@link #setMode (package) modes} for this uid to the default value. * * @param code The app-op * @param uid The uid */ public abstract void setAllPkgModesToDefault(int code, int uid); - - /** - * Get the (raw) mode of an app-op. - * - * <p>Does <u>not</u> verify that package belongs to uid. The caller needs to do that. - * - * @param code The code of the op - * @param uid The uid of the package the op belongs to - * @param packageName The package the op belongs to - * - * @return The mode of the op - */ - public abstract @AppOpsManager.Mode int checkOperationUnchecked(int code, int uid, - @NonNull String packageName); } diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java index b1d791b58a79..8ad2b36ae0da 100644 --- a/core/java/android/app/NotificationChannel.java +++ b/core/java/android/app/NotificationChannel.java @@ -15,6 +15,8 @@ */ package android.app; +import static android.annotation.SystemApi.Client.MODULE_APPS; + import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; @@ -317,9 +319,14 @@ public final class NotificationChannel implements Parcelable { } /** + * Allows users to block notifications sent through this channel, if this channel belongs to + * a package that is signed with the system signature. If the channel does not belong to a + * package that is signed with the system signature, this method does nothing. + * @param blockableSystem if {@code true}, allows users to block notifications on this channel. * @hide */ - @UnsupportedAppUsage + @SystemApi(client = MODULE_APPS) + @TestApi public void setBlockableSystem(boolean blockableSystem) { mBlockableSystem = blockableSystem; } @@ -639,6 +646,7 @@ public final class NotificationChannel implements Parcelable { /** * @hide */ + @TestApi public boolean isBlockableSystem() { return mBlockableSystem; } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 12d3c59c2bbb..79a2c9010f35 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -6993,7 +6993,9 @@ public class DevicePolicyManager { * @param userHandle The user for whom to check the caller-id permission * @hide */ - public boolean getBluetoothContactSharingDisabled(UserHandle userHandle) { + @SystemApi + @RequiresPermission(permission.INTERACT_ACROSS_USERS) + public boolean getBluetoothContactSharingDisabled(@NonNull UserHandle userHandle) { if (mService != null) { try { return mService.getBluetoothContactSharingDisabledForUser(userHandle diff --git a/core/java/android/app/timedetector/PhoneTimeSuggestion.java b/core/java/android/app/timedetector/PhoneTimeSuggestion.java index 479e4b4efb4c..bd649f88f40a 100644 --- a/core/java/android/app/timedetector/PhoneTimeSuggestion.java +++ b/core/java/android/app/timedetector/PhoneTimeSuggestion.java @@ -18,6 +18,7 @@ package android.app.timedetector; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.os.TimestampedValue; @@ -28,17 +29,23 @@ import java.util.List; import java.util.Objects; /** - * A time signal from a telephony source. The value can be {@code null} to indicate that the - * telephony source has entered an "un-opinionated" state and any previously sent suggestions are - * being withdrawn. When not {@code null}, the value consists of the number of milliseconds elapsed - * since 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime clock when that number - * was established. The elapsed realtime clock is considered accurate but volatile, so time signals - * must not be persisted across device resets. + * A time suggestion from an identified telephony source. e.g. from NITZ information from a specific + * radio. + * + * <p>The time value can be {@code null} to indicate that the telephony source has entered an + * "un-opinionated" state and any previous suggestions from the source are being withdrawn. When not + * {@code null}, the value consists of the number of milliseconds elapsed since 1/1/1970 00:00:00 + * UTC and the time according to the elapsed realtime clock when that number was established. The + * elapsed realtime clock is considered accurate but volatile, so time suggestions must not be + * persisted across device resets. * * @hide */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public final class PhoneTimeSuggestion implements Parcelable { + /** @hide */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public static final @NonNull Parcelable.Creator<PhoneTimeSuggestion> CREATOR = new Parcelable.Creator<PhoneTimeSuggestion>() { public PhoneTimeSuggestion createFromParcel(Parcel in) { @@ -85,15 +92,27 @@ public final class PhoneTimeSuggestion implements Parcelable { dest.writeList(mDebugInfo); } + /** + * Returns an identifier for the source of this suggestion. When a device has several "phones", + * i.e. sim slots or equivalent, it is used to identify which one. + */ public int getPhoneId() { return mPhoneId; } + /** + * Returns the suggestion. {@code null} means that the caller is no longer sure what time it + * is. + */ @Nullable public TimestampedValue<Long> getUtcTime() { return mUtcTime; } + /** + * Returns debug metadata for the suggestion. The information is present in {@link #toString()} + * but is not considered for {@link #equals(Object)} and {@link #hashCode()}. + */ @NonNull public List<String> getDebugInfo() { return mDebugInfo == null @@ -105,7 +124,7 @@ public final class PhoneTimeSuggestion implements Parcelable { * information is present in {@link #toString()} but is not considered for * {@link #equals(Object)} and {@link #hashCode()}. */ - public void addDebugInfo(String debugInfo) { + public void addDebugInfo(@NonNull String debugInfo) { if (mDebugInfo == null) { mDebugInfo = new ArrayList<>(); } @@ -156,16 +175,19 @@ public final class PhoneTimeSuggestion implements Parcelable { * * @hide */ - public static class Builder { + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final class Builder { private final int mPhoneId; - private TimestampedValue<Long> mUtcTime; - private List<String> mDebugInfo; + @Nullable private TimestampedValue<Long> mUtcTime; + @Nullable private List<String> mDebugInfo; + /** Creates a builder with the specified {@code phoneId}. */ public Builder(int phoneId) { mPhoneId = phoneId; } /** Returns the builder for call chaining. */ + @NonNull public Builder setUtcTime(@Nullable TimestampedValue<Long> utcTime) { if (utcTime != null) { // utcTime can be null, but the value it holds cannot. @@ -177,6 +199,7 @@ public final class PhoneTimeSuggestion implements Parcelable { } /** Returns the builder for call chaining. */ + @NonNull public Builder addDebugInfo(@NonNull String debugInfo) { if (mDebugInfo == null) { mDebugInfo = new ArrayList<>(); @@ -186,6 +209,7 @@ public final class PhoneTimeSuggestion implements Parcelable { } /** Returns the {@link PhoneTimeSuggestion}. */ + @NonNull public PhoneTimeSuggestion build() { return new PhoneTimeSuggestion(this); } diff --git a/core/java/android/app/timedetector/TimeDetector.java b/core/java/android/app/timedetector/TimeDetector.java index 54dd1bed5361..7c29f017c02b 100644 --- a/core/java/android/app/timedetector/TimeDetector.java +++ b/core/java/android/app/timedetector/TimeDetector.java @@ -18,6 +18,7 @@ package android.app.timedetector; import android.annotation.NonNull; import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; import android.os.RemoteException; @@ -29,8 +30,11 @@ import android.util.Log; /** * The interface through which system components can send signals to the TimeDetectorService. + * + * <p>This class is marked non-final for mockito. * @hide */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @SystemService(Context.TIME_DETECTOR_SERVICE) public class TimeDetector { private static final String TAG = "timedetector.TimeDetector"; @@ -38,6 +42,7 @@ public class TimeDetector { private final ITimeDetectorService mITimeDetectorService; + /** @hide */ public TimeDetector() throws ServiceNotFoundException { mITimeDetectorService = ITimeDetectorService.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.TIME_DETECTOR_SERVICE)); @@ -62,6 +67,8 @@ public class TimeDetector { /** * Suggests the user's manually entered current time to the detector. + * + * @hide */ @RequiresPermission(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE) public void suggestManualTime(@NonNull ManualTimeSuggestion timeSuggestion) { @@ -77,6 +84,8 @@ public class TimeDetector { /** * A shared utility method to create a {@link ManualTimeSuggestion}. + * + * @hide */ public static ManualTimeSuggestion createManualTimeSuggestion(long when, String why) { TimestampedValue<Long> utcTime = @@ -88,6 +97,8 @@ public class TimeDetector { /** * Suggests the time according to a network time source like NTP. + * + * @hide */ @RequiresPermission(android.Manifest.permission.SET_TIME) public void suggestNetworkTime(NetworkTimeSuggestion timeSuggestion) { diff --git a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java b/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java index e8162488394c..d71ffcb9f772 100644 --- a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java +++ b/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java @@ -19,6 +19,7 @@ package android.app.timezonedetector; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; @@ -30,12 +31,27 @@ import java.util.List; import java.util.Objects; /** - * A suggested time zone from a Phone-based signal, e.g. from MCC and NITZ information. + * A time zone suggestion from an identified telephony source, e.g. from MCC and NITZ information + * associated with a specific radio. + * + * <p>The time zone ID can be {@code null} to indicate that the telephony source has entered an + * "un-opinionated" state and any previous suggestions from that source are being withdrawn. + * When not {@code null}, the value consists of a suggested time zone ID and metadata that can be + * used to judge quality / certainty of the suggestion. + * + * <p>{@code matchType} must be set to {@link #MATCH_TYPE_NA} when {@code zoneId} is {@code null}, + * and one of the other {@code MATCH_TYPE_} values when it is not {@code null}. + * + * <p>{@code quality} must be set to {@link #QUALITY_NA} when {@code zoneId} is {@code null}, + * and one of the other {@code QUALITY_} values when it is not {@code null}. * * @hide */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public final class PhoneTimeZoneSuggestion implements Parcelable { + /** @hide */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @NonNull public static final Creator<PhoneTimeZoneSuggestion> CREATOR = new Creator<PhoneTimeZoneSuggestion>() { @@ -58,6 +74,7 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { return new Builder(phoneId).addDebugInfo(debugInfo).build(); } + /** @hide */ @IntDef({ MATCH_TYPE_NA, MATCH_TYPE_NETWORK_COUNTRY_ONLY, MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET, MATCH_TYPE_EMULATOR_ZONE_ID, MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY }) @Retention(RetentionPolicy.SOURCE) @@ -90,6 +107,7 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { */ public static final int MATCH_TYPE_TEST_NETWORK_OFFSET_ONLY = 5; + /** @hide */ @IntDef({ QUALITY_NA, QUALITY_SINGLE_ZONE, QUALITY_MULTIPLE_ZONES_WITH_SAME_OFFSET, QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS }) @Retention(RetentionPolicy.SOURCE) @@ -115,7 +133,7 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { /** * The ID of the phone this suggestion is associated with. For multiple-sim devices this - * helps to establish origin so filtering / stickiness can be implemented. + * helps to establish source so filtering / stickiness can be implemented. */ private final int mPhoneId; @@ -123,6 +141,7 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { * The suggestion. {@code null} means there is no current suggestion and any previous suggestion * should be forgotten. */ + @Nullable private final String mZoneId; /** @@ -139,9 +158,10 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { private final int mQuality; /** - * Free-form debug information about how the signal was derived. Used for debug only, + * Free-form debug information about how the suggestion was derived. Used for debug only, * intentionally not used in equals(), etc. */ + @Nullable private List<String> mDebugInfo; private PhoneTimeZoneSuggestion(Builder builder) { @@ -182,25 +202,47 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { return 0; } + /** + * Returns an identifier for the source of this suggestion. When a device has several "phones", + * i.e. sim slots or equivalent, it is used to identify which one. + */ public int getPhoneId() { return mPhoneId; } + /** + * Returns the suggested time zone Olson ID, e.g. "America/Los_Angeles". {@code null} means that + * the caller is no longer sure what the current time zone is. See + * {@link PhoneTimeZoneSuggestion} for the associated {@code matchType} / {@code quality} rules. + */ @Nullable public String getZoneId() { return mZoneId; } + /** + * Returns information about how the suggestion was determined which could be used to rank + * suggestions when several are available from different sources. See + * {@link PhoneTimeZoneSuggestion} for the associated rules. + */ @MatchType public int getMatchType() { return mMatchType; } + /** + * Returns information about the likelihood of the suggested zone being correct. See + * {@link PhoneTimeZoneSuggestion} for the associated rules. + */ @Quality public int getQuality() { return mQuality; } + /** + * Returns debug metadata for the suggestion. The information is present in {@link #toString()} + * but is not considered for {@link #equals(Object)} and {@link #hashCode()}. + */ @NonNull public List<String> getDebugInfo() { return mDebugInfo == null @@ -267,36 +309,43 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { * * @hide */ - public static class Builder { + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final class Builder { private final int mPhoneId; - private String mZoneId; + @Nullable private String mZoneId; @MatchType private int mMatchType; @Quality private int mQuality; - private List<String> mDebugInfo; + @Nullable private List<String> mDebugInfo; public Builder(int phoneId) { mPhoneId = phoneId; } - /** Returns the builder for call chaining. */ - public Builder setZoneId(String zoneId) { + /** + * Returns the builder for call chaining. + */ + @NonNull + public Builder setZoneId(@Nullable String zoneId) { mZoneId = zoneId; return this; } /** Returns the builder for call chaining. */ + @NonNull public Builder setMatchType(@MatchType int matchType) { mMatchType = matchType; return this; } /** Returns the builder for call chaining. */ + @NonNull public Builder setQuality(@Quality int quality) { mQuality = quality; return this; } /** Returns the builder for call chaining. */ + @NonNull public Builder addDebugInfo(@NonNull String debugInfo) { if (mDebugInfo == null) { mDebugInfo = new ArrayList<>(); @@ -333,6 +382,7 @@ public final class PhoneTimeZoneSuggestion implements Parcelable { } /** Returns the {@link PhoneTimeZoneSuggestion}. */ + @NonNull public PhoneTimeZoneSuggestion build() { validate(); return new PhoneTimeZoneSuggestion(this); diff --git a/core/java/android/app/timezonedetector/TimeZoneDetector.java b/core/java/android/app/timezonedetector/TimeZoneDetector.java index e165d8a76caa..5b5f311264e3 100644 --- a/core/java/android/app/timezonedetector/TimeZoneDetector.java +++ b/core/java/android/app/timezonedetector/TimeZoneDetector.java @@ -18,6 +18,7 @@ package android.app.timezonedetector; import android.annotation.NonNull; import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; import android.os.RemoteException; @@ -28,8 +29,10 @@ import android.util.Log; /** * The interface through which system components can send signals to the TimeZoneDetectorService. * + * <p>This class is non-final for mockito. * @hide */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @SystemService(Context.TIME_ZONE_DETECTOR_SERVICE) public class TimeZoneDetector { private static final String TAG = "timezonedetector.TimeZoneDetector"; @@ -37,6 +40,7 @@ public class TimeZoneDetector { private final ITimeZoneDetectorService mITimeZoneDetectorService; + /** @hide */ public TimeZoneDetector() throws ServiceNotFoundException { mITimeZoneDetectorService = ITimeZoneDetectorService.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.TIME_ZONE_DETECTOR_SERVICE)); @@ -46,7 +50,10 @@ public class TimeZoneDetector { * Suggests the current time zone, determined using telephony signals, to the detector. The * detector may ignore the signal based on system settings, whether better information is * available, and so on. + * + * @hide */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @RequiresPermission(android.Manifest.permission.SUGGEST_PHONE_TIME_AND_ZONE) public void suggestPhoneTimeZone(@NonNull PhoneTimeZoneSuggestion timeZoneSuggestion) { if (DEBUG) { @@ -62,6 +69,8 @@ public class TimeZoneDetector { /** * Suggests the current time zone, determined for the user's manually information, to the * detector. The detector may ignore the signal based on system settings. + * + * @hide */ @RequiresPermission(android.Manifest.permission.SUGGEST_MANUAL_TIME_AND_ZONE) public void suggestManualTimeZone(@NonNull ManualTimeZoneSuggestion timeZoneSuggestion) { @@ -77,6 +86,8 @@ public class TimeZoneDetector { /** * A shared utility method to create a {@link ManualTimeZoneSuggestion}. + * + * @hide */ public static ManualTimeZoneSuggestion createManualTimeZoneSuggestion(String tzId, String why) { ManualTimeZoneSuggestion suggestion = new ManualTimeZoneSuggestion(tzId); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index f2f905126715..cd4af968ebfc 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -30,6 +30,7 @@ import android.annotation.StringDef; import android.annotation.StringRes; import android.annotation.StyleRes; import android.annotation.StyleableRes; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; import android.annotation.UserIdInt; @@ -3827,6 +3828,7 @@ public abstract class Context { */ @SystemApi @TestApi + @SuppressLint("ServiceName") public static final String STATUS_BAR_SERVICE = "statusbar"; /** @@ -3921,6 +3923,7 @@ public abstract class Context { public static final String NETWORK_STATS_SERVICE = "netstats"; /** {@hide} */ @SystemApi + @SuppressLint("ServiceName") public static final String NETWORK_POLICY_SERVICE = "netpolicy"; /** {@hide} */ public static final String NETWORK_WATCHLIST_SERVICE = "network_watchlist"; @@ -4230,6 +4233,7 @@ public abstract class Context { * @see #getSystemService(String) */ @TestApi + @SuppressLint("ServiceName") // TODO: This should be renamed to CONTENT_CAPTURE_SERVICE public static final String CONTENT_CAPTURE_MANAGER_SERVICE = "content_capture"; /** diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index 9c7bf1f7c996..9cba7aab3c87 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -4011,6 +4011,7 @@ public class Intent implements Parcelable, Cloneable { * <p> * @see #EXTRA_SIM_STATE * @see #EXTRA_SIM_LOCKED_REASON + * @see #EXTRA_REBROADCAST_ON_UNLOCK * * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED} or * {@link #ACTION_SIM_APPLICATION_STATE_CHANGED} @@ -4187,6 +4188,18 @@ public class Intent implements Parcelable, Cloneable { public static final String SIM_ABSENT_ON_PERM_DISABLED = "PERM_DISABLED"; /** + * The extra used with {@link #ACTION_SIM_STATE_CHANGED} for indicating whether this broadcast + * is a rebroadcast on unlock. Defaults to {@code false} if not specified. + * + * @hide + * @deprecated Use {@link #ACTION_SIM_CARD_STATE_CHANGED} or + * {@link #ACTION_SIM_APPLICATION_STATE_CHANGED} + */ + @Deprecated + @SystemApi + public static final String EXTRA_REBROADCAST_ON_UNLOCK = "rebroadcastOnUnlock"; + + /** * Broadcast Action: indicate that the phone service state has changed. * The intent will have the following extra values:</p> * <p> diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java index 1142a07bc66c..2497ea9c7950 100644 --- a/core/java/android/hardware/biometrics/BiometricPrompt.java +++ b/core/java/android/hardware/biometrics/BiometricPrompt.java @@ -32,6 +32,7 @@ import android.os.CancellationSignal; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; +import android.security.identity.IdentityCredential; import android.text.TextUtils; import android.util.Log; @@ -401,6 +402,10 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan super(mac); } + public CryptoObject(@NonNull IdentityCredential credential) { + super(credential); + } + /** * Get {@link Signature} object. * @return {@link Signature} object or null if this doesn't contain one. @@ -424,6 +429,14 @@ public class BiometricPrompt implements BiometricAuthenticator, BiometricConstan public Mac getMac() { return super.getMac(); } + + /** + * Get {@link IdentityCredential} object. + * @return {@link IdentityCredential} object or null if this doesn't contain one. + */ + public @Nullable IdentityCredential getIdentityCredential() { + return super.getIdentityCredential(); + } } /** diff --git a/core/java/android/hardware/biometrics/CryptoObject.java b/core/java/android/hardware/biometrics/CryptoObject.java index 787dc6696cd3..0af18dfb0e3a 100644 --- a/core/java/android/hardware/biometrics/CryptoObject.java +++ b/core/java/android/hardware/biometrics/CryptoObject.java @@ -17,6 +17,7 @@ package android.hardware.biometrics; import android.annotation.NonNull; +import android.security.identity.IdentityCredential; import android.security.keystore.AndroidKeyStoreProvider; import java.security.Signature; @@ -26,7 +27,8 @@ import javax.crypto.Mac; /** * A wrapper class for the crypto objects supported by BiometricPrompt and FingerprintManager. - * Currently the framework supports {@link Signature}, {@link Cipher} and {@link Mac} objects. + * Currently the framework supports {@link Signature}, {@link Cipher}, {@link Mac} and + * {@link IdentityCredential} objects. * @hide */ public class CryptoObject { @@ -44,6 +46,10 @@ public class CryptoObject { mCrypto = mac; } + public CryptoObject(@NonNull IdentityCredential credential) { + mCrypto = credential; + } + /** * Get {@link Signature} object. * @return {@link Signature} object or null if this doesn't contain one. @@ -69,11 +75,23 @@ public class CryptoObject { } /** + * Get {@link IdentityCredential} object. + * @return {@link IdentityCredential} object or null if this doesn't contain one. + */ + public IdentityCredential getIdentityCredential() { + return mCrypto instanceof IdentityCredential ? (IdentityCredential) mCrypto : null; + } + + /** * @hide * @return the opId associated with this object or 0 if none */ public final long getOpId() { - return mCrypto != null - ? AndroidKeyStoreProvider.getKeyStoreOperationHandle(mCrypto) : 0; + if (mCrypto == null) { + return 0; + } else if (mCrypto instanceof IdentityCredential) { + return ((IdentityCredential) mCrypto).getCredstoreOperationHandle(); + } + return AndroidKeyStoreProvider.getKeyStoreOperationHandle(mCrypto); } }; diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java index 315af32580aa..16f96888bb0a 100644 --- a/core/java/android/hardware/fingerprint/FingerprintManager.java +++ b/core/java/android/hardware/fingerprint/FingerprintManager.java @@ -44,6 +44,7 @@ import android.os.Looper; import android.os.PowerManager; import android.os.RemoteException; import android.os.UserHandle; +import android.security.identity.IdentityCredential; import android.util.Slog; import java.security.Signature; @@ -125,6 +126,10 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing super(mac); } + public CryptoObject(@NonNull IdentityCredential credential) { + super(credential); + } + /** * Get {@link Signature} object. * @return {@link Signature} object or null if this doesn't contain one. @@ -148,6 +153,14 @@ public class FingerprintManager implements BiometricAuthenticator, BiometricFing public Mac getMac() { return super.getMac(); } + + /** + * Get {@link IdentityCredential} object. + * @return {@link IdentityCredential} object or null if this doesn't contain one. + */ + public @Nullable IdentityCredential getIdentityCredential() { + return super.getIdentityCredential(); + } } /** diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 929edf0835bb..e8740c8e5de0 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -662,7 +662,7 @@ public class ConnectivityManager { * {@hide} */ @Deprecated - @UnsupportedAppUsage + @SystemApi public static final int TYPE_WIFI_P2P = 13; /** @@ -3169,10 +3169,10 @@ public class ConnectivityManager { /** * @hide * Register a NetworkAgent with ConnectivityService. - * @return NetID corresponding to NetworkAgent. + * @return Network corresponding to NetworkAgent. */ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) - public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, + public Network registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, NetworkCapabilities nc, int score, NetworkMisc misc) { return registerNetworkAgent(messenger, ni, lp, nc, score, misc, NetworkProvider.ID_NONE); } @@ -3180,10 +3180,10 @@ public class ConnectivityManager { /** * @hide * Register a NetworkAgent with ConnectivityService. - * @return NetID corresponding to NetworkAgent. + * @return Network corresponding to NetworkAgent. */ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) - public int registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, + public Network registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, NetworkCapabilities nc, int score, NetworkMisc misc, int providerId) { try { return mService.registerNetworkAgent(messenger, ni, lp, nc, score, misc, providerId); @@ -3622,14 +3622,26 @@ public class ConnectivityManager { /** * Helper function to request a network with a particular legacy type. * - * This is temporarily public @hide so it can be called by system code that uses the - * NetworkRequest API to request networks but relies on CONNECTIVITY_ACTION broadcasts for - * instead network notifications. + * @deprecated This is temporarily public for tethering to backwards compatibility that uses + * the NetworkRequest API to request networks with legacy type and relies on + * CONNECTIVITY_ACTION broadcasts instead of NetworkCallbacks. New caller should use + * {@link #requestNetwork(NetworkRequest, NetworkCallback, Handler)} instead. * * TODO: update said system code to rely on NetworkCallbacks and make this method private. + + * @param request {@link NetworkRequest} describing this request. + * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note + * the callback must not be shared - it uniquely specifies this request. + * @param timeoutMs The time in milliseconds to attempt looking for a suitable network + * before {@link NetworkCallback#onUnavailable()} is called. The timeout must + * be a positive value (i.e. >0). + * @param legacyType to specify the network type(#TYPE_*). + * @param handler {@link Handler} to specify the thread upon which the callback will be invoked. * * @hide */ + @SystemApi + @Deprecated public void requestNetwork(@NonNull NetworkRequest request, @NonNull NetworkCallback networkCallback, int timeoutMs, int legacyType, @NonNull Handler handler) { diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index e6a0379ff629..3aee4d5da5f2 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -152,7 +152,7 @@ interface IConnectivityManager void declareNetworkRequestUnfulfillable(in NetworkRequest request); - int registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp, + Network registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp, in NetworkCapabilities nc, int score, in NetworkMisc misc, in int factorySerialNumber); NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities, diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl index 385cb1d68b57..72a6b397a30c 100644 --- a/core/java/android/net/INetworkPolicyManager.aidl +++ b/core/java/android/net/INetworkPolicyManager.aidl @@ -57,9 +57,6 @@ interface INetworkPolicyManager { @UnsupportedAppUsage boolean getRestrictBackground(); - /** Callback used to change internal state on tethering */ - void onTetheringChanged(String iface, boolean tethering); - /** Gets the restrict background status based on the caller's UID: 1 - disabled 2 - whitelisted diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index 5f6cc6eced5d..a5f7d536d8f6 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -44,9 +44,7 @@ import java.util.concurrent.atomic.AtomicBoolean; * @hide */ public abstract class NetworkAgent extends Handler { - // Guaranteed to be valid (not NETID_UNSET), otherwise registerNetworkAgent() would have thrown - // an exception. - public final int netId; + public final Network network; private volatile AsyncChannel mAsyncChannel; private final String LOG_TAG; @@ -245,7 +243,7 @@ public abstract class NetworkAgent extends Handler { if (VDBG) log("Registering NetworkAgent"); ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( Context.CONNECTIVITY_SERVICE); - netId = cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni), + network = cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni), new LinkProperties(lp), new NetworkCapabilities(nc), score, misc, providerId); } diff --git a/core/java/android/net/NetworkFactory.java b/core/java/android/net/NetworkFactory.java index 824ddb8dd260..e27103755e6d 100644 --- a/core/java/android/net/NetworkFactory.java +++ b/core/java/android/net/NetworkFactory.java @@ -115,13 +115,6 @@ public class NetworkFactory extends Handler { */ private static final int CMD_SET_FILTER = BASE + 3; - /** - * Sent by NetworkFactory to ConnectivityService to indicate that a request is - * unfulfillable. - * @see #releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest). - */ - public static final int EVENT_UNFULFILLABLE_REQUEST = BASE + 4; - private final Context mContext; private final ArrayList<Message> mPreConnectedQueue = new ArrayList<Message>(); private final String LOG_TAG; diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index c7b30096db29..ee4379a85b6b 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -300,22 +300,34 @@ public class NetworkRequest implements Parcelable { * this without a single transport set will generate an exception, as will * subsequently adding or removing transports after this is set. * </p> - * The interpretation of this {@code String} is bearer specific and bearers that use - * it should document their particulars. For example, Bluetooth may use some sort of - * device id while WiFi could used ssid and/or bssid. Cellular may use carrier spn. + * If the {@code networkSpecifier} is provided, it shall be interpreted as follows: + * <ul> + * <li>If the specifier can be parsed as an integer, it will be treated as a + * {@link android.net TelephonyNetworkSpecifier}, and the provided integer will be + * interpreted as a SubscriptionId. + * <li>If the value is an ethernet interface name, it will be treated as such. + * <li>For all other cases, the behavior is undefined. + * </ul> * - * @param networkSpecifier An {@code String} of opaque format used to specify the bearer - * specific network specifier where the bearer has a choice of - * networks. + * @param networkSpecifier A {@code String} of either a SubscriptionId in cellular + * network request or an ethernet interface name in ethernet + * network request. + * + * @deprecated Use {@link #setNetworkSpecifier(NetworkSpecifier)} instead. */ + @Deprecated public Builder setNetworkSpecifier(String networkSpecifier) { - /* - * A StringNetworkSpecifier does not accept null or empty ("") strings. When network - * specifiers were strings a null string and an empty string were considered equivalent. - * Hence no meaning is attached to a null or empty ("") string. - */ - return setNetworkSpecifier(TextUtils.isEmpty(networkSpecifier) ? null - : new StringNetworkSpecifier(networkSpecifier)); + try { + int subId = Integer.parseInt(networkSpecifier); + return setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder() + .setSubscriptionId(subId).build()); + } catch (NumberFormatException nfe) { + // A StringNetworkSpecifier does not accept null or empty ("") strings. When network + // specifiers were strings a null string and an empty string were considered + // equivalent. Hence no meaning is attached to a null or empty ("") string. + return setNetworkSpecifier(TextUtils.isEmpty(networkSpecifier) ? null + : new StringNetworkSpecifier(networkSpecifier)); + } } /** @@ -455,6 +467,19 @@ public class NetworkRequest implements Parcelable { } /** + * Returns true iff. the capabilities requested in this NetworkRequest are satisfied by the + * provided {@link NetworkCapabilities}. + * + * @param nc Capabilities that should satisfy this NetworkRequest. null capabilities do not + * satisfy any request. + * @hide + */ + @SystemApi + public boolean satisfiedBy(@Nullable NetworkCapabilities nc) { + return networkCapabilities.satisfiedByNetworkCapabilities(nc); + } + + /** * @see Builder#addTransportType(int) */ public boolean hasTransport(@Transport int transportType) { diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java index f6dc52522cb2..c233ec0e52cf 100644 --- a/core/java/android/net/NetworkScoreManager.java +++ b/core/java/android/net/NetworkScoreManager.java @@ -163,27 +163,26 @@ public class NetworkScoreManager { public static final String EXTRA_NEW_SCORER = "newScorer"; /** @hide */ - @IntDef({CACHE_FILTER_NONE, CACHE_FILTER_CURRENT_NETWORK, CACHE_FILTER_SCAN_RESULTS}) + @IntDef({SCORE_FILTER_NONE, SCORE_FILTER_CURRENT_NETWORK, SCORE_FILTER_SCAN_RESULTS}) @Retention(RetentionPolicy.SOURCE) - public @interface CacheUpdateFilter {} + public @interface ScoreUpdateFilter {} /** - * Do not filter updates sent to the cache. - * @hide + * Do not filter updates sent to the {@link NetworkScoreCallback}]. */ - public static final int CACHE_FILTER_NONE = 0; + public static final int SCORE_FILTER_NONE = 0; /** - * Only send cache updates when the network matches the connected network. - * @hide + * Only send updates to the {@link NetworkScoreCallback} when the network matches the connected + * network. */ - public static final int CACHE_FILTER_CURRENT_NETWORK = 1; + public static final int SCORE_FILTER_CURRENT_NETWORK = 1; /** - * Only send cache updates when the network is part of the current scan result set. - * @hide + * Only send updates to the {@link NetworkScoreCallback} when the network is part of the + * current scan result set. */ - public static final int CACHE_FILTER_SCAN_RESULTS = 2; + public static final int SCORE_FILTER_SCAN_RESULTS = 2; /** @hide */ @IntDef({RECOMMENDATIONS_ENABLED_FORCED_OFF, RECOMMENDATIONS_ENABLED_OFF, @@ -404,13 +403,13 @@ public class NetworkScoreManager { * @throws SecurityException if the caller does not hold the * {@link permission#REQUEST_NETWORK_SCORES} permission. * @throws IllegalArgumentException if a score cache is already registered for this type. - * @deprecated equivalent to registering for cache updates with CACHE_FILTER_NONE. + * @deprecated equivalent to registering for cache updates with {@link #SCORE_FILTER_NONE}. * @hide */ @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES) @Deprecated // migrate to registerNetworkScoreCache(int, INetworkScoreCache, int) public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache) { - registerNetworkScoreCache(networkType, scoreCache, CACHE_FILTER_NONE); + registerNetworkScoreCache(networkType, scoreCache, SCORE_FILTER_NONE); } /** @@ -418,7 +417,7 @@ public class NetworkScoreManager { * * @param networkType the type of network this cache can handle. See {@link NetworkKey#type} * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores - * @param filterType the {@link CacheUpdateFilter} to apply + * @param filterType the {@link ScoreUpdateFilter} to apply * @throws SecurityException if the caller does not hold the * {@link permission#REQUEST_NETWORK_SCORES} permission. * @throws IllegalArgumentException if a score cache is already registered for this type. @@ -426,7 +425,7 @@ public class NetworkScoreManager { */ @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES) public void registerNetworkScoreCache(int networkType, INetworkScoreCache scoreCache, - @CacheUpdateFilter int filterType) { + @ScoreUpdateFilter int filterType) { try { mService.registerNetworkScoreCache(networkType, scoreCache, filterType); } catch (RemoteException e) { @@ -510,7 +509,7 @@ public class NetworkScoreManager { * Register a network score callback. * * @param networkType the type of network this cache can handle. See {@link NetworkKey#type} - * @param filterType the {@link CacheUpdateFilter} to apply + * @param filterType the {@link ScoreUpdateFilter} to apply * @param callback implementation of {@link NetworkScoreCallback} that will be invoked when the * scores change. * @param executor The executor on which to execute the callbacks. @@ -522,7 +521,7 @@ public class NetworkScoreManager { @SystemApi @RequiresPermission(android.Manifest.permission.REQUEST_NETWORK_SCORES) public void registerNetworkScoreCallback(@NetworkKey.NetworkType int networkType, - @CacheUpdateFilter int filterType, + @ScoreUpdateFilter int filterType, @NonNull @CallbackExecutor Executor executor, @NonNull NetworkScoreCallback callback) throws SecurityException { if (callback == null || executor == null) { diff --git a/core/java/android/net/SocketKeepalive.java b/core/java/android/net/SocketKeepalive.java index fb224fbe1318..fc9a8f63c131 100644 --- a/core/java/android/net/SocketKeepalive.java +++ b/core/java/android/net/SocketKeepalive.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.os.Binder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -53,7 +54,11 @@ import java.util.concurrent.Executor; public abstract class SocketKeepalive implements AutoCloseable { static final String TAG = "SocketKeepalive"; - /** @hide */ + /** + * No errors. + * @hide + */ + @SystemApi public static final int SUCCESS = 0; /** @hide */ diff --git a/core/java/android/net/TelephonyNetworkSpecifier.java b/core/java/android/net/TelephonyNetworkSpecifier.java new file mode 100644 index 000000000000..726f77059707 --- /dev/null +++ b/core/java/android/net/TelephonyNetworkSpecifier.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2020 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 android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +/** + * NetworkSpecifier object for cellular network request. Apps should use the + * {@link TelephonyNetworkSpecifier.Builder} class to create an instance. + */ +public final class TelephonyNetworkSpecifier extends NetworkSpecifier implements Parcelable { + + private final int mSubId; + + /** + * Return the subscription Id of current TelephonyNetworkSpecifier object. + * + * @return The subscription id. + */ + public int getSubscriptionId() { + return mSubId; + } + + /** + * @hide + */ + public TelephonyNetworkSpecifier(int subId) { + this.mSubId = subId; + } + + public static final @NonNull Creator<TelephonyNetworkSpecifier> CREATOR = + new Creator<TelephonyNetworkSpecifier>() { + @Override + public TelephonyNetworkSpecifier createFromParcel(Parcel in) { + int subId = in.readInt(); + return new TelephonyNetworkSpecifier(subId); + } + + @Override + public TelephonyNetworkSpecifier[] newArray(int size) { + return new TelephonyNetworkSpecifier[size]; + } + }; + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mSubId); + } + + @Override + public int hashCode() { + return mSubId; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof TelephonyNetworkSpecifier)) { + return false; + } + + TelephonyNetworkSpecifier lhs = (TelephonyNetworkSpecifier) obj; + return mSubId == lhs.mSubId; + } + + @Override + public String toString() { + return new StringBuilder() + .append("TelephonyNetworkSpecifier [") + .append("mSubId = ").append(mSubId) + .append("]") + .toString(); + } + + /** @hide */ + @Override + public boolean satisfiedBy(NetworkSpecifier other) { + // Any generic requests should be satisfied by a specific telephony network. + // For simplicity, we treat null same as MatchAllNetworkSpecifier + return equals(other) || other == null || other instanceof MatchAllNetworkSpecifier; + } + + + /** + * Builder to create {@link TelephonyNetworkSpecifier} object. + */ + public static final class Builder { + // Integer.MIN_VALUE which is not a valid subId, services as the sentinel to check if + // subId was set + private static final int SENTINEL_SUB_ID = Integer.MIN_VALUE; + + private int mSubId; + + public Builder() { + mSubId = SENTINEL_SUB_ID; + } + + /** + * Set the subscription id. + * + * @param subId The subscription Id. + * @return Instance of {@link Builder} to enable the chaining of the builder method. + */ + public @NonNull Builder setSubscriptionId(int subId) { + mSubId = subId; + return this; + } + + /** + * Create a NetworkSpecifier for the cellular network request. + * + * @return TelephonyNetworkSpecifier object. + * @throws IllegalArgumentException when subscription Id is not provided through + * {@link #setSubscriptionId(int)}. + */ + public @NonNull TelephonyNetworkSpecifier build() { + if (mSubId == SENTINEL_SUB_ID) { + throw new IllegalArgumentException("Subscription Id is not provided."); + } + return new TelephonyNetworkSpecifier(mSubId); + } + } +} diff --git a/core/java/android/os/IVibratorService.aidl b/core/java/android/os/IVibratorService.aidl index 6b881fecad56..264ab6038ea6 100644 --- a/core/java/android/os/IVibratorService.aidl +++ b/core/java/android/os/IVibratorService.aidl @@ -24,7 +24,8 @@ interface IVibratorService { boolean hasVibrator(); boolean hasAmplitudeControl(); - boolean setAlwaysOnEffect(int id, in VibrationEffect effect, in AudioAttributes attributes); + boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, in VibrationEffect effect, + in AudioAttributes attributes); void vibrate(int uid, String opPkg, in VibrationEffect effect, in AudioAttributes attributes, String reason, IBinder token); void cancelVibrate(IBinder token); diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java index f585c75b6bb7..11a425d54621 100644 --- a/core/java/android/os/SystemVibrator.java +++ b/core/java/android/os/SystemVibrator.java @@ -70,13 +70,14 @@ public class SystemVibrator extends Vibrator { } @Override - public boolean setAlwaysOnEffect(int id, VibrationEffect effect, AudioAttributes attributes) { + public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, VibrationEffect effect, + AudioAttributes attributes) { if (mService == null) { Log.w(TAG, "Failed to set always-on effect; no vibrator service."); return false; } try { - return mService.setAlwaysOnEffect(id, effect, attributes); + return mService.setAlwaysOnEffect(uid, opPkg, alwaysOnId, effect, attributes); } catch (RemoteException e) { Log.w(TAG, "Failed to set always-on effect.", e); } diff --git a/core/java/android/os/TimestampedValue.java b/core/java/android/os/TimestampedValue.java index 348574ed43c7..f4c87ac9dfc9 100644 --- a/core/java/android/os/TimestampedValue.java +++ b/core/java/android/os/TimestampedValue.java @@ -18,6 +18,7 @@ package android.os; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import java.util.Objects; @@ -35,19 +36,27 @@ import java.util.Objects; * @param <T> the type of the value with an associated timestamp * @hide */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public final class TimestampedValue<T> implements Parcelable { private final long mReferenceTimeMillis; + @Nullable private final T mValue; - public TimestampedValue(long referenceTimeMillis, T value) { + public TimestampedValue(long referenceTimeMillis, @Nullable T value) { mReferenceTimeMillis = referenceTimeMillis; mValue = value; } + /** Returns the reference time value. See {@link TimestampedValue} for more information. */ public long getReferenceTimeMillis() { return mReferenceTimeMillis; } + /** + * Returns the value associated with the timestamp. See {@link TimestampedValue} for more + * information. + */ + @Nullable public T getValue() { return mValue; } @@ -86,6 +95,8 @@ public final class TimestampedValue<T> implements Parcelable { return one.mReferenceTimeMillis - two.mReferenceTimeMillis; } + /** @hide */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public static final @NonNull Parcelable.Creator<TimestampedValue<?>> CREATOR = new Parcelable.ClassLoaderCreator<TimestampedValue<?>>() { diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java index ccbb0f191f6f..ae75f3d0d7e6 100644 --- a/core/java/android/os/Vibrator.java +++ b/core/java/android/os/Vibrator.java @@ -155,7 +155,7 @@ public abstract class Vibrator { /** * Configure an always-on haptics effect. * - * @param id The board-specific always-on ID to configure. + * @param alwaysOnId The board-specific always-on ID to configure. * @param effect Vibration effect to assign to always-on id. Passing null will disable it. * @param attributes {@link AudioAttributes} corresponding to the vibration. For example, * specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or @@ -164,8 +164,17 @@ public abstract class Vibrator { * @hide */ @RequiresPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON) - public boolean setAlwaysOnEffect(int id, @Nullable VibrationEffect effect, - @Nullable AudioAttributes attributes) { + public boolean setAlwaysOnEffect(int alwaysOnId, @Nullable VibrationEffect effect, + @Nullable AudioAttributes attributes) { + return setAlwaysOnEffect(Process.myUid(), mPackageName, alwaysOnId, effect, attributes); + } + + /** + * @hide + */ + @RequiresPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON) + public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, + @Nullable VibrationEffect effect, @Nullable AudioAttributes attributes) { Log.w(TAG, "Always-on effects aren't supported"); return false; } diff --git a/core/java/android/os/image/DynamicSystemClient.java b/core/java/android/os/image/DynamicSystemClient.java index 921f0f2ab1e2..5cb33615fe22 100644 --- a/core/java/android/os/image/DynamicSystemClient.java +++ b/core/java/android/os/image/DynamicSystemClient.java @@ -256,9 +256,13 @@ public class DynamicSystemClient { mService.send(msg); } catch (RemoteException e) { Slog.e(TAG, "Unable to get status from installation service"); - mExecutor.execute(() -> { + if (mExecutor != null) { + mExecutor.execute(() -> { + mListener.onStatusChanged(STATUS_UNKNOWN, CAUSE_ERROR_IPC, 0, e); + }); + } else { mListener.onStatusChanged(STATUS_UNKNOWN, CAUSE_ERROR_IPC, 0, e); - }); + } } } diff --git a/core/java/android/os/image/DynamicSystemManager.java b/core/java/android/os/image/DynamicSystemManager.java index 4c92c28c1bfa..cbf531c5730a 100644 --- a/core/java/android/os/image/DynamicSystemManager.java +++ b/core/java/android/os/image/DynamicSystemManager.java @@ -106,9 +106,9 @@ public class DynamicSystemManager { * @return true if the call succeeds */ @RequiresPermission(android.Manifest.permission.MANAGE_DYNAMIC_SYSTEM) - public boolean startInstallation() { + public boolean startInstallation(String dsuSlot) { try { - return mService.startInstallation(); + return mService.startInstallation(dsuSlot); } catch (RemoteException e) { throw new RuntimeException(e.toString()); } diff --git a/core/java/android/os/image/IDynamicSystemService.aidl b/core/java/android/os/image/IDynamicSystemService.aidl index 69cbab2c68ad..cc32f998d0c2 100644 --- a/core/java/android/os/image/IDynamicSystemService.aidl +++ b/core/java/android/os/image/IDynamicSystemService.aidl @@ -22,9 +22,10 @@ interface IDynamicSystemService { /** * Start DynamicSystem installation. + * @param dsuSlot Name used to identify this installation * @return true if the call succeeds */ - boolean startInstallation(); + boolean startInstallation(@utf8InCpp String dsuSlot); /** * Create a DSU partition. This call may take 60~90 seconds. The caller diff --git a/core/java/android/se/omapi/SEService.java b/core/java/android/se/omapi/SEService.java index 00060ab8ef4a..a5c5c613e1f2 100644 --- a/core/java/android/se/omapi/SEService.java +++ b/core/java/android/se/omapi/SEService.java @@ -98,6 +98,8 @@ public final class SEService { private static final String TAG = "OMAPI.SEService"; + private static final String UICC_TERMINAL = "SIM"; + private final Object mLock = new Object(); /** The client context (e.g. activity). */ @@ -190,32 +192,33 @@ public final class SEService { * is of length 0. */ public @NonNull Reader[] getReaders() { - if (mSecureElementService == null) { - throw new IllegalStateException("service not connected to system"); - } - String[] readerNames; - try { - readerNames = mSecureElementService.getReaders(); - } catch (RemoteException e) { - throw new RuntimeException(e); - } + loadReaders(); - Reader[] readers = new Reader[readerNames.length]; - int i = 0; - for (String readerName : readerNames) { - if (mReaders.get(readerName) == null) { - try { - mReaders.put(readerName, new Reader(this, readerName, - getReader(readerName))); - readers[i++] = mReaders.get(readerName); - } catch (Exception e) { - Log.e(TAG, "Error adding Reader: " + readerName, e); - } - } else { - readers[i++] = mReaders.get(readerName); - } - } - return readers; + return mReaders.values().toArray(new Reader[0]); + } + + /** + * Obtain a UICC Reader instance with specific slot number from the SecureElementService + * + * @param slotNumber The index of the uicc slot. The index starts from 1. + * @throws IllegalArgumentException if the reader object corresponding to the uiccSlotNumber + * is not exist. + * @return A Reader object for this uicc slot. + */ + public @NonNull Reader getUiccReader(int slotNumber) { + if (slotNumber < 1) { + throw new IllegalArgumentException("slotNumber should be larger than 0"); + } + loadReaders(); + + String readerName = UICC_TERMINAL + slotNumber; + Reader reader = mReaders.get(readerName); + + if (reader == null) { + throw new IllegalArgumentException("Reader:" + readerName + " doesn't exist"); + } + + return reader; } /** @@ -270,4 +273,30 @@ public final class SEService { throw new IllegalStateException(e.getMessage()); } } + + /** + * Load available Secure Element Readers + */ + private void loadReaders() { + if (mSecureElementService == null) { + throw new IllegalStateException("service not connected to system"); + } + String[] readerNames; + try { + readerNames = mSecureElementService.getReaders(); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + + for (String readerName : readerNames) { + if (mReaders.get(readerName) == null) { + try { + mReaders.put(readerName, new Reader(this, readerName, + getReader(readerName))); + } catch (Exception e) { + Log.e(TAG, "Error adding Reader: " + readerName, e); + } + } + } + } } diff --git a/core/java/android/timezone/CountryTimeZones.java b/core/java/android/timezone/CountryTimeZones.java new file mode 100644 index 000000000000..ada59d6d7d55 --- /dev/null +++ b/core/java/android/timezone/CountryTimeZones.java @@ -0,0 +1,265 @@ +/* + * 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.timezone; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; +import android.icu.util.TimeZone; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; + +/** + * Information about a country's time zones. + * + * @hide + */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public final class CountryTimeZones { + + /** + * A mapping to a time zone ID with some associated metadata. + * + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final class TimeZoneMapping { + + private libcore.timezone.CountryTimeZones.TimeZoneMapping mDelegate; + + TimeZoneMapping(libcore.timezone.CountryTimeZones.TimeZoneMapping delegate) { + this.mDelegate = Objects.requireNonNull(delegate); + } + + /** + * Returns the ID for this mapping. See also {@link #getTimeZone()} which handles when the + * ID is unrecognized. + */ + @NonNull + public String getTimeZoneId() { + return mDelegate.timeZoneId; + } + + /** + * Returns a {@link TimeZone} object for this mapping, or {@code null} if the ID is + * unrecognized. + */ + @Nullable + public TimeZone getTimeZone() { + return mDelegate.getTimeZone(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TimeZoneMapping that = (TimeZoneMapping) o; + return this.mDelegate.equals(that.mDelegate); + } + + @Override + public int hashCode() { + return this.mDelegate.hashCode(); + } + + @Override + public String toString() { + return mDelegate.toString(); + } + } + + /** + * The result of lookup up a time zone using offset information (and possibly more). + * + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + public static final class OffsetResult { + + private final TimeZone mTimeZone; + private final boolean mIsOnlyMatch; + + /** Creates an instance with the supplied information. */ + public OffsetResult(@NonNull TimeZone timeZone, boolean isOnlyMatch) { + mTimeZone = Objects.requireNonNull(timeZone); + mIsOnlyMatch = isOnlyMatch; + } + + /** + * Returns a time zone that matches the supplied criteria. + */ + @NonNull + public TimeZone getTimeZone() { + return mTimeZone; + } + + /** + * Returns {@code true} if there is only one matching time zone for the supplied criteria. + */ + public boolean isOnlyMatch() { + return mIsOnlyMatch; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + OffsetResult that = (OffsetResult) o; + return mIsOnlyMatch == that.mIsOnlyMatch + && mTimeZone.getID().equals(that.mTimeZone.getID()); + } + + @Override + public int hashCode() { + return Objects.hash(mTimeZone, mIsOnlyMatch); + } + + @Override + public String toString() { + return "OffsetResult{" + + "mTimeZone=" + mTimeZone + + ", mIsOnlyMatch=" + mIsOnlyMatch + + '}'; + } + } + + @NonNull + private final libcore.timezone.CountryTimeZones mDelegate; + + CountryTimeZones(libcore.timezone.CountryTimeZones delegate) { + mDelegate = delegate; + } + + /** + * Returns true if the ISO code for the country is a match for the one specified. + */ + public boolean isForCountryCode(@NonNull String countryIso) { + return mDelegate.isForCountryCode(countryIso); + } + + /** + * Returns the default time zone ID for the country. Can return {@code null} in cases when no + * data is available or the time zone ID was not recognized. + */ + @Nullable + public String getDefaultTimeZoneId() { + return mDelegate.getDefaultTimeZoneId(); + } + + /** + * Returns the default time zone for the country. Can return {@code null} in cases when no data + * is available or the time zone ID was not recognized. + */ + @Nullable + public TimeZone getDefaultTimeZone() { + return mDelegate.getDefaultTimeZone(); + } + + /** + * Qualifier for a country's default time zone. {@code true} indicates whether the default + * would be a good choice <em>generally</em> when there's no other information available. + */ + public boolean isDefaultTimeZoneBoosted() { + return mDelegate.getDefaultTimeZoneBoost(); + } + + /** + * Returns true if the country has at least one zone that is the same as UTC at the given time. + */ + public boolean hasUtcZone(long whenMillis) { + return mDelegate.hasUtcZone(whenMillis); + } + + /** + * Returns a time zone for the country, if there is one, that matches the desired properties. If + * there are multiple matches and the {@code bias} is one of them then it is returned, otherwise + * an arbitrary match is returned based on the {@link #getEffectiveTimeZoneMappingsAt(long)} + * ordering. + * + * @param totalOffsetMillis the offset from UTC at {@code whenMillis} + * @param isDst the Daylight Savings Time state at {@code whenMillis}. {@code true} means DST, + * {@code false} means not DST, {@code null} means unknown + * @param dstOffsetMillis the part of {@code totalOffsetMillis} contributed by DST, only used if + * {@code isDst} is {@code true}. The value can be {@code null} if the DST offset is + * unknown + * @param whenMillis the UTC time to match against + * @param bias the time zone to prefer, can be {@code null} + */ + @Nullable + public OffsetResult lookupByOffsetWithBias(int totalOffsetMillis, @Nullable Boolean isDst, + @SuppressLint("AutoBoxing") @Nullable Integer dstOffsetMillis, long whenMillis, + @Nullable TimeZone bias) { + libcore.timezone.CountryTimeZones.OffsetResult delegateOffsetResult = + mDelegate.lookupByOffsetWithBias( + totalOffsetMillis, isDst, dstOffsetMillis, whenMillis, bias); + return delegateOffsetResult == null ? null : + new OffsetResult(delegateOffsetResult.mTimeZone, delegateOffsetResult.mOneMatch); + } + + /** + * Returns an immutable, ordered list of time zone mappings for the country in an undefined but + * "priority" order, filtered so that only "effective" time zone IDs are returned. An + * "effective" time zone is one that differs from another time zone used in the country after + * {@code whenMillis}. The list can be empty if there were no zones configured or the configured + * zone IDs were not recognized. + */ + @NonNull + public List<TimeZoneMapping> getEffectiveTimeZoneMappingsAt(long whenMillis) { + List<libcore.timezone.CountryTimeZones.TimeZoneMapping> delegateList = + mDelegate.getEffectiveTimeZoneMappingsAt(whenMillis); + + List<TimeZoneMapping> toReturn = new ArrayList<>(delegateList.size()); + for (libcore.timezone.CountryTimeZones.TimeZoneMapping delegateMapping : delegateList) { + toReturn.add(new TimeZoneMapping(delegateMapping)); + } + return Collections.unmodifiableList(toReturn); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + CountryTimeZones that = (CountryTimeZones) o; + return mDelegate.equals(that.mDelegate); + } + + @Override + public int hashCode() { + return Objects.hash(mDelegate); + } + + @Override + public String toString() { + return mDelegate.toString(); + } +} diff --git a/core/java/android/timezone/TelephonyLookup.java b/core/java/android/timezone/TelephonyLookup.java new file mode 100644 index 000000000000..39dbe85cb485 --- /dev/null +++ b/core/java/android/timezone/TelephonyLookup.java @@ -0,0 +1,71 @@ +/* + * 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.timezone; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; + +import com.android.internal.annotations.GuardedBy; + +import java.util.Objects; + +/** + * A class that can find time zone-related information about telephony networks. + * + * @hide + */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public class TelephonyLookup { + + private static Object sLock = new Object(); + @GuardedBy("sLock") + private static TelephonyLookup sInstance; + + @NonNull + private final libcore.timezone.TelephonyLookup mDelegate; + + /** + * Obtains an instance for use when resolving telephony time zone information. This method never + * returns {@code null}. + */ + @NonNull + public static TelephonyLookup getInstance() { + synchronized (sLock) { + if (sInstance == null) { + sInstance = new TelephonyLookup(libcore.timezone.TelephonyLookup.getInstance()); + } + return sInstance; + } + } + + private TelephonyLookup(@NonNull libcore.timezone.TelephonyLookup delegate) { + mDelegate = Objects.requireNonNull(delegate); + } + + /** + * Returns an object capable of querying telephony network information. This method can return + * {@code null} in the event of an error while reading the underlying data files. + */ + @Nullable + public TelephonyNetworkFinder getTelephonyNetworkFinder() { + libcore.timezone.TelephonyNetworkFinder telephonyNetworkFinderDelegate = + mDelegate.getTelephonyNetworkFinder(); + return telephonyNetworkFinderDelegate != null + ? new TelephonyNetworkFinder(telephonyNetworkFinderDelegate) : null; + } +} diff --git a/core/java/android/timezone/TelephonyNetwork.java b/core/java/android/timezone/TelephonyNetwork.java new file mode 100644 index 000000000000..ae39fbddfa1c --- /dev/null +++ b/core/java/android/timezone/TelephonyNetwork.java @@ -0,0 +1,86 @@ +/* + * 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.timezone; + +import android.annotation.NonNull; +import android.annotation.SystemApi; + +import java.util.Objects; + +/** + * Information about a telephony network. + * + * @hide + */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public class TelephonyNetwork { + + @NonNull + private final libcore.timezone.TelephonyNetwork mDelegate; + + TelephonyNetwork(@NonNull libcore.timezone.TelephonyNetwork delegate) { + mDelegate = Objects.requireNonNull(delegate); + } + + /** + * Returns the Mobile Country Code of the network. + */ + @NonNull + public String getMcc() { + return mDelegate.getMcc(); + } + + /** + * Returns the Mobile Network Code of the network. + */ + @NonNull + public String getMnc() { + return mDelegate.getMnc(); + } + + /** + * Returns the country in which the network operates as an ISO 3166 alpha-2 (lower case). + */ + @NonNull + public String getCountryIsoCode() { + return mDelegate.getCountryIsoCode(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + TelephonyNetwork that = (TelephonyNetwork) o; + return mDelegate.equals(that.mDelegate); + } + + @Override + public int hashCode() { + return Objects.hash(mDelegate); + } + + @Override + public String toString() { + return "TelephonyNetwork{" + + "mDelegate=" + mDelegate + + '}'; + } +} diff --git a/core/java/android/timezone/TelephonyNetworkFinder.java b/core/java/android/timezone/TelephonyNetworkFinder.java new file mode 100644 index 000000000000..a81a516c4b33 --- /dev/null +++ b/core/java/android/timezone/TelephonyNetworkFinder.java @@ -0,0 +1,55 @@ +/* + * 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.timezone; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; + +import java.util.Objects; + +/** + * A class that can find telephony networks loaded via {@link TelephonyLookup}. + * + * @hide + */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public class TelephonyNetworkFinder { + + @NonNull + private final libcore.timezone.TelephonyNetworkFinder mDelegate; + + TelephonyNetworkFinder(libcore.timezone.TelephonyNetworkFinder delegate) { + mDelegate = Objects.requireNonNull(delegate); + } + + /** + * Returns information held about a specific MCC + MNC combination. It is expected for this + * method to return {@code null}. Only known, unusual networks will typically have information + * returned, e.g. if they operate in countries other than the one suggested by their MCC. + */ + @Nullable + public TelephonyNetwork findNetworkByMccMnc(@NonNull String mcc, @NonNull String mnc) { + Objects.requireNonNull(mcc); + Objects.requireNonNull(mnc); + + libcore.timezone.TelephonyNetwork telephonyNetworkDelegate = + mDelegate.findNetworkByMccMnc(mcc, mnc); + return telephonyNetworkDelegate != null + ? new TelephonyNetwork(telephonyNetworkDelegate) : null; + } +} diff --git a/core/java/android/timezone/TimeZoneFinder.java b/core/java/android/timezone/TimeZoneFinder.java new file mode 100644 index 000000000000..15dfe62bb789 --- /dev/null +++ b/core/java/android/timezone/TimeZoneFinder.java @@ -0,0 +1,67 @@ +/* + * 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.timezone; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; + +import com.android.internal.annotations.GuardedBy; + +/** + * A class that can be used to find time zones. + * + * @hide + */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public final class TimeZoneFinder { + + private static Object sLock = new Object(); + @GuardedBy("sLock") + private static TimeZoneFinder sInstance; + + private final libcore.timezone.TimeZoneFinder mDelegate; + + private TimeZoneFinder(libcore.timezone.TimeZoneFinder delegate) { + mDelegate = delegate; + } + + /** + * Obtains an instance for use when resolving telephony time zone information. This method never + * returns {@code null}. + */ + @NonNull + public static TimeZoneFinder getInstance() { + synchronized (sLock) { + if (sInstance == null) { + sInstance = new TimeZoneFinder(libcore.timezone.TimeZoneFinder.getInstance()); + } + } + return sInstance; + } + + /** + * Returns a {@link CountryTimeZones} object associated with the specified country code. + * Caching is handled as needed. If the country code is not recognized or there is an error + * during lookup this method can return null. + */ + @Nullable + public CountryTimeZones lookupCountryTimeZones(@NonNull String countryIso) { + libcore.timezone.CountryTimeZones delegate = mDelegate.lookupCountryTimeZones(countryIso); + return delegate == null ? null : new CountryTimeZones(delegate); + } +} diff --git a/core/java/com/android/ims/internal/uce/uceservice/ImsUceManager.java b/core/java/com/android/ims/internal/uce/uceservice/ImsUceManager.java index 4b0b098d4e5b..9aee879f21da 100644 --- a/core/java/com/android/ims/internal/uce/uceservice/ImsUceManager.java +++ b/core/java/com/android/ims/internal/uce/uceservice/ImsUceManager.java @@ -18,16 +18,9 @@ package com.android.ims.internal.uce.uceservice; import android.content.Context; import android.content.Intent; - -import android.os.Handler; -import android.os.HandlerThread; import android.os.IBinder; -import android.os.Message; -import android.os.ServiceManager; import android.os.RemoteException; - -import java.util.HashMap; -import android.util.Log; +import android.os.ServiceManager; /** * ImsUceManager Declaration @@ -49,55 +42,25 @@ public class ImsUceManager { private IUceService mUceService = null; private UceServiceDeathRecipient mDeathReceipient = new UceServiceDeathRecipient(); private Context mContext; - private int mPhoneId; - /** - * Stores the UceManager instaces of Clients identified by - * phoneId - * @hide - */ - private static HashMap<Integer, ImsUceManager> sUceManagerInstances = - new HashMap<Integer, ImsUceManager>(); + private static final Object sLock = new Object(); + private static ImsUceManager sUceManager; public static final String ACTION_UCE_SERVICE_UP = "com.android.ims.internal.uce.UCE_SERVICE_UP"; public static final String ACTION_UCE_SERVICE_DOWN = "com.android.ims.internal.uce.UCE_SERVICE_DOWN"; - /** Uce Service status received in IUceListener.setStatus() - * callback - * @hide - */ - public static final int UCE_SERVICE_STATUS_FAILURE = 0; - /** indicate UI to call Presence/Options API. */ - public static final int UCE_SERVICE_STATUS_ON = 1; - /** Indicate UI destroy Presence/Options */ - public static final int UCE_SERVICE_STATUS_CLOSED = 2; - /** Service up and trying to register for network events */ - public static final int UCE_SERVICE_STATUS_READY = 3; - - /** - * Part of the ACTION_UCE_SERVICE_UP or _DOWN intents. A long - * value; the phone ID corresponding to the IMS service coming up or down. - * Internal use only. - * @hide - */ - public static final String EXTRA_PHONE_ID = "android:phone_id"; - /** * Gets the instance of UCE Manager * @hide */ - public static ImsUceManager getInstance(Context context, int phoneId) { - //if (DBG) Log.d (LOG_TAG, "GetInstance Called"); - synchronized (sUceManagerInstances) { - if (sUceManagerInstances.containsKey(phoneId)) { - return sUceManagerInstances.get(phoneId); - } else { - ImsUceManager uceMgr = new ImsUceManager(context, phoneId); - sUceManagerInstances.put(phoneId, uceMgr); - return uceMgr; + public static ImsUceManager getInstance(Context context) { + synchronized (sLock) { + if (sUceManager == null && context != null) { + sUceManager = new ImsUceManager(context); } + return sUceManager; } } @@ -105,10 +68,9 @@ public class ImsUceManager { * Constructor * @hide */ - private ImsUceManager(Context context, int phoneId) { + private ImsUceManager(Context context) { //if (DBG) Log.d (LOG_TAG, "Constructor"); mContext = context; - mPhoneId = phoneId; createUceService(true); } @@ -129,7 +91,7 @@ public class ImsUceManager { * Gets the UCE service name * @hide */ - private String getUceServiceName(int phoneId) { + private String getUceServiceName() { return UCE_SERVICE; } @@ -143,14 +105,14 @@ public class ImsUceManager { public void createUceService(boolean checkService) { //if (DBG) Log.d (LOG_TAG, "CreateUceService Called"); if (checkService) { - IBinder binder = ServiceManager.checkService(getUceServiceName(mPhoneId)); + IBinder binder = ServiceManager.checkService(getUceServiceName()); if (binder == null) { //if (DBG)Log.d (LOG_TAG, "Unable to find IBinder"); return; } } - IBinder b = ServiceManager.getService(getUceServiceName(mPhoneId)); + IBinder b = ServiceManager.getService(getUceServiceName()); if (b != null) { try { @@ -174,12 +136,10 @@ public class ImsUceManager { private class UceServiceDeathRecipient implements IBinder.DeathRecipient { @Override public void binderDied() { - //if (DBG) Log.d (LOG_TAG, "found IBinder/IUceService Service Died"); mUceService = null; if (mContext != null) { Intent intent = new Intent(ACTION_UCE_SERVICE_DOWN); - intent.putExtra(EXTRA_PHONE_ID, mPhoneId); mContext.sendBroadcast(new Intent(intent)); } } diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java index 179828c4b456..13d0c5c831b6 100644 --- a/core/java/com/android/internal/os/RuntimeInit.java +++ b/core/java/com/android/internal/os/RuntimeInit.java @@ -35,6 +35,7 @@ import com.android.internal.logging.AndroidConfig; import com.android.server.NetworkManagementSocketTagger; import dalvik.system.RuntimeHooks; +import dalvik.system.ThreadPrioritySetter; import dalvik.system.VMRuntime; import libcore.content.type.MimeMap; @@ -204,6 +205,7 @@ public class RuntimeInit { */ public static void preForkInit() { if (DEBUG) Slog.d(TAG, "Entered preForkInit."); + RuntimeHooks.setThreadPrioritySetter(new RuntimeThreadPrioritySetter()); RuntimeInit.enableDdms(); // TODO(b/142019040#comment13): Decide whether to load the default instance eagerly, i.e. // MimeMap.setDefault(DefaultMimeMapFactory.create()); @@ -216,6 +218,35 @@ public class RuntimeInit { MimeMap.setDefaultSupplier(DefaultMimeMapFactory::create); } + private static class RuntimeThreadPrioritySetter implements ThreadPrioritySetter { + // Should remain consistent with kNiceValues[] in system/libartpalette/palette_android.cc + private static final int[] NICE_VALUES = { + Process.THREAD_PRIORITY_LOWEST, // 1 (MIN_PRIORITY) + Process.THREAD_PRIORITY_BACKGROUND + 6, + Process.THREAD_PRIORITY_BACKGROUND + 3, + Process.THREAD_PRIORITY_BACKGROUND, + Process.THREAD_PRIORITY_DEFAULT, // 5 (NORM_PRIORITY) + Process.THREAD_PRIORITY_DEFAULT - 2, + Process.THREAD_PRIORITY_DEFAULT - 4, + Process.THREAD_PRIORITY_URGENT_DISPLAY + 3, + Process.THREAD_PRIORITY_URGENT_DISPLAY + 2, + Process.THREAD_PRIORITY_URGENT_DISPLAY // 10 (MAX_PRIORITY) + }; + + @Override + public void setPriority(int nativeTid, int priority) { + // Check NICE_VALUES[] length first. + if (NICE_VALUES.length != (1 + Thread.MAX_PRIORITY - Thread.MIN_PRIORITY)) { + throw new AssertionError("Unexpected NICE_VALUES.length=" + NICE_VALUES.length); + } + // Priority should be in the range of MIN_PRIORITY (1) to MAX_PRIORITY (10). + if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) { + throw new IllegalArgumentException("Priority out of range: " + priority); + } + Process.setThreadPriority(nativeTid, NICE_VALUES[priority - Thread.MIN_PRIORITY]); + } + } + @UnsupportedAppUsage protected static final void commonInit() { if (DEBUG) Slog.d(TAG, "Entered RuntimeInit!"); diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index 33adec106d97..c1c74dcfb9e6 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -35,6 +35,7 @@ import android.system.ErrnoException; import android.system.Os; import android.util.Log; +import dalvik.annotation.optimization.FastNative; import dalvik.system.ZygoteHooks; import libcore.io.IoUtils; @@ -49,9 +50,9 @@ import java.io.InputStreamReader; /** @hide */ public final class Zygote { /* - * Bit values for "runtimeFlags" argument. The definitions are duplicated - * in the native code. - */ + * Bit values for "runtimeFlags" argument. The definitions are duplicated + * in the native code. + */ /** enable debugging over JDWP */ public static final int DEBUG_ENABLE_JDWP = 1; @@ -187,6 +188,11 @@ public final class Zygote { */ public static final int SOCKET_BUFFER_SIZE = 256; + /** + * @hide for internal use only + */ + private static final int PRIORITY_MAX = -20; + /** a prototype instance for a future List.toArray() */ protected static final int[][] INT_ARRAY_2D = new int[0][0]; @@ -251,8 +257,7 @@ public final class Zygote { int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir, int targetSdkVersion) { ZygoteHooks.preFork(); - // Resets nice priority for zygote process. - resetNicePriority(); + int pid = nativeForkAndSpecialize( uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose, fdsToIgnore, startChildZygote, instructionSet, appDataDir); @@ -264,6 +269,10 @@ public final class Zygote { // Note that this event ends at the end of handleChildProc, Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork"); } + + // Set the Java Language thread priority to the default value for new apps. + Thread.currentThread().setPriority(Thread.NORM_PRIORITY); + ZygoteHooks.postForkCommon(); return pid; } @@ -298,7 +307,7 @@ public final class Zygote { int[][] rlimits, int mountExternal, String seInfo, String niceName, boolean startChildZygote, String instructionSet, String appDataDir) { nativeSpecializeAppProcess(uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, - niceName, startChildZygote, instructionSet, appDataDir); + niceName, startChildZygote, instructionSet, appDataDir); // Enable tracing as soon as possible for the child process. Trace.setTracingEnabled(true, runtimeFlags); @@ -306,6 +315,9 @@ public final class Zygote { // Note that this event ends at the end of handleChildProc. Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork"); + // Set the Java Language thread priority to the default value for new apps. + Thread.currentThread().setPriority(Thread.NORM_PRIORITY); + /* * This is called here (instead of after the fork but before the specialize) to maintain * consistancy with the code paths for forkAndSpecialize. @@ -350,15 +362,19 @@ public final class Zygote { public static int forkSystemServer(int uid, int gid, int[] gids, int runtimeFlags, int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) { ZygoteHooks.preFork(); - // Resets nice priority for zygote process. - resetNicePriority(); + int pid = nativeForkSystemServer( uid, gid, gids, runtimeFlags, rlimits, permittedCapabilities, effectiveCapabilities); + // Enable tracing as soon as we enter the system_server. if (pid == 0) { Trace.setTracingEnabled(true, runtimeFlags); } + + // Set the Java Language thread priority to the default value for new apps. + Thread.currentThread().setPriority(Thread.NORM_PRIORITY); + ZygoteHooks.postForkCommon(); return pid; } @@ -476,13 +492,16 @@ public final class Zygote { /** * Fork a new unspecialized app process from the zygote * + * @param usapPoolSocket The server socket the USAP will call accept on * @param sessionSocketRawFDs Anonymous session sockets that are currently open + * @param isPriorityFork Value controlling the process priority level until accept is called * @return In the Zygote process this function will always return null; in unspecialized app * processes this function will return a Runnable object representing the new * application that is passed up from usapMain. */ static Runnable forkUsap(LocalServerSocket usapPoolSocket, - int[] sessionSocketRawFDs) { + int[] sessionSocketRawFDs, + boolean isPriorityFork) { FileDescriptor[] pipeFDs = null; try { @@ -492,7 +511,8 @@ public final class Zygote { } int pid = - nativeForkUsap(pipeFDs[0].getInt$(), pipeFDs[1].getInt$(), sessionSocketRawFDs); + nativeForkUsap(pipeFDs[0].getInt$(), pipeFDs[1].getInt$(), + sessionSocketRawFDs, isPriorityFork); if (pid == 0) { IoUtils.closeQuietly(pipeFDs[0]); @@ -506,8 +526,9 @@ public final class Zygote { } private static native int nativeForkUsap(int readPipeFD, - int writePipeFD, - int[] sessionSocketRawFDs); + int writePipeFD, + int[] sessionSocketRawFDs, + boolean isPriorityFork); /** * This function is used by unspecialized app processes to wait for specialization requests from @@ -518,7 +539,7 @@ public final class Zygote { * @return A runnable oject representing the new application. */ private static Runnable usapMain(LocalServerSocket usapPoolSocket, - FileDescriptor writePipe) { + FileDescriptor writePipe) { final int pid = Process.myPid(); Process.setArgV0(Process.is64Bit() ? "usap64" : "usap32"); @@ -527,6 +548,11 @@ public final class Zygote { Credentials peerCredentials = null; ZygoteArguments args = null; + // Change the priority to max before calling accept so we can respond to new specialization + // requests as quickly as possible. This will be reverted to the default priority in the + // native specialization code. + boostUsapPriority(); + while (true) { try { sessionSocket = usapPoolSocket.accept(); @@ -568,6 +594,7 @@ public final class Zygote { try { // SIGTERM is blocked on loop exit. This prevents a USAP that is specializing from // being killed during a pool flush. + setAppProcessName(args, "USAP"); applyUidSecurityPolicy(args, peerCredentials); applyDebuggerSystemProperty(args); @@ -628,23 +655,18 @@ public final class Zygote { } specializeAppProcess(args.mUid, args.mGid, args.mGids, - args.mRuntimeFlags, rlimits, args.mMountExternal, - args.mSeInfo, args.mNiceName, args.mStartChildZygote, - args.mInstructionSet, args.mAppDataDir); + args.mRuntimeFlags, rlimits, args.mMountExternal, + args.mSeInfo, args.mNiceName, args.mStartChildZygote, + args.mInstructionSet, args.mAppDataDir); disableExecuteOnly(args.mTargetSdkVersion); - if (args.mNiceName != null) { - Process.setArgV0(args.mNiceName); - } - - // End of the postFork event. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); return ZygoteInit.zygoteInit(args.mTargetSdkVersion, - args.mDisabledCompatChanges, - args.mRemainingArgs, - null /* classLoader */); + args.mDisabledCompatChanges, + args.mRemainingArgs, + null /* classLoader */); } finally { // Unblock SIGTERM to restore the process to default behavior. unblockSigTerm(); @@ -663,6 +685,22 @@ public final class Zygote { private static native void nativeUnblockSigTerm(); + private static void boostUsapPriority() { + nativeBoostUsapPriority(); + } + + private static native void nativeBoostUsapPriority(); + + static void setAppProcessName(ZygoteArguments args, String loggingTag) { + if (args.mNiceName != null) { + Process.setArgV0(args.mNiceName); + } else if (args.mPackageName != null) { + Process.setArgV0(args.mPackageName); + } else { + Log.w(loggingTag, "Unable to set package name."); + } + } + private static final String USAP_ERROR_PREFIX = "Invalid command to USAP: "; /** @@ -685,7 +723,7 @@ public final class Zygote { throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--start-child-zygote"); } else if (args.mApiBlacklistExemptions != null) { throw new IllegalArgumentException( - USAP_ERROR_PREFIX + "--set-api-blacklist-exemptions"); + USAP_ERROR_PREFIX + "--set-api-blacklist-exemptions"); } else if (args.mHiddenApiAccessLogSampleRate != -1) { throw new IllegalArgumentException( USAP_ERROR_PREFIX + "--hidden-api-log-sampling-rate="); @@ -696,8 +734,8 @@ public final class Zygote { throw new IllegalArgumentException(USAP_ERROR_PREFIX + "--invoke-with"); } else if (args.mPermittedCapabilities != 0 || args.mEffectiveCapabilities != 0) { throw new ZygoteSecurityException("Client may not specify capabilities: " - + "permitted=0x" + Long.toHexString(args.mPermittedCapabilities) - + ", effective=0x" + Long.toHexString(args.mEffectiveCapabilities)); + + "permitted=0x" + Long.toHexString(args.mPermittedCapabilities) + + ", effective=0x" + Long.toHexString(args.mEffectiveCapabilities)); } } @@ -754,7 +792,7 @@ public final class Zygote { if (uidRestricted && args.mUidSpecified && (args.mUid < Process.SYSTEM_UID)) { throw new ZygoteSecurityException( "System UID may not launch process with UID < " - + Process.SYSTEM_UID); + + Process.SYSTEM_UID); } } @@ -804,8 +842,8 @@ public final class Zygote { if (args.mInvokeWith != null && peerUid != 0 && (args.mRuntimeFlags & Zygote.DEBUG_ENABLE_JDWP) == 0) { throw new ZygoteSecurityException("Peer is permitted to specify an " - + "explicit invoke-with wrapper command only for debuggable " - + "applications."); + + "explicit invoke-with wrapper command only for debuggable " + + "applications."); } } @@ -888,7 +926,7 @@ public final class Zygote { return new LocalServerSocket(fd); } catch (IOException ex) { throw new RuntimeException( - "Error building socket from file descriptor: " + fileDesc, ex); + "Error building socket from file descriptor: " + fileDesc, ex); } } @@ -903,15 +941,6 @@ public final class Zygote { } /** - * Resets the calling thread priority to the default value (Thread.NORM_PRIORITY - * or nice value 0). This updates both the priority value in java.lang.Thread and - * the nice value (setpriority). - */ - static void resetNicePriority() { - Thread.currentThread().setPriority(Thread.NORM_PRIORITY); - } - - /** * Executes "/system/bin/sh -c <command>" using the exec() system call. * This method throws a runtime exception if exec() failed, otherwise, this * method never returns. @@ -941,4 +970,19 @@ public final class Zygote { command.append(" '").append(arg.replace("'", "'\\''")).append("'"); } } + + /** + * Parse the given unsolicited zygote message as type SIGCHLD, + * extract the payload information into the given output buffer. + * + * @param in The unsolicited zygote message to be parsed + * @param length The number of bytes in the message + * @param out The output buffer where the payload information will be placed + * @return Number of elements being place into output buffer, or -1 if + * either the message is malformed or not the type as expected here. + * + * @hide + */ + @FastNative + public static native int nativeParseSigChld(byte[] in, int length, int[] out); } diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index e8d6681a1d17..2666d5278a90 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -346,7 +346,7 @@ class ZygoteConnection { if (zygoteServer.isUsapPoolEnabled()) { Runnable fpResult = zygoteServer.fillUsapPool( - new int[]{mSocket.getFileDescriptor().getInt$()}); + new int[]{mSocket.getFileDescriptor().getInt$()}, false); if (fpResult != null) { zygoteServer.setForkChild(); @@ -485,9 +485,7 @@ class ZygoteConnection { closeSocket(); - if (parsedArgs.mNiceName != null) { - Process.setArgV0(parsedArgs.mNiceName); - } + Zygote.setAppProcessName(parsedArgs, TAG); // End of the postFork event. Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index fd022376e6d3..348262e1a9d3 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -825,6 +825,18 @@ public class ZygoteInit { return result; } + /** + * This is the entry point for a Zygote process. It creates the Zygote server, loads resources, + * and handles other tasks related to preparing the process for forking into applications. + * + * This process is started with a nice value of -20 (highest priority). All paths that flow + * into new processes are required to either set the priority to the default value or terminate + * before executing any non-system code. The native side of this occurs in SpecializeCommon, + * while the Java Language priority is changed in ZygoteInit.handleSystemServerProcess, + * ZygoteConnection.handleChildProc, and Zygote.usapMain. + * + * @param argv Command line arguments used to specify the Zygote's configuration. + */ @UnsupportedAppUsage public static void main(String argv[]) { ZygoteServer zygoteServer = null; @@ -888,8 +900,6 @@ public class ZygoteInit { EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END, SystemClock.uptimeMillis()); bootTimingsTraceLog.traceEnd(); // ZygotePreload - } else { - Zygote.resetNicePriority(); } // Do an initial gc to clean up after startup diff --git a/core/java/com/android/internal/os/ZygoteServer.java b/core/java/com/android/internal/os/ZygoteServer.java index 1fd6e269348f..8d281b7ce9a0 100644 --- a/core/java/com/android/internal/os/ZygoteServer.java +++ b/core/java/com/android/internal/os/ZygoteServer.java @@ -66,6 +66,12 @@ class ZygoteServer { /** The default value used for the USAP_POOL_SIZE_MIN device property */ private static final String USAP_POOL_SIZE_MIN_DEFAULT = "1"; + /** The default value used for the USAP_REFILL_DELAY_MS device property */ + private static final String USAP_POOL_REFILL_DELAY_MS_DEFAULT = "3000"; + + /** The "not a timestamp" value for the refill delay timestamp mechanism. */ + private static final int INVALID_TIMESTAMP = -1; + /** * Indicates if this Zygote server can support a unspecialized app process pool. Currently this * should only be true for the primary and secondary Zygotes, and not the App Zygotes or the @@ -131,6 +137,24 @@ class ZygoteServer { */ private int mUsapPoolRefillThreshold = 0; + /** + * Number of milliseconds to delay before refilling the pool if it hasn't reached its + * minimum value. + */ + private int mUsapPoolRefillDelayMs = -1; + + /** + * If and when we should refill the USAP pool. + */ + private UsapPoolRefillAction mUsapPoolRefillAction; + private long mUsapPoolRefillTriggerTimestamp; + + private enum UsapPoolRefillAction { + DELAYED, + IMMEDIATE, + NONE + } + ZygoteServer() { mUsapPoolEventFD = null; mZygoteSocket = null; @@ -160,9 +184,8 @@ class ZygoteServer { Zygote.USAP_POOL_SECONDARY_SOCKET_NAME); } - fetchUsapPoolPolicyProps(); - mUsapPoolSupported = true; + fetchUsapPoolPolicyProps(); } void setForkChild() { @@ -267,6 +290,13 @@ class ZygoteServer { mUsapPoolSizeMax); } + final String usapPoolRefillDelayMsPropString = Zygote.getConfigurationProperty( + ZygoteConfig.USAP_POOL_REFILL_DELAY_MS, USAP_POOL_REFILL_DELAY_MS_DEFAULT); + + if (!usapPoolRefillDelayMsPropString.isEmpty()) { + mUsapPoolRefillDelayMs = Integer.parseInt(usapPoolRefillDelayMsPropString); + } + // Sanity check if (mUsapPoolSizeMin >= mUsapPoolSizeMax) { Log.w(TAG, "The max size of the USAP pool must be greater than the minimum size." @@ -293,9 +323,16 @@ class ZygoteServer { } } + private void fetchUsapPoolPolicyPropsIfUnfetched() { + if (mIsFirstPropertyCheck) { + mIsFirstPropertyCheck = false; + fetchUsapPoolPolicyProps(); + } + } + /** - * Checks to see if the current policy says that pool should be refilled, and spawns new USAPs - * if necessary. + * Refill the USAP Pool to the appropriate level, determined by whether this is a priority + * refill event or not. * * @param sessionSocketRawFDs Anonymous session sockets that are currently open * @return In the Zygote process this function will always return null; in unspecialized app @@ -303,38 +340,47 @@ class ZygoteServer { * application that is passed up from usapMain. */ - Runnable fillUsapPool(int[] sessionSocketRawFDs) { + Runnable fillUsapPool(int[] sessionSocketRawFDs, boolean isPriorityRefill) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Zygote:FillUsapPool"); // Ensure that the pool properties have been fetched. - fetchUsapPoolPolicyPropsWithMinInterval(); + fetchUsapPoolPolicyPropsIfUnfetched(); int usapPoolCount = Zygote.getUsapPoolCount(); - int numUsapsToSpawn = mUsapPoolSizeMax - usapPoolCount; + int numUsapsToSpawn; + + if (isPriorityRefill) { + // Refill to min + numUsapsToSpawn = mUsapPoolSizeMin - usapPoolCount; + + Log.i("zygote", + "Priority USAP Pool refill. New USAPs: " + numUsapsToSpawn); + } else { + // Refill up to max + numUsapsToSpawn = mUsapPoolSizeMax - usapPoolCount; - if (usapPoolCount < mUsapPoolSizeMin - || numUsapsToSpawn >= mUsapPoolRefillThreshold) { + Log.i("zygote", + "Delayed USAP Pool refill. New USAPs: " + numUsapsToSpawn); + } - // Disable some VM functionality and reset some system values - // before forking. - ZygoteHooks.preFork(); - Zygote.resetNicePriority(); + // Disable some VM functionality and reset some system values + // before forking. + ZygoteHooks.preFork(); - while (usapPoolCount++ < mUsapPoolSizeMax) { - Runnable caller = Zygote.forkUsap(mUsapPoolSocket, sessionSocketRawFDs); + while (--numUsapsToSpawn >= 0) { + Runnable caller = + Zygote.forkUsap(mUsapPoolSocket, sessionSocketRawFDs, isPriorityRefill); - if (caller != null) { - return caller; - } + if (caller != null) { + return caller; } + } - // Re-enable runtime services for the Zygote. Services for unspecialized app process - // are re-enabled in specializeAppProcess. - ZygoteHooks.postForkCommon(); + // Re-enable runtime services for the Zygote. Services for unspecialized app process + // are re-enabled in specializeAppProcess. + ZygoteHooks.postForkCommon(); - Log.i("zygote", - "Filled the USAP pool. New USAPs: " + numUsapsToSpawn); - } + resetUsapRefillState(); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); @@ -358,13 +404,18 @@ class ZygoteServer { mUsapPoolEnabled = newStatus; if (newStatus) { - return fillUsapPool(new int[]{ sessionSocket.getFileDescriptor().getInt$() }); + return fillUsapPool(new int[]{ sessionSocket.getFileDescriptor().getInt$() }, false); } else { Zygote.emptyUsapPool(); return null; } } + void resetUsapRefillState() { + mUsapPoolRefillAction = UsapPoolRefillAction.NONE; + mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP; + } + /** * Runs the zygote process's select loop. Accepts new connections as * they happen, and reads commands from connections one spawn-request's @@ -377,8 +428,11 @@ class ZygoteServer { socketFDs.add(mZygoteSocket.getFileDescriptor()); peers.add(null); + mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP; + while (true) { fetchUsapPoolPolicyPropsWithMinInterval(); + mUsapPoolRefillAction = UsapPoolRefillAction.NONE; int[] usapPipeFDs = null; StructPollfd[] pollFDs; @@ -430,140 +484,199 @@ class ZygoteServer { } } + int pollTimeoutMs; + + if (mUsapPoolRefillTriggerTimestamp == INVALID_TIMESTAMP) { + pollTimeoutMs = -1; + } else { + long elapsedTimeMs = System.currentTimeMillis() - mUsapPoolRefillTriggerTimestamp; + + if (elapsedTimeMs >= mUsapPoolRefillDelayMs) { + // Normalize the poll timeout value when the time between one poll event and the + // next pushes us over the delay value. This prevents poll receiving a 0 + // timeout value, which would result in it returning immediately. + pollTimeoutMs = -1; + + } else if (elapsedTimeMs <= 0) { + // This can occur if the clock used by currentTimeMillis is reset, which is + // possible because it is not guaranteed to be monotonic. Because we can't tell + // how far back the clock was set the best way to recover is to simply re-start + // the respawn delay countdown. + pollTimeoutMs = mUsapPoolRefillDelayMs; + + } else { + pollTimeoutMs = (int) (mUsapPoolRefillDelayMs - elapsedTimeMs); + } + } + + int pollReturnValue; try { - Os.poll(pollFDs, -1); + pollReturnValue = Os.poll(pollFDs, pollTimeoutMs); } catch (ErrnoException ex) { throw new RuntimeException("poll failed", ex); } - boolean usapPoolFDRead = false; - - while (--pollIndex >= 0) { - if ((pollFDs[pollIndex].revents & POLLIN) == 0) { - continue; - } - - if (pollIndex == 0) { - // Zygote server socket + if (pollReturnValue == 0) { + // The poll timeout has been exceeded. This only occurs when we have finished the + // USAP pool refill delay period. - ZygoteConnection newPeer = acceptCommandPeer(abiList); - peers.add(newPeer); - socketFDs.add(newPeer.getFileDescriptor()); + mUsapPoolRefillTriggerTimestamp = INVALID_TIMESTAMP; + mUsapPoolRefillAction = UsapPoolRefillAction.DELAYED; - } else if (pollIndex < usapPoolEventFDIndex) { - // Session socket accepted from the Zygote server socket + } else { + boolean usapPoolFDRead = false; - try { - ZygoteConnection connection = peers.get(pollIndex); - final Runnable command = connection.processOneCommand(this); + while (--pollIndex >= 0) { + if ((pollFDs[pollIndex].revents & POLLIN) == 0) { + continue; + } - // TODO (chriswailes): Is this extra check necessary? - if (mIsForkChild) { - // We're in the child. We should always have a command to run at this - // stage if processOneCommand hasn't called "exec". - if (command == null) { - throw new IllegalStateException("command == null"); + if (pollIndex == 0) { + // Zygote server socket + + ZygoteConnection newPeer = acceptCommandPeer(abiList); + peers.add(newPeer); + socketFDs.add(newPeer.getFileDescriptor()); + + } else if (pollIndex < usapPoolEventFDIndex) { + // Session socket accepted from the Zygote server socket + + try { + ZygoteConnection connection = peers.get(pollIndex); + final Runnable command = connection.processOneCommand(this); + + // TODO (chriswailes): Is this extra check necessary? + if (mIsForkChild) { + // We're in the child. We should always have a command to run at + // this stage if processOneCommand hasn't called "exec". + if (command == null) { + throw new IllegalStateException("command == null"); + } + + return command; + } else { + // We're in the server - we should never have any commands to run. + if (command != null) { + throw new IllegalStateException("command != null"); + } + + // We don't know whether the remote side of the socket was closed or + // not until we attempt to read from it from processOneCommand. This + // shows up as a regular POLLIN event in our regular processing + // loop. + if (connection.isClosedByPeer()) { + connection.closeSocket(); + peers.remove(pollIndex); + socketFDs.remove(pollIndex); + } } + } catch (Exception e) { + if (!mIsForkChild) { + // We're in the server so any exception here is one that has taken + // place pre-fork while processing commands or reading / writing + // from the control socket. Make a loud noise about any such + // exceptions so that we know exactly what failed and why. - return command; - } else { - // We're in the server - we should never have any commands to run. - if (command != null) { - throw new IllegalStateException("command != null"); - } + Slog.e(TAG, "Exception executing zygote command: ", e); + + // Make sure the socket is closed so that the other end knows + // immediately that something has gone wrong and doesn't time out + // waiting for a response. + ZygoteConnection conn = peers.remove(pollIndex); + conn.closeSocket(); - // We don't know whether the remote side of the socket was closed or - // not until we attempt to read from it from processOneCommand. This - // shows up as a regular POLLIN event in our regular processing loop. - if (connection.isClosedByPeer()) { - connection.closeSocket(); - peers.remove(pollIndex); socketFDs.remove(pollIndex); + } else { + // We're in the child so any exception caught here has happened post + // fork and before we execute ActivityThread.main (or any other + // main() method). Log the details of the exception and bring down + // the process. + Log.e(TAG, "Caught post-fork exception in child process.", e); + throw e; } + } finally { + // Reset the child flag, in the event that the child process is a child- + // zygote. The flag will not be consulted this loop pass after the + // Runnable is returned. + mIsForkChild = false; } - } catch (Exception e) { - if (!mIsForkChild) { - // We're in the server so any exception here is one that has taken place - // pre-fork while processing commands or reading / writing from the - // control socket. Make a loud noise about any such exceptions so that - // we know exactly what failed and why. - - Slog.e(TAG, "Exception executing zygote command: ", e); - - // Make sure the socket is closed so that the other end knows - // immediately that something has gone wrong and doesn't time out - // waiting for a response. - ZygoteConnection conn = peers.remove(pollIndex); - conn.closeSocket(); - - socketFDs.remove(pollIndex); - } else { - // We're in the child so any exception caught here has happened post - // fork and before we execute ActivityThread.main (or any other main() - // method). Log the details of the exception and bring down the process. - Log.e(TAG, "Caught post-fork exception in child process.", e); - throw e; - } - } finally { - // Reset the child flag, in the event that the child process is a child- - // zygote. The flag will not be consulted this loop pass after the Runnable - // is returned. - mIsForkChild = false; - } - } else { - // Either the USAP pool event FD or a USAP reporting pipe. - - // If this is the event FD the payload will be the number of USAPs removed. - // If this is a reporting pipe FD the payload will be the PID of the USAP - // that was just specialized. - long messagePayload = -1; - - try { - byte[] buffer = new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES]; - int readBytes = Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length); - if (readBytes == Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) { - DataInputStream inputStream = - new DataInputStream(new ByteArrayInputStream(buffer)); + } else { + // Either the USAP pool event FD or a USAP reporting pipe. + + // If this is the event FD the payload will be the number of USAPs removed. + // If this is a reporting pipe FD the payload will be the PID of the USAP + // that was just specialized. The `continue` statements below ensure that + // the messagePayload will always be valid if we complete the try block + // without an exception. + long messagePayload; + + try { + byte[] buffer = new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES]; + int readBytes = + Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length); + + if (readBytes == Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) { + DataInputStream inputStream = + new DataInputStream(new ByteArrayInputStream(buffer)); + + messagePayload = inputStream.readLong(); + } else { + Log.e(TAG, "Incomplete read from USAP management FD of size " + + readBytes); + continue; + } + } catch (Exception ex) { + if (pollIndex == usapPoolEventFDIndex) { + Log.e(TAG, "Failed to read from USAP pool event FD: " + + ex.getMessage()); + } else { + Log.e(TAG, "Failed to read from USAP reporting pipe: " + + ex.getMessage()); + } - messagePayload = inputStream.readLong(); - } else { - Log.e(TAG, "Incomplete read from USAP management FD of size " - + readBytes); continue; } - } catch (Exception ex) { - if (pollIndex == usapPoolEventFDIndex) { - Log.e(TAG, "Failed to read from USAP pool event FD: " - + ex.getMessage()); - } else { - Log.e(TAG, "Failed to read from USAP reporting pipe: " - + ex.getMessage()); + + if (pollIndex > usapPoolEventFDIndex) { + Zygote.removeUsapTableEntry((int) messagePayload); } - continue; + usapPoolFDRead = true; } + } - if (pollIndex > usapPoolEventFDIndex) { - Zygote.removeUsapTableEntry((int) messagePayload); - } + if (usapPoolFDRead) { + int usapPoolCount = Zygote.getUsapPoolCount(); - usapPoolFDRead = true; + if (usapPoolCount < mUsapPoolSizeMin) { + // Immediate refill + mUsapPoolRefillAction = UsapPoolRefillAction.IMMEDIATE; + } else if (mUsapPoolSizeMax - usapPoolCount >= mUsapPoolRefillThreshold) { + // Delayed refill + mUsapPoolRefillTriggerTimestamp = System.currentTimeMillis(); + } } } - // Check to see if the USAP pool needs to be refilled. - if (usapPoolFDRead) { + if (mUsapPoolRefillAction != UsapPoolRefillAction.NONE) { int[] sessionSocketRawFDs = socketFDs.subList(1, socketFDs.size()) .stream() .mapToInt(FileDescriptor::getInt$) .toArray(); - final Runnable command = fillUsapPool(sessionSocketRawFDs); + final boolean isPriorityRefill = + mUsapPoolRefillAction == UsapPoolRefillAction.IMMEDIATE; + + final Runnable command = + fillUsapPool(sessionSocketRawFDs, isPriorityRefill); if (command != null) { return command; + } else if (isPriorityRefill) { + // Schedule a delayed refill to finish refilling the pool. + mUsapPoolRefillTriggerTimestamp = System.currentTimeMillis(); } } } diff --git a/core/java/com/android/internal/util/ConnectivityUtil.java b/core/java/com/android/internal/util/ConnectivityUtil.java new file mode 100644 index 000000000000..b1d4fa0d3fd3 --- /dev/null +++ b/core/java/com/android/internal/util/ConnectivityUtil.java @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2020 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.internal.util; + +import android.Manifest; +import android.annotation.Nullable; +import android.app.ActivityManager; +import android.app.AppOpsManager; +import android.content.Context; +import android.content.pm.PackageManager; +import android.location.LocationManager; +import android.os.Binder; +import android.os.Build; +import android.os.UserHandle; +import android.os.UserManager; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; + + +/** + * Utility methods for common functionality using by different networks. + * + * @hide + */ +public class ConnectivityUtil { + + private static final String TAG = "ConnectivityUtil"; + + private final Context mContext; + private final AppOpsManager mAppOps; + private final UserManager mUserManager; + + public ConnectivityUtil(Context context) { + mContext = context; + mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); + mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); + } + + /** + * API to determine if the caller has fine/coarse location permission (depending on + * config/targetSDK level) and the location mode is enabled for the user. SecurityException is + * thrown if the caller has no permission or the location mode is disabled. + * @param pkgName package name of the application requesting access + * @param featureId The feature in the package + * @param uid The uid of the package + * @param message A message describing why the permission was checked. Only needed if this is + * not inside of a two-way binder call from the data receiver + */ + public void enforceLocationPermission(String pkgName, @Nullable String featureId, int uid, + @Nullable String message) + throws SecurityException { + checkPackage(uid, pkgName); + + // Location mode must be enabled + if (!isLocationModeEnabled()) { + // Location mode is disabled, scan results cannot be returned + throw new SecurityException("Location mode is disabled for the device"); + } + + // LocationAccess by App: caller must have Coarse/Fine Location permission to have access to + // location information. + boolean canAppPackageUseLocation = checkCallersLocationPermission(pkgName, featureId, + uid, /* coarseForTargetSdkLessThanQ */ true, message); + + // If neither caller or app has location access, there is no need to check + // any other permissions. Deny access to scan results. + if (!canAppPackageUseLocation) { + throw new SecurityException("UID " + uid + " has no location permission"); + } + // If the User or profile is current, permission is granted + // Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission. + if (!isCurrentProfile(uid) && !checkInteractAcrossUsersFull(uid)) { + throw new SecurityException("UID " + uid + " profile not permitted"); + } + } + + /** + * Checks that calling process has android.Manifest.permission.ACCESS_FINE_LOCATION or + * android.Manifest.permission.ACCESS_COARSE_LOCATION (depending on config/targetSDK level) + * and a corresponding app op is allowed for this package and uid. + * + * @param pkgName PackageName of the application requesting access + * @param featureId The feature in the package + * @param uid The uid of the package + * @param coarseForTargetSdkLessThanQ If true and the targetSDK < Q then will check for COARSE + * else (false or targetSDK >= Q) then will check for FINE + * @param message A message describing why the permission was checked. Only needed if this is + * not inside of a two-way binder call from the data receiver + */ + public boolean checkCallersLocationPermission(String pkgName, @Nullable String featureId, + int uid, boolean coarseForTargetSdkLessThanQ, @Nullable String message) { + boolean isTargetSdkLessThanQ = isTargetSdkLessThan(pkgName, Build.VERSION_CODES.Q, uid); + + String permissionType = Manifest.permission.ACCESS_FINE_LOCATION; + if (coarseForTargetSdkLessThanQ && isTargetSdkLessThanQ) { + // Having FINE permission implies having COARSE permission (but not the reverse) + permissionType = Manifest.permission.ACCESS_COARSE_LOCATION; + } + if (getUidPermission(permissionType, uid) + == PackageManager.PERMISSION_DENIED) { + return false; + } + + // Always checking FINE - even if will not enforce. This will record the request for FINE + // so that a location request by the app is surfaced to the user. + boolean isFineLocationAllowed = noteAppOpAllowed( + AppOpsManager.OPSTR_FINE_LOCATION, pkgName, featureId, uid, message); + if (isFineLocationAllowed) { + return true; + } + if (coarseForTargetSdkLessThanQ && isTargetSdkLessThanQ) { + return noteAppOpAllowed(AppOpsManager.OPSTR_COARSE_LOCATION, pkgName, featureId, uid, + message); + } + return false; + } + + /** + * Retrieves a handle to LocationManager (if not already done) and check if location is enabled. + */ + public boolean isLocationModeEnabled() { + LocationManager locationManager = + (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); + try { + return locationManager.isLocationEnabledForUser(UserHandle.of( + getCurrentUser())); + } catch (Exception e) { + Log.e(TAG, "Failure to get location mode via API, falling back to settings", e); + return false; + } + } + + private boolean isTargetSdkLessThan(String packageName, int versionCode, int callingUid) { + long ident = Binder.clearCallingIdentity(); + try { + if (mContext.getPackageManager().getApplicationInfoAsUser( + packageName, 0, + UserHandle.getUserHandleForUid(callingUid)).targetSdkVersion + < versionCode) { + return true; + } + } catch (PackageManager.NameNotFoundException e) { + // In case of exception, assume unknown app (more strict checking) + // Note: This case will never happen since checkPackage is + // called to verify validity before checking App's version. + } finally { + Binder.restoreCallingIdentity(ident); + } + return false; + } + + private boolean noteAppOpAllowed(String op, String pkgName, @Nullable String featureId, + int uid, @Nullable String message) { + return mAppOps.noteOp(op, uid, pkgName) == AppOpsManager.MODE_ALLOWED; + } + + private void checkPackage(int uid, String pkgName) throws SecurityException { + if (pkgName == null) { + throw new SecurityException("Checking UID " + uid + " but Package Name is Null"); + } + mAppOps.checkPackage(uid, pkgName); + } + + private boolean isCurrentProfile(int uid) { + UserHandle currentUser = UserHandle.of(getCurrentUser()); + UserHandle callingUser = UserHandle.getUserHandleForUid(uid); + return currentUser.equals(callingUser) + || mUserManager.isSameProfileGroup( + currentUser.getIdentifier(), callingUser.getIdentifier()); + } + + private boolean checkInteractAcrossUsersFull(int uid) { + return getUidPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, uid) + == PackageManager.PERMISSION_GRANTED; + } + + @VisibleForTesting + protected int getCurrentUser() { + return ActivityManager.getCurrentUser(); + } + + private int getUidPermission(String permissionType, int uid) { + // We don't care about pid, pass in -1 + return mContext.checkPermission(permissionType, -1, uid); + } +} diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 85752ab25e4b..486df621f4f1 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -63,6 +63,7 @@ #include <sys/stat.h> #include <sys/time.h> #include <sys/types.h> +#include <sys/un.h> #include <sys/utsname.h> #include <sys/wait.h> #include <unistd.h> @@ -164,11 +165,26 @@ static std::atomic_uint32_t gUsapPoolCount = 0; static int gUsapPoolEventFD = -1; /** + * The socket file descriptor used to send notifications to the + * system_server. + */ +static int gSystemServerSocketFd = -1; + +/** * The maximum value that the gUSAPPoolSizeMax variable may take. This value * is a mirror of ZygoteServer.USAP_POOL_SIZE_MAX_LIMIT */ static constexpr int USAP_POOL_SIZE_MAX_LIMIT = 100; +/** The numeric value for the maximum priority a process may possess. */ +static constexpr int PROCESS_PRIORITY_MAX = -20; + +/** The numeric value for the minimum priority a process may possess. */ +static constexpr int PROCESS_PRIORITY_MIN = 19; + +/** The numeric value for the normal priority a process should have. */ +static constexpr int PROCESS_PRIORITY_DEFAULT = 0; + /** * A helper class containing accounting information for USAPs. */ @@ -305,6 +321,26 @@ enum RuntimeFlags : uint32_t { PROFILE_FROM_SHELL = 1 << 15, }; +enum UnsolicitedZygoteMessageTypes : uint32_t { + UNSOLICITED_ZYGOTE_MESSAGE_TYPE_RESERVED = 0, + UNSOLICITED_ZYGOTE_MESSAGE_TYPE_SIGCHLD = 1, +}; + +struct UnsolicitedZygoteMessageSigChld { + struct { + UnsolicitedZygoteMessageTypes type; + } header; + struct { + pid_t pid; + uid_t uid; + int status; + } payload; +}; + +// Keep sync with services/core/java/com/android/server/am/ProcessList.java +static constexpr struct sockaddr_un kSystemServerSockAddr = + {.sun_family = AF_LOCAL, .sun_path = "/data/system/unsolzygotesocket"}; + // Forward declaration so we don't have to move the signal handler. static bool RemoveUsapTableEntry(pid_t usap_pid); @@ -314,8 +350,37 @@ static void RuntimeAbort(JNIEnv* env, int line, const char* msg) { env->FatalError(oss.str().c_str()); } +// Create the socket which is going to be used to send unsolicited message +// to system_server, the socket will be closed post forking a child process. +// It's expected to be called at each zygote's initialization. +static void initUnsolSocketToSystemServer() { + gSystemServerSocketFd = socket(AF_LOCAL, SOCK_DGRAM | SOCK_NONBLOCK, 0); + if (gSystemServerSocketFd >= 0) { + ALOGV("Zygote:systemServerSocketFD = %d", gSystemServerSocketFd); + } else { + ALOGE("Unable to create socket file descriptor to connect to system_server"); + } +} + +static void sendSigChildStatus(const pid_t pid, const uid_t uid, const int status) { + int socketFd = gSystemServerSocketFd; + if (socketFd >= 0) { + // fill the message buffer + struct UnsolicitedZygoteMessageSigChld data = + {.header = {.type = UNSOLICITED_ZYGOTE_MESSAGE_TYPE_SIGCHLD}, + .payload = {.pid = pid, .uid = uid, .status = status}}; + if (TEMP_FAILURE_RETRY( + sendto(socketFd, &data, sizeof(data), 0, + reinterpret_cast<const struct sockaddr*>(&kSystemServerSockAddr), + sizeof(kSystemServerSockAddr))) == -1) { + async_safe_format_log(ANDROID_LOG_ERROR, LOG_TAG, + "Zygote failed to write to system_server FD: %s", + strerror(errno)); + } + } +} // This signal handler is for zygote mode, since the zygote must reap its children -static void SigChldHandler(int /*signal_number*/) { +static void SigChldHandler(int /*signal_number*/, siginfo_t* info, void* /*ucontext*/) { pid_t pid; int status; int64_t usaps_removed = 0; @@ -329,6 +394,8 @@ static void SigChldHandler(int /*signal_number*/) { int saved_errno = errno; while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { + // Notify system_server that we received a SIGCHLD + sendSigChildStatus(pid, info->si_uid, status); // Log process-death status that we care about. if (WIFEXITED(status)) { async_safe_format_log(ANDROID_LOG_INFO, LOG_TAG, @@ -402,8 +469,7 @@ static void SigChldHandler(int /*signal_number*/) { // This ends up being called repeatedly before each fork(), but there's // no real harm in that. static void SetSignalHandlers() { - struct sigaction sig_chld = {}; - sig_chld.sa_handler = SigChldHandler; + struct sigaction sig_chld = {.sa_flags = SA_SIGINFO, .sa_sigaction = SigChldHandler}; if (sigaction(SIGCHLD, &sig_chld, nullptr) < 0) { ALOGW("Error setting SIGCHLD handler: %s", strerror(errno)); @@ -903,7 +969,8 @@ static void ClearUsapTable() { // Utility routine to fork a process from the zygote. static pid_t ForkCommon(JNIEnv* env, bool is_system_server, const std::vector<int>& fds_to_close, - const std::vector<int>& fds_to_ignore) { + const std::vector<int>& fds_to_ignore, + bool is_priority_fork) { SetSignalHandlers(); // Curry a failure function. @@ -936,6 +1003,12 @@ static pid_t ForkCommon(JNIEnv* env, bool is_system_server, pid_t pid = fork(); if (pid == 0) { + if (is_priority_fork) { + setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX); + } else { + setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MIN); + } + // The child process. PreApplicationInit(); @@ -951,6 +1024,9 @@ static pid_t ForkCommon(JNIEnv* env, bool is_system_server, // Turn fdsan back on. android_fdsan_set_error_level(fdsan_error_level); + + // Reset the fd to the unsolicited zygote socket + gSystemServerSocketFd = -1; } else { ALOGD("Forked child process %d", pid); } @@ -1125,9 +1201,16 @@ static void SpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray gids, } } + if (is_child_zygote) { + initUnsolSocketToSystemServer(); + } + env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags, is_system_server, is_child_zygote, managed_instruction_set); + // Reset the process priority to the default value. + setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_DEFAULT); + if (env->ExceptionCheck()) { fail_fn("Error calling post fork hooks."); } @@ -1367,7 +1450,12 @@ static jint com_android_internal_os_Zygote_nativeForkAndSpecialize( fds_to_ignore.push_back(gUsapPoolEventFD); } - pid_t pid = ForkCommon(env, false, fds_to_close, fds_to_ignore); + if (gSystemServerSocketFd != -1) { + fds_to_close.push_back(gSystemServerSocketFd); + fds_to_ignore.push_back(gSystemServerSocketFd); + } + + pid_t pid = ForkCommon(env, false, fds_to_close, fds_to_ignore, true); if (pid == 0) { SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, @@ -1392,9 +1480,15 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer( fds_to_ignore.push_back(gUsapPoolEventFD); } + if (gSystemServerSocketFd != -1) { + fds_to_close.push_back(gSystemServerSocketFd); + fds_to_ignore.push_back(gSystemServerSocketFd); + } + pid_t pid = ForkCommon(env, true, fds_to_close, - fds_to_ignore); + fds_to_ignore, + true); if (pid == 0) { SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits, permitted_capabilities, effective_capabilities, @@ -1436,13 +1530,15 @@ static jint com_android_internal_os_Zygote_nativeForkSystemServer( * zygote in managed code. * @param managed_session_socket_fds A list of anonymous session sockets that must be ignored by * the FD hygiene code and automatically "closed" in the new USAP. + * @param is_priority_fork Controls the nice level assigned to the newly created process * @return */ static jint com_android_internal_os_Zygote_nativeForkUsap(JNIEnv* env, jclass, jint read_pipe_fd, jint write_pipe_fd, - jintArray managed_session_socket_fds) { + jintArray managed_session_socket_fds, + jboolean is_priority_fork) { std::vector<int> fds_to_close(MakeUsapPipeReadFDVector()), fds_to_ignore(fds_to_close); @@ -1456,6 +1552,9 @@ static jint com_android_internal_os_Zygote_nativeForkUsap(JNIEnv* env, fds_to_close.push_back(gZygoteSocketFD); fds_to_close.push_back(gUsapPoolEventFD); fds_to_close.insert(fds_to_close.end(), session_socket_fds.begin(), session_socket_fds.end()); + if (gSystemServerSocketFd != -1) { + fds_to_close.push_back(gSystemServerSocketFd); + } fds_to_ignore.push_back(gZygoteSocketFD); fds_to_ignore.push_back(gUsapPoolSocketFD); @@ -1463,8 +1562,12 @@ static jint com_android_internal_os_Zygote_nativeForkUsap(JNIEnv* env, fds_to_ignore.push_back(read_pipe_fd); fds_to_ignore.push_back(write_pipe_fd); fds_to_ignore.insert(fds_to_ignore.end(), session_socket_fds.begin(), session_socket_fds.end()); + if (gSystemServerSocketFd != -1) { + fds_to_ignore.push_back(gSystemServerSocketFd); + } - pid_t usap_pid = ForkCommon(env, /* is_system_server= */ false, fds_to_close, fds_to_ignore); + pid_t usap_pid = ForkCommon(env, /* is_system_server= */ false, fds_to_close, fds_to_ignore, + is_priority_fork == JNI_TRUE); if (usap_pid != 0) { ++gUsapPoolCount; @@ -1562,6 +1665,7 @@ static void com_android_internal_os_Zygote_nativeInitNativeState(JNIEnv* env, jc ALOGE("Unable to fetch USAP pool socket file descriptor"); } + initUnsolSocketToSystemServer(); /* * Security Initialization */ @@ -1701,6 +1805,48 @@ static void com_android_internal_os_Zygote_nativeUnblockSigTerm(JNIEnv* env, jcl UnblockSignal(SIGTERM, fail_fn); } +static void com_android_internal_os_Zygote_nativeBoostUsapPriority(JNIEnv* env, jclass) { + setpriority(PRIO_PROCESS, 0, PROCESS_PRIORITY_MAX); +} + +static jint com_android_internal_os_Zygote_nativeParseSigChld(JNIEnv* env, jclass, jbyteArray in, + jint length, jintArray out) { + if (length != sizeof(struct UnsolicitedZygoteMessageSigChld)) { + // Apparently it's not the message we are expecting. + return -1; + } + if (in == nullptr || out == nullptr) { + // Invalid parameter + jniThrowException(env, "java/lang/IllegalArgumentException", nullptr); + return -1; + } + ScopedByteArrayRO source(env, in); + if (source.size() < length) { + // Invalid parameter + jniThrowException(env, "java/lang/IllegalArgumentException", nullptr); + return -1; + } + const struct UnsolicitedZygoteMessageSigChld* msg = + reinterpret_cast<const struct UnsolicitedZygoteMessageSigChld*>(source.get()); + + switch (msg->header.type) { + case UNSOLICITED_ZYGOTE_MESSAGE_TYPE_SIGCHLD: { + ScopedIntArrayRW buf(env, out); + if (buf.size() != 3) { + jniThrowException(env, "java/lang/IllegalArgumentException", nullptr); + return UNSOLICITED_ZYGOTE_MESSAGE_TYPE_RESERVED; + } + buf[0] = msg->payload.pid; + buf[1] = msg->payload.uid; + buf[2] = msg->payload.status; + return 3; + } + default: + break; + } + return -1; +} + static const JNINativeMethod gMethods[] = { { "nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;)I", @@ -1713,7 +1859,7 @@ static const JNINativeMethod gMethods[] = { (void *) com_android_internal_os_Zygote_nativePreApplicationInit }, { "nativeInstallSeccompUidGidFilter", "(II)V", (void *) com_android_internal_os_Zygote_nativeInstallSeccompUidGidFilter }, - { "nativeForkUsap", "(II[I)I", + { "nativeForkUsap", "(II[IZ)I", (void *) com_android_internal_os_Zygote_nativeForkUsap }, { "nativeSpecializeAppProcess", "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;)V", @@ -1735,7 +1881,11 @@ static const JNINativeMethod gMethods[] = { { "nativeBlockSigTerm", "()V", (void* ) com_android_internal_os_Zygote_nativeBlockSigTerm }, { "nativeUnblockSigTerm", "()V", - (void* ) com_android_internal_os_Zygote_nativeUnblockSigTerm } + (void* ) com_android_internal_os_Zygote_nativeUnblockSigTerm }, + { "nativeBoostUsapPriority", "()V", + (void* ) com_android_internal_os_Zygote_nativeBoostUsapPriority }, + {"nativeParseSigChld", "([BI[I)I", + (void* ) com_android_internal_os_Zygote_nativeParseSigChld}, }; int register_com_android_internal_os_Zygote(JNIEnv* env) { diff --git a/core/proto/android/server/jobscheduler.proto b/core/proto/android/server/jobscheduler.proto index 28733798b9ad..7452f809a14d 100644 --- a/core/proto/android/server/jobscheduler.proto +++ b/core/proto/android/server/jobscheduler.proto @@ -232,6 +232,8 @@ message ConstantsProto { // Whether or not TimeController should skip setting wakeup alarms for jobs that aren't // ready now. optional bool skip_not_ready_jobs = 1; + // Whether or not TimeController will use a non-wakeup alarm for delay constraints. + optional bool use_non_wakeup_alarm_for_delay = 2; } optional TimeController time_controller = 25; diff --git a/core/proto/android/stats/otaupdate/updateengine_enums.proto b/core/proto/android/stats/otaupdate/updateengine_enums.proto new file mode 100644 index 000000000000..a6e9919ba606 --- /dev/null +++ b/core/proto/android/stats/otaupdate/updateengine_enums.proto @@ -0,0 +1,82 @@ +/* + * 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. + */ + +syntax = "proto2"; +package android.stats.otaupdate; + +// The payload type of an OTA update attempt on A/B devices. +enum PayloadType { + FULL = 10000; + DELTA = 10001; +} + +// The attempt result reported by the update engine for an OTA update. +enum AttemptResult { + UPDATE_SUCCEEDED = 10000; + INTERNAL_ERROR = 10001; + PAYLOAD_DOWNLOAD_ERROR = 10002; + METADATA_MALFORMED = 10003; + OPERATION_MALFORMED = 10004; + OPERATION_EXECUTION_ERROR = 10005; + METADATA_VERIFICATION_FAILED = 10006; + PAYLOAD_VERIFICATION_FAILED = 10007; + VERIFICATION_FAILED = 10008; + POSTINSTALL_FAILED = 10009; + ABNORMAL_TERMINATION = 10010; + UPDATE_CANCELED = 10011; + UPDATE_SUCCEEDED_NOT_ACTIVE = 10012; +} + +// The error code reported by the update engine after an OTA update attempt +// on A/B devices. More details in system/update_engine/common/error_code.h +enum ErrorCode { + SUCCESS = 10000; + ERROR = 10001; + FILESYSTEM_COPIER_ERROR = 10004; + POST_INSTALL_RUNNER_ERROR = 10005; + PAYLOAD_MISMATCHED_TYPE_ERROR = 10006; + INSTALL_DEVICE_OPEN_ERROR = 10007; + KERNEL_DEVICE_OPEN_ERROR = 10008; + DOWNLOAD_TRANSFER_ERROR = 10009; + PAYLOAD_HASH_MISMATCH_ERROR = 10010; + PAYLOAD_SIZE_MISMATCH_ERROR = 10011; + DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 10012; + DOWNLOAD_NEW_PARTITION_INFO_ERROR = 10013; + DOWNLOAD_WRITE_ERROR = 10014; + NEW_ROOTFS_VERIFICATION_ERROR = 10015; + SIGNED_DELTA_PAYLOAD_EXPECTED_ERROR = 10017; + DOWNLOAD_PAYLOAD_PUB_KEY_VERIFICATION_ERROR = 10018; + DOWNLOAD_STATE_INITIALIZATION_ERROR = 10020; + DOWNLOAD_INVALID_METADATA_MAGIC_STRING = 10021; + DOWNLOAD_SIGNATURE_MISSING_IN_MANIFEST = 10022; + DOWNLOAD_MANIFEST_PARSE_ERROR = 10023; + DOWNLOAD_METADATA_SIGNATURE_ERROR = 10024; + DOWNLOAD_METADATA_SIGNATURE_VERIFICATION_ERROR = 10025; + DOWNLOAD_METADATA_SIGNATURE_MISMATCH = 10026; + DOWNLOAD_OPERATION_HASH_VERIFICATION_ERROR = 10027; + DOWNLOAD_OPERATION_EXECUTION_ERROR = 10028; + DOWNLOAD_OPERATION_HASH_MISMATCH = 10029; + DOWNLOAD_INVALID_METADATA_SIZE = 10032; + DOWNLOAD_INVALID_METADATA_SIGNATURE = 10033; + DOWNLOAD_OPERATION_HASH_MISSING_ERROR = 10038; + DOWNLOAD_METADATA_SIGNATURE_MISSING_ERROR = 10039; + UNSUPPORTED_MAJOR_PAYLOAD_VERSION = 10044; + UNSUPPORTED_MINOR_PAYLOAD_VERSION = 10045; + FILESYSTEM_VERIFIER_ERROR = 10047; + USER_CANCELED = 10048; + PAYLOAD_TIMESTAMP_ERROR = 10051; + UPDATED_BUT_NOT_ACTIVE = 10052; +} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 5cd717a9058d..5c204aba49a1 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -556,10 +556,12 @@ <protected-broadcast android:name="com.android.sync.SYNC_CONN_STATUS_CHANGED" /> - <protected-broadcast android:name="com.android.phone.SIP_INCOMING_CALL" /> + <protected-broadcast android:name="android.net.sip.action.SIP_INCOMING_CALL" /> <protected-broadcast android:name="com.android.phone.SIP_ADD_PHONE" /> - <protected-broadcast android:name="com.android.phone.SIP_REMOVE_PHONE" /> - <protected-broadcast android:name="com.android.phone.SIP_CALL_OPTION_CHANGED" /> + <protected-broadcast android:name="android.net.sip.action.SIP_REMOVE_PROFILE" /> + <protected-broadcast android:name="android.net.sip.action.SIP_SERVICE_UP" /> + <protected-broadcast android:name="android.net.sip.action.SIP_CALL_OPTION_CHANGED" /> + <protected-broadcast android:name="android.net.sip.action.START_SIP" /> <protected-broadcast android:name="android.bluetooth.adapter.action.BLE_ACL_CONNECTED" /> <protected-broadcast android:name="android.bluetooth.adapter.action.BLE_ACL_DISCONNECTED" /> @@ -2551,7 +2553,7 @@ <!-- Allows telephony to suggest the time / time zone. <p>Not for use by third-party applications. - @hide + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) @hide --> <permission android:name="android.permission.SUGGEST_PHONE_TIME_AND_ZONE" android:protectionLevel="signature|telephony" /> diff --git a/core/tests/overlaytests/host/Android.bp b/core/tests/overlaytests/host/Android.bp new file mode 100644 index 000000000000..a2fcef56b780 --- /dev/null +++ b/core/tests/overlaytests/host/Android.bp @@ -0,0 +1,30 @@ +// 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. + +java_test_host { + name: "OverlayHostTests", + srcs: ["src/**/*.java"], + libs: ["tradefed"], + test_suites: ["general-tests"], + target_required: [ + "OverlayHostTests_NonPlatformSignatureOverlay", + "OverlayHostTests_PlatformSignatureStaticOverlay", + "OverlayHostTests_PlatformSignatureOverlay", + "OverlayHostTests_UpdateOverlay", + "OverlayHostTests_FrameworkOverlayV1", + "OverlayHostTests_FrameworkOverlayV2", + "OverlayHostTests_AppOverlayV1", + "OverlayHostTests_AppOverlayV2", + ], +} diff --git a/core/tests/overlaytests/host/Android.mk b/core/tests/overlaytests/host/Android.mk index e7348d52adfe..d58d9393c0b8 100644 --- a/core/tests/overlaytests/host/Android.mk +++ b/core/tests/overlaytests/host/Android.mk @@ -14,23 +14,6 @@ LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) -LOCAL_SRC_FILES := $(call all-java-files-under,src) -LOCAL_MODULE_TAGS := tests -LOCAL_MODULE := OverlayHostTests -LOCAL_JAVA_LIBRARIES := tradefed -LOCAL_COMPATIBILITY_SUITE := general-tests -LOCAL_TARGET_REQUIRED_MODULES := \ - OverlayHostTests_NonPlatformSignatureOverlay \ - OverlayHostTests_PlatformSignatureStaticOverlay \ - OverlayHostTests_PlatformSignatureOverlay \ - OverlayHostTests_UpdateOverlay \ - OverlayHostTests_FrameworkOverlayV1 \ - OverlayHostTests_FrameworkOverlayV2 \ - OverlayHostTests_AppOverlayV1 \ - OverlayHostTests_AppOverlayV2 -include $(BUILD_HOST_JAVA_LIBRARY) - # Include to build test-apps. include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/core/tests/utiltests/src/com/android/internal/util/ConnectivityUtilTest.java b/core/tests/utiltests/src/com/android/internal/util/ConnectivityUtilTest.java new file mode 100644 index 000000000000..556471260141 --- /dev/null +++ b/core/tests/utiltests/src/com/android/internal/util/ConnectivityUtilTest.java @@ -0,0 +1,286 @@ +/* + * Copyright (C) 2020 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.internal.util; + +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +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.doThrow; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.Manifest; +import android.app.AppOpsManager; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.location.LocationManager; +import android.os.Binder; +import android.os.Build; +import android.os.UserHandle; +import android.os.UserManager; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.util.HashMap; + +/** Unit tests for {@link ConnectivityUtil}. */ +public class ConnectivityUtilTest { + + public static final String TAG = "ConnectivityUtilTest"; + + // Mock objects for testing + @Mock private Context mMockContext; + @Mock private PackageManager mMockPkgMgr; + @Mock private ApplicationInfo mMockApplInfo; + @Mock private AppOpsManager mMockAppOps; + @Mock private UserManager mMockUserManager; + @Mock private LocationManager mLocationManager; + + private static final String TEST_PKG_NAME = "com.google.somePackage"; + private static final String TEST_FEATURE_ID = "com.google.someFeature"; + private static final int MANAGED_PROFILE_UID = 1100000; + private static final int OTHER_USER_UID = 1200000; + + private final String mInteractAcrossUsersFullPermission = + "android.permission.INTERACT_ACROSS_USERS_FULL"; + private final String mManifestStringCoarse = + Manifest.permission.ACCESS_COARSE_LOCATION; + private final String mManifestStringFine = + Manifest.permission.ACCESS_FINE_LOCATION; + + // Test variables + private int mWifiScanAllowApps; + private int mUid; + private int mCoarseLocationPermission; + private int mAllowCoarseLocationApps; + private int mFineLocationPermission; + private int mAllowFineLocationApps; + private int mCurrentUser; + private boolean mIsLocationEnabled; + private boolean mThrowSecurityException; + private Answer<Integer> mReturnPermission; + private HashMap<String, Integer> mPermissionsList = new HashMap<String, Integer>(); + + private class TestConnectivityUtil extends ConnectivityUtil { + + TestConnectivityUtil(Context context) { + super(context); + } + + @Override + protected int getCurrentUser() { + return mCurrentUser; + } + } + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + initTestVars(); + } + + private void setupMocks() throws Exception { + when(mMockPkgMgr.getApplicationInfoAsUser(eq(TEST_PKG_NAME), eq(0), any())) + .thenReturn(mMockApplInfo); + when(mMockContext.getPackageManager()).thenReturn(mMockPkgMgr); + when(mMockAppOps.noteOp(AppOpsManager.OPSTR_WIFI_SCAN, mUid, TEST_PKG_NAME)) + .thenReturn(mWifiScanAllowApps); + when(mMockAppOps.noteOp(eq(AppOpsManager.OPSTR_COARSE_LOCATION), eq(mUid), + eq(TEST_PKG_NAME))) + .thenReturn(mAllowCoarseLocationApps); + when(mMockAppOps.noteOp(eq(AppOpsManager.OPSTR_FINE_LOCATION), eq(mUid), + eq(TEST_PKG_NAME))) + .thenReturn(mAllowFineLocationApps); + if (mThrowSecurityException) { + doThrow(new SecurityException("Package " + TEST_PKG_NAME + " doesn't belong" + + " to application bound to user " + mUid)) + .when(mMockAppOps).checkPackage(mUid, TEST_PKG_NAME); + } + when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)) + .thenReturn(mMockAppOps); + when(mMockContext.getSystemService(Context.USER_SERVICE)) + .thenReturn(mMockUserManager); + when(mMockContext.getSystemService(Context.LOCATION_SERVICE)).thenReturn(mLocationManager); + } + + private void setupTestCase() throws Exception { + setupMocks(); + setupMockInterface(); + } + + private void initTestVars() { + mPermissionsList.clear(); + mReturnPermission = createPermissionAnswer(); + mWifiScanAllowApps = AppOpsManager.MODE_ERRORED; + mUid = OTHER_USER_UID; + mThrowSecurityException = true; + mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.M; + mIsLocationEnabled = false; + mCurrentUser = UserHandle.USER_SYSTEM; + mCoarseLocationPermission = PackageManager.PERMISSION_DENIED; + mFineLocationPermission = PackageManager.PERMISSION_DENIED; + mAllowCoarseLocationApps = AppOpsManager.MODE_ERRORED; + mAllowFineLocationApps = AppOpsManager.MODE_ERRORED; + } + + private void setupMockInterface() { + Binder.restoreCallingIdentity((((long) mUid) << 32) | Binder.getCallingPid()); + doAnswer(mReturnPermission).when(mMockContext).checkPermission( + anyString(), anyInt(), anyInt()); + when(mMockUserManager.isSameProfileGroup(UserHandle.SYSTEM.getIdentifier(), + UserHandle.getUserHandleForUid(MANAGED_PROFILE_UID).getIdentifier())) + .thenReturn(true); + when(mMockContext.checkPermission(mManifestStringCoarse, -1, mUid)) + .thenReturn(mCoarseLocationPermission); + when(mMockContext.checkPermission(mManifestStringFine, -1, mUid)) + .thenReturn(mFineLocationPermission); + when(mLocationManager.isLocationEnabledForUser(any())).thenReturn(mIsLocationEnabled); + } + + private Answer<Integer> createPermissionAnswer() { + return new Answer<Integer>() { + @Override + public Integer answer(InvocationOnMock invocation) { + int myUid = (int) invocation.getArguments()[1]; + String myPermission = (String) invocation.getArguments()[0]; + mPermissionsList.get(myPermission); + if (mPermissionsList.containsKey(myPermission)) { + int uid = mPermissionsList.get(myPermission); + if (myUid == uid) { + return PackageManager.PERMISSION_GRANTED; + } + } + return PackageManager.PERMISSION_DENIED; + } + }; + } + + @Test + public void testEnforceLocationPermission_HasAllPermissions_BeforeQ() throws Exception { + mIsLocationEnabled = true; + mThrowSecurityException = false; + mCoarseLocationPermission = PackageManager.PERMISSION_GRANTED; + mAllowCoarseLocationApps = AppOpsManager.MODE_ALLOWED; + mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED; + mUid = mCurrentUser; + setupTestCase(); + new TestConnectivityUtil(mMockContext) + .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null); + } + + @Test + public void testEnforceLocationPermission_HasAllPermissions_AfterQ() throws Exception { + mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.Q; + mIsLocationEnabled = true; + mThrowSecurityException = false; + mUid = mCurrentUser; + mFineLocationPermission = PackageManager.PERMISSION_GRANTED; + mAllowFineLocationApps = AppOpsManager.MODE_ALLOWED; + mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED; + setupTestCase(); + new TestConnectivityUtil(mMockContext) + .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null); + } + + @Test + public void testEnforceLocationPermission_PkgNameAndUidMismatch() throws Exception { + mThrowSecurityException = true; + mIsLocationEnabled = true; + mFineLocationPermission = PackageManager.PERMISSION_GRANTED; + mAllowFineLocationApps = AppOpsManager.MODE_ALLOWED; + mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED; + setupTestCase(); + + assertThrows(SecurityException.class, + () -> new TestConnectivityUtil(mMockContext) + .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null)); + } + + @Test + public void testenforceCanAccessScanResults_UserOrProfileNotCurrent() throws Exception { + mIsLocationEnabled = true; + mThrowSecurityException = false; + mCoarseLocationPermission = PackageManager.PERMISSION_GRANTED; + mAllowCoarseLocationApps = AppOpsManager.MODE_ALLOWED; + mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED; + setupTestCase(); + + assertThrows(SecurityException.class, + () -> new TestConnectivityUtil(mMockContext) + .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null)); + } + + @Test + public void testenforceCanAccessScanResults_NoCoarseLocationPermission() throws Exception { + mThrowSecurityException = false; + mIsLocationEnabled = true; + setupTestCase(); + assertThrows(SecurityException.class, + () -> new TestConnectivityUtil(mMockContext) + .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null)); + } + + @Test + public void testenforceCanAccessScanResults_NoFineLocationPermission() throws Exception { + mThrowSecurityException = false; + mMockApplInfo.targetSdkVersion = Build.VERSION_CODES.Q; + mIsLocationEnabled = true; + mCoarseLocationPermission = PackageManager.PERMISSION_GRANTED; + mAllowFineLocationApps = AppOpsManager.MODE_ERRORED; + mUid = MANAGED_PROFILE_UID; + setupTestCase(); + + assertThrows(SecurityException.class, + () -> new TestConnectivityUtil(mMockContext) + .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null)); + verify(mMockAppOps, never()).noteOp(anyInt(), anyInt(), anyString()); + } + + @Test + public void testenforceCanAccessScanResults_LocationModeDisabled() throws Exception { + mThrowSecurityException = false; + mUid = MANAGED_PROFILE_UID; + mWifiScanAllowApps = AppOpsManager.MODE_ALLOWED; + mPermissionsList.put(mInteractAcrossUsersFullPermission, mUid); + mIsLocationEnabled = false; + + setupTestCase(); + + assertThrows(SecurityException.class, + () -> new TestConnectivityUtil(mMockContext) + .enforceLocationPermission(TEST_PKG_NAME, TEST_FEATURE_ID, mUid, null)); + } + + private static void assertThrows(Class<? extends Exception> exceptionClass, Runnable r) { + try { + r.run(); + Assert.fail("Expected " + exceptionClass + " to be thrown."); + } catch (Exception exception) { + assertTrue(exceptionClass.isInstance(exception)); + } + } +} diff --git a/data/etc/Android.bp b/data/etc/Android.bp index 4493f3a8dddc..0d12e1f7f83d 100644 --- a/data/etc/Android.bp +++ b/data/etc/Android.bp @@ -43,7 +43,7 @@ prebuilt_etc { prebuilt_etc { name: "privapp_whitelist_com.android.carrierconfig", - product_specific: true, + system_ext_specific: true, sub_dir: "permissions", src: "com.android.carrierconfig.xml", filename_from_src: true, @@ -67,7 +67,7 @@ prebuilt_etc { prebuilt_etc { name: "privapp_whitelist_com.android.emergency", - product_specific: true, + system_ext_specific: true, sub_dir: "permissions", src: "com.android.emergency.xml", filename_from_src: true, @@ -82,7 +82,7 @@ prebuilt_etc { prebuilt_etc { name: "privapp_whitelist_com.android.launcher3", - product_specific: true, + system_ext_specific: true, sub_dir: "permissions", src: "com.android.launcher3.xml", filename_from_src: true, @@ -90,7 +90,7 @@ prebuilt_etc { prebuilt_etc { name: "privapp_whitelist_com.android.provision", - product_specific: true, + system_ext_specific: true, sub_dir: "permissions", src: "com.android.provision.xml", filename_from_src: true, @@ -98,7 +98,7 @@ prebuilt_etc { prebuilt_etc { name: "privapp_whitelist_com.android.settings", - product_specific: true, + system_ext_specific: true, sub_dir: "permissions", src: "com.android.settings.xml", filename_from_src: true, @@ -114,7 +114,7 @@ prebuilt_etc { prebuilt_etc { name: "privapp_whitelist_com.android.storagemanager", - product_specific: true, + system_ext_specific: true, sub_dir: "permissions", src: "com.android.storagemanager.xml", filename_from_src: true, @@ -122,7 +122,7 @@ prebuilt_etc { prebuilt_etc { name: "privapp_whitelist_com.android.systemui", - product_specific: true, + system_ext_specific: true, sub_dir: "permissions", src: "com.android.systemui.xml", filename_from_src: true, diff --git a/data/etc/CleanSpec.mk b/data/etc/CleanSpec.mk new file mode 100644 index 000000000000..783a7edadeb7 --- /dev/null +++ b/data/etc/CleanSpec.mk @@ -0,0 +1,60 @@ +# 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. +# + +# If you don't need to do a full clean build but would like to touch +# a file or delete some intermediate files, add a clean step to the end +# of the list. These steps will only be run once, if they haven't been +# run before. +# +# E.g.: +# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) +# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) +# +# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with +# files that are missing or have been moved. +# +# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. +# Use $(OUT_DIR) to refer to the "out" directory. +# +# If you need to re-do something that's already mentioned, just copy +# the command and add it to the bottom of the list. E.g., if a change +# that you made last week required touching a file and a change you +# made today requires touching the same file, just copy the old +# touch step and add it to the end of the list. +# +# ***************************************************************** +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER +# ***************************************************************** + +# For example: +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.carrierconfig.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.carrierconfig.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.emergency.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.emergency.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.provision.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.provision.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.settings.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.settings.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.launcher3.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.launcher3.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.systemui.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.systemui.xml) +# ****************************************************************** +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER +# ****************************************************************** diff --git a/data/etc/car/Android.bp b/data/etc/car/Android.bp index 9272ea5e584b..7faf4cdcf66d 100644 --- a/data/etc/car/Android.bp +++ b/data/etc/car/Android.bp @@ -126,5 +126,5 @@ prebuilt_etc { sub_dir: "permissions", src: "com.android.car.developeroptions.xml", filename_from_src: true, - product_specific: true, + system_ext_specific: true, } diff --git a/data/etc/car/CleanSpec.mk b/data/etc/car/CleanSpec.mk new file mode 100644 index 000000000000..18f7d343676b --- /dev/null +++ b/data/etc/car/CleanSpec.mk @@ -0,0 +1,50 @@ +# 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. +# + +# If you don't need to do a full clean build but would like to touch +# a file or delete some intermediate files, add a clean step to the end +# of the list. These steps will only be run once, if they haven't been +# run before. +# +# E.g.: +# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) +# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) +# +# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with +# files that are missing or have been moved. +# +# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. +# Use $(OUT_DIR) to refer to the "out" directory. +# +# If you need to re-do something that's already mentioned, just copy +# the command and add it to the bottom of the list. E.g., if a change +# that you made last week required touching a file and a change you +# made today requires touching the same file, just copy the old +# touch step and add it to the end of the list. +# +# ***************************************************************** +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER +# ***************************************************************** + +# For example: +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/etc/permissions/com.android.car.developeroptions.xml) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/etc/permissions/com.android.car.developeroptions.xml) +# ****************************************************************** +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER +# ****************************************************************** diff --git a/data/etc/com.android.systemui.xml b/data/etc/com.android.systemui.xml index a305d48c4633..1d735674d72d 100644 --- a/data/etc/com.android.systemui.xml +++ b/data/etc/com.android.systemui.xml @@ -22,7 +22,6 @@ <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/> <permission name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"/> <permission name="android.permission.CHANGE_OVERLAY_PACKAGES"/> - <permission name="android.permission.CONNECTIVITY_INTERNAL"/> <permission name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS"/> <permission name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS"/> <permission name="android.permission.CONTROL_VPN"/> @@ -38,6 +37,7 @@ <permission name="android.permission.MODIFY_DAY_NIGHT_MODE"/> <permission name="android.permission.MODIFY_PHONE_STATE"/> <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/> + <permission name="android.permission.OBSERVE_NETWORK_POLICY"/> <permission name="android.permission.OVERRIDE_WIFI_CONFIG"/> <permission name="android.permission.READ_DREAM_STATE"/> <permission name="android.permission.READ_FRAME_BUFFER"/> diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index 3477aedefacf..eec2072c6d5d 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -67,7 +67,6 @@ applications that come with the platform <privapp-permissions package="com.android.managedprovisioning"> <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/> <permission name="android.permission.CHANGE_CONFIGURATION"/> - <permission name="android.permission.CONNECTIVITY_INTERNAL"/> <permission name="android.permission.CRYPT_KEEPER"/> <permission name="android.permission.DELETE_PACKAGES"/> <permission name="android.permission.INSTALL_PACKAGES"/> @@ -240,6 +239,7 @@ applications that come with the platform <permission name="android.permission.READ_NETWORK_USAGE_HISTORY"/> <permission name="android.permission.TETHER_PRIVILEGED"/> <permission name="android.permission.UPDATE_APP_OPS_STATS"/> + <permission name="android.permission.UPDATE_DEVICE_STATS"/> </privapp-permissions> <privapp-permissions package="com.android.server.telecom"> @@ -361,7 +361,6 @@ applications that come with the platform </privapp-permissions> <privapp-permissions package="com.android.vpndialogs"> - <permission name="android.permission.CONNECTIVITY_INTERNAL"/> <permission name="android.permission.CONTROL_VPN"/> </privapp-permissions> diff --git a/identity/MODULE_LICENSE_APACHE2 b/identity/MODULE_LICENSE_APACHE2 new file mode 100644 index 000000000000..e69de29bb2d1 --- /dev/null +++ b/identity/MODULE_LICENSE_APACHE2 diff --git a/identity/NOTICE b/identity/NOTICE new file mode 100644 index 000000000000..64aaa8dbd68e --- /dev/null +++ b/identity/NOTICE @@ -0,0 +1,190 @@ + + Copyright (c) 2009, 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. + + 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. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + diff --git a/identity/OWNERS b/identity/OWNERS new file mode 100644 index 000000000000..533d90b2cd13 --- /dev/null +++ b/identity/OWNERS @@ -0,0 +1,3 @@ +swillden@google.com +zeuthen@google.com + diff --git a/identity/java/android/security/identity/AccessControlProfile.java b/identity/java/android/security/identity/AccessControlProfile.java new file mode 100644 index 000000000000..10e451c97707 --- /dev/null +++ b/identity/java/android/security/identity/AccessControlProfile.java @@ -0,0 +1,131 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.identity; + +import android.annotation.NonNull; + +import java.security.cert.X509Certificate; + +/** + * A class used to specify access controls. + */ +public class AccessControlProfile { + private AccessControlProfileId mAccessControlProfileId = new AccessControlProfileId(0); + private X509Certificate mReaderCertificate = null; + private boolean mUserAuthenticationRequired = true; + private long mUserAuthenticationTimeout = 0; + + private AccessControlProfile() { + } + + AccessControlProfileId getAccessControlProfileId() { + return mAccessControlProfileId; + } + + long getUserAuthenticationTimeout() { + return mUserAuthenticationTimeout; + } + + boolean isUserAuthenticationRequired() { + return mUserAuthenticationRequired; + } + + X509Certificate getReaderCertificate() { + return mReaderCertificate; + } + + /** + * A builder for {@link AccessControlProfile}. + */ + public static final class Builder { + private AccessControlProfile mProfile; + + /** + * Each access control profile has numeric identifier that must be unique within the + * context of a Credential and may be used to reference the profile. + * + * <p>By default, the resulting {@link AccessControlProfile} will require user + * authentication with a timeout of zero, thus requiring the holder to authenticate for + * every presentation where data elements using this access control profile is used.</p> + * + * @param accessControlProfileId the access control profile identifier. + */ + public Builder(@NonNull AccessControlProfileId accessControlProfileId) { + mProfile = new AccessControlProfile(); + mProfile.mAccessControlProfileId = accessControlProfileId; + } + + /** + * Set whether user authentication is required. + * + * <p>This should be used sparingly since disabling user authentication on just a single + * data element can easily create a + * <a href="https://en.wikipedia.org/wiki/Relay_attack">Relay Attack</a> if the device + * on which the credential is stored is compromised.</p> + * + * @param userAuthenticationRequired Set to true if user authentication is required, + * false otherwise. + * @return The builder. + */ + public @NonNull Builder setUserAuthenticationRequired(boolean userAuthenticationRequired) { + mProfile.mUserAuthenticationRequired = userAuthenticationRequired; + return this; + } + + /** + * Sets the authentication timeout to use. + * + * <p>The authentication timeout specifies the amount of time, in milliseconds, for which a + * user authentication is valid, if user authentication is required (see + * {@link #setUserAuthenticationRequired(boolean)}).</p> + * + * <p>If the timeout is zero, then authentication is always required for each reader + * session.</p> + * + * @param userAuthenticationTimeoutMillis the authentication timeout, in milliseconds. + * @return The builder. + */ + public @NonNull Builder setUserAuthenticationTimeout(long userAuthenticationTimeoutMillis) { + mProfile.mUserAuthenticationTimeout = userAuthenticationTimeoutMillis; + return this; + } + + /** + * Sets the reader certificate to use when checking access control. + * + * <p>If set, this is checked against the certificate chain presented by + * reader. The access check is fulfilled only if one of the certificates + * in the chain, matches the certificate set by this method.</p> + * + * @param readerCertificate the certificate to use for the access control check. + * @return The builder. + */ + public @NonNull Builder setReaderCertificate(@NonNull X509Certificate readerCertificate) { + mProfile.mReaderCertificate = readerCertificate; + return this; + } + + /** + * Creates a new {@link AccessControlProfile} from the data supplied to the builder. + * + * @return The created {@link AccessControlProfile} object. + */ + public @NonNull AccessControlProfile build() { + return mProfile; + } + } +} diff --git a/identity/java/android/security/identity/AccessControlProfileId.java b/identity/java/android/security/identity/AccessControlProfileId.java new file mode 100644 index 000000000000..3d5945065ad7 --- /dev/null +++ b/identity/java/android/security/identity/AccessControlProfileId.java @@ -0,0 +1,42 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.identity; + +/** + * A class used to wrap an access control profile identifiers. + */ +public class AccessControlProfileId { + private int mId = 0; + + /** + * Constructs a new object holding a numerical identifier. + * + * @param id the identifier. + */ + public AccessControlProfileId(int id) { + this.mId = id; + } + + /** + * Gets the numerical identifier wrapped by this object. + * + * @return the identifier. + */ + public int getId() { + return this.mId; + } +} diff --git a/identity/java/android/security/identity/AlreadyPersonalizedException.java b/identity/java/android/security/identity/AlreadyPersonalizedException.java new file mode 100644 index 000000000000..1933882aa4bf --- /dev/null +++ b/identity/java/android/security/identity/AlreadyPersonalizedException.java @@ -0,0 +1,43 @@ +/* + * 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.security.identity; + +import android.annotation.NonNull; + +/** + * Thrown if trying to create a credential which already exists. + */ +public class AlreadyPersonalizedException extends IdentityCredentialException { + /** + * Constructs a new {@link AlreadyPersonalizedException} exception. + * + * @param message the detail message. + */ + public AlreadyPersonalizedException(@NonNull String message) { + super(message); + } + + /** + * Constructs a new {@link AlreadyPersonalizedException} exception. + * + * @param message the detail message. + * @param cause the cause. + */ + public AlreadyPersonalizedException(@NonNull String message, @NonNull Throwable cause) { + super(message, cause); + } +} diff --git a/identity/java/android/security/identity/CipherSuiteNotSupportedException.java b/identity/java/android/security/identity/CipherSuiteNotSupportedException.java new file mode 100644 index 000000000000..e7a6c8969482 --- /dev/null +++ b/identity/java/android/security/identity/CipherSuiteNotSupportedException.java @@ -0,0 +1,43 @@ +/* + * 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.security.identity; + +import android.annotation.NonNull; + +/** + * Thrown if trying to use a cipher suite which isn't supported. + */ +public class CipherSuiteNotSupportedException extends IdentityCredentialException { + /** + * Constructs a new {@link CipherSuiteNotSupportedException} exception. + * + * @param message the detail message. + */ + public CipherSuiteNotSupportedException(@NonNull String message) { + super(message); + } + + /** + * Constructs a new {@link CipherSuiteNotSupportedException} exception. + * + * @param message the detail message. + * @param cause the cause. + */ + public CipherSuiteNotSupportedException(@NonNull String message, @NonNull Throwable cause) { + super(message, cause); + } +} diff --git a/identity/java/android/security/identity/CredstoreIdentityCredential.java b/identity/java/android/security/identity/CredstoreIdentityCredential.java new file mode 100644 index 000000000000..c520331ab72d --- /dev/null +++ b/identity/java/android/security/identity/CredstoreIdentityCredential.java @@ -0,0 +1,424 @@ +/* + * 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.security.identity; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.LinkedList; +import java.util.Map; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.KeyAgreement; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +class CredstoreIdentityCredential extends IdentityCredential { + + private static final String TAG = "CredstoreIdentityCredential"; + private String mCredentialName; + private @IdentityCredentialStore.Ciphersuite int mCipherSuite; + private Context mContext; + private ICredential mBinder; + + CredstoreIdentityCredential(Context context, String credentialName, + @IdentityCredentialStore.Ciphersuite int cipherSuite, + ICredential binder) { + mContext = context; + mCredentialName = credentialName; + mCipherSuite = cipherSuite; + mBinder = binder; + } + + private KeyPair mEphemeralKeyPair = null; + private SecretKey mSecretKey = null; + private SecretKey mReaderSecretKey = null; + private int mEphemeralCounter; + private int mReadersExpectedEphemeralCounter; + + private void ensureEphemeralKeyPair() { + if (mEphemeralKeyPair != null) { + return; + } + try { + // This PKCS#12 blob is generated in credstore, using BoringSSL. + // + // The main reason for this convoluted approach and not just sending the decomposed + // key-pair is that this would require directly using (device-side) BouncyCastle which + // is tricky due to various API hiding efforts. So instead we have credstore generate + // this PKCS#12 blob. The blob is encrypted with no password (sadly, also, BoringSSL + // doesn't support not using encryption when building a PKCS#12 blob). + // + byte[] pkcs12 = mBinder.createEphemeralKeyPair(); + String alias = "ephemeralKey"; + char[] password = {}; + + KeyStore ks = KeyStore.getInstance("PKCS12"); + ByteArrayInputStream bais = new ByteArrayInputStream(pkcs12); + ks.load(bais, password); + PrivateKey privKey = (PrivateKey) ks.getKey(alias, password); + + Certificate cert = ks.getCertificate(alias); + PublicKey pubKey = cert.getPublicKey(); + + mEphemeralKeyPair = new KeyPair(pubKey, privKey); + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } catch (KeyStoreException + | CertificateException + | UnrecoverableKeyException + | NoSuchAlgorithmException + | IOException e) { + throw new RuntimeException("Unexpected exception ", e); + } + } + + @Override + public @NonNull KeyPair createEphemeralKeyPair() { + ensureEphemeralKeyPair(); + return mEphemeralKeyPair; + } + + @Override + public void setReaderEphemeralPublicKey(@NonNull PublicKey readerEphemeralPublicKey) + throws InvalidKeyException { + try { + byte[] uncompressedForm = + Util.publicKeyEncodeUncompressedForm(readerEphemeralPublicKey); + mBinder.setReaderEphemeralPublicKey(uncompressedForm); + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + + ensureEphemeralKeyPair(); + + try { + KeyAgreement ka = KeyAgreement.getInstance("ECDH"); + ka.init(mEphemeralKeyPair.getPrivate()); + ka.doPhase(readerEphemeralPublicKey, true); + byte[] sharedSecret = ka.generateSecret(); + + byte[] salt = new byte[1]; + byte[] info = new byte[0]; + + salt[0] = 0x01; + byte[] derivedKey = Util.computeHkdf("HmacSha256", sharedSecret, salt, info, 32); + mSecretKey = new SecretKeySpec(derivedKey, "AES"); + + salt[0] = 0x00; + derivedKey = Util.computeHkdf("HmacSha256", sharedSecret, salt, info, 32); + mReaderSecretKey = new SecretKeySpec(derivedKey, "AES"); + + mEphemeralCounter = 0; + mReadersExpectedEphemeralCounter = 0; + + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("Error performing key agreement", e); + } + } + + @Override + public @NonNull byte[] encryptMessageToReader(@NonNull byte[] messagePlaintext) { + byte[] messageCiphertextAndAuthTag = null; + try { + ByteBuffer iv = ByteBuffer.allocate(12); + iv.putInt(0, 0x00000000); + iv.putInt(4, 0x00000001); + iv.putInt(8, mEphemeralCounter); + Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + GCMParameterSpec encryptionParameterSpec = new GCMParameterSpec(128, iv.array()); + cipher.init(Cipher.ENCRYPT_MODE, mSecretKey, encryptionParameterSpec); + messageCiphertextAndAuthTag = cipher.doFinal(messagePlaintext); + } catch (BadPaddingException + | IllegalBlockSizeException + | NoSuchPaddingException + | InvalidKeyException + | NoSuchAlgorithmException + | InvalidAlgorithmParameterException e) { + throw new RuntimeException("Error encrypting message", e); + } + mEphemeralCounter += 1; + return messageCiphertextAndAuthTag; + } + + @Override + public @NonNull byte[] decryptMessageFromReader(@NonNull byte[] messageCiphertext) + throws MessageDecryptionException { + ByteBuffer iv = ByteBuffer.allocate(12); + iv.putInt(0, 0x00000000); + iv.putInt(4, 0x00000000); + iv.putInt(8, mReadersExpectedEphemeralCounter); + byte[] plainText = null; + try { + final Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + cipher.init(Cipher.DECRYPT_MODE, mReaderSecretKey, + new GCMParameterSpec(128, iv.array())); + plainText = cipher.doFinal(messageCiphertext); + } catch (BadPaddingException + | IllegalBlockSizeException + | InvalidAlgorithmParameterException + | InvalidKeyException + | NoSuchAlgorithmException + | NoSuchPaddingException e) { + throw new MessageDecryptionException("Error decrypting message", e); + } + mReadersExpectedEphemeralCounter += 1; + return plainText; + } + + @Override + public @NonNull Collection<X509Certificate> getCredentialKeyCertificateChain() { + try { + byte[] certsBlob = mBinder.getCredentialKeyCertificateChain(); + ByteArrayInputStream bais = new ByteArrayInputStream(certsBlob); + + Collection<? extends Certificate> certs = null; + try { + CertificateFactory factory = CertificateFactory.getInstance("X.509"); + certs = factory.generateCertificates(bais); + } catch (CertificateException e) { + throw new RuntimeException("Error decoding certificates", e); + } + + LinkedList<X509Certificate> x509Certs = new LinkedList<>(); + for (Certificate cert : certs) { + x509Certs.add((X509Certificate) cert); + } + return x509Certs; + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + + private boolean mAllowUsingExhaustedKeys = true; + + @Override + public void setAllowUsingExhaustedKeys(boolean allowUsingExhaustedKeys) { + mAllowUsingExhaustedKeys = allowUsingExhaustedKeys; + } + + private boolean mOperationHandleSet = false; + private long mOperationHandle = 0; + + /** + * Called by android.hardware.biometrics.CryptoObject#getOpId() to get an + * operation handle. + * + * @hide + */ + @Override + public long getCredstoreOperationHandle() { + if (!mOperationHandleSet) { + try { + mOperationHandle = mBinder.selectAuthKey(mAllowUsingExhaustedKeys); + mOperationHandleSet = true; + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + if (e.errorCode == ICredentialStore.ERROR_NO_AUTHENTICATION_KEY_AVAILABLE) { + // The NoAuthenticationKeyAvailableException will be thrown when + // the caller proceeds to call getEntries(). + } + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + return mOperationHandle; + } + + @NonNull + @Override + public ResultData getEntries( + @Nullable byte[] requestMessage, + @NonNull Map<String, Collection<String>> entriesToRequest, + @Nullable byte[] sessionTranscript, + @Nullable byte[] readerSignature) + throws SessionTranscriptMismatchException, NoAuthenticationKeyAvailableException, + InvalidReaderSignatureException, EphemeralPublicKeyNotFoundException, + InvalidRequestMessageException { + + RequestNamespaceParcel[] rnsParcels = new RequestNamespaceParcel[entriesToRequest.size()]; + int n = 0; + for (String namespaceName : entriesToRequest.keySet()) { + Collection<String> entryNames = entriesToRequest.get(namespaceName); + rnsParcels[n] = new RequestNamespaceParcel(); + rnsParcels[n].namespaceName = namespaceName; + rnsParcels[n].entries = new RequestEntryParcel[entryNames.size()]; + int m = 0; + for (String entryName : entryNames) { + rnsParcels[n].entries[m] = new RequestEntryParcel(); + rnsParcels[n].entries[m].name = entryName; + m++; + } + n++; + } + + GetEntriesResultParcel resultParcel = null; + try { + resultParcel = mBinder.getEntries( + requestMessage != null ? requestMessage : new byte[0], + rnsParcels, + sessionTranscript != null ? sessionTranscript : new byte[0], + readerSignature != null ? readerSignature : new byte[0], + mAllowUsingExhaustedKeys); + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + if (e.errorCode == ICredentialStore.ERROR_EPHEMERAL_PUBLIC_KEY_NOT_FOUND) { + throw new EphemeralPublicKeyNotFoundException(e.getMessage(), e); + } else if (e.errorCode == ICredentialStore.ERROR_INVALID_READER_SIGNATURE) { + throw new InvalidReaderSignatureException(e.getMessage(), e); + } else if (e.errorCode == ICredentialStore.ERROR_NO_AUTHENTICATION_KEY_AVAILABLE) { + throw new NoAuthenticationKeyAvailableException(e.getMessage(), e); + } else if (e.errorCode == ICredentialStore.ERROR_INVALID_ITEMS_REQUEST_MESSAGE) { + throw new InvalidRequestMessageException(e.getMessage(), e); + } else if (e.errorCode == ICredentialStore.ERROR_SESSION_TRANSCRIPT_MISMATCH) { + throw new SessionTranscriptMismatchException(e.getMessage(), e); + } else { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + + byte[] mac = resultParcel.mac; + if (mac != null && mac.length == 0) { + mac = null; + } + CredstoreResultData.Builder resultDataBuilder = new CredstoreResultData.Builder( + resultParcel.staticAuthenticationData, resultParcel.deviceNameSpaces, mac); + + for (ResultNamespaceParcel resultNamespaceParcel : resultParcel.resultNamespaces) { + for (ResultEntryParcel resultEntryParcel : resultNamespaceParcel.entries) { + if (resultEntryParcel.status == ICredential.STATUS_OK) { + resultDataBuilder.addEntry(resultNamespaceParcel.namespaceName, + resultEntryParcel.name, resultEntryParcel.value); + } else { + resultDataBuilder.addErrorStatus(resultNamespaceParcel.namespaceName, + resultEntryParcel.name, + resultEntryParcel.status); + } + } + } + return resultDataBuilder.build(); + } + + @Override + public void setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey) { + try { + mBinder.setAvailableAuthenticationKeys(keyCount, maxUsesPerKey); + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + + @Override + public @NonNull Collection<X509Certificate> getAuthKeysNeedingCertification() { + try { + AuthKeyParcel[] authKeyParcels = mBinder.getAuthKeysNeedingCertification(); + LinkedList<X509Certificate> x509Certs = new LinkedList<>(); + CertificateFactory factory = CertificateFactory.getInstance("X.509"); + for (AuthKeyParcel authKeyParcel : authKeyParcels) { + Collection<? extends Certificate> certs = null; + ByteArrayInputStream bais = new ByteArrayInputStream(authKeyParcel.x509cert); + certs = factory.generateCertificates(bais); + if (certs.size() != 1) { + throw new RuntimeException("Returned blob yields more than one X509 cert"); + } + X509Certificate authKeyCert = (X509Certificate) certs.iterator().next(); + x509Certs.add(authKeyCert); + } + return x509Certs; + } catch (CertificateException e) { + throw new RuntimeException("Error decoding authenticationKey", e); + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + + @Override + public void storeStaticAuthenticationData(X509Certificate authenticationKey, + byte[] staticAuthData) + throws UnknownAuthenticationKeyException { + try { + AuthKeyParcel authKeyParcel = new AuthKeyParcel(); + authKeyParcel.x509cert = authenticationKey.getEncoded(); + mBinder.storeStaticAuthenticationData(authKeyParcel, staticAuthData); + } catch (CertificateEncodingException e) { + throw new RuntimeException("Error encoding authenticationKey", e); + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + if (e.errorCode == ICredentialStore.ERROR_AUTHENTICATION_KEY_NOT_FOUND) { + throw new UnknownAuthenticationKeyException(e.getMessage(), e); + } else { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + } + + @Override + public @NonNull int[] getAuthenticationDataUsageCount() { + try { + int[] usageCount = mBinder.getAuthenticationDataUsageCount(); + return usageCount; + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } +} diff --git a/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java b/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java new file mode 100644 index 000000000000..dcc6b95aec02 --- /dev/null +++ b/identity/java/android/security/identity/CredstoreIdentityCredentialStore.java @@ -0,0 +1,162 @@ +/* + * 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.security.identity; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; +import android.os.ServiceManager; + +class CredstoreIdentityCredentialStore extends IdentityCredentialStore { + + private static final String TAG = "CredstoreIdentityCredentialStore"; + + private Context mContext = null; + private ICredentialStore mStore = null; + + private CredstoreIdentityCredentialStore(@NonNull Context context, ICredentialStore store) { + mContext = context; + mStore = store; + } + + static CredstoreIdentityCredentialStore getInstanceForType(@NonNull Context context, + int credentialStoreType) { + ICredentialStoreFactory storeFactory = + ICredentialStoreFactory.Stub.asInterface( + ServiceManager.getService("android.security.identity")); + + ICredentialStore credStore = null; + try { + credStore = storeFactory.getCredentialStore(credentialStoreType); + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + if (e.errorCode == ICredentialStore.ERROR_GENERIC) { + return null; + } else { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + if (credStore == null) { + return null; + } + + return new CredstoreIdentityCredentialStore(context, credStore); + } + + private static CredstoreIdentityCredentialStore sInstanceDefault = null; + private static CredstoreIdentityCredentialStore sInstanceDirectAccess = null; + + public static @Nullable IdentityCredentialStore getInstance(@NonNull Context context) { + if (sInstanceDefault == null) { + sInstanceDefault = getInstanceForType(context, + ICredentialStoreFactory.CREDENTIAL_STORE_TYPE_DEFAULT); + } + return sInstanceDefault; + } + + public static @Nullable IdentityCredentialStore getDirectAccessInstance(@NonNull + Context context) { + if (sInstanceDirectAccess == null) { + sInstanceDirectAccess = getInstanceForType(context, + ICredentialStoreFactory.CREDENTIAL_STORE_TYPE_DIRECT_ACCESS); + } + return sInstanceDirectAccess; + } + + @Override + public @NonNull String[] getSupportedDocTypes() { + try { + SecurityHardwareInfoParcel info; + info = mStore.getSecurityHardwareInfo(); + return info.supportedDocTypes; + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + + @Override public @NonNull WritableIdentityCredential createCredential( + @NonNull String credentialName, + @NonNull String docType) throws AlreadyPersonalizedException, + DocTypeNotSupportedException { + try { + IWritableCredential wc; + wc = mStore.createCredential(credentialName, docType); + return new CredstoreWritableIdentityCredential(mContext, credentialName, docType, wc); + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + if (e.errorCode == ICredentialStore.ERROR_ALREADY_PERSONALIZED) { + throw new AlreadyPersonalizedException(e.getMessage(), e); + } else if (e.errorCode == ICredentialStore.ERROR_DOCUMENT_TYPE_NOT_SUPPORTED) { + throw new DocTypeNotSupportedException(e.getMessage(), e); + } else { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + } + + @Override public @Nullable IdentityCredential getCredentialByName( + @NonNull String credentialName, + @Ciphersuite int cipherSuite) throws CipherSuiteNotSupportedException { + try { + ICredential credstoreCredential; + credstoreCredential = mStore.getCredentialByName(credentialName, cipherSuite); + return new CredstoreIdentityCredential(mContext, credentialName, cipherSuite, + credstoreCredential); + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + if (e.errorCode == ICredentialStore.ERROR_NO_SUCH_CREDENTIAL) { + return null; + } else if (e.errorCode == ICredentialStore.ERROR_CIPHER_SUITE_NOT_SUPPORTED) { + throw new CipherSuiteNotSupportedException(e.getMessage(), e); + } else { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + } + + @Override + public @Nullable byte[] deleteCredentialByName(@NonNull String credentialName) { + ICredential credstoreCredential = null; + try { + try { + credstoreCredential = mStore.getCredentialByName(credentialName, + CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256); + } catch (android.os.ServiceSpecificException e) { + if (e.errorCode == ICredentialStore.ERROR_NO_SUCH_CREDENTIAL) { + return null; + } + } + byte[] proofOfDeletion = credstoreCredential.deleteCredential(); + return proofOfDeletion; + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + +} diff --git a/identity/java/android/security/identity/CredstoreResultData.java b/identity/java/android/security/identity/CredstoreResultData.java new file mode 100644 index 000000000000..ef7afca6b888 --- /dev/null +++ b/identity/java/android/security/identity/CredstoreResultData.java @@ -0,0 +1,162 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.identity; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.Map; + +/** + * An object that contains the result of retrieving data from a credential. This is used to return + * data requested from a {@link IdentityCredential}. + */ +class CredstoreResultData extends ResultData { + + byte[] mStaticAuthenticationData = null; + byte[] mAuthenticatedData = null; + byte[] mMessageAuthenticationCode = null; + + private Map<String, Map<String, EntryData>> mData = new LinkedHashMap<>(); + + private static class EntryData { + @Status + int mStatus; + byte[] mValue; + + EntryData(byte[] value, @Status int status) { + this.mValue = value; + this.mStatus = status; + } + } + + CredstoreResultData() {} + + @Override + public @NonNull byte[] getAuthenticatedData() { + return mAuthenticatedData; + } + + @Override + public @Nullable byte[] getMessageAuthenticationCode() { + return mMessageAuthenticationCode; + } + + @Override + public @NonNull byte[] getStaticAuthenticationData() { + return mStaticAuthenticationData; + } + + @Override + public @NonNull Collection<String> getNamespaceNames() { + return Collections.unmodifiableCollection(mData.keySet()); + } + + @Override + public @Nullable Collection<String> getEntryNames(@NonNull String namespaceName) { + Map<String, EntryData> innerMap = mData.get(namespaceName); + if (innerMap == null) { + return null; + } + return Collections.unmodifiableCollection(innerMap.keySet()); + } + + @Override + public @Nullable Collection<String> getRetrievedEntryNames(@NonNull String namespaceName) { + Map<String, EntryData> innerMap = mData.get(namespaceName); + if (innerMap == null) { + return null; + } + LinkedList<String> result = new LinkedList<String>(); + for (Map.Entry<String, EntryData> entry : innerMap.entrySet()) { + if (entry.getValue().mStatus == STATUS_OK) { + result.add(entry.getKey()); + } + } + return result; + } + + private EntryData getEntryData(@NonNull String namespaceName, @NonNull String name) { + Map<String, EntryData> innerMap = mData.get(namespaceName); + if (innerMap == null) { + return null; + } + return innerMap.get(name); + } + + @Override + @Status + public int getStatus(@NonNull String namespaceName, @NonNull String name) { + EntryData value = getEntryData(namespaceName, name); + if (value == null) { + return STATUS_NOT_REQUESTED; + } + return value.mStatus; + } + + @Override + public @Nullable byte[] getEntry(@NonNull String namespaceName, @NonNull String name) { + EntryData value = getEntryData(namespaceName, name); + if (value == null) { + return null; + } + return value.mValue; + } + + static class Builder { + private CredstoreResultData mResultData; + + Builder(byte[] staticAuthenticationData, + byte[] authenticatedData, + byte[] messageAuthenticationCode) { + this.mResultData = new CredstoreResultData(); + this.mResultData.mStaticAuthenticationData = staticAuthenticationData; + this.mResultData.mAuthenticatedData = authenticatedData; + this.mResultData.mMessageAuthenticationCode = messageAuthenticationCode; + } + + private Map<String, EntryData> getOrCreateInnerMap(String namespaceName) { + Map<String, EntryData> innerMap = mResultData.mData.get(namespaceName); + if (innerMap == null) { + innerMap = new LinkedHashMap<>(); + mResultData.mData.put(namespaceName, innerMap); + } + return innerMap; + } + + Builder addEntry(String namespaceName, String name, byte[] value) { + Map<String, EntryData> innerMap = getOrCreateInnerMap(namespaceName); + innerMap.put(name, new EntryData(value, STATUS_OK)); + return this; + } + + Builder addErrorStatus(String namespaceName, String name, @Status int status) { + Map<String, EntryData> innerMap = getOrCreateInnerMap(namespaceName); + innerMap.put(name, new EntryData(null, status)); + return this; + } + + CredstoreResultData build() { + return mResultData; + } + } + +} diff --git a/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java b/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java new file mode 100644 index 000000000000..335636cb07ae --- /dev/null +++ b/identity/java/android/security/identity/CredstoreWritableIdentityCredential.java @@ -0,0 +1,168 @@ +/* + * 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.security.identity; + +import android.annotation.NonNull; +import android.content.Context; +import android.security.GateKeeper; + +import java.io.ByteArrayInputStream; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.LinkedList; + +class CredstoreWritableIdentityCredential extends WritableIdentityCredential { + + private static final String TAG = "CredstoreWritableIdentityCredential"; + + private String mDocType; + private String mCredentialName; + private Context mContext; + private IWritableCredential mBinder; + + CredstoreWritableIdentityCredential(Context context, + @NonNull String credentialName, + @NonNull String docType, + IWritableCredential binder) { + mContext = context; + mDocType = docType; + mCredentialName = credentialName; + mBinder = binder; + } + + @NonNull @Override + public Collection<X509Certificate> getCredentialKeyCertificateChain(@NonNull byte[] challenge) { + try { + byte[] certsBlob = mBinder.getCredentialKeyCertificateChain(challenge); + ByteArrayInputStream bais = new ByteArrayInputStream(certsBlob); + + Collection<? extends Certificate> certs = null; + try { + CertificateFactory factory = CertificateFactory.getInstance("X.509"); + certs = factory.generateCertificates(bais); + } catch (CertificateException e) { + throw new RuntimeException("Error decoding certificates", e); + } + + LinkedList<X509Certificate> x509Certs = new LinkedList<>(); + for (Certificate cert : certs) { + x509Certs.add((X509Certificate) cert); + } + return x509Certs; + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + + @NonNull @Override + public byte[] personalize(@NonNull PersonalizationData personalizationData) { + + Collection<AccessControlProfile> accessControlProfiles = + personalizationData.getAccessControlProfiles(); + + AccessControlProfileParcel[] acpParcels = + new AccessControlProfileParcel[accessControlProfiles.size()]; + boolean usingUserAuthentication = false; + int n = 0; + for (AccessControlProfile profile : accessControlProfiles) { + acpParcels[n] = new AccessControlProfileParcel(); + acpParcels[n].id = profile.getAccessControlProfileId().getId(); + X509Certificate cert = profile.getReaderCertificate(); + if (cert != null) { + try { + acpParcels[n].readerCertificate = cert.getEncoded(); + } catch (CertificateException e) { + throw new RuntimeException("Error encoding reader certificate", e); + } + } else { + acpParcels[n].readerCertificate = new byte[0]; + } + acpParcels[n].userAuthenticationRequired = profile.isUserAuthenticationRequired(); + acpParcels[n].userAuthenticationTimeoutMillis = profile.getUserAuthenticationTimeout(); + if (profile.isUserAuthenticationRequired()) { + usingUserAuthentication = true; + } + n++; + } + + Collection<String> namespaceNames = personalizationData.getNamespaceNames(); + + EntryNamespaceParcel[] ensParcels = new EntryNamespaceParcel[namespaceNames.size()]; + n = 0; + for (String namespaceName : namespaceNames) { + PersonalizationData.NamespaceData nsd = + personalizationData.getNamespaceData(namespaceName); + + ensParcels[n] = new EntryNamespaceParcel(); + ensParcels[n].namespaceName = namespaceName; + + Collection<String> entryNames = nsd.getEntryNames(); + EntryParcel[] eParcels = new EntryParcel[entryNames.size()]; + int m = 0; + for (String entryName : entryNames) { + eParcels[m] = new EntryParcel(); + eParcels[m].name = entryName; + eParcels[m].value = nsd.getEntryValue(entryName); + Collection<AccessControlProfileId> acpIds = + nsd.getAccessControlProfileIds(entryName); + eParcels[m].accessControlProfileIds = new int[acpIds.size()]; + int o = 0; + for (AccessControlProfileId acpId : acpIds) { + eParcels[m].accessControlProfileIds[o++] = acpId.getId(); + } + m++; + } + ensParcels[n].entries = eParcels; + n++; + } + + // Note: The value 0 is used to convey that no user-authentication is needed for this + // credential. This is to allow creating credentials w/o user authentication on devices + // where Secure lock screen is not enabled. + long secureUserId = 0; + if (usingUserAuthentication) { + secureUserId = getRootSid(); + } + try { + byte[] personalizationReceipt = mBinder.personalize(acpParcels, ensParcels, + secureUserId); + return personalizationReceipt; + } catch (android.os.RemoteException e) { + throw new RuntimeException("Unexpected RemoteException ", e); + } catch (android.os.ServiceSpecificException e) { + throw new RuntimeException("Unexpected ServiceSpecificException with code " + + e.errorCode, e); + } + } + + private static long getRootSid() { + long rootSid = GateKeeper.getSecureUserId(); + if (rootSid == 0) { + throw new IllegalStateException("Secure lock screen must be enabled" + + " to create credentials requiring user authentication"); + } + return rootSid; + } + + +} diff --git a/identity/java/android/security/identity/DocTypeNotSupportedException.java b/identity/java/android/security/identity/DocTypeNotSupportedException.java new file mode 100644 index 000000000000..754e44af5411 --- /dev/null +++ b/identity/java/android/security/identity/DocTypeNotSupportedException.java @@ -0,0 +1,43 @@ +/* + * 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.security.identity; + +import android.annotation.NonNull; + +/** + * Thrown if trying to create a credential with an unsupported document type. + */ +public class DocTypeNotSupportedException extends IdentityCredentialException { + /** + * Constructs a new {@link DocTypeNotSupportedException} exception. + * + * @param message the detail message. + */ + public DocTypeNotSupportedException(@NonNull String message) { + super(message); + } + + /** + * Constructs a new {@link DocTypeNotSupportedException} exception. + * + * @param message the detail message. + * @param cause the cause. + */ + public DocTypeNotSupportedException(@NonNull String message, @NonNull Throwable cause) { + super(message, cause); + } +} diff --git a/identity/java/android/security/identity/EphemeralPublicKeyNotFoundException.java b/identity/java/android/security/identity/EphemeralPublicKeyNotFoundException.java new file mode 100644 index 000000000000..265f271b54f7 --- /dev/null +++ b/identity/java/android/security/identity/EphemeralPublicKeyNotFoundException.java @@ -0,0 +1,44 @@ +/* + * 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.security.identity; + +import android.annotation.NonNull; + +/** + * Thrown if the ephemeral public key was not found in the session transcript + * passed to {@link IdentityCredential#getEntries(byte[], Map, byte[], byte[])}. + */ +public class EphemeralPublicKeyNotFoundException extends IdentityCredentialException { + /** + * Constructs a new {@link EphemeralPublicKeyNotFoundException} exception. + * + * @param message the detail message. + */ + public EphemeralPublicKeyNotFoundException(@NonNull String message) { + super(message); + } + + /** + * Constructs a new {@link EphemeralPublicKeyNotFoundException} exception. + * + * @param message the detail message. + * @param cause the cause. + */ + public EphemeralPublicKeyNotFoundException(@NonNull String message, @NonNull Throwable cause) { + super(message, cause); + } +} diff --git a/identity/java/android/security/identity/IdentityCredential.java b/identity/java/android/security/identity/IdentityCredential.java new file mode 100644 index 000000000000..bd439199f914 --- /dev/null +++ b/identity/java/android/security/identity/IdentityCredential.java @@ -0,0 +1,309 @@ +/* + * 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.security.identity; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.PublicKey; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.Map; + +/** + * Class used to read data from a previously provisioned credential. + * + * Use {@link IdentityCredentialStore#getCredentialByName(String, int)} to get a + * {@link IdentityCredential} instance. + */ +public abstract class IdentityCredential { + /** + * @hide + */ + protected IdentityCredential() {} + + /** + * Create an ephemeral key pair to use to establish a secure channel with a reader. + * + * <p>Most applications will use only the public key, and only to send it to the reader, + * allowing the private key to be used internally for {@link #encryptMessageToReader(byte[])} + * and {@link #decryptMessageFromReader(byte[])}. The private key is also provided for + * applications that wish to use a cipher suite that is not supported by + * {@link IdentityCredentialStore}. + * + * @return ephemeral key pair to use to establish a secure channel with a reader. + */ + public @NonNull abstract KeyPair createEphemeralKeyPair(); + + /** + * Set the ephemeral public key provided by the reader. This must be called before + * {@link #encryptMessageToReader} or {@link #decryptMessageFromReader} can be called. + * + * @param readerEphemeralPublicKey The ephemeral public key provided by the reader to + * establish a secure session. + * @throws InvalidKeyException if the given key is invalid. + */ + public abstract void setReaderEphemeralPublicKey(@NonNull PublicKey readerEphemeralPublicKey) + throws InvalidKeyException; + + /** + * Encrypt a message for transmission to the reader. + * + * @param messagePlaintext unencrypted message to encrypt. + * @return encrypted message. + */ + public @NonNull abstract byte[] encryptMessageToReader(@NonNull byte[] messagePlaintext); + + /** + * Decrypt a message received from the reader. + * + * @param messageCiphertext encrypted message to decrypt. + * @return decrypted message. + * @throws MessageDecryptionException if the ciphertext couldn't be decrypted. + */ + public @NonNull abstract byte[] decryptMessageFromReader(@NonNull byte[] messageCiphertext) + throws MessageDecryptionException; + + /** + * Gets the X.509 certificate chain for the CredentialKey which identifies this + * credential to the issuing authority. This is the same certificate chain that + * was returned by {@link WritableIdentityCredential#getCredentialKeyCertificateChain(byte[])} + * when the credential was first created and its Android Keystore extension will + * contain the <code>challenge</code> data set at that time. See the documentation + * for that method for important information about this certificate chain. + * + * @return the certificate chain for this credential's CredentialKey. + */ + public @NonNull abstract Collection<X509Certificate> getCredentialKeyCertificateChain(); + + /** + * Sets whether to allow using an authentication key which use count has been exceeded if no + * other key is available. This must be called prior to calling + * {@link #getEntries(byte[], Map, byte[], byte[])} or using a + * {@link android.hardware.biometrics.BiometricPrompt.CryptoObject} which references this + * object. + * + * By default this is set to true. + * + * @param allowUsingExhaustedKeys whether to allow using an authentication key which use count + * has been exceeded if no other key is available. + */ + public abstract void setAllowUsingExhaustedKeys(boolean allowUsingExhaustedKeys); + + /** + * Called by android.hardware.biometrics.CryptoObject#getOpId() to get an + * operation handle. + * + * @hide + */ + public abstract long getCredstoreOperationHandle(); + + /** + * Retrieve data entries and associated data from this {@code IdentityCredential}. + * + * <p>If an access control check fails for one of the requested entries or if the entry + * doesn't exist, the entry is simply not returned. The application can detect this + * by using the {@link ResultData#getStatus(String, String)} method on each of the requested + * entries. + * + * <p>It is the responsibility of the calling application to know if authentication is needed + * and use e.g. {@link android.hardware.biometrics.BiometricPrompt}) to make the user + * authenticate using a {@link android.hardware.biometrics.BiometricPrompt.CryptoObject} which + * references this object. If needed, this must be done before calling + * {@link #getEntries(byte[], Map, byte[], byte[])}. + * + * <p>If this method returns successfully (i.e. without throwing an exception), it must not be + * called again on this instance. + * + * <p>If not {@code null} the {@code requestMessage} parameter must contain data for the request + * from the verifier. The content can be defined in the way appropriate for the credential, byt + * there are three requirements that must be met to work with this API: + * <ul> + * <li>The content must be a CBOR-encoded structure.</li> + * <li>The CBOR structure must be a map.</li> + * <li>The map must contain a tstr key "nameSpaces" whose value contains a map, as described in + * the example below.</li> + * </ul> + * + * <p>Here's an example of CBOR which conforms to this requirement: + * <pre> + * ItemsRequest = { + * ? "docType" : DocType, + * "nameSpaces" : NameSpaces, + * ? "RequestInfo" : {* tstr => any} ; Additional info the reader wants to provide + * } + * + * NameSpaces = { + * + NameSpace => DataElements ; Requested data elements for each NameSpace + * } + * + * NameSpace = tstr + * + * DataElements = { + * + DataElement => IntentToRetain + * } + * + * DataElement = tstr + * IntentToRetain = bool + * </pre> + * + * <p>If the {@code sessionTranscript} parameter is not {@code null}, it must contain CBOR + * data conforming to the following CDDL schema: + * + * <pre> + * SessionTranscript = [ + * DeviceEngagementBytes, + * EReaderKeyBytes + * ] + * + * DeviceEngagementBytes = #6.24(bstr .cbor DeviceEngagement) + * EReaderKeyBytes = #6.24(bstr .cbor EReaderKey.Pub) + * </pre> + * + * <p>If the SessionTranscript is not empty, a COSE_Key structure for the public part + * of the key-pair previously generated by {@link #createEphemeralKeyPair()} must appear + * somewhere in {@code DeviceEngagement} and the X and Y coordinates must both be present + * in uncompressed form. + * + * <p>If {@code readerAuth} is not {@code null} it must be the bytes of a COSE_Sign1 + * structure as defined in RFC 8152. For the payload nil shall be used and the + * detached payload is the ReaderAuthentication CBOR described below. + * <pre> + * ReaderAuthentication = [ + * "ReaderAuthentication", + * SessionTranscript, + * ItemsRequestBytes + * ] + * + * ItemsRequestBytes = #6.24(bstr .cbor ItemsRequest) ; Bytes of ItemsRequest + * </pre> + * + * <p>The public key corresponding to the key used to made signature, can be + * found in the {@code x5chain} unprotected header element of the COSE_Sign1 + * structure (as as described in 'draft-ietf-cose-x509-04'). There will be at + * least one certificate in said element and there may be more (and if so, + * each certificate must be signed by its successor). + * + * <p>Data elements protected by reader authentication is returned if, and only if, they are + * mentioned in {@code requestMessage}, {@code requestMessage} is signed by the top-most + * certificate in {@code readerCertificateChain}, and the data element is configured + * with an {@link AccessControlProfile} with a {@link X509Certificate} in + * {@code readerCertificateChain}. + * + * <p>Note that only items referenced in {@code entriesToRequest} are returned - the + * {@code requestMessage} parameter is only used to for enforcing reader authentication. + * + * @param requestMessage If not {@code null}, must contain CBOR data conforming to + * the schema mentioned above. + * @param entriesToRequest The entries to request, organized as a map of namespace + * names with each value being a collection of data elements + * in the given namespace. + * @param readerSignature COSE_Sign1 structure as described above or {@code null} + * if reader authentication is not being used. + * @return A {@link ResultData} object containing entry data organized by namespace and a + * cryptographically authenticated representation of the same data. + * @throws SessionTranscriptMismatchException Thrown when trying use multiple different + * session transcripts in the same presentation + * session. + * @throws NoAuthenticationKeyAvailableException if authentication keys were never + * provisioned, the method + * {@link #setAvailableAuthenticationKeys(int, int)} + * was called with {@code keyCount} set to 0, + * the method + * {@link #setAllowUsingExhaustedKeys(boolean)} + * was called with {@code false} and all + * available authentication keys have been + * exhausted. + * @throws InvalidReaderSignatureException if the reader signature is invalid, or it + * doesn't contain a certificate chain, or if + * the signature failed to validate. + * @throws InvalidRequestMessageException if the requestMessage is malformed. + * @throws EphemeralPublicKeyNotFoundException if the ephemeral public key was not found in + * the session transcript. + */ + public abstract @NonNull ResultData getEntries( + @Nullable byte[] requestMessage, + @NonNull Map<String, Collection<String>> entriesToRequest, + @Nullable byte[] sessionTranscript, + @Nullable byte[] readerSignature) + throws SessionTranscriptMismatchException, NoAuthenticationKeyAvailableException, + InvalidReaderSignatureException, EphemeralPublicKeyNotFoundException, + InvalidRequestMessageException; + + /** + * Sets the number of dynamic authentication keys the {@code IdentityCredential} will maintain, + * and the number of times each should be used. + * + * <p>{@code IdentityCredential}s will select the least-used dynamic authentication key each + * time {@link #getEntries(byte[], Map, byte[], byte[])} is called. {@code IdentityCredential}s + * for which this method has not been called behave as though it had been called wit + * {@code keyCount} 0 and {@code maxUsesPerKey} 1. + * + * @param keyCount The number of active, certified dynamic authentication keys the + * {@code IdentityCredential} will try to keep available. This value + * must be non-negative. + * @param maxUsesPerKey The maximum number of times each of the keys will be used before it's + * eligible for replacement. This value must be greater than zero. + */ + public abstract void setAvailableAuthenticationKeys(int keyCount, int maxUsesPerKey); + + /** + * Gets a collection of dynamic authentication keys that need certification. + * + * <p>When there aren't enough certified dynamic authentication keys, either because the key + * count has been increased or because one or more keys have reached their usage count, this + * method will generate replacement keys and certificates and return them for issuer + * certification. The issuer certificates and associated static authentication data must then + * be provided back to the {@code IdentityCredential} using + * {@link #storeStaticAuthenticationData(X509Certificate, byte[])}. + * + * <p>Each X.509 certificate is signed by CredentialKey. The certificate chain for CredentialKey + * can be obtained using the {@link #getCredentialKeyCertificateChain()} method. + * + * @return A collection of X.509 certificates for dynamic authentication keys that need issuer + * certification. + */ + public @NonNull abstract Collection<X509Certificate> getAuthKeysNeedingCertification(); + + /** + * Store authentication data associated with a dynamic authentication key. + * + * This should only be called for an authenticated key returned by + * {@link #getAuthKeysNeedingCertification()}. + * + * @param authenticationKey The dynamic authentication key for which certification and + * associated static + * authentication data is being provided. + * @param staticAuthData Static authentication data provided by the issuer that validates + * the authenticity + * and integrity of the credential data fields. + * @throws UnknownAuthenticationKeyException If the given authentication key is not recognized. + */ + public abstract void storeStaticAuthenticationData( + @NonNull X509Certificate authenticationKey, + @NonNull byte[] staticAuthData) + throws UnknownAuthenticationKeyException; + + /** + * Get the number of times the dynamic authentication keys have been used. + * + * @return int array of dynamic authentication key usage counts. + */ + public @NonNull abstract int[] getAuthenticationDataUsageCount(); +} diff --git a/identity/java/android/security/identity/IdentityCredentialException.java b/identity/java/android/security/identity/IdentityCredentialException.java new file mode 100644 index 000000000000..c8113803d5d3 --- /dev/null +++ b/identity/java/android/security/identity/IdentityCredentialException.java @@ -0,0 +1,44 @@ +/* + * 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.security.identity; + +import android.annotation.NonNull; + +/** + * Base class for all Identity Credential exceptions. + */ +public class IdentityCredentialException extends Exception { + /** + * Constructs a new {@link IdentityCredentialException} exception. + * + * @param message the detail message. + */ + public IdentityCredentialException(@NonNull String message) { + super(message); + } + + /** + * Constructs a new {@link IdentityCredentialException} exception. + * + * @param message the detail message. + * @param cause the cause. + */ + public IdentityCredentialException(@NonNull String message, @NonNull Throwable cause) { + super(message, cause); + } + +} diff --git a/identity/java/android/security/identity/IdentityCredentialStore.java b/identity/java/android/security/identity/IdentityCredentialStore.java new file mode 100644 index 000000000000..a1dfc77adb29 --- /dev/null +++ b/identity/java/android/security/identity/IdentityCredentialStore.java @@ -0,0 +1,186 @@ +/* + * 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.security.identity; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.Context; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * An interface to a secure store for user identity documents. + * + * <p>This interface is deliberately fairly general and abstract. To the extent possible, + * specification of the message formats and semantics of communication with credential + * verification devices and issuing authorities (IAs) is out of scope. It provides the + * interface with secure storage but a credential-specific Android application will be + * required to implement the presentation and verification protocols and processes + * appropriate for the specific credential type. + * + * <p>Multiple credentials can be created. Each credential comprises:</p> + * <ul> + * <li>A document type, which is a string.</li> + * + * <li>A set of namespaces, which serve to disambiguate value names. It is recommended + * that namespaces be structured as reverse domain names so that IANA effectively serves + * as the namespace registrar.</li> + * + * <li>For each namespace, a set of name/value pairs, each with an associated set of + * access control profile IDs. Names are strings and values are typed and can be any + * value supported by <a href="http://cbor.io/">CBOR</a>.</li> + * + * <li>A set of access control profiles, each with a profile ID and a specification + * of the conditions which satisfy the profile's requirements.</li> + * + * <li>An asymmetric key pair which is used to authenticate the credential to the Issuing + * Authority, called the <em>CredentialKey</em>.</li> + * + * <li>A set of zero or more named reader authentication public keys, which are used to + * authenticate an authorized reader to the credential.</li> + * + * <li>A set of named signing keys, which are used to sign collections of values and session + * transcripts.</li> + * </ul> + * + * <p>Implementing support for user identity documents in secure storage requires dedicated + * hardware-backed support and may not always be available. + * + * <p>Two different credential stores exist - the <em>default</em> store and the + * <em>direct access</em> store. Most often credentials will be accessed through the default + * store but that requires that the Android device be powered up and fully functional. + * It is desirable to allow identity credential usage when the Android device's battery is too + * low to boot the Android operating system, so direct access to the secure hardware via NFC + * may allow data retrieval, if the secure hardware chooses to implement it. + * + * <p>Credentials provisioned to the direct access store should <strong>always</strong> use reader + * authentication to protect data elements. The reason for this is user authentication or user + * approval of data release is not possible when the device is off. + */ +public abstract class IdentityCredentialStore { + IdentityCredentialStore() {} + + /** + * Specifies that the cipher suite that will be used to secure communications between the reader + * is: + * + * <ul> + * <li>ECDHE with HKDF-SHA-256 for key agreement.</li> + * <li>AES-256 with GCM block mode for authenticated encryption (nonces are incremented by one + * for every message).</li> + * <li>ECDSA with SHA-256 for signing (used for signing session transcripts to defeat + * man-in-the-middle attacks), signing keys are not ephemeral. See {@link IdentityCredential} + * for details on reader and prover signing keys.</li> + * </ul> + * + * <p> + * At present this is the only supported cipher suite. + */ + public static final int CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256 = 1; + + /** + * Gets the default {@link IdentityCredentialStore}. + * + * @param context the application context. + * @return the {@link IdentityCredentialStore} or {@code null} if the device doesn't + * have hardware-backed support for secure storage of user identity documents. + */ + public static @Nullable IdentityCredentialStore getInstance(@NonNull Context context) { + return CredstoreIdentityCredentialStore.getInstance(context); + } + + /** + * Gets the {@link IdentityCredentialStore} for direct access. + * + * <p>Direct access requires specialized NFC hardware and may not be supported on all + * devices even if default store is available. Credentials provisioned to the direct + * access store should <strong>always</strong> use reader authentication to protect + * data elements. + * + * @param context the application context. + * @return the {@link IdentityCredentialStore} or {@code null} if direct access is not + * supported on this device. + */ + public static @Nullable IdentityCredentialStore getDirectAccessInstance(@NonNull + Context context) { + return CredstoreIdentityCredentialStore.getDirectAccessInstance(context); + } + + /** + * Gets a list of supported document types. + * + * <p>Only the direct-access store may restrict the kind of document types that can be used for + * credentials. The default store always supports any document type. + * + * @return The supported document types or the empty array if any document type is supported. + */ + public abstract @NonNull String[] getSupportedDocTypes(); + + /** + * Creates a new credential. + * + * @param credentialName The name used to identify the credential. + * @param docType The document type for the credential. + * @return A @{link WritableIdentityCredential} that can be used to create a new credential. + * @throws AlreadyPersonalizedException if a credential with the given name already exists. + * @throws DocTypeNotSupportedException if the given document type isn't supported by the store. + */ + public abstract @NonNull WritableIdentityCredential createCredential( + @NonNull String credentialName, @NonNull String docType) + throws AlreadyPersonalizedException, DocTypeNotSupportedException; + + /** + * Retrieve a named credential. + * + * @param credentialName the name of the credential to retrieve. + * @param cipherSuite the cipher suite to use for communicating with the verifier. + * @return The named credential, or null if not found. + */ + public abstract @Nullable IdentityCredential getCredentialByName(@NonNull String credentialName, + @Ciphersuite int cipherSuite) + throws CipherSuiteNotSupportedException; + + /** + * Delete a named credential. + * + * <p>This method returns a COSE_Sign1 data structure signed by the CredentialKey + * with payload set to {@code ProofOfDeletion} as defined below: + * + * <pre> + * ProofOfDeletion = [ + * "ProofOfDeletion", ; tstr + * tstr, ; DocType + * bool ; true if this is a test credential, should + * ; always be false. + * ] + * </pre> + * + * @param credentialName the name of the credential to delete. + * @return {@code null} if the credential was not found, the COSE_Sign1 data structure above + * if the credential was found and deleted. + */ + public abstract @Nullable byte[] deleteCredentialByName(@NonNull String credentialName); + + /** @hide */ + @IntDef(value = {CIPHERSUITE_ECDHE_HKDF_ECDSA_WITH_AES_256_GCM_SHA256}) + @Retention(RetentionPolicy.SOURCE) + public @interface Ciphersuite { + } + +} diff --git a/identity/java/android/security/identity/InvalidReaderSignatureException.java b/identity/java/android/security/identity/InvalidReaderSignatureException.java new file mode 100644 index 000000000000..3f7027005830 --- /dev/null +++ b/identity/java/android/security/identity/InvalidReaderSignatureException.java @@ -0,0 +1,46 @@ +/* + * 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.security.identity; + +import android.annotation.NonNull; + +/** + * Thrown if the reader signature is invalid, or it doesn't contain a certificate chain, or if the + * signature failed to validate. + */ +public class InvalidReaderSignatureException extends IdentityCredentialException { + /** + * Constructs a new {@link InvalidReaderSignatureException} exception. + * + * @param message the detail message. + */ + public InvalidReaderSignatureException(@NonNull String message) { + super(message); + } + + + /** + * Constructs a new {@link InvalidReaderSignatureException} exception. + * + * @param message the detail message. + * @param cause the cause. + */ + public InvalidReaderSignatureException(@NonNull String message, + @NonNull Throwable cause) { + super(message, cause); + } +} diff --git a/identity/java/android/security/identity/InvalidRequestMessageException.java b/identity/java/android/security/identity/InvalidRequestMessageException.java new file mode 100644 index 000000000000..b0c073c33a8d --- /dev/null +++ b/identity/java/android/security/identity/InvalidRequestMessageException.java @@ -0,0 +1,46 @@ +/* + * 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.security.identity; + +import android.annotation.NonNull; + +/** + * Thrown if message with the request doesn't satisfy the requirements documented in + * {@link IdentityCredential#getEntries(byte[], Map, byte[], byte[])}. + */ +public class InvalidRequestMessageException extends IdentityCredentialException { + /** + * Constructs a new {@link InvalidRequestMessageException} exception. + * + * @param message the detail message. + */ + public InvalidRequestMessageException(@NonNull String message) { + super(message); + } + + + /** + * Constructs a new {@link InvalidRequestMessageException} exception. + * + * @param message the detail message. + * @param cause the cause. + */ + public InvalidRequestMessageException(@NonNull String message, + @NonNull Throwable cause) { + super(message, cause); + } +} diff --git a/identity/java/android/security/identity/MessageDecryptionException.java b/identity/java/android/security/identity/MessageDecryptionException.java new file mode 100644 index 000000000000..7a6169ea1d5b --- /dev/null +++ b/identity/java/android/security/identity/MessageDecryptionException.java @@ -0,0 +1,44 @@ +/* + * 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.security.identity; + +import android.annotation.NonNull; + +/** + * Thrown when failing to decrypt a message from the reader device. + */ +public class MessageDecryptionException extends IdentityCredentialException { + + /** + * Constructs a new {@link MessageDecryptionException} exception. + * + * @param message the detail message. + */ + public MessageDecryptionException(@NonNull String message) { + super(message); + } + + /** + * Constructs a new {@link MessageDecryptionException} exception. + * + * @param message the detail message. + * @param cause the cause. + */ + public MessageDecryptionException(@NonNull String message, @NonNull Throwable cause) { + super(message, cause); + } +} diff --git a/identity/java/android/security/identity/NoAuthenticationKeyAvailableException.java b/identity/java/android/security/identity/NoAuthenticationKeyAvailableException.java new file mode 100644 index 000000000000..7f404037fbb1 --- /dev/null +++ b/identity/java/android/security/identity/NoAuthenticationKeyAvailableException.java @@ -0,0 +1,46 @@ +/* + * 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.security.identity; + +import android.annotation.NonNull; + +/** + * Thrown if no dynamic authentication keys are available. + */ +public class NoAuthenticationKeyAvailableException extends IdentityCredentialException { + + /** + * Constructs a new {@link NoAuthenticationKeyAvailableException} exception. + * + * @param message the detail message. + */ + public NoAuthenticationKeyAvailableException(@NonNull String message) { + super(message); + } + + /** + * Constructs a new {@link NoAuthenticationKeyAvailableException} exception. + * + * @param message the detail message. + * @param cause the cause. + */ + public NoAuthenticationKeyAvailableException(@NonNull String message, + @NonNull Throwable cause) { + super(message, cause); + } + +} diff --git a/identity/java/android/security/identity/PersonalizationData.java b/identity/java/android/security/identity/PersonalizationData.java new file mode 100644 index 000000000000..44370a1780f8 --- /dev/null +++ b/identity/java/android/security/identity/PersonalizationData.java @@ -0,0 +1,157 @@ +/* + * 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.security.identity; + +import android.annotation.NonNull; + +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.LinkedList; + +/** + * An object that holds personalization data. + * + * This data includes access control profiles and a set of data entries and values, grouped by + * namespace. + * + * This is used to provision data into a {@link WritableIdentityCredential}. + * + * @see WritableIdentityCredential#personalize + */ +public class PersonalizationData { + + private PersonalizationData() { + } + + private LinkedList<AccessControlProfile> mProfiles = new LinkedList<>(); + + private LinkedHashMap<String, NamespaceData> mNamespaces = new LinkedHashMap<>(); + + Collection<AccessControlProfile> getAccessControlProfiles() { + return Collections.unmodifiableCollection(mProfiles); + } + + Collection<String> getNamespaceNames() { + return Collections.unmodifiableCollection(mNamespaces.keySet()); + } + + NamespaceData getNamespaceData(String namespace) { + return mNamespaces.get(namespace); + } + + static class NamespaceData { + + private String mNamespace; + private LinkedHashMap<String, EntryData> mEntries = new LinkedHashMap<>(); + + private NamespaceData(String namespace) { + this.mNamespace = namespace; + } + + String getNamespaceName() { + return mNamespace; + } + + Collection<String> getEntryNames() { + return Collections.unmodifiableCollection(mEntries.keySet()); + } + + Collection<AccessControlProfileId> getAccessControlProfileIds(String name) { + EntryData value = mEntries.get(name); + if (value != null) { + return value.mAccessControlProfileIds; + } + return null; + } + + byte[] getEntryValue(String name) { + EntryData value = mEntries.get(name); + if (value != null) { + return value.mValue; + } + return null; + } + } + + private static class EntryData { + byte[] mValue; + Collection<AccessControlProfileId> mAccessControlProfileIds; + + EntryData(byte[] value, Collection<AccessControlProfileId> accessControlProfileIds) { + this.mValue = value; + this.mAccessControlProfileIds = accessControlProfileIds; + } + } + + /** + * A builder for {@link PersonalizationData}. + */ + public static final class Builder { + private PersonalizationData mData; + + /** + * Creates a new builder for a given namespace. + */ + public Builder() { + this.mData = new PersonalizationData(); + } + + /** + * Adds a new entry to the builder. + * + * @param namespace The namespace to use, e.g. {@code org.iso.18013-5.2019}. + * @param name The name of the entry, e.g. {@code height}. + * @param accessControlProfileIds A set of access control profiles to use. + * @param value The value to add, in CBOR encoding. + * @return The builder. + */ + public @NonNull Builder setEntry(@NonNull String namespace, @NonNull String name, + @NonNull Collection<AccessControlProfileId> accessControlProfileIds, + @NonNull byte[] value) { + NamespaceData namespaceData = mData.mNamespaces.get(namespace); + if (namespaceData == null) { + namespaceData = new NamespaceData(namespace); + mData.mNamespaces.put(namespace, namespaceData); + } + // TODO: validate/verify that value is proper CBOR. + namespaceData.mEntries.put(name, new EntryData(value, accessControlProfileIds)); + return this; + } + + /** + * Adds a new access control profile to the builder. + * + * @param profile The access control profile. + * @return The builder. + */ + public @NonNull Builder addAccessControlProfile(@NonNull AccessControlProfile profile) { + mData.mProfiles.add(profile); + return this; + } + + /** + * Creates a new {@link PersonalizationData} with all the entries added to the builder. + * + * @return A new {@link PersonalizationData} instance. + */ + public @NonNull PersonalizationData build() { + return mData; + } + } + +} diff --git a/identity/java/android/security/identity/ResultData.java b/identity/java/android/security/identity/ResultData.java new file mode 100644 index 000000000000..0982c8a4ab31 --- /dev/null +++ b/identity/java/android/security/identity/ResultData.java @@ -0,0 +1,224 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.identity; + +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; + +import java.lang.annotation.Retention; +import java.util.Collection; + +/** + * An object that contains the result of retrieving data from a credential. This is used to return + * data requested from a {@link IdentityCredential}. + */ +public abstract class ResultData { + + /** Value was successfully retrieved. */ + public static final int STATUS_OK = 0; + + /** Requested entry does not exist. */ + public static final int STATUS_NO_SUCH_ENTRY = 1; + + /** Requested entry was not requested. */ + public static final int STATUS_NOT_REQUESTED = 2; + + /** Requested entry wasn't in the request message. */ + public static final int STATUS_NOT_IN_REQUEST_MESSAGE = 3; + + /** The requested entry was not retrieved because user authentication wasn't performed. */ + public static final int STATUS_USER_AUTHENTICATION_FAILED = 4; + + /** The requested entry was not retrieved because reader authentication wasn't performed. */ + public static final int STATUS_READER_AUTHENTICATION_FAILED = 5; + + /** + * The requested entry was not retrieved because it was configured without any access + * control profile. + */ + public static final int STATUS_NO_ACCESS_CONTROL_PROFILES = 6; + + /** + * @hide + */ + protected ResultData() {} + + /** + * Returns a CBOR structure containing the retrieved data. + * + * <p>This structure - along with the session transcript - may be cryptographically + * authenticated to prove to the reader that the data is from a trusted credential and + * {@link #getMessageAuthenticationCode()} can be used to get a MAC. + * + * <p>The CBOR structure which is cryptographically authenticated is the + * {@code DeviceAuthentication} structure according to the following + * <a href="https://tools.ietf.org/html/draft-ietf-cbor-cddl-06">CDDL</a> schema: + * + * <pre> + * DeviceAuthentication = [ + * "DeviceAuthentication", + * SessionTranscript, + * DocType, + * DeviceNameSpacesBytes + * ] + * + * DocType = tstr + * + * SessionTranscript = [ + * DeviceEngagementBytes, + * EReaderKeyBytes + * ] + * + * DeviceEngagementBytes = #6.24(bstr .cbor DeviceEngagement) + * EReaderKeyBytes = #6.24(bstr .cbor EReaderKey.Pub) + * + * DeviceNameSpacesBytes = #6.24(bstr .cbor DeviceNameSpaces) + * </pre> + * + * where + * + * <pre> + * DeviceNameSpaces = { + * * NameSpace => DeviceSignedItems + * } + * + * DeviceSignedItems = { + * + DataItemName => DataItemValue + * } + * + * NameSpace = tstr + * DataItemName = tstr + * DataItemValue = any + * </pre> + * + * <p>The returned data is the binary encoding of the {@code DeviceNameSpaces} structure + * as defined above. + * + * @return The bytes of the {@code DeviceNameSpaces} CBOR structure. + */ + public abstract @NonNull byte[] getAuthenticatedData(); + + /** + * Returns a message authentication code over the data returned by + * {@link #getAuthenticatedData}, to prove to the reader that the data is from a trusted + * credential. + * + * <p>The MAC proves to the reader that the data is from a trusted credential. This code is + * produced by using the key agreement and key derivation function from the ciphersuite + * with the authentication private key and the reader ephemeral public key to compute a + * shared message authentication code (MAC) key, then using the MAC function from the + * ciphersuite to compute a MAC of the authenticated data. + * + * <p>If the {@code sessionTranscript} parameter passed to + * {@link IdentityCredential#getEntries(byte[], Map, byte[], byte[])} was {@code null} + * or the reader ephmeral public key was never set using + * {@link IdentityCredential#setReaderEphemeralPublicKey(PublicKey)}, no message + * authencation code will be produced and this method will return {@code null}. + * + * @return A COSE_Mac0 structure with the message authentication code as described above + * or {@code null} if the conditions specified above are not met. + */ + public abstract @Nullable byte[] getMessageAuthenticationCode(); + + /** + * Returns the static authentication data associated with the dynamic authentication + * key used to sign or MAC the data returned by {@link #getAuthenticatedData()}. + * + * @return The static authentication data associated with dynamic authentication key used to + * MAC the data. + */ + public abstract @NonNull byte[] getStaticAuthenticationData(); + + /** + * Gets the names of namespaces with retrieved entries. + * + * @return collection of name of namespaces containing retrieved entries. May be empty if no + * data was retrieved. + */ + public abstract @NonNull Collection<String> getNamespaceNames(); + + /** + * Get the names of all entries. + * + * This includes the name of entries that wasn't successfully retrieved. + * + * @param namespaceName the namespace name to get entries for. + * @return A collection of names or {@code null} if there are no entries for the given + * namespace. + */ + public abstract @Nullable Collection<String> getEntryNames(@NonNull String namespaceName); + + /** + * Get the names of all entries that was successfully retrieved. + * + * This only return entries for which {@link #getStatus(String, String)} will return + * {@link #STATUS_OK}. + * + * @param namespaceName the namespace name to get entries for. + * @return A collection of names or {@code null} if there are no entries for the given + * namespace. + */ + public abstract @Nullable Collection<String> getRetrievedEntryNames( + @NonNull String namespaceName); + + /** + * Gets the status of an entry. + * + * This returns {@link #STATUS_OK} if the value was retrieved, {@link #STATUS_NO_SUCH_ENTRY} + * if the given entry wasn't retrieved, {@link #STATUS_NOT_REQUESTED} if it wasn't requested, + * {@link #STATUS_NOT_IN_REQUEST_MESSAGE} if the request message was set but the entry wasn't + * present in the request message, + * {@link #STATUS_USER_AUTHENTICATION_FAILED} if the value + * wasn't retrieved because the necessary user authentication wasn't performed, + * {@link #STATUS_READER_AUTHENTICATION_FAILED} if the supplied reader certificate chain + * didn't match the set of certificates the entry was provisioned with, or + * {@link #STATUS_NO_ACCESS_CONTROL_PROFILES} if the entry was configured without any + * access control profiles. + * + * @param namespaceName the namespace name of the entry. + * @param name the name of the entry to get the value for. + * @return the status indicating whether the value was retrieved and if not, why. + */ + @Status + public abstract int getStatus(@NonNull String namespaceName, @NonNull String name); + + /** + * Gets the raw CBOR data for the value of an entry. + * + * This should only be called on an entry for which the {@link #getStatus(String, String)} + * method returns {@link #STATUS_OK}. + * + * @param namespaceName the namespace name of the entry. + * @param name the name of the entry to get the value for. + * @return the raw CBOR data or {@code null} if no entry with the given name exists. + */ + public abstract @Nullable byte[] getEntry(@NonNull String namespaceName, @NonNull String name); + + /** + * The type of the entry status. + * @hide + */ + @Retention(SOURCE) + @IntDef({STATUS_OK, STATUS_NO_SUCH_ENTRY, STATUS_NOT_REQUESTED, STATUS_NOT_IN_REQUEST_MESSAGE, + STATUS_USER_AUTHENTICATION_FAILED, STATUS_READER_AUTHENTICATION_FAILED, + STATUS_NO_ACCESS_CONTROL_PROFILES}) + public @interface Status { + } +} diff --git a/identity/java/android/security/identity/SessionTranscriptMismatchException.java b/identity/java/android/security/identity/SessionTranscriptMismatchException.java new file mode 100644 index 000000000000..8c2406043f67 --- /dev/null +++ b/identity/java/android/security/identity/SessionTranscriptMismatchException.java @@ -0,0 +1,44 @@ +/* + * 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.security.identity; + +import android.annotation.NonNull; + +/** + * Thrown when trying use multiple different session transcripts in the same presentation session. + */ +public class SessionTranscriptMismatchException extends IdentityCredentialException { + + /** + * Constructs a new {@link SessionTranscriptMismatchException} exception. + * + * @param message the detail message. + */ + public SessionTranscriptMismatchException(@NonNull String message) { + super(message); + } + + /** + * Constructs a new {@link SessionTranscriptMismatchException} exception. + * + * @param message the detail message. + * @param cause the cause. + */ + public SessionTranscriptMismatchException(@NonNull String message, @NonNull Throwable cause) { + super(message, cause); + } +} diff --git a/identity/java/android/security/identity/UnknownAuthenticationKeyException.java b/identity/java/android/security/identity/UnknownAuthenticationKeyException.java new file mode 100644 index 000000000000..f454b2ce2af9 --- /dev/null +++ b/identity/java/android/security/identity/UnknownAuthenticationKeyException.java @@ -0,0 +1,43 @@ +/* + * 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.security.identity; + +import android.annotation.NonNull; + +/** + * Thrown if trying to certify an unknown dynamic authentication key. + */ +public class UnknownAuthenticationKeyException extends IdentityCredentialException { + /** + * Constructs a new {@link UnknownAuthenticationKeyException} exception. + * + * @param message the detail message. + */ + public UnknownAuthenticationKeyException(@NonNull String message) { + super(message); + } + + /** + * Constructs a new {@link UnknownAuthenticationKeyException} exception. + * + * @param message the detail message. + * @param cause the cause. + */ + public UnknownAuthenticationKeyException(@NonNull String message, @NonNull Throwable cause) { + super(message, cause); + } +} diff --git a/identity/java/android/security/identity/Util.java b/identity/java/android/security/identity/Util.java new file mode 100644 index 000000000000..6eefeb8f3f2a --- /dev/null +++ b/identity/java/android/security/identity/Util.java @@ -0,0 +1,140 @@ +/* + * 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.security.identity; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECPoint; +import java.util.Collection; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +class Util { + private static final String TAG = "Util"; + + static int[] integerCollectionToArray(Collection<Integer> collection) { + int[] result = new int[collection.size()]; + int n = 0; + for (int item : collection) { + result[n++] = item; + } + return result; + } + + static byte[] stripLeadingZeroes(byte[] value) { + int n = 0; + while (n < value.length && value[n] == 0) { + n++; + } + int newLen = value.length - n; + byte[] ret = new byte[newLen]; + int m = 0; + while (n < value.length) { + ret[m++] = value[n++]; + } + return ret; + } + + static byte[] publicKeyEncodeUncompressedForm(PublicKey publicKey) { + ECPoint w = ((ECPublicKey) publicKey).getW(); + // X and Y are always positive so for interop we remove any leading zeroes + // inserted by the BigInteger encoder. + byte[] x = stripLeadingZeroes(w.getAffineX().toByteArray()); + byte[] y = stripLeadingZeroes(w.getAffineY().toByteArray()); + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + baos.write(0x04); + baos.write(x); + baos.write(y); + return baos.toByteArray(); + } catch (IOException e) { + throw new RuntimeException("Unexpected IOException", e); + } + } + + /** + * Computes an HKDF. + * + * This is based on https://github.com/google/tink/blob/master/java/src/main/java/com/google + * /crypto/tink/subtle/Hkdf.java + * which is also Copyright (c) Google and also licensed under the Apache 2 license. + * + * @param macAlgorithm the MAC algorithm used for computing the Hkdf. I.e., "HMACSHA1" or + * "HMACSHA256". + * @param ikm the input keying material. + * @param salt optional salt. A possibly non-secret random value. If no salt is + * provided (i.e. if + * salt has length 0) then an array of 0s of the same size as the hash + * digest is used as salt. + * @param info optional context and application specific information. + * @param size The length of the generated pseudorandom string in bytes. The maximal + * size is + * 255.DigestSize, where DigestSize is the size of the underlying HMAC. + * @return size pseudorandom bytes. + */ + static byte[] computeHkdf( + String macAlgorithm, final byte[] ikm, final byte[] salt, final byte[] info, int size) { + Mac mac = null; + try { + mac = Mac.getInstance(macAlgorithm); + } catch (NoSuchAlgorithmException e) { + throw new RuntimeException("No such algorithm: " + macAlgorithm, e); + } + if (size > 255 * mac.getMacLength()) { + throw new RuntimeException("size too large"); + } + try { + if (salt == null || salt.length == 0) { + // According to RFC 5869, Section 2.2 the salt is optional. If no salt is provided + // then HKDF uses a salt that is an array of zeros of the same length as the hash + // digest. + mac.init(new SecretKeySpec(new byte[mac.getMacLength()], macAlgorithm)); + } else { + mac.init(new SecretKeySpec(salt, macAlgorithm)); + } + byte[] prk = mac.doFinal(ikm); + byte[] result = new byte[size]; + int ctr = 1; + int pos = 0; + mac.init(new SecretKeySpec(prk, macAlgorithm)); + byte[] digest = new byte[0]; + while (true) { + mac.update(digest); + mac.update(info); + mac.update((byte) ctr); + digest = mac.doFinal(); + if (pos + digest.length < size) { + System.arraycopy(digest, 0, result, pos, digest.length); + pos += digest.length; + ctr++; + } else { + System.arraycopy(digest, 0, result, pos, size - pos); + break; + } + } + return result; + } catch (InvalidKeyException e) { + throw new RuntimeException("Error MACing", e); + } + } + +} diff --git a/identity/java/android/security/identity/WritableIdentityCredential.java b/identity/java/android/security/identity/WritableIdentityCredential.java new file mode 100644 index 000000000000..5f575b9d56f3 --- /dev/null +++ b/identity/java/android/security/identity/WritableIdentityCredential.java @@ -0,0 +1,111 @@ +/* + * 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.security.identity; + +import android.annotation.NonNull; + +import java.security.cert.X509Certificate; +import java.util.Collection; + +/** + * Class used to personalize a new identity credential. + * + * <p>Credentials cannot be updated or modified after creation; any changes require deletion and + * re-creation. + * + * Use {@link IdentityCredentialStore#createCredential(String, String)} to create a new credential. + */ +public abstract class WritableIdentityCredential { + /** + * Generates and returns an X.509 certificate chain for the CredentialKey which identifies this + * credential to the issuing authority. The certificate contains an + * <a href="https://source.android.com/security/keystore/attestation">Android Keystore</a> + * attestation extension which describes the key and the security hardware in which it lives. + * + * <p>Additionally, the attestation extension will contain the tag TODO_IC_KEY which indicates + * it is an Identity Credential key (which can only sign/MAC very specific messages) and not + * an Android Keystore key (which can be used to sign/MAC anything). + * + * <p>The issuer <b>MUST</b> carefully examine this certificate chain including (but not + * limited to) checking that the root certificate is well-known, the tag TODO_IC_KEY is + * present, the passed in challenge is present, the device has verified boot enabled, that each + * certificate in the chain is signed by its successor, that none of the certificates have been + * revoked and so on. + * + * <p>It is not strictly necessary to use this method to provision a credential if the issuing + * authority doesn't care about the nature of the security hardware. If called, however, this + * method must be called before {@link #personalize(PersonalizationData)}. + * + * @param challenge is a byte array whose contents should be unique, fresh and provided by + * the issuing authority. The value provided is embedded in the attestation + * extension and enables the issuing authority to verify that the attestation + * certificate is fresh. + * @return the X.509 certificate for this credential's CredentialKey. + */ + public abstract @NonNull Collection<X509Certificate> getCredentialKeyCertificateChain( + @NonNull byte[] challenge); + + /** + * Stores all of the data in the credential, with the specified access control profiles. + * + * <p>This method returns a COSE_Sign1 data structure signed by the CredentialKey with payload + * set to {@code ProofOfProvisioning} as defined below. + * + * <pre> + * ProofOfProvisioning = [ + * "ProofOfProvisioning", ; tstr + * tstr, ; DocType + * [ * AccessControlProfile ], + * ProvisionedData, + * bool ; true if this is a test credential, should + * ; always be false. + * ] + * + * AccessControlProfile = { + * "id": uint, + * ? "readerCertificate" : bstr, + * ? ( + * "userAuthenticationRequired" : bool, + * "timeoutMillis" : uint, + * ) + * } + * + * ProvisionedData = { + * * Namespace => [ + Entry ] + * }, + * + * Namespace = tstr + * + * Entry = { + * "name" : tstr, + * "value" : any, + * "accessControlProfiles" : [ * uint ], + * } + * </pre> + * + * <p>This data structure provides a guarantee to the issuer about the data which may be + * returned in the CBOR returned by + * {@link ResultData#getAuthenticatedData()} during a credential + * presentation. + * + * @param personalizationData The data to provision, including access control profiles + * and data elements and their values, grouped into namespaces. + * @return A COSE_Sign1 data structure, see above. + */ + public abstract @NonNull byte[] personalize( + @NonNull PersonalizationData personalizationData); +} diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 4c08a3829934..98de9c3ea88e 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -25,11 +25,6 @@ cc_defaults { // GCC false-positives on this warning, and since we -Werror that's // a problem "-Wno-free-nonheap-object", - - // Clang is producing non-determistic binary when the new pass manager is - // enabled. Disable the new PM as a temporary workaround. - // b/142372146 - "-fno-experimental-new-pass-manager", ], include_dirs: [ diff --git a/media/OWNERS b/media/OWNERS index 8bd037a14150..be605831a24b 100644 --- a/media/OWNERS +++ b/media/OWNERS @@ -5,6 +5,7 @@ elaurent@google.com etalvala@google.com gkasten@google.com hdmoon@google.com +hkuang@google.com hunga@google.com insun@google.com jaewan@google.com diff --git a/media/java/android/media/soundtrigger/SoundTriggerDetector.java b/media/java/android/media/soundtrigger/SoundTriggerDetector.java index 56e5566df29c..77596a5de815 100644 --- a/media/java/android/media/soundtrigger/SoundTriggerDetector.java +++ b/media/java/android/media/soundtrigger/SoundTriggerDetector.java @@ -22,7 +22,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.hardware.soundtrigger.IRecognitionStatusCallback; import android.hardware.soundtrigger.SoundTrigger; import android.hardware.soundtrigger.SoundTrigger.RecognitionConfig; diff --git a/media/java/android/media/soundtrigger/SoundTriggerManager.java b/media/java/android/media/soundtrigger/SoundTriggerManager.java index ada77c53bb34..3f0aec63283c 100644 --- a/media/java/android/media/soundtrigger/SoundTriggerManager.java +++ b/media/java/android/media/soundtrigger/SoundTriggerManager.java @@ -23,7 +23,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.hardware.soundtrigger.SoundTrigger; diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java index 1b9cac0c8c99..377b2bc19c6b 100644 --- a/media/java/android/media/tv/TvInputInfo.java +++ b/media/java/android/media/tv/TvInputInfo.java @@ -20,7 +20,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.StringRes; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java index 5c11ed9bb7b4..7fbb3376d5fb 100755 --- a/media/java/android/media/tv/TvInputService.java +++ b/media/java/android/media/tv/TvInputService.java @@ -22,9 +22,9 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.app.ActivityManager; import android.app.Service; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.Intent; import android.graphics.PixelFormat; diff --git a/media/java/android/mtp/MtpPropertyList.java b/media/java/android/mtp/MtpPropertyList.java index 557f099c25c1..53d838d84518 100644 --- a/media/java/android/mtp/MtpPropertyList.java +++ b/media/java/android/mtp/MtpPropertyList.java @@ -16,7 +16,8 @@ package android.mtp; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import java.util.ArrayList; import java.util.List; diff --git a/media/java/android/mtp/MtpStorage.java b/media/java/android/mtp/MtpStorage.java index 65d0fef74b25..d385816c6f86 100644 --- a/media/java/android/mtp/MtpStorage.java +++ b/media/java/android/mtp/MtpStorage.java @@ -16,7 +16,7 @@ package android.mtp; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.storage.StorageVolume; import android.provider.MediaStore; diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java index 86a1076af122..06adf30a8303 100644 --- a/media/java/android/service/media/MediaBrowserService.java +++ b/media/java/android/service/media/MediaBrowserService.java @@ -21,8 +21,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; -import android.annotation.UnsupportedAppUsage; import android.app.Service; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; diff --git a/media/mca/effect/java/android/media/effect/SingleFilterEffect.java b/media/mca/effect/java/android/media/effect/SingleFilterEffect.java index dfbf5d20e074..121443f56285 100644 --- a/media/mca/effect/java/android/media/effect/SingleFilterEffect.java +++ b/media/mca/effect/java/android/media/effect/SingleFilterEffect.java @@ -17,12 +17,11 @@ package android.media.effect; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.filterfw.core.Filter; import android.filterfw.core.FilterFactory; import android.filterfw.core.FilterFunction; import android.filterfw.core.Frame; -import android.media.effect.EffectContext; /** * Effect subclass for effects based on a single Filter. Subclasses need only invoke the diff --git a/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java b/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java index 52615bf09faa..3a7f1ed4f7ec 100644 --- a/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java +++ b/media/mca/filterfw/java/android/filterfw/GraphEnvironment.java @@ -17,11 +17,11 @@ package android.filterfw; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.filterfw.core.AsyncRunner; -import android.filterfw.core.FilterGraph; import android.filterfw.core.FilterContext; +import android.filterfw.core.FilterGraph; import android.filterfw.core.FrameManager; import android.filterfw.core.GraphRunner; import android.filterfw.core.RoundRobinScheduler; diff --git a/media/mca/filterfw/java/android/filterfw/core/Filter.java b/media/mca/filterfw/java/android/filterfw/core/Filter.java index 4f56b923f6ed..a608ef5be3f4 100644 --- a/media/mca/filterfw/java/android/filterfw/core/Filter.java +++ b/media/mca/filterfw/java/android/filterfw/core/Filter.java @@ -17,19 +17,15 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.FilterContext; -import android.filterfw.core.FilterPort; -import android.filterfw.core.KeyValueMap; -import android.filterfw.io.TextGraphReader; -import android.filterfw.io.GraphIOException; +import android.compat.annotation.UnsupportedAppUsage; import android.filterfw.format.ObjectFormat; +import android.filterfw.io.GraphIOException; +import android.filterfw.io.TextGraphReader; import android.util.Log; import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.reflect.Field; -import java.lang.Thread; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; diff --git a/media/mca/filterfw/java/android/filterfw/core/FilterContext.java b/media/mca/filterfw/java/android/filterfw/core/FilterContext.java index a19220ef85f8..6b0a2193dceb 100644 --- a/media/mca/filterfw/java/android/filterfw/core/FilterContext.java +++ b/media/mca/filterfw/java/android/filterfw/core/FilterContext.java @@ -17,11 +17,7 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.Filter; -import android.filterfw.core.Frame; -import android.filterfw.core.FrameManager; -import android.filterfw.core.GLEnvironment; +import android.compat.annotation.UnsupportedAppUsage; import java.util.HashMap; import java.util.HashSet; diff --git a/media/mca/filterfw/java/android/filterfw/core/FilterGraph.java b/media/mca/filterfw/java/android/filterfw/core/FilterGraph.java index e6ca11ffca3c..35a298fd6dfb 100644 --- a/media/mca/filterfw/java/android/filterfw/core/FilterGraph.java +++ b/media/mca/filterfw/java/android/filterfw/core/FilterGraph.java @@ -17,6 +17,11 @@ package android.filterfw.core; +import android.compat.annotation.UnsupportedAppUsage; +import android.filterpacks.base.FrameBranch; +import android.filterpacks.base.NullFilter; +import android.util.Log; + import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -25,14 +30,6 @@ import java.util.Map.Entry; import java.util.Set; import java.util.Stack; -import android.filterfw.core.FilterContext; -import android.filterfw.core.KeyValueMap; -import android.filterpacks.base.FrameBranch; -import android.filterpacks.base.NullFilter; - -import android.annotation.UnsupportedAppUsage; -import android.util.Log; - /** * @hide */ diff --git a/media/mca/filterfw/java/android/filterfw/core/Frame.java b/media/mca/filterfw/java/android/filterfw/core/Frame.java index e880783247a3..c4d935ae4873 100644 --- a/media/mca/filterfw/java/android/filterfw/core/Frame.java +++ b/media/mca/filterfw/java/android/filterfw/core/Frame.java @@ -17,9 +17,7 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.FrameFormat; -import android.filterfw.core.FrameManager; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Bitmap; import java.nio.ByteBuffer; diff --git a/media/mca/filterfw/java/android/filterfw/core/FrameFormat.java b/media/mca/filterfw/java/android/filterfw/core/FrameFormat.java index eb0ff0a32c3f..a87e9b9ffbcf 100644 --- a/media/mca/filterfw/java/android/filterfw/core/FrameFormat.java +++ b/media/mca/filterfw/java/android/filterfw/core/FrameFormat.java @@ -17,9 +17,7 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.KeyValueMap; -import android.filterfw.core.MutableFrameFormat; +import android.compat.annotation.UnsupportedAppUsage; import java.util.Arrays; import java.util.Map.Entry; diff --git a/media/mca/filterfw/java/android/filterfw/core/FrameManager.java b/media/mca/filterfw/java/android/filterfw/core/FrameManager.java index 85c8fcd9787d..e49aaf1d6fad 100644 --- a/media/mca/filterfw/java/android/filterfw/core/FrameManager.java +++ b/media/mca/filterfw/java/android/filterfw/core/FrameManager.java @@ -17,10 +17,7 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.Frame; -import android.filterfw.core.FrameFormat; -import android.filterfw.core.MutableFrameFormat; +import android.compat.annotation.UnsupportedAppUsage; /** * @hide diff --git a/media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java b/media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java index e25d6a7d70ab..7e4e8a64a81f 100644 --- a/media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java +++ b/media/mca/filterfw/java/android/filterfw/core/GLEnvironment.java @@ -17,13 +17,12 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.NativeAllocatorTag; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.SurfaceTexture; +import android.media.MediaRecorder; import android.os.Looper; import android.util.Log; import android.view.Surface; -import android.media.MediaRecorder; /** * @hide diff --git a/media/mca/filterfw/java/android/filterfw/core/GLFrame.java b/media/mca/filterfw/java/android/filterfw/core/GLFrame.java index 9e3025fafb6e..1ccd7feaa7c3 100644 --- a/media/mca/filterfw/java/android/filterfw/core/GLFrame.java +++ b/media/mca/filterfw/java/android/filterfw/core/GLFrame.java @@ -17,15 +17,10 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.Frame; -import android.filterfw.core.FrameFormat; -import android.filterfw.core.FrameManager; -import android.filterfw.core.NativeFrame; -import android.filterfw.core.StopWatchMap; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.Bitmap; -import android.opengl.GLES20; import android.graphics.Rect; +import android.opengl.GLES20; import java.nio.ByteBuffer; diff --git a/media/mca/filterfw/java/android/filterfw/core/GraphRunner.java b/media/mca/filterfw/java/android/filterfw/core/GraphRunner.java index 250cfaaba9d4..b57e8bb7262e 100644 --- a/media/mca/filterfw/java/android/filterfw/core/GraphRunner.java +++ b/media/mca/filterfw/java/android/filterfw/core/GraphRunner.java @@ -17,7 +17,7 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * @hide diff --git a/media/mca/filterfw/java/android/filterfw/core/MutableFrameFormat.java b/media/mca/filterfw/java/android/filterfw/core/MutableFrameFormat.java index ae2ad99899f0..da00b1ffb180 100644 --- a/media/mca/filterfw/java/android/filterfw/core/MutableFrameFormat.java +++ b/media/mca/filterfw/java/android/filterfw/core/MutableFrameFormat.java @@ -17,9 +17,7 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.FrameFormat; -import android.filterfw.core.KeyValueMap; +import android.compat.annotation.UnsupportedAppUsage; import java.util.Arrays; diff --git a/media/mca/filterfw/java/android/filterfw/core/Program.java b/media/mca/filterfw/java/android/filterfw/core/Program.java index 376c08554eb2..145388e4437e 100644 --- a/media/mca/filterfw/java/android/filterfw/core/Program.java +++ b/media/mca/filterfw/java/android/filterfw/core/Program.java @@ -17,8 +17,7 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.Frame; +import android.compat.annotation.UnsupportedAppUsage; /** * @hide diff --git a/media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java b/media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java index f41636e7cf76..e043be0e27bd 100644 --- a/media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java +++ b/media/mca/filterfw/java/android/filterfw/core/ShaderProgram.java @@ -17,12 +17,7 @@ package android.filterfw.core; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.core.Frame; -import android.filterfw.core.NativeAllocatorTag; -import android.filterfw.core.Program; -import android.filterfw.core.StopWatchMap; -import android.filterfw.core.VertexFrame; +import android.compat.annotation.UnsupportedAppUsage; import android.filterfw.geometry.Quad; import android.opengl.GLES20; diff --git a/media/mca/filterfw/java/android/filterfw/format/ImageFormat.java b/media/mca/filterfw/java/android/filterfw/format/ImageFormat.java index ac087305287f..0e05092d0cdd 100644 --- a/media/mca/filterfw/java/android/filterfw/format/ImageFormat.java +++ b/media/mca/filterfw/java/android/filterfw/format/ImageFormat.java @@ -17,7 +17,7 @@ package android.filterfw.format; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.filterfw.core.FrameFormat; import android.filterfw.core.MutableFrameFormat; import android.graphics.Bitmap; diff --git a/media/mca/filterfw/java/android/filterfw/geometry/Point.java b/media/mca/filterfw/java/android/filterfw/geometry/Point.java index d7acf12dd1de..96d2d7b08b74 100644 --- a/media/mca/filterfw/java/android/filterfw/geometry/Point.java +++ b/media/mca/filterfw/java/android/filterfw/geometry/Point.java @@ -17,8 +17,7 @@ package android.filterfw.geometry; -import android.annotation.UnsupportedAppUsage; -import java.lang.Math; +import android.compat.annotation.UnsupportedAppUsage; /** * @hide diff --git a/media/mca/filterfw/java/android/filterfw/geometry/Quad.java b/media/mca/filterfw/java/android/filterfw/geometry/Quad.java index 610e5b80399d..2b308a91576f 100644 --- a/media/mca/filterfw/java/android/filterfw/geometry/Quad.java +++ b/media/mca/filterfw/java/android/filterfw/geometry/Quad.java @@ -17,10 +17,8 @@ package android.filterfw.geometry; -import android.annotation.UnsupportedAppUsage; -import android.filterfw.geometry.Point; +import android.compat.annotation.UnsupportedAppUsage; -import java.lang.Float; import java.util.Arrays; import java.util.Collections; import java.util.List; diff --git a/opengl/java/android/opengl/EGL14.java b/opengl/java/android/opengl/EGL14.java index 728e6e18cc31..90b46fd5901a 100644 --- a/opengl/java/android/opengl/EGL14.java +++ b/opengl/java/android/opengl/EGL14.java @@ -18,11 +18,11 @@ package android.opengl; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.SurfaceTexture; import android.view.Surface; -import android.view.SurfaceView; import android.view.SurfaceHolder; +import android.view.SurfaceView; /** * EGL 1.4 diff --git a/opengl/java/android/opengl/GLES20.java b/opengl/java/android/opengl/GLES20.java index d66e7ac84a3b..e853e4447daa 100644 --- a/opengl/java/android/opengl/GLES20.java +++ b/opengl/java/android/opengl/GLES20.java @@ -19,7 +19,7 @@ package android.opengl; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** OpenGL ES 2.0 */ diff --git a/opengl/java/android/opengl/GLSurfaceView.java b/opengl/java/android/opengl/GLSurfaceView.java index 8a3e6a0b0fd5..75131b0f6b9c 100644 --- a/opengl/java/android/opengl/GLSurfaceView.java +++ b/opengl/java/android/opengl/GLSurfaceView.java @@ -16,7 +16,7 @@ package android.opengl; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Trace; import android.util.AttributeSet; diff --git a/opengl/java/com/google/android/gles_jni/EGLImpl.java b/opengl/java/com/google/android/gles_jni/EGLImpl.java index f94f69f0fd3f..b4ea0a6132a5 100644 --- a/opengl/java/com/google/android/gles_jni/EGLImpl.java +++ b/opengl/java/com/google/android/gles_jni/EGLImpl.java @@ -16,13 +16,12 @@ package com.google.android.gles_jni; +import android.compat.annotation.UnsupportedAppUsage; import android.graphics.SurfaceTexture; import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; -import dalvik.annotation.compat.UnsupportedAppUsage; - import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLContext; diff --git a/opengl/java/com/google/android/gles_jni/GLImpl.java b/opengl/java/com/google/android/gles_jni/GLImpl.java index 2a8d07f03148..3c808a6ada48 100644 --- a/opengl/java/com/google/android/gles_jni/GLImpl.java +++ b/opengl/java/com/google/android/gles_jni/GLImpl.java @@ -20,14 +20,13 @@ package com.google.android.gles_jni; import android.app.AppGlobals; +import android.compat.annotation.UnsupportedAppUsage; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.os.Build; import android.os.UserHandle; import android.util.Log; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.nio.Buffer; import javax.microedition.khronos.opengles.GL10; diff --git a/opengl/java/javax/microedition/khronos/egl/EGL10.java b/opengl/java/javax/microedition/khronos/egl/EGL10.java index 8a2517062d4d..ea571c7311a1 100644 --- a/opengl/java/javax/microedition/khronos/egl/EGL10.java +++ b/opengl/java/javax/microedition/khronos/egl/EGL10.java @@ -16,8 +16,7 @@ package javax.microedition.khronos.egl; -import android.annotation.UnsupportedAppUsage; -import java.lang.String; +import android.compat.annotation.UnsupportedAppUsage; public interface EGL10 extends EGL { int EGL_SUCCESS = 0x3000; diff --git a/packages/CarSystemUI/Android.bp b/packages/CarSystemUI/Android.bp index 672879ae6e9d..68da999ae786 100644 --- a/packages/CarSystemUI/Android.bp +++ b/packages/CarSystemUI/Android.bp @@ -82,7 +82,7 @@ android_app { ], platform_apis: true, - product_specific: true, + system_ext_specific: true, certificate: "platform", privileged: true, diff --git a/packages/CarSystemUI/CleanSpec.mk b/packages/CarSystemUI/CleanSpec.mk new file mode 100644 index 000000000000..ceac67c55f09 --- /dev/null +++ b/packages/CarSystemUI/CleanSpec.mk @@ -0,0 +1,50 @@ +# 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. +# + +# If you don't need to do a full clean build but would like to touch +# a file or delete some intermediate files, add a clean step to the end +# of the list. These steps will only be run once, if they haven't been +# run before. +# +# E.g.: +# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) +# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) +# +# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with +# files that are missing or have been moved. +# +# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. +# Use $(OUT_DIR) to refer to the "out" directory. +# +# If you need to re-do something that's already mentioned, just copy +# the command and add it to the bottom of the list. E.g., if a change +# that you made last week required touching a file and a change you +# made today requires touching the same file, just copy the old +# touch step and add it to the end of the list. +# +# ***************************************************************** +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER +# ***************************************************************** + +# For example: +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/priv-app/CarSystemUI) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/priv-app/CarSystemUI) +# ****************************************************************** +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER +# ****************************************************************** diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java index c2ce84023869..9ccb837cf613 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/DynamicSystemInstallationService.java @@ -56,6 +56,7 @@ import android.os.PowerManager; import android.os.RemoteException; import android.os.image.DynamicSystemClient; import android.os.image.DynamicSystemManager; +import android.text.TextUtils; import android.util.Log; import android.widget.Toast; @@ -74,6 +75,8 @@ public class DynamicSystemInstallationService extends Service // TODO (b/131866826): This is currently for test only. Will move this to System API. static final String KEY_ENABLE_WHEN_COMPLETED = "KEY_ENABLE_WHEN_COMPLETED"; + static final String KEY_DSU_SLOT = "KEY_DSU_SLOT"; + static final String DEFAULT_DSU_SLOT = "dsu"; /* * Intent actions @@ -244,10 +247,15 @@ public class DynamicSystemInstallationService extends Service long systemSize = intent.getLongExtra(DynamicSystemClient.KEY_SYSTEM_SIZE, 0); long userdataSize = intent.getLongExtra(DynamicSystemClient.KEY_USERDATA_SIZE, 0); mEnableWhenCompleted = intent.getBooleanExtra(KEY_ENABLE_WHEN_COMPLETED, false); + String dsuSlot = intent.getStringExtra(KEY_DSU_SLOT); + if (TextUtils.isEmpty(dsuSlot)) { + dsuSlot = DEFAULT_DSU_SLOT; + } // TODO: better constructor or builder - mInstallTask = new InstallationAsyncTask( - url, systemSize, userdataSize, this, mDynSystem, this); + mInstallTask = + new InstallationAsyncTask( + url, dsuSlot, systemSize, userdataSize, this, mDynSystem, this); mInstallTask.execute(); @@ -409,7 +417,9 @@ public class DynamicSystemInstallationService extends Service break; case STATUS_READY: - builder.setContentText(getString(R.string.notification_install_completed)); + String msgCompleted = getString(R.string.notification_install_completed); + builder.setContentText(msgCompleted) + .setStyle(new Notification.BigTextStyle().bigText(msgCompleted)); builder.addAction(new Notification.Action.Builder( null, getString(R.string.notification_action_discard), @@ -422,7 +432,9 @@ public class DynamicSystemInstallationService extends Service break; case STATUS_IN_USE: - builder.setContentText(getString(R.string.notification_dynsystem_in_use)); + String msgInUse = getString(R.string.notification_dynsystem_in_use); + builder.setContentText(msgInUse) + .setStyle(new Notification.BigTextStyle().bigText(msgInUse)); builder.addAction(new Notification.Action.Builder( null, getString(R.string.notification_action_uninstall), @@ -452,7 +464,49 @@ public class DynamicSystemInstallationService extends Service } private void postStatus(int status, int cause, Throwable detail) { - Log.d(TAG, "postStatus(): statusCode=" + status + ", causeCode=" + cause); + String statusString; + String causeString; + + switch (status) { + case STATUS_NOT_STARTED: + statusString = "NOT_STARTED"; + break; + case STATUS_IN_PROGRESS: + statusString = "IN_PROGRESS"; + break; + case STATUS_READY: + statusString = "READY"; + break; + case STATUS_IN_USE: + statusString = "IN_USE"; + break; + default: + statusString = "UNKNOWN"; + break; + } + + switch (cause) { + case CAUSE_INSTALL_COMPLETED: + causeString = "INSTALL_COMPLETED"; + break; + case CAUSE_INSTALL_CANCELLED: + causeString = "INSTALL_CANCELLED"; + break; + case CAUSE_ERROR_IO: + causeString = "ERROR_IO"; + break; + case CAUSE_ERROR_INVALID_URL: + causeString = "ERROR_INVALID_URL"; + break; + case CAUSE_ERROR_EXCEPTION: + causeString = "ERROR_EXCEPTION"; + break; + default: + causeString = "CAUSE_NOT_SPECIFIED"; + break; + } + + Log.d(TAG, "status=" + statusString + ", cause=" + causeString); boolean notifyOnNotificationBar = true; diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java index b206a1fccba4..9aea0e713179 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/InstallationAsyncTask.java @@ -89,10 +89,12 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog interface ProgressListener { void onProgressUpdate(Progress progress); + void onResult(int resultCode, Throwable detail); } private final String mUrl; + private final String mDsuSlot; private final long mSystemSize; private final long mUserdataSize; private final Context mContext; @@ -106,9 +108,16 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog private InputStream mStream; private ZipFile mZipFile; - InstallationAsyncTask(String url, long systemSize, long userdataSize, Context context, - DynamicSystemManager dynSystem, ProgressListener listener) { + InstallationAsyncTask( + String url, + String dsuSlot, + long systemSize, + long userdataSize, + Context context, + DynamicSystemManager dynSystem, + ProgressListener listener) { mUrl = url; + mDsuSlot = dsuSlot; mSystemSize = systemSize; mUserdataSize = userdataSize; mContext = context; @@ -126,14 +135,17 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog verifyAndPrepare(); - mDynSystem.startInstallation(); + mDynSystem.startInstallation(mDsuSlot); installUserdata(); if (isCancelled()) { mDynSystem.remove(); return null; } - + if (mUrl == null) { + mDynSystem.finishInstallation(); + return null; + } installImages(); if (isCancelled()) { mDynSystem.remove(); @@ -194,6 +206,9 @@ class InstallationAsyncTask extends AsyncTask<String, InstallationAsyncTask.Prog } private void verifyAndPrepare() throws Exception { + if (mUrl == null) { + return; + } String extension = mUrl.substring(mUrl.lastIndexOf('.') + 1); if ("gz".equals(extension) || "gzip".equals(extension)) { diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java index 3b3933b7db10..e42ded74acd0 100644 --- a/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java +++ b/packages/DynamicSystemInstallationService/src/com/android/dynsystem/VerificationActivity.java @@ -28,11 +28,9 @@ import android.os.image.DynamicSystemClient; import android.util.FeatureFlagUtils; import android.util.Log; - /** - * This Activity starts KeyguardManager and ask the user to confirm - * before any installation request. If the device is not protected by - * a password, it approves the request by default. + * This Activity starts KeyguardManager and ask the user to confirm before any installation request. + * If the device is not protected by a password, it approves the request by default. */ public class VerificationActivity extends Activity { @@ -88,11 +86,15 @@ public class VerificationActivity extends Activity { Uri url = callingIntent.getData(); Bundle extras = callingIntent.getExtras(); - sVerifiedUrl = url.toString(); + if (url != null) { + sVerifiedUrl = url.toString(); + } // start service Intent intent = new Intent(this, DynamicSystemInstallationService.class); - intent.setData(url); + if (url != null) { + intent.setData(url); + } intent.setAction(DynamicSystemClient.ACTION_START_INSTALL); intent.putExtras(extras); @@ -106,6 +108,7 @@ public class VerificationActivity extends Activity { } static boolean isVerified(String url) { + if (url == null) return true; return sVerifiedUrl != null && sVerifiedUrl.equals(url); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index abfee1d415d6..9765074a4927 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -184,13 +184,28 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> } } + /** + * Connect this device. + * + * @param connectAllProfiles {@code true} to connect all profile, {@code false} otherwise. + * + * @deprecated use {@link #connect()} instead. + */ + @Deprecated public void connect(boolean connectAllProfiles) { + connect(); + } + + /** + * Connect this device. + */ + public void connect() { if (!ensurePaired()) { return; } mConnectAttempted = SystemClock.elapsedRealtime(); - connectWithoutResettingTimer(connectAllProfiles); + connectAllEnabledProfiles(); } public long getHiSyncId() { @@ -211,10 +226,10 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> void onBondingDockConnect() { // Attempt to connect if UUIDs are available. Otherwise, // we will connect when the ACTION_UUID intent arrives. - connect(false); + connect(); } - private void connectWithoutResettingTimer(boolean connectAllProfiles) { + private void connectAllEnabledProfiles() { synchronized (mProfileLock) { // Try to initialize the profiles if they were not. if (mProfiles.isEmpty()) { @@ -229,36 +244,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> return; } - int preferredProfiles = 0; - for (LocalBluetoothProfile profile : mProfiles) { - if (connectAllProfiles ? profile.accessProfileEnabled() - : profile.isAutoConnectable()) { - if (profile.isPreferred(mDevice)) { - ++preferredProfiles; - connectInt(profile); - } - } - } - if (BluetoothUtils.D) Log.d(TAG, "Preferred profiles = " + preferredProfiles); - - if (preferredProfiles == 0) { - connectAutoConnectableProfiles(); - } - } - } - - private void connectAutoConnectableProfiles() { - if (!ensurePaired()) { - return; - } - - synchronized (mProfileLock) { - for (LocalBluetoothProfile profile : mProfiles) { - if (profile.isAutoConnectable()) { - profile.setPreferred(mDevice, true); - connectInt(profile); - } - } + mLocalAdapter.connectAllEnabledProfiles(mDevice); } } @@ -625,7 +611,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> */ if (!mProfiles.isEmpty() && ((mConnectAttempted + timeout) > SystemClock.elapsedRealtime())) { - connectWithoutResettingTimer(false); + connectAllEnabledProfiles(); } dispatchAttributesChanged(); @@ -644,7 +630,7 @@ public class CachedBluetoothDevice implements Comparable<CachedBluetoothDevice> refresh(); if (bondState == BluetoothDevice.BOND_BONDED && mDevice.isBondingInitiatedLocally()) { - connect(false); + connect(); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java index 4e16c66d736b..56b14c6b652d 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java @@ -116,7 +116,7 @@ public class LocalMediaManager implements BluetoothCallback { final CachedBluetoothDevice cachedDevice = ((BluetoothMediaDevice) device).getCachedDevice(); if (!cachedDevice.isConnected() && !cachedDevice.isBusy()) { - cachedDevice.connect(true); + cachedDevice.connect(); return; } } diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java index b11585a73946..8bd5f57f9b71 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java @@ -90,7 +90,7 @@ public class WifiStatusTracker extends ConnectivityManager.NetworkCallback { public void setListening(boolean listening) { if (listening) { mNetworkScoreManager.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, - mWifiNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK); + mWifiNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_CURRENT_NETWORK); mWifiNetworkScoreCache.registerListener(mCacheListener); mConnectivityManager.registerNetworkCallback( mNetworkRequest, mNetworkCallback, mHandler); diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java index 3e359d216234..f7131392c68c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java @@ -359,7 +359,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro mNetworkScoreManager.registerNetworkScoreCache( NetworkKey.TYPE_WIFI, mScoreCache, - NetworkScoreManager.CACHE_FILTER_SCAN_RESULTS); + NetworkScoreManager.SCORE_FILTER_SCAN_RESULTS); } private void requestScoresForNetworkKeys(Collection<NetworkKey> keys) { diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/OWNER b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/OWNER new file mode 100644 index 000000000000..5c2a7b892f8f --- /dev/null +++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/OWNER @@ -0,0 +1,4 @@ +# People who can approve changes for submission +arcwang@google.com +govenliu@google.com +qal@google.com diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java index 98bb74ad0718..4b9f6c22d78c 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/LocalMediaManagerTest.java @@ -127,7 +127,7 @@ public class LocalMediaManagerTest { mLocalMediaManager.registerCallback(mCallback); mLocalMediaManager.connectDevice(device); - verify(cachedDevice).connect(true); + verify(cachedDevice).connect(); } @Test diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/OWNER b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/OWNER new file mode 100644 index 000000000000..5c2a7b892f8f --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/OWNER @@ -0,0 +1,4 @@ +# People who can approve changes for submission +arcwang@google.com +govenliu@google.com +qal@google.com diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp index d674be4c8fc0..dbfaca0b6b80 100644 --- a/packages/SystemUI/Android.bp +++ b/packages/SystemUI/Android.bp @@ -142,7 +142,7 @@ android_app { resource_dirs: [], platform_apis: true, - product_specific: true, + system_ext_specific: true, certificate: "platform", privileged: true, diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 403e894a68e4..262365da3a06 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -72,7 +72,7 @@ <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" /> <uses-permission android:name="android.permission.OVERRIDE_WIFI_CONFIG" /> <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" /> - <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" /> + <uses-permission android:name="android.permission.OBSERVE_NETWORK_POLICY" /> <uses-permission android:name="android.permission.NETWORK_SETTINGS" /> <uses-permission android:name="android.permission.TETHER_PRIVILEGED" /> <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" /> diff --git a/packages/SystemUI/CleanSpec.mk b/packages/SystemUI/CleanSpec.mk new file mode 100644 index 000000000000..2a2e4e44e834 --- /dev/null +++ b/packages/SystemUI/CleanSpec.mk @@ -0,0 +1,50 @@ +# 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. +# + +# If you don't need to do a full clean build but would like to touch +# a file or delete some intermediate files, add a clean step to the end +# of the list. These steps will only be run once, if they haven't been +# run before. +# +# E.g.: +# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) +# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) +# +# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with +# files that are missing or have been moved. +# +# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. +# Use $(OUT_DIR) to refer to the "out" directory. +# +# If you need to re-do something that's already mentioned, just copy +# the command and add it to the bottom of the list. E.g., if a change +# that you made last week required touching a file and a change you +# made today requires touching the same file, just copy the old +# touch step and add it to the end of the list. +# +# ***************************************************************** +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THE BANNER +# ***************************************************************** + +# For example: +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/product/priv-app/SystemUI) +$(call add-clean-step, rm -rf $(PRODUCT_OUT)/product/priv-app/SystemUI) +# ****************************************************************** +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER +# ****************************************************************** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java index 5020744e6982..1c646b2d4ee2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -15,6 +15,9 @@ */ package com.android.systemui.statusbar.policy; +import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN; +import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS; + import android.content.Context; import android.content.Intent; import android.database.ContentObserver; @@ -708,7 +711,11 @@ public class MobileSignalController extends SignalController< } mServiceState = state; if (mServiceState != null) { - updateDataNetType(mServiceState.getDataNetworkType()); + NetworkRegistrationInfo regInfo = mServiceState.getNetworkRegistrationInfo( + DOMAIN_PS, TRANSPORT_TYPE_WWAN); + if (regInfo != null) { + updateDataNetType(regInfo.getAccessNetworkTechnology()); + } } updateTelephony(); } diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml index efb4ff008b23..a897b0098bb7 100644 --- a/packages/SystemUI/tests/AndroidManifest.xml +++ b/packages/SystemUI/tests/AndroidManifest.xml @@ -35,7 +35,6 @@ <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" /> <uses-permission android:name="android.permission.ACCESS_VR_MANAGER" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> - <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" /> <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" /> <uses-permission android:name="android.permission.REQUEST_NETWORK_SCORES" /> <uses-permission android:name="android.permission.CONTROL_VPN" /> diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java index b43527ca2ca6..59270d86844b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java @@ -16,6 +16,9 @@ package com.android.systemui.statusbar.policy; +import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN; +import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS; + import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; @@ -39,6 +42,7 @@ import android.net.wifi.WifiManager; import android.os.Handler; import android.provider.Settings; import android.provider.Settings.Global; +import android.telephony.NetworkRegistrationInfo; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SignalStrength; @@ -347,7 +351,13 @@ public class NetworkControllerBaseTest extends SysuiTestCase { } public void updateDataConnectionState(int dataState, int dataNetType) { - when(mServiceState.getDataNetworkType()).thenReturn(dataNetType); + NetworkRegistrationInfo fakeRegInfo = new NetworkRegistrationInfo.Builder() + .setTransportType(TRANSPORT_TYPE_WWAN) + .setDomain(DOMAIN_PS) + .setAccessNetworkTechnology(dataNetType) + .build(); + when(mServiceState.getNetworkRegistrationInfo(DOMAIN_PS, TRANSPORT_TYPE_WWAN)) + .thenReturn(fakeRegInfo); mPhoneStateListener.onDataConnectionStateChanged(dataState, dataNetType); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java index 99e5a76b3a11..47e0c3c1600d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java @@ -1,5 +1,8 @@ package com.android.systemui.statusbar.policy; +import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN; +import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS; + import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.anyInt; @@ -418,7 +421,13 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { // State from NR_5G to NONE NR_STATE_RESTRICTED, showing corresponding icon doReturn(NetworkRegistrationInfo.NR_STATE_RESTRICTED).when(mServiceState).getNrState(); - doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType(); + NetworkRegistrationInfo fakeRegInfo = new NetworkRegistrationInfo.Builder() + .setTransportType(TRANSPORT_TYPE_WWAN) + .setDomain(DOMAIN_PS) + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_LTE) + .build(); + doReturn(fakeRegInfo).when(mServiceState) + .getNetworkRegistrationInfo(DOMAIN_PS, TRANSPORT_TYPE_WWAN); mPhoneStateListener.onDataConnectionStateChanged(TelephonyManager.DATA_CONNECTED, TelephonyManager.NETWORK_TYPE_LTE); @@ -480,8 +489,13 @@ public class NetworkControllerDataTest extends NetworkControllerBaseTest { verifyDataIndicators(TelephonyIcons.ICON_LTE); - when(mServiceState.getDataNetworkType()) - .thenReturn(TelephonyManager.NETWORK_TYPE_HSPA); + NetworkRegistrationInfo fakeRegInfo = new NetworkRegistrationInfo.Builder() + .setTransportType(TRANSPORT_TYPE_WWAN) + .setDomain(DOMAIN_PS) + .setAccessNetworkTechnology(TelephonyManager.NETWORK_TYPE_HSPA) + .build(); + when(mServiceState.getNetworkRegistrationInfo(DOMAIN_PS, TRANSPORT_TYPE_WWAN)) + .thenReturn(fakeRegInfo); updateServiceState(); verifyDataIndicators(TelephonyIcons.ICON_H); } diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp index d297f3f84189..1315ed08464a 100644 --- a/packages/Tethering/Android.bp +++ b/packages/Tethering/Android.bp @@ -34,7 +34,7 @@ java_defaults { "framework-tethering", "unsupportedappusage", ], - + plugins: ["java_api_finder"], manifest: "AndroidManifestBase.xml", } diff --git a/packages/Tethering/AndroidManifest.xml b/packages/Tethering/AndroidManifest.xml index 5a71eb23abad..c71d0d7bc543 100644 --- a/packages/Tethering/AndroidManifest.xml +++ b/packages/Tethering/AndroidManifest.xml @@ -36,6 +36,7 @@ <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" /> <uses-permission android:name="android.permission.TETHER_PRIVILEGED" /> <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" /> + <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" /> <uses-permission android:name="android.permission.WRITE_SETTINGS" /> <application diff --git a/packages/Tethering/res/values/config.xml b/packages/Tethering/res/values/config.xml index ca290c637773..6fa1f77bdd38 100644 --- a/packages/Tethering/res/values/config.xml +++ b/packages/Tethering/res/values/config.xml @@ -100,7 +100,7 @@ <!-- If the mobile hotspot feature requires provisioning, a package name and class name can be provided to launch a supported application that provisions the devices. - EntitlementManager will send an inent to Settings with the specified package name and + EntitlementManager will send an intent to Settings with the specified package name and class name in extras to launch provision app. TODO: note what extras here. diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java index 6ac467e39a9d..0491ad7c3413 100644 --- a/packages/Tethering/src/android/net/ip/IpServer.java +++ b/packages/Tethering/src/android/net/ip/IpServer.java @@ -26,7 +26,6 @@ import static android.net.util.TetheringMessageBase.BASE_IPSERVER; import android.net.INetd; import android.net.INetworkStackStatusCallback; -import android.net.INetworkStatsService; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; @@ -176,7 +175,6 @@ public class IpServer extends StateMachine { private final SharedLog mLog; private final INetd mNetd; - private final INetworkStatsService mStatsService; private final Callback mCallback; private final InterfaceController mInterfaceCtrl; @@ -208,12 +206,10 @@ public class IpServer extends StateMachine { public IpServer( String ifaceName, Looper looper, int interfaceType, SharedLog log, - INetd netd, INetworkStatsService statsService, Callback callback, - boolean usingLegacyDhcp, Dependencies deps) { + INetd netd, Callback callback, boolean usingLegacyDhcp, Dependencies deps) { super(ifaceName, looper); mLog = log.forSubComponent(ifaceName); mNetd = netd; - mStatsService = statsService; mCallback = callback; mInterfaceCtrl = new InterfaceController(ifaceName, mNetd, mLog); mIfaceName = ifaceName; @@ -445,7 +441,8 @@ public class IpServer extends StateMachine { } final Boolean setIfaceUp; - if (mInterfaceType == TetheringManager.TETHERING_WIFI) { + if (mInterfaceType == TetheringManager.TETHERING_WIFI + || mInterfaceType == TetheringManager.TETHERING_WIFI_P2P) { // The WiFi stack has ownership of the interface up/down state. // It is unclear whether the Bluetooth or USB stacks will manage their own // state. @@ -882,12 +879,6 @@ public class IpServer extends StateMachine { // to remove their rules, which generates errors. // Just do the best we can. try { - // About to tear down NAT; gather remaining statistics. - mStatsService.forceUpdate(); - } catch (Exception e) { - mLog.e("Exception in forceUpdate: " + e.toString()); - } - try { mNetd.ipfwdRemoveInterfaceForward(mIfaceName, upstreamIface); } catch (RemoteException | ServiceSpecificException e) { mLog.e("Exception in ipfwdRemoveInterfaceForward: " + e.toString()); diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java index 4e2a2c1c7af7..1cabc8d0b5b7 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/EntitlementManager.java @@ -27,8 +27,6 @@ import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKONWN; import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR; import static android.net.TetheringManager.TETHER_ERROR_PROVISION_FAILED; -import static com.android.internal.R.string.config_wifi_tether_enable; - import android.app.AlarmManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; @@ -36,7 +34,6 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.res.Resources; import android.net.util.SharedLog; import android.os.Bundle; import android.os.Handler; @@ -54,6 +51,7 @@ import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.StateMachine; +import com.android.networkstack.tethering.R; import java.io.PrintWriter; @@ -75,9 +73,7 @@ public class EntitlementManager { "com.android.server.connectivity.tethering.PROVISIONING_RECHECK_ALARM"; private static final String EXTRA_SUBID = "subId"; - // {@link ComponentName} of the Service used to run tether provisioning. - private static final ComponentName TETHER_SERVICE = ComponentName.unflattenFromString( - Resources.getSystem().getString(config_wifi_tether_enable)); + private final ComponentName mSilentProvisioningService; private static final int MS_PER_HOUR = 60 * 60 * 1000; private static final int EVENT_START_PROVISIONING = 0; private static final int EVENT_STOP_PROVISIONING = 1; @@ -122,6 +118,8 @@ public class EntitlementManager { mHandler = new EntitlementHandler(masterHandler.getLooper()); mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_PROVISIONING_ALARM), null, mHandler); + mSilentProvisioningService = ComponentName.unflattenFromString( + mContext.getResources().getString(R.string.config_wifi_tether_enable)); } public void setOnUiEntitlementFailedListener(final OnUiEntitlementFailedListener listener) { @@ -377,7 +375,7 @@ public class EntitlementManager { intent.putExtra(EXTRA_RUN_PROVISION, true); intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver); intent.putExtra(EXTRA_SUBID, subId); - intent.setComponent(TETHER_SERVICE); + intent.setComponent(mSilentProvisioningService); // Only admin user can change tethering and SilentTetherProvisioning don't need to // show UI, it is fine to always start setting's background service as system user. mContext.startService(intent); diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java index ce7c2a669f0a..cc36f4a9c516 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadController.java @@ -16,35 +16,40 @@ package com.android.server.connectivity.tethering; +import static android.net.NetworkStats.DEFAULT_NETWORK_NO; +import static android.net.NetworkStats.METERED_NO; +import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.SET_DEFAULT; -import static android.net.NetworkStats.STATS_PER_UID; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; -import static android.net.TrafficStats.UID_TETHERING; +import static android.net.NetworkStats.UID_TETHERING; import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.usage.NetworkStatsManager; import android.content.ContentResolver; -import android.net.ITetheringStatsProvider; import android.net.InetAddresses; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.NetworkStats; +import android.net.NetworkStats.Entry; import android.net.RouteInfo; import android.net.netlink.ConntrackMessage; import android.net.netlink.NetlinkConstants; import android.net.netlink.NetlinkSocket; +import android.net.netstats.provider.AbstractNetworkStatsProvider; +import android.net.netstats.provider.NetworkStatsProviderCallback; import android.net.util.SharedLog; import android.os.Handler; -import android.os.INetworkManagementService; -import android.os.Looper; -import android.os.RemoteException; -import android.os.SystemClock; import android.provider.Settings; import android.system.ErrnoException; import android.system.OsConstants; import android.text.TextUtils; +import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; import com.android.server.connectivity.tethering.OffloadHardwareInterface.ForwardedStats; @@ -73,13 +78,19 @@ public class OffloadController { private static final String ANYIP = "0.0.0.0"; private static final ForwardedStats EMPTY_STATS = new ForwardedStats(); + @VisibleForTesting + enum StatsType { + STATS_PER_IFACE, + STATS_PER_UID, + } + private enum UpdateType { IF_NEEDED, FORCE }; private final Handler mHandler; private final OffloadHardwareInterface mHwInterface; private final ContentResolver mContentResolver; - private final INetworkManagementService mNms; - private final ITetheringStatsProvider mStatsProvider; + private final @NonNull OffloadTetheringStatsProvider mStatsProvider; + private final @Nullable NetworkStatsProviderCallback mStatsProviderCb; private final SharedLog mLog; private final HashMap<String, LinkProperties> mDownstreams; private boolean mConfigInitialized; @@ -109,22 +120,23 @@ public class OffloadController { private int mNatUpdateNetlinkErrors; public OffloadController(Handler h, OffloadHardwareInterface hwi, - ContentResolver contentResolver, INetworkManagementService nms, SharedLog log) { + ContentResolver contentResolver, NetworkStatsManager nsm, SharedLog log) { mHandler = h; mHwInterface = hwi; mContentResolver = contentResolver; - mNms = nms; mStatsProvider = new OffloadTetheringStatsProvider(); mLog = log.forSubComponent(TAG); mDownstreams = new HashMap<>(); mExemptPrefixes = new HashSet<>(); mLastLocalPrefixStrs = new HashSet<>(); - + NetworkStatsProviderCallback providerCallback = null; try { - mNms.registerTetheringStatsProvider(mStatsProvider, getClass().getSimpleName()); - } catch (RemoteException e) { - mLog.e("Cannot register offload stats provider: " + e); + providerCallback = nsm.registerNetworkStatsProvider( + getClass().getSimpleName(), mStatsProvider); + } catch (RuntimeException e) { + Log.wtf(TAG, "Cannot register offload stats provider: " + e); } + mStatsProviderCb = providerCallback; } /** Start hardware offload. */ @@ -173,7 +185,7 @@ public class OffloadController { // and we need to synchronize stats and limits between // software and hardware forwarding. updateStatsForAllUpstreams(); - forceTetherStatsPoll(); + mStatsProvider.pushTetherStats(); } @Override @@ -186,7 +198,7 @@ public class OffloadController { // limits set take into account any software tethering // traffic that has been happening in the meantime. updateStatsForAllUpstreams(); - forceTetherStatsPoll(); + mStatsProvider.pushTetherStats(); // [2] (Re)Push all state. computeAndPushLocalPrefixes(UpdateType.FORCE); pushAllDownstreamState(); @@ -204,14 +216,11 @@ public class OffloadController { // the HAL queued the callback. // TODO: rev the HAL so that it provides an interface name. - // Fetch current stats, so that when our notification reaches - // NetworkStatsService and triggers a poll, we will respond with - // current data (which will be above the limit that was reached). - // Note that if we just changed upstream, this is unnecessary but harmless. - // The stats for the previous upstream were already updated on this thread - // just after the upstream was changed, so they are also up-to-date. updateStatsForCurrentUpstream(); - forceTetherStatsPoll(); + mStatsProvider.pushTetherStats(); + // Push stats to service does not cause the service react to it immediately. + // Inform the service about limit reached. + if (mStatsProviderCb != null) mStatsProviderCb.onLimitReached(); } @Override @@ -253,42 +262,37 @@ public class OffloadController { return mConfigInitialized && mControlInitialized; } - private class OffloadTetheringStatsProvider extends ITetheringStatsProvider.Stub { - @Override - public NetworkStats getTetherStats(int how) { - // getTetherStats() is the only function in OffloadController that can be called from - // a different thread. Do not attempt to update stats by querying the offload HAL - // synchronously from a different thread than our Handler thread. http://b/64771555. - Runnable updateStats = () -> { - updateStatsForCurrentUpstream(); - }; - if (Looper.myLooper() == mHandler.getLooper()) { - updateStats.run(); - } else { - mHandler.post(updateStats); - } - - NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0); - NetworkStats.Entry entry = new NetworkStats.Entry(); - entry.set = SET_DEFAULT; - entry.tag = TAG_NONE; - entry.uid = (how == STATS_PER_UID) ? UID_TETHERING : UID_ALL; - - for (Map.Entry<String, ForwardedStats> kv : mForwardedStats.entrySet()) { - ForwardedStats value = kv.getValue(); - entry.iface = kv.getKey(); - entry.rxBytes = value.rxBytes; - entry.txBytes = value.txBytes; - stats.addEntry(entry); + @VisibleForTesting + class OffloadTetheringStatsProvider extends AbstractNetworkStatsProvider { + // These stats must only ever be touched on the handler thread. + @NonNull + private NetworkStats mIfaceStats = new NetworkStats(0L, 0); + @NonNull + private NetworkStats mUidStats = new NetworkStats(0L, 0); + + @VisibleForTesting + @NonNull + NetworkStats getTetherStats(@NonNull StatsType how) { + NetworkStats stats = new NetworkStats(0L, 0); + final int uid = (how == StatsType.STATS_PER_UID) ? UID_TETHERING : UID_ALL; + + for (final Map.Entry<String, ForwardedStats> kv : mForwardedStats.entrySet()) { + final ForwardedStats value = kv.getValue(); + final Entry entry = new Entry(kv.getKey(), uid, SET_DEFAULT, TAG_NONE, METERED_NO, + ROAMING_NO, DEFAULT_NETWORK_NO, value.rxBytes, 0L, value.txBytes, 0L, 0L); + stats = stats.addValues(entry); } return stats; } @Override - public void setInterfaceQuota(String iface, long quotaBytes) { + public void setLimit(String iface, long quotaBytes) { + mLog.i("setLimit: " + iface + "," + quotaBytes); + // Listen for all iface is necessary since upstream might be changed after limit + // is set. mHandler.post(() -> { - if (quotaBytes == ITetheringStatsProvider.QUOTA_UNLIMITED) { + if (quotaBytes == QUOTA_UNLIMITED) { mInterfaceQuotas.remove(iface); } else { mInterfaceQuotas.put(iface, quotaBytes); @@ -296,6 +300,42 @@ public class OffloadController { maybeUpdateDataLimit(iface); }); } + + /** + * Push stats to service, but does not cause a force polling. Note that this can only be + * called on the handler thread. + */ + public void pushTetherStats() { + // TODO: remove the accumulated stats and report the diff from HAL directly. + if (null == mStatsProviderCb) return; + final NetworkStats ifaceDiff = + getTetherStats(StatsType.STATS_PER_IFACE).subtract(mIfaceStats); + final NetworkStats uidDiff = + getTetherStats(StatsType.STATS_PER_UID).subtract(mUidStats); + try { + mStatsProviderCb.onStatsUpdated(0 /* token */, ifaceDiff, uidDiff); + mIfaceStats = mIfaceStats.add(ifaceDiff); + mUidStats = mUidStats.add(uidDiff); + } catch (RuntimeException e) { + mLog.e("Cannot report network stats: ", e); + } + } + + @Override + public void requestStatsUpdate(int token) { + mLog.i("requestStatsUpdate: " + token); + // Do not attempt to update stats by querying the offload HAL + // synchronously from a different thread than the Handler thread. http://b/64771555. + mHandler.post(() -> { + updateStatsForCurrentUpstream(); + pushTetherStats(); + }); + } + + @Override + public void setAlert(long quotaBytes) { + // TODO: Ask offload HAL to notify alert without stopping traffic. + } } private String currentUpstreamInterface() { @@ -353,14 +393,6 @@ public class OffloadController { } } - private void forceTetherStatsPoll() { - try { - mNms.tetherLimitReached(mStatsProvider); - } catch (RemoteException e) { - mLog.e("Cannot report data limit reached: " + e); - } - } - /** Set current tethering upstream LinkProperties. */ public void setUpstreamLinkProperties(LinkProperties lp) { if (!started() || Objects.equals(mUpstreamLinkProperties, lp)) return; diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java index 4a8ef1f92754..90b9d3f148dc 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/OffloadHardwareInterface.java @@ -29,6 +29,8 @@ import android.os.Handler; import android.os.RemoteException; import android.system.OsConstants; +import com.android.internal.annotations.VisibleForTesting; + import java.util.ArrayList; @@ -91,6 +93,12 @@ public class OffloadHardwareInterface { txBytes = 0; } + @VisibleForTesting + public ForwardedStats(long rxBytes, long txBytes) { + this.rxBytes = rxBytes; + this.txBytes = txBytes; + } + /** Add Tx/Rx bytes. */ public void add(ForwardedStats other) { rxBytes += other.rxBytes; diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java index 5b97f50f1208..5bf41ce25b2b 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/Tethering.java @@ -20,6 +20,7 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.hardware.usb.UsbManager.USB_CONFIGURED; import static android.hardware.usb.UsbManager.USB_CONNECTED; import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS; +import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO; import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED; @@ -53,6 +54,7 @@ import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; +import android.app.usage.NetworkStatsManager; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothPan; import android.bluetooth.BluetoothProfile; @@ -63,9 +65,8 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.res.Resources; import android.hardware.usb.UsbManager; +import android.net.ConnectivityManager; import android.net.INetd; -import android.net.INetworkPolicyManager; -import android.net.INetworkStatsService; import android.net.ITetheringEventCallback; import android.net.IpPrefix; import android.net.LinkAddress; @@ -176,8 +177,6 @@ public class Tethering { private final Context mContext; private final ArrayMap<String, TetherState> mTetherStates; private final BroadcastReceiver mStateReceiver; - private final INetworkStatsService mStatsService; - private final INetworkPolicyManager mPolicyManager; private final Looper mLooper; private final StateMachine mTetherMasterSM; private final OffloadController mOffloadController; @@ -207,13 +206,13 @@ public class Tethering { private boolean mWifiTetherRequested; private Network mTetherUpstream; private TetherStatesParcel mTetherStatesParcel; + private boolean mDataSaverEnabled = false; + private String mWifiP2pTetherInterface = null; public Tethering(TetheringDependencies deps) { mLog.mark("Tethering.constructed"); mDeps = deps; mContext = mDeps.getContext(); - mStatsService = mDeps.getINetworkStatsService(); - mPolicyManager = mDeps.getINetworkPolicyManager(); mNetd = mDeps.getINetd(mContext); mLooper = mDeps.getTetheringLooper(); @@ -224,10 +223,12 @@ public class Tethering { mTetherMasterSM = new TetherMasterSM("TetherMaster", mLooper, deps); mTetherMasterSM.start(); + final NetworkStatsManager statsManager = + (NetworkStatsManager) mContext.getSystemService(Context.NETWORK_STATS_SERVICE); mHandler = mTetherMasterSM.getHandler(); mOffloadController = new OffloadController(mHandler, mDeps.getOffloadHardwareInterface(mHandler, mLog), mContext.getContentResolver(), - mDeps.getINetworkManagementService(), mLog); + statsManager, mLog); mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog, TetherMasterSM.EVENT_UPSTREAM_CALLBACK); mForwardedDownstreams = new HashSet<>(); @@ -264,7 +265,7 @@ public class Tethering { } final UserManager userManager = (UserManager) mContext.getSystemService( - Context.USER_SERVICE); + Context.USER_SERVICE); mTetheringRestriction = new UserRestrictionActionListener(userManager, this); final TetheringThreadExecutor executor = new TetheringThreadExecutor(mHandler); mActiveDataSubIdListener = new ActiveDataSubIdListener(executor); @@ -288,6 +289,7 @@ public class Tethering { filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); filter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); filter.addAction(UserManager.ACTION_USER_RESTRICTIONS_CHANGED); + filter.addAction(ACTION_RESTRICT_BACKGROUND_CHANGED); mContext.registerReceiver(mStateReceiver, filter, null, handler); } @@ -484,7 +486,7 @@ public class Tethering { } private void setBluetoothTethering(final boolean enable, final ResultReceiver receiver) { - final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); + final BluetoothAdapter adapter = mDeps.getBluetoothAdapter(); if (adapter == null || !adapter.isEnabled()) { Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: " + (adapter == null)); @@ -740,8 +742,7 @@ public class Tethering { .setContentIntent(pi); mLastNotificationId = id; - notificationManager.notify(null, mLastNotificationId, - mTetheredNotificationBuilder.buildInto(new Notification())); + notificationManager.notify(null, mLastNotificationId, mTetheredNotificationBuilder.build()); } @VisibleForTesting @@ -775,6 +776,9 @@ public class Tethering { } else if (action.equals(UserManager.ACTION_USER_RESTRICTIONS_CHANGED)) { mLog.log("OBSERVED user restrictions changed"); handleUserRestrictionAction(); + } else if (action.equals(ACTION_RESTRICT_BACKGROUND_CHANGED)) { + mLog.log("OBSERVED data saver changed"); + handleDataSaverChanged(); } } @@ -849,6 +853,11 @@ public class Tethering { } } + private boolean isGroupOwner(WifiP2pGroup group) { + return group != null && group.isGroupOwner() + && !TextUtils.isEmpty(group.getInterface()); + } + private void handleWifiP2pAction(Intent intent) { if (mConfig.isWifiP2pLegacyTetheringMode()) return; @@ -861,30 +870,51 @@ public class Tethering { Log.d(TAG, "WifiP2pAction: P2pInfo: " + p2pInfo + " Group: " + group); } - if (p2pInfo == null) return; - // When a p2p group is disconnected, p2pInfo would be cleared. - // group is still valid for detecting whether this device is group owner. - if (group == null || !group.isGroupOwner() - || TextUtils.isEmpty(group.getInterface())) return; - synchronized (Tethering.this.mPublicSync) { - // Enter below only if this device is Group Owner with a valid interface. - if (p2pInfo.groupFormed) { - TetherState tetherState = mTetherStates.get(group.getInterface()); - if (tetherState == null - || (tetherState.lastState != IpServer.STATE_TETHERED - && tetherState.lastState != IpServer.STATE_LOCAL_ONLY)) { - enableWifiIpServingLocked(group.getInterface(), IFACE_IP_MODE_LOCAL_ONLY); - } - } else { - disableWifiP2pIpServingLocked(group.getInterface()); + // if no group is formed, bring it down if needed. + if (p2pInfo == null || !p2pInfo.groupFormed) { + disableWifiP2pIpServingLockedIfNeeded(mWifiP2pTetherInterface); + mWifiP2pTetherInterface = null; + return; } + + // If there is a group but the device is not the owner, bail out. + if (!isGroupOwner(group)) return; + + // If already serving from the correct interface, nothing to do. + if (group.getInterface().equals(mWifiP2pTetherInterface)) return; + + // If already serving from another interface, turn it down first. + if (!TextUtils.isEmpty(mWifiP2pTetherInterface)) { + mLog.w("P2P tethered interface " + mWifiP2pTetherInterface + + "is different from current interface " + + group.getInterface() + ", re-tether it"); + disableWifiP2pIpServingLockedIfNeeded(mWifiP2pTetherInterface); + } + + // Finally bring up serving on the new interface + mWifiP2pTetherInterface = group.getInterface(); + enableWifiIpServingLocked(mWifiP2pTetherInterface, IFACE_IP_MODE_LOCAL_ONLY); } } private void handleUserRestrictionAction() { mTetheringRestriction.onUserRestrictionsChanged(); } + + private void handleDataSaverChanged() { + final ConnectivityManager connMgr = (ConnectivityManager) mContext.getSystemService( + Context.CONNECTIVITY_SERVICE); + final boolean isDataSaverEnabled = connMgr.getRestrictBackgroundStatus() + != ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; + + if (mDataSaverEnabled == isDataSaverEnabled) return; + + mDataSaverEnabled = isDataSaverEnabled; + if (mDataSaverEnabled) { + untetherAll(); + } + } } @VisibleForTesting @@ -962,7 +992,9 @@ public class Tethering { disableWifiIpServingLockedCommon(TETHERING_WIFI, ifname, apState); } - private void disableWifiP2pIpServingLocked(String ifname) { + private void disableWifiP2pIpServingLockedIfNeeded(String ifname) { + if (TextUtils.isEmpty(ifname)) return; + disableWifiIpServingLockedCommon(TETHERING_WIFI_P2P, ifname, /* dummy */ 0); } @@ -1982,15 +2014,6 @@ public class Tethering { mLog.log(String.format("OBSERVED iface=%s state=%s error=%s", iface, state, error)); - try { - // Notify that we're tethering (or not) this interface. - // This is how data saver for instance knows if the user explicitly - // turned on tethering (thus keeping us from being in data saver mode). - mPolicyManager.onTetheringChanged(iface, state == IpServer.STATE_TETHERED); - } catch (RemoteException e) { - // Not really very much we can do here. - } - // If TetherMasterSM is in ErrorState, TetherMasterSM stays there. // Thus we give a chance for TetherMasterSM to recover to InitialState // by sending CMD_CLEAR_ERROR @@ -2054,7 +2077,7 @@ public class Tethering { mLog.log("adding TetheringInterfaceStateMachine for: " + iface); final TetherState tetherState = new TetherState( - new IpServer(iface, mLooper, interfaceType, mLog, mNetd, mStatsService, + new IpServer(iface, mLooper, interfaceType, mLog, mNetd, makeControlCallback(), mConfig.enableLegacyDhcpServer, mDeps.getIpServerDependencies())); mTetherStates.put(iface, tetherState); diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java index dbe789288c6f..068c346fbfc1 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringConfiguration.java @@ -23,18 +23,6 @@ import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY; -import static com.android.internal.R.array.config_mobile_hotspot_provision_app; -import static com.android.internal.R.array.config_tether_bluetooth_regexs; -import static com.android.internal.R.array.config_tether_dhcp_range; -import static com.android.internal.R.array.config_tether_upstream_types; -import static com.android.internal.R.array.config_tether_usb_regexs; -import static com.android.internal.R.array.config_tether_wifi_p2p_regexs; -import static com.android.internal.R.array.config_tether_wifi_regexs; -import static com.android.internal.R.bool.config_tether_upstream_automatic; -import static com.android.internal.R.integer.config_mobile_hotspot_provision_check_period; -import static com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui; -import static com.android.networkstack.tethering.R.bool.config_tether_enable_legacy_dhcp_server; - import android.content.Context; import android.content.res.Resources; import android.net.TetheringConfigurationParcel; @@ -45,6 +33,7 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import com.android.internal.annotations.VisibleForTesting; +import com.android.networkstack.tethering.R; import java.io.PrintWriter; import java.util.ArrayList; @@ -113,27 +102,30 @@ public class TetheringConfiguration { activeDataSubId = id; Resources res = getResources(ctx, activeDataSubId); - tetherableUsbRegexs = getResourceStringArray(res, config_tether_usb_regexs); + tetherableUsbRegexs = getResourceStringArray(res, R.array.config_tether_usb_regexs); // TODO: Evaluate deleting this altogether now that Wi-Fi always passes // us an interface name. Careful consideration needs to be given to // implications for Settings and for provisioning checks. - tetherableWifiRegexs = getResourceStringArray(res, config_tether_wifi_regexs); - tetherableWifiP2pRegexs = getResourceStringArray(res, config_tether_wifi_p2p_regexs); - tetherableBluetoothRegexs = getResourceStringArray(res, config_tether_bluetooth_regexs); + tetherableWifiRegexs = getResourceStringArray(res, R.array.config_tether_wifi_regexs); + tetherableWifiP2pRegexs = getResourceStringArray( + res, R.array.config_tether_wifi_p2p_regexs); + tetherableBluetoothRegexs = getResourceStringArray( + res, R.array.config_tether_bluetooth_regexs); isDunRequired = checkDunRequired(ctx); - chooseUpstreamAutomatically = getResourceBoolean(res, config_tether_upstream_automatic); + chooseUpstreamAutomatically = getResourceBoolean( + res, R.bool.config_tether_upstream_automatic); preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(res, isDunRequired); legacyDhcpRanges = getLegacyDhcpRanges(res); defaultIPv4DNS = copy(DEFAULT_IPV4_DNS); enableLegacyDhcpServer = getEnableLegacyDhcpServer(res); - provisioningApp = getResourceStringArray(res, config_mobile_hotspot_provision_app); + provisioningApp = getResourceStringArray(res, R.array.config_mobile_hotspot_provision_app); provisioningAppNoUi = getProvisioningAppNoUi(res); provisioningCheckPeriod = getResourceInteger(res, - config_mobile_hotspot_provision_check_period, + R.integer.config_mobile_hotspot_provision_check_period, 0 /* No periodic re-check */); configLog.log(toString()); @@ -248,7 +240,7 @@ public class TetheringConfiguration { } private static Collection<Integer> getUpstreamIfaceTypes(Resources res, boolean dunRequired) { - final int[] ifaceTypes = res.getIntArray(config_tether_upstream_types); + final int[] ifaceTypes = res.getIntArray(R.array.config_tether_upstream_types); final ArrayList<Integer> upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length); for (int i : ifaceTypes) { switch (i) { @@ -298,7 +290,7 @@ public class TetheringConfiguration { } private static String[] getLegacyDhcpRanges(Resources res) { - final String[] fromResource = getResourceStringArray(res, config_tether_dhcp_range); + final String[] fromResource = getResourceStringArray(res, R.array.config_tether_dhcp_range); if ((fromResource.length > 0) && (fromResource.length % 2 == 0)) { return fromResource; } @@ -307,7 +299,7 @@ public class TetheringConfiguration { private static String getProvisioningAppNoUi(Resources res) { try { - return res.getString(config_mobile_hotspot_provision_app_no_ui); + return res.getString(R.string.config_mobile_hotspot_provision_app_no_ui); } catch (Resources.NotFoundException e) { return ""; } @@ -339,7 +331,7 @@ public class TetheringConfiguration { } private boolean getEnableLegacyDhcpServer(final Resources res) { - return getResourceBoolean(res, config_tether_enable_legacy_dhcp_server) + return getResourceBoolean(res, R.bool.config_tether_enable_legacy_dhcp_server) || getDeviceConfigBoolean(TETHER_ENABLE_LEGACY_DHCP_SERVER); } diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java index b16b3294a112..e019c3aca26a 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringDependencies.java @@ -16,18 +16,15 @@ package com.android.server.connectivity.tethering; +import android.bluetooth.BluetoothAdapter; import android.content.Context; import android.net.INetd; -import android.net.INetworkPolicyManager; -import android.net.INetworkStatsService; import android.net.NetworkRequest; import android.net.ip.IpServer; import android.net.util.SharedLog; import android.os.Handler; import android.os.IBinder; -import android.os.INetworkManagementService; import android.os.Looper; -import android.os.ServiceManager; import com.android.internal.util.StateMachine; @@ -97,33 +94,6 @@ public abstract class TetheringDependencies { } /** - * Get a reference to INetworkManagementService to registerTetheringStatsProvider from - * OffloadController. Note: This should be removed soon by Usage refactor work in R - * development cycle. - */ - public INetworkManagementService getINetworkManagementService() { - return INetworkManagementService.Stub.asInterface( - ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)); - } - - /** - * Get a reference to INetworkStatsService to force update tethering usage. - * Note: This should be removed in R development cycle. - */ - public INetworkStatsService getINetworkStatsService() { - return INetworkStatsService.Stub.asInterface( - ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); - } - - /** - * Get a reference to INetworkPolicyManager to be used by tethering. - */ - public INetworkPolicyManager getINetworkPolicyManager() { - return INetworkPolicyManager.Stub.asInterface( - ServiceManager.getService(Context.NETWORK_POLICY_SERVICE)); - } - - /** * Get a reference to INetd to be used by tethering. */ public INetd getINetd(Context context) { @@ -140,4 +110,9 @@ public abstract class TetheringDependencies { * Get Context of TetheringSerice. */ public abstract Context getContext(); + + /** + * Get a reference to BluetoothAdapter to be used by tethering. + */ + public abstract BluetoothAdapter getBluetoothAdapter(); } diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java index e4e4a090603d..cb7d3920e693 100644 --- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java +++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java @@ -24,6 +24,7 @@ import static android.net.TetheringManager.TETHER_ERROR_UNSUPPORTED; import static android.net.dhcp.IDhcpServer.STATUS_UNKNOWN_ERROR; import android.app.Service; +import android.bluetooth.BluetoothAdapter; import android.content.Context; import android.content.Intent; import android.net.IIntResultListener; @@ -42,7 +43,6 @@ import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.os.ResultReceiver; -import android.os.ServiceManager; import android.os.SystemProperties; import android.os.UserManager; import android.provider.Settings; @@ -363,7 +363,7 @@ public class TetheringService extends Service { IBinder connector; try { final long before = System.currentTimeMillis(); - while ((connector = ServiceManager.getService( + while ((connector = (IBinder) mContext.getSystemService( Context.NETWORK_STACK_SERVICE)) == null) { if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) { Log.wtf(TAG, "Timeout, fail to get INetworkStackConnector"); @@ -377,6 +377,11 @@ public class TetheringService extends Service { } return INetworkStackConnector.Stub.asInterface(connector); } + + @Override + public BluetoothAdapter getBluetoothAdapter() { + return BluetoothAdapter.getDefaultAdapter(); + } }; } return mDeps; diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index 65a0ac13a84b..f29ad780b92c 100644 --- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -52,7 +52,6 @@ import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; import android.net.INetd; -import android.net.INetworkStatsService; import android.net.InterfaceConfigurationParcel; import android.net.IpPrefix; import android.net.LinkAddress; @@ -99,7 +98,6 @@ public class IpServerTest { private static final int MAKE_DHCPSERVER_TIMEOUT_MS = 1000; @Mock private INetd mNetd; - @Mock private INetworkStatsService mStatsService; @Mock private IpServer.Callback mCallback; @Mock private SharedLog mSharedLog; @Mock private IDhcpServer mDhcpServer; @@ -139,13 +137,13 @@ public class IpServerTest { mInterfaceConfiguration.prefixLength = BLUETOOTH_DHCP_PREFIX_LENGTH; } mIpServer = new IpServer( - IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, mNetd, mStatsService, + IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, mNetd, mCallback, usingLegacyDhcp, mDependencies); mIpServer.start(); // Starting the state machine always puts us in a consistent state and notifies // the rest of the world that we've changed from an unknown to available state. mLooper.dispatchAll(); - reset(mNetd, mStatsService, mCallback); + reset(mNetd, mCallback); when(mRaDaemon.start()).thenReturn(true); } @@ -162,7 +160,7 @@ public class IpServerTest { if (upstreamIface != null) { dispatchTetherConnectionChanged(upstreamIface); } - reset(mNetd, mStatsService, mCallback); + reset(mNetd, mCallback); } @Before public void setUp() throws Exception { @@ -173,13 +171,13 @@ public class IpServerTest { @Test public void startsOutAvailable() { mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(), TETHERING_BLUETOOTH, mSharedLog, - mNetd, mStatsService, mCallback, false /* usingLegacyDhcp */, mDependencies); + mNetd, mCallback, false /* usingLegacyDhcp */, mDependencies); mIpServer.start(); mLooper.dispatchAll(); verify(mCallback).updateInterfaceState( mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR); verify(mCallback).updateLinkProperties(eq(mIpServer), any(LinkProperties.class)); - verifyNoMoreInteractions(mCallback, mNetd, mStatsService); + verifyNoMoreInteractions(mCallback, mNetd); } @Test @@ -198,7 +196,7 @@ public class IpServerTest { // None of these commands should trigger us to request action from // the rest of the system. dispatchCommand(command); - verifyNoMoreInteractions(mNetd, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mCallback); } } @@ -210,7 +208,7 @@ public class IpServerTest { verify(mCallback).updateInterfaceState( mIpServer, STATE_UNAVAILABLE, TETHER_ERROR_NO_ERROR); verify(mCallback).updateLinkProperties(eq(mIpServer), any(LinkProperties.class)); - verifyNoMoreInteractions(mNetd, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mCallback); } @Test @@ -228,7 +226,7 @@ public class IpServerTest { mIpServer, STATE_TETHERED, TETHER_ERROR_NO_ERROR); inOrder.verify(mCallback).updateLinkProperties( eq(mIpServer), any(LinkProperties.class)); - verifyNoMoreInteractions(mNetd, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mCallback); } @Test @@ -236,7 +234,7 @@ public class IpServerTest { initTetheredStateMachine(TETHERING_BLUETOOTH, null); dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED); - InOrder inOrder = inOrder(mNetd, mStatsService, mCallback); + InOrder inOrder = inOrder(mNetd, mCallback); inOrder.verify(mNetd).tetherApplyDnsInterfaces(); inOrder.verify(mNetd).tetherInterfaceRemove(IFACE_NAME); inOrder.verify(mNetd).networkRemoveInterface(INetd.LOCAL_NET_ID, IFACE_NAME); @@ -245,7 +243,7 @@ public class IpServerTest { mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR); inOrder.verify(mCallback).updateLinkProperties( eq(mIpServer), any(LinkProperties.class)); - verifyNoMoreInteractions(mNetd, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mCallback); } @Test @@ -265,7 +263,7 @@ public class IpServerTest { inOrder.verify(mCallback).updateLinkProperties( eq(mIpServer), mLinkPropertiesCaptor.capture()); assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue()); - verifyNoMoreInteractions(mNetd, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mCallback); } @Test @@ -275,7 +273,7 @@ public class IpServerTest { dispatchCommand(IpServer.CMD_TETHER_REQUESTED, STATE_LOCAL_ONLY); InOrder inOrder = inOrder(mCallback, mNetd); inOrder.verify(mNetd).interfaceSetCfg(argThat(cfg -> - IFACE_NAME.equals(cfg.ifName) && assertContainsFlag(cfg.flags, IF_STATE_UP))); + IFACE_NAME.equals(cfg.ifName) && assertNotContainsFlag(cfg.flags, IF_STATE_UP))); inOrder.verify(mNetd).tetherInterfaceAdd(IFACE_NAME); inOrder.verify(mNetd).networkAddInterface(INetd.LOCAL_NET_ID, IFACE_NAME); inOrder.verify(mNetd, times(2)).networkAddRoute(eq(INetd.LOCAL_NET_ID), eq(IFACE_NAME), @@ -285,7 +283,7 @@ public class IpServerTest { inOrder.verify(mCallback).updateLinkProperties( eq(mIpServer), mLinkPropertiesCaptor.capture()); assertIPv4AddressAndDirectlyConnectedRoute(mLinkPropertiesCaptor.getValue()); - verifyNoMoreInteractions(mNetd, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mCallback); } @Test @@ -298,7 +296,7 @@ public class IpServerTest { InOrder inOrder = inOrder(mNetd); inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE); inOrder.verify(mNetd).ipfwdAddInterfaceForward(IFACE_NAME, UPSTREAM_IFACE); - verifyNoMoreInteractions(mNetd, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mCallback); } @Test @@ -306,13 +304,12 @@ public class IpServerTest { initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE); dispatchTetherConnectionChanged(UPSTREAM_IFACE2); - InOrder inOrder = inOrder(mNetd, mStatsService); - inOrder.verify(mStatsService).forceUpdate(); + InOrder inOrder = inOrder(mNetd); inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE); inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE); inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2); inOrder.verify(mNetd).ipfwdAddInterfaceForward(IFACE_NAME, UPSTREAM_IFACE2); - verifyNoMoreInteractions(mNetd, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mCallback); } @Test @@ -322,12 +319,10 @@ public class IpServerTest { doThrow(RemoteException.class).when(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2); dispatchTetherConnectionChanged(UPSTREAM_IFACE2); - InOrder inOrder = inOrder(mNetd, mStatsService); - inOrder.verify(mStatsService).forceUpdate(); + InOrder inOrder = inOrder(mNetd); inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE); inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE); inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2); - inOrder.verify(mStatsService).forceUpdate(); inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE2); inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE2); } @@ -340,13 +335,11 @@ public class IpServerTest { IFACE_NAME, UPSTREAM_IFACE2); dispatchTetherConnectionChanged(UPSTREAM_IFACE2); - InOrder inOrder = inOrder(mNetd, mStatsService); - inOrder.verify(mStatsService).forceUpdate(); + InOrder inOrder = inOrder(mNetd); inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE); inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE); inOrder.verify(mNetd).tetherAddForward(IFACE_NAME, UPSTREAM_IFACE2); inOrder.verify(mNetd).ipfwdAddInterfaceForward(IFACE_NAME, UPSTREAM_IFACE2); - inOrder.verify(mStatsService).forceUpdate(); inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE2); inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE2); } @@ -356,8 +349,7 @@ public class IpServerTest { initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE); dispatchCommand(IpServer.CMD_TETHER_UNREQUESTED); - InOrder inOrder = inOrder(mNetd, mStatsService, mCallback); - inOrder.verify(mStatsService).forceUpdate(); + InOrder inOrder = inOrder(mNetd, mCallback); inOrder.verify(mNetd).ipfwdRemoveInterfaceForward(IFACE_NAME, UPSTREAM_IFACE); inOrder.verify(mNetd).tetherRemoveForward(IFACE_NAME, UPSTREAM_IFACE); inOrder.verify(mNetd).tetherApplyDnsInterfaces(); @@ -368,7 +360,7 @@ public class IpServerTest { mIpServer, STATE_AVAILABLE, TETHER_ERROR_NO_ERROR); inOrder.verify(mCallback).updateLinkProperties( eq(mIpServer), any(LinkProperties.class)); - verifyNoMoreInteractions(mNetd, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mCallback); } @Test @@ -435,11 +427,11 @@ public class IpServerTest { public void ignoresDuplicateUpstreamNotifications() throws Exception { initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE); - verifyNoMoreInteractions(mNetd, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mCallback); for (int i = 0; i < 5; i++) { dispatchTetherConnectionChanged(UPSTREAM_IFACE); - verifyNoMoreInteractions(mNetd, mStatsService, mCallback); + verifyNoMoreInteractions(mNetd, mCallback); } } @@ -555,4 +547,14 @@ public class IpServerTest { fail("Missing flag: " + match); return false; } + + private boolean assertNotContainsFlag(String[] flags, String match) { + for (String flag : flags) { + if (flag.equals(match)) { + fail("Unexpected flag: " + match); + return false; + } + } + return true; + } } diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java index 79bba7f6e663..4f0746199786 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/EntitlementManagerTest.java @@ -27,7 +27,6 @@ import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; -import static com.android.networkstack.tethering.R.bool.config_tether_enable_legacy_dhcp_server; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -56,10 +55,10 @@ import android.telephony.CarrierConfigManager; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; -import com.android.internal.R; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.internal.util.test.BroadcastInterceptingContext; +import com.android.networkstack.tethering.R; import org.junit.After; import org.junit.Before; @@ -157,16 +156,18 @@ public final class EntitlementManagerTest { eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean())); when(mResources.getStringArray(R.array.config_tether_dhcp_range)) - .thenReturn(new String[0]); + .thenReturn(new String[0]); when(mResources.getStringArray(R.array.config_tether_usb_regexs)) - .thenReturn(new String[0]); + .thenReturn(new String[0]); when(mResources.getStringArray(R.array.config_tether_wifi_regexs)) - .thenReturn(new String[0]); + .thenReturn(new String[0]); when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs)) - .thenReturn(new String[0]); + .thenReturn(new String[0]); when(mResources.getIntArray(R.array.config_tether_upstream_types)) - .thenReturn(new int[0]); - when(mResources.getBoolean(config_tether_enable_legacy_dhcp_server)).thenReturn(false); + .thenReturn(new int[0]); + when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( + false); + when(mResources.getString(R.string.config_wifi_tether_enable)).thenReturn(""); when(mLog.forSubComponent(anyString())).thenReturn(mLog); mMockContext = new MockContext(mContext); diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java index 7886ca6c132d..7e62e5aca993 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/OffloadControllerTest.java @@ -16,21 +16,26 @@ package com.android.server.connectivity.tethering; +import static android.net.NetworkStats.DEFAULT_NETWORK_NO; +import static android.net.NetworkStats.METERED_NO; +import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.SET_DEFAULT; -import static android.net.NetworkStats.STATS_PER_IFACE; -import static android.net.NetworkStats.STATS_PER_UID; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; +import static android.net.NetworkStats.UID_TETHERING; import static android.net.RouteInfo.RTN_UNICAST; -import static android.net.TrafficStats.UID_TETHERING; import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED; +import static com.android.server.connectivity.tethering.OffloadController.StatsType.STATS_PER_IFACE; +import static com.android.server.connectivity.tethering.OffloadController.StatsType.STATS_PER_UID; import static com.android.server.connectivity.tethering.OffloadHardwareInterface.ForwardedStats; import static com.android.testutils.MiscAssertsKt.assertContainsAll; import static com.android.testutils.MiscAssertsKt.assertThrows; +import static com.android.testutils.NetworkStatsUtilsKt.orderInsensitiveEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyLong; import static org.mockito.Matchers.anyObject; @@ -39,11 +44,14 @@ import static org.mockito.Matchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; 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.annotation.NonNull; +import android.app.usage.NetworkStatsManager; import android.content.Context; import android.content.pm.ApplicationInfo; import android.net.ITetheringStatsProvider; @@ -51,10 +59,12 @@ import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.NetworkStats; +import android.net.NetworkStats.Entry; import android.net.RouteInfo; +import android.net.netstats.provider.AbstractNetworkStatsProvider; +import android.net.netstats.provider.NetworkStatsProviderCallback; import android.net.util.SharedLog; import android.os.Handler; -import android.os.INetworkManagementService; import android.os.Looper; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; @@ -97,11 +107,13 @@ public class OffloadControllerTest { @Mock private OffloadHardwareInterface mHardware; @Mock private ApplicationInfo mApplicationInfo; @Mock private Context mContext; - @Mock private INetworkManagementService mNMService; + @Mock private NetworkStatsManager mStatsManager; + @Mock private NetworkStatsProviderCallback mTetherStatsProviderCb; private final ArgumentCaptor<ArrayList> mStringArrayCaptor = ArgumentCaptor.forClass(ArrayList.class); - private final ArgumentCaptor<ITetheringStatsProvider.Stub> mTetherStatsProviderCaptor = - ArgumentCaptor.forClass(ITetheringStatsProvider.Stub.class); + private final ArgumentCaptor<OffloadController.OffloadTetheringStatsProvider> + mTetherStatsProviderCaptor = + ArgumentCaptor.forClass(OffloadController.OffloadTetheringStatsProvider.class); private final ArgumentCaptor<OffloadHardwareInterface.ControlCallback> mControlCallbackCaptor = ArgumentCaptor.forClass(OffloadHardwareInterface.ControlCallback.class); private MockContentResolver mContentResolver; @@ -114,6 +126,8 @@ public class OffloadControllerTest { mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); when(mContext.getContentResolver()).thenReturn(mContentResolver); FakeSettingsProvider.clearSettingsProvider(); + when(mStatsManager.registerNetworkStatsProvider(anyString(), any())) + .thenReturn(mTetherStatsProviderCb); } @After public void tearDown() throws Exception { @@ -139,9 +153,9 @@ public class OffloadControllerTest { private OffloadController makeOffloadController() throws Exception { OffloadController offload = new OffloadController(new Handler(Looper.getMainLooper()), - mHardware, mContentResolver, mNMService, new SharedLog("test")); - verify(mNMService).registerTetheringStatsProvider( - mTetherStatsProviderCaptor.capture(), anyString()); + mHardware, mContentResolver, mStatsManager, new SharedLog("test")); + verify(mStatsManager).registerNetworkStatsProvider(anyString(), + mTetherStatsProviderCaptor.capture()); return offload; } @@ -384,12 +398,11 @@ public class OffloadControllerTest { inOrder.verifyNoMoreInteractions(); } - private void assertNetworkStats(String iface, ForwardedStats stats, NetworkStats.Entry entry) { - assertEquals(iface, entry.iface); - assertEquals(stats.rxBytes, entry.rxBytes); - assertEquals(stats.txBytes, entry.txBytes); - assertEquals(SET_DEFAULT, entry.set); - assertEquals(TAG_NONE, entry.tag); + private static @NonNull Entry buildTestEntry(@NonNull OffloadController.StatsType how, + @NonNull String iface, long rxBytes, long txBytes) { + return new Entry(iface, how == STATS_PER_IFACE ? UID_ALL : UID_TETHERING, SET_DEFAULT, + TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, rxBytes, 0L, + txBytes, 0L, 0L); } @Test @@ -400,19 +413,16 @@ public class OffloadControllerTest { final OffloadController offload = makeOffloadController(); offload.start(); + final OffloadController.OffloadTetheringStatsProvider provider = + mTetherStatsProviderCaptor.getValue(); + final String ethernetIface = "eth1"; final String mobileIface = "rmnet_data0"; - ForwardedStats ethernetStats = new ForwardedStats(); - ethernetStats.rxBytes = 12345; - ethernetStats.txBytes = 54321; - - ForwardedStats mobileStats = new ForwardedStats(); - mobileStats.rxBytes = 999; - mobileStats.txBytes = 99999; - - when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn(ethernetStats); - when(mHardware.getForwardedStats(eq(mobileIface))).thenReturn(mobileStats); + when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn( + new ForwardedStats(12345, 54321)); + when(mHardware.getForwardedStats(eq(mobileIface))).thenReturn( + new ForwardedStats(999, 99999)); InOrder inOrder = inOrder(mHardware); @@ -432,10 +442,35 @@ public class OffloadControllerTest { // Expect that we fetch stats from the previous upstream. inOrder.verify(mHardware, times(1)).getForwardedStats(eq(mobileIface)); - ethernetStats = new ForwardedStats(); - ethernetStats.rxBytes = 100000; - ethernetStats.txBytes = 100000; - when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn(ethernetStats); + // Verify that the fetched stats are stored. + final NetworkStats ifaceStats = provider.getTetherStats(STATS_PER_IFACE); + final NetworkStats uidStats = provider.getTetherStats(STATS_PER_UID); + final NetworkStats expectedIfaceStats = new NetworkStats(0L, 2) + .addValues(buildTestEntry(STATS_PER_IFACE, mobileIface, 999, 99999)) + .addValues(buildTestEntry(STATS_PER_IFACE, ethernetIface, 12345, 54321)); + + final NetworkStats expectedUidStats = new NetworkStats(0L, 2) + .addValues(buildTestEntry(STATS_PER_UID, mobileIface, 999, 99999)) + .addValues(buildTestEntry(STATS_PER_UID, ethernetIface, 12345, 54321)); + + assertTrue(orderInsensitiveEquals(expectedIfaceStats, ifaceStats)); + assertTrue(orderInsensitiveEquals(expectedUidStats, uidStats)); + + final ArgumentCaptor<NetworkStats> ifaceStatsCaptor = ArgumentCaptor.forClass( + NetworkStats.class); + final ArgumentCaptor<NetworkStats> uidStatsCaptor = ArgumentCaptor.forClass( + NetworkStats.class); + + // Force pushing stats update to verify the stats reported. + provider.pushTetherStats(); + verify(mTetherStatsProviderCb, times(1)).onStatsUpdated(anyInt(), + ifaceStatsCaptor.capture(), uidStatsCaptor.capture()); + assertTrue(orderInsensitiveEquals(expectedIfaceStats, ifaceStatsCaptor.getValue())); + assertTrue(orderInsensitiveEquals(expectedUidStats, uidStatsCaptor.getValue())); + + + when(mHardware.getForwardedStats(eq(ethernetIface))).thenReturn( + new ForwardedStats(100000, 100000)); offload.setUpstreamLinkProperties(null); // Expect that we first clear the HAL's upstream parameters. inOrder.verify(mHardware, times(1)).setUpstreamParameters( @@ -443,37 +478,38 @@ public class OffloadControllerTest { // Expect that we fetch stats from the previous upstream. inOrder.verify(mHardware, times(1)).getForwardedStats(eq(ethernetIface)); - ITetheringStatsProvider provider = mTetherStatsProviderCaptor.getValue(); - NetworkStats stats = provider.getTetherStats(STATS_PER_IFACE); - NetworkStats perUidStats = provider.getTetherStats(STATS_PER_UID); - waitForIdle(); // There is no current upstream, so no stats are fetched. inOrder.verify(mHardware, never()).getForwardedStats(any()); inOrder.verifyNoMoreInteractions(); - assertEquals(2, stats.size()); - assertEquals(2, perUidStats.size()); - - NetworkStats.Entry entry = null; - for (int i = 0; i < stats.size(); i++) { - assertEquals(UID_ALL, stats.getValues(i, entry).uid); - assertEquals(UID_TETHERING, perUidStats.getValues(i, entry).uid); - } - - int ethernetPosition = ethernetIface.equals(stats.getValues(0, entry).iface) ? 0 : 1; - int mobilePosition = 1 - ethernetPosition; - - entry = stats.getValues(mobilePosition, entry); - assertNetworkStats(mobileIface, mobileStats, entry); - entry = perUidStats.getValues(mobilePosition, entry); - assertNetworkStats(mobileIface, mobileStats, entry); - - ethernetStats.rxBytes = 12345 + 100000; - ethernetStats.txBytes = 54321 + 100000; - entry = stats.getValues(ethernetPosition, entry); - assertNetworkStats(ethernetIface, ethernetStats, entry); - entry = perUidStats.getValues(ethernetPosition, entry); - assertNetworkStats(ethernetIface, ethernetStats, entry); + // Verify that the stored stats is accumulated. + final NetworkStats ifaceStatsAccu = provider.getTetherStats(STATS_PER_IFACE); + final NetworkStats uidStatsAccu = provider.getTetherStats(STATS_PER_UID); + final NetworkStats expectedIfaceStatsAccu = new NetworkStats(0L, 2) + .addValues(buildTestEntry(STATS_PER_IFACE, mobileIface, 999, 99999)) + .addValues(buildTestEntry(STATS_PER_IFACE, ethernetIface, 112345, 154321)); + + final NetworkStats expectedUidStatsAccu = new NetworkStats(0L, 2) + .addValues(buildTestEntry(STATS_PER_UID, mobileIface, 999, 99999)) + .addValues(buildTestEntry(STATS_PER_UID, ethernetIface, 112345, 154321)); + + assertTrue(orderInsensitiveEquals(expectedIfaceStatsAccu, ifaceStatsAccu)); + assertTrue(orderInsensitiveEquals(expectedUidStatsAccu, uidStatsAccu)); + + // Verify that only diff of stats is reported. + reset(mTetherStatsProviderCb); + provider.pushTetherStats(); + final NetworkStats expectedIfaceStatsDiff = new NetworkStats(0L, 2) + .addValues(buildTestEntry(STATS_PER_IFACE, mobileIface, 0, 0)) + .addValues(buildTestEntry(STATS_PER_IFACE, ethernetIface, 100000, 100000)); + + final NetworkStats expectedUidStatsDiff = new NetworkStats(0L, 2) + .addValues(buildTestEntry(STATS_PER_UID, mobileIface, 0, 0)) + .addValues(buildTestEntry(STATS_PER_UID, ethernetIface, 100000, 100000)); + verify(mTetherStatsProviderCb, times(1)).onStatsUpdated(anyInt(), + ifaceStatsCaptor.capture(), uidStatsCaptor.capture()); + assertTrue(orderInsensitiveEquals(expectedIfaceStatsDiff, ifaceStatsCaptor.getValue())); + assertTrue(orderInsensitiveEquals(expectedUidStatsDiff, uidStatsCaptor.getValue())); } @Test @@ -493,19 +529,19 @@ public class OffloadControllerTest { lp.setInterfaceName(ethernetIface); offload.setUpstreamLinkProperties(lp); - ITetheringStatsProvider provider = mTetherStatsProviderCaptor.getValue(); + AbstractNetworkStatsProvider provider = mTetherStatsProviderCaptor.getValue(); final InOrder inOrder = inOrder(mHardware); when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(true); when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(true); // Applying an interface quota to the current upstream immediately sends it to the hardware. - provider.setInterfaceQuota(ethernetIface, ethernetLimit); + provider.setLimit(ethernetIface, ethernetLimit); waitForIdle(); inOrder.verify(mHardware).setDataLimit(ethernetIface, ethernetLimit); inOrder.verifyNoMoreInteractions(); // Applying an interface quota to another upstream does not take any immediate action. - provider.setInterfaceQuota(mobileIface, mobileLimit); + provider.setLimit(mobileIface, mobileLimit); waitForIdle(); inOrder.verify(mHardware, never()).setDataLimit(anyString(), anyLong()); @@ -518,7 +554,7 @@ public class OffloadControllerTest { // Setting a limit of ITetheringStatsProvider.QUOTA_UNLIMITED causes the limit to be set // to Long.MAX_VALUE. - provider.setInterfaceQuota(mobileIface, ITetheringStatsProvider.QUOTA_UNLIMITED); + provider.setLimit(mobileIface, ITetheringStatsProvider.QUOTA_UNLIMITED); waitForIdle(); inOrder.verify(mHardware).setDataLimit(mobileIface, Long.MAX_VALUE); @@ -526,7 +562,7 @@ public class OffloadControllerTest { when(mHardware.setUpstreamParameters(any(), any(), any(), any())).thenReturn(false); lp.setInterfaceName(ethernetIface); offload.setUpstreamLinkProperties(lp); - provider.setInterfaceQuota(mobileIface, mobileLimit); + provider.setLimit(mobileIface, mobileLimit); waitForIdle(); inOrder.verify(mHardware, never()).setDataLimit(anyString(), anyLong()); @@ -535,7 +571,7 @@ public class OffloadControllerTest { when(mHardware.setDataLimit(anyString(), anyLong())).thenReturn(false); lp.setInterfaceName(mobileIface); offload.setUpstreamLinkProperties(lp); - provider.setInterfaceQuota(mobileIface, mobileLimit); + provider.setLimit(mobileIface, mobileLimit); waitForIdle(); inOrder.verify(mHardware).getForwardedStats(ethernetIface); inOrder.verify(mHardware).stopOffloadControl(); @@ -551,7 +587,7 @@ public class OffloadControllerTest { OffloadHardwareInterface.ControlCallback callback = mControlCallbackCaptor.getValue(); callback.onStoppedLimitReached(); - verify(mNMService, times(1)).tetherLimitReached(mTetherStatsProviderCaptor.getValue()); + verify(mTetherStatsProviderCb, times(1)).onStatsUpdated(anyInt(), any(), any()); } @Test @@ -654,9 +690,10 @@ public class OffloadControllerTest { // Verify forwarded stats behaviour. verify(mHardware, times(1)).getForwardedStats(eq(RMNET0)); verify(mHardware, times(1)).getForwardedStats(eq(WLAN0)); + // TODO: verify the exact stats reported. + verify(mTetherStatsProviderCb, times(1)).onStatsUpdated(anyInt(), any(), any()); + verifyNoMoreInteractions(mTetherStatsProviderCb); verifyNoMoreInteractions(mHardware); - verify(mNMService, times(1)).tetherLimitReached(mTetherStatsProviderCaptor.getValue()); - verifyNoMoreInteractions(mNMService); } @Test @@ -719,8 +756,8 @@ public class OffloadControllerTest { // Verify forwarded stats behaviour. verify(mHardware, times(1)).getForwardedStats(eq(RMNET0)); verify(mHardware, times(1)).getForwardedStats(eq(WLAN0)); - verify(mNMService, times(1)).tetherLimitReached(mTetherStatsProviderCaptor.getValue()); - verifyNoMoreInteractions(mNMService); + verify(mTetherStatsProviderCb, times(1)).onStatsUpdated(anyInt(), any(), any()); + verifyNoMoreInteractions(mTetherStatsProviderCb); // TODO: verify local prefixes and downstreams are also pushed to the HAL. verify(mHardware, times(1)).setLocalPrefixes(mStringArrayCaptor.capture()); diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java index ef97ad418245..3635964dd6a6 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringConfigurationTest.java @@ -26,13 +26,6 @@ import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; -import static com.android.internal.R.array.config_mobile_hotspot_provision_app; -import static com.android.internal.R.array.config_tether_bluetooth_regexs; -import static com.android.internal.R.array.config_tether_dhcp_range; -import static com.android.internal.R.array.config_tether_upstream_types; -import static com.android.internal.R.array.config_tether_usb_regexs; -import static com.android.internal.R.array.config_tether_wifi_regexs; -import static com.android.networkstack.tethering.R.bool.config_tether_enable_legacy_dhcp_server; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -51,6 +44,7 @@ import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.internal.util.test.BroadcastInterceptingContext; +import com.android.networkstack.tethering.R; import org.junit.After; import org.junit.Before; @@ -120,15 +114,18 @@ public class TetheringConfigurationTest { () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY), eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean())); - when(mResources.getStringArray(config_tether_dhcp_range)).thenReturn(new String[0]); - when(mResources.getStringArray(config_tether_usb_regexs)).thenReturn(new String[0]); - when(mResources.getStringArray(config_tether_wifi_regexs)) + when(mResources.getStringArray(R.array.config_tether_dhcp_range)).thenReturn( + new String[0]); + when(mResources.getStringArray(R.array.config_tether_usb_regexs)).thenReturn(new String[0]); + when(mResources.getStringArray(R.array.config_tether_wifi_regexs)) .thenReturn(new String[]{ "test_wlan\\d" }); - when(mResources.getStringArray(config_tether_bluetooth_regexs)).thenReturn(new String[0]); - when(mResources.getIntArray(config_tether_upstream_types)).thenReturn(new int[0]); - when(mResources.getStringArray(config_mobile_hotspot_provision_app)) + when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs)).thenReturn( + new String[0]); + when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[0]); + when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app)) .thenReturn(new String[0]); - when(mResources.getBoolean(config_tether_enable_legacy_dhcp_server)).thenReturn(false); + when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( + false); mHasTelephonyManager = true; mMockContext = new MockContext(mContext); mEnableLegacyDhcpServer = false; @@ -140,7 +137,7 @@ public class TetheringConfigurationTest { } private TetheringConfiguration getTetheringConfiguration(int... legacyTetherUpstreamTypes) { - when(mResources.getIntArray(config_tether_upstream_types)).thenReturn( + when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn( legacyTetherUpstreamTypes); return new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); } @@ -224,7 +221,7 @@ public class TetheringConfigurationTest { @Test public void testNoDefinedUpstreamTypesAddsEthernet() { - when(mResources.getIntArray(config_tether_upstream_types)).thenReturn(new int[]{}); + when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[]{}); when(mTelephonyManager.isTetheringApnRequired()).thenReturn(false); final TetheringConfiguration cfg = new TetheringConfiguration( @@ -246,7 +243,7 @@ public class TetheringConfigurationTest { @Test public void testDefinedUpstreamTypesSansEthernetAddsEthernet() { - when(mResources.getIntArray(config_tether_upstream_types)).thenReturn( + when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn( new int[]{TYPE_WIFI, TYPE_MOBILE_HIPRI}); when(mTelephonyManager.isTetheringApnRequired()).thenReturn(false); @@ -264,7 +261,7 @@ public class TetheringConfigurationTest { @Test public void testDefinedUpstreamTypesWithEthernetDoesNotAddEthernet() { - when(mResources.getIntArray(config_tether_upstream_types)) + when(mResources.getIntArray(R.array.config_tether_upstream_types)) .thenReturn(new int[]{TYPE_WIFI, TYPE_ETHERNET, TYPE_MOBILE_HIPRI}); when(mTelephonyManager.isTetheringApnRequired()).thenReturn(false); @@ -282,7 +279,8 @@ public class TetheringConfigurationTest { @Test public void testNewDhcpServerDisabled() { - when(mResources.getBoolean(config_tether_enable_legacy_dhcp_server)).thenReturn(true); + when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( + true); doReturn(false).when( () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY), eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean())); @@ -291,7 +289,8 @@ public class TetheringConfigurationTest { new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID); assertTrue(enableByRes.enableLegacyDhcpServer); - when(mResources.getBoolean(config_tether_enable_legacy_dhcp_server)).thenReturn(false); + when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( + false); doReturn(true).when( () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY), eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean())); @@ -303,7 +302,8 @@ public class TetheringConfigurationTest { @Test public void testNewDhcpServerEnabled() { - when(mResources.getBoolean(config_tether_enable_legacy_dhcp_server)).thenReturn(false); + when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( + false); doReturn(false).when( () -> DeviceConfig.getBoolean(eq(NAMESPACE_CONNECTIVITY), eq(TetheringConfiguration.TETHER_ENABLE_LEGACY_DHCP_SERVER), anyBoolean())); @@ -329,16 +329,17 @@ public class TetheringConfigurationTest { private void setUpResourceForSubId() { when(mResourcesForSubId.getStringArray( - config_tether_dhcp_range)).thenReturn(new String[0]); + R.array.config_tether_dhcp_range)).thenReturn(new String[0]); when(mResourcesForSubId.getStringArray( - config_tether_usb_regexs)).thenReturn(new String[0]); + R.array.config_tether_usb_regexs)).thenReturn(new String[0]); when(mResourcesForSubId.getStringArray( - config_tether_wifi_regexs)).thenReturn(new String[]{ "test_wlan\\d" }); + R.array.config_tether_wifi_regexs)).thenReturn(new String[]{ "test_wlan\\d" }); when(mResourcesForSubId.getStringArray( - config_tether_bluetooth_regexs)).thenReturn(new String[0]); - when(mResourcesForSubId.getIntArray(config_tether_upstream_types)).thenReturn(new int[0]); + R.array.config_tether_bluetooth_regexs)).thenReturn(new String[0]); + when(mResourcesForSubId.getIntArray(R.array.config_tether_upstream_types)).thenReturn( + new int[0]); when(mResourcesForSubId.getStringArray( - config_mobile_hotspot_provision_app)).thenReturn(PROVISIONING_APP_NAME); + R.array.config_mobile_hotspot_provision_app)).thenReturn(PROVISIONING_APP_NAME); } } diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java index 0df32fd9f35b..affd69154b70 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java @@ -19,6 +19,9 @@ package com.android.server.connectivity.tethering; import static android.hardware.usb.UsbManager.USB_CONFIGURED; import static android.hardware.usb.UsbManager.USB_CONNECTED; import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS; +import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED; +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED; +import static android.net.ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED; import static android.net.RouteInfo.RTN_UNICAST; import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED; import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY; @@ -37,8 +40,6 @@ import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED; import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; -import static com.android.networkstack.tethering.R.bool.config_tether_enable_legacy_dhcp_server; - import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -53,6 +54,7 @@ import static org.mockito.Mockito.any; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; @@ -60,6 +62,8 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import android.app.usage.NetworkStatsManager; +import android.bluetooth.BluetoothAdapter; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -68,9 +72,8 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.res.Resources; import android.hardware.usb.UsbManager; +import android.net.ConnectivityManager; import android.net.INetd; -import android.net.INetworkPolicyManager; -import android.net.INetworkStatsService; import android.net.ITetheringEventCallback; import android.net.InetAddresses; import android.net.InterfaceConfigurationParcel; @@ -99,7 +102,6 @@ import android.net.wifi.p2p.WifiP2pInfo; import android.net.wifi.p2p.WifiP2pManager; import android.os.Bundle; import android.os.Handler; -import android.os.INetworkManagementService; import android.os.Looper; import android.os.PersistableBundle; import android.os.RemoteException; @@ -120,6 +122,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.StateMachine; import com.android.internal.util.test.BroadcastInterceptingContext; import com.android.internal.util.test.FakeSettingsProvider; +import com.android.networkstack.tethering.R; import org.junit.After; import org.junit.Before; @@ -133,6 +136,7 @@ import java.net.Inet4Address; import java.net.Inet6Address; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Vector; @RunWith(AndroidJUnit4.class) @@ -151,9 +155,7 @@ public class TetheringTest { @Mock private ApplicationInfo mApplicationInfo; @Mock private Context mContext; - @Mock private INetworkManagementService mNMService; - @Mock private INetworkStatsService mStatsService; - @Mock private INetworkPolicyManager mPolicyManager; + @Mock private NetworkStatsManager mStatsManager; @Mock private OffloadHardwareInterface mOffloadHardwareInterface; @Mock private Resources mResources; @Mock private TelephonyManager mTelephonyManager; @@ -167,6 +169,7 @@ public class TetheringTest { @Mock private INetd mNetd; @Mock private UserManager mUserManager; @Mock private NetworkRequest mNetworkRequest; + @Mock private ConnectivityManager mCm; private final MockIpServerDependencies mIpServerDependencies = spy(new MockIpServerDependencies()); @@ -217,6 +220,8 @@ public class TetheringTest { if (Context.USB_SERVICE.equals(name)) return mUsbManager; if (Context.TELEPHONY_SERVICE.equals(name)) return mTelephonyManager; if (Context.USER_SERVICE.equals(name)) return mUserManager; + if (Context.NETWORK_STATS_SERVICE.equals(name)) return mStatsManager; + if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm; return super.getSystemService(name); } @@ -334,21 +339,6 @@ public class TetheringTest { } @Override - public INetworkManagementService getINetworkManagementService() { - return mNMService; - } - - @Override - public INetworkStatsService getINetworkStatsService() { - return mStatsService; - } - - @Override - public INetworkPolicyManager getINetworkPolicyManager() { - return mPolicyManager; - } - - @Override public INetd getINetd(Context context) { return mNetd; } @@ -362,6 +352,12 @@ public class TetheringTest { public Context getContext() { return mServiceContext; } + + @Override + public BluetoothAdapter getBluetoothAdapter() { + // TODO: add test for bluetooth tethering. + return null; + } } private static UpstreamNetworkState buildMobileUpstreamState(boolean withIPv4, @@ -420,24 +416,24 @@ public class TetheringTest { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - when(mResources.getStringArray(com.android.internal.R.array.config_tether_dhcp_range)) + when(mResources.getStringArray(R.array.config_tether_dhcp_range)) .thenReturn(new String[0]); - when(mResources.getStringArray(com.android.internal.R.array.config_tether_usb_regexs)) + when(mResources.getStringArray(R.array.config_tether_usb_regexs)) .thenReturn(new String[] { "test_rndis\\d" }); - when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_regexs)) + when(mResources.getStringArray(R.array.config_tether_wifi_regexs)) .thenReturn(new String[]{ "test_wlan\\d" }); - when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_p2p_regexs)) + when(mResources.getStringArray(R.array.config_tether_wifi_p2p_regexs)) .thenReturn(new String[]{ "test_p2p-p2p\\d-.*" }); - when(mResources.getStringArray(com.android.internal.R.array.config_tether_bluetooth_regexs)) + when(mResources.getStringArray(R.array.config_tether_bluetooth_regexs)) .thenReturn(new String[0]); - when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types)) - .thenReturn(new int[0]); - when(mResources.getBoolean(com.android.internal.R.bool.config_tether_upstream_automatic)) - .thenReturn(false); - when(mResources.getBoolean(config_tether_enable_legacy_dhcp_server)).thenReturn(false); + when(mResources.getIntArray(R.array.config_tether_upstream_types)).thenReturn(new int[0]); + when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)).thenReturn(false); + when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( + false); when(mNetd.interfaceGetList()) .thenReturn(new String[] { TEST_MOBILE_IFNAME, TEST_WLAN_IFNAME, TEST_USB_IFNAME, TEST_P2P_IFNAME}); + when(mResources.getString(R.string.config_wifi_tether_enable)).thenReturn(""); mInterfaceConfiguration = new InterfaceConfigurationParcel(); mInterfaceConfiguration.flags = new String[0]; when(mRouterAdvertisementDaemon.start()) @@ -457,7 +453,7 @@ public class TetheringTest { mServiceContext.registerReceiver(mBroadcastReceiver, new IntentFilter(ACTION_TETHER_STATE_CHANGED)); mTethering = makeTethering(); - verify(mNMService).registerTetheringStatsProvider(any(), anyString()); + verify(mStatsManager, times(1)).registerNetworkStatsProvider(anyString(), any()); verify(mNetd).registerUnsolicitedEventListener(any()); final ArgumentCaptor<PhoneStateListener> phoneListenerCaptor = ArgumentCaptor.forClass(PhoneStateListener.class); @@ -497,17 +493,21 @@ public class TetheringTest { private void sendWifiP2pConnectionChanged( boolean isGroupFormed, boolean isGroupOwner, String ifname) { + WifiP2pGroup group = null; WifiP2pInfo p2pInfo = new WifiP2pInfo(); p2pInfo.groupFormed = isGroupFormed; - p2pInfo.isGroupOwner = isGroupOwner; + if (isGroupFormed) { + p2pInfo.isGroupOwner = isGroupOwner; + group = mock(WifiP2pGroup.class); + when(group.isGroupOwner()).thenReturn(isGroupOwner); + when(group.getInterface()).thenReturn(ifname); + } - WifiP2pGroup group = new WifiP2pGroup(); - group.setIsGroupOwner(isGroupOwner); - group.setInterface(ifname); + final Intent intent = mock(Intent.class); + when(intent.getAction()).thenReturn(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); + when(intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO)).thenReturn(p2pInfo); + when(intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP)).thenReturn(group); - final Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); - intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, p2pInfo); - intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, group); mServiceContext.sendBroadcastAsUserMultiplePermissions(intent, UserHandle.ALL, P2P_RECEIVER_PERMISSIONS_FOR_BROADCAST); } @@ -698,7 +698,8 @@ public class TetheringTest { @Test public void workingMobileUsbTethering_IPv4LegacyDhcp() { - when(mResources.getBoolean(config_tether_enable_legacy_dhcp_server)).thenReturn(true); + when(mResources.getBoolean(R.bool.config_tether_enable_legacy_dhcp_server)).thenReturn( + true); sendConfigurationChanged(); final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState(); runUsbTethering(upstreamState); @@ -786,8 +787,7 @@ public class TetheringTest { @Test public void configTetherUpstreamAutomaticIgnoresConfigTetherUpstreamTypes() throws Exception { - when(mResources.getBoolean(com.android.internal.R.bool.config_tether_upstream_automatic)) - .thenReturn(true); + when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)).thenReturn(true); sendConfigurationChanged(); // Setup IPv6 @@ -1315,7 +1315,7 @@ public class TetheringTest { private void workingWifiP2pGroupOwnerLegacyMode( boolean emulateInterfaceStatusChanged) throws Exception { // change to legacy mode and update tethering information by chaning SIM - when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_p2p_regexs)) + when(mResources.getStringArray(R.array.config_tether_wifi_p2p_regexs)) .thenReturn(new String[]{}); final int fakeSubId = 1234; mPhoneStateListener.onActiveDataSubscriptionIdChanged(fakeSubId); @@ -1353,6 +1353,50 @@ public class TetheringTest { workingWifiP2pGroupClient(false); } + private void setDataSaverEnabled(boolean enabled) { + final Intent intent = new Intent(ACTION_RESTRICT_BACKGROUND_CHANGED); + mServiceContext.sendBroadcastAsUser(intent, UserHandle.ALL); + + final int status = enabled ? RESTRICT_BACKGROUND_STATUS_ENABLED + : RESTRICT_BACKGROUND_STATUS_DISABLED; + when(mCm.getRestrictBackgroundStatus()).thenReturn(status); + mLooper.dispatchAll(); + } + + @Test + public void testDataSaverChanged() { + // Start Tethering. + final UpstreamNetworkState upstreamState = buildMobileIPv4UpstreamState(); + runUsbTethering(upstreamState); + assertContains(Arrays.asList(mTethering.getTetheredIfaces()), TEST_USB_IFNAME); + // Data saver is ON. + setDataSaverEnabled(true); + // Verify that tethering should be disabled. + verify(mUsbManager, times(1)).setCurrentFunctions(UsbManager.FUNCTION_NONE); + mTethering.interfaceRemoved(TEST_USB_IFNAME); + mLooper.dispatchAll(); + assertEquals(mTethering.getTetheredIfaces(), new String[0]); + reset(mUsbManager); + + runUsbTethering(upstreamState); + // Verify that user can start tethering again without turning OFF data saver. + assertContains(Arrays.asList(mTethering.getTetheredIfaces()), TEST_USB_IFNAME); + + // If data saver is keep ON with change event, tethering should not be OFF this time. + setDataSaverEnabled(true); + verify(mUsbManager, times(0)).setCurrentFunctions(UsbManager.FUNCTION_NONE); + assertContains(Arrays.asList(mTethering.getTetheredIfaces()), TEST_USB_IFNAME); + + // If data saver is turned OFF, it should not change tethering. + setDataSaverEnabled(false); + verify(mUsbManager, times(0)).setCurrentFunctions(UsbManager.FUNCTION_NONE); + assertContains(Arrays.asList(mTethering.getTetheredIfaces()), TEST_USB_IFNAME); + } + + private static <T> void assertContains(Collection<T> collection, T element) { + assertTrue(element + " not found in " + collection, collection.contains(element)); + } + // TODO: Test that a request for hotspot mode doesn't interfere with an // already operating tethering mode interface. } diff --git a/packages/WAPPushManager/Android.bp b/packages/WAPPushManager/Android.bp index c3913698022d..083dac944936 100644 --- a/packages/WAPPushManager/Android.bp +++ b/packages/WAPPushManager/Android.bp @@ -10,5 +10,5 @@ android_app { proguard_flags_files: ["proguard.flags"], }, - product_specific: true, + system_ext_specific: true, } diff --git a/packages/WAPPushManager/CleanSpec.mk b/packages/WAPPushManager/CleanSpec.mk index 2dcbb1034622..f4e316c56bbf 100644 --- a/packages/WAPPushManager/CleanSpec.mk +++ b/packages/WAPPushManager/CleanSpec.mk @@ -49,3 +49,5 @@ # ************************************************ $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/app/WAPPushManager) +$(call add-clean-step, rm -rf $(TARGET_OUT_PRODUCT)/app/WAPPushManager) + diff --git a/packages/WallpaperCropper/Android.bp b/packages/WallpaperCropper/Android.bp index 40c423520081..ac38b271395c 100644 --- a/packages/WallpaperCropper/Android.bp +++ b/packages/WallpaperCropper/Android.bp @@ -3,7 +3,7 @@ android_app { srcs: ["src/**/*.java"], platform_apis: true, certificate: "platform", - product_specific: true, + system_ext_specific: true, privileged: true, optimize: { proguard_flags_files: ["proguard.flags"], diff --git a/packages/WallpaperCropper/CleanSpec.mk b/packages/WallpaperCropper/CleanSpec.mk index e6d8d5a774f1..f08c3430756a 100644 --- a/packages/WallpaperCropper/CleanSpec.mk +++ b/packages/WallpaperCropper/CleanSpec.mk @@ -44,6 +44,7 @@ #$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) #$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) $(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/priv-app/WallpaperCropper) +$(call add-clean-step, rm -rf $(TARGET_OUT_PRODUCT)/priv-app/WallpaperCropper) # ************************************************ # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST diff --git a/rs/java/android/renderscript/BaseObj.java b/rs/java/android/renderscript/BaseObj.java index b7e05d9c984c..7b5514b8a0d1 100644 --- a/rs/java/android/renderscript/BaseObj.java +++ b/rs/java/android/renderscript/BaseObj.java @@ -16,8 +16,10 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import dalvik.system.CloseGuard; + import java.util.concurrent.locks.ReentrantReadWriteLock; /** diff --git a/rs/java/android/renderscript/Element.java b/rs/java/android/renderscript/Element.java index b8eb3a1d7a40..0941907d35f8 100644 --- a/rs/java/android/renderscript/Element.java +++ b/rs/java/android/renderscript/Element.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * <p>An Element represents one item within an {@link diff --git a/rs/java/android/renderscript/FileA3D.java b/rs/java/android/renderscript/FileA3D.java index 9a6b0bcd4544..7cc2825ae565 100644 --- a/rs/java/android/renderscript/FileA3D.java +++ b/rs/java/android/renderscript/FileA3D.java @@ -16,13 +16,13 @@ package android.renderscript; -import java.io.File; -import java.io.InputStream; - -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.AssetManager; import android.content.res.Resources; +import java.io.File; +import java.io.InputStream; + /** * @hide * @deprecated in API 16 diff --git a/rs/java/android/renderscript/Font.java b/rs/java/android/renderscript/Font.java index 583350e91795..df9d8019f28d 100644 --- a/rs/java/android/renderscript/Font.java +++ b/rs/java/android/renderscript/Font.java @@ -16,17 +16,16 @@ package android.renderscript; +import android.compat.annotation.UnsupportedAppUsage; +import android.content.res.AssetManager; +import android.content.res.Resources; +import android.os.Environment; + import java.io.File; import java.io.InputStream; import java.util.HashMap; import java.util.Map; -import android.os.Environment; - -import android.annotation.UnsupportedAppUsage; -import android.content.res.AssetManager; -import android.content.res.Resources; - /** * @hide * @deprecated in API 16 diff --git a/rs/java/android/renderscript/Matrix4f.java b/rs/java/android/renderscript/Matrix4f.java index 026c9fbd7d5e..a9469c979494 100644 --- a/rs/java/android/renderscript/Matrix4f.java +++ b/rs/java/android/renderscript/Matrix4f.java @@ -16,8 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; -import java.lang.Math; +import android.compat.annotation.UnsupportedAppUsage; /** diff --git a/rs/java/android/renderscript/Mesh.java b/rs/java/android/renderscript/Mesh.java index 5321dcb957dc..826225a70d86 100644 --- a/rs/java/android/renderscript/Mesh.java +++ b/rs/java/android/renderscript/Mesh.java @@ -16,7 +16,8 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import java.util.Vector; /** diff --git a/rs/java/android/renderscript/Program.java b/rs/java/android/renderscript/Program.java index e28d646f5f1c..ff072183e927 100644 --- a/rs/java/android/renderscript/Program.java +++ b/rs/java/android/renderscript/Program.java @@ -17,14 +17,14 @@ package android.renderscript; +import android.compat.annotation.UnsupportedAppUsage; +import android.content.res.Resources; +import android.util.Log; + import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; -import android.annotation.UnsupportedAppUsage; -import android.content.res.Resources; -import android.util.Log; - /** * @hide diff --git a/rs/java/android/renderscript/ProgramFragment.java b/rs/java/android/renderscript/ProgramFragment.java index 3dde9b6d6400..880531207b4d 100644 --- a/rs/java/android/renderscript/ProgramFragment.java +++ b/rs/java/android/renderscript/ProgramFragment.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** diff --git a/rs/java/android/renderscript/ProgramFragmentFixedFunction.java b/rs/java/android/renderscript/ProgramFragmentFixedFunction.java index d05d41da8b6f..c741ce6e77ed 100644 --- a/rs/java/android/renderscript/ProgramFragmentFixedFunction.java +++ b/rs/java/android/renderscript/ProgramFragmentFixedFunction.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** diff --git a/rs/java/android/renderscript/ProgramRaster.java b/rs/java/android/renderscript/ProgramRaster.java index 33000acb4eb0..a21696c82161 100644 --- a/rs/java/android/renderscript/ProgramRaster.java +++ b/rs/java/android/renderscript/ProgramRaster.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** diff --git a/rs/java/android/renderscript/ProgramStore.java b/rs/java/android/renderscript/ProgramStore.java index 622fe21be47a..7e61347ee218 100644 --- a/rs/java/android/renderscript/ProgramStore.java +++ b/rs/java/android/renderscript/ProgramStore.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** diff --git a/rs/java/android/renderscript/ProgramVertex.java b/rs/java/android/renderscript/ProgramVertex.java index 83d9ea7be645..9257234de42c 100644 --- a/rs/java/android/renderscript/ProgramVertex.java +++ b/rs/java/android/renderscript/ProgramVertex.java @@ -38,7 +38,7 @@ **/ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** diff --git a/rs/java/android/renderscript/ProgramVertexFixedFunction.java b/rs/java/android/renderscript/ProgramVertexFixedFunction.java index 579d3bb507e8..03c2eaf91242 100644 --- a/rs/java/android/renderscript/ProgramVertexFixedFunction.java +++ b/rs/java/android/renderscript/ProgramVertexFixedFunction.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** diff --git a/rs/java/android/renderscript/RSSurfaceView.java b/rs/java/android/renderscript/RSSurfaceView.java index 561373cef625..6bdde387b334 100644 --- a/rs/java/android/renderscript/RSSurfaceView.java +++ b/rs/java/android/renderscript/RSSurfaceView.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.util.AttributeSet; import android.view.SurfaceHolder; diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java index f4c27771c846..46c49e5a5e11 100644 --- a/rs/java/android/renderscript/RenderScript.java +++ b/rs/java/android/renderscript/RenderScript.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.res.AssetManager; import android.graphics.Bitmap; diff --git a/rs/java/android/renderscript/RenderScriptCacheDir.java b/rs/java/android/renderscript/RenderScriptCacheDir.java index 1797bef4be8d..862d032d6987 100644 --- a/rs/java/android/renderscript/RenderScriptCacheDir.java +++ b/rs/java/android/renderscript/RenderScriptCacheDir.java @@ -16,7 +16,8 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; + import java.io.File; /** diff --git a/rs/java/android/renderscript/RenderScriptGL.java b/rs/java/android/renderscript/RenderScriptGL.java index 6fac83e8c4a8..dafaf367364d 100644 --- a/rs/java/android/renderscript/RenderScriptGL.java +++ b/rs/java/android/renderscript/RenderScriptGL.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.graphics.SurfaceTexture; import android.view.Surface; diff --git a/rs/java/android/renderscript/Script.java b/rs/java/android/renderscript/Script.java index 9ad9aea9d7aa..d1d3a7642382 100644 --- a/rs/java/android/renderscript/Script.java +++ b/rs/java/android/renderscript/Script.java @@ -16,7 +16,7 @@ package android.renderscript; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.util.SparseArray; /** diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 657207237bf0..29f9e58a5d8a 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -88,7 +88,6 @@ import android.net.Network; import android.net.NetworkAgent; import android.net.NetworkCapabilities; import android.net.NetworkConfig; -import android.net.NetworkFactory; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkMisc; @@ -2835,26 +2834,11 @@ public class ConnectivityService extends IConnectivityManager.Stub return true; } - // TODO: delete when direct use of registerNetworkFactory is no longer supported. - private boolean maybeHandleNetworkFactoryMessage(Message msg) { - switch (msg.what) { - default: - return false; - case NetworkFactory.EVENT_UNFULFILLABLE_REQUEST: { - handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.sendingUid, - /* callOnUnavailable */ true); - break; - } - } - return true; - } - @Override public void handleMessage(Message msg) { if (!maybeHandleAsyncChannelMessage(msg) && !maybeHandleNetworkMonitorMessage(msg) - && !maybeHandleNetworkAgentInfoMessage(msg) - && !maybeHandleNetworkFactoryMessage(msg)) { + && !maybeHandleNetworkAgentInfoMessage(msg)) { maybeHandleNetworkAgentMessage(msg); } } @@ -5496,7 +5480,10 @@ public class ConnectivityService extends IConnectivityManager.Stub // changes that would conflict throughout the automerger graph. Having this method temporarily // helps with the process of going through with all these dependent changes across the entire // tree. - public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, + /** + * Register a new agent. {@see #registerNetworkAgent} below. + */ + public Network registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, int currentScore, NetworkMisc networkMisc) { return registerNetworkAgent(messenger, networkInfo, linkProperties, networkCapabilities, @@ -5517,8 +5504,9 @@ public class ConnectivityService extends IConnectivityManager.Stub * {@link NetworkAgentInfo#getCurrentScore}. * @param networkMisc metadata about the network. This is never updated. * @param providerId the ID of the provider owning this NetworkAgent. + * @return the network created for this agent. */ - public int registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, + public Network registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, int currentScore, NetworkMisc networkMisc, int providerId) { enforceNetworkFactoryPermission(); @@ -5551,7 +5539,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // If the network disconnects or sends any other event before that, messages are deferred by // NetworkAgent until nai.asyncChannel.connect(), which will be called when finalizing the // registration. - return nai.network.netId; + return nai.network; } private void handleRegisterNetworkAgent(NetworkAgentInfo nai, INetworkMonitor networkMonitor) { @@ -5803,6 +5791,19 @@ public class ConnectivityService extends IConnectivityManager.Stub return INetd.PERMISSION_NONE; } + private void updateNetworkPermissions(@NonNull final NetworkAgentInfo nai, + @NonNull final NetworkCapabilities newNc) { + final int oldPermission = getNetworkPermission(nai.networkCapabilities); + final int newPermission = getNetworkPermission(newNc); + if (oldPermission != newPermission && nai.created && !nai.isVPN()) { + try { + mNMS.setNetworkPermission(nai.network.netId, newPermission); + } catch (RemoteException e) { + loge("Exception in setNetworkPermission: " + e); + } + } + } + /** * Augments the NetworkCapabilities passed in by a NetworkAgent with capabilities that are * maintained here that the NetworkAgent is not aware of (e.g., validated, captive portal, @@ -5874,21 +5875,11 @@ public class ConnectivityService extends IConnectivityManager.Stub * @param nai the network having its capabilities updated. * @param nc the new network capabilities. */ - private void updateCapabilities(int oldScore, NetworkAgentInfo nai, NetworkCapabilities nc) { + private void updateCapabilities(final int oldScore, @NonNull final NetworkAgentInfo nai, + @NonNull final NetworkCapabilities nc) { NetworkCapabilities newNc = mixInCapabilities(nai, nc); - if (Objects.equals(nai.networkCapabilities, newNc)) return; - - final int oldPermission = getNetworkPermission(nai.networkCapabilities); - final int newPermission = getNetworkPermission(newNc); - if (oldPermission != newPermission && nai.created && !nai.isVPN()) { - try { - mNMS.setNetworkPermission(nai.network.netId, newPermission); - } catch (RemoteException e) { - loge("Exception in setNetworkPermission: " + e); - } - } - + updateNetworkPermissions(nai, newNc); final NetworkCapabilities prevNc = nai.getAndSetNetworkCapabilities(newNc); updateUids(nai, prevNc, newNc); @@ -6253,6 +6244,30 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + // An accumulator class to gather the list of changes that result from a rematch. + // TODO : enrich to represent an entire set of changes to apply. + private static class NetworkReassignment { + static class NetworkBgStatePair { + @NonNull final NetworkAgentInfo mNetwork; + final boolean mOldBackground; + NetworkBgStatePair(@NonNull final NetworkAgentInfo network, + final boolean oldBackground) { + mNetwork = network; + mOldBackground = oldBackground; + } + } + + @NonNull private final Set<NetworkBgStatePair> mRematchedNetworks = new ArraySet<>(); + + @NonNull Iterable<NetworkBgStatePair> getRematchedNetworks() { + return mRematchedNetworks; + } + + void addRematchedNetwork(@NonNull final NetworkBgStatePair network) { + mRematchedNetworks.add(network); + } + } + private ArrayMap<NetworkRequestInfo, NetworkAgentInfo> computeRequestReassignmentForNetwork( @NonNull final NetworkAgentInfo newNetwork) { final int score = newNetwork.getCurrentScore(); @@ -6298,8 +6313,8 @@ public class ConnectivityService extends IConnectivityManager.Stub // needed. A network is needed if it is the best network for // one or more NetworkRequests, or if it is a VPN. // - // - Tears down newNetwork if it just became validated - // but turns out to be unneeded. + // - Writes into the passed reassignment object all changes that should be done for + // rematching this network with all requests, to be applied later. // // NOTE: This function only adds NetworkRequests that "newNetwork" could satisfy, // it does not remove NetworkRequests that other Networks could better satisfy. @@ -6307,15 +6322,22 @@ public class ConnectivityService extends IConnectivityManager.Stub // This function should be used when possible instead of {@code rematchAllNetworksAndRequests} // as it performs better by a factor of the number of Networks. // + // TODO : stop writing to the passed reassignment. This is temporarily more useful, but + // it's unidiomatic Java and it's hard to read. + // + // @param changes a currently-building list of changes to write to // @param newNetwork is the network to be matched against NetworkRequests. // @param now the time the rematch starts, as returned by SystemClock.elapsedRealtime(); - private void rematchNetworkAndRequests(NetworkAgentInfo newNetwork, long now) { + private void rematchNetworkAndRequests(@NonNull final NetworkReassignment changes, + @NonNull final NetworkAgentInfo newNetwork, final long now) { ensureRunningOnConnectivityServiceThread(); if (!newNetwork.everConnected) return; boolean isNewDefault = false; NetworkAgentInfo oldDefaultNetwork = null; - final boolean wasBackgroundNetwork = newNetwork.isBackgroundNetwork(); + changes.addRematchedNetwork(new NetworkReassignment.NetworkBgStatePair(newNetwork, + newNetwork.isBackgroundNetwork())); + final int score = newNetwork.getCurrentScore(); if (VDBG || DDBG) log("rematching " + newNetwork.name()); @@ -6418,39 +6440,12 @@ public class ConnectivityService extends IConnectivityManager.Stub if (newNetwork.getCurrentScore() != score) { Slog.wtf(TAG, String.format( "BUG: %s changed score during rematch: %d -> %d", - newNetwork.name(), score, newNetwork.getCurrentScore())); + newNetwork.name(), score, newNetwork.getCurrentScore())); } // Notify requested networks are available after the default net is switched, but // before LegacyTypeTracker sends legacy broadcasts for (NetworkRequestInfo nri : addedRequests) notifyNetworkAvailable(newNetwork, nri); - - // Finally, process listen requests and update capabilities if the background state has - // changed for this network. For consistency with previous behavior, send onLost callbacks - // before onAvailable. - processNewlyLostListenRequests(newNetwork); - - // Maybe the network changed background states. Update its capabilities. - final boolean backgroundChanged = wasBackgroundNetwork != newNetwork.isBackgroundNetwork(); - if (backgroundChanged) { - final NetworkCapabilities newNc = mixInCapabilities(newNetwork, - newNetwork.networkCapabilities); - - final int oldPermission = getNetworkPermission(newNetwork.networkCapabilities); - final int newPermission = getNetworkPermission(newNc); - if (oldPermission != newPermission) { - try { - mNMS.setNetworkPermission(newNetwork.network.netId, newPermission); - } catch (RemoteException e) { - loge("Exception in setNetworkPermission: " + e); - } - } - - newNetwork.getAndSetNetworkCapabilities(newNc); - notifyNetworkCallbacks(newNetwork, ConnectivityManager.CALLBACK_CAP_CHANGED); - } - - processNewlySatisfiedListenRequests(newNetwork); } /** @@ -6472,12 +6467,24 @@ public class ConnectivityService extends IConnectivityManager.Stub // scoring network and then a higher scoring network, which could produce multiple // callbacks. Arrays.sort(nais); + final NetworkReassignment changes = new NetworkReassignment(); for (final NetworkAgentInfo nai : nais) { - rematchNetworkAndRequests(nai, now); + rematchNetworkAndRequests(changes, nai, now); } final NetworkAgentInfo newDefaultNetwork = getDefaultNetwork(); + for (final NetworkReassignment.NetworkBgStatePair event : changes.getRematchedNetworks()) { + // Process listen requests and update capabilities if the background state has + // changed for this network. For consistency with previous behavior, send onLost + // callbacks before onAvailable. + processNewlyLostListenRequests(event.mNetwork); + if (event.mOldBackground != event.mNetwork.isBackgroundNetwork()) { + applyBackgroundChangeForRematch(event.mNetwork); + } + processNewlySatisfiedListenRequests(event.mNetwork); + } + for (final NetworkAgentInfo nai : nais) { // Rematching may have altered the linger state of some networks, so update all linger // timers. updateLingerState reads the state from the network agent and does nothing @@ -6509,6 +6516,24 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + /** + * Apply a change in background state resulting from rematching networks with requests. + * + * During rematch, a network may change background states by starting to satisfy or stopping + * to satisfy a foreground request. Listens don't count for this. When a network changes + * background states, its capabilities need to be updated and callbacks fired for the + * capability change. + * + * @param nai The network that changed background states + */ + private void applyBackgroundChangeForRematch(@NonNull final NetworkAgentInfo nai) { + final NetworkCapabilities newNc = mixInCapabilities(nai, nai.networkCapabilities); + if (Objects.equals(nai.networkCapabilities, newNc)) return; + updateNetworkPermissions(nai, newNc); + nai.getAndSetNetworkCapabilities(newNc); + notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED); + } + private void updateLegacyTypeTrackerAndVpnLockdownForRematch( @Nullable final NetworkAgentInfo oldDefaultNetwork, @Nullable final NetworkAgentInfo newDefaultNetwork, diff --git a/services/core/java/com/android/server/DynamicSystemService.java b/services/core/java/com/android/server/DynamicSystemService.java index 7909e3096cbe..c60460fccb76 100644 --- a/services/core/java/com/android/server/DynamicSystemService.java +++ b/services/core/java/com/android/server/DynamicSystemService.java @@ -44,9 +44,9 @@ public class DynamicSystemService extends IDynamicSystemService.Stub implements private static final String TAG = "DynamicSystemService"; private static final String NO_SERVICE_ERROR = "no gsiservice"; private static final int GSID_ROUGH_TIMEOUT_MS = 8192; - private static final String PATH_DEFAULT = "/data/gsi"; + private static final String PATH_DEFAULT = "/data/gsi/"; private Context mContext; - private String mInstallPath; + private String mInstallPath, mDsuSlot; private volatile IGsiService mGsiService; DynamicSystemService(Context context) { @@ -115,7 +115,7 @@ public class DynamicSystemService extends IDynamicSystemService.Stub implements } @Override - public boolean startInstallation() throws RemoteException { + public boolean startInstallation(String dsuSlot) throws RemoteException { IGsiService service = getGsiService(); // priority from high to low: sysprop -> sdcard -> /data String path = SystemProperties.get("os.aot.path"); @@ -129,16 +129,17 @@ public class DynamicSystemService extends IDynamicSystemService.Stub implements if (!Environment.MEDIA_MOUNTED.equals(volume.getState())) continue; File sdCard = volume.getPathFile(); if (sdCard.isDirectory()) { - path = sdCard.getPath(); + path = new File(sdCard, dsuSlot).getPath(); break; } } if (path.isEmpty()) { - path = PATH_DEFAULT; + path = PATH_DEFAULT + dsuSlot; } Slog.i(TAG, "startInstallation -> " + path); } mInstallPath = path; + mDsuSlot = dsuSlot; if (service.openInstall(path) != 0) { Slog.i(TAG, "Failed to open " + path); return false; @@ -203,7 +204,7 @@ public class DynamicSystemService extends IDynamicSystemService.Stub implements public boolean setEnable(boolean enable, boolean oneShot) throws RemoteException { IGsiService gsiService = getGsiService(); if (enable) { - return gsiService.enableGsi(oneShot) == 0; + return gsiService.enableGsi(oneShot, mDsuSlot) == 0; } else { return gsiService.disableGsi(); } diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java index 9a7a4e79ab33..2fb1f7783814 100644 --- a/services/core/java/com/android/server/NetworkScoreService.java +++ b/services/core/java/com/android/server/NetworkScoreService.java @@ -54,7 +54,6 @@ import android.provider.Settings.Global; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; -import android.util.IntArray; import android.util.Log; import com.android.internal.annotations.GuardedBy; @@ -527,7 +526,7 @@ public class NetworkScoreService extends INetworkScoreService.Stub { @Override public void accept(INetworkScoreCache networkScoreCache, Object cookie) { - int filterType = NetworkScoreManager.CACHE_FILTER_NONE; + int filterType = NetworkScoreManager.SCORE_FILTER_NONE; if (cookie instanceof Integer) { filterType = (Integer) cookie; } @@ -551,17 +550,17 @@ public class NetworkScoreService extends INetworkScoreService.Stub { private List<ScoredNetwork> filterScores(List<ScoredNetwork> scoredNetworkList, int filterType) { switch (filterType) { - case NetworkScoreManager.CACHE_FILTER_NONE: + case NetworkScoreManager.SCORE_FILTER_NONE: return scoredNetworkList; - case NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK: + case NetworkScoreManager.SCORE_FILTER_CURRENT_NETWORK: if (mCurrentNetworkFilter == null) { mCurrentNetworkFilter = new CurrentNetworkScoreCacheFilter(new WifiInfoSupplier(mContext)); } return mCurrentNetworkFilter.apply(scoredNetworkList); - case NetworkScoreManager.CACHE_FILTER_SCAN_RESULTS: + case NetworkScoreManager.SCORE_FILTER_SCAN_RESULTS: if (mScanResultsFilter == null) { mScanResultsFilter = new ScanResultsScoreCacheFilter( new ScanResultsSupplier(mContext)); diff --git a/services/core/java/com/android/server/NetworkTimeUpdateService.java b/services/core/java/com/android/server/NetworkTimeUpdateService.java index 1ff455ea7a8f..c34dd984f865 100644 --- a/services/core/java/com/android/server/NetworkTimeUpdateService.java +++ b/services/core/java/com/android/server/NetworkTimeUpdateService.java @@ -16,15 +16,273 @@ package com.android.server; -import android.os.IBinder; +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.app.timedetector.NetworkTimeSuggestion; +import android.app.timedetector.TimeDetector; +import android.content.BroadcastReceiver; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.database.ContentObserver; +import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; +import android.net.Network; +import android.os.Binder; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Looper; +import android.os.Message; +import android.os.PowerManager; +import android.os.SystemClock; +import android.os.TimestampedValue; +import android.provider.Settings; +import android.util.Log; +import android.util.NtpTrustedTime; +import android.util.TimeUtils; + +import com.android.internal.util.DumpUtils; + +import java.io.FileDescriptor; +import java.io.PrintWriter; /** - * An interface for NetworkTimeUpdateService implementations. Eventually part or all of this service - * will be subsumed into {@link com.android.server.timedetector.TimeDetectorService}. In the - * meantime this interface allows Android to use either the old or new implementation. + * Monitors the network time. If looking up the network time fails for some reason, it tries a few + * times with a short interval and then resets to checking on longer intervals. + * + * <p>When available, the time is always suggested to the {@link + * com.android.server.timedetector.TimeDetectorService} where it may be used to set the device + * system clock, depending on user settings and what other signals are available. */ -public interface NetworkTimeUpdateService extends IBinder { +public class NetworkTimeUpdateService extends Binder { + + private static final String TAG = "NetworkTimeUpdateService"; + private static final boolean DBG = false; + + private static final int EVENT_AUTO_TIME_ENABLED = 1; + private static final int EVENT_POLL_NETWORK_TIME = 2; + private static final int EVENT_NETWORK_CHANGED = 3; + + private static final String ACTION_POLL = + "com.android.server.NetworkTimeUpdateService.action.POLL"; + + private static final int POLL_REQUEST = 0; + + private Network mDefaultNetwork = null; + + private final Context mContext; + private final NtpTrustedTime mTime; + private final AlarmManager mAlarmManager; + private final TimeDetector mTimeDetector; + private final ConnectivityManager mCM; + private final PendingIntent mPendingPollIntent; + private final PowerManager.WakeLock mWakeLock; + + // NTP lookup is done on this thread and handler + private Handler mHandler; + private AutoTimeSettingObserver mAutoTimeSettingObserver; + private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback; + + // Normal polling frequency + private final long mPollingIntervalMs; + // Try-again polling interval, in case the network request failed + private final long mPollingIntervalShorterMs; + // Number of times to try again + private final int mTryAgainTimesMax; + // Keeps track of how many quick attempts were made to fetch NTP time. + // During bootup, the network may not have been up yet, or it's taking time for the + // connection to happen. + private int mTryAgainCounter; + + public NetworkTimeUpdateService(Context context) { + mContext = context; + mTime = NtpTrustedTime.getInstance(context); + mAlarmManager = mContext.getSystemService(AlarmManager.class); + mTimeDetector = mContext.getSystemService(TimeDetector.class); + mCM = mContext.getSystemService(ConnectivityManager.class); + + Intent pollIntent = new Intent(ACTION_POLL, null); + mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0); + + mPollingIntervalMs = mContext.getResources().getInteger( + com.android.internal.R.integer.config_ntpPollingInterval); + mPollingIntervalShorterMs = mContext.getResources().getInteger( + com.android.internal.R.integer.config_ntpPollingIntervalShorter); + mTryAgainTimesMax = mContext.getResources().getInteger( + com.android.internal.R.integer.config_ntpRetry); + + mWakeLock = context.getSystemService(PowerManager.class).newWakeLock( + PowerManager.PARTIAL_WAKE_LOCK, TAG); + } /** Initialize the receivers and initiate the first NTP request */ - void systemRunning(); + public void systemRunning() { + registerForAlarms(); + + HandlerThread thread = new HandlerThread(TAG); + thread.start(); + mHandler = new MyHandler(thread.getLooper()); + mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback(); + mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler); + + mAutoTimeSettingObserver = new AutoTimeSettingObserver(mContext, mHandler, + EVENT_AUTO_TIME_ENABLED); + mAutoTimeSettingObserver.observe(); + } + + private void registerForAlarms() { + mContext.registerReceiver( + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget(); + } + }, new IntentFilter(ACTION_POLL)); + } + + private void onPollNetworkTime(int event) { + // If we don't have any default network, don't bother. + if (mDefaultNetwork == null) return; + mWakeLock.acquire(); + try { + onPollNetworkTimeUnderWakeLock(event); + } finally { + mWakeLock.release(); + } + } + + private void onPollNetworkTimeUnderWakeLock(int event) { + // Force an NTP fix when outdated + NtpTrustedTime.TimeResult cachedNtpResult = mTime.getCachedTimeResult(); + if (cachedNtpResult == null || cachedNtpResult.getAgeMillis() >= mPollingIntervalMs) { + if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh"); + mTime.forceRefresh(); + cachedNtpResult = mTime.getCachedTimeResult(); + } + + if (cachedNtpResult != null && cachedNtpResult.getAgeMillis() < mPollingIntervalMs) { + // Obtained fresh fix; schedule next normal update + resetAlarm(mPollingIntervalMs); + + // Suggest the time to the time detector. It may choose use it to set the system clock. + TimestampedValue<Long> timeSignal = new TimestampedValue<>( + cachedNtpResult.getElapsedRealtimeMillis(), cachedNtpResult.getTimeMillis()); + NetworkTimeSuggestion timeSuggestion = new NetworkTimeSuggestion(timeSignal); + timeSuggestion.addDebugInfo("Origin: NetworkTimeUpdateService. event=" + event); + mTimeDetector.suggestNetworkTime(timeSuggestion); + } else { + // No fresh fix; schedule retry + mTryAgainCounter++; + if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) { + resetAlarm(mPollingIntervalShorterMs); + } else { + // Try much later + mTryAgainCounter = 0; + resetAlarm(mPollingIntervalMs); + } + } + } + + /** + * Cancel old alarm and starts a new one for the specified interval. + * + * @param interval when to trigger the alarm, starting from now. + */ + private void resetAlarm(long interval) { + mAlarmManager.cancel(mPendingPollIntent); + long now = SystemClock.elapsedRealtime(); + long next = now + interval; + mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent); + } + + /** Handler to do the network accesses on */ + private class MyHandler extends Handler { + + MyHandler(Looper l) { + super(l); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case EVENT_AUTO_TIME_ENABLED: + case EVENT_POLL_NETWORK_TIME: + case EVENT_NETWORK_CHANGED: + onPollNetworkTime(msg.what); + break; + } + } + } + + private class NetworkTimeUpdateCallback extends NetworkCallback { + @Override + public void onAvailable(Network network) { + Log.d(TAG, String.format("New default network %s; checking time.", network)); + mDefaultNetwork = network; + // Running on mHandler so invoke directly. + onPollNetworkTime(EVENT_NETWORK_CHANGED); + } + + @Override + public void onLost(Network network) { + if (network.equals(mDefaultNetwork)) mDefaultNetwork = null; + } + } + + /** + * Observer to watch for changes to the AUTO_TIME setting. It only triggers when the setting + * is enabled. + */ + private static class AutoTimeSettingObserver extends ContentObserver { + + private final Context mContext; + private final int mMsg; + private final Handler mHandler; + + AutoTimeSettingObserver(Context context, Handler handler, int msg) { + super(handler); + mContext = context; + mHandler = handler; + mMsg = msg; + } + + void observe() { + ContentResolver resolver = mContext.getContentResolver(); + resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME), + false, this); + } + + @Override + public void onChange(boolean selfChange) { + if (isAutomaticTimeEnabled()) { + mHandler.obtainMessage(mMsg).sendToTarget(); + } + } + + /** + * Checks if the user prefers to automatically set the time. + */ + private boolean isAutomaticTimeEnabled() { + ContentResolver resolver = mContext.getContentResolver(); + return Settings.Global.getInt(resolver, Settings.Global.AUTO_TIME, 0) != 0; + } + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; + pw.print("PollingIntervalMs: "); + TimeUtils.formatDuration(mPollingIntervalMs, pw); + pw.print("\nPollingIntervalShorterMs: "); + TimeUtils.formatDuration(mPollingIntervalShorterMs, pw); + pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax); + pw.println("\nTryAgainCounter: " + mTryAgainCounter); + NtpTrustedTime.TimeResult ntpResult = mTime.getCachedTimeResult(); + pw.println("NTP cache result: " + ntpResult); + if (ntpResult != null) { + pw.println("NTP result age: " + ntpResult.getAgeMillis()); + } + pw.println(); + } } diff --git a/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java b/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java deleted file mode 100644 index 7894788cb0b6..000000000000 --- a/services/core/java/com/android/server/NetworkTimeUpdateServiceImpl.java +++ /dev/null @@ -1,288 +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. - */ - -package com.android.server; - -import android.app.AlarmManager; -import android.app.PendingIntent; -import android.app.timedetector.NetworkTimeSuggestion; -import android.app.timedetector.TimeDetector; -import android.content.BroadcastReceiver; -import android.content.ContentResolver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.database.ContentObserver; -import android.net.ConnectivityManager; -import android.net.ConnectivityManager.NetworkCallback; -import android.net.Network; -import android.os.Binder; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.Looper; -import android.os.Message; -import android.os.PowerManager; -import android.os.SystemClock; -import android.os.TimestampedValue; -import android.provider.Settings; -import android.util.Log; -import android.util.NtpTrustedTime; -import android.util.TimeUtils; - -import com.android.internal.util.DumpUtils; - -import java.io.FileDescriptor; -import java.io.PrintWriter; - -/** - * Monitors the network time. If looking up the network time fails for some reason, it tries a few - * times with a short interval and then resets to checking on longer intervals. - * - * <p>When available, the time is always suggested to the {@link - * com.android.server.timedetector.TimeDetectorService} where it may be used to set the device - * system clock, depending on user settings and what other signals are available. - */ -public class NetworkTimeUpdateServiceImpl extends Binder implements NetworkTimeUpdateService { - - private static final String TAG = "NetworkTimeUpdateService"; - private static final boolean DBG = false; - - private static final int EVENT_AUTO_TIME_ENABLED = 1; - private static final int EVENT_POLL_NETWORK_TIME = 2; - private static final int EVENT_NETWORK_CHANGED = 3; - - private static final String ACTION_POLL = - "com.android.server.NetworkTimeUpdateService.action.POLL"; - - private static final int POLL_REQUEST = 0; - - private Network mDefaultNetwork = null; - - private final Context mContext; - private final NtpTrustedTime mTime; - private final AlarmManager mAlarmManager; - private final TimeDetector mTimeDetector; - private final ConnectivityManager mCM; - private final PendingIntent mPendingPollIntent; - private final PowerManager.WakeLock mWakeLock; - - // NTP lookup is done on this thread and handler - private Handler mHandler; - private AutoTimeSettingObserver mAutoTimeSettingObserver; - private NetworkTimeUpdateCallback mNetworkTimeUpdateCallback; - - // Normal polling frequency - private final long mPollingIntervalMs; - // Try-again polling interval, in case the network request failed - private final long mPollingIntervalShorterMs; - // Number of times to try again - private final int mTryAgainTimesMax; - // Keeps track of how many quick attempts were made to fetch NTP time. - // During bootup, the network may not have been up yet, or it's taking time for the - // connection to happen. - private int mTryAgainCounter; - - public NetworkTimeUpdateServiceImpl(Context context) { - mContext = context; - mTime = NtpTrustedTime.getInstance(context); - mAlarmManager = mContext.getSystemService(AlarmManager.class); - mTimeDetector = mContext.getSystemService(TimeDetector.class); - mCM = mContext.getSystemService(ConnectivityManager.class); - - Intent pollIntent = new Intent(ACTION_POLL, null); - mPendingPollIntent = PendingIntent.getBroadcast(mContext, POLL_REQUEST, pollIntent, 0); - - mPollingIntervalMs = mContext.getResources().getInteger( - com.android.internal.R.integer.config_ntpPollingInterval); - mPollingIntervalShorterMs = mContext.getResources().getInteger( - com.android.internal.R.integer.config_ntpPollingIntervalShorter); - mTryAgainTimesMax = mContext.getResources().getInteger( - com.android.internal.R.integer.config_ntpRetry); - - mWakeLock = context.getSystemService(PowerManager.class).newWakeLock( - PowerManager.PARTIAL_WAKE_LOCK, TAG); - } - - @Override - public void systemRunning() { - registerForAlarms(); - - HandlerThread thread = new HandlerThread(TAG); - thread.start(); - mHandler = new MyHandler(thread.getLooper()); - mNetworkTimeUpdateCallback = new NetworkTimeUpdateCallback(); - mCM.registerDefaultNetworkCallback(mNetworkTimeUpdateCallback, mHandler); - - mAutoTimeSettingObserver = new AutoTimeSettingObserver(mContext, mHandler, - EVENT_AUTO_TIME_ENABLED); - mAutoTimeSettingObserver.observe(); - } - - private void registerForAlarms() { - mContext.registerReceiver( - new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - mHandler.obtainMessage(EVENT_POLL_NETWORK_TIME).sendToTarget(); - } - }, new IntentFilter(ACTION_POLL)); - } - - private void onPollNetworkTime(int event) { - // If we don't have any default network, don't bother. - if (mDefaultNetwork == null) return; - mWakeLock.acquire(); - try { - onPollNetworkTimeUnderWakeLock(event); - } finally { - mWakeLock.release(); - } - } - - private void onPollNetworkTimeUnderWakeLock(int event) { - // Force an NTP fix when outdated - NtpTrustedTime.TimeResult cachedNtpResult = mTime.getCachedTimeResult(); - if (cachedNtpResult == null || cachedNtpResult.getAgeMillis() >= mPollingIntervalMs) { - if (DBG) Log.d(TAG, "Stale NTP fix; forcing refresh"); - mTime.forceRefresh(); - cachedNtpResult = mTime.getCachedTimeResult(); - } - - if (cachedNtpResult != null && cachedNtpResult.getAgeMillis() < mPollingIntervalMs) { - // Obtained fresh fix; schedule next normal update - resetAlarm(mPollingIntervalMs); - - // Suggest the time to the time detector. It may choose use it to set the system clock. - TimestampedValue<Long> timeSignal = new TimestampedValue<>( - cachedNtpResult.getElapsedRealtimeMillis(), cachedNtpResult.getTimeMillis()); - NetworkTimeSuggestion timeSuggestion = new NetworkTimeSuggestion(timeSignal); - timeSuggestion.addDebugInfo("Origin: NetworkTimeUpdateServiceImpl. event=" + event); - mTimeDetector.suggestNetworkTime(timeSuggestion); - } else { - // No fresh fix; schedule retry - mTryAgainCounter++; - if (mTryAgainTimesMax < 0 || mTryAgainCounter <= mTryAgainTimesMax) { - resetAlarm(mPollingIntervalShorterMs); - } else { - // Try much later - mTryAgainCounter = 0; - resetAlarm(mPollingIntervalMs); - } - } - } - - /** - * Cancel old alarm and starts a new one for the specified interval. - * - * @param interval when to trigger the alarm, starting from now. - */ - private void resetAlarm(long interval) { - mAlarmManager.cancel(mPendingPollIntent); - long now = SystemClock.elapsedRealtime(); - long next = now + interval; - mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, next, mPendingPollIntent); - } - - /** Handler to do the network accesses on */ - private class MyHandler extends Handler { - - public MyHandler(Looper l) { - super(l); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case EVENT_AUTO_TIME_ENABLED: - case EVENT_POLL_NETWORK_TIME: - case EVENT_NETWORK_CHANGED: - onPollNetworkTime(msg.what); - break; - } - } - } - - private class NetworkTimeUpdateCallback extends NetworkCallback { - @Override - public void onAvailable(Network network) { - Log.d(TAG, String.format("New default network %s; checking time.", network)); - mDefaultNetwork = network; - // Running on mHandler so invoke directly. - onPollNetworkTime(EVENT_NETWORK_CHANGED); - } - - @Override - public void onLost(Network network) { - if (network.equals(mDefaultNetwork)) mDefaultNetwork = null; - } - } - - /** - * Observer to watch for changes to the AUTO_TIME setting. It only triggers when the setting - * is enabled. - */ - private static class AutoTimeSettingObserver extends ContentObserver { - - private final Context mContext; - private final int mMsg; - private final Handler mHandler; - - AutoTimeSettingObserver(Context context, Handler handler, int msg) { - super(handler); - mContext = context; - mHandler = handler; - mMsg = msg; - } - - void observe() { - ContentResolver resolver = mContext.getContentResolver(); - resolver.registerContentObserver(Settings.Global.getUriFor(Settings.Global.AUTO_TIME), - false, this); - } - - @Override - public void onChange(boolean selfChange) { - if (isAutomaticTimeEnabled()) { - mHandler.obtainMessage(mMsg).sendToTarget(); - } - } - - /** - * Checks if the user prefers to automatically set the time. - */ - private boolean isAutomaticTimeEnabled() { - ContentResolver resolver = mContext.getContentResolver(); - return Settings.Global.getInt(resolver, Settings.Global.AUTO_TIME, 0) != 0; - } - } - - @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; - pw.print("PollingIntervalMs: "); - TimeUtils.formatDuration(mPollingIntervalMs, pw); - pw.print("\nPollingIntervalShorterMs: "); - TimeUtils.formatDuration(mPollingIntervalShorterMs, pw); - pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax); - pw.println("\nTryAgainCounter: " + mTryAgainCounter); - NtpTrustedTime.TimeResult ntpResult = mTime.getCachedTimeResult(); - pw.println("NTP cache result: " + ntpResult); - if (ntpResult != null) { - pw.println("NTP result age: " + ntpResult.getAgeMillis()); - } - pw.println(); - } -} diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java index d1bc6af88347..90b0c11cc8dd 100644 --- a/services/core/java/com/android/server/StorageManagerService.java +++ b/services/core/java/com/android/server/StorageManagerService.java @@ -2648,9 +2648,11 @@ class StorageManagerService extends IStorageManager.Stub */ @Override public boolean supportsCheckpoint() throws RemoteException { - // Only the system process is permitted to start checkpoints - if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) { - throw new SecurityException("no permission to check filesystem checkpoint support"); + // Only the root, system_server and shell processes are permitted to start checkpoints + final int callingUid = Binder.getCallingUid(); + if (callingUid != Process.SYSTEM_UID && callingUid != Process.ROOT_UID + && callingUid != Process.SHELL_UID) { + throw new SecurityException("no permission to start filesystem checkpoint"); } return mVold.supportsCheckpoint(); @@ -2665,8 +2667,10 @@ class StorageManagerService extends IStorageManager.Stub */ @Override public void startCheckpoint(int numTries) throws RemoteException { - // Only the system process is permitted to start checkpoints - if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) { + // Only the root, system_server and shell processes are permitted to start checkpoints + final int callingUid = Binder.getCallingUid(); + if (callingUid != Process.SYSTEM_UID && callingUid != Process.ROOT_UID + && callingUid != Process.SHELL_UID) { throw new SecurityException("no permission to start filesystem checkpoint"); } diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 630554ddf72d..8b436c5f2435 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -50,6 +50,13 @@ import android.telephony.CallQuality; import android.telephony.CellIdentity; import android.telephony.CellInfo; import android.telephony.CellLocation; +import android.telephony.CellSignalStrength; +import android.telephony.CellSignalStrengthCdma; +import android.telephony.CellSignalStrengthGsm; +import android.telephony.CellSignalStrengthLte; +import android.telephony.CellSignalStrengthNr; +import android.telephony.CellSignalStrengthTdscdma; +import android.telephony.CellSignalStrengthWcdma; import android.telephony.DataFailCause; import android.telephony.DisconnectCause; import android.telephony.LocationAccessPolicy; @@ -404,7 +411,11 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mVoiceActivationState = copyOf(mVoiceActivationState, mNumPhones); mDataActivationState = copyOf(mDataActivationState, mNumPhones); mUserMobileDataState = copyOf(mUserMobileDataState, mNumPhones); - mSignalStrength = copyOf(mSignalStrength, mNumPhones); + if (mSignalStrength != null) { + mSignalStrength = copyOf(mSignalStrength, mNumPhones); + } else { + mSignalStrength = new SignalStrength[mNumPhones]; + } mMessageWaiting = copyOf(mMessageWaiting, mNumPhones); mCallForwarding = copyOf(mCallForwarding, mNumPhones); mCellIdentity = copyOf(mCellIdentity, mNumPhones); @@ -438,7 +449,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mDataActivationState[i] = TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN; mCallIncomingNumber[i] = ""; mServiceState[i] = new ServiceState(); - mSignalStrength[i] = new SignalStrength(); + mSignalStrength[i] = null; mUserMobileDataState[i] = false; mMessageWaiting[i] = false; mCallForwarding[i] = false; @@ -522,7 +533,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { mDataActivationState[i] = TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN; mCallIncomingNumber[i] = ""; mServiceState[i] = new ServiceState(); - mSignalStrength[i] = new SignalStrength(); + mSignalStrength[i] = null; mUserMobileDataState[i] = false; mMessageWaiting[i] = false; mCallForwarding[i] = false; @@ -799,10 +810,12 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) { try { - int gsmSignalStrength = mSignalStrength[phoneId] - .getGsmSignalStrength(); - r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1 - : gsmSignalStrength)); + if (mSignalStrength[phoneId] != null) { + int gsmSignalStrength = mSignalStrength[phoneId] + .getGsmSignalStrength(); + r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1 + : gsmSignalStrength)); + } } catch (RemoteException ex) { remove(r.binder); } @@ -859,7 +872,9 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { } if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) { try { - r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]); + if (mSignalStrength[phoneId] != null) { + r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]); + } } catch (RemoteException ex) { remove(r.binder); } @@ -1293,7 +1308,8 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { // only CarrierService with carrier privilege rule should have the permission int[] subIds = Arrays.stream(SubscriptionManager.from(mContext) .getActiveSubscriptionIdList(false)) - .filter(i -> TelephonyPermissions.checkCarrierPrivilegeForSubId(i)).toArray(); + .filter(i -> TelephonyPermissions.checkCarrierPrivilegeForSubId(mContext, + i)).toArray(); if (ArrayUtils.isEmpty(subIds)) { loge("notifyCarrierNetworkChange without carrier privilege"); // the active subId does not have carrier privilege. @@ -1595,7 +1611,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { TelephonyManager.DATA_UNKNOWN, TelephonyManager.NETWORK_TYPE_UNKNOWN, ApnSetting.getApnTypesBitmaskFromString(apnType), null, null, - DataFailCause.NONE)); + DataFailCause.NONE, null)); for (Record r : mRecords) { if (r.matchPhoneStateListenerEvent( PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) @@ -1780,7 +1796,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { TelephonyManager.DATA_UNKNOWN, TelephonyManager.NETWORK_TYPE_UNKNOWN, ApnSetting.getApnTypesBitmaskFromString(apnType), null, null, - failCause)); + failCause, null)); for (Record r : mRecords) { if (r.matchPhoneStateListenerEvent( PhoneStateListener.LISTEN_PRECISE_DATA_CONNECTION_STATE) @@ -2203,13 +2219,32 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { Intent intent = new Intent(TelephonyIntents.ACTION_SIGNAL_STRENGTH_CHANGED); Bundle data = new Bundle(); - signalStrength.fillInNotifierBundle(data); + fillInSignalStrengthNotifierBundle(signalStrength, data); intent.putExtras(data); intent.putExtra(PHONE_CONSTANTS_SUBSCRIPTION_KEY, subId); intent.putExtra(PHONE_CONSTANTS_SLOT_KEY, phoneId); mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } + private void fillInSignalStrengthNotifierBundle(SignalStrength signalStrength, Bundle bundle) { + List<CellSignalStrength> cellSignalStrengths = signalStrength.getCellSignalStrengths(); + for (CellSignalStrength cellSignalStrength : cellSignalStrengths) { + if (cellSignalStrength instanceof CellSignalStrengthLte) { + bundle.putParcelable("Lte", (CellSignalStrengthLte) cellSignalStrength); + } else if (cellSignalStrength instanceof CellSignalStrengthCdma) { + bundle.putParcelable("Cdma", (CellSignalStrengthCdma) cellSignalStrength); + } else if (cellSignalStrength instanceof CellSignalStrengthGsm) { + bundle.putParcelable("Gsm", (CellSignalStrengthGsm) cellSignalStrength); + } else if (cellSignalStrength instanceof CellSignalStrengthWcdma) { + bundle.putParcelable("Wcdma", (CellSignalStrengthWcdma) cellSignalStrength); + } else if (cellSignalStrength instanceof CellSignalStrengthTdscdma) { + bundle.putParcelable("Tdscdma", (CellSignalStrengthTdscdma) cellSignalStrength); + } else if (cellSignalStrength instanceof CellSignalStrengthNr) { + bundle.putParcelable("Nr", (CellSignalStrengthNr) cellSignalStrength); + } + } + } + /** * Broadcasts an intent notifying apps of a phone state change. {@code subId} can be * a valid subId, in which case this function fires a subId-specific intent, or it @@ -2301,7 +2336,7 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { return; } - TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege( + TelephonyPermissions.enforceCallingOrSelfCarrierPrivilege(mContext, SubscriptionManager.getDefaultSubscriptionId(), method); } @@ -2518,11 +2553,14 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) { try { - SignalStrength signalStrength = mSignalStrength[phoneId]; - if (DBG) { - log("checkPossibleMissNotify: onSignalStrengthsChanged SS=" + signalStrength); + if (mSignalStrength[phoneId] != null) { + SignalStrength signalStrength = mSignalStrength[phoneId]; + if (DBG) { + log("checkPossibleMissNotify: onSignalStrengthsChanged SS=" + + signalStrength); + } + r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength)); } - r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength)); } catch (RemoteException ex) { mRemoveList.add(r.binder); } @@ -2530,14 +2568,16 @@ public class TelephonyRegistry extends ITelephonyRegistry.Stub { if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) { try { - int gsmSignalStrength = mSignalStrength[phoneId] - .getGsmSignalStrength(); - if (DBG) { - log("checkPossibleMissNotify: onSignalStrengthChanged SS=" + - gsmSignalStrength); + if (mSignalStrength[phoneId] != null) { + int gsmSignalStrength = mSignalStrength[phoneId] + .getGsmSignalStrength(); + if (DBG) { + log("checkPossibleMissNotify: onSignalStrengthChanged SS=" + + gsmSignalStrength); + } + r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1 + : gsmSignalStrength)); } - r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1 - : gsmSignalStrength)); } catch (RemoteException ex) { mRemoveList.add(r.binder); } diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java index d19d2ddd7c3c..a7e36b23a98b 100644 --- a/services/core/java/com/android/server/TestNetworkService.java +++ b/services/core/java/com/android/server/TestNetworkService.java @@ -219,7 +219,7 @@ class TestNetworkService extends ITestNetworkManager.Stub { // Has to be in TestNetworkAgent to ensure all teardown codepaths properly clean up // resources, even for binder death or unwanted calls. synchronized (mTestNetworkTracker) { - mTestNetworkTracker.remove(netId); + mTestNetworkTracker.remove(network.netId); } } } @@ -338,7 +338,7 @@ class TestNetworkService extends ITestNetworkManager.Stub { callingUid, binder); - mTestNetworkTracker.put(agent.netId, agent); + mTestNetworkTracker.put(agent.network.netId, agent); } } catch (SocketException e) { throw new UncheckedIOException(e); diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index a1480e305d9e..e7179e09c4b3 100644 --- a/services/core/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java @@ -60,7 +60,6 @@ import android.provider.DeviceConfig; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.util.DebugUtils; -import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.StatsLog; @@ -162,8 +161,7 @@ public class VibratorService extends IVibratorService.Stub private int mHapticFeedbackIntensity; private int mNotificationIntensity; private int mRingIntensity; - private SparseArray<Pair<VibrationEffect, AudioAttributes>> mAlwaysOnEffects = - new SparseArray<>(); + private SparseArray<Vibration> mAlwaysOnEffects = new SparseArray<>(); static native boolean vibratorExists(); static native void vibratorInit(); @@ -477,6 +475,10 @@ public class VibratorService extends IVibratorService.Stub Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY), true, mSettingObserver, UserHandle.USER_ALL); + mContext.getContentResolver().registerContentObserver( + Settings.Global.getUriFor(Settings.Global.ZEN_MODE), + true, mSettingObserver, UserHandle.USER_ALL); + mContext.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -524,7 +526,8 @@ public class VibratorService extends IVibratorService.Stub } @Override // Binder call - public boolean setAlwaysOnEffect(int id, VibrationEffect effect, AudioAttributes attrs) { + public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, VibrationEffect effect, + AudioAttributes attrs) { if (!hasPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON)) { throw new SecurityException("Requires VIBRATE_ALWAYS_ON permission"); } @@ -534,8 +537,8 @@ public class VibratorService extends IVibratorService.Stub } if (effect == null) { synchronized (mLock) { - mAlwaysOnEffects.delete(id); - vibratorAlwaysOnDisable(id); + mAlwaysOnEffects.delete(alwaysOnId); + vibratorAlwaysOnDisable(alwaysOnId); } } else { if (!verifyVibrationEffect(effect)) { @@ -545,14 +548,11 @@ public class VibratorService extends IVibratorService.Stub Slog.e(TAG, "Only prebaked effects supported for always-on."); return false; } - if (attrs == null) { - attrs = new AudioAttributes.Builder() - .setUsage(AudioAttributes.USAGE_UNKNOWN) - .build(); - } + attrs = fixupVibrationAttributes(attrs); synchronized (mLock) { - mAlwaysOnEffects.put(id, Pair.create(effect, attrs)); - updateAlwaysOnLocked(id, effect, attrs); + Vibration vib = new Vibration(null, effect, attrs, uid, opPkg, null); + mAlwaysOnEffects.put(alwaysOnId, vib); + updateAlwaysOnLocked(alwaysOnId, vib); } } return true; @@ -592,6 +592,25 @@ public class VibratorService extends IVibratorService.Stub return true; } + private AudioAttributes fixupVibrationAttributes(AudioAttributes attrs) { + if (attrs == null) { + attrs = new AudioAttributes.Builder() + .setUsage(AudioAttributes.USAGE_UNKNOWN) + .build(); + } + if (shouldBypassDnd(attrs)) { + if (!(hasPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) + || hasPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + || hasPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING))) { + final int flags = attrs.getAllFlags() + & ~AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY; + attrs = new AudioAttributes.Builder(attrs).replaceFlags(flags).build(); + } + } + + return attrs; + } + private static long[] getLongIntArray(Resources r, int resid) { int[] ar = r.getIntArray(resid); if (ar == null) { @@ -621,21 +640,7 @@ public class VibratorService extends IVibratorService.Stub return; } - if (attrs == null) { - attrs = new AudioAttributes.Builder() - .setUsage(AudioAttributes.USAGE_UNKNOWN) - .build(); - } - - if (shouldBypassDnd(attrs)) { - if (!(hasPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) - || hasPermission(android.Manifest.permission.MODIFY_PHONE_STATE) - || hasPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING))) { - final int flags = attrs.getAllFlags() - & ~AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY; - attrs = new AudioAttributes.Builder(attrs).replaceFlags(flags).build(); - } - } + attrs = fixupVibrationAttributes(attrs); // If our current vibration is longer than the new vibration and is the same amplitude, // then just let the current one finish. @@ -796,29 +801,8 @@ public class VibratorService extends IVibratorService.Stub private void startVibrationLocked(final Vibration vib) { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationLocked"); try { - if (!isAllowedToVibrateLocked(vib)) { - return; - } - final int intensity = getCurrentIntensityLocked(vib); - if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) { - return; - } - - if (vib.isRingtone() && !shouldVibrateForRingtone()) { - if (DEBUG) { - Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones"); - } - return; - } - - final int mode = getAppOpMode(vib); - if (mode != AppOpsManager.MODE_ALLOWED) { - if (mode == AppOpsManager.MODE_ERRORED) { - // We might be getting calls from within system_server, so we don't actually - // want to throw a SecurityException here. - Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid); - } + if (!shouldVibrate(vib, intensity)) { return; } applyVibrationIntensityScalingLocked(vib, intensity); @@ -985,6 +969,35 @@ public class VibratorService extends IVibratorService.Stub return mode; } + private boolean shouldVibrate(Vibration vib, int intensity) { + if (!isAllowedToVibrateLocked(vib)) { + return false; + } + + if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) { + return false; + } + + if (vib.isRingtone() && !shouldVibrateForRingtone()) { + if (DEBUG) { + Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones"); + } + return false; + } + + final int mode = getAppOpMode(vib); + if (mode != AppOpsManager.MODE_ALLOWED) { + if (mode == AppOpsManager.MODE_ERRORED) { + // We might be getting calls from within system_server, so we don't actually + // want to throw a SecurityException here. + Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid); + } + return false; + } + + return true; + } + @GuardedBy("mLock") private void reportFinishVibrationLocked() { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked"); @@ -1096,14 +1109,12 @@ public class VibratorService extends IVibratorService.Stub mVibrator.getDefaultRingVibrationIntensity(), UserHandle.USER_CURRENT); } - private void updateAlwaysOnLocked(int id, VibrationEffect effect, AudioAttributes attrs) { - // TODO: Check DND and LowPower settings - final Vibration vib = new Vibration(null, effect, attrs, 0, null, null); + private void updateAlwaysOnLocked(int id, Vibration vib) { final int intensity = getCurrentIntensityLocked(vib); - if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) { + if (!shouldVibrate(vib, intensity)) { vibratorAlwaysOnDisable(id); } else { - final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect; + final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect; final int strength = intensityToEffectStrength(intensity); vibratorAlwaysOnEnable(id, prebaked.getId(), strength); } @@ -1112,8 +1123,8 @@ public class VibratorService extends IVibratorService.Stub private void updateAlwaysOnLocked() { for (int i = 0; i < mAlwaysOnEffects.size(); i++) { int id = mAlwaysOnEffects.keyAt(i); - Pair<VibrationEffect, AudioAttributes> pair = mAlwaysOnEffects.valueAt(i); - updateAlwaysOnLocked(id, pair.first, pair.second); + Vibration vib = mAlwaysOnEffects.valueAt(i); + updateAlwaysOnLocked(id, vib); } } diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 766fa3ba55c1..c2652c06e5a9 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -20,6 +20,7 @@ import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY; import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; import static android.app.ActivityThread.PROC_START_SEQ_IDENT; import static android.content.pm.PackageManager.MATCH_DIRECT_BOOT_AUTO; +import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT; import static android.os.Process.SYSTEM_UID; import static android.os.Process.THREAD_PRIORITY_BACKGROUND; import static android.os.Process.getFreeMemory; @@ -57,6 +58,8 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.res.Resources; import android.graphics.Point; +import android.net.LocalSocket; +import android.net.LocalSocketAddress; import android.os.AppZygote; import android.os.Binder; import android.os.Build; @@ -74,6 +77,7 @@ import android.os.Trace; import android.os.UserHandle; import android.os.storage.StorageManager; import android.os.storage.StorageManagerInternal; +import android.system.Os; import android.text.TextUtils; import android.util.ArrayMap; import android.util.EventLog; @@ -102,6 +106,7 @@ import com.android.server.wm.WindowManagerService; import dalvik.system.VMRuntime; import java.io.File; +import java.io.FileDescriptor; import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; @@ -245,6 +250,10 @@ public final class ProcessList { private static final String PROPERTY_USE_APP_IMAGE_STARTUP_CACHE = "persist.device_config.runtime_native.use_app_image_startup_cache"; + // The socket path for zygote to send unsolicited msg. + // Must keep sync with com_android_internal_os_Zygote.cpp. + private static final String UNSOL_ZYGOTE_MSG_SOCKET_PATH = "/data/system/unsolzygotesocket"; + // Low Memory Killer Daemon command codes. // These must be kept in sync with lmk_cmd definitions in lmkd.h // @@ -388,6 +397,28 @@ public final class ProcessList { private PlatformCompat mPlatformCompat = null; + /** + * The server socket in system_server, zygote will connect to it + * in order to send unsolicited messages to system_server. + */ + private LocalSocket mSystemServerSocketForZygote; + + /** + * Maximum number of bytes that an incoming unsolicited zygote message could be. + * To be updated if new message type needs to be supported. + */ + private static final int MAX_ZYGOTE_UNSOLICITED_MESSAGE_SIZE = 16; + + /** + * The buffer to be used to receive the incoming unsolicited zygote message. + */ + private final byte[] mZygoteUnsolicitedMessage = new byte[MAX_ZYGOTE_UNSOLICITED_MESSAGE_SIZE]; + + /** + * The buffer to be used to receive the SIGCHLD data, it includes pid/uid/status. + */ + private final int[] mZygoteSigChldMessage = new int[3]; + interface LmkdKillListener { /** * Called when there is a process kill by lmkd. @@ -645,6 +676,13 @@ public final class ProcessList { } } ); + // Start listening on incoming connections from zygotes. + mSystemServerSocketForZygote = createSystemServerSocketForZygote(); + if (mSystemServerSocketForZygote != null) { + sKillHandler.getLooper().getQueue().addOnFileDescriptorEventListener( + mSystemServerSocketForZygote.getFileDescriptor(), + EVENT_INPUT, this::handleZygoteMessages); + } } } @@ -3267,4 +3305,66 @@ public final class ProcessList { } } } + + private void handleZygoteSigChld(int pid, int uid, int status) { + // Just log it now. + if (DEBUG_PROCESSES) { + Slog.i(TAG, "Got SIGCHLD from zygote: pid=" + pid + ", uid=" + uid + + ", status=" + Integer.toHexString(status)); + } + } + + /** + * Create a server socket in system_server, zygote will connect to it + * in order to send unsolicited messages to system_server. + */ + private LocalSocket createSystemServerSocketForZygote() { + // The file system entity for this socket is created with 0666 perms, owned + // by system:system. selinux restricts things so that only zygotes can + // access it. + final File socketFile = new File(UNSOL_ZYGOTE_MSG_SOCKET_PATH); + if (socketFile.exists()) { + socketFile.delete(); + } + + LocalSocket serverSocket = null; + try { + serverSocket = new LocalSocket(LocalSocket.SOCKET_DGRAM); + serverSocket.bind(new LocalSocketAddress( + UNSOL_ZYGOTE_MSG_SOCKET_PATH, LocalSocketAddress.Namespace.FILESYSTEM)); + Os.chmod(UNSOL_ZYGOTE_MSG_SOCKET_PATH, 0666); + } catch (Exception e) { + if (serverSocket != null) { + try { + serverSocket.close(); + } catch (IOException ex) { + } + serverSocket = null; + } + } + return serverSocket; + } + + /** + * Handle the unsolicited message from zygote. + */ + private int handleZygoteMessages(FileDescriptor fd, int events) { + final int eventFd = fd.getInt$(); + if ((events & EVENT_INPUT) != 0) { + // An incoming message from zygote + try { + final int len = Os.read(fd, mZygoteUnsolicitedMessage, 0, + mZygoteUnsolicitedMessage.length); + if (len > 0 && mZygoteSigChldMessage.length == Zygote.nativeParseSigChld( + mZygoteUnsolicitedMessage, len, mZygoteSigChldMessage)) { + handleZygoteSigChld(mZygoteSigChldMessage[0] /* pid */, + mZygoteSigChldMessage[1] /* uid */, + mZygoteSigChldMessage[2] /* status */); + } + } catch (Exception e) { + Slog.w(TAG, "Exception in reading unsolicited zygote message: " + e); + } + } + return EVENT_INPUT; + } } diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 314e04c8da32..d45bc72aee11 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -1110,8 +1110,8 @@ public class AppOpsService extends IAppOpsService.Stub { return Collections.emptyList(); } synchronized (this) { - Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* edit */, - false /* uidMismatchExpected */); + Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false /* isPrivileged */, + false /* edit */); if (pkgOps == null) { return null; } @@ -1208,8 +1208,7 @@ public class AppOpsService extends IAppOpsService.Stub { private void pruneOp(Op op, int uid, String packageName) { if (!op.hasAnyTime()) { - Ops ops = getOpsRawLocked(uid, packageName, false /* edit */, - false /* uidMismatchExpected */); + Ops ops = getOpsRawLocked(uid, packageName, false /* isPrivileged */, false /* edit */); if (ops != null) { ops.remove(op.op); if (ops.size() <= 0) { @@ -1409,11 +1408,6 @@ public class AppOpsService extends IAppOpsService.Stub { } } - @Override - public void setMode(int code, int uid, String packageName, int mode) { - setMode(code, uid, packageName, mode, true, false); - } - /** * Sets the mode for a certain op and uid. * @@ -1421,19 +1415,25 @@ public class AppOpsService extends IAppOpsService.Stub { * @param uid The UID for which to set * @param packageName The package for which to set * @param mode The new mode to set - * @param verifyUid Iff {@code true}, check that the package name belongs to the uid - * @param isPrivileged Whether the package is privileged. (Only used if {@code verifyUid == - * false}) */ - private void setMode(int code, int uid, @NonNull String packageName, int mode, - boolean verifyUid, boolean isPrivileged) { + @Override + public void setMode(int code, int uid, @NonNull String packageName, int mode) { enforceManageAppOpsModes(Binder.getCallingPid(), Binder.getCallingUid(), uid); verifyIncomingOp(code); ArraySet<ModeCallback> repCbs = null; code = AppOpsManager.opToSwitch(code); + + boolean isPrivileged; + try { + isPrivileged = verifyAndGetIsPrivileged(uid, packageName); + } catch (SecurityException e) { + Slog.e(TAG, "Cannot setMode", e); + return; + } + synchronized (this) { UidState uidState = getUidStateLocked(uid, false); - Op op = getOpLocked(code, uid, packageName, true, verifyUid, isPrivileged); + Op op = getOpLocked(code, uid, packageName, isPrivileged, true); if (op != null) { if (op.mode != mode) { op.mode = mode; @@ -1799,34 +1799,32 @@ public class AppOpsService extends IAppOpsService.Stub { } /** - * @see #checkOperationUnchecked(int, int, String, boolean, boolean) - */ - private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName, - boolean raw) { - return checkOperationUnchecked(code, uid, packageName, raw, true); - } - - /** * Get the mode of an app-op. * * @param code The code of the op * @param uid The uid of the package the op belongs to * @param packageName The package the op belongs to * @param raw If the raw state of eval-ed state should be checked. - * @param verify If the code should check the package belongs to the uid * * @return The mode of the op */ private @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName, - boolean raw, boolean verify) { + boolean raw) { if (isOpRestrictedDueToSuspend(code, packageName, uid)) { return AppOpsManager.MODE_IGNORED; } + + boolean isPrivileged; + + try { + isPrivileged = verifyAndGetIsPrivileged(uid, packageName); + } catch (SecurityException e) { + Slog.e(TAG, "checkOperation", e); + return AppOpsManager.opToDefaultMode(code); + } + synchronized (this) { - if (verify) { - checkPackage(uid, packageName); - } - if (isOpRestrictedLocked(uid, code, packageName)) { + if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) { return AppOpsManager.MODE_IGNORED; } code = AppOpsManager.opToSwitch(code); @@ -1836,7 +1834,7 @@ public class AppOpsService extends IAppOpsService.Stub { final int rawMode = uidState.opModes.get(code); return raw ? rawMode : uidState.evalMode(code, rawMode); } - Op op = getOpLocked(code, uid, packageName, false, verify, false); + Op op = getOpLocked(code, uid, packageName, false, false); if (op == null) { return AppOpsManager.opToDefaultMode(code); } @@ -1941,14 +1939,12 @@ public class AppOpsService extends IAppOpsService.Stub { @Override public int checkPackage(int uid, String packageName) { Preconditions.checkNotNull(packageName); - synchronized (this) { - Ops ops = getOpsRawLocked(uid, packageName, true /* edit */, - true /* uidMismatchExpected */); - if (ops != null) { - return AppOpsManager.MODE_ALLOWED; - } else { - return AppOpsManager.MODE_ERRORED; - } + try { + verifyAndGetIsPrivileged(uid, packageName); + + return AppOpsManager.MODE_ALLOWED; + } catch (SecurityException ignored) { + return AppOpsManager.MODE_ERRORED; } } @@ -2011,9 +2007,16 @@ public class AppOpsService extends IAppOpsService.Stub { private int noteOperationUnchecked(int code, int uid, String packageName, int proxyUid, String proxyPackageName, @OpFlags int flags) { + boolean isPrivileged; + try { + isPrivileged = verifyAndGetIsPrivileged(uid, packageName); + } catch (SecurityException e) { + Slog.e(TAG, "noteOperation", e); + return AppOpsManager.MODE_ERRORED; + } + synchronized (this) { - final Ops ops = getOpsRawLocked(uid, packageName, true /* edit */, - false /* uidMismatchExpected */); + final Ops ops = getOpsRawLocked(uid, packageName, isPrivileged, true /* edit */); if (ops == null) { scheduleOpNotedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_IGNORED); @@ -2022,7 +2025,7 @@ public class AppOpsService extends IAppOpsService.Stub { return AppOpsManager.MODE_ERRORED; } final Op op = getOpLocked(ops, code, true); - if (isOpRestrictedLocked(uid, code, packageName)) { + if (isOpRestrictedLocked(uid, code, packageName, isPrivileged)) { scheduleOpNotedIfNeededLocked(code, uid, packageName, AppOpsManager.MODE_IGNORED); return AppOpsManager.MODE_IGNORED; @@ -2181,16 +2184,25 @@ public class AppOpsService extends IAppOpsService.Stub { return AppOpsManager.MODE_IGNORED; } ClientState client = (ClientState)token; + + boolean isPrivileged; + try { + isPrivileged = verifyAndGetIsPrivileged(uid, packageName); + } catch (SecurityException e) { + Slog.e(TAG, "startOperation", e); + return AppOpsManager.MODE_ERRORED; + } + synchronized (this) { - final Ops ops = getOpsRawLocked(uid, resolvedPackageName, true /* edit */, - false /* uidMismatchExpected */); + final Ops ops = getOpsRawLocked(uid, resolvedPackageName, isPrivileged, + true /* edit */); if (ops == null) { if (DEBUG) Slog.d(TAG, "startOperation: no op for code " + code + " uid " + uid + " package " + resolvedPackageName); return AppOpsManager.MODE_ERRORED; } final Op op = getOpLocked(ops, code, true); - if (isOpRestrictedLocked(uid, code, resolvedPackageName)) { + if (isOpRestrictedLocked(uid, code, resolvedPackageName, isPrivileged)) { return AppOpsManager.MODE_IGNORED; } final int switchCode = AppOpsManager.opToSwitch(code); @@ -2262,8 +2274,17 @@ public class AppOpsService extends IAppOpsService.Stub { return; } ClientState client = (ClientState) token; + + boolean isPrivileged; + try { + isPrivileged = verifyAndGetIsPrivileged(uid, packageName); + } catch (SecurityException e) { + Slog.e(TAG, "Cannot finishOperation", e); + return; + } + synchronized (this) { - Op op = getOpLocked(code, uid, resolvedPackageName, true, true, false); + Op op = getOpLocked(code, uid, resolvedPackageName, isPrivileged, true); if (op == null) { return; } @@ -2513,8 +2534,76 @@ public class AppOpsService extends IAppOpsService.Stub { uidState.pendingStateCommitTime = 0; } - private Ops getOpsRawLocked(int uid, String packageName, boolean edit, - boolean uidMismatchExpected) { + /** + * Verify that package belongs to uid and return whether the package is privileged. + * + * @param uid The uid the package belongs to + * @param packageName The package the might belong to the uid + * + * @return {@code true} iff the package is privileged + */ + private boolean verifyAndGetIsPrivileged(int uid, String packageName) { + if (uid == Process.ROOT_UID) { + // For backwards compatibility, don't check package name for root UID. + return false; + } + + // Do not check if uid/packageName is already known + synchronized (this) { + UidState uidState = mUidStates.get(uid); + if (uidState != null && uidState.pkgOps != null) { + Ops ops = uidState.pkgOps.get(packageName); + + if (ops != null) { + return ops.isPrivileged; + } + } + } + + boolean isPrivileged = false; + final long ident = Binder.clearCallingIdentity(); + try { + int pkgUid; + + ApplicationInfo appInfo = LocalServices.getService(PackageManagerInternal.class) + .getApplicationInfo(packageName, PackageManager.MATCH_DIRECT_BOOT_AWARE + | PackageManager.MATCH_DIRECT_BOOT_UNAWARE + | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS + | PackageManager.MATCH_UNINSTALLED_PACKAGES + | PackageManager.MATCH_INSTANT, + Process.SYSTEM_UID, UserHandle.getUserId(uid)); + if (appInfo != null) { + pkgUid = appInfo.uid; + isPrivileged = (appInfo.privateFlags + & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; + } else { + pkgUid = resolveUid(packageName); + if (pkgUid >= 0) { + isPrivileged = false; + } + } + if (pkgUid != uid) { + throw new SecurityException("Specified package " + packageName + " under uid " + uid + + " but it is really " + pkgUid); + } + } finally { + Binder.restoreCallingIdentity(ident); + } + + return isPrivileged; + } + + /** + * Get (and potentially create) ops. + * + * @param uid The uid the package belongs to + * @param packageName The name of the package + * @param isPrivileged If the package is privilidged (ignored if {@code edit} is false) + * @param edit If an ops does not exist, create the ops? + + * @return + */ + private Ops getOpsRawLocked(int uid, String packageName, boolean isPrivileged, boolean edit) { UidState uidState = getUidStateLocked(uid, edit); if (uidState == null) { return null; @@ -2532,47 +2621,6 @@ public class AppOpsService extends IAppOpsService.Stub { if (!edit) { return null; } - boolean isPrivileged = false; - // This is the first time we have seen this package name under this uid, - // so let's make sure it is valid. - if (uid != 0) { - final long ident = Binder.clearCallingIdentity(); - try { - int pkgUid = -1; - try { - ApplicationInfo appInfo = ActivityThread.getPackageManager() - .getApplicationInfo(packageName, - PackageManager.MATCH_DIRECT_BOOT_AWARE - | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, - UserHandle.getUserId(uid)); - if (appInfo != null) { - pkgUid = appInfo.uid; - isPrivileged = (appInfo.privateFlags - & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; - } else { - pkgUid = resolveUid(packageName); - if (pkgUid >= 0) { - isPrivileged = false; - } - } - } catch (RemoteException e) { - Slog.w(TAG, "Could not contact PackageManager", e); - } - if (pkgUid != uid) { - // Oops! The package name is not valid for the uid they are calling - // under. Abort. - if (!uidMismatchExpected) { - RuntimeException ex = new RuntimeException("here"); - ex.fillInStackTrace(); - Slog.w(TAG, "Bad call: specified package " + packageName - + " under uid " + uid + " but it is really " + pkgUid, ex); - } - return null; - } - } finally { - Binder.restoreCallingIdentity(ident); - } - } ops = new Ops(packageName, uidState, isPrivileged); uidState.pkgOps.put(packageName, ops); } @@ -2580,7 +2628,7 @@ public class AppOpsService extends IAppOpsService.Stub { } /** - * Get the state of all ops for a package, <b>don't verify that package belongs to uid</b>. + * Get the state of all ops for a package. * * <p>Usually callers should use {@link #getOpLocked} and not call this directly. * @@ -2638,23 +2686,15 @@ public class AppOpsService extends IAppOpsService.Stub { * @param code The code of the op * @param uid The uid the of the package * @param packageName The package name for which to get the state for + * @param isPrivileged Whether the package is privileged or not (only used if {@code edit + * == true}) * @param edit Iff {@code true} create the {@link Op} object if not yet created - * @param verifyUid Iff {@code true} check that the package belongs to the uid - * @param isPrivileged Whether the package is privileged or not (only used if {@code verifyUid - * == false}) * * @return The {@link Op state} of the op */ - private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName, boolean edit, - boolean verifyUid, boolean isPrivileged) { - Ops ops; - - if (verifyUid) { - ops = getOpsRawLocked(uid, packageName, edit, false /* uidMismatchExpected */); - } else { - ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged); - } - + private @Nullable Op getOpLocked(int code, int uid, @NonNull String packageName, + boolean isPrivileged, boolean edit) { + Ops ops = getOpsRawNoVerifyLocked(uid, packageName, edit, isPrivileged); if (ops == null) { return null; } @@ -2684,7 +2724,8 @@ public class AppOpsService extends IAppOpsService.Stub { return pmi.isPackageSuspended(packageName, UserHandle.getUserId(uid)); } - private boolean isOpRestrictedLocked(int uid, int code, String packageName) { + private boolean isOpRestrictedLocked(int uid, int code, String packageName, + boolean isPrivileged) { int userHandle = UserHandle.getUserId(uid); final int restrictionSetCount = mOpUserRestrictions.size(); @@ -2696,8 +2737,8 @@ public class AppOpsService extends IAppOpsService.Stub { if (AppOpsManager.opAllowSystemBypassRestriction(code)) { // If we are the system, bypass user restrictions for certain codes synchronized (this) { - Ops ops = getOpsRawLocked(uid, packageName, true /* edit */, - false /* uidMismatchExpected */); + Ops ops = getOpsRawLocked(uid, packageName, isPrivileged, + true /* edit */); if ((ops != null) && ops.isPrivileged) { return false; } @@ -3068,7 +3109,7 @@ public class AppOpsService extends IAppOpsService.Stub { out.attribute(null, "n", Integer.toString(pkg.getUid())); synchronized (this) { Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(), - false /* edit */, false /* uidMismatchExpected */); + false /* isPrivileged */, false /* edit */); // Should always be present as the list of PackageOps is generated // from Ops. if (ops != null) { @@ -4647,18 +4688,8 @@ public class AppOpsService extends IAppOpsService.Stub { } @Override - public void setUidMode(int code, int uid, int mode) { - AppOpsService.this.setUidMode(code, uid, mode); - } - - @Override public void setAllPkgModesToDefault(int code, int uid) { AppOpsService.this.setAllPkgModesToDefault(code, uid); } - - @Override - public @Mode int checkOperationUnchecked(int code, int uid, @NonNull String packageName) { - return AppOpsService.this.checkOperationUnchecked(code, uid, packageName, true, false); - } } } diff --git a/services/core/java/com/android/server/appop/TEST_MAPPING b/services/core/java/com/android/server/appop/TEST_MAPPING index a53797dfa9e0..1a5dac503463 100644 --- a/services/core/java/com/android/server/appop/TEST_MAPPING +++ b/services/core/java/com/android/server/appop/TEST_MAPPING @@ -10,6 +10,14 @@ "include-filter": "com.android.server.appop" } ] + }, + { + "name": "FrameworksMockingServicesTests", + "options": [ + { + "include-filter": "com.android.server.appop" + } + ] } ] } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 25fdf6447061..88a63f1aa06d 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -6292,7 +6292,7 @@ public class AudioService extends IAudioService.Stub return false; } boolean suppress = false; - if (resolvedStream == DEFAULT_VOL_STREAM_NO_PLAYBACK && mController != null) { + if (resolvedStream != AudioSystem.STREAM_MUSIC && mController != null) { final long now = SystemClock.uptimeMillis(); if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) { // ui will become visible diff --git a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java index dfc00806992b..4bf606e801f9 100644 --- a/services/core/java/com/android/server/compat/OverrideValidatorImpl.java +++ b/services/core/java/com/android/server/compat/OverrideValidatorImpl.java @@ -53,6 +53,7 @@ public class OverrideValidatorImpl extends IOverrideValidator.Stub { public OverrideAllowedState getOverrideAllowedState(long changeId, String packageName) { boolean debuggableBuild = false; boolean finalBuild = false; + int minTargetSdk = mCompatConfig.minTargetSdkForChangeId(changeId); debuggableBuild = mAndroidBuildClassifier.isDebuggableBuild(); finalBuild = mAndroidBuildClassifier.isFinalBuild(); @@ -76,15 +77,14 @@ public class OverrideValidatorImpl extends IOverrideValidator.Stub { if ((applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) { return new OverrideAllowedState(DISABLED_NOT_DEBUGGABLE, -1, -1); } - int minTargetSdk = mCompatConfig.minTargetSdkForChangeId(changeId); - // Do not allow overriding non-target sdk gated changes on user builds - if (minTargetSdk == -1) { - return new OverrideAllowedState(DISABLED_NON_TARGET_SDK, appTargetSdk, minTargetSdk); - } // Allow overriding any change for debuggable apps on non-final builds. if (!finalBuild) { return new OverrideAllowedState(ALLOWED, appTargetSdk, minTargetSdk); } + // Do not allow overriding non-target sdk gated changes on user builds + if (minTargetSdk == -1) { + return new OverrideAllowedState(DISABLED_NON_TARGET_SDK, appTargetSdk, minTargetSdk); + } // Only allow to opt-in for a targetSdk gated change. if (applicationInfo.targetSdkVersion < minTargetSdk) { return new OverrideAllowedState(ALLOWED, appTargetSdk, minTargetSdk); diff --git a/services/core/java/com/android/server/connectivity/DataConnectionStats.java b/services/core/java/com/android/server/connectivity/DataConnectionStats.java index 1b1c54682255..5010e46a74eb 100644 --- a/services/core/java/com/android/server/connectivity/DataConnectionStats.java +++ b/services/core/java/com/android/server/connectivity/DataConnectionStats.java @@ -16,6 +16,9 @@ package com.android.server.connectivity; +import static android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN; +import static android.telephony.NetworkRegistrationInfo.DOMAIN_PS; + import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -24,6 +27,7 @@ import android.net.ConnectivityManager; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; +import android.telephony.NetworkRegistrationInfo; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SignalStrength; @@ -91,7 +95,10 @@ public class DataConnectionStats extends BroadcastReceiver { boolean visible = (simReadyOrUnknown || isCdma()) // we only check the sim state for GSM && hasService() && mDataState == TelephonyManager.DATA_CONNECTED; - int networkType = mServiceState.getDataNetworkType(); + NetworkRegistrationInfo regInfo = + mServiceState.getNetworkRegistrationInfo(DOMAIN_PS, TRANSPORT_TYPE_WWAN); + int networkType = regInfo == null ? TelephonyManager.NETWORK_TYPE_UNKNOWN + : regInfo.getAccessNetworkTechnology(); if (DEBUG) Log.d(TAG, String.format("Noting data connection for network type %s: %svisible", networkType, visible ? "" : "not ")); try { diff --git a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java index 6fa999cb039a..04c792ae482b 100644 --- a/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java +++ b/services/core/java/com/android/server/connectivity/MultipathPolicyTracker.java @@ -26,6 +26,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkPolicy.LIMIT_DISABLED; import static android.net.NetworkPolicy.WARNING_DISABLED; import static android.provider.Settings.Global.NETWORK_DEFAULT_DAILY_MULTIPATH_QUOTA_BYTES; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static com.android.server.net.NetworkPolicyManagerInternal.QUOTA_TYPE_MULTIPATH; import static com.android.server.net.NetworkPolicyManagerService.OPPORTUNISTIC_QUOTA_UNKNOWN; @@ -46,19 +47,18 @@ import android.net.NetworkIdentity; import android.net.NetworkPolicy; import android.net.NetworkPolicyManager; import android.net.NetworkRequest; +import android.net.NetworkSpecifier; import android.net.NetworkStats; import android.net.NetworkTemplate; -import android.net.StringNetworkSpecifier; +import android.net.TelephonyNetworkSpecifier; +import android.net.Uri; import android.os.BestClock; import android.os.Handler; import android.os.SystemClock; -import android.net.Uri; import android.os.UserHandle; import android.provider.Settings; import android.telephony.TelephonyManager; -import android.util.DataUnit; import android.util.DebugUtils; -import android.util.Pair; import android.util.Range; import android.util.Slog; @@ -74,7 +74,6 @@ import java.time.ZoneId; import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; -import java.util.Iterator; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; @@ -185,7 +184,6 @@ public class MultipathPolicyTracker { // Track information on mobile networks as they come and go. class MultipathTracker { final Network network; - final int subId; final String subscriberId; private long mQuota; @@ -198,13 +196,14 @@ public class MultipathPolicyTracker { public MultipathTracker(Network network, NetworkCapabilities nc) { this.network = network; this.mNetworkCapabilities = new NetworkCapabilities(nc); - try { - subId = Integer.parseInt( - ((StringNetworkSpecifier) nc.getNetworkSpecifier()).toString()); - } catch (ClassCastException | NullPointerException | NumberFormatException e) { + NetworkSpecifier specifier = nc.getNetworkSpecifier(); + int subId = INVALID_SUBSCRIPTION_ID; + if (specifier instanceof TelephonyNetworkSpecifier) { + subId = ((TelephonyNetworkSpecifier) specifier).getSubscriptionId(); + } else { throw new IllegalStateException(String.format( - "Can't get subId from mobile network %s (%s): %s", - network, nc, e.getMessage())); + "Can't get subId from mobile network %s (%s)", + network, nc)); } TelephonyManager tele = mContext.getSystemService(TelephonyManager.class); diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java index 21795184b1bd..2c415570d5fa 100644 --- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java +++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java @@ -28,7 +28,7 @@ import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.net.NetworkSpecifier; -import android.net.StringNetworkSpecifier; +import android.net.TelephonyNetworkSpecifier; import android.net.wifi.WifiInfo; import android.os.UserHandle; import android.telephony.SubscriptionManager; @@ -223,14 +223,8 @@ public class NetworkNotificationManager { // name has been added to it NetworkSpecifier specifier = nai.networkCapabilities.getNetworkSpecifier(); int subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; - if (specifier instanceof StringNetworkSpecifier) { - try { - subId = Integer.parseInt( - ((StringNetworkSpecifier) specifier).specifier); - } catch (NumberFormatException e) { - Slog.e(TAG, "NumberFormatException on " - + ((StringNetworkSpecifier) specifier).specifier); - } + if (specifier instanceof TelephonyNetworkSpecifier) { + subId = ((TelephonyNetworkSpecifier) specifier).getSubscriptionId(); } details = mTelephonyManager.createForSubscriptionId(subId) diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index a46ada873408..08e73efb8f82 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -848,7 +848,7 @@ public class Vpn { } public int getNetId() { - return mNetworkAgent != null ? mNetworkAgent.netId : NETID_UNSET; + return mNetworkAgent != null ? mNetworkAgent.network.netId : NETID_UNSET; } private LinkProperties makeLinkProperties() { diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java index 1fc0db3ff7cb..6dcfadef5f8c 100644 --- a/services/core/java/com/android/server/display/DisplayModeDirector.java +++ b/services/core/java/com/android/server/display/DisplayModeDirector.java @@ -76,7 +76,7 @@ public class DisplayModeDirector { private static final int GLOBAL_ID = -1; // The tolerance within which we consider something approximately equals. - private static final float EPSILON = 0.001f; + private static final float EPSILON = 0.01f; private final Object mLock = new Object(); private final Context mContext; diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 63302705b36f..69cbc22f41bf 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -3454,7 +3454,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } /** - * This is kept due to {@link android.annotation.UnsupportedAppUsage} in + * This is kept due to {@link android.compat.annotation.UnsupportedAppUsage} in * {@link InputMethodManager#getInputMethodWindowVisibleHeight()} and a dependency in * {@link InputMethodService#onCreate()}. * diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java index ababad961c2d..97df55706bf8 100644 --- a/services/core/java/com/android/server/job/controllers/TimeController.java +++ b/services/core/java/com/android/server/job/controllers/TimeController.java @@ -325,8 +325,7 @@ public final class TimeController extends StateController { && !wouldBeReadyWithConstraintLocked( job, JobStatus.CONSTRAINT_TIMING_DELAY)) { if (DEBUG) { - Slog.i(TAG, - "Skipping " + job + " because delay won't make it ready."); + Slog.i(TAG, "Skipping " + job + " because delay won't make it ready."); } continue; } @@ -385,7 +384,8 @@ public final class TimeController extends StateController { /** * Set an alarm with the {@link android.app.AlarmManager} for the next time at which a job's * delay will expire. - * This alarm <b>will</b> wake up the phone. + * This alarm <b>will not</b> wake up the phone if + * {@link TcConstants#USE_NON_WAKEUP_ALARM_FOR_DELAY} is true. */ private void setDelayExpiredAlarmLocked(long alarmTimeElapsedMillis, WorkSource ws) { alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis); @@ -393,8 +393,11 @@ public final class TimeController extends StateController { return; } mNextDelayExpiredElapsedMillis = alarmTimeElapsedMillis; - updateAlarmWithListenerLocked(DELAY_TAG, mNextDelayExpiredListener, - mNextDelayExpiredElapsedMillis, ws); + final int alarmType = + mTcConstants.USE_NON_WAKEUP_ALARM_FOR_DELAY + ? AlarmManager.ELAPSED_REALTIME : AlarmManager.ELAPSED_REALTIME_WAKEUP; + updateAlarmWithListenerLocked(DELAY_TAG, alarmType, + mNextDelayExpiredListener, mNextDelayExpiredElapsedMillis, ws); } /** @@ -408,16 +411,16 @@ public final class TimeController extends StateController { return; } mNextJobExpiredElapsedMillis = alarmTimeElapsedMillis; - updateAlarmWithListenerLocked(DEADLINE_TAG, mDeadlineExpiredListener, - mNextJobExpiredElapsedMillis, ws); + updateAlarmWithListenerLocked(DEADLINE_TAG, AlarmManager.ELAPSED_REALTIME_WAKEUP, + mDeadlineExpiredListener, mNextJobExpiredElapsedMillis, ws); } private long maybeAdjustAlarmTime(long proposedAlarmTimeElapsedMillis) { return Math.max(proposedAlarmTimeElapsedMillis, sElapsedRealtimeClock.millis()); } - private void updateAlarmWithListenerLocked(String tag, OnAlarmListener listener, - long alarmTimeElapsed, WorkSource ws) { + private void updateAlarmWithListenerLocked(String tag, @AlarmManager.AlarmType int alarmType, + OnAlarmListener listener, long alarmTimeElapsed, WorkSource ws) { ensureAlarmServiceLocked(); if (alarmTimeElapsed == Long.MAX_VALUE) { mAlarmService.cancel(listener); @@ -425,7 +428,7 @@ public final class TimeController extends StateController { if (DEBUG) { Slog.d(TAG, "Setting " + tag + " for: " + alarmTimeElapsed); } - mAlarmService.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTimeElapsed, + mAlarmService.set(alarmType, alarmTimeElapsed, AlarmManager.WINDOW_HEURISTIC, 0, tag, listener, null, ws); } } @@ -464,8 +467,11 @@ public final class TimeController extends StateController { private final KeyValueListParser mParser = new KeyValueListParser(','); private static final String KEY_SKIP_NOT_READY_JOBS = "skip_not_ready_jobs"; + private static final String KEY_USE_NON_WAKEUP_ALARM_FOR_DELAY = + "use_non_wakeup_delay_alarm"; private static final boolean DEFAULT_SKIP_NOT_READY_JOBS = true; + private static final boolean DEFAULT_USE_NON_WAKEUP_ALARM_FOR_DELAY = true; /** * Whether or not TimeController should skip setting wakeup alarms for jobs that aren't @@ -474,6 +480,12 @@ public final class TimeController extends StateController { public boolean SKIP_NOT_READY_JOBS = DEFAULT_SKIP_NOT_READY_JOBS; /** + * Whether or not TimeController should skip setting wakeup alarms for jobs that aren't + * ready now. + */ + public boolean USE_NON_WAKEUP_ALARM_FOR_DELAY = DEFAULT_USE_NON_WAKEUP_ALARM_FOR_DELAY; + + /** * Creates a content observer. * * @param handler The handler to run {@link #onChange} on, or null if none. @@ -510,6 +522,12 @@ public final class TimeController extends StateController { recheckAlarmsLocked(); } } + + USE_NON_WAKEUP_ALARM_FOR_DELAY = mParser.getBoolean( + KEY_USE_NON_WAKEUP_ALARM_FOR_DELAY, DEFAULT_USE_NON_WAKEUP_ALARM_FOR_DELAY); + // Intentionally not calling checkExpiredDelaysAndResetAlarm() here. There's no need to + // iterate through the entire list again for this constant change. The next delay alarm + // that is set will make use of the new constant value. } private void dump(IndentingPrintWriter pw) { @@ -517,12 +535,16 @@ public final class TimeController extends StateController { pw.println("TimeController:"); pw.increaseIndent(); pw.printPair(KEY_SKIP_NOT_READY_JOBS, SKIP_NOT_READY_JOBS).println(); + pw.printPair(KEY_USE_NON_WAKEUP_ALARM_FOR_DELAY, + USE_NON_WAKEUP_ALARM_FOR_DELAY).println(); pw.decreaseIndent(); } private void dump(ProtoOutputStream proto) { final long tcToken = proto.start(ConstantsProto.TIME_CONTROLLER); proto.write(ConstantsProto.TimeController.SKIP_NOT_READY_JOBS, SKIP_NOT_READY_JOBS); + proto.write(ConstantsProto.TimeController.USE_NON_WAKEUP_ALARM_FOR_DELAY, + USE_NON_WAKEUP_ALARM_FOR_DELAY); proto.end(tcToken); } } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 04b51a93b994..9760185ca6df 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -161,7 +161,7 @@ import android.net.NetworkStack; import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkTemplate; -import android.net.StringNetworkSpecifier; +import android.net.TelephonyNetworkSpecifier; import android.net.TrafficStats; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; @@ -169,6 +169,7 @@ import android.os.BestClock; import android.os.Binder; import android.os.Environment; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.HandlerThread; import android.os.IDeviceIdleController; import android.os.INetworkManagementService; @@ -876,7 +877,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // Listen for subscriber changes mContext.getSystemService(SubscriptionManager.class).addOnSubscriptionsChangedListener( - new OnSubscriptionsChangedListener(mHandler.getLooper()) { + new HandlerExecutor(mHandler), + new OnSubscriptionsChangedListener() { @Override public void onSubscriptionsChanged() { updateNetworksInternal(); @@ -2869,17 +2871,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @Override - public void onTetheringChanged(String iface, boolean tethering) { - // No need to enforce permission because setRestrictBackground() will do it. - synchronized (mUidRulesFirstLock) { - if (mRestrictBackground && tethering) { - Log.d(TAG, "Tethering on (" + iface +"); disable Data Saver"); - setRestrictBackground(false); - } - } - } - - @Override public void setRestrictBackground(boolean restrictBackground) { Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "setRestrictBackground"); try { @@ -4547,7 +4538,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } case MSG_STATS_PROVIDER_LIMIT_REACHED: { mNetworkStats.forceUpdate(); + synchronized (mNetworkPoliciesSecondLock) { + // Some providers might hit the limit reached event prior to others. Thus, + // re-calculate and update interface quota for every provider is needed. + updateNetworkRulesNL(); updateNetworkEnabledNL(); updateNotificationsNL(); } @@ -4555,17 +4550,22 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } case MSG_LIMIT_REACHED: { final String iface = (String) msg.obj; - synchronized (mNetworkPoliciesSecondLock) { - if (mMeteredIfaces.contains(iface)) { - // force stats update to make sure we have - // numbers that caused alert to trigger. - mNetworkStats.forceUpdate(); - - updateNetworkEnabledNL(); - updateNotificationsNL(); + // fast return if not needed. + if (!mMeteredIfaces.contains(iface)) { + return true; } } + + // force stats update to make sure the service have the numbers that caused + // alert to trigger. + mNetworkStats.forceUpdate(); + + synchronized (mNetworkPoliciesSecondLock) { + updateNetworkRulesNL(); + updateNetworkEnabledNL(); + updateNotificationsNL(); + } return true; } case MSG_RESTRICT_BACKGROUND_CHANGED: { @@ -5304,16 +5304,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } private int parseSubId(NetworkState state) { - // TODO: moved to using a legitimate NetworkSpecifier instead of string parsing int subId = INVALID_SUBSCRIPTION_ID; if (state != null && state.networkCapabilities != null && state.networkCapabilities.hasTransport(TRANSPORT_CELLULAR)) { NetworkSpecifier spec = state.networkCapabilities.getNetworkSpecifier(); - if (spec instanceof StringNetworkSpecifier) { - try { - subId = Integer.parseInt(((StringNetworkSpecifier) spec).specifier); - } catch (NumberFormatException e) { - } + if (spec instanceof TelephonyNetworkSpecifier) { + subId = ((TelephonyNetworkSpecifier) spec).getSubscriptionId(); } } return subId; diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index 2705455078ff..349a0031613b 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -41,6 +41,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.ParcelFileDescriptor; +import android.os.ParcelableException; import android.os.PowerManager; import android.os.RemoteException; import android.os.ServiceManager; @@ -414,29 +415,28 @@ public class StagingManager { } else { params.installFlags |= PackageManager.INSTALL_DISABLE_VERIFICATION; } - int apkSessionId = mPi.createSession( - params, originalSession.getInstallerPackageName(), - 0 /* UserHandle.SYSTEM */); - PackageInstallerSession apkSession = mPi.getSession(apkSessionId); - try { + int apkSessionId = mPi.createSession( + params, originalSession.getInstallerPackageName(), + 0 /* UserHandle.SYSTEM */); + PackageInstallerSession apkSession = mPi.getSession(apkSessionId); apkSession.open(); for (String apkFilePath : apkFilePaths) { File apkFile = new File(apkFilePath); ParcelFileDescriptor pfd = ParcelFileDescriptor.open(apkFile, ParcelFileDescriptor.MODE_READ_ONLY); - long sizeBytes = pfd.getStatSize(); + long sizeBytes = (pfd == null) ? -1 : pfd.getStatSize(); if (sizeBytes < 0) { Slog.e(TAG, "Unable to get size of: " + apkFilePath); return null; } apkSession.write(apkFile.getName(), 0, sizeBytes, pfd); } - } catch (IOException e) { + return apkSession; + } catch (IOException | ParcelableException e) { Slog.e(TAG, "Failure to install APK staged session " + originalSession.sessionId, e); return null; } - return apkSession; } private boolean commitApkSession(@NonNull PackageInstallerSession apkSession, diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java index f56231fc02af..9e86a4bd2880 100644 --- a/services/core/java/com/android/server/pm/dex/DexManager.java +++ b/services/core/java/com/android/server/pm/dex/DexManager.java @@ -229,6 +229,7 @@ public class DexManager { // If the dex file is the primary apk (or a split) and not isUsedByOtherApps // do not record it. This case does not bring any new usable information // and can be safely skipped. + dexPathIndex++; continue; } diff --git a/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp b/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp index 9cd743b3466a..8b6526ff49f0 100644 --- a/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp +++ b/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp @@ -20,6 +20,7 @@ #include <inttypes.h> #include <sys/stat.h> #include <sys/types.h> +#include <vector> #include <jni.h> diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index b5b21f4189b4..c56634146c7b 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -1695,7 +1695,7 @@ public final class SystemServer { if (!isWatch && !disableNetworkTime) { traceBeginAndSlog("StartNetworkTimeUpdateService"); try { - networkTimeUpdater = new NetworkTimeUpdateServiceImpl(context); + networkTimeUpdater = new NetworkTimeUpdateService(context); ServiceManager.addService("network_time_update_service", networkTimeUpdater); } catch (Throwable e) { reportWtf("starting NetworkTimeUpdate service", e); diff --git a/services/net/Android.bp b/services/net/Android.bp index 9c7cfc197bba..cf84bdfb5b6f 100644 --- a/services/net/Android.bp +++ b/services/net/Android.bp @@ -23,7 +23,6 @@ filegroup { name: "services-tethering-shared-srcs", srcs: [ ":framework-annotations", - "java/android/net/util/NetdService.java", "java/android/net/util/NetworkConstants.java", ], visibility: ["//frameworks/base/packages/Tethering"], diff --git a/services/tests/mockingservicestests/AndroidManifest.xml b/services/tests/mockingservicestests/AndroidManifest.xml index 32d7d026ff10..1200c0c8c7bd 100644 --- a/services/tests/mockingservicestests/AndroidManifest.xml +++ b/services/tests/mockingservicestests/AndroidManifest.xml @@ -20,6 +20,7 @@ <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" /> <uses-permission android:name="android.permission.HARDWARE_TEST"/> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> + <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" /> <application android:testOnly="true" android:debuggable="true"> diff --git a/services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java index 71661452d800..698e491a8926 100644 --- a/services/tests/servicestests/src/com/android/server/appop/AppOpsServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/appop/AppOpsServiceTest.java @@ -25,14 +25,27 @@ import static android.app.AppOpsManager.OP_READ_SMS; import static android.app.AppOpsManager.OP_WIFI_SCAN; import static android.app.AppOpsManager.OP_WRITE_SMS; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.when; + import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.nullable; + import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.AppOpsManager.OpEntry; import android.app.AppOpsManager.PackageOps; import android.content.Context; +import android.content.pm.PackageManagerInternal; import android.os.Handler; import android.os.HandlerThread; import android.os.Process; @@ -43,12 +56,17 @@ import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.dx.mockito.inline.extended.StaticMockitoSession; +import com.android.server.LocalServices; + +import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.quality.Strictness; import java.io.File; import java.util.List; @@ -69,21 +87,46 @@ public class AppOpsServiceTest { // State will be persisted into this XML file. private static final String APP_OPS_FILENAME = "appops-service-test.xml"; + private static final Context sContext = InstrumentationRegistry.getTargetContext(); + private static final String sMyPackageName = sContext.getOpPackageName(); + private File mAppOpsFile; - private Context mContext; private Handler mHandler; - private AppOpsManager mAppOpsManager; private AppOpsService mAppOpsService; - private String mMyPackageName; private int mMyUid; private long mTestStartMillis; + private StaticMockitoSession mMockingSession; + + @Before + public void mockPackageManagerInternalGetApplicationInfo() { + mMockingSession = mockitoSession() + .strictness(Strictness.LENIENT) + .spyStatic(LocalServices.class) + .startMocking(); + + // Mock LocalServices.getService(PackageManagerInternal.class).getApplicationInfo dependency + // needed by AppOpsService + PackageManagerInternal mockPackageManagerInternal = mock(PackageManagerInternal.class); + when(mockPackageManagerInternal.getApplicationInfo(eq(sMyPackageName), anyInt(), anyInt(), + anyInt())).thenReturn(sContext.getApplicationInfo()); + doReturn(mockPackageManagerInternal).when( + () -> LocalServices.getService(PackageManagerInternal.class)); + } + + private void setupAppOpsService() { + mAppOpsService = new AppOpsService(mAppOpsFile, mHandler); + mAppOpsService.mContext = spy(sContext); + + // Always approve all permission checks + doNothing().when(mAppOpsService.mContext).enforcePermission(anyString(), anyInt(), + anyInt(), nullable(String.class)); + } private static String sDefaultAppopHistoryParameters; @Before public void setUp() { - mContext = InstrumentationRegistry.getTargetContext(); - mAppOpsFile = new File(mContext.getFilesDir(), APP_OPS_FILENAME); + mAppOpsFile = new File(sContext.getFilesDir(), APP_OPS_FILENAME); if (mAppOpsFile.exists()) { // Start with a clean state (persisted into XML). mAppOpsFile.delete(); @@ -92,13 +135,10 @@ public class AppOpsServiceTest { HandlerThread handlerThread = new HandlerThread(TAG); handlerThread.start(); mHandler = new Handler(handlerThread.getLooper()); - mMyPackageName = mContext.getOpPackageName(); mMyUid = Process.myUid(); - mAppOpsManager = mContext.getSystemService(AppOpsManager.class); - mAppOpsService = new AppOpsService(mAppOpsFile, mHandler); - mAppOpsService.mHistoricalRegistry.systemReady(mContext.getContentResolver()); - mAppOpsService.mContext = mContext; + setupAppOpsService(); + mAppOpsService.mHistoricalRegistry.systemReady(sContext.getContentResolver()); mTestStartMillis = System.currentTimeMillis(); } @@ -118,6 +158,11 @@ public class AppOpsServiceTest { sDefaultAppopHistoryParameters); } + @After + public void resetStaticMocks() { + mMockingSession.finishMocking(); + } + @Test public void testGetOpsForPackage_noOpsLogged() { assertThat(getLoggedOps()).isNull(); @@ -125,16 +170,16 @@ public class AppOpsServiceTest { @Test public void testNoteOperationAndGetOpsForPackage() { - mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED); - mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, mMyPackageName, MODE_ERRORED); + mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); + mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, sMyPackageName, MODE_ERRORED); // Note an op that's allowed. - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName); + mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName); List<PackageOps> loggedOps = getLoggedOps(); assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED); // Note another op that's not allowed. - mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, mMyPackageName); + mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, sMyPackageName); loggedOps = getLoggedOps(); assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED); assertContainsOp(loggedOps, OP_WRITE_SMS, -1, mTestStartMillis, MODE_ERRORED); @@ -148,17 +193,17 @@ public class AppOpsServiceTest { @Test public void testNoteOperationAndGetOpsForPackage_controlledByDifferentOp() { // This op controls WIFI_SCAN - mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, mMyPackageName, MODE_ALLOWED); + mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_ALLOWED); - assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, sMyPackageName)) .isEqualTo(MODE_ALLOWED); assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, -1, MODE_ALLOWED /* default for WIFI_SCAN; this is not changed or used in this test */); // Now set COARSE_LOCATION to ERRORED -> this will make WIFI_SCAN disabled as well. - mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, mMyPackageName, MODE_ERRORED); - assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, mMyPackageName)) + mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_ERRORED); + assertThat(mAppOpsService.noteOperation(OP_WIFI_SCAN, mMyUid, sMyPackageName)) .isEqualTo(MODE_ERRORED); assertContainsOp(getLoggedOps(), OP_WIFI_SCAN, mTestStartMillis, mTestStartMillis, @@ -168,15 +213,14 @@ public class AppOpsServiceTest { // Tests the dumping and restoring of the in-memory state to/from XML. @Test public void testStatePersistence() { - mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED); - mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, mMyPackageName, MODE_ERRORED); - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName); - mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, mMyPackageName); + mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); + mAppOpsService.setMode(OP_WRITE_SMS, mMyUid, sMyPackageName, MODE_ERRORED); + mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName); + mAppOpsService.noteOperation(OP_WRITE_SMS, mMyUid, sMyPackageName); mAppOpsService.writeState(); // Create a new app ops service, and initialize its state from XML. - mAppOpsService = new AppOpsService(mAppOpsFile, mHandler); - mAppOpsService.mContext = mContext; + setupAppOpsService(); mAppOpsService.readState(); // Query the state of the 2nd service. @@ -188,13 +232,12 @@ public class AppOpsServiceTest { // Tests that ops are persisted during shutdown. @Test public void testShutdown() { - mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED); - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName); + mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); + mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName); mAppOpsService.shutdown(); // Create a new app ops service, and initialize its state from XML. - mAppOpsService = new AppOpsService(mAppOpsFile, mHandler); - mAppOpsService.mContext = mContext; + setupAppOpsService(); mAppOpsService.readState(); // Query the state of the 2nd service. @@ -204,21 +247,21 @@ public class AppOpsServiceTest { @Test public void testGetOpsForPackage() { - mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED); - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName); + mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); + mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName); // Query all ops List<PackageOps> loggedOps = mAppOpsService.getOpsForPackage( - mMyUid, mMyPackageName, null /* all ops */); + mMyUid, sMyPackageName, null /* all ops */); assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED); // Query specific ops loggedOps = mAppOpsService.getOpsForPackage( - mMyUid, mMyPackageName, new int[]{OP_READ_SMS, OP_WRITE_SMS}); + mMyUid, sMyPackageName, new int[]{OP_READ_SMS, OP_WRITE_SMS}); assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED); // Query unknown UID - loggedOps = mAppOpsService.getOpsForPackage(mMyUid + 1, mMyPackageName, null /* all ops */); + loggedOps = mAppOpsService.getOpsForPackage(mMyUid + 1, sMyPackageName, null /* all ops */); assertThat(loggedOps).isNull(); // Query unknown package name @@ -226,31 +269,31 @@ public class AppOpsServiceTest { assertThat(loggedOps).isNull(); // Query op code that's not been logged - loggedOps = mAppOpsService.getOpsForPackage(mMyUid, mMyPackageName, + loggedOps = mAppOpsService.getOpsForPackage(mMyUid, sMyPackageName, new int[]{OP_WRITE_SMS}); assertThat(loggedOps).isNull(); } @Test public void testPackageRemoved() { - mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED); - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName); + mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); + mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName); List<PackageOps> loggedOps = getLoggedOps(); assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED); - mAppOpsService.packageRemoved(mMyUid, mMyPackageName); + mAppOpsService.packageRemoved(mMyUid, sMyPackageName); assertThat(getLoggedOps()).isNull(); } @Ignore("Historical appops are disabled in Android Q") @Test public void testPackageRemovedHistoricalOps() throws InterruptedException { - mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED); - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName); + mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); + mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName); AppOpsManager.HistoricalOps historicalOps = new AppOpsManager.HistoricalOps(0, 15000); - historicalOps.increaseAccessCount(OP_READ_SMS, mMyUid, mMyPackageName, + historicalOps.increaseAccessCount(OP_READ_SMS, mMyUid, sMyPackageName, AppOpsManager.UID_STATE_PERSISTENT, 0, 1); mAppOpsService.addHistoricalOps(historicalOps); @@ -263,7 +306,7 @@ public class AppOpsServiceTest { }); // First, do a fetch to ensure it's written - mAppOpsService.getHistoricalOps(mMyUid, mMyPackageName, null, 0, Long.MAX_VALUE, 0, + mAppOpsService.getHistoricalOps(mMyUid, sMyPackageName, null, 0, Long.MAX_VALUE, 0, callback); latchRef.get().await(5, TimeUnit.SECONDS); @@ -271,11 +314,11 @@ public class AppOpsServiceTest { assertThat(resultOpsRef.get().isEmpty()).isFalse(); // Then, check it's deleted on removal - mAppOpsService.packageRemoved(mMyUid, mMyPackageName); + mAppOpsService.packageRemoved(mMyUid, sMyPackageName); latchRef.set(new CountDownLatch(1)); - mAppOpsService.getHistoricalOps(mMyUid, mMyPackageName, null, 0, Long.MAX_VALUE, 0, + mAppOpsService.getHistoricalOps(mMyUid, sMyPackageName, null, 0, Long.MAX_VALUE, 0, callback); latchRef.get().await(5, TimeUnit.SECONDS); @@ -285,8 +328,8 @@ public class AppOpsServiceTest { @Test public void testUidRemoved() { - mAppOpsService.setMode(OP_READ_SMS, mMyUid, mMyPackageName, MODE_ALLOWED); - mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, mMyPackageName); + mAppOpsService.setMode(OP_READ_SMS, mMyUid, sMyPackageName, MODE_ALLOWED); + mAppOpsService.noteOperation(OP_READ_SMS, mMyUid, sMyPackageName); List<PackageOps> loggedOps = getLoggedOps(); assertContainsOp(loggedOps, OP_READ_SMS, mTestStartMillis, -1, MODE_ALLOWED); @@ -297,7 +340,7 @@ public class AppOpsServiceTest { private void setupProcStateTests() { // For the location proc state tests - mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, mMyPackageName, MODE_FOREGROUND); + mAppOpsService.setMode(OP_COARSE_LOCATION, mMyUid, sMyPackageName, MODE_FOREGROUND); mAppOpsService.mConstants.FG_SERVICE_STATE_SETTLE_TIME = 0; mAppOpsService.mConstants.TOP_STATE_SETTLE_TIME = 0; mAppOpsService.mConstants.BG_STATE_SETTLE_TIME = 0; @@ -308,18 +351,18 @@ public class AppOpsServiceTest { setupProcStateTests(); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); // Second time to make sure that settle time is overcome Thread.sleep(50); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); } @@ -328,11 +371,11 @@ public class AppOpsServiceTest { setupProcStateTests(); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); } @@ -341,12 +384,12 @@ public class AppOpsServiceTest { setupProcStateTests(); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE_LOCATION); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isEqualTo(MODE_ALLOWED); } @@ -355,18 +398,18 @@ public class AppOpsServiceTest { setupProcStateTests(); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE); // Second time to make sure that settle time is overcome Thread.sleep(50); mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); } @@ -375,30 +418,30 @@ public class AppOpsServiceTest { setupProcStateTests(); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_CACHED_EMPTY); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, ActivityManager.PROCESS_STATE_TOP); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE_LOCATION); // Second time to make sure that settle time is overcome Thread.sleep(50); mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE_LOCATION); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isEqualTo(MODE_ALLOWED); mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE); // Second time to make sure that settle time is overcome Thread.sleep(50); mAppOpsService.updateUidProcState(mMyUid, PROCESS_STATE_FOREGROUND_SERVICE); - assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, mMyPackageName)) + assertThat(mAppOpsService.noteOperation(OP_COARSE_LOCATION, mMyUid, sMyPackageName)) .isNotEqualTo(MODE_ALLOWED); } private List<PackageOps> getLoggedOps() { - return mAppOpsService.getOpsForPackage(mMyUid, mMyPackageName, null /* all ops */); + return mAppOpsService.getOpsForPackage(mMyUid, sMyPackageName, null /* all ops */); } private void assertContainsOp(List<PackageOps> loggedOps, int opCode, long minMillis, @@ -407,7 +450,7 @@ public class AppOpsServiceTest { boolean opLogged = false; for (PackageOps pkgOps : loggedOps) { assertWithMessage("Unexpected UID").that(mMyUid).isEqualTo(pkgOps.getUid()); - assertWithMessage("Unexpected package name").that(mMyPackageName).isEqualTo( + assertWithMessage("Unexpected package name").that(sMyPackageName).isEqualTo( pkgOps.getPackageName()); for (OpEntry opEntry : pkgOps.getOps()) { diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java index 19369dbe5f44..6c29f6050276 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/TimeControllerTest.java @@ -530,6 +530,46 @@ public class TimeControllerTest { } @Test + public void testJobDelayWakeupAlarmToggling() { + final long now = JobSchedulerService.sElapsedRealtimeClock.millis(); + + JobStatus job = createJobStatus( + "testMaybeStartTrackingJobLocked_DeadlineReverseOrder", + createJob().setMinimumLatency(HOUR_IN_MILLIS)); + + doReturn(true).when(mTimeController) + .wouldBeReadyWithConstraintLocked(eq(job), anyInt()); + + // Starting off with using a wakeup alarm. + mConstants.USE_NON_WAKEUP_ALARM_FOR_DELAY = false; + InOrder inOrder = inOrder(mAlarmManager); + + mTimeController.maybeStartTrackingJobLocked(job, null); + inOrder.verify(mAlarmManager, times(1)) + .set(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), eq(now + HOUR_IN_MILLIS), anyLong(), + anyLong(), + eq(TAG_DELAY), any(), any(), any()); + + // Use a non wakeup alarm. + mConstants.USE_NON_WAKEUP_ALARM_FOR_DELAY = true; + + mTimeController.maybeStartTrackingJobLocked(job, null); + inOrder.verify(mAlarmManager, times(1)) + .set(eq(AlarmManager.ELAPSED_REALTIME), eq(now + HOUR_IN_MILLIS), anyLong(), + anyLong(), eq(TAG_DELAY), + any(), any(), any()); + + // Back off, use a wakeup alarm. + mConstants.USE_NON_WAKEUP_ALARM_FOR_DELAY = false; + + mTimeController.maybeStartTrackingJobLocked(job, null); + inOrder.verify(mAlarmManager, times(1)) + .set(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), eq(now + HOUR_IN_MILLIS), anyLong(), + anyLong(), + eq(TAG_DELAY), any(), any(), any()); + } + + @Test public void testCheckExpiredDelaysAndResetAlarm_WithSkipping_AllReady() { mConstants.SKIP_NOT_READY_JOBS = true; mTimeController.recheckAlarmsLocked(); diff --git a/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java b/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java index 50437b4d5f3e..d367f71de921 100644 --- a/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/DynamicSystemServiceTest.java @@ -36,7 +36,7 @@ public class DynamicSystemServiceTest extends AndroidTestCase { public void test1() { assertTrue("dynamic_system service available", mService != null); try { - mService.startInstallation(); + mService.startInstallation("dsu"); fail("DynamicSystemService did not throw SecurityException as expected"); } catch (SecurityException e) { // expected diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java index 07b17ebdeb63..ca5dfb133345 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java @@ -16,7 +16,7 @@ package com.android.server; -import static android.net.NetworkScoreManager.CACHE_FILTER_NONE; +import static android.net.NetworkScoreManager.SCORE_FILTER_NONE; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; @@ -304,7 +304,7 @@ public class NetworkScoreServiceTest { bindToScorer(true /*callerIsScorer*/); mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, - mNetworkScoreCache, CACHE_FILTER_NONE); + mNetworkScoreCache, SCORE_FILTER_NONE); mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK}); @@ -319,9 +319,9 @@ public class NetworkScoreServiceTest { bindToScorer(true /*callerIsScorer*/); mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, - mNetworkScoreCache, CACHE_FILTER_NONE); + mNetworkScoreCache, SCORE_FILTER_NONE); mNetworkScoreService.registerNetworkScoreCache( - NetworkKey.TYPE_WIFI, mNetworkScoreCache2, CACHE_FILTER_NONE); + NetworkKey.TYPE_WIFI, mNetworkScoreCache2, SCORE_FILTER_NONE); // updateScores should update both caches mNetworkScoreService.updateScores(new ScoredNetwork[]{SCORED_NETWORK}); @@ -376,7 +376,7 @@ public class NetworkScoreServiceTest { bindToScorer(true /*callerIsScorer*/); mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache, - CACHE_FILTER_NONE); + SCORE_FILTER_NONE); mNetworkScoreService.clearScores(); verify(mNetworkScoreCache).clearScores(); @@ -390,7 +390,7 @@ public class NetworkScoreServiceTest { .thenReturn(PackageManager.PERMISSION_GRANTED); mNetworkScoreService.registerNetworkScoreCache(NetworkKey.TYPE_WIFI, mNetworkScoreCache, - CACHE_FILTER_NONE); + SCORE_FILTER_NONE); mNetworkScoreService.clearScores(); verify(mNetworkScoreCache).clearScores(); @@ -470,7 +470,7 @@ public class NetworkScoreServiceTest { try { mNetworkScoreService.registerNetworkScoreCache( - NetworkKey.TYPE_WIFI, mNetworkScoreCache, CACHE_FILTER_NONE); + NetworkKey.TYPE_WIFI, mNetworkScoreCache, SCORE_FILTER_NONE); fail("SecurityException expected"); } catch (SecurityException e) { // expected @@ -613,7 +613,7 @@ public class NetworkScoreServiceTest { new ArrayList<>(scoredNetworkList), NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter); - consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_NONE); + consumer.accept(mNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_NONE); verify(mNetworkScoreCache).updateScores(scoredNetworkList); verifyZeroInteractions(mCurrentNetworkFilter, mScanResultsFilter); @@ -654,7 +654,7 @@ public class NetworkScoreServiceTest { Collections.emptyList(), NetworkKey.TYPE_WIFI, mCurrentNetworkFilter, mScanResultsFilter); - consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_NONE); + consumer.accept(mNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_NONE); verifyZeroInteractions(mNetworkScoreCache, mCurrentNetworkFilter, mScanResultsFilter); } @@ -671,7 +671,7 @@ public class NetworkScoreServiceTest { List<ScoredNetwork> filteredList = new ArrayList<>(scoredNetworkList); filteredList.remove(SCORED_NETWORK); when(mCurrentNetworkFilter.apply(scoredNetworkList)).thenReturn(filteredList); - consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_CURRENT_NETWORK); + consumer.accept(mNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_CURRENT_NETWORK); verify(mNetworkScoreCache).updateScores(filteredList); verifyZeroInteractions(mScanResultsFilter); @@ -689,7 +689,7 @@ public class NetworkScoreServiceTest { List<ScoredNetwork> filteredList = new ArrayList<>(scoredNetworkList); filteredList.remove(SCORED_NETWORK); when(mScanResultsFilter.apply(scoredNetworkList)).thenReturn(filteredList); - consumer.accept(mNetworkScoreCache, NetworkScoreManager.CACHE_FILTER_SCAN_RESULTS); + consumer.accept(mNetworkScoreCache, NetworkScoreManager.SCORE_FILTER_SCAN_RESULTS); verify(mNetworkScoreCache).updateScores(filteredList); verifyZeroInteractions(mCurrentNetworkFilter); diff --git a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java index ecd07bdc4544..b14291b34195 100644 --- a/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java +++ b/services/tests/servicestests/src/com/android/server/compat/OverrideValidatorImplTest.java @@ -188,7 +188,7 @@ public class OverrideValidatorImplTest { } @Test - public void getOverrideAllowedState_betaBuildEnabledChangeDebugApp_rejectOverride() + public void getOverrideAllowedState_betaBuildEnabledChangeDebugApp_allowOverride() throws Exception { CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext) .addEnabledChangeWithId(1).build(); @@ -203,11 +203,11 @@ public class OverrideValidatorImplTest { overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); assertThat(allowedState) - .isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1)); + .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1)); } @Test - public void getOverrideAllowedState_betaBuildDisabledChangeDebugApp_rejectOverride() + public void getOverrideAllowedState_betaBuildDisabledChangeDebugApp_allowOverride() throws Exception { CompatConfig config = CompatConfigBuilder.create(betaBuild(), mContext) .addDisabledChangeWithId(1).build(); @@ -221,7 +221,7 @@ public class OverrideValidatorImplTest { overrideValidator.getOverrideAllowedState(1, PACKAGE_NAME); assertThat(allowedState) - .isEqualTo(new OverrideAllowedState(DISABLED_NON_TARGET_SDK, -1, -1)); + .isEqualTo(new OverrideAllowedState(ALLOWED, -1, -1)); } @Test diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java index 2c941c604f3f..2e58ad68fc7c 100644 --- a/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/net/NetworkPolicyManagerServiceTest.java @@ -112,7 +112,7 @@ import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; -import android.net.StringNetworkSpecifier; +import android.net.TelephonyNetworkSpecifier; import android.os.Binder; import android.os.Handler; import android.os.INetworkManagementService; @@ -1729,9 +1729,11 @@ public class NetworkPolicyManagerServiceTest { .getService(NetworkPolicyManagerInternal.class); npmi.onStatsProviderLimitReached("TEST"); - // Verifies that the limit reached leads to a force update. + // Verifies that the limit reached leads to a force update and new limit should be set. postMsgAndWaitForCompletion(); verify(mStatsService).forceUpdate(); + postMsgAndWaitForCompletion(); + verify(mStatsService).setStatsProviderLimit(TEST_IFACE, 10000L - 4999L - 1999L); } /** @@ -1836,7 +1838,8 @@ public class NetworkPolicyManagerServiceTest { if (!roaming) { nc.addCapability(NET_CAPABILITY_NOT_ROAMING); } - nc.setNetworkSpecifier(new StringNetworkSpecifier(String.valueOf(subId))); + nc.setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder() + .setSubscriptionId(subId).build()); return nc; } diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java index 0196279cbf56..a4ba056b96a8 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java @@ -160,6 +160,31 @@ public class DexManagerTests { } @Test + public void testNotifyPrimaryAndSecondary() { + List<String> dexFiles = mFooUser0.getBaseAndSplitDexPaths(); + List<String> secondaries = mFooUser0.getSecondaryDexPaths(); + int baseAndSplitCount = dexFiles.size(); + dexFiles.addAll(secondaries); + + notifyDexLoad(mFooUser0, dexFiles, mUser0); + + PackageUseInfo pui = getPackageUseInfo(mFooUser0); + assertIsUsedByOtherApps(mFooUser0, pui, false); + assertEquals(secondaries.size(), pui.getDexUseInfoMap().size()); + + String[] allExpectedContexts = DexoptUtils.processContextForDexLoad( + Arrays.asList(mFooUser0.mClassLoader), + Arrays.asList(String.join(File.pathSeparator, dexFiles))); + String[] secondaryExpectedContexts = Arrays.copyOfRange(allExpectedContexts, + baseAndSplitCount, dexFiles.size()); + + assertSecondaryUse(mFooUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0, + secondaryExpectedContexts); + + assertHasDclInfo(mFooUser0, mFooUser0, secondaries); + } + + @Test public void testNotifySecondaryForeign() { // Foo loads bar secondary files. List<String> barSecondaries = mBarUser0.getSecondaryDexPaths(); diff --git a/telecomm/java/android/telecom/AudioState.java b/telecomm/java/android/telecom/AudioState.java index 8b8c86be7b0a..ea641f866b98 100644 --- a/telecomm/java/android/telecom/AudioState.java +++ b/telecomm/java/android/telecom/AudioState.java @@ -19,7 +19,7 @@ package android.telecom; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java index 86ad795b9ea2..826a89eb38bb 100644 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -20,12 +20,11 @@ import android.annotation.IntDef; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.os.Handler; -import android.os.IBinder; import android.os.ParcelFileDescriptor; import com.android.internal.telecom.IVideoProvider; @@ -569,6 +568,7 @@ public final class Call { private final Bundle mExtras; private final Bundle mIntentExtras; private final long mCreationTimeMillis; + private final String mContactDisplayName; private final @CallDirection int mCallDirection; private final @Connection.VerificationStatus int mCallerNumberVerificationStatus; @@ -873,6 +873,17 @@ public final class Call { } /** + * Returns the name of the caller on the remote end, as derived from a + * {@link android.provider.ContactsContract} lookup of the call's handle. + * @return The name of the caller, or {@code null} if the lookup is not yet complete, if + * there's no contacts entry for the caller, or if the {@link InCallService} does + * not hold the {@link android.Manifest.permission#READ_CONTACTS} permission. + */ + public @Nullable String getContactDisplayName() { + return mContactDisplayName; + } + + /** * Indicates whether the call is an incoming or outgoing call. * @return The call's direction. */ @@ -910,6 +921,7 @@ public final class Call { areBundlesEqual(mExtras, d.mExtras) && areBundlesEqual(mIntentExtras, d.mIntentExtras) && Objects.equals(mCreationTimeMillis, d.mCreationTimeMillis) && + Objects.equals(mContactDisplayName, d.mContactDisplayName) && Objects.equals(mCallDirection, d.mCallDirection) && Objects.equals(mCallerNumberVerificationStatus, d.mCallerNumberVerificationStatus); @@ -934,6 +946,7 @@ public final class Call { mExtras, mIntentExtras, mCreationTimeMillis, + mContactDisplayName, mCallDirection, mCallerNumberVerificationStatus); } @@ -956,6 +969,7 @@ public final class Call { Bundle extras, Bundle intentExtras, long creationTimeMillis, + String contactDisplayName, int callDirection, int callerNumberVerificationStatus) { mTelecomCallId = telecomCallId; @@ -974,6 +988,7 @@ public final class Call { mExtras = extras; mIntentExtras = intentExtras; mCreationTimeMillis = creationTimeMillis; + mContactDisplayName = contactDisplayName; mCallDirection = callDirection; mCallerNumberVerificationStatus = callerNumberVerificationStatus; } @@ -997,6 +1012,7 @@ public final class Call { parcelableCall.getExtras(), parcelableCall.getIntentExtras(), parcelableCall.getCreationTimeMillis(), + parcelableCall.getContactDisplayName(), parcelableCall.getCallDirection(), parcelableCall.getCallerNumberVerificationStatus()); } @@ -1446,6 +1462,7 @@ public final class Call { private boolean mChildrenCached; private String mParentId = null; + private String mActiveGenericConferenceChild = null; private int mState; private List<String> mCannedTextResponses = null; private String mCallingPackage; @@ -1944,6 +1961,20 @@ public final class Call { } /** + * Returns the child {@link Call} in a generic conference that is currently active. + * For calls that are not generic conferences, or when the generic conference has more than + * 2 children, returns {@code null}. + * @see Details#PROPERTY_GENERIC_CONFERENCE + * @return The active child call. + */ + public @Nullable Call getGenericConferenceActiveChildCall() { + if (mActiveGenericConferenceChild != null) { + return mPhone.internalGetCallByTelecomId(mActiveGenericConferenceChild); + } + return null; + } + + /** * Obtains a list of canned, pre-configured message responses to present to the user as * ways of rejecting this {@code Call} using via a text message. * @@ -2191,6 +2222,13 @@ public final class Call { mChildrenCached = false; } + String activeChildCallId = parcelableCall.getActiveChildCallId(); + boolean activeChildChanged = !Objects.equals(activeChildCallId, + mActiveGenericConferenceChild); + if (activeChildChanged) { + mActiveGenericConferenceChild = activeChildCallId; + } + List<String> conferenceableCallIds = parcelableCall.getConferenceableCallIds(); List<Call> conferenceableCalls = new ArrayList<Call>(conferenceableCallIds.size()); for (String otherId : conferenceableCallIds) { @@ -2250,7 +2288,7 @@ public final class Call { if (parentChanged) { fireParentChanged(getParent()); } - if (childrenChanged) { + if (childrenChanged || activeChildChanged) { fireChildrenChanged(getChildren()); } if (isRttChanged) { diff --git a/telecomm/java/android/telecom/CallerInfo.java b/telecomm/java/android/telecom/CallerInfo.java index a5d25e2ce4bb..fb6f99405759 100644 --- a/telecomm/java/android/telecom/CallerInfo.java +++ b/telecomm/java/android/telecom/CallerInfo.java @@ -17,7 +17,7 @@ package android.telecom; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; @@ -41,8 +41,8 @@ import com.android.i18n.phonenumbers.NumberParseException; import com.android.i18n.phonenumbers.PhoneNumberUtil; import com.android.i18n.phonenumbers.Phonenumber.PhoneNumber; import com.android.i18n.phonenumbers.geocoding.PhoneNumberOfflineGeocoder; - import com.android.internal.annotations.VisibleForTesting; + import java.util.Locale; diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index 8808339b1664..f205ec64f49b 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -21,9 +21,9 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.Notification; import android.bluetooth.BluetoothDevice; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Intent; import android.hardware.camera2.CameraManager; import android.net.Uri; diff --git a/telecomm/java/android/telecom/Log.java b/telecomm/java/android/telecom/Log.java index 7d4ee7686512..4f6a9d6450f8 100644 --- a/telecomm/java/android/telecom/Log.java +++ b/telecomm/java/android/telecom/Log.java @@ -16,7 +16,7 @@ package android.telecom; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.net.Uri; import android.os.Build; diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java index a234bb0af8fa..415a817b58d5 100644 --- a/telecomm/java/android/telecom/ParcelableCall.java +++ b/telecomm/java/android/telecom/ParcelableCall.java @@ -16,27 +16,286 @@ package android.telecom; -import android.annotation.UnsupportedAppUsage; +import android.annotation.Nullable; +import android.compat.annotation.UnsupportedAppUsage; import android.net.Uri; import android.os.Build; import android.os.Bundle; -import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; import android.telecom.Call.Details.CallDirection; +import com.android.internal.telecom.IVideoProvider; + import java.util.ArrayList; import java.util.Collections; import java.util.List; -import com.android.internal.telecom.IVideoProvider; - /** * Information about a call that is used between InCallService and Telecom. * @hide */ public final class ParcelableCall implements Parcelable { + + public static class ParcelableCallBuilder { + private String mId; + private int mState; + private DisconnectCause mDisconnectCause; + private List<String> mCannedSmsResponses; + private int mCapabilities; + private int mProperties; + private int mSupportedAudioRoutes; + private long mConnectTimeMillis; + private Uri mHandle; + private int mHandlePresentation; + private String mCallerDisplayName; + private int mCallerDisplayNamePresentation; + private GatewayInfo mGatewayInfo; + private PhoneAccountHandle mAccountHandle; + private boolean mIsVideoCallProviderChanged; + private IVideoProvider mVideoCallProvider; + private boolean mIsRttCallChanged; + private ParcelableRttCall mRttCall; + private String mParentCallId; + private List<String> mChildCallIds; + private StatusHints mStatusHints; + private int mVideoState; + private List<String> mConferenceableCallIds; + private Bundle mIntentExtras; + private Bundle mExtras; + private long mCreationTimeMillis; + private int mCallDirection; + private int mCallerNumberVerificationStatus; + private String mContactDisplayName; + private String mActiveChildCallId; + + public ParcelableCallBuilder setId(String id) { + mId = id; + return this; + } + + public ParcelableCallBuilder setState(int state) { + mState = state; + return this; + } + + public ParcelableCallBuilder setDisconnectCause(DisconnectCause disconnectCause) { + mDisconnectCause = disconnectCause; + return this; + } + + public ParcelableCallBuilder setCannedSmsResponses(List<String> cannedSmsResponses) { + mCannedSmsResponses = cannedSmsResponses; + return this; + } + + public ParcelableCallBuilder setCapabilities(int capabilities) { + mCapabilities = capabilities; + return this; + } + + public ParcelableCallBuilder setProperties(int properties) { + mProperties = properties; + return this; + } + + public ParcelableCallBuilder setSupportedAudioRoutes(int supportedAudioRoutes) { + mSupportedAudioRoutes = supportedAudioRoutes; + return this; + } + + public ParcelableCallBuilder setConnectTimeMillis(long connectTimeMillis) { + mConnectTimeMillis = connectTimeMillis; + return this; + } + + public ParcelableCallBuilder setHandle(Uri handle) { + mHandle = handle; + return this; + } + + public ParcelableCallBuilder setHandlePresentation(int handlePresentation) { + mHandlePresentation = handlePresentation; + return this; + } + + public ParcelableCallBuilder setCallerDisplayName(String callerDisplayName) { + mCallerDisplayName = callerDisplayName; + return this; + } + + public ParcelableCallBuilder setCallerDisplayNamePresentation( + int callerDisplayNamePresentation) { + mCallerDisplayNamePresentation = callerDisplayNamePresentation; + return this; + } + + public ParcelableCallBuilder setGatewayInfo(GatewayInfo gatewayInfo) { + mGatewayInfo = gatewayInfo; + return this; + } + + public ParcelableCallBuilder setAccountHandle(PhoneAccountHandle accountHandle) { + mAccountHandle = accountHandle; + return this; + } + + public ParcelableCallBuilder setIsVideoCallProviderChanged( + boolean isVideoCallProviderChanged) { + mIsVideoCallProviderChanged = isVideoCallProviderChanged; + return this; + } + + public ParcelableCallBuilder setVideoCallProvider(IVideoProvider videoCallProvider) { + mVideoCallProvider = videoCallProvider; + return this; + } + + public ParcelableCallBuilder setIsRttCallChanged(boolean isRttCallChanged) { + mIsRttCallChanged = isRttCallChanged; + return this; + } + + public ParcelableCallBuilder setRttCall(ParcelableRttCall rttCall) { + mRttCall = rttCall; + return this; + } + + public ParcelableCallBuilder setParentCallId(String parentCallId) { + mParentCallId = parentCallId; + return this; + } + + public ParcelableCallBuilder setChildCallIds(List<String> childCallIds) { + mChildCallIds = childCallIds; + return this; + } + + public ParcelableCallBuilder setStatusHints(StatusHints statusHints) { + mStatusHints = statusHints; + return this; + } + + public ParcelableCallBuilder setVideoState(int videoState) { + mVideoState = videoState; + return this; + } + + public ParcelableCallBuilder setConferenceableCallIds( + List<String> conferenceableCallIds) { + mConferenceableCallIds = conferenceableCallIds; + return this; + } + + public ParcelableCallBuilder setIntentExtras(Bundle intentExtras) { + mIntentExtras = intentExtras; + return this; + } + + public ParcelableCallBuilder setExtras(Bundle extras) { + mExtras = extras; + return this; + } + + public ParcelableCallBuilder setCreationTimeMillis(long creationTimeMillis) { + mCreationTimeMillis = creationTimeMillis; + return this; + } + + public ParcelableCallBuilder setCallDirection(int callDirection) { + mCallDirection = callDirection; + return this; + } + + public ParcelableCallBuilder setCallerNumberVerificationStatus( + int callerNumberVerificationStatus) { + mCallerNumberVerificationStatus = callerNumberVerificationStatus; + return this; + } + + public ParcelableCallBuilder setContactDisplayName(String contactDisplayName) { + mContactDisplayName = contactDisplayName; + return this; + } + + public ParcelableCallBuilder setActiveChildCallId(String activeChildCallId) { + mActiveChildCallId = activeChildCallId; + return this; + } + + public ParcelableCall createParcelableCall() { + return new ParcelableCall( + mId, + mState, + mDisconnectCause, + mCannedSmsResponses, + mCapabilities, + mProperties, + mSupportedAudioRoutes, + mConnectTimeMillis, + mHandle, + mHandlePresentation, + mCallerDisplayName, + mCallerDisplayNamePresentation, + mGatewayInfo, + mAccountHandle, + mIsVideoCallProviderChanged, + mVideoCallProvider, + mIsRttCallChanged, + mRttCall, + mParentCallId, + mChildCallIds, + mStatusHints, + mVideoState, + mConferenceableCallIds, + mIntentExtras, + mExtras, + mCreationTimeMillis, + mCallDirection, + mCallerNumberVerificationStatus, + mContactDisplayName, + mActiveChildCallId); + } + + public static ParcelableCallBuilder fromParcelableCall(ParcelableCall parcelableCall) { + ParcelableCallBuilder newBuilder = new ParcelableCallBuilder(); + newBuilder.mId = parcelableCall.mId; + newBuilder.mState = parcelableCall.mState; + newBuilder.mDisconnectCause = parcelableCall.mDisconnectCause; + newBuilder.mCannedSmsResponses = parcelableCall.mCannedSmsResponses; + newBuilder.mCapabilities = parcelableCall.mCapabilities; + newBuilder.mProperties = parcelableCall.mProperties; + newBuilder.mSupportedAudioRoutes = parcelableCall.mSupportedAudioRoutes; + newBuilder.mConnectTimeMillis = parcelableCall.mConnectTimeMillis; + newBuilder.mHandle = parcelableCall.mHandle; + newBuilder.mHandlePresentation = parcelableCall.mHandlePresentation; + newBuilder.mCallerDisplayName = parcelableCall.mCallerDisplayName; + newBuilder.mCallerDisplayNamePresentation = + parcelableCall.mCallerDisplayNamePresentation; + newBuilder.mGatewayInfo = parcelableCall.mGatewayInfo; + newBuilder.mAccountHandle = parcelableCall.mAccountHandle; + newBuilder.mIsVideoCallProviderChanged = parcelableCall.mIsVideoCallProviderChanged; + newBuilder.mVideoCallProvider = parcelableCall.mVideoCallProvider; + newBuilder.mIsRttCallChanged = parcelableCall.mIsRttCallChanged; + newBuilder.mRttCall = parcelableCall.mRttCall; + newBuilder.mParentCallId = parcelableCall.mParentCallId; + newBuilder.mChildCallIds = parcelableCall.mChildCallIds; + newBuilder.mStatusHints = parcelableCall.mStatusHints; + newBuilder.mVideoState = parcelableCall.mVideoState; + newBuilder.mConferenceableCallIds = parcelableCall.mConferenceableCallIds; + newBuilder.mIntentExtras = parcelableCall.mIntentExtras; + newBuilder.mExtras = parcelableCall.mExtras; + newBuilder.mCreationTimeMillis = parcelableCall.mCreationTimeMillis; + newBuilder.mCallDirection = parcelableCall.mCallDirection; + newBuilder.mCallerNumberVerificationStatus = + parcelableCall.mCallerNumberVerificationStatus; + newBuilder.mContactDisplayName = parcelableCall.mContactDisplayName; + newBuilder.mActiveChildCallId = parcelableCall.mActiveChildCallId; + return newBuilder; + } + } + private final String mId; private final int mState; private final DisconnectCause mDisconnectCause; @@ -66,6 +325,8 @@ public final class ParcelableCall implements Parcelable { private final long mCreationTimeMillis; private final int mCallDirection; private final int mCallerNumberVerificationStatus; + private final String mContactDisplayName; + private final String mActiveChildCallId; // Only valid for CDMA conferences public ParcelableCall( String id, @@ -95,7 +356,10 @@ public final class ParcelableCall implements Parcelable { Bundle extras, long creationTimeMillis, int callDirection, - int callerNumberVerificationStatus) { + int callerNumberVerificationStatus, + String contactDisplayName, + String activeChildCallId + ) { mId = id; mState = state; mDisconnectCause = disconnectCause; @@ -124,6 +388,8 @@ public final class ParcelableCall implements Parcelable { mCreationTimeMillis = creationTimeMillis; mCallDirection = callDirection; mCallerNumberVerificationStatus = callerNumberVerificationStatus; + mContactDisplayName = contactDisplayName; + mActiveChildCallId = activeChildCallId; } /** The unique ID of the call. */ @@ -333,6 +599,21 @@ public final class ParcelableCall implements Parcelable { return mCallerNumberVerificationStatus; } + /** + * @return the name of the remote party as derived from a contacts DB lookup. + */ + public @Nullable String getContactDisplayName() { + return mContactDisplayName; + } + + /** + * @return On a CDMA conference with two participants, returns the ID of the child call that's + * currently active. + */ + public @Nullable String getActiveChildCallId() { + return mActiveChildCallId; + } + /** Responsible for creating ParcelableCall objects for deserialized Parcels. */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) public static final @android.annotation.NonNull Parcelable.Creator<ParcelableCall> CREATOR = @@ -372,35 +653,40 @@ public final class ParcelableCall implements Parcelable { long creationTimeMillis = source.readLong(); int callDirection = source.readInt(); int callerNumberVerificationStatus = source.readInt(); - return new ParcelableCall( - id, - state, - disconnectCause, - cannedSmsResponses, - capabilities, - properties, - supportedAudioRoutes, - connectTimeMillis, - handle, - handlePresentation, - callerDisplayName, - callerDisplayNamePresentation, - gatewayInfo, - accountHandle, - isVideoCallProviderChanged, - videoCallProvider, - isRttCallChanged, - rttCall, - parentCallId, - childCallIds, - statusHints, - videoState, - conferenceableCallIds, - intentExtras, - extras, - creationTimeMillis, - callDirection, - callerNumberVerificationStatus); + String contactDisplayName = source.readString(); + String activeChildCallId = source.readString(); + return new ParcelableCallBuilder() + .setId(id) + .setState(state) + .setDisconnectCause(disconnectCause) + .setCannedSmsResponses(cannedSmsResponses) + .setCapabilities(capabilities) + .setProperties(properties) + .setSupportedAudioRoutes(supportedAudioRoutes) + .setConnectTimeMillis(connectTimeMillis) + .setHandle(handle) + .setHandlePresentation(handlePresentation) + .setCallerDisplayName(callerDisplayName) + .setCallerDisplayNamePresentation(callerDisplayNamePresentation) + .setGatewayInfo(gatewayInfo) + .setAccountHandle(accountHandle) + .setIsVideoCallProviderChanged(isVideoCallProviderChanged) + .setVideoCallProvider(videoCallProvider) + .setIsRttCallChanged(isRttCallChanged) + .setRttCall(rttCall) + .setParentCallId(parentCallId) + .setChildCallIds(childCallIds) + .setStatusHints(statusHints) + .setVideoState(videoState) + .setConferenceableCallIds(conferenceableCallIds) + .setIntentExtras(intentExtras) + .setExtras(extras) + .setCreationTimeMillis(creationTimeMillis) + .setCallDirection(callDirection) + .setCallerNumberVerificationStatus(callerNumberVerificationStatus) + .setContactDisplayName(contactDisplayName) + .setActiveChildCallId(activeChildCallId) + .createParcelableCall(); } @Override @@ -447,6 +733,8 @@ public final class ParcelableCall implements Parcelable { destination.writeLong(mCreationTimeMillis); destination.writeInt(mCallDirection); destination.writeInt(mCallerNumberVerificationStatus); + destination.writeString(mContactDisplayName); + destination.writeString(mActiveChildCallId); } @Override diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java index 61a639a1a235..a427ed612b31 100644 --- a/telecomm/java/android/telecom/Phone.java +++ b/telecomm/java/android/telecom/Phone.java @@ -17,8 +17,8 @@ package android.telecom; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; import android.bluetooth.BluetoothDevice; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Bundle; import android.util.ArrayMap; diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java index eb568e04ebf3..e1bcb5fbdf00 100644 --- a/telecomm/java/android/telecom/PhoneAccountHandle.java +++ b/telecomm/java/android/telecom/PhoneAccountHandle.java @@ -18,7 +18,7 @@ package android.telecom; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.os.Build; import android.os.Parcel; diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index af3c55abf00c..ffb27797d340 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -26,7 +26,7 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -848,6 +848,17 @@ public class TelecomManager { */ public static final int PRESENTATION_PAYPHONE = 4; + + /* + * Values for the adb property "persist.radio.videocall.audio.output" + */ + /** @hide */ + public static final int AUDIO_OUTPUT_ENABLE_SPEAKER = 0; + /** @hide */ + public static final int AUDIO_OUTPUT_DISABLE_SPEAKER = 1; + /** @hide */ + public static final int AUDIO_OUTPUT_DEFAULT = AUDIO_OUTPUT_ENABLE_SPEAKER; + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef( diff --git a/telecomm/java/android/telecom/VideoCallImpl.java b/telecomm/java/android/telecom/VideoCallImpl.java index 4a1aa0a8ffa4..109e7f829f2e 100644 --- a/telecomm/java/android/telecom/VideoCallImpl.java +++ b/telecomm/java/android/telecom/VideoCallImpl.java @@ -16,7 +16,7 @@ package android.telecom; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.net.Uri; import android.os.Build; import android.os.Handler; diff --git a/telecomm/java/android/telecom/VideoProfile.java b/telecomm/java/android/telecom/VideoProfile.java index 64e6ca3416e3..4197f3cfc6c3 100644 --- a/telecomm/java/android/telecom/VideoProfile.java +++ b/telecomm/java/android/telecom/VideoProfile.java @@ -19,7 +19,6 @@ package android.telecom; import android.annotation.FloatRange; import android.annotation.IntDef; import android.annotation.IntRange; -import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; diff --git a/telephony/common/com/android/internal/telephony/GsmAlphabet.java b/telephony/common/com/android/internal/telephony/GsmAlphabet.java index f7383ab1f632..60cd40094950 100644 --- a/telephony/common/com/android/internal/telephony/GsmAlphabet.java +++ b/telephony/common/com/android/internal/telephony/GsmAlphabet.java @@ -16,7 +16,7 @@ package com.android.internal.telephony; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.os.Build; import android.util.Log; diff --git a/telephony/common/com/android/internal/telephony/SmsApplication.java b/telephony/common/com/android/internal/telephony/SmsApplication.java index 39ff44772cc9..3a900d9c224f 100644 --- a/telephony/common/com/android/internal/telephony/SmsApplication.java +++ b/telephony/common/com/android/internal/telephony/SmsApplication.java @@ -20,6 +20,7 @@ import android.Manifest.permission; import android.annotation.Nullable; import android.app.AppOpsManager; import android.app.role.RoleManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -48,8 +49,6 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.util.Collection; import java.util.HashMap; import java.util.List; diff --git a/telephony/common/com/android/internal/telephony/SmsConstants.java b/telephony/common/com/android/internal/telephony/SmsConstants.java index 19f52b0ef429..3aa8bbf607d1 100644 --- a/telephony/common/com/android/internal/telephony/SmsConstants.java +++ b/telephony/common/com/android/internal/telephony/SmsConstants.java @@ -15,7 +15,7 @@ */ package com.android.internal.telephony; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * SMS Constants and must be the same as the corresponding diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java index 72ad4cd83d01..5beb06d8595a 100644 --- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java +++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java @@ -27,8 +27,6 @@ import android.content.pm.PackageManager; import android.os.Binder; import android.os.Build; import android.os.Process; -import android.os.RemoteException; -import android.os.ServiceManager; import android.os.UserHandle; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -41,7 +39,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; -import java.util.function.Supplier; /** Utility class for Telephony permission enforcement. */ public final class TelephonyPermissions { @@ -49,9 +46,6 @@ public final class TelephonyPermissions { private static final boolean DBG = false; - private static final Supplier<ITelephony> TELEPHONY_SUPPLIER = () -> - ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE)); - /** * Whether to disable the new device identifier access restrictions. */ @@ -137,49 +131,6 @@ public final class TelephonyPermissions { public static boolean checkReadPhoneState( Context context, int subId, int pid, int uid, String callingPackage, @Nullable String callingFeatureId, String message) { - return checkReadPhoneState( - context, TELEPHONY_SUPPLIER, subId, pid, uid, callingPackage, callingFeatureId, - message); - } - - /** - * Check whether the calling packages has carrier privileges for the passing subscription. - * @return {@code true} if the caller has carrier privileges, {@false} otherwise. - */ - public static boolean checkCarrierPrivilegeForSubId(int subId) { - if (SubscriptionManager.isValidSubscriptionId(subId) - && getCarrierPrivilegeStatus(TELEPHONY_SUPPLIER, subId, Binder.getCallingUid()) - == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { - return true; - } - return false; - } - - /** - * Check whether the app with the given pid/uid can read phone state. - * - * <p>This method behaves in one of the following ways: - * <ul> - * <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the - * READ_PHONE_STATE runtime permission, or carrier privileges on the given subId. - * <li>throw SecurityException: if the caller didn't declare any of these permissions, or, for - * apps which support runtime permissions, if the caller does not currently have any of - * these permissions. - * <li>return false: if the caller lacks all of these permissions and doesn't support runtime - * permissions. This implies that the user revoked the ability to read phone state - * manually (via AppOps). In this case we can't throw as it would break app compatibility, - * so we return false to indicate that the calling function should return dummy data. - * </ul> - * - * <p>Note: for simplicity, this method always returns false for callers using legacy - * permissions and who have had READ_PHONE_STATE revoked, even if they are carrier-privileged. - * Such apps should migrate to runtime permissions or stop requiring READ_PHONE_STATE on P+ - * devices. - */ - @VisibleForTesting - public static boolean checkReadPhoneState( - Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid, - String callingPackage, @Nullable String callingFeatureId, String message) { try { context.enforcePermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message); @@ -194,7 +145,7 @@ public final class TelephonyPermissions { // If we don't have the runtime permission, but do have carrier privileges, that // suffices for reading phone state. if (SubscriptionManager.isValidSubscriptionId(subId)) { - enforceCarrierPrivilege(telephonySupplier, subId, uid, message); + enforceCarrierPrivilege(context, subId, uid, message); return true; } throw phoneStateException; @@ -209,23 +160,16 @@ public final class TelephonyPermissions { } /** - * Check whether the app with the given pid/uid can read phone state, or has carrier - * privileges on any active subscription. - * - * <p>If the app does not have carrier privilege, this method will return {@code false} instead - * of throwing a SecurityException. Therefore, the callers cannot tell the difference - * between M+ apps which declare the runtime permission but do not have it, and pre-M apps - * which declare the static permission but had access revoked via AppOps. Apps in the former - * category expect SecurityExceptions; apps in the latter don't. So this method is suitable for - * use only if the behavior in both scenarios is meant to be identical. - * - * @return {@code true} if the app can read phone state or has carrier privilege; - * {@code false} otherwise. + * Check whether the calling packages has carrier privileges for the passing subscription. + * @return {@code true} if the caller has carrier privileges, {@false} otherwise. */ - public static boolean checkReadPhoneStateOnAnyActiveSub(Context context, int pid, int uid, - String callingPackage, @Nullable String callingFeatureId, String message) { - return checkReadPhoneStateOnAnyActiveSub(context, TELEPHONY_SUPPLIER, pid, uid, - callingPackage, callingFeatureId, message); + public static boolean checkCarrierPrivilegeForSubId(Context context, int subId) { + if (SubscriptionManager.isValidSubscriptionId(subId) + && getCarrierPrivilegeStatus(context, subId, Binder.getCallingUid()) + == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { + return true; + } + return false; } /** @@ -242,9 +186,7 @@ public final class TelephonyPermissions { * @return {@code true} if the app can read phone state or has carrier privilege; * {@code false} otherwise. */ - @VisibleForTesting - public static boolean checkReadPhoneStateOnAnyActiveSub( - Context context, Supplier<ITelephony> telephonySupplier, int pid, int uid, + public static boolean checkReadPhoneStateOnAnyActiveSub(Context context, int pid, int uid, String callingPackage, @Nullable String callingFeatureId, String message) { try { context.enforcePermission( @@ -259,7 +201,7 @@ public final class TelephonyPermissions { } catch (SecurityException phoneStateException) { // If we don't have the runtime permission, but do have carrier privileges, that // suffices for reading phone state. - return checkCarrierPrivilegeForAnySubId(context, telephonySupplier, uid); + return checkCarrierPrivilegeForAnySubId(context, uid); } } @@ -374,12 +316,11 @@ public final class TelephonyPermissions { } // If the calling package has carrier privileges for specified sub, then allow access. - if (checkCarrierPrivilegeForSubId(subId)) return true; + if (checkCarrierPrivilegeForSubId(context, subId)) return true; // If the calling package has carrier privileges for any subscription // and allowCarrierPrivilegeOnAnySub is set true, then allow access. - if (allowCarrierPrivilegeOnAnySub && checkCarrierPrivilegeForAnySubId( - context, TELEPHONY_SUPPLIER, uid)) { + if (allowCarrierPrivilegeOnAnySub && checkCarrierPrivilegeForAnySubId(context, uid)) { return true; } @@ -471,7 +412,7 @@ public final class TelephonyPermissions { uid) == PackageManager.PERMISSION_GRANTED) { return false; } - if (checkCarrierPrivilegeForSubId(subId)) { + if (checkCarrierPrivilegeForSubId(context, subId)) { return false; } } @@ -487,26 +428,12 @@ public final class TelephonyPermissions { public static boolean checkReadCallLog( Context context, int subId, int pid, int uid, String callingPackage, @Nullable String callingPackageName) { - return checkReadCallLog( - context, TELEPHONY_SUPPLIER, subId, pid, uid, callingPackage, callingPackageName); - } - - /** - * Check whether the app with the given pid/uid can read the call log. - * @return {@code true} if the specified app has the read call log permission and AppOpp granted - * to it, {@code false} otherwise. - */ - @VisibleForTesting - public static boolean checkReadCallLog( - Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid, - String callingPackage, @Nullable String callingFeatureId) { - if (context.checkPermission(Manifest.permission.READ_CALL_LOG, pid, uid) != PERMISSION_GRANTED) { // If we don't have the runtime permission, but do have carrier privileges, that // suffices for being able to see the call phone numbers. if (SubscriptionManager.isValidSubscriptionId(subId)) { - enforceCarrierPrivilege(telephonySupplier, subId, uid, "readCallLog"); + enforceCarrierPrivilege(context, subId, uid, "readCallLog"); return true; } return false; @@ -529,7 +456,7 @@ public final class TelephonyPermissions { Context context, int subId, String callingPackage, @Nullable String callingFeatureId, String message) { return checkReadPhoneNumber( - context, TELEPHONY_SUPPLIER, subId, Binder.getCallingPid(), Binder.getCallingUid(), + context, subId, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage, callingFeatureId, message); } @@ -541,7 +468,7 @@ public final class TelephonyPermissions { */ @VisibleForTesting public static boolean checkReadPhoneNumber( - Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid, + Context context, int subId, int pid, int uid, String callingPackage, @Nullable String callingFeatureId, String message) { // Default SMS app can always read it. AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); @@ -556,7 +483,7 @@ public final class TelephonyPermissions { // First, check if we can read the phone state. try { return checkReadPhoneState( - context, telephonySupplier, subId, pid, uid, callingPackage, callingFeatureId, + context, subId, pid, uid, callingPackage, callingFeatureId, message); } catch (SecurityException readPhoneStateSecurityException) { } @@ -598,7 +525,7 @@ public final class TelephonyPermissions { } if (DBG) Log.d(LOG_TAG, "No modify permission, check carrier privilege next."); - enforceCallingOrSelfCarrierPrivilege(subId, message); + enforceCallingOrSelfCarrierPrivilege(context, subId, message); } /** @@ -618,7 +545,7 @@ public final class TelephonyPermissions { Log.d(LOG_TAG, "No READ_PHONE_STATE permission, check carrier privilege next."); } - enforceCallingOrSelfCarrierPrivilege(subId, message); + enforceCallingOrSelfCarrierPrivilege(context, subId, message); } /** @@ -635,11 +562,38 @@ public final class TelephonyPermissions { } if (DBG) { - Log.d(LOG_TAG, "No READ_PRIVILEDED_PHONE_STATE permission, " + Log.d(LOG_TAG, "No READ_PRIVILEGED_PHONE_STATE permission, " + "check carrier privilege next."); } - enforceCallingOrSelfCarrierPrivilege(subId, message); + enforceCallingOrSelfCarrierPrivilege(context, subId, message); + } + + /** + * Ensure the caller (or self, if not processing an IPC) has + * {@link android.Manifest.permission#READ_PRIVILEGED_PHONE_STATE} or + * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE} or carrier privileges. + * + * @throws SecurityException if the caller does not have the required permission/privileges + */ + public static void enforeceCallingOrSelfReadPrecisePhoneStatePermissionOrCarrierPrivilege( + Context context, int subId, String message) { + if (context.checkCallingOrSelfPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + == PERMISSION_GRANTED) { + return; + } + + if (context.checkCallingOrSelfPermission(Manifest.permission.READ_PRECISE_PHONE_STATE) + == PERMISSION_GRANTED) { + return; + } + + if (DBG) { + Log.d(LOG_TAG, "No READ_PRIVILEGED_PHONE_STATE nor READ_PRECISE_PHONE_STATE permission" + + ", check carrier privilege next."); + } + + enforceCallingOrSelfCarrierPrivilege(context, subId, message); } /** @@ -647,21 +601,18 @@ public final class TelephonyPermissions { * * @throws SecurityException if the caller does not have the required privileges */ - public static void enforceCallingOrSelfCarrierPrivilege(int subId, String message) { + public static void enforceCallingOrSelfCarrierPrivilege( + Context context, int subId, String message) { // NOTE: It's critical that we explicitly pass the calling UID here rather than call // TelephonyManager#hasCarrierPrivileges directly, as the latter only works when called from // the phone process. When called from another process, it will check whether that process // has carrier privileges instead. - enforceCarrierPrivilege(subId, Binder.getCallingUid(), message); - } - - private static void enforceCarrierPrivilege(int subId, int uid, String message) { - enforceCarrierPrivilege(TELEPHONY_SUPPLIER, subId, uid, message); + enforceCarrierPrivilege(context, subId, Binder.getCallingUid(), message); } private static void enforceCarrierPrivilege( - Supplier<ITelephony> telephonySupplier, int subId, int uid, String message) { - if (getCarrierPrivilegeStatus(telephonySupplier, subId, uid) + Context context, int subId, int uid, String message) { + if (getCarrierPrivilegeStatus(context, subId, uid) != TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { if (DBG) Log.e(LOG_TAG, "No Carrier Privilege."); throw new SecurityException(message); @@ -669,13 +620,12 @@ public final class TelephonyPermissions { } /** Returns whether the provided uid has carrier privileges for any active subscription ID. */ - private static boolean checkCarrierPrivilegeForAnySubId( - Context context, Supplier<ITelephony> telephonySupplier, int uid) { + private static boolean checkCarrierPrivilegeForAnySubId(Context context, int uid) { SubscriptionManager sm = (SubscriptionManager) context.getSystemService( Context.TELEPHONY_SUBSCRIPTION_SERVICE); int[] activeSubIds = sm.getActiveSubscriptionIdList(/* visibleOnly */ false); for (int activeSubId : activeSubIds) { - if (getCarrierPrivilegeStatus(telephonySupplier, activeSubId, uid) + if (getCarrierPrivilegeStatus(context, activeSubId, uid) == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { return true; } @@ -683,18 +633,15 @@ public final class TelephonyPermissions { return false; } - private static int getCarrierPrivilegeStatus( - Supplier<ITelephony> telephonySupplier, int subId, int uid) { - ITelephony telephony = telephonySupplier.get(); + private static int getCarrierPrivilegeStatus(Context context, int subId, int uid) { + final long identity = Binder.clearCallingIdentity(); try { - if (telephony != null) { - return telephony.getCarrierPrivilegeStatusForUid(subId, uid); - } - } catch (RemoteException e) { - // Fallback below. + TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService( + Context.TELEPHONY_SERVICE); + return telephonyManager.createForSubscriptionId(subId).getCarrierPrivilegeStatus(uid); + } finally { + Binder.restoreCallingIdentity(identity); } - Log.e(LOG_TAG, "Phone process is down, cannot check carrier privileges"); - return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; } /** diff --git a/telephony/common/com/google/android/mms/ContentType.java b/telephony/common/com/google/android/mms/ContentType.java index 12e4b7e26e1e..4a971dd34c8f 100644 --- a/telephony/common/com/google/android/mms/ContentType.java +++ b/telephony/common/com/google/android/mms/ContentType.java @@ -17,7 +17,7 @@ package com.google.android.mms; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.util.ArrayList; diff --git a/telephony/common/com/google/android/mms/InvalidHeaderValueException.java b/telephony/common/com/google/android/mms/InvalidHeaderValueException.java index 2836c3075b3b..55087ff0fb1d 100644 --- a/telephony/common/com/google/android/mms/InvalidHeaderValueException.java +++ b/telephony/common/com/google/android/mms/InvalidHeaderValueException.java @@ -17,7 +17,7 @@ package com.google.android.mms; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * Thrown when an invalid header value was set. diff --git a/telephony/common/com/google/android/mms/MmsException.java b/telephony/common/com/google/android/mms/MmsException.java index 5be33ed1fac9..24bceb37f590 100644 --- a/telephony/common/com/google/android/mms/MmsException.java +++ b/telephony/common/com/google/android/mms/MmsException.java @@ -17,7 +17,7 @@ package com.google.android.mms; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; /** * A generic exception that is thrown by the Mms client. diff --git a/telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java b/telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java index ae447d7a7417..8693385bb032 100644 --- a/telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java +++ b/telephony/common/com/google/android/mms/pdu/AcknowledgeInd.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.google.android.mms.InvalidHeaderValueException; diff --git a/telephony/common/com/google/android/mms/pdu/Base64.java b/telephony/common/com/google/android/mms/pdu/Base64.java index 483fa7f9842e..0d6a46a59fcc 100644 --- a/telephony/common/com/google/android/mms/pdu/Base64.java +++ b/telephony/common/com/google/android/mms/pdu/Base64.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; public class Base64 { /** diff --git a/telephony/common/com/google/android/mms/pdu/CharacterSets.java b/telephony/common/com/google/android/mms/pdu/CharacterSets.java index 27da35e2d928..5172b7b67f88 100644 --- a/telephony/common/com/google/android/mms/pdu/CharacterSets.java +++ b/telephony/common/com/google/android/mms/pdu/CharacterSets.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.io.UnsupportedEncodingException; import java.util.HashMap; diff --git a/telephony/common/com/google/android/mms/pdu/DeliveryInd.java b/telephony/common/com/google/android/mms/pdu/DeliveryInd.java index 7093ac63338c..8fb6a7545abf 100644 --- a/telephony/common/com/google/android/mms/pdu/DeliveryInd.java +++ b/telephony/common/com/google/android/mms/pdu/DeliveryInd.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.google.android.mms.InvalidHeaderValueException; diff --git a/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java b/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java index 41662750842f..8c0380f77cdd 100644 --- a/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java +++ b/telephony/common/com/google/android/mms/pdu/EncodedStringValue.java @@ -17,10 +17,9 @@ package com.google.android.mms.pdu; +import android.compat.annotation.UnsupportedAppUsage; import android.util.Log; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; diff --git a/telephony/common/com/google/android/mms/pdu/GenericPdu.java b/telephony/common/com/google/android/mms/pdu/GenericPdu.java index ebf16ac7e632..320b13ffed2b 100644 --- a/telephony/common/com/google/android/mms/pdu/GenericPdu.java +++ b/telephony/common/com/google/android/mms/pdu/GenericPdu.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.google.android.mms.InvalidHeaderValueException; diff --git a/telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java b/telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java index e108f7600baf..42a89c69e873 100644 --- a/telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java +++ b/telephony/common/com/google/android/mms/pdu/MultimediaMessagePdu.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.google.android.mms.InvalidHeaderValueException; diff --git a/telephony/common/com/google/android/mms/pdu/NotificationInd.java b/telephony/common/com/google/android/mms/pdu/NotificationInd.java index b561bd4ab3a7..ca4615c2e9fe 100644 --- a/telephony/common/com/google/android/mms/pdu/NotificationInd.java +++ b/telephony/common/com/google/android/mms/pdu/NotificationInd.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.google.android.mms.InvalidHeaderValueException; diff --git a/telephony/common/com/google/android/mms/pdu/NotifyRespInd.java b/telephony/common/com/google/android/mms/pdu/NotifyRespInd.java index 3c70f86a0890..ebd81afc0173 100644 --- a/telephony/common/com/google/android/mms/pdu/NotifyRespInd.java +++ b/telephony/common/com/google/android/mms/pdu/NotifyRespInd.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.google.android.mms.InvalidHeaderValueException; diff --git a/telephony/common/com/google/android/mms/pdu/PduBody.java b/telephony/common/com/google/android/mms/pdu/PduBody.java index 51914e4110b0..f7f285f653b9 100644 --- a/telephony/common/com/google/android/mms/pdu/PduBody.java +++ b/telephony/common/com/google/android/mms/pdu/PduBody.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.util.HashMap; import java.util.Map; diff --git a/telephony/common/com/google/android/mms/pdu/PduComposer.java b/telephony/common/com/google/android/mms/pdu/PduComposer.java index e24bf21a11b5..b8b212c493aa 100644 --- a/telephony/common/com/google/android/mms/pdu/PduComposer.java +++ b/telephony/common/com/google/android/mms/pdu/PduComposer.java @@ -17,12 +17,11 @@ package com.google.android.mms.pdu; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.Context; import android.text.TextUtils; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; import java.io.IOException; diff --git a/telephony/common/com/google/android/mms/pdu/PduContentTypes.java b/telephony/common/com/google/android/mms/pdu/PduContentTypes.java index 8551b2f9b693..57141fedf1e0 100644 --- a/telephony/common/com/google/android/mms/pdu/PduContentTypes.java +++ b/telephony/common/com/google/android/mms/pdu/PduContentTypes.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; public class PduContentTypes { /** diff --git a/telephony/common/com/google/android/mms/pdu/PduHeaders.java b/telephony/common/com/google/android/mms/pdu/PduHeaders.java index b5244645fda1..3e6218480dc5 100644 --- a/telephony/common/com/google/android/mms/pdu/PduHeaders.java +++ b/telephony/common/com/google/android/mms/pdu/PduHeaders.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.google.android.mms.InvalidHeaderValueException; diff --git a/telephony/common/com/google/android/mms/pdu/PduParser.java b/telephony/common/com/google/android/mms/pdu/PduParser.java index f48399410723..5340245ae869 100755 --- a/telephony/common/com/google/android/mms/pdu/PduParser.java +++ b/telephony/common/com/google/android/mms/pdu/PduParser.java @@ -17,10 +17,9 @@ package com.google.android.mms.pdu; +import android.compat.annotation.UnsupportedAppUsage; import android.util.Log; -import dalvik.annotation.compat.UnsupportedAppUsage; - import com.google.android.mms.ContentType; import com.google.android.mms.InvalidHeaderValueException; diff --git a/telephony/common/com/google/android/mms/pdu/PduPart.java b/telephony/common/com/google/android/mms/pdu/PduPart.java index 09b775118dc3..8dd976b2569f 100644 --- a/telephony/common/com/google/android/mms/pdu/PduPart.java +++ b/telephony/common/com/google/android/mms/pdu/PduPart.java @@ -17,10 +17,9 @@ package com.google.android.mms.pdu; +import android.compat.annotation.UnsupportedAppUsage; import android.net.Uri; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.util.HashMap; import java.util.Map; diff --git a/telephony/common/com/google/android/mms/pdu/PduPersister.java b/telephony/common/com/google/android/mms/pdu/PduPersister.java index 8efca0ea3909..fcd5b8ff57a8 100755 --- a/telephony/common/com/google/android/mms/pdu/PduPersister.java +++ b/telephony/common/com/google/android/mms/pdu/PduPersister.java @@ -17,6 +17,7 @@ package com.google.android.mms.pdu; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.ContentUris; import android.content.ContentValues; @@ -40,8 +41,6 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; -import dalvik.annotation.compat.UnsupportedAppUsage; - import com.google.android.mms.ContentType; import com.google.android.mms.InvalidHeaderValueException; import com.google.android.mms.MmsException; diff --git a/telephony/common/com/google/android/mms/pdu/QuotedPrintable.java b/telephony/common/com/google/android/mms/pdu/QuotedPrintable.java index 9d6535c72e90..4e1d7f5775ec 100644 --- a/telephony/common/com/google/android/mms/pdu/QuotedPrintable.java +++ b/telephony/common/com/google/android/mms/pdu/QuotedPrintable.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import java.io.ByteArrayOutputStream; diff --git a/telephony/common/com/google/android/mms/pdu/ReadOrigInd.java b/telephony/common/com/google/android/mms/pdu/ReadOrigInd.java index e38c62dde622..4ba3c71580e0 100644 --- a/telephony/common/com/google/android/mms/pdu/ReadOrigInd.java +++ b/telephony/common/com/google/android/mms/pdu/ReadOrigInd.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.google.android.mms.InvalidHeaderValueException; diff --git a/telephony/common/com/google/android/mms/pdu/ReadRecInd.java b/telephony/common/com/google/android/mms/pdu/ReadRecInd.java index 9696bc259d00..37ccfb9c9b9b 100644 --- a/telephony/common/com/google/android/mms/pdu/ReadRecInd.java +++ b/telephony/common/com/google/android/mms/pdu/ReadRecInd.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.google.android.mms.InvalidHeaderValueException; diff --git a/telephony/common/com/google/android/mms/pdu/RetrieveConf.java b/telephony/common/com/google/android/mms/pdu/RetrieveConf.java index 03755af4189c..260adfc093f2 100644 --- a/telephony/common/com/google/android/mms/pdu/RetrieveConf.java +++ b/telephony/common/com/google/android/mms/pdu/RetrieveConf.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.google.android.mms.InvalidHeaderValueException; diff --git a/telephony/common/com/google/android/mms/pdu/SendConf.java b/telephony/common/com/google/android/mms/pdu/SendConf.java index b85982791ada..779923801bfa 100644 --- a/telephony/common/com/google/android/mms/pdu/SendConf.java +++ b/telephony/common/com/google/android/mms/pdu/SendConf.java @@ -17,7 +17,7 @@ package com.google.android.mms.pdu; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.google.android.mms.InvalidHeaderValueException; diff --git a/telephony/common/com/google/android/mms/pdu/SendReq.java b/telephony/common/com/google/android/mms/pdu/SendReq.java index c1b7f934c0f7..6e2f2da01791 100644 --- a/telephony/common/com/google/android/mms/pdu/SendReq.java +++ b/telephony/common/com/google/android/mms/pdu/SendReq.java @@ -17,10 +17,9 @@ package com.google.android.mms.pdu; +import android.compat.annotation.UnsupportedAppUsage; import android.util.Log; -import dalvik.annotation.compat.UnsupportedAppUsage; - import com.google.android.mms.InvalidHeaderValueException; public class SendReq extends MultimediaMessagePdu { diff --git a/telephony/common/com/google/android/mms/util/AbstractCache.java b/telephony/common/com/google/android/mms/util/AbstractCache.java index ab5d48a4ce3d..25862e73581e 100644 --- a/telephony/common/com/google/android/mms/util/AbstractCache.java +++ b/telephony/common/com/google/android/mms/util/AbstractCache.java @@ -17,10 +17,9 @@ package com.google.android.mms.util; +import android.compat.annotation.UnsupportedAppUsage; import android.util.Log; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.util.HashMap; public abstract class AbstractCache<K, V> { diff --git a/telephony/common/com/google/android/mms/util/DownloadDrmHelper.java b/telephony/common/com/google/android/mms/util/DownloadDrmHelper.java index 118de465a518..0f9390daa725 100644 --- a/telephony/common/com/google/android/mms/util/DownloadDrmHelper.java +++ b/telephony/common/com/google/android/mms/util/DownloadDrmHelper.java @@ -17,12 +17,11 @@ package com.google.android.mms.util; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.drm.DrmManagerClient; import android.util.Log; -import dalvik.annotation.compat.UnsupportedAppUsage; - public class DownloadDrmHelper { private static final String TAG = "DownloadDrmHelper"; diff --git a/telephony/common/com/google/android/mms/util/DrmConvertSession.java b/telephony/common/com/google/android/mms/util/DrmConvertSession.java index 0e8ec91f4ef6..156c7ad8baac 100644 --- a/telephony/common/com/google/android/mms/util/DrmConvertSession.java +++ b/telephony/common/com/google/android/mms/util/DrmConvertSession.java @@ -16,14 +16,13 @@ */ package com.google.android.mms.util; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.drm.DrmConvertedStatus; import android.drm.DrmManagerClient; import android.provider.Downloads; import android.util.Log; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.io.FileNotFoundException; import java.io.IOException; import java.io.RandomAccessFile; diff --git a/telephony/common/com/google/android/mms/util/PduCache.java b/telephony/common/com/google/android/mms/util/PduCache.java index 94e38946f632..c380d6b3e30f 100644 --- a/telephony/common/com/google/android/mms/util/PduCache.java +++ b/telephony/common/com/google/android/mms/util/PduCache.java @@ -17,14 +17,13 @@ package com.google.android.mms.util; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentUris; import android.content.UriMatcher; import android.net.Uri; import android.provider.Telephony.Mms; import android.util.Log; -import dalvik.annotation.compat.UnsupportedAppUsage; - import java.util.HashMap; import java.util.HashSet; diff --git a/telephony/common/com/google/android/mms/util/PduCacheEntry.java b/telephony/common/com/google/android/mms/util/PduCacheEntry.java index 1ecd1bf93e7f..a4a25d2471ff 100644 --- a/telephony/common/com/google/android/mms/util/PduCacheEntry.java +++ b/telephony/common/com/google/android/mms/util/PduCacheEntry.java @@ -17,7 +17,7 @@ package com.google.android.mms.util; -import dalvik.annotation.compat.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import com.google.android.mms.pdu.GenericPdu; diff --git a/telephony/common/com/google/android/mms/util/SqliteWrapper.java b/telephony/common/com/google/android/mms/util/SqliteWrapper.java index 2dd1dc11c2a9..31fe4d7683d6 100644 --- a/telephony/common/com/google/android/mms/util/SqliteWrapper.java +++ b/telephony/common/com/google/android/mms/util/SqliteWrapper.java @@ -18,6 +18,7 @@ package com.google.android.mms.util; import android.app.ActivityManager; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; @@ -27,8 +28,6 @@ import android.net.Uri; import android.util.Log; import android.widget.Toast; -import dalvik.annotation.compat.UnsupportedAppUsage; - public final class SqliteWrapper { private static final String TAG = "SqliteWrapper"; private static final String SQLITE_EXCEPTION_DETAIL_MESSAGE diff --git a/telephony/java/android/service/euicc/EuiccProfileInfo.java b/telephony/java/android/service/euicc/EuiccProfileInfo.java index 6c357ccdd03d..8450a9018634 100644 --- a/telephony/java/android/service/euicc/EuiccProfileInfo.java +++ b/telephony/java/android/service/euicc/EuiccProfileInfo.java @@ -19,7 +19,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.service.carrier.CarrierIdentifier; diff --git a/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java b/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java index c7a985160730..2382f657c9ee 100644 --- a/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java +++ b/telephony/java/android/service/euicc/GetDefaultDownloadableSubscriptionListResult.java @@ -17,7 +17,7 @@ package android.service.euicc; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.telephony.euicc.DownloadableSubscription; diff --git a/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java b/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java index abd4065c754a..d0fb51180c1d 100644 --- a/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java +++ b/telephony/java/android/service/euicc/GetDownloadableSubscriptionMetadataResult.java @@ -17,7 +17,7 @@ package android.service.euicc; import android.annotation.Nullable; import android.annotation.SystemApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.telephony.euicc.DownloadableSubscription; diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java index bb28df2b64eb..d325cd84855c 100644 --- a/telephony/java/android/telephony/AccessNetworkConstants.java +++ b/telephony/java/android/telephony/AccessNetworkConstants.java @@ -50,18 +50,12 @@ public final class AccessNetworkConstants { /** * Transport type for Wireless Wide Area Networks (i.e. Cellular) - * @hide */ - @SystemApi - @TestApi public static final int TRANSPORT_TYPE_WWAN = 1; /** * Transport type for Wireless Local Area Networks (i.e. Wifi) - * @hide */ - @SystemApi - @TestApi public static final int TRANSPORT_TYPE_WLAN = 2; /** @hide */ diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 628a27565845..d863090a18d1 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -16,8 +16,6 @@ package android.telephony; -import com.android.telephony.Rlog; - import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; @@ -26,7 +24,7 @@ import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.content.ComponentName; import android.content.Context; import android.os.PersistableBundle; @@ -37,6 +35,7 @@ import android.telecom.TelecomManager; import android.telephony.ims.ImsReasonInfo; import com.android.internal.telephony.ICarrierConfigLoader; +import com.android.telephony.Rlog; /** * Provides access to telephony configuration values that are carrier-specific. @@ -301,7 +300,6 @@ public class CarrierConfigManager { /** * A string array containing numbers that shouldn't be included in the call log. - * @hide */ public static final String KEY_UNLOGGABLE_NUMBERS_STRING_ARRAY = "unloggable_numbers_string_array"; @@ -314,12 +312,11 @@ public class CarrierConfigManager { KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool"; /** - * Do only allow auto selection in Advanced Network Settings when in home network. + * Only allow auto selection in Advanced Network Settings when in home network. * Manual selection is allowed when in roaming network. - * @hide */ - public static final String - KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL = "only_auto_select_in_home_network"; + public static final String KEY_ONLY_AUTO_SELECT_IN_HOME_NETWORK_BOOL = + "only_auto_select_in_home_network"; /** * Control whether users receive a simplified network settings UI and improved network @@ -583,9 +580,6 @@ public class CarrierConfigManager { * registration state to change. That is, turning on or off mobile data will not cause VT to be * enabled or disabled. * When {@code false}, disabling mobile data will cause VT to be de-registered. - * <p> - * See also {@link #KEY_VILTE_DATA_IS_METERED_BOOL}. - * @hide */ public static final String KEY_IGNORE_DATA_ENABLED_CHANGED_FOR_VIDEO_CALLS = "ignore_data_enabled_changed_for_video_calls"; @@ -649,7 +643,6 @@ public class CarrierConfigManager { /** * Default WFC_IMS_enabled: true VoWiFi by default is on * false VoWiFi by default is off - * @hide */ public static final String KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL = "carrier_default_wfc_ims_enabled_bool"; @@ -721,9 +714,7 @@ public class CarrierConfigManager { * * As of now, Verizon is the only carrier enforcing this dependency in their * WFC awareness and activation requirements. - * - * @hide - * */ + */ public static final String KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL = "carrier_volte_override_wfc_provisioning_bool"; @@ -1084,10 +1075,6 @@ public class CarrierConfigManager { * * When {@code false}, the old behavior is used, where the toggle in accessibility settings is * used to set the IMS stack's RTT enabled state. - * - * @deprecated -- this flag no longer does anything. Remove once the new behavior is verified. - * - * @hide */ public static final String KEY_IGNORE_RTT_MODE_SETTING_BOOL = "ignore_rtt_mode_setting_bool"; @@ -1128,7 +1115,6 @@ public class CarrierConfigManager { * Determines whether the IMS conference merge process supports and returns its participants * data. When {@code true}, on merge complete, conference call would have a list of its * participants returned in XML format, {@code false otherwise}. - * @hide */ public static final String KEY_SUPPORT_IMS_CONFERENCE_EVENT_PACKAGE_BOOL = "support_ims_conference_event_package_bool"; @@ -1201,20 +1187,18 @@ public class CarrierConfigManager { public static final String KEY_ENABLE_APPS_STRING_ARRAY = "enable_apps_string_array"; /** - * Determine whether user can switch Wi-Fi preferred or Cellular preferred in calling preference. + * Determine whether user can switch Wi-Fi preferred or Cellular preferred + * in calling preference. * Some operators support Wi-Fi Calling only, not VoLTE. * They don't need "Cellular preferred" option. - * In this case, set uneditalbe attribute for preferred preference. - * @hide + * In this case, set uneditable attribute for preferred preference. */ public static final String KEY_EDITABLE_WFC_MODE_BOOL = "editable_wfc_mode_bool"; - /** - * Flag to indicate if Wi-Fi needs to be disabled in ECBM - * @hide - **/ - public static final String - KEY_CONFIG_WIFI_DISABLE_IN_ECBM = "config_wifi_disable_in_ecbm"; + /** + * Flag to indicate if Wi-Fi needs to be disabled in ECBM. + */ + public static final String KEY_CONFIG_WIFI_DISABLE_IN_ECBM = "config_wifi_disable_in_ecbm"; /** * List operator-specific error codes and indices of corresponding error strings in @@ -1278,9 +1262,8 @@ public class CarrierConfigManager { public static final String KEY_WFC_SPN_USE_ROOT_LOCALE = "wfc_spn_use_root_locale"; /** - * The Component Name of the activity that can setup the emergency addrees for WiFi Calling + * The Component Name of the activity that can setup the emergency address for WiFi Calling * as per carrier requirement. - * @hide */ public static final String KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING = "wfc_emergency_address_carrier_app_string"; @@ -1444,22 +1427,19 @@ public class CarrierConfigManager { public static final String KEY_ALLOW_ADDING_APNS_BOOL = "allow_adding_apns_bool"; /** - * APN types that user is not allowed to modify - * @hide + * APN types that user is not allowed to modify. */ public static final String KEY_READ_ONLY_APN_TYPES_STRING_ARRAY = "read_only_apn_types_string_array"; /** - * APN fields that user is not allowed to modify - * @hide + * APN fields that user is not allowed to modify. */ public static final String KEY_READ_ONLY_APN_FIELDS_STRING_ARRAY = "read_only_apn_fields_string_array"; /** * Default value of APN types field if not specified by user when adding/modifying an APN. - * @hide */ public static final String KEY_APN_SETTINGS_DEFAULT_APN_TYPES_STRING_ARRAY = "apn_settings_default_apn_types_string_array"; @@ -1490,29 +1470,25 @@ public class CarrierConfigManager { "hide_digits_helper_text_on_stk_input_screen_bool"; /** - * Boolean indicating if show data RAT icon on status bar even when data is disabled - * @hide + * Boolean indicating if show data RAT icon on status bar even when data is disabled. */ public static final String KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL = "always_show_data_rat_icon_bool"; /** - * Boolean indicating if default data account should show LTE or 4G icon - * @hide + * Boolean indicating if default data account should show LTE or 4G icon. */ public static final String KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL = "show_4g_for_lte_data_icon_bool"; /** * Boolean indicating if default data account should show 4G icon when in 3G. - * @hide */ public static final String KEY_SHOW_4G_FOR_3G_DATA_ICON_BOOL = "show_4g_for_3g_data_icon_bool"; /** - * Boolean indicating if lte+ icon should be shown if available - * @hide + * Boolean indicating if LTE+ icon should be shown if available. */ public static final String KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL = "hide_lte_plus_data_icon_bool"; @@ -1527,10 +1503,8 @@ public class CarrierConfigManager { "operator_name_filter_pattern_string"; /** - * The string is used to compare with operator name. If it matches the pattern then show - * specific data icon. - * - * @hide + * The string is used to compare with operator name. + * If it matches the pattern then show specific data icon. */ public static final String KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING = "show_carrier_data_icon_pattern_string"; @@ -1543,33 +1517,28 @@ public class CarrierConfigManager { "show_precise_failed_cause_bool"; /** - * Boolean to decide whether lte is enabled. - * @hide + * Boolean to decide whether LTE is enabled. */ public static final String KEY_LTE_ENABLED_BOOL = "lte_enabled_bool"; /** * Boolean to decide whether TD-SCDMA is supported. - * @hide */ public static final String KEY_SUPPORT_TDSCDMA_BOOL = "support_tdscdma_bool"; /** * A list of mcc/mnc that support TD-SCDMA for device when connect to the roaming network. - * @hide */ public static final String KEY_SUPPORT_TDSCDMA_ROAMING_NETWORKS_STRING_ARRAY = "support_tdscdma_roaming_networks_string_array"; /** * Boolean to decide whether world mode is enabled. - * @hide */ public static final String KEY_WORLD_MODE_ENABLED_BOOL = "world_mode_enabled_bool"; /** * Flatten {@link android.content.ComponentName} of the carrier's settings activity. - * @hide */ public static final String KEY_CARRIER_SETTINGS_ACTIVITY_COMPONENT_NAME_STRING = "carrier_settings_activity_component_name_string"; @@ -1607,7 +1576,10 @@ public class CarrierConfigManager { public static final String KEY_MMS_UA_PROF_TAG_NAME_STRING = "uaProfTagName"; public static final String KEY_MMS_UA_PROF_URL_STRING = "uaProfUrl"; public static final String KEY_MMS_USER_AGENT_STRING = "userAgent"; - /** @hide */ + /** + * If true, add "Connection: close" header to MMS HTTP requests so the connection + * is immediately closed (disabling keep-alive). + */ public static final String KEY_MMS_CLOSE_CONNECTION_BOOL = "mmsCloseConnection"; /** @@ -1623,25 +1595,23 @@ public class CarrierConfigManager { /** * Defines carrier-specific actions which act upon * com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED, used for customization of the - * default carrier app + * default carrier app. * Format: "CARRIER_ACTION_IDX, ..." * Where {@code CARRIER_ACTION_IDX} is an integer defined in - * {@link com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils} + * com.android.carrierdefaultapp.CarrierActionUtils * Example: - * {@link com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_DISABLE_METERED_APNS - * disable_metered_apns} - * @hide + * com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_DISABLE_METERED_APNS + * disables metered APNs */ - @UnsupportedAppUsage + @SuppressLint("IntentName") public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_REDIRECTION_STRING_ARRAY = "carrier_default_actions_on_redirection_string_array"; /** - * Defines carrier-specific actions which act upon - * com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED + * Defines carrier-specific actions which act upon CARRIER_SIGNAL_REQUEST_NETWORK_FAILED * and configured signal args: - * {@link com.android.internal.telephony.TelephonyIntents#EXTRA_APN_TYPE_KEY apnType}, - * {@link com.android.internal.telephony.TelephonyIntents#EXTRA_ERROR_CODE_KEY errorCode} + * android.telephony.TelephonyManager#EXTRA_APN_TYPE, + * android.telephony.TelephonyManager#EXTRA_ERROR_CODE * used for customization of the default carrier app * Format: * { @@ -1649,42 +1619,41 @@ public class CarrierConfigManager { * "APN_1, ERROR_CODE_2 : CARRIER_ACTION_IDX_1 " * } * Where {@code APN_1} is a string defined in - * {@link com.android.internal.telephony.PhoneConstants PhoneConstants} + * com.android.internal.telephony.PhoneConstants * Example: "default" * - * {@code ERROR_CODE_1} is an integer defined in - * {@link DataFailCause DcFailure} + * {@code ERROR_CODE_1} is an integer defined in android.telephony.DataFailCause * Example: - * {@link DataFailCause#MISSING_UNKNOWN_APN} + * android.telephony.DataFailCause#MISSING_UNKNOWN_APN * * {@code CARRIER_ACTION_IDX_1} is an integer defined in - * {@link com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils} + * com.android.carrierdefaultapp.CarrierActionUtils * Example: - * {@link com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_DISABLE_METERED_APNS} - * @hide + * com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_DISABLE_METERED_APNS + * disables metered APNs */ + @SuppressLint("IntentName") public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_DCFAILURE_STRING_ARRAY = "carrier_default_actions_on_dcfailure_string_array"; /** - * Defines carrier-specific actions which act upon - * com.android.internal.telephony.CARRIER_SIGNAL_RESET, used for customization of the - * default carrier app + * Defines carrier-specific actions which act upon CARRIER_SIGNAL_RESET, + * used for customization of the default carrier app. * Format: "CARRIER_ACTION_IDX, ..." * Where {@code CARRIER_ACTION_IDX} is an integer defined in - * {@link com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils} + * com.android.carrierdefaultapp.CarrierActionUtils * Example: - * {@link com.android.carrierdefaultapp.CarrierActionUtils - * #CARRIER_ACTION_CANCEL_ALL_NOTIFICATIONS clear all notifications on reset} - * @hide + * com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_CANCEL_ALL_NOTIFICATIONS + * clears all notifications on reset */ + @SuppressLint("IntentName") public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_RESET = "carrier_default_actions_on_reset_string_array"; /** * Defines carrier-specific actions which act upon * com.android.internal.telephony.CARRIER_SIGNAL_DEFAULT_NETWORK_AVAILABLE, - * used for customization of the default carrier app + * used for customization of the default carrier app. * Format: * { * "true : CARRIER_ACTION_IDX_1", @@ -1692,17 +1661,17 @@ public class CarrierConfigManager { * } * Where {@code true} is a boolean indicates default network available/unavailable * Where {@code CARRIER_ACTION_IDX} is an integer defined in - * {@link com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils} + * com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils * Example: - * {@link com.android.carrierdefaultapp.CarrierActionUtils - * #CARRIER_ACTION_ENABLE_DEFAULT_URL_HANDLER enable the app as the default URL handler} - * @hide + * com.android.carrierdefaultapp.CarrierActionUtils#CARRIER_ACTION_ENABLE_DEFAULT_URL_HANDLER + * enables the app as the default URL handler */ + @SuppressLint("IntentName") public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_DEFAULT_NETWORK_AVAILABLE = "carrier_default_actions_on_default_network_available_string_array"; + /** - * Defines a list of acceptable redirection url for default carrier app - * @hides + * Defines a list of acceptable redirection url for default carrier app. */ public static final String KEY_CARRIER_DEFAULT_REDIRECTION_URL_STRING_ARRAY = "carrier_default_redirection_url_string_array"; @@ -1830,10 +1799,10 @@ public class CarrierConfigManager { /** * Determines whether to enable enhanced call blocking feature on the device. - * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED - * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_PRIVATE - * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_PAYPHONE - * @see SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNKNOWN + * android.provider.BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNREGISTERED + * android.provider.BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_PRIVATE + * android.provider.BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_PAYPHONE + * android.provider.BlockedNumberContract.SystemContract#ENHANCED_SETTING_KEY_BLOCK_UNKNOWN * * <p> * 1. For Single SIM(SS) device, it can be customized in both carrier_config_mccmnc.xml @@ -1843,7 +1812,6 @@ public class CarrierConfigManager { * function is used regardless of SIM. * <p> * If {@code true} enable enhanced call blocking feature on the device, {@code false} otherwise. - * @hide */ public static final String KEY_SUPPORT_ENHANCED_CALL_BLOCKING_BOOL = "support_enhanced_call_blocking_bool"; @@ -1946,7 +1914,6 @@ public class CarrierConfigManager { /** * Flag indicating whether the carrier supports call deflection for an incoming IMS call. - * @hide */ public static final String KEY_CARRIER_ALLOW_DEFLECT_IMS_CALL_BOOL = "carrier_allow_deflect_ims_call_bool"; @@ -2011,8 +1978,6 @@ public class CarrierConfigManager { /** * Whether system apps are allowed to use fallback if carrier video call is not available. * Defaults to {@code true}. - * - * @hide */ public static final String KEY_ALLOW_VIDEO_CALLING_FALLBACK_BOOL = "allow_video_calling_fallback_bool"; @@ -2050,9 +2015,8 @@ public class CarrierConfigManager { "enhanced_4g_lte_title_variant_bool"; /** - * The index indicates the carrier specified title string of Enahnce 4G LTE Mode settings. + * The index indicates the carrier specified title string of Enhanced 4G LTE Mode settings. * Default value is 0, which indicates the default title string. - * @hide */ public static final String KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT = "enhanced_4g_lte_title_variant_int"; @@ -2096,15 +2060,13 @@ public class CarrierConfigManager { * {@link #KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL} is false. If * {@link #KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL} is true, this * configuration is ignored and roaming preference cannot be changed. - * @hide */ public static final String KEY_EDITABLE_WFC_ROAMING_MODE_BOOL = "editable_wfc_roaming_mode_bool"; /** - * Flag specifying wether to show blocking pay phone option in blocked numbers screen. Only show - * the option if payphone call presentation represents in the carrier's region. - * @hide + * Flag specifying whether to show blocking pay phone option in blocked numbers screen. + * Only show the option if payphone call presentation is present in the carrier's region. */ public static final java.lang.String KEY_SHOW_BLOCKING_PAY_PHONE_OPTION_BOOL = "show_blocking_pay_phone_option_bool"; @@ -2114,7 +2076,6 @@ public class CarrierConfigManager { * {@code false} - roaming preference can be selected separately from the home preference. * {@code true} - roaming preference is the same as home preference and * {@link #KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT} is used as the default value. - * @hide */ public static final String KEY_USE_WFC_HOME_NETWORK_MODE_IN_ROAMING_NETWORK_BOOL = "use_wfc_home_network_mode_in_roaming_network_bool"; @@ -2148,7 +2109,6 @@ public class CarrierConfigManager { * while the device is registered over WFC. Default value is -1, which indicates * that this notification is not pertinent for a particular carrier. We've added a delay * to prevent false positives. - * @hide */ public static final String KEY_EMERGENCY_NOTIFICATION_DELAY_INT = "emergency_notification_delay_int"; @@ -2199,7 +2159,6 @@ public class CarrierConfigManager { /** * Flag specifying whether to show an alert dialog for video call charges. * By default this value is {@code false}. - * @hide */ public static final String KEY_SHOW_VIDEO_CALL_CHARGES_ALERT_DIALOG_BOOL = "show_video_call_charges_alert_dialog_bool"; @@ -2486,10 +2445,9 @@ public class CarrierConfigManager { /** * Identifies if the key is available for WLAN or EPDG or both. The value is a bitmask. * 0 indicates that neither EPDG or WLAN is enabled. - * 1 indicates that key type {@link TelephonyManager#KEY_TYPE_EPDG} is enabled. - * 2 indicates that key type {@link TelephonyManager#KEY_TYPE_WLAN} is enabled. + * 1 indicates that key type TelephonyManager#KEY_TYPE_EPDG is enabled. + * 2 indicates that key type TelephonyManager#KEY_TYPE_WLAN is enabled. * 3 indicates that both are enabled. - * @hide */ public static final String IMSI_KEY_AVAILABILITY_INT = "imsi_key_availability_int"; @@ -2508,7 +2466,6 @@ public class CarrierConfigManager { /** * Flag specifying whether IMS registration state menu is shown in Status Info setting, * default to false. - * @hide */ public static final String KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL = "show_ims_registration_status_bool"; @@ -2564,7 +2521,6 @@ public class CarrierConfigManager { /** * The flag to disable the popup dialog which warns the user of data charges. - * @hide */ public static final String KEY_DISABLE_CHARGE_INDICATION_BOOL = "disable_charge_indication_bool"; @@ -2629,15 +2585,13 @@ public class CarrierConfigManager { /** * Determines whether any carrier has been identified and its specific config has been applied, * default to false. - * @hide */ public static final String KEY_CARRIER_CONFIG_APPLIED_BOOL = "carrier_config_applied_bool"; /** * Determines whether we should show a warning asking the user to check with their carrier - * on pricing when the user enabled data roaming. + * on pricing when the user enabled data roaming, * default to false. - * @hide */ public static final String KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL = "check_pricing_with_carrier_data_roaming_bool"; @@ -2789,10 +2743,10 @@ public class CarrierConfigManager { * Specifies a carrier-defined {@link android.telecom.CallRedirectionService} which Telecom * will bind to for outgoing calls. An empty string indicates that no carrier-defined * {@link android.telecom.CallRedirectionService} is specified. - * @hide */ public static final String KEY_CALL_REDIRECTION_SERVICE_COMPONENT_NAME_STRING = "call_redirection_service_component_name_string"; + /** * Support for the original string display of CDMA MO call. * By default, it is disabled. @@ -2905,8 +2859,8 @@ public class CarrierConfigManager { "call_waiting_service_class_int"; /** - * This configuration allow the system UI to display different 5G icon for different 5G - * scenario. + * This configuration allows the system UI to display different 5G icons for different 5G + * scenarios. * * There are five 5G scenarios: * 1. connected_mmwave: device currently connected to 5G cell as the secondary cell and using @@ -2923,24 +2877,22 @@ public class CarrierConfigManager { * 5G cell as a secondary cell) but the use of 5G is restricted. * * The configured string contains multiple key-value pairs separated by comma. For each pair, - * the key and value is separated by a colon. The key is corresponded to a 5G status above and + * the key and value are separated by a colon. The key corresponds to a 5G status above and * the value is the icon name. Use "None" as the icon name if no icon should be shown in a * specific 5G scenario. If the scenario is "None", config can skip this key and value. * * Icon name options: "5G_Plus", "5G". * * Here is an example: - * UE want to display 5G_Plus icon for scenario#1, and 5G icon for scenario#2; otherwise no + * UE wants to display 5G_Plus icon for scenario#1, and 5G icon for scenario#2; otherwise not * define. * The configuration is: "connected_mmwave:5G_Plus,connected:5G" - * - * @hide */ public static final String KEY_5G_ICON_CONFIGURATION_STRING = "5g_icon_configuration_string"; /** - * Timeout in second for displaying 5G icon, default value is 0 which means the timer is + * Timeout in seconds for displaying 5G icon, default value is 0 which means the timer is * disabled. * * System UI will show the 5G icon and start a timer with the timeout from this config when the @@ -2949,8 +2901,6 @@ public class CarrierConfigManager { * * If 5G is reacquired during this timer, the timer is canceled and restarted when 5G is next * lost. Allows us to momentarily lose 5G without blinking the icon. - * - * @hide */ public static final String KEY_5G_ICON_DISPLAY_GRACE_PERIOD_SEC_INT = "5g_icon_display_grace_period_sec_int"; @@ -3068,8 +3018,6 @@ public class CarrierConfigManager { * signal bar of primary network. By default it will be false, meaning whenever data * is going over opportunistic network, signal bar will reflect signal strength and rat * icon of that network. - * - * @hide */ public static final String KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN = "always_show_primary_signal_bar_in_opportunistic_network_boolean"; @@ -3163,7 +3111,6 @@ public class CarrierConfigManager { * 1 - yes. This is default. * @hide */ - // TODO(b/119567985): name this key properly public static final String KEY_SUPL_ES_STRING = KEY_PREFIX + "supl_es"; /** @@ -3283,8 +3230,6 @@ public class CarrierConfigManager { /** * 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"; @@ -3390,8 +3335,8 @@ public class CarrierConfigManager { "support_wps_over_ims_bool"; /** - * Holds the list of carrier certificate hashes. Note that each carrier has its own certificates - * @hide + * Holds the list of carrier certificate hashes. + * Note that each carrier has its own certificates. */ public static final String KEY_CARRIER_CERTIFICATE_STRING_ARRAY = "carrier_certificate_string_array"; @@ -3575,7 +3520,7 @@ public class CarrierConfigManager { sDefaults.putInt(KEY_IMS_DTMF_TONE_DELAY_INT, 0); sDefaults.putInt(KEY_CDMA_DTMF_TONE_DELAY_INT, 100); sDefaults.putBoolean(KEY_CALL_FORWARDING_MAP_NON_NUMBER_TO_VOICEMAIL_BOOL, false); - sDefaults.putBoolean(KEY_IGNORE_RTT_MODE_SETTING_BOOL, true); + sDefaults.putBoolean(KEY_IGNORE_RTT_MODE_SETTING_BOOL, false); sDefaults.putInt(KEY_CDMA_3WAYCALL_FLASH_DELAY_INT , 0); sDefaults.putBoolean(KEY_SUPPORT_CONFERENCE_CALL_BOOL, true); sDefaults.putBoolean(KEY_SUPPORT_IMS_CONFERENCE_CALL_BOOL, true); diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java index 8e703fee3126..399b1a4f25de 100644 --- a/telephony/java/android/telephony/CellIdentity.java +++ b/telephony/java/android/telephony/CellIdentity.java @@ -22,10 +22,13 @@ import android.annotation.CallSuper; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.hardware.radio.V1_0.CellInfoType; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; +import com.android.telephony.Rlog; + import java.util.Objects; import java.util.UUID; @@ -324,6 +327,86 @@ public abstract class CellIdentity implements Parcelable { } /** @hide */ + public static CellIdentity create(android.hardware.radio.V1_0.CellIdentity cellIdentity) { + if (cellIdentity == null) return null; + switch(cellIdentity.cellInfoType) { + case CellInfoType.GSM: { + if (cellIdentity.cellIdentityGsm.size() == 1) { + return new CellIdentityGsm(cellIdentity.cellIdentityGsm.get(0)); + } + break; + } + case CellInfoType.WCDMA: { + if (cellIdentity.cellIdentityWcdma.size() == 1) { + return new CellIdentityWcdma(cellIdentity.cellIdentityWcdma.get(0)); + } + break; + } + case CellInfoType.TD_SCDMA: { + if (cellIdentity.cellIdentityTdscdma.size() == 1) { + return new CellIdentityTdscdma(cellIdentity.cellIdentityTdscdma.get(0)); + } + break; + } + case CellInfoType.LTE: { + if (cellIdentity.cellIdentityLte.size() == 1) { + return new CellIdentityLte(cellIdentity.cellIdentityLte.get(0)); + } + break; + } + case CellInfoType.CDMA: { + if (cellIdentity.cellIdentityCdma.size() == 1) { + return new CellIdentityCdma(cellIdentity.cellIdentityCdma.get(0)); + } + break; + } + case CellInfoType.NONE: break; + default: break; + } + return null; + } + + /** @hide */ + public static CellIdentity create(android.hardware.radio.V1_2.CellIdentity cellIdentity) { + if (cellIdentity == null) return null; + switch(cellIdentity.cellInfoType) { + case CellInfoType.GSM: { + if (cellIdentity.cellIdentityGsm.size() == 1) { + return new CellIdentityGsm(cellIdentity.cellIdentityGsm.get(0)); + } + break; + } + case CellInfoType.WCDMA: { + if (cellIdentity.cellIdentityWcdma.size() == 1) { + return new CellIdentityWcdma(cellIdentity.cellIdentityWcdma.get(0)); + } + break; + } + case CellInfoType.TD_SCDMA: { + if (cellIdentity.cellIdentityTdscdma.size() == 1) { + return new CellIdentityTdscdma(cellIdentity.cellIdentityTdscdma.get(0)); + } + break; + } + case CellInfoType.LTE: { + if (cellIdentity.cellIdentityLte.size() == 1) { + return new CellIdentityLte(cellIdentity.cellIdentityLte.get(0)); + } + break; + } + case CellInfoType.CDMA: { + if (cellIdentity.cellIdentityCdma.size() == 1) { + return new CellIdentityCdma(cellIdentity.cellIdentityCdma.get(0)); + } + break; + } + case CellInfoType.NONE: break; + default: break; + } + return null; + } + + /** @hide */ public static CellIdentity create(android.hardware.radio.V1_5.CellIdentity ci) { if (ci == null) return null; switch (ci.getDiscriminator()) { diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java index 2ecdfce92825..49f425acead6 100644 --- a/telephony/java/android/telephony/CellIdentityGsm.java +++ b/telephony/java/android/telephony/CellIdentityGsm.java @@ -18,7 +18,7 @@ package android.telephony; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.telephony.gsm.GsmCellLocation; import android.text.TextUtils; diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java index 15c91752badf..bc4655069dba 100644 --- a/telephony/java/android/telephony/CellIdentityLte.java +++ b/telephony/java/android/telephony/CellIdentityLte.java @@ -18,7 +18,7 @@ package android.telephony; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.UnsupportedAppUsage; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.telephony.gsm.GsmCellLocation; diff --git a/telephony/java/android/telephony/CellInfo.java b/telephony/java/android/telephony/CellInfo.java index 475c99b7fae2..ec86c144c08e 100644 --- a/telephony/java/android/telephony/CellInfo.java +++ b/telephony/java/android/telephony/CellInfo.java @@ -18,6 +18,7 @@ package android.telephony; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.SuppressLint; import android.compat.annotation.UnsupportedAppUsage; import android.hardware.radio.V1_4.CellInfo.Info; import android.os.Parcel; @@ -179,6 +180,18 @@ public abstract class CellInfo implements Parcelable { * * @return a time stamp in nanos since boot. */ + @SuppressLint("MethodNameUnits") + public long getTimestampNanos() { + return mTimeStamp; + } + + /** + * Approximate time this cell information was received from the modem. + * + * @return a time stamp in nanos since boot. + * @deprecated Use {@link #getTimestampNanos} instead. + */ + @Deprecated public long getTimeStamp() { return mTimeStamp; } diff --git a/telephony/java/android/telephony/NetworkRegistrationInfo.java b/telephony/java/android/telephony/NetworkRegistrationInfo.java index cbd5ed665898..32ffb75f373c 100644 --- a/telephony/java/android/telephony/NetworkRegistrationInfo.java +++ b/telephony/java/android/telephony/NetworkRegistrationInfo.java @@ -36,10 +36,7 @@ import java.util.stream.Collectors; /** * Description of a mobile network registration info - * @hide */ -@SystemApi -@TestApi public final class NetworkRegistrationInfo implements Parcelable { /** * Network domain @@ -51,9 +48,9 @@ public final class NetworkRegistrationInfo implements Parcelable { /** Unknown / Unspecified domain */ public static final int DOMAIN_UNKNOWN = 0; - /** Circuit switching domain */ + /** Circuit switched domain */ public static final int DOMAIN_CS = android.hardware.radio.V1_5.Domain.CS; - /** Packet switching domain */ + /** Packet switched domain */ public static final int DOMAIN_PS = android.hardware.radio.V1_5.Domain.PS; /** Applicable to both CS and PS Domain */ public static final int DOMAIN_CS_PS = DOMAIN_CS | DOMAIN_PS; @@ -69,17 +66,41 @@ public final class NetworkRegistrationInfo implements Parcelable { REGISTRATION_STATE_UNKNOWN, REGISTRATION_STATE_ROAMING}) public @interface RegistrationState {} - /** Not registered. The device is not currently searching a new operator to register. */ + /** + * Not registered. The device is not currently searching a new operator to register. + * @hide + */ + @SystemApi @TestApi public static final int REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING = 0; - /** Registered on home network. */ + /** + * Registered on home network. + * @hide + */ + @SystemApi @TestApi public static final int REGISTRATION_STATE_HOME = 1; - /** Not registered. The device is currently searching a new operator to register. */ + /** + * Not registered. The device is currently searching a new operator to register. + * @hide + */ + @SystemApi @TestApi public static final int REGISTRATION_STATE_NOT_REGISTERED_SEARCHING = 2; - /** Registration denied. */ + /** + * Registration denied. + * @hide + */ + @SystemApi @TestApi public static final int REGISTRATION_STATE_DENIED = 3; - /** Registration state is unknown. */ + /** + * Registration state is unknown. + * @hide + */ + @SystemApi @TestApi public static final int REGISTRATION_STATE_UNKNOWN = 4; - /** Registered on roaming network. */ + /** + * Registered on roaming network. + * @hide + */ + @SystemApi @TestApi public static final int REGISTRATION_STATE_ROAMING = 5; /** @hide */ @@ -92,7 +113,6 @@ public final class NetworkRegistrationInfo implements Parcelable { /** * The device isn't camped on an LTE cell or the LTE cell doesn't support E-UTRA-NR * Dual Connectivity(EN-DC). - * @hide */ public static final int NR_STATE_NONE = 0; @@ -100,7 +120,6 @@ public final class NetworkRegistrationInfo implements Parcelable { * The device is camped on an LTE cell that supports E-UTRA-NR Dual Connectivity(EN-DC) but * either the use of dual connectivity with NR(DCNR) is restricted or NR is not supported by * the selected PLMN. - * @hide */ public static final int NR_STATE_RESTRICTED = 1; @@ -108,14 +127,12 @@ public final class NetworkRegistrationInfo implements Parcelable { * The device is camped on an LTE cell that supports E-UTRA-NR Dual Connectivity(EN-DC) and both * the use of dual connectivity with NR(DCNR) is not restricted and NR is supported by the * selected PLMN. - * @hide */ public static final int NR_STATE_NOT_RESTRICTED = 2; /** * The device is camped on an LTE cell that supports E-UTRA-NR Dual Connectivity(EN-DC) and * also connected to at least one 5G cell as a secondary serving cell. - * @hide */ public static final int NR_STATE_CONNECTED = 3; @@ -129,22 +146,34 @@ public final class NetworkRegistrationInfo implements Parcelable { SERVICE_TYPE_VIDEO, SERVICE_TYPE_EMERGENCY}) public @interface ServiceType {} - /** Unkown service */ + /** + * Unknown service + */ public static final int SERVICE_TYPE_UNKNOWN = 0; - /** Voice service */ + /** + * Voice service + */ public static final int SERVICE_TYPE_VOICE = 1; - /** Data service */ + /** + * Data service + */ public static final int SERVICE_TYPE_DATA = 2; - /** SMS service */ + /** + * SMS service + */ public static final int SERVICE_TYPE_SMS = 3; - /** Video service */ + /** + * Video service + */ public static final int SERVICE_TYPE_VIDEO = 4; - /** Emergency service */ + /** + * Emergency service + */ public static final int SERVICE_TYPE_EMERGENCY = 5; @Domain @@ -330,9 +359,7 @@ public final class NetworkRegistrationInfo implements Parcelable { * Get the 5G NR connection state. * * @return the 5G NR connection state. - * @hide */ - @SystemApi public @NRState int getNrState() { return mNrState; } @@ -344,7 +371,10 @@ public final class NetworkRegistrationInfo implements Parcelable { /** * @return The registration state. + * + * @hide */ + @SystemApi @TestApi public @RegistrationState int getRegistrationState() { return mRegistrationState; } @@ -352,6 +382,21 @@ public final class NetworkRegistrationInfo implements Parcelable { /** * @return {@code true} if registered on roaming network, {@code false} otherwise. */ + public boolean isRegistered() { + return mRegistrationState == REGISTRATION_STATE_HOME + || mRegistrationState == REGISTRATION_STATE_ROAMING; + } + + /** + * @return {@code true} if registered on roaming network, {@code false} otherwise. + */ + public boolean isSearching() { + return mRegistrationState == REGISTRATION_STATE_NOT_REGISTERED_SEARCHING; + } + + /** + * @return {@code true} if registered on roaming network, {@code false} otherwise. + */ public boolean isRoaming() { return mRoamingType != ServiceState.ROAMING_TYPE_NOT_ROAMING; } @@ -376,15 +421,18 @@ public final class NetworkRegistrationInfo implements Parcelable { /** * @return the current network roaming type. + * @hide */ - + @SystemApi @TestApi public @ServiceState.RoamingType int getRoamingType() { return mRoamingType; } /** * @return Whether emergency is enabled. + * @hide */ + @SystemApi @TestApi public boolean isEmergencyEnabled() { return mEmergencyOnly; } /** @@ -422,7 +470,9 @@ public final class NetworkRegistrationInfo implements Parcelable { * @return Reason for denial if the registration state is {@link #REGISTRATION_STATE_DENIED}. * Depending on {@code accessNetworkTechnology}, the values are defined in 3GPP TS 24.008 * 10.5.3.6 for UMTS, 3GPP TS 24.301 9.9.3.9 for LTE, and 3GPP2 A.S0001 6.2.2.44 for CDMA + * @hide */ + @SystemApi @TestApi public int getRejectCause() { return mRejectCause; } @@ -445,8 +495,10 @@ public final class NetworkRegistrationInfo implements Parcelable { /** * @return Data registration related info + * @hide */ @Nullable + @SystemApi @TestApi public DataSpecificRegistrationInfo getDataSpecificInfo() { return mDataSpecificInfo; } @@ -571,7 +623,11 @@ public final class NetworkRegistrationInfo implements Parcelable { && mNrState == other.mNrState; } + /** + * @hide + */ @Override + @SystemApi @TestApi public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mDomain); dest.writeInt(mTransportType); @@ -659,7 +715,9 @@ public final class NetworkRegistrationInfo implements Parcelable { * .setRegistrationState(REGISTRATION_STATE_HOME) * .build(); * </code></pre> + * @hide */ + @SystemApi @TestApi public static final class Builder { @Domain private int mDomain; @@ -759,7 +817,9 @@ public final class NetworkRegistrationInfo implements Parcelable { * @param emergencyOnly True if this network registration is for emergency use only. * * @return The same instance of the builder. + * @hide */ + @SystemApi @TestApi public @NonNull Builder setEmergencyOnly(boolean emergencyOnly) { mEmergencyOnly = emergencyOnly; return this; @@ -771,7 +831,9 @@ public final class NetworkRegistrationInfo implements Parcelable { * @param availableServices Available services. * * @return The same instance of the builder. + * @hide */ + @SystemApi @TestApi public @NonNull Builder setAvailableServices( @NonNull @ServiceType List<Integer> availableServices) { mAvailableServices = availableServices; @@ -784,7 +846,9 @@ public final class NetworkRegistrationInfo implements Parcelable { * @param cellIdentity The cell identity. * * @return The same instance of the builder. + * @hide */ + @SystemApi @TestApi public @NonNull Builder setCellIdentity(@Nullable CellIdentity cellIdentity) { mCellIdentity = cellIdentity; return this; @@ -792,9 +856,10 @@ public final class NetworkRegistrationInfo implements Parcelable { /** * Build the NetworkRegistrationInfo. - * * @return the NetworkRegistrationInfo object. + * @hide */ + @SystemApi @TestApi public @NonNull NetworkRegistrationInfo build() { return new NetworkRegistrationInfo(mDomain, mTransportType, mRegistrationState, mAccessNetworkTechnology, mRejectCause, mEmergencyOnly, mAvailableServices, diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java index 4c090b8a96cd..31434c1d2adf 100644 --- a/telephony/java/android/telephony/PreciseDataConnectionState.java +++ b/telephony/java/android/telephony/PreciseDataConnectionState.java @@ -81,18 +81,20 @@ public final class PreciseDataConnectionState implements Parcelable { /** - * Constructor + * Constructor of PreciseDataConnectionState * * @param state the state of the data connection * @param networkType the access network that is/would carry this data connection * @param apnTypes the APN types that this data connection carries - * @param apnSetting if there is a valid APN for this Data Connection, then the APN Settings; - * if there is no valid APN setting for the specific type, then this will be null + * @param apn the APN of this data connection * @param linkProperties if the data connection is connected, the properties of the connection * @param failCause in case a procedure related to this data connection fails, a non-zero error * code indicating the cause of the failure. + * @param apnSetting if there is a valid APN for this Data Connection, then the APN Settings; + * if there is no valid APN setting for the specific type, then this will be null * @hide */ + @SystemApi public PreciseDataConnectionState(@DataState int state, @NetworkType int networkType, @ApnType int apnTypes, @NonNull String apn, diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 2c62d0667e19..ed003ed81ddc 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -16,8 +16,6 @@ package android.telephony; -import com.android.telephony.Rlog; - import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -36,6 +34,8 @@ import android.telephony.NetworkRegistrationInfo.Domain; import android.telephony.NetworkRegistrationInfo.NRState; import android.text.TextUtils; +import com.android.telephony.Rlog; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -584,8 +584,8 @@ public class ServiceState implements Parcelable { */ @DuplexMode public int getDuplexMode() { - // only support LTE duplex mode - if (!isLte(getRilDataRadioTechnology())) { + // support LTE/NR duplex mode + if (!isPsOnlyTech(getRilDataRadioTechnology())) { return DUPLEX_MODE_UNKNOWN; } @@ -1624,7 +1624,8 @@ public class ServiceState implements Parcelable { * @return Current data network type * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P) + @SystemApi + @TestApi public @NetworkType int getDataNetworkType() { final NetworkRegistrationInfo iwlanRegInfo = getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WLAN); @@ -1717,9 +1718,10 @@ public class ServiceState implements Parcelable { } /** @hide */ - public static boolean isLte(int radioTechnology) { - return radioTechnology == RIL_RADIO_TECHNOLOGY_LTE || - radioTechnology == RIL_RADIO_TECHNOLOGY_LTE_CA; + public static boolean isPsOnlyTech(int radioTechnology) { + return radioTechnology == RIL_RADIO_TECHNOLOGY_LTE + || radioTechnology == RIL_RADIO_TECHNOLOGY_LTE_CA + || radioTechnology == RIL_RADIO_TECHNOLOGY_NR; } /** @hide */ @@ -1835,10 +1837,8 @@ public class ServiceState implements Parcelable { * Get all of the available network registration info. * * @return List of {@link NetworkRegistrationInfo} - * @hide */ @NonNull - @SystemApi public List<NetworkRegistrationInfo> getNetworkRegistrationInfoList() { synchronized (mNetworkRegistrationInfos) { List<NetworkRegistrationInfo> newList = new ArrayList<>(); diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java index 4ff1aab32406..483ccc437f89 100644 --- a/telephony/java/android/telephony/SignalStrength.java +++ b/telephony/java/android/telephony/SignalStrength.java @@ -16,15 +16,18 @@ package android.telephony; -import com.android.telephony.Rlog; - import android.annotation.NonNull; +import android.annotation.SuppressLint; +import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Bundle; import android.os.Parcel; import android.os.Parcelable; import android.os.PersistableBundle; +import android.os.SystemClock; + +import com.android.telephony.Rlog; import java.util.ArrayList; import java.util.List; @@ -76,6 +79,9 @@ public class SignalStrength implements Parcelable { /* The type of signal measurement */ private static final String MEASUREMENT_TYPE_RSCP = "rscp"; + // timeStamp of signalStrength in nanoseconds since boot + private long mTimestamp = Long.MAX_VALUE; + CellSignalStrengthCdma mCdma; CellSignalStrengthGsm mGsm; CellSignalStrengthWcdma mWcdma; @@ -134,6 +140,7 @@ public class SignalStrength implements Parcelable { mTdscdma = tdscdma; mLte = lte; mNr = nr; + mTimestamp = SystemClock.elapsedRealtimeNanos(); } /** @@ -268,6 +275,7 @@ public class SignalStrength implements Parcelable { mTdscdma.updateLevel(cc, ss); mLte.updateLevel(cc, ss); mNr.updateLevel(cc, ss); + mTimestamp = SystemClock.elapsedRealtimeNanos(); } /** @@ -277,8 +285,8 @@ public class SignalStrength implements Parcelable { * * @hide */ - @UnsupportedAppUsage - public SignalStrength(SignalStrength s) { + @SystemApi + public SignalStrength(@NonNull SignalStrength s) { copyFrom(s); } @@ -293,6 +301,7 @@ public class SignalStrength implements Parcelable { mTdscdma = new CellSignalStrengthTdscdma(s.mTdscdma); mLte = new CellSignalStrengthLte(s.mLte); mNr = new CellSignalStrengthNr(s.mNr); + mTimestamp = s.getTimestampNanos(); } /** @@ -310,6 +319,7 @@ public class SignalStrength implements Parcelable { mTdscdma = in.readParcelable(CellSignalStrengthTdscdma.class.getClassLoader()); mLte = in.readParcelable(CellSignalStrengthLte.class.getClassLoader()); mNr = in.readParcelable(CellSignalStrengthLte.class.getClassLoader()); + mTimestamp = in.readLong(); } /** @@ -322,9 +332,18 @@ public class SignalStrength implements Parcelable { out.writeParcelable(mTdscdma, flags); out.writeParcelable(mLte, flags); out.writeParcelable(mNr, flags); + out.writeLong(mTimestamp); } /** + * @return mTimestamp in nanoseconds + */ + @SuppressLint("MethodNameUnits") + public long getTimestampNanos() { + return mTimestamp; + } + + /** * {@link Parcelable#describeContents} */ public int describeContents() { diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index db90550c5331..b5dea7c02148 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -2425,16 +2425,6 @@ public final class SmsManager { /** Intent extra name for HTTP status code for MMS HTTP failure in integer type */ public static final String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS"; - /** Represents the received SMS message for importing {@hide} */ - public static final int SMS_TYPE_INCOMING = 0; - /** Represents the sent SMS message for importing {@hide} */ - public static final int SMS_TYPE_OUTGOING = 1; - - /** Message status property: whether the message has been seen. 1 means seen, 0 not {@hide} */ - public static final String MESSAGE_STATUS_SEEN = "seen"; - /** Message status property: whether the message has been read. 1 means read, 0 not {@hide} */ - public static final String MESSAGE_STATUS_READ = "read"; - /** * Get carrier-dependent MMS configuration values. * diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java index c217b8b83c26..30a61c31ab81 100644 --- a/telephony/java/android/telephony/SmsMessage.java +++ b/telephony/java/android/telephony/SmsMessage.java @@ -20,8 +20,13 @@ import com.android.telephony.Rlog; import static android.telephony.TelephonyManager.PHONE_TYPE_CDMA; +import android.Manifest; +import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.StringDef; +import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.os.Binder; @@ -31,8 +36,10 @@ import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.GsmAlphabet.TextEncodingDetails; import com.android.internal.telephony.Sms7BitEncodingTranslator; import com.android.internal.telephony.SmsConstants; +import com.android.internal.telephony.SmsHeader; import com.android.internal.telephony.SmsMessageBase; import com.android.internal.telephony.SmsMessageBase.SubmitPduBase; +import com.android.internal.telephony.cdma.sms.UserData; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -56,6 +63,16 @@ public class SmsMessage { UNKNOWN, CLASS_0, CLASS_1, CLASS_2, CLASS_3; } + /** @hide */ + @IntDef(prefix = { "ENCODING_" }, value = { + ENCODING_UNKNOWN, + ENCODING_7BIT, + ENCODING_8BIT, + ENCODING_16BIT + }) + @Retention(RetentionPolicy.SOURCE) + public @interface EncodingSize {} + /** User data text encoding code unit size */ public static final int ENCODING_UNKNOWN = 0; public static final int ENCODING_7BIT = 1; @@ -315,6 +332,34 @@ public class SmsMessage { } /** + * Create an SmsMessage from a native SMS-Submit PDU, specified by Bluetooth Message Access + * Profile Specification v1.4.2 5.8. + * This is used by Bluetooth MAP profile to decode message when sending non UTF-8 SMS messages. + * + * @param data Message data. + * @param isCdma Indicates weather the type of the SMS is CDMA. + * @return An SmsMessage representing the message. + * + * @hide + */ + @SystemApi + @Nullable + public static SmsMessage createFromNativeSmsSubmitPdu(@NonNull byte[] data, boolean isCdma) { + SmsMessageBase wrappedMessage; + + if (isCdma) { + wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromEfRecord( + 0, data); + } else { + // Bluetooth uses its own method to decode GSM PDU so this part is not called. + wrappedMessage = com.android.internal.telephony.gsm.SmsMessage.createFromEfRecord( + 0, data); + } + + return wrappedMessage != null ? new SmsMessage(wrappedMessage) : null; + } + + /** * Get the TP-Layer-Length for the given SMS-SUBMIT PDU Basically, the * length in bytes (not hex chars) less the SMSC header * @@ -633,6 +678,83 @@ public class SmsMessage { } /** + * Get an SMS-SUBMIT PDU's encoded message. + * This is used by Bluetooth MAP profile to handle long non UTF-8 SMS messages. + * + * @param isTypeGsm true when message's type is GSM, false when type is CDMA + * @param destinationAddress the address of the destination for the message + * @param message message content + * @param encoding User data text encoding code unit size + * @param languageTable GSM national language table to use, specified by 3GPP + * 23.040 9.2.3.24.16 + * @param languageShiftTable GSM national language shift table to use, specified by 3GPP + * 23.040 9.2.3.24.15 + * @param refNumber parameter to create SmsHeader + * @param seqNumber parameter to create SmsHeader + * @param msgCount parameter to create SmsHeader + * @return a byte[] containing the encoded message + * + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED) + @SystemApi + @NonNull + public static byte[] getSubmitPduEncodedMessage(boolean isTypeGsm, + @NonNull String destinationAddress, + @NonNull String message, + @EncodingSize int encoding, int languageTable, + int languageShiftTable, int refNumber, + int seqNumber, int msgCount) { + byte[] data; + SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef(); + concatRef.refNumber = refNumber; + concatRef.seqNumber = seqNumber; // 1-based sequence + concatRef.msgCount = msgCount; + // We currently set this to true since our messaging app will never + // send more than 255 parts (it converts the message to MMS well before that). + // However, we should support 3rd party messaging apps that might need 16-bit + // references + // Note: It's not sufficient to just flip this bit to true; it will have + // ripple effects (several calculations assume 8-bit ref). + concatRef.isEightBits = true; + SmsHeader smsHeader = new SmsHeader(); + smsHeader.concatRef = concatRef; + + /* Depending on the type, call either GSM or CDMA getSubmitPdu(). The encoding + * will be determined(again) by getSubmitPdu(). + * All packets need to be encoded using the same encoding, as the bMessage + * only have one filed to describe the encoding for all messages in a concatenated + * SMS... */ + if (encoding == ENCODING_7BIT) { + smsHeader.languageTable = languageTable; + smsHeader.languageShiftTable = languageShiftTable; + } + + if (isTypeGsm) { + data = com.android.internal.telephony.gsm.SmsMessage.getSubmitPdu(null, + destinationAddress, message, false, + SmsHeader.toByteArray(smsHeader), encoding, languageTable, + languageShiftTable).encodedMessage; + } else { // SMS_TYPE_CDMA + UserData uData = new UserData(); + uData.payloadStr = message; + uData.userDataHeader = smsHeader; + if (encoding == ENCODING_7BIT) { + uData.msgEncoding = UserData.ENCODING_GSM_7BIT_ALPHABET; + } else { // assume UTF-16 + uData.msgEncoding = UserData.ENCODING_UNICODE_16; + } + uData.msgEncodingSet = true; + data = com.android.internal.telephony.cdma.SmsMessage.getSubmitPdu( + destinationAddress, uData, false).encodedMessage; + } + if (data == null) { + return new byte[0]; + } + return data; + } + + /** * Returns the address of the SMS service center that relayed this message * or null if there is none. */ diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 262cf1a92c89..bd8321e21f1b 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -1950,6 +1950,16 @@ public class TelephonyManager { public static final int PHONE_TYPE_CDMA = PhoneConstants.PHONE_TYPE_CDMA; /** Phone is via SIP. */ public static final int PHONE_TYPE_SIP = PhoneConstants.PHONE_TYPE_SIP; + /** Phone is via IMS. */ + public static final int PHONE_TYPE_IMS = PhoneConstants.PHONE_TYPE_IMS; + + /** + * Phone is via Third Party. + * + * @hide + */ + @SystemApi + public static final int PHONE_TYPE_THIRD_PARTY = PhoneConstants.PHONE_TYPE_THIRD_PARTY; /** * Returns the current phone type. @@ -9093,15 +9103,20 @@ public class TelephonyManager { } /** - * Requested state of SIM - * - * CARD_POWER_DOWN * Powers down the SIM. SIM must be up prior. - * - * CARD_POWER_UP + * @hide + */ + @SystemApi + public static final int CARD_POWER_DOWN = 0; + + /** * Powers up the SIM normally. SIM must be down prior. - * - * CARD_POWER_UP_PASS_THROUGH + * @hide + */ + @SystemApi + public static final int CARD_POWER_UP = 1; + + /** * Powers up the SIM in PASS_THROUGH mode. SIM must be down prior. * When SIM is powered up in PASS_THOUGH mode, the modem does not send * any command to it (for example SELECT of MF, or TERMINAL CAPABILITY), @@ -9114,12 +9129,9 @@ public class TelephonyManager { * is activated, and normal behavior occurs at the next SIM initialization, * unless PASS_THROUGH mode is requested again. Hence, the last power-up mode * is NOT persistent across boots. On reboot, SIM will power up normally. + * @hide */ - /** @hide */ - public static final int CARD_POWER_DOWN = 0; - /** @hide */ - public static final int CARD_POWER_UP = 1; - /** @hide */ + @SystemApi public static final int CARD_POWER_UP_PASS_THROUGH = 2; /** @@ -10272,6 +10284,7 @@ public class TelephonyManager { * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}. * * @param enabled control enable or disable carrier data. + * @see #resetAllCarrierActions() * @hide */ @SystemApi @@ -10298,6 +10311,7 @@ public class TelephonyManager { * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}. * * @param enabled control enable or disable radio. + * @see #resetAllCarrierActions() * @hide */ @SystemApi @@ -10324,6 +10338,7 @@ public class TelephonyManager { * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}. * * @param report control start/stop reporting network status. + * @see #resetAllCarrierActions() * @hide */ @SystemApi @@ -11750,6 +11765,32 @@ public class TelephonyManager { } /** + * Get the calling application status about carrier privileges for the subscription created + * in TelephonyManager. Used by Telephony Module for permission checking. + * + * @param uid Uid to check. + * @return any value of {@link #CARRIER_PRIVILEGE_STATUS_HAS_ACCESS}, + * {@link #CARRIER_PRIVILEGE_STATUS_NO_ACCESS}, + * {@link #CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED}, or + * {@link #CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES} + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public int getCarrierPrivilegeStatus(int uid) { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.getCarrierPrivilegeStatusForUid(getSubId(), uid); + } + } catch (RemoteException ex) { + Log.e(TAG, "getCarrierPrivilegeStatus RemoteException", ex); + } + return TelephonyManager.CARRIER_PRIVILEGE_STATUS_NO_ACCESS; + } + + /** * Returns a list of APNs set as overrides by the device policy manager via * {@link #addDevicePolicyOverrideApn}. * This method must only be called from the system or phone processes. diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java index 998b39dfb436..d6dea2c8974b 100644 --- a/telephony/java/android/telephony/ims/ImsCallProfile.java +++ b/telephony/java/android/telephony/ims/ImsCallProfile.java @@ -18,6 +18,7 @@ package android.telephony.ims; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; @@ -40,10 +41,11 @@ import java.util.ArrayList; import java.util.List; /** - * Parcelable object to handle IMS call profile. - * It is created from GSMA IR.92/IR.94, 3GPP TS 24.229/TS 26.114/TS26.111. - * It provides the service and call type, the additional information related to the call. - * + * A Parcelable object to handle the IMS call profile, which provides the service, call type, and + * additional information related to the call. + * <p> + * See the following specifications for more information about this class: GSMA IR.92/IR.94, + * 3GPP TS 24.229/TS 26.114/TS26.111. * @hide */ @SystemApi @@ -151,12 +153,13 @@ public final class ImsCallProfile implements Parcelable { */ public static final String EXTRA_CONFERENCE_AVAIL = "conference_avail"; - // Extra string for internal use only. OEMs should not use - // this for packing extras. /** + * Extra key used to store a Bundle containing proprietary extras to send to the ImsService. + * Use {@link #getProprietaryCallExtras()} instead. * @hide */ - public static final String EXTRA_OEM_EXTRAS = "OemCallExtras"; + @TestApi + public static final String EXTRA_OEM_EXTRAS = "android.telephony.ims.extra.OEM_EXTRAS"; /** * Rule for originating identity (number) presentation, MO/MT. @@ -679,6 +682,18 @@ public final class ImsCallProfile implements Parcelable { return mCallExtras; } + /** + * Get the proprietary extras set for this ImsCallProfile. + * @return A {@link Bundle} containing proprietary call extras that were not set by the + * platform. + */ + public @Nullable Bundle getProprietaryCallExtras() { + if (mCallExtras == null) { + return null; + } + return mCallExtras.getBundle(EXTRA_OEM_EXTRAS); + } + public ImsStreamMediaProfile getMediaProfile() { return mMediaProfile; } diff --git a/telephony/java/android/telephony/ims/ImsException.java b/telephony/java/android/telephony/ims/ImsException.java index 39af2e770882..cb3f0f92625e 100644 --- a/telephony/java/android/telephony/ims/ImsException.java +++ b/telephony/java/android/telephony/ims/ImsException.java @@ -30,10 +30,7 @@ import java.lang.annotation.RetentionPolicy; /** * This class defines an IMS-related exception that has been thrown while interacting with a * device or carrier provided ImsService implementation. - * @hide */ -@SystemApi -@TestApi public final class ImsException extends Exception { /** @@ -83,7 +80,10 @@ public final class ImsException extends Exception { /** * A new {@link ImsException} with an unspecified {@link ImsErrorCode} code. * @param message an optional message to detail the error condition more specifically. + * @hide */ + @SystemApi + @TestApi public ImsException(@Nullable String message) { super(getMessage(message, CODE_ERROR_UNSPECIFIED)); } @@ -91,7 +91,10 @@ public final class ImsException extends Exception { /** * A new {@link ImsException} that includes an {@link ImsErrorCode} error code. * @param message an optional message to detail the error condition more specifically. + * @hide */ + @SystemApi + @TestApi public ImsException(@Nullable String message, @ImsErrorCode int code) { super(getMessage(message, code)); mCode = code; @@ -102,7 +105,10 @@ public final class ImsException extends Exception { * {@link Throwable} that contains the original error that was thrown to lead to this Exception. * @param message an optional message to detail the error condition more specifically. * @param cause the {@link Throwable} that caused this {@link ImsException} to be created. + * @hide */ + @SystemApi + @TestApi public ImsException(@Nullable String message, @ImsErrorCode int code, @Nullable Throwable cause) { super(getMessage(message, code), cause); diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java index 5fd0af564d34..c66672f13129 100644 --- a/telephony/java/android/telephony/ims/ImsMmTelManager.java +++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java @@ -23,6 +23,8 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SuppressAutoDoc; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; import android.content.Context; @@ -56,10 +58,7 @@ import java.util.function.Consumer; * associated subscription. * * @see #createForSubscriptionId(int) - * @hide */ -@SystemApi -@TestApi public class ImsMmTelManager implements RegistrationManager { /** @@ -94,9 +93,11 @@ public class ImsMmTelManager implements RegistrationManager { * @see #registerImsRegistrationCallback(Executor, RegistrationCallback) (RegistrationCallback) * @see #unregisterImsRegistrationCallback(RegistrationCallback) * @deprecated Use {@link RegistrationManager.RegistrationCallback} instead. + * @hide */ // Do not add to this class, add to RegistrationManager.RegistrationCallback instead. @Deprecated + @SystemApi @TestApi public static class RegistrationCallback extends RegistrationManager.RegistrationCallback { /** @@ -141,7 +142,7 @@ public class ImsMmTelManager implements RegistrationManager { /** * Receives IMS capability status updates from the ImsService. This information is also - * available via the {@link #isAvailable(int, int)} method below. + * available via the {@see #isAvailable(int, int)} method below. * * @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback) (CapabilityCallback) * @see #unregisterMmTelCapabilityCallback(CapabilityCallback) @@ -190,7 +191,7 @@ public class ImsMmTelManager implements RegistrationManager { * If unavailable, the feature is not able to support the unavailable capability at this * time. * - * This information can also be queried using the {@link #isAvailable(int, int)} API. + * This information can also be queried using the {@see #isAvailable(int, int)} API. * * @param capabilities The new availability of the capabilities. */ @@ -218,8 +219,20 @@ public class ImsMmTelManager implements RegistrationManager { * * @param subId The ID of the subscription that this ImsMmTelManager will use. * @see android.telephony.SubscriptionManager#getActiveSubscriptionInfoList() + * + * <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE + * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges + * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}). + * * @throws IllegalArgumentException if the subscription is invalid. + * */ + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + android.Manifest.permission.READ_PRECISE_PHONE_STATE + }) + @SuppressLint("ManagerLookup") public static @NonNull ImsMmTelManager createForSubscriptionId(int subId) { if (!SubscriptionManager.isValidSubscriptionId(subId)) { throw new IllegalArgumentException("Invalid subscription ID"); @@ -258,8 +271,10 @@ public class ImsMmTelManager implements RegistrationManager { * reason. * @deprecated Use {@link RegistrationManager#registerImsRegistrationCallback(Executor, * RegistrationManager.RegistrationCallback)} instead. + * @hide */ @Deprecated + @SystemApi @TestApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull @CallbackExecutor Executor executor, @NonNull RegistrationCallback c) throws ImsException { @@ -284,9 +299,20 @@ public class ImsMmTelManager implements RegistrationManager { } } - /**{@inheritDoc}*/ + /** + * + * <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE + * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges + * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}). + * + * {@inheritDoc} + * + */ @Override - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void registerImsRegistrationCallback(@NonNull @CallbackExecutor Executor executor, @NonNull RegistrationManager.RegistrationCallback c) throws ImsException { if (c == null) { @@ -317,8 +343,10 @@ public class ImsMmTelManager implements RegistrationManager { * @see #registerImsRegistrationCallback(Executor, RegistrationCallback) * @deprecated Use {@link #unregisterImsRegistrationCallback( * RegistrationManager.RegistrationCallback)}. + * @hide */ @Deprecated + @SystemApi @TestApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull RegistrationCallback c) { if (c == null) { @@ -331,9 +359,20 @@ public class ImsMmTelManager implements RegistrationManager { } } - /**{@inheritDoc}*/ + /** + * + * <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE + * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges + * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}). + * Access by profile owners is deprecated and will be removed in a future release. + * + *{@inheritDoc} + */ @Override - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void unregisterImsRegistrationCallback( @NonNull RegistrationManager.RegistrationCallback c) { if (c == null) { @@ -346,9 +385,13 @@ public class ImsMmTelManager implements RegistrationManager { } } - /**{@inheritDoc}*/ + /** + * {@inheritDoc} + * @hide + */ @Override - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SystemApi @TestApi + @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getRegistrationState(@NonNull @CallbackExecutor Executor executor, @NonNull @ImsRegistrationState Consumer<Integer> stateCallback) { if (stateCallback == null) { @@ -369,9 +412,19 @@ public class ImsMmTelManager implements RegistrationManager { } } - /**{@inheritDoc}*/ + /** + * <p>Requires Permission: {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE + * READ_PRECISE_PHONE_STATE} or that the calling app has carrier privileges + * (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}). + * Access by profile owners is deprecated and will be removed in a future release. + * + *{@inheritDoc} + */ @Override - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void getRegistrationTransportType(@NonNull @CallbackExecutor Executor executor, @NonNull @AccessNetworkConstants.TransportType Consumer<Integer> transportTypeCallback) { @@ -397,12 +450,25 @@ public class ImsMmTelManager implements RegistrationManager { /** * Registers a {@link CapabilityCallback} with the system, which will provide MmTel service * availability updates for the subscription specified in - * {@link #createForSubscriptionId(int)}. The method {@link #isAvailable(int, int)} + * {@link #createForSubscriptionId(int)}. The method {@see #isAvailable(int, int)} * can also be used to query this information at any time. * * Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to * subscription changed events and call * {@link #unregisterMmTelCapabilityCallback(CapabilityCallback)} to clean up. + * <p>This API requires one of the following: + * <ul> + * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li> + * <li>If the caller is the device or profile owner, the caller holds the + * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li> + * <li>The caller has carrier privileges (see + * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any + * active subscription.</li> + * <li>The caller is the default SMS app for the device.</li> + * </ul> + * <p>The profile owner is an app that owns a managed profile on the device; for more details + * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. + * Access by profile owners is deprecated and will be removed in a future release. * * When the callback is registered, it will initiate the callback c to be called with the * current capabilities. @@ -418,7 +484,10 @@ public class ImsMmTelManager implements RegistrationManager { * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed * reason. */ - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void registerMmTelCapabilityCallback(@NonNull @CallbackExecutor Executor executor, @NonNull CapabilityCallback c) throws ImsException { if (c == null) { @@ -450,10 +519,27 @@ public class ImsMmTelManager implements RegistrationManager { * When the subscription associated with this callback is removed (SIM removed, ESIM swap, * etc...), this callback will automatically be removed. If this method is called for an * inactive subscription, it will result in a no-op. + * <p>This API requires one of the following: + * <ul> + * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li> + * <li>If the caller is the device or profile owner, the caller holds the + * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li> + * <li>The caller has carrier privileges (see + * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any + * active subscription.</li> + * <li>The caller is the default SMS app for the device.</li> + * </ul> + * <p>The profile owner is an app that owns a managed profile on the device; for more details + * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. + * Access by profile owners is deprecated and will be removed in a future release. + * * @param c The MmTel {@link CapabilityCallback} to be removed. * @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback) */ - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void unregisterMmTelCapabilityCallback(@NonNull CapabilityCallback c) { if (c == null) { throw new IllegalArgumentException("Must include a non-null RegistrationCallback."); @@ -475,6 +561,19 @@ public class ImsMmTelManager implements RegistrationManager { * <p> * Note: If the carrier configuration for advanced calling is not editable or hidden, this * method will always return the default value. + * <p>This API requires one of the following: + * <ul> + * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li> + * <li>If the caller is the device or profile owner, the caller holds the + * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li> + * <li>The caller has carrier privileges (see + * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any + * active subscription.</li> + * <li>The caller is the default SMS app for the device.</li> + * </ul> + * <p>The profile owner is an app that owns a managed profile on the device; for more details + * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. + * Access by profile owners is deprecated and will be removed in a future release. * * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL * @see android.telephony.CarrierConfigManager#KEY_EDITABLE_ENHANCED_4G_LTE_BOOL @@ -486,7 +585,10 @@ public class ImsMmTelManager implements RegistrationManager { * active (SIM is not inserted, ESIM inactive) or invalid. * @return true if the user's setting for advanced calling is enabled, false otherwise. */ - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isAdvancedCallingSettingEnabled() { try { return getITelephony().isAdvancedCallingSettingEnabled(mSubId); @@ -524,8 +626,10 @@ public class ImsMmTelManager implements RegistrationManager { * @see #isAdvancedCallingSettingEnabled() * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. + * @hide */ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) + @SystemApi @TestApi public void setAdvancedCallingSettingEnabled(boolean isEnabled) { try { getITelephony().setAdvancedCallingSettingEnabled(mSubId, isEnabled); @@ -556,13 +660,15 @@ public class ImsMmTelManager implements RegistrationManager { * {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN} * @param capability The IMS MmTel capability to query, can be one of the following: * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE}, - * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO, + * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO}, * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT}, * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS} * @return {@code true} if the MmTel IMS capability is capable for this subscription, false * otherwise. + * @hide */ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SystemApi @TestApi public boolean isCapable(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability, @ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech) { try { @@ -583,12 +689,14 @@ public class ImsMmTelManager implements RegistrationManager { * {@link ImsRegistrationImplBase#REGISTRATION_TECH_IWLAN} * @param capability The IMS MmTel capability to query, can be one of the following: * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE}, - * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO, + * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO}, * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_UT}, * {@link MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_SMS} * @return {@code true} if the MmTel IMS capability is available for this subscription, false * otherwise. + * @hide */ + @SystemApi @TestApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isAvailable(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability, @ImsRegistrationImplBase.ImsRegistrationTech int imsRegTech) { @@ -613,7 +721,9 @@ public class ImsMmTelManager implements RegistrationManager { * capability is supported on this carrier network for the transport specified. * @throws ImsException if the subscription is no longer valid or the IMS service is not * available. + * @hide */ + @SystemApi @TestApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void isSupported(@MmTelFeature.MmTelCapabilities.MmTelCapability int capability, @AccessNetworkConstants.TransportType int transportType, @@ -642,12 +752,32 @@ public class ImsMmTelManager implements RegistrationManager { /** * The user's setting for whether or not they have enabled the "Video Calling" setting. * + * <p> + * Note: If the carrier configuration for advanced calling is not editable or hidden, this + * method will always return the default value. + * <p>This API requires one of the following: + * <ul> + * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li> + * <li>If the caller is the device or profile owner, the caller holds the + * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li> + * <li>The caller has carrier privileges (see + * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any + * active subscription.</li> + * <li>The caller is the default SMS app for the device.</li> + * </ul> + * <p>The profile owner is an app that owns a managed profile on the device; for more details + * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. + * Access by profile owners is deprecated and will be removed in a future release. + * * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. * @return true if the user’s “Video Calling” setting is currently enabled. * @see #setVtSettingEnabled(boolean) */ - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + android.Manifest.permission.READ_PRECISE_PHONE_STATE}) + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). public boolean isVtSettingEnabled() { try { return getITelephony().isVtSettingEnabled(mSubId); @@ -669,7 +799,9 @@ public class ImsMmTelManager implements RegistrationManager { * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. * @see #isVtSettingEnabled() + * @hide */ + @SystemApi @TestApi @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void setVtSettingEnabled(boolean isEnabled) { try { @@ -689,11 +821,28 @@ public class ImsMmTelManager implements RegistrationManager { /** * @return true if the user's setting for Voice over WiFi is enabled and false if it is not. * + * <p>This API requires one of the following: + * <ul> + * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li> + * <li>If the caller is the device or profile owner, the caller holds the + * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li> + * <li>The caller has carrier privileges (see + * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any + * active subscription.</li> + * <li>The caller is the default SMS app for the device.</li> + * </ul> + * <p>The profile owner is an app that owns a managed profile on the device; for more details + * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. + * Access by profile owners is deprecated and will be removed in a future release. + * * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. * @see #setVoWiFiSettingEnabled(boolean) */ - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isVoWiFiSettingEnabled() { try { return getITelephony().isVoWiFiSettingEnabled(mSubId); @@ -716,7 +865,9 @@ public class ImsMmTelManager implements RegistrationManager { * active (SIM is not inserted, ESIM inactive) or invalid. * @param isEnabled true if the user's setting for Voice over WiFi is enabled, false otherwise= * @see #isVoWiFiSettingEnabled() + * @hide */ + @SystemApi @TestApi @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiSettingEnabled(boolean isEnabled) { try { @@ -736,13 +887,30 @@ public class ImsMmTelManager implements RegistrationManager { /** * Returns the user's voice over WiFi roaming setting associated with the current subscription. * + * <p>This API requires one of the following: + * <ul> + * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li> + * <li>If the caller is the device or profile owner, the caller holds the + * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li> + * <li>The caller has carrier privileges (see + * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any + * active subscription.</li> + * <li>The caller is the default SMS app for the device.</li> + * </ul> + * <p>The profile owner is an app that owns a managed profile on the device; for more details + * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. + * Access by profile owners is deprecated and will be removed in a future release. + * * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. * @return true if the user's setting for Voice over WiFi while roaming is enabled, false * if disabled. * @see #setVoWiFiRoamingSettingEnabled(boolean) */ - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isVoWiFiRoamingSettingEnabled() { try { return getITelephony().isVoWiFiRoamingSettingEnabled(mSubId); @@ -766,7 +934,9 @@ public class ImsMmTelManager implements RegistrationManager { * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. * @see #isVoWiFiRoamingSettingEnabled() + * @hide */ + @SystemApi @TestApi @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiRoamingSettingEnabled(boolean isEnabled) { try { @@ -796,7 +966,9 @@ public class ImsMmTelManager implements RegistrationManager { * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. * @see #setVoWiFiSettingEnabled(boolean) + * @hide */ + @SystemApi @TestApi @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiNonPersistent(boolean isCapable, int mode) { try { @@ -816,6 +988,20 @@ public class ImsMmTelManager implements RegistrationManager { /** * Returns the user's voice over WiFi Roaming mode setting associated with the device. * + * <p>This API requires one of the following: + * <ul> + * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li> + * <li>If the caller is the device or profile owner, the caller holds the + * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li> + * <li>The caller has carrier privileges (see + * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any + * active subscription.</li> + * <li>The caller is the default SMS app for the device.</li> + * </ul> + * <p>The profile owner is an app that owns a managed profile on the device; for more details + * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. + * Access by profile owners is deprecated and will be removed in a future release. + * * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. * @return The Voice over WiFi Mode preference set by the user, which can be one of the @@ -825,7 +1011,10 @@ public class ImsMmTelManager implements RegistrationManager { * - {@link #WIFI_MODE_WIFI_PREFERRED} * @see #setVoWiFiSettingEnabled(boolean) */ - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public @WiFiCallingMode int getVoWiFiModeSetting() { try { return getITelephony().getVoWiFiModeSetting(mSubId); @@ -851,7 +1040,9 @@ public class ImsMmTelManager implements RegistrationManager { * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. * @see #getVoWiFiModeSetting() + * @hide */ + @SystemApi @TestApi @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiModeSetting(@WiFiCallingMode int mode) { try { @@ -880,7 +1071,9 @@ public class ImsMmTelManager implements RegistrationManager { * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. * @see #setVoWiFiRoamingSettingEnabled(boolean) + * @hide */ + @SystemApi @TestApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public @WiFiCallingMode int getVoWiFiRoamingModeSetting() { try { @@ -909,7 +1102,9 @@ public class ImsMmTelManager implements RegistrationManager { * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. * @see #getVoWiFiRoamingModeSetting() + * @hide */ + @SystemApi @TestApi @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void setVoWiFiRoamingModeSetting(@WiFiCallingMode int mode) { try { @@ -936,7 +1131,9 @@ public class ImsMmTelManager implements RegistrationManager { * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. * @param isEnabled if true RTT should be enabled during calls made on this subscription. + * @hide */ + @SystemApi @TestApi @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void setRttCapabilitySetting(boolean isEnabled) { try { @@ -956,12 +1153,29 @@ public class ImsMmTelManager implements RegistrationManager { /** * @return true if TTY over VoLTE is supported * + * <p>This API requires one of the following: + * <ul> + * <li>The caller holds the READ_PRECISE_PHONE_STATE permission.</li> + * <li>If the caller is the device or profile owner, the caller holds the + * {@link Manifest.permission#READ_PRECISE_PHONE_STATE} permission.</li> + * <li>The caller has carrier privileges (see + * {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on any + * active subscription.</li> + * <li>The caller is the default SMS app for the device.</li> + * </ul> + * <p>The profile owner is an app that owns a managed profile on the device; for more details + * see <a href="https://developer.android.com/work/managed-profiles">Work profiles</a>. + * Access by profile owners is deprecated and will be removed in a future release. + * * @throws IllegalArgumentException if the subscription associated with this operation is not * active (SIM is not inserted, ESIM inactive) or invalid. * @see android.telecom.TelecomManager#getCurrentTtyMode * @see android.telephony.CarrierConfigManager#KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL */ - @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + @SuppressAutoDoc // No support for device / profile owner or carrier privileges (b/72967236). + @RequiresPermission(anyOf = { + android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isTtyOverVolteEnabled() { try { return getITelephony().isTtyOverVolteEnabled(mSubId); @@ -988,7 +1202,9 @@ public class ImsMmTelManager implements RegistrationManager { * specified when the service state has been retrieved from the IMS service. * @throws ImsException if the IMS service associated with this subscription is not available or * the IMS service is not available. + * @hide */ + @SystemApi @TestApi @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull @CallbackExecutor Executor executor, @NonNull @ImsFeature.ImsState Consumer<Integer> callback) throws ImsException { diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java index 1b1a135952fb..666a688e8cc0 100644 --- a/telephony/java/android/telephony/ims/ProvisioningManager.java +++ b/telephony/java/android/telephony/ims/ProvisioningManager.java @@ -26,11 +26,10 @@ import android.annotation.SystemApi; import android.annotation.TestApi; import android.annotation.WorkerThread; import android.content.Context; -import android.content.pm.IPackageManager; -import android.content.pm.PackageManager; import android.os.Binder; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.ServiceSpecificException; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.ims.aidl.IImsConfigCallback; @@ -376,13 +375,11 @@ public class ProvisioningManager { @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void registerProvisioningChangedCallback(@NonNull @CallbackExecutor Executor executor, @NonNull Callback callback) throws ImsException { - if (!isImsAvailableOnDevice()) { - throw new ImsException("IMS not available on device.", - ImsException.CODE_ERROR_UNSUPPORTED_OPERATION); - } callback.setExecutor(executor); try { getITelephony().registerImsProvisioningChangedCallback(mSubId, callback.getBinder()); + } catch (ServiceSpecificException e) { + throw new ImsException(e.getMessage(), e.errorCode); } catch (RemoteException | IllegalStateException e) { throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); } @@ -591,35 +588,25 @@ public class ProvisioningManager { /** * Notify the framework that an RCS autoconfiguration XML file has been received for * provisioning. + * <p> + * Requires Permission: Manifest.permission.MODIFY_PHONE_STATE or that the calling app has + * carrier privileges (see {@link #hasCarrierPrivileges}). * @param config The XML file to be read. ASCII/UTF8 encoded text if not compressed. * @param isCompressed The XML file is compressed in gzip format and must be decompressed * before being read. - * @hide + * */ @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE) public void notifyRcsAutoConfigurationReceived(@NonNull byte[] config, boolean isCompressed) { if (config == null) { throw new IllegalArgumentException("Must include a non-null config XML file."); } - // TODO: Connect to ImsConfigImplBase. - throw new UnsupportedOperationException("notifyRcsAutoConfigurationReceived is not" - + "supported"); - } - - private static boolean isImsAvailableOnDevice() { - IPackageManager pm = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); - if (pm == null) { - // For some reason package manger is not available.. This will fail internally anyways, - // so do not throw error and allow. - return true; - } try { - return pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS, 0); + getITelephony().notifyRcsAutoConfigurationReceived(mSubId, config, isCompressed); } catch (RemoteException e) { - // For some reason package manger is not available.. This will fail internally anyways, - // so do not throw error and allow. + throw e.rethrowAsRuntimeException(); } - return true; + } private static ITelephony getITelephony() { diff --git a/telephony/java/android/telephony/ims/RcsContactUceCapability.java b/telephony/java/android/telephony/ims/RcsContactUceCapability.java index 893a311e646b..3e2903fa6f47 100644 --- a/telephony/java/android/telephony/ims/RcsContactUceCapability.java +++ b/telephony/java/android/telephony/ims/RcsContactUceCapability.java @@ -83,8 +83,23 @@ public final class RcsContactUceCapability implements Parcelable { public static final int CAPABILITY_RCS_VOICE_CALL = (1 << 19); /** Supports RCS video calling */ public static final int CAPABILITY_RCS_VIDEO_CALL = (1 << 20); - /** Supports RCS video calling, where video media can not be dropped */ + /** Supports RCS video calling, where video media can not be dropped. */ public static final int CAPABILITY_RCS_VIDEO_ONLY_CALL = (1 << 21); + /** Supports call composer, where outgoing calls can be enriched with pre-call content.*/ + public static final int CAPABILITY_CALL_COMPOSER = (1 << 22); + /** Supports post call information that is included in the call if the call is missed.*/ + public static final int CAPABILITY_POST_CALL = (1 << 23); + /** Supports sharing a map where the user can draw, share markers, and share their position. */ + public static final int CAPABILITY_SHARED_MAP = (1 << 24); + /** Supports sharing a canvas, where users can draw, add images, and change background colors.*/ + public static final int CAPABILITY_SHARED_SKETCH = (1 << 25); + /** Supports communication with Chatbots. */ + public static final int CAPABILITY_CHAT_BOT = (1 << 26); + /** Supports Chatbot roles. */ + public static final int CAPABILITY_CHAT_BOT_ROLE = (1 << 27); + /** Supports the unidirectional plug-ins framework. */ + public static final int CAPABILITY_PLUG_IN = (1 << 28); + /** @hide*/ @Retention(RetentionPolicy.SOURCE) @@ -110,7 +125,14 @@ public final class RcsContactUceCapability implements Parcelable { CAPABILITY_GEOLOCATION_PULL_FILE_TRANSFER, CAPABILITY_RCS_VOICE_CALL, CAPABILITY_RCS_VIDEO_CALL, - CAPABILITY_RCS_VIDEO_ONLY_CALL + CAPABILITY_RCS_VIDEO_ONLY_CALL, + CAPABILITY_CALL_COMPOSER, + CAPABILITY_POST_CALL, + CAPABILITY_SHARED_MAP, + CAPABILITY_SHARED_SKETCH, + CAPABILITY_CHAT_BOT, + CAPABILITY_CHAT_BOT_ROLE, + CAPABILITY_PLUG_IN }) public @interface CapabilityFlag {} @@ -183,7 +205,7 @@ public final class RcsContactUceCapability implements Parcelable { } private final Uri mContactUri; - private int mCapabilities; + private long mCapabilities; private List<String> mExtensionTags = new ArrayList<>(); private Map<Integer, Uri> mServiceMap = new HashMap<>(); @@ -198,7 +220,7 @@ public final class RcsContactUceCapability implements Parcelable { private RcsContactUceCapability(Parcel in) { mContactUri = in.readParcelable(Uri.class.getClassLoader()); - mCapabilities = in.readInt(); + mCapabilities = in.readLong(); in.readStringList(mExtensionTags); // read mServiceMap as key,value pair int mapSize = in.readInt(); @@ -223,7 +245,7 @@ public final class RcsContactUceCapability implements Parcelable { @Override public void writeToParcel(@NonNull Parcel out, int flags) { out.writeParcelable(mContactUri, 0); - out.writeInt(mCapabilities); + out.writeLong(mCapabilities); out.writeStringList(mExtensionTags); // write mServiceMap as key,value pairs int mapSize = mServiceMap.keySet().size(); diff --git a/telephony/java/android/telephony/ims/RegistrationManager.java b/telephony/java/android/telephony/ims/RegistrationManager.java index 99bb259602e5..a1f6b78ba7c5 100644 --- a/telephony/java/android/telephony/ims/RegistrationManager.java +++ b/telephony/java/android/telephony/ims/RegistrationManager.java @@ -22,8 +22,6 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; -import android.annotation.SystemApi; -import android.annotation.TestApi; import android.net.Uri; import android.os.Binder; import android.telephony.AccessNetworkConstants; @@ -41,10 +39,7 @@ import java.util.function.Consumer; /** * Manages IMS Service registration state for associated {@link ImsFeature}s. - * @hide */ -@SystemApi -@TestApi public interface RegistrationManager { /** @@ -139,7 +134,6 @@ public interface RegistrationManager { getAccessType(imsRadioTech), info))); } - @Override public void onSubscriberAssociatedUriChanged(Uri[] uris) { if (mLocalCallback == null) return; @@ -225,7 +219,11 @@ public interface RegistrationManager { /** * Registers a {@link RegistrationCallback} with the system. Use - * {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed + * @param executor The {@link Executor} that will be used to call the IMS registration state + * callback. + * @param c A callback called on the supplied {@link Executor} that will contain the + * registration state of the IMS service, which will be one of the + * {@see SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed * events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up. * * When the callback is registered, it will initiate the callback c to be called with the @@ -275,10 +273,10 @@ public interface RegistrationManager { * Gets the Transport Type associated with the current IMS registration. * @param executor The {@link Executor} that will be used to call the transportTypeCallback. * @param transportTypeCallback The transport type associated with the current IMS registration, - * which will be one of following: - * {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN}, - * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, or - * {@link AccessNetworkConstants#TRANSPORT_TYPE_INVALID}. + * which will be one of following: + * {@see AccessNetworkConstants#TRANSPORT_TYPE_WWAN}, + * {@see AccessNetworkConstants#TRANSPORT_TYPE_WLAN}, or + * {@see AccessNetworkConstants#TRANSPORT_TYPE_INVALID}. */ @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) void getRegistrationTransportType( diff --git a/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl b/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl index 53e459697958..57206c9f059a 100644 --- a/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl +++ b/telephony/java/android/telephony/ims/aidl/IImsConfig.aidl @@ -40,4 +40,5 @@ interface IImsConfig { // Return result code defined in ImsConfig#OperationStatusConstants int setConfigString(int item, String value); void updateImsCarrierConfigs(in PersistableBundle bundle); + void notifyRcsAutoConfigurationReceived(in byte[] config, boolean isCompressed); } diff --git a/telephony/java/android/telephony/ims/aidl/IRcsFeatureListener.aidl b/telephony/java/android/telephony/ims/aidl/IRcsFeatureListener.aidl index 881b4776b25b..70cf651d3924 100644 --- a/telephony/java/android/telephony/ims/aidl/IRcsFeatureListener.aidl +++ b/telephony/java/android/telephony/ims/aidl/IRcsFeatureListener.aidl @@ -32,11 +32,11 @@ interface IRcsFeatureListener { oneway void onNetworkResponse(int code, in String reason, int operationToken); oneway void onCapabilityRequestResponsePresence(in List<RcsContactUceCapability> infos, int operationToken); - oneway void onNotifyUpdateCapabilities(); + oneway void onNotifyUpdateCapabilities(int publishTriggerType); oneway void onUnpublish(); // RcsSipOptionsImplBase specific oneway void onCapabilityRequestResponseOptions(int code, in String reason, in RcsContactUceCapability info, int operationToken); oneway void onRemoteCapabilityRequest(in Uri contactUri, in RcsContactUceCapability remoteInfo, int operationToken); -}
\ No newline at end of file +} diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java index 72390d070337..5d102cb4ac06 100644 --- a/telephony/java/android/telephony/ims/feature/ImsFeature.java +++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java @@ -60,15 +60,21 @@ public abstract class ImsFeature { * This feature supports emergency calling over MMTEL. If defined, the framework will try to * place an emergency call over IMS first. If it is not defined, the framework will only use * CSFB for emergency calling. + * @hide */ + @SystemApi @TestApi public static final int FEATURE_EMERGENCY_MMTEL = 0; /** * This feature supports the MMTEL feature. + * @hide */ + @SystemApi @TestApi public static final int FEATURE_MMTEL = 1; /** * This feature supports the RCS feature. + * @hide */ + @SystemApi @TestApi public static final int FEATURE_RCS = 2; /** * Total number of features defined @@ -116,18 +122,24 @@ public abstract class ImsFeature { * This {@link ImsFeature}'s state is unavailable and should not be communicated with. This will * remove all bindings back to the framework. Any attempt to communicate with the framework * during this time will result in an {@link IllegalStateException}. + * @hide */ + @SystemApi @TestApi public static final int STATE_UNAVAILABLE = 0; /** * This {@link ImsFeature} state is initializing and should not be communicated with. This will * remove all bindings back to the framework. Any attempt to communicate with the framework * during this time will result in an {@link IllegalStateException}. + * @hide */ + @SystemApi @TestApi public static final int STATE_INITIALIZING = 1; /** * This {@link ImsFeature} is ready for communication. Do not attempt to call framework methods - * until {@link #onFeatureReady()} is called. + * until {@see #onFeatureReady()} is called. + * @hide */ + @SystemApi @TestApi public static final int STATE_READY = 2; /** @@ -155,11 +167,15 @@ public abstract class ImsFeature { /** * The capability was unable to be changed. + * @hide */ + @SystemApi @TestApi public static final int CAPABILITY_ERROR_GENERIC = -1; /** * The capability was able to be changed. + * @hide */ + @SystemApi @TestApi public static final int CAPABILITY_SUCCESS = 0; /** @@ -331,17 +347,20 @@ public abstract class ImsFeature { * * @see SubscriptionManager#getSubscriptionIds(int) for more information on getting the * subscription IDs associated with this slot. + * @hide */ + @SystemApi @TestApi public final int getSlotIndex() { return mSlotId; } /** - * @return The current state of the feature, defined as {@link #STATE_UNAVAILABLE}, - * {@link #STATE_INITIALIZING}, or {@link #STATE_READY}. + * @return The current state of the ImsFeature, set previously by {@link #setFeatureState(int)} + * or {@link #STATE_UNAVAILABLE} if it has not been updated yet. * @hide */ - public int getFeatureState() { + @SystemApi @TestApi + public @ImsState int getFeatureState() { synchronized (mLock) { return mState; } @@ -352,7 +371,9 @@ public abstract class ImsFeature { * stop communication, depending on the state sent. * @param state The ImsFeature's state, defined as {@link #STATE_UNAVAILABLE}, * {@link #STATE_INITIALIZING}, or {@link #STATE_READY}. + * @hide */ + @SystemApi @TestApi public final void setFeatureState(@ImsState int state) { synchronized (mLock) { if (mState != state) { diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java index 56c87710244c..0d5a979e5894 100644 --- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java +++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java @@ -52,14 +52,18 @@ import java.lang.annotation.RetentionPolicy; * * Any class wishing to use MmTelFeature should extend this class and implement all methods that the * service supports. - * @hide */ -@SystemApi -@TestApi public class MmTelFeature extends ImsFeature { private static final String LOG_TAG = "MmTelFeature"; + /** + * @hide + */ + @SystemApi @TestApi + public MmTelFeature() { + } + private final IImsMmTelFeature mImsMMTelBinder = new IImsMmTelFeature.Stub() { @Override @@ -215,11 +219,11 @@ public class MmTelFeature extends ImsFeature { * {@link MmTelCapabilities#CAPABILITY_TYPE_SMS}. * * The capabilities of this MmTelFeature will be set by the framework and can be queried with - * {@link #queryCapabilityStatus()}. + * {@see #queryCapabilityStatus()}. * * This MmTelFeature can then return the status of each of these capabilities (enabled or not) - * by sending a {@link #notifyCapabilitiesStatusChanged} callback to the framework. The current - * status can also be queried using {@link #queryCapabilityStatus()}. + * by sending a {@see #notifyCapabilitiesStatusChanged} callback to the framework. The current + * status can also be queried using {@see #queryCapabilityStatus()}. * @see #isCapable(int) */ public static class MmTelCapabilities extends Capabilities { @@ -228,13 +232,18 @@ public class MmTelFeature extends ImsFeature { * Create a new empty {@link MmTelCapabilities} instance. * @see #addCapabilities(int) * @see #removeCapabilities(int) + * @hide */ + @SystemApi @TestApi public MmTelCapabilities() { super(); } - /**@deprecated Use {@link MmTelCapabilities} to construct a new instance instead.*/ + /**@deprecated Use {@link MmTelCapabilities} to construct a new instance instead. + * @hide + */ @Deprecated + @SystemApi @TestApi public MmTelCapabilities(Capabilities c) { mCapabilities = c.mCapabilities; } @@ -243,11 +252,17 @@ public class MmTelFeature extends ImsFeature { * Create a new {link @MmTelCapabilities} instance with the provided capabilities. * @param capabilities The capabilities that are supported for MmTel in the form of a * bitfield. + * @hide */ + @SystemApi @TestApi public MmTelCapabilities(@MmTelCapability int capabilities) { super(capabilities); } + /** + * @hide + */ + @SystemApi @TestApi @IntDef(flag = true, value = { CAPABILITY_TYPE_VOICE, @@ -278,23 +293,39 @@ public class MmTelFeature extends ImsFeature { */ public static final int CAPABILITY_TYPE_SMS = 1 << 3; + /** + * @hide + */ @Override + @SystemApi @TestApi public final void addCapabilities(@MmTelCapability int capabilities) { super.addCapabilities(capabilities); } + /** + * @hide + */ @Override + @SystemApi @TestApi public final void removeCapabilities(@MmTelCapability int capability) { super.removeCapabilities(capability); } + /** + * @hide + */ @Override + @SystemApi @TestApi public final boolean isCapable(@MmTelCapability int capabilities) { return super.isCapable(capabilities); } + /** + * @hide + */ @NonNull @Override + @SystemApi @TestApi public String toString() { StringBuilder builder = new StringBuilder("MmTel Capabilities - ["); builder.append("Voice: "); @@ -319,8 +350,10 @@ public class MmTelFeature extends ImsFeature { /** * Called when the IMS provider receives an incoming call. * @param c The {@link ImsCallSession} associated with the new call. + * @hide */ @Override + @SystemApi @TestApi public void onIncomingCall(IImsCallSession c, Bundle extras) { } @@ -329,8 +362,10 @@ public class MmTelFeature extends ImsFeature { * Called when the IMS provider implicitly rejects an incoming call during setup. * @param callProfile An {@link ImsCallProfile} with the call details. * @param reason The {@link ImsReasonInfo} reason for call rejection. + * @hide */ @Override + @SystemApi @TestApi public void onRejectedCall(ImsCallProfile callProfile, ImsReasonInfo reason) { } @@ -338,8 +373,10 @@ public class MmTelFeature extends ImsFeature { /** * Updates the Listener when the voice message count for IMS has changed. * @param count an integer representing the new message count. + * @hide */ @Override + @SystemApi @TestApi public void onVoiceMessageCountUpdate(int count) { } @@ -348,14 +385,22 @@ public class MmTelFeature extends ImsFeature { /** * To be returned by {@link #shouldProcessCall(String[])} when the ImsService should process the * outgoing call as IMS. + * @hide */ + @SystemApi @TestApi public static final int PROCESS_CALL_IMS = 0; /** * To be returned by {@link #shouldProcessCall(String[])} when the telephony framework should * not process the outgoing call as IMS and should instead use circuit switch. + * @hide */ + @SystemApi @TestApi public static final int PROCESS_CALL_CSFB = 1; + /** + * @hide + */ + @SystemApi @TestApi @IntDef(flag = true, value = { PROCESS_CALL_IMS, @@ -368,7 +413,9 @@ public class MmTelFeature extends ImsFeature { * If the flag is present and true, it indicates that the incoming call is for USSD. * <p> * This is an optional boolean flag. + * @hide */ + @SystemApi @TestApi public static final String EXTRA_IS_USSD = "android.telephony.ims.feature.extra.IS_USSD"; /** @@ -379,7 +426,9 @@ public class MmTelFeature extends ImsFeature { * certain situations. * <p> * This is an optional boolean flag. + * @hide */ + @SystemApi @TestApi public static final String EXTRA_IS_UNKNOWN_CALL = "android.telephony.ims.feature.extra.IS_UNKNOWN_CALL"; @@ -388,6 +437,7 @@ public class MmTelFeature extends ImsFeature { /** * @param listener A {@link Listener} used when the MmTelFeature receives an incoming call and * notifies the framework. + * @hide */ private void setListener(IImsMmTelListener listener) { synchronized (mLock) { @@ -406,9 +456,11 @@ public class MmTelFeature extends ImsFeature { * Should be a subset of the capabilities that are enabled by the framework in * {@link #changeEnabledCapabilities}. * @return A copy of the current MmTelFeature capability status. + * @hide */ @Override - public final MmTelCapabilities queryCapabilityStatus() { + @SystemApi @TestApi + public @NonNull final MmTelCapabilities queryCapabilityStatus() { return new MmTelCapabilities(super.queryCapabilityStatus()); } @@ -420,7 +472,9 @@ public class MmTelFeature extends ImsFeature { * the status of that capability is disabled. This can happen if the network does not currently * support the capability that is enabled. A capability that is disabled by the framework (via * {@link #changeEnabledCapabilities}) should also show the status as disabled. + * @hide */ + @SystemApi @TestApi public final void notifyCapabilitiesStatusChanged(@NonNull MmTelCapabilities c) { if (c == null) { throw new IllegalArgumentException("MmTelCapabilities must be non-null!"); @@ -433,7 +487,9 @@ public class MmTelFeature extends ImsFeature { * @param c The {@link ImsCallSessionImplBase} of the new incoming call. * @param extras A bundle containing extra parameters related to the call. See * {@link #EXTRA_IS_UNKNOWN_CALL} and {@link #EXTRA_IS_USSD} above. + * @hide */ + @SystemApi @TestApi public final void notifyIncomingCall(@NonNull ImsCallSessionImplBase c, @NonNull Bundle extras) { if (c == null || extras == null) { @@ -458,7 +514,9 @@ public class MmTelFeature extends ImsFeature { * @param callProfile The {@link ImsCallProfile} IMS call profile with details. * This can be null if no call information is available for the rejected call. * @param reason The {@link ImsReasonInfo} call rejection reason. + * * @hide */ + @SystemApi @TestApi public final void notifyRejectedCall(@NonNull ImsCallProfile callProfile, @NonNull ImsReasonInfo reason) { if (callProfile == null || reason == null) { @@ -497,7 +555,9 @@ public class MmTelFeature extends ImsFeature { /** * Notify the framework of a change in the Voice Message count. * @link count the new Voice Message count. + * @hide */ + @SystemApi @TestApi public final void notifyVoiceMessageCountUpdate(int count) { synchronized (mLock) { if (mListener == null) { @@ -518,8 +578,10 @@ public class MmTelFeature extends ImsFeature { * status for capability A. * @param capability The capability that we are querying the configuration for. * @return true if the capability is enabled, false otherwise. + * @hide */ @Override + @SystemApi @TestApi public boolean queryCapabilityConfiguration(@MmTelCapabilities.MmTelCapability int capability, @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) { // Base implementation - Override to provide functionality @@ -537,8 +599,10 @@ public class MmTelFeature extends ImsFeature { * Enabling/Disabling a capability here indicates that the capability should be registered or * deregistered (depending on the capability change) and become available or unavailable to * the framework. + * * @hide */ @Override + @SystemApi @TestApi public void changeEnabledCapabilities(@NonNull CapabilityChangeRequest request, @NonNull CapabilityCallbackProxy c) { // Base implementation, no-op @@ -561,7 +625,9 @@ public class MmTelFeature extends ImsFeature { * {@link ImsCallProfile#CALL_TYPE_VS_TX} * {@link ImsCallProfile#CALL_TYPE_VS_RX} * @return a {@link ImsCallProfile} object + * @hide */ + @SystemApi @TestApi public @Nullable ImsCallProfile createCallProfile(int callSessionType, int callType) { // Base Implementation - Should be overridden return null; @@ -582,7 +648,9 @@ public class MmTelFeature extends ImsFeature { * {@link ImsCallSession} directly. * * @param profile a call profile to make the call + * @hide */ + @SystemApi @TestApi public @Nullable ImsCallSessionImplBase createCallSession(@NonNull ImsCallProfile profile) { // Base Implementation - Should be overridden return null; @@ -599,7 +667,9 @@ public class MmTelFeature extends ImsFeature { * call as a conference. * @return a {@link ProcessCallResult} to the framework, which will be used to determine if the * call will be placed over IMS or via CSFB. + * @hide */ + @SystemApi @TestApi public @ProcessCallResult int shouldProcessCall(@NonNull String[] numbers) { return PROCESS_CALL_IMS; } @@ -632,7 +702,9 @@ public class MmTelFeature extends ImsFeature { /** * @return The {@link ImsUtImplBase} Ut interface implementation for the supplementary service * configuration. + * @hide */ + @SystemApi @TestApi public @NonNull ImsUtImplBase getUt() { // Base Implementation - Should be overridden return new ImsUtImplBase(); @@ -641,7 +713,9 @@ public class MmTelFeature extends ImsFeature { /** * @return The {@link ImsEcbmImplBase} Emergency call-back mode interface for emergency VoLTE * calls that support it. + * @hide */ + @SystemApi @TestApi public @NonNull ImsEcbmImplBase getEcbm() { // Base Implementation - Should be overridden return new ImsEcbmImplBase(); @@ -650,7 +724,9 @@ public class MmTelFeature extends ImsFeature { /** * @return The {@link ImsMultiEndpointImplBase} implementation for implementing Dialog event * package processing for multi-endpoint. + * @hide */ + @SystemApi @TestApi public @NonNull ImsMultiEndpointImplBase getMultiEndpoint() { // Base Implementation - Should be overridden return new ImsMultiEndpointImplBase(); @@ -676,7 +752,9 @@ public class MmTelFeature extends ImsFeature { * // Remote side is dead * } * } + * @hide */ + @SystemApi @TestApi public void setUiTtyMode(int mode, @Nullable Message onCompleteMessage) { // Base Implementation - Should be overridden } @@ -710,7 +788,9 @@ public class MmTelFeature extends ImsFeature { * * @return an instance of {@link ImsSmsImplBase} which should be implemented by the IMS * Provider. + * @hide */ + @SystemApi @TestApi public @NonNull ImsSmsImplBase getSmsImplementation() { return new ImsSmsImplBase(); } @@ -719,14 +799,22 @@ public class MmTelFeature extends ImsFeature { return getSmsImplementation().getSmsFormat(); } - /**{@inheritDoc}*/ + /** + * {@inheritDoc} + * @hide + */ @Override + @SystemApi @TestApi public void onFeatureRemoved() { // Base Implementation - Should be overridden } - /**{@inheritDoc}*/ + /** + * {@inheritDoc} + * @hide + */ @Override + @SystemApi @TestApi public void onFeatureReady() { // Base Implementation - Should be overridden } diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java index 1516c65e4b4d..e0d576db4f14 100644 --- a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java @@ -17,6 +17,7 @@ package android.telephony.ims.stub; import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.SystemApi; import android.annotation.TestApi; import android.content.Context; @@ -200,6 +201,12 @@ public class ImsConfigImplBase { } } + @Override + public void notifyRcsAutoConfigurationReceived(byte[] config, boolean isCompressed) + throws RemoteException { + getImsConfigImpl().notifyRcsAutoConfigurationReceived(config, isCompressed); + } + private void notifyImsConfigChanged(int item, int value) throws RemoteException { getImsConfigImpl().notifyConfigChanged(item, value); } @@ -357,9 +364,9 @@ public class ImsConfigImplBase { * @param config The XML file to be read, if not compressed, it should be in ASCII/UTF8 format. * @param isCompressed The XML file is compressed in gzip format and must be decompressed * before being read. - * @hide + * */ - public void notifyRcsAutoConfigurationReceived(byte[] config, boolean isCompressed) { + public void notifyRcsAutoConfigurationReceived(@NonNull byte[] config, boolean isCompressed) { } /** diff --git a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java index feac3c2ebfde..3ec4f3468497 100644 --- a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java +++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java @@ -16,6 +16,7 @@ package android.telephony.ims.stub; +import android.annotation.IntDef; import android.annotation.SystemApi; import android.annotation.TestApi; import android.os.Bundle; @@ -25,6 +26,9 @@ import android.telephony.ims.ImsUtListener; import com.android.ims.internal.IImsUt; import com.android.ims.internal.IImsUtListener; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Base implementation of IMS UT interface, which implements stubs. Override these methods to * implement functionality. @@ -36,6 +40,70 @@ import com.android.ims.internal.IImsUtListener; @SystemApi @TestApi public class ImsUtImplBase { + /** + * Bar all incoming calls. (See 3GPP TS 24.611) + */ + public static final int CALL_BARRING_ALL_INCOMING = 1; + + /** + * Bar all outgoing calls. (See 3GPP TS 24.611) + */ + public static final int CALL_BARRING_ALL_OUTGOING = 2; + + /** + * Bar all outgoing international calls. (See 3GPP TS 24.611) + */ + public static final int CALL_BARRING_OUTGOING_INTL = 3; + + /** + * Bar all outgoing international calls, excluding those to the home PLMN country + * (See 3GPP TS 24.611) + */ + public static final int CALL_BARRING_OUTGOING_INTL_EXCL_HOME = 4; + + /** + * Bar all incoming calls when roaming (See 3GPP TS 24.611) + */ + public static final int CALL_BLOCKING_INCOMING_WHEN_ROAMING = 5; + + /** + * Enable Anonymous Communication Rejection (See 3GPP TS 24.611) + */ + public static final int CALL_BARRING_ANONYMOUS_INCOMING = 6; + + /** + * Bar all incoming and outgoing calls. (See 3GPP TS 24.611) + */ + public static final int CALL_BARRING_ALL = 7; + + /** + * Bar all outgoing service requests, including calls. (See 3GPP TS 24.611) + */ + public static final int CALL_BARRING_OUTGOING_ALL_SERVICES = 8; + + /** + * Bar all incoming service requests, including calls. (See 3GPP TS 24.611) + */ + public static final int CALL_BARRING_INCOMING_ALL_SERVICES = 9; + + /** + * Bar specific incoming calls. (See 3GPP TS 24.611) + */ + public static final int CALL_BARRING_SPECIFIC_INCOMING_CALLS = 10; + + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "CALL_BARRING_", value = {CALL_BARRING_ALL_INCOMING, CALL_BARRING_ALL_OUTGOING, + CALL_BARRING_OUTGOING_INTL, CALL_BARRING_OUTGOING_INTL_EXCL_HOME, + CALL_BLOCKING_INCOMING_WHEN_ROAMING, CALL_BARRING_ANONYMOUS_INCOMING, + CALL_BARRING_ALL, CALL_BARRING_OUTGOING_ALL_SERVICES, + CALL_BARRING_INCOMING_ALL_SERVICES, CALL_BARRING_SPECIFIC_INCOMING_CALLS}) + public @interface CallBarringMode {} + + /** + * Constant used to denote an invalid return value. + */ + public static final int INVALID_RESULT = -1; private IImsUt.Stub mServiceImpl = new IImsUt.Stub() { @Override @@ -247,15 +315,15 @@ public class ImsUtImplBase { /** * Updates the configuration of the call barring. */ - public int updateCallBarring(int cbType, int action, String[] barrList) { + public int updateCallBarring(@CallBarringMode int cbType, int action, String[] barrList) { return -1; } /** * Updates the configuration of the call barring for specified service class. */ - public int updateCallBarringForServiceClass(int cbType, int action, String[] barrList, - int serviceClass) { + public int updateCallBarringForServiceClass(@CallBarringMode int cbType, int action, + String[] barrList, int serviceClass) { return -1; } diff --git a/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java index 055fca57a628..bb034489a296 100644 --- a/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java +++ b/telephony/java/android/telephony/ims/stub/RcsPresenceExchangeImplBase.java @@ -113,6 +113,51 @@ public class RcsPresenceExchangeImplBase extends RcsCapabilityExchange { }) public @interface PresenceResponseCode {} + + /** A capability update has been requested due to the Entity Tag (ETag) expiring. */ + public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 0; + /** A capability update has been requested due to moving to LTE with VoPS disabled. */ + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED = 1; + /** A capability update has been requested due to moving to LTE with VoPS enabled. */ + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED = 2; + /** A capability update has been requested due to moving to eHRPD. */ + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD = 3; + /** A capability update has been requested due to moving to HSPA+. */ + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS = 4; + /** A capability update has been requested due to moving to 3G. */ + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 5; + /** A capability update has been requested due to moving to 2G. */ + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 6; + /** A capability update has been requested due to moving to WLAN */ + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN = 7; + /** A capability update has been requested due to moving to IWLAN */ + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN = 8; + /** A capability update has been requested but the reason is unknown. */ + public static final int CAPABILITY_UPDATE_TRIGGER_UNKNOWN = 9; + /** A capability update has been requested due to moving to 5G NR with VoPS disabled. */ + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED = 10; + /** A capability update has been requested due to moving to 5G NR with VoPS enabled. */ + public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED = 11; + + /** @hide*/ + @IntDef(value = { + CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED, + CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_DISABLED, + CAPABILITY_UPDATE_TRIGGER_MOVE_TO_LTE_VOPS_ENABLED, + CAPABILITY_UPDATE_TRIGGER_MOVE_TO_EHRPD, + CAPABILITY_UPDATE_TRIGGER_MOVE_TO_HSPAPLUS, + CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G, + CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G, + CAPABILITY_UPDATE_TRIGGER_MOVE_TO_WLAN, + CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN, + CAPABILITY_UPDATE_TRIGGER_UNKNOWN, + CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_DISABLED, + CAPABILITY_UPDATE_TRIGGER_MOVE_TO_NR5G_VOPS_ENABLED + }, prefix = "CAPABILITY_UPDATE_TRIGGER_") + @Retention(RetentionPolicy.SOURCE) + public @interface StackPublishTriggerType { + } + /** * Provide the framework with a subsequent network response update to * {@link #updateCapabilities(RcsContactUceCapability, int)} and @@ -164,15 +209,18 @@ public class RcsPresenceExchangeImplBase extends RcsCapabilityExchange { * This is typically used when trying to generate an initial PUBLISH for a new subscription to * the network. The device will cache all presence publications after boot until this method is * called once. + * @param publishTriggerType {@link StackPublishTriggerType} The reason for the capability + * update request. * @throws ImsException If this {@link RcsPresenceExchangeImplBase} instance is not currently * connected to the framework. This can happen if the {@link RcsFeature} is not * {@link ImsFeature#STATE_READY} and the {@link RcsFeature} has not received the * {@link ImsFeature#onFeatureReady()} callback. This may also happen in rare cases when the * Telephony stack has crashed. */ - public final void onNotifyUpdateCapabilites() throws ImsException { + public final void onNotifyUpdateCapabilites(@StackPublishTriggerType int publishTriggerType) + throws ImsException { try { - getListener().onNotifyUpdateCapabilities(); + getListener().onNotifyUpdateCapabilities(publishTriggerType); } catch (RemoteException e) { throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); } diff --git a/telephony/java/com/android/ims/ImsUtInterface.java b/telephony/java/com/android/ims/ImsUtInterface.java index 50b63bd25435..15f837189843 100644 --- a/telephony/java/com/android/ims/ImsUtInterface.java +++ b/telephony/java/com/android/ims/ImsUtInterface.java @@ -21,6 +21,7 @@ import android.os.Handler; import android.os.Message; import android.telephony.ims.ImsCallForwardInfo; import android.telephony.ims.ImsSsInfo; +import android.telephony.ims.stub.ImsUtImplBase; /** * Provides APIs for the supplementary service settings using IMS (Ut interface). @@ -58,47 +59,48 @@ public interface ImsUtInterface { * CDIV (Communication Diversion, 3GPP TS 24.604) * actions: target, no reply timer */ - public static final int CDIV_CF_UNCONDITIONAL = 0; - public static final int CDIV_CF_BUSY = 1; - public static final int CDIV_CF_NO_REPLY = 2; - public static final int CDIV_CF_NOT_REACHABLE = 3; + public static final int CDIV_CF_UNCONDITIONAL = ImsCallForwardInfo.CDIV_CF_REASON_UNCONDITIONAL; + public static final int CDIV_CF_BUSY = ImsCallForwardInfo.CDIV_CF_REASON_BUSY; + public static final int CDIV_CF_NO_REPLY = ImsCallForwardInfo.CDIV_CF_REASON_NO_REPLY; + public static final int CDIV_CF_NOT_REACHABLE = ImsCallForwardInfo.CDIV_CF_REASON_NOT_REACHABLE; // For CS service code: 002 - public static final int CDIV_CF_ALL = 4; + public static final int CDIV_CF_ALL = ImsCallForwardInfo.CDIV_CF_REASON_ALL; // For CS service code: 004 - public static final int CDIV_CF_ALL_CONDITIONAL = 5; + public static final int CDIV_CF_ALL_CONDITIONAL = + ImsCallForwardInfo.CDIV_CF_REASON_ALL_CONDITIONAL; // It's only supported in the IMS service (CS does not define it). // IR.92 recommends that an UE activates both the CFNRc and the CFNL // (CDIV using condition not-registered) to the same target. - public static final int CDIV_CF_NOT_LOGGED_IN = 6; + public static final int CDIV_CF_NOT_LOGGED_IN = ImsCallForwardInfo.CDIV_CF_REASON_NOT_LOGGED_IN; /** * CB (Communication Barring, 3GPP TS 24.611) */ // Barring of All Incoming Calls - public static final int CB_BAIC = 1; + public static final int CB_BAIC = ImsUtImplBase.CALL_BARRING_ALL_INCOMING; // Barring of All Outgoing Calls - public static final int CB_BAOC = 2; + public static final int CB_BAOC = ImsUtImplBase.CALL_BARRING_ALL_OUTGOING; // Barring of Outgoing International Calls - public static final int CB_BOIC = 3; + public static final int CB_BOIC = ImsUtImplBase.CALL_BARRING_OUTGOING_INTL; // Barring of Outgoing International Calls - excluding Home Country - public static final int CB_BOIC_EXHC = 4; + public static final int CB_BOIC_EXHC = ImsUtImplBase.CALL_BARRING_OUTGOING_INTL_EXCL_HOME; // Barring of Incoming Calls - when roaming - public static final int CB_BIC_WR = 5; + public static final int CB_BIC_WR = ImsUtImplBase.CALL_BLOCKING_INCOMING_WHEN_ROAMING; // Barring of Anonymous Communication Rejection (ACR) - a particular case of ICB service - public static final int CB_BIC_ACR = 6; + public static final int CB_BIC_ACR = ImsUtImplBase.CALL_BARRING_ANONYMOUS_INCOMING; // Barring of All Calls - public static final int CB_BA_ALL = 7; + public static final int CB_BA_ALL = ImsUtImplBase.CALL_BARRING_ALL; // Barring of Outgoing Services (Service Code 333 - 3GPP TS 22.030 Table B-1) - public static final int CB_BA_MO = 8; + public static final int CB_BA_MO = ImsUtImplBase.CALL_BARRING_OUTGOING_ALL_SERVICES; // Barring of Incoming Services (Service Code 353 - 3GPP TS 22.030 Table B-1) - public static final int CB_BA_MT = 9; + public static final int CB_BA_MT = ImsUtImplBase.CALL_BARRING_INCOMING_ALL_SERVICES; // Barring of Specific Incoming calls - public static final int CB_BS_MT = 10; + public static final int CB_BS_MT = ImsUtImplBase.CALL_BARRING_SPECIFIC_INCOMING_CALLS; /** * Invalid result value. */ - public static final int INVALID = (-1); + public static final int INVALID = ImsUtImplBase.INVALID_RESULT; diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index a85c85c0d5e4..1f84451a35e4 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -2132,4 +2132,9 @@ interface ITelephony { * Command line command to enable or disable handling of CEP data for test purposes. */ oneway void setCepEnabled(boolean isCepEnabled); + + /** + * Notify Rcs auto config received. + */ + void notifyRcsAutoConfigurationReceived(int subId, in byte[] config, boolean isCompressed); } diff --git a/tests/libs-permissions/Android.bp b/tests/libs-permissions/Android.bp index 330bfc9022df..66a1f83dc308 100644 --- a/tests/libs-permissions/Android.bp +++ b/tests/libs-permissions/Android.bp @@ -2,6 +2,7 @@ java_library { name: "com.android.test.libs.product", installable: true, product_specific: true, + sdk_version: "current", srcs: ["product/java/**/*.java"], required: ["com.android.test.libs.product.xml"], } diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java index 18474a83b368..0bf64b929ec7 100644 --- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java +++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java @@ -222,7 +222,7 @@ public class NetworkAgentWrapper implements TestableNetworkCallback.HasNetwork { @Override public Network getNetwork() { - return new Network(mNetworkAgent.netId); + return mNetworkAgent.network; } public void expectPreventReconnectReceived(long timeoutMs) { diff --git a/tests/net/java/android/net/TelephonyNetworkSpecifierTest.java b/tests/net/java/android/net/TelephonyNetworkSpecifierTest.java new file mode 100644 index 000000000000..47afed441ace --- /dev/null +++ b/tests/net/java/android/net/TelephonyNetworkSpecifierTest.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import static com.android.testutils.ParcelUtilsKt.assertParcelSane; + +import static org.junit.Assert.assertEquals; + +import android.telephony.SubscriptionManager; + +import androidx.test.filters.SmallTest; + +import org.junit.Test; + +/** + * Unit test for {@link android.net.TelephonyNetworkSpecifier}. + */ +@SmallTest +public class TelephonyNetworkSpecifierTest { + private static final int TEST_SUBID = 5; + + /** + * Validate that IllegalArgumentException will be thrown if build TelephonyNetworkSpecifier + * without calling {@link TelephonyNetworkSpecifier.Builder#setSubscriptionId(int)}. + */ + @Test + public void testBuilderBuildWithDefault() { + try { + new TelephonyNetworkSpecifier.Builder().build(); + } catch (IllegalArgumentException iae) { + // expected, test pass + } + } + + /** + * Validate that no exception will be thrown even if pass invalid subscription id to + * {@link TelephonyNetworkSpecifier.Builder#setSubscriptionId(int)}. + */ + @Test + public void testBuilderBuildWithInvalidSubId() { + TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier.Builder() + .setSubscriptionId(SubscriptionManager.INVALID_SUBSCRIPTION_ID) + .build(); + assertEquals(specifier.getSubscriptionId(), SubscriptionManager.INVALID_SUBSCRIPTION_ID); + } + + /** + * Validate the correctness of TelephonyNetworkSpecifier when provide valid subId. + */ + @Test + public void testBuilderBuildWithValidSubId() { + final TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier.Builder() + .setSubscriptionId(TEST_SUBID) + .build(); + assertEquals(TEST_SUBID, specifier.getSubscriptionId()); + } + + /** + * Validate that parcel marshalling/unmarshalling works. + */ + @Test + public void testParcel() { + TelephonyNetworkSpecifier specifier = new TelephonyNetworkSpecifier.Builder() + .setSubscriptionId(TEST_SUBID) + .build(); + assertParcelSane(specifier, 1 /* fieldCount */); + } +} diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index b2d363e27839..1901a1db633b 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -575,7 +575,7 @@ public class ConnectivityServiceTest { } }; - assertEquals(na.netId, nmNetworkCaptor.getValue().netId); + assertEquals(na.network.netId, nmNetworkCaptor.getValue().netId); mNmCallbacks = nmCbCaptor.getValue(); mNmCallbacks.onNetworkMonitorCreated(mNetworkMonitor); diff --git a/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java b/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java index b783467cfaf2..de1028cd2303 100644 --- a/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java +++ b/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java @@ -51,6 +51,7 @@ import android.net.NetworkPolicy; import android.net.NetworkPolicyManager; import android.net.NetworkTemplate; import android.net.StringNetworkSpecifier; +import android.net.TelephonyNetworkSpecifier; import android.os.Handler; import android.provider.Settings; import android.telephony.TelephonyManager; @@ -229,7 +230,7 @@ public class MultipathPolicyTrackerTest { verify(mCM).registerNetworkCallback(any(), networkCallback.capture(), any()); // Simulate callback after capability changes - final NetworkCapabilities capabilities = new NetworkCapabilities() + NetworkCapabilities capabilities = new NetworkCapabilities() .addCapability(NET_CAPABILITY_INTERNET) .addTransportType(TRANSPORT_CELLULAR) .setNetworkSpecifier(new StringNetworkSpecifier("234")); @@ -239,6 +240,19 @@ public class MultipathPolicyTrackerTest { networkCallback.getValue().onCapabilitiesChanged( TEST_NETWORK, capabilities); + + // make sure it also works with the new introduced TelephonyNetworkSpecifier + capabilities = new NetworkCapabilities() + .addCapability(NET_CAPABILITY_INTERNET) + .addTransportType(TRANSPORT_CELLULAR) + .setNetworkSpecifier(new TelephonyNetworkSpecifier.Builder() + .setSubscriptionId(234).build()); + if (!roaming) { + capabilities.addCapability(NET_CAPABILITY_NOT_ROAMING); + } + networkCallback.getValue().onCapabilitiesChanged( + TEST_NETWORK, + capabilities); } @Test diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp index 45cea8190844..40eae545c06b 100644 --- a/tools/aapt2/ResourceParser.cpp +++ b/tools/aapt2/ResourceParser.cpp @@ -1643,8 +1643,14 @@ bool ResourceParser::ParseDeclareStyleable(xml::XmlPullParser* parser, ParsedResource* out_resource) { out_resource->name.type = ResourceType::kStyleable; - // Declare-styleable is kPrivate by default, because it technically only exists in R.java. - out_resource->visibility_level = Visibility::Level::kPublic; + if (!options_.preserve_visibility_of_styleables) { + // This was added in change Idd21b5de4d20be06c6f8c8eb5a22ccd68afc4927 to mimic aapt1, but no one + // knows exactly what for. + // + // FWIW, styleables only appear in generated R classes. For custom views these should always be + // package-private (to be used only by the view class); themes are a different story. + out_resource->visibility_level = Visibility::Level::kPublic; + } // Declare-styleable only ends up in default config; if (out_resource->config != ConfigDescription::DefaultConfig()) { diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h index 06bb0c9cf264..9d3ecc866c5d 100644 --- a/tools/aapt2/ResourceParser.h +++ b/tools/aapt2/ResourceParser.h @@ -46,6 +46,12 @@ struct ResourceParserOptions { */ bool error_on_positional_arguments = true; + /** + * If true, apply the same visibility rules for styleables as are used for + * all other resources. Otherwise, all styleables will be made public. + */ + bool preserve_visibility_of_styleables = false; + // If visibility was forced, we need to use it when creating a new resource and also error if we // try to parse the <public>, <public-group>, <java-symbol> or <symbol> tags. Maybe<Visibility::Level> visibility; diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp index 464225fefb85..46ad7cbe49e9 100644 --- a/tools/aapt2/ResourceParser_test.cpp +++ b/tools/aapt2/ResourceParser_test.cpp @@ -611,6 +611,32 @@ TEST_F(ResourceParserTest, ParseAttributesDeclareStyleable) { EXPECT_THAT(styleable->entries[2].name, Eq(make_value(test::ParseNameOrDie("attr/baz")))); } +TEST_F(ResourceParserTest, ParseDeclareStyleablePreservingVisibility) { + StringInputStream input(R"( + <resources> + <declare-styleable name="foo"> + <attr name="myattr" /> + </declare-styleable> + <declare-styleable name="bar"> + <attr name="myattr" /> + </declare-styleable> + <public type="styleable" name="bar" /> + </resources>)"); + ResourceParser parser(context_->GetDiagnostics(), &table_, Source{"test"}, + ConfigDescription::DefaultConfig(), + ResourceParserOptions{.preserve_visibility_of_styleables = true}); + + xml::XmlPullParser xml_parser(&input); + ASSERT_TRUE(parser.Parse(&xml_parser)); + + EXPECT_EQ( + table_.FindResource(test::ParseNameOrDie("styleable/foo")).value().entry->visibility.level, + Visibility::Level::kUndefined); + EXPECT_EQ( + table_.FindResource(test::ParseNameOrDie("styleable/bar")).value().entry->visibility.level, + Visibility::Level::kPublic); +} + TEST_F(ResourceParserTest, ParsePrivateAttributesDeclareStyleable) { std::string input = R"( <declare-styleable xmlns:privAndroid="http://schemas.android.com/apk/prv/res/android" diff --git a/tools/aapt2/cmd/Compile.cpp b/tools/aapt2/cmd/Compile.cpp index 9b81369fa9f0..21719705838d 100644 --- a/tools/aapt2/cmd/Compile.cpp +++ b/tools/aapt2/cmd/Compile.cpp @@ -159,6 +159,7 @@ static bool CompileTable(IAaptContext* context, const CompileOptions& options, ResourceParserOptions parser_options; parser_options.error_on_positional_arguments = !options.legacy_mode; + parser_options.preserve_visibility_of_styleables = options.preserve_visibility_of_styleables; parser_options.translatable = translatable_file; // If visibility was forced, we need to use it when creating a new resource and also error if diff --git a/tools/aapt2/cmd/Compile.h b/tools/aapt2/cmd/Compile.h index d3456b25da9a..1752a1adac24 100644 --- a/tools/aapt2/cmd/Compile.h +++ b/tools/aapt2/cmd/Compile.h @@ -35,6 +35,8 @@ struct CompileOptions { bool pseudolocalize = false; bool no_png_crunch = false; bool legacy_mode = false; + // See comments on aapt::ResourceParserOptions. + bool preserve_visibility_of_styleables = false; bool verbose = false; }; @@ -56,6 +58,11 @@ class CompileCommand : public Command { AddOptionalSwitch("--no-crunch", "Disables PNG processing", &options_.no_png_crunch); AddOptionalSwitch("--legacy", "Treat errors that used to be valid in AAPT as warnings", &options_.legacy_mode); + AddOptionalSwitch("--preserve-visibility-of-styleables", + "If specified, apply the same visibility rules for\n" + "styleables as are used for all other resources.\n" + "Otherwise, all stylesables will be made public.", + &options_.preserve_visibility_of_styleables); AddOptionalFlag("--visibility", "Sets the visibility of the compiled resources to the specified\n" "level. Accepted levels: public, private, default", &visibility_); |