diff options
28 files changed, 812 insertions, 141 deletions
diff --git a/api/current.txt b/api/current.txt index 4baa8c3f78a3..bcd8ebb05141 100755 --- a/api/current.txt +++ b/api/current.txt @@ -35081,6 +35081,15 @@ package android.provider { method public static java.lang.String getLastOutgoingCall(android.content.Context); field public static final int ANSWERED_EXTERNALLY_TYPE = 7; // 0x7 field public static final int BLOCKED_TYPE = 6; // 0x6 + field public static final java.lang.String BLOCK_REASON = "block_reason"; + field public static final int BLOCK_REASON_BLOCKED_NUMBER = 3; // 0x3 + field public static final int BLOCK_REASON_CALL_SCREENING_SERVICE = 1; // 0x1 + field public static final int BLOCK_REASON_DIRECT_TO_VOICEMAIL = 2; // 0x2 + field public static final int BLOCK_REASON_NOT_BLOCKED = 0; // 0x0 + field public static final int BLOCK_REASON_NOT_IN_CONTACTS = 7; // 0x7 + field public static final int BLOCK_REASON_PAY_PHONE = 6; // 0x6 + field public static final int BLOCK_REASON_RESTRICTED_NUMBER = 5; // 0x5 + field public static final int BLOCK_REASON_UNKNOWN_NUMBER = 4; // 0x4 field public static final java.lang.String CACHED_FORMATTED_NUMBER = "formatted_number"; field public static final java.lang.String CACHED_LOOKUP_URI = "lookup_uri"; field public static final java.lang.String CACHED_MATCHED_NUMBER = "matched_number"; @@ -35090,6 +35099,8 @@ package android.provider { field public static final java.lang.String CACHED_NUMBER_TYPE = "numbertype"; field public static final java.lang.String CACHED_PHOTO_ID = "photo_id"; field public static final java.lang.String CACHED_PHOTO_URI = "photo_uri"; + field public static final java.lang.String CALL_SCREENING_APP_NAME = "call_screening_app_name"; + field public static final java.lang.String CALL_SCREENING_COMPONENT_NAME = "call_screening_component_name"; field public static final android.net.Uri CONTENT_FILTER_URI; field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/calls"; field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/calls"; diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt index 9857cd072068..dacbd674837b 100644 --- a/config/boot-image-profile.txt +++ b/config/boot-image-profile.txt @@ -24141,7 +24141,90 @@ HSPLandroid/icu/util/CharsTrie;->jumpByDelta(Ljava/lang/CharSequence;I)I HSPLandroid/icu/util/CharsTrie;->next(I)Landroid/icu/util/BytesTrie$Result; HSPLandroid/icu/util/CharsTrie;->nextImpl(II)Landroid/icu/util/BytesTrie$Result; HSPLandroid/icu/util/CharsTrie;->readValue(Ljava/lang/CharSequence;II)I -HSPLandroid/icu/util/Currency$1;-><init>()V +HSPLandroid/icu/util/CodePointTrie$Small8;->fromBinary(Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Small8; +HSPLandroid/icu/util/CodePointTrie$Small32;->fromBinary(Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Small32; +HSPLandroid/icu/util/CodePointTrie$Small16;->fromBinary(Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Small16; +HSPLandroid/icu/util/CodePointTrie$Fast8;->fromBinary(Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Fast8; +HSPLandroid/icu/util/CodePointTrie$Fast8;->bmpGet(I)I +HSPLandroid/icu/util/CodePointTrie$Fast8;->get(I)I +HSPLandroid/icu/util/CodePointTrie$Fast8;->suppGet(I)I +HSPLandroid/icu/util/CodePointTrie$Fast32;->fromBinary(Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Fast32; +HSPLandroid/icu/util/CodePointTrie$Fast32;->bmpGet(I)I +HSPLandroid/icu/util/CodePointTrie$Fast32;->get(I)I +HSPLandroid/icu/util/CodePointTrie$Fast32;->suppGet(I)I +HSPLandroid/icu/util/CodePointTrie$Fast16;->fromBinary(Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Fast16; +HSPLandroid/icu/util/CodePointTrie$Fast16;->bmpGet(I)I +HSPLandroid/icu/util/CodePointTrie$Fast16;->get(I)I +HSPLandroid/icu/util/CodePointTrie$Fast16;->suppGet(I)I +HSPLandroid/icu/util/CodePointTrie$Small;->fromBinary(Landroid/icu/util/CodePointTrie$ValueWidth;Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Small; +HSPLandroid/icu/util/CodePointTrie$Small;->cpIndex(I)I +HSPLandroid/icu/util/CodePointTrie$Small;->getType()Landroid/icu/util/CodePointTrie$Type; +HSPLandroid/icu/util/CodePointTrie$Small;->stringIterator(Ljava/lang/CharSequence;I)Landroid/icu/util/CodePointMap$StringIterator; +HSPLandroid/icu/util/CodePointTrie$Fast;->fromBinary(Landroid/icu/util/CodePointTrie$ValueWidth;Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie$Fast; +HSPLandroid/icu/util/CodePointTrie$Fast;->bmpGet(I)I +HSPLandroid/icu/util/CodePointTrie$Fast;->cpIndex(I)I +HSPLandroid/icu/util/CodePointTrie$Fast;->getType()Landroid/icu/util/CodePointTrie$Type; +HSPLandroid/icu/util/CodePointTrie$Fast;->stringIterator(Ljava/lang/CharSequence;I)Landroid/icu/util/CodePointMap$StringIterator; +HSPLandroid/icu/util/CodePointTrie$Fast;->suppGet(I)I +HSPLandroid/icu/util/CodePointTrie$Data8;->getDataLength()I +HSPLandroid/icu/util/CodePointTrie$Data8;->getFromIndex(I)I +HSPLandroid/icu/util/CodePointTrie$Data8;->getValueWidth()Landroid/icu/util/CodePointTrie$ValueWidth; +HSPLandroid/icu/util/CodePointTrie$Data8;->write(Ljava/io/DataOutputStream;)I +HSPLandroid/icu/util/CodePointTrie$Data32;->getDataLength()I +HSPLandroid/icu/util/CodePointTrie$Data32;->getFromIndex(I)I +HSPLandroid/icu/util/CodePointTrie$Data32;->getValueWidth()Landroid/icu/util/CodePointTrie$ValueWidth; +HSPLandroid/icu/util/CodePointTrie$Data32;->write(Ljava/io/DataOutputStream;)I +HSPLandroid/icu/util/CodePointTrie$Data16;->getDataLength()I +HSPLandroid/icu/util/CodePointTrie$Data16;->getFromIndex(I)I +HSPLandroid/icu/util/CodePointTrie$Data16;->getValueWidth()Landroid/icu/util/CodePointTrie$ValueWidth; +HSPLandroid/icu/util/CodePointTrie$Data16;->write(Ljava/io/DataOutputStream;)I +HSPLandroid/icu/util/CodePointTrie$Data;->getDataLength()I +HSPLandroid/icu/util/CodePointTrie$Data;->getFromIndex(I)I +HSPLandroid/icu/util/CodePointTrie$Data;->getValueWidth()Landroid/icu/util/CodePointTrie$ValueWidth; +HSPLandroid/icu/util/CodePointTrie$Data;->write(Ljava/io/DataOutputStream;)I +HSPLandroid/icu/util/CodePointTrie$ValueWidth;->valueOf(Ljava/lang/String;)Landroid/icu/util/CodePointTrie$ValueWidth; +HSPLandroid/icu/util/CodePointTrie$ValueWidth;->values()[Landroid/icu/util/CodePointTrie$ValueWidth; +HSPLandroid/icu/util/CodePointTrie$Type;->valueOf(Ljava/lang/String;)Landroid/icu/util/CodePointTrie$Type; +HSPLandroid/icu/util/CodePointTrie$Type;->values()[Landroid/icu/util/CodePointTrie$Type; +HSPLandroid/icu/util/CodePointTrie;->fromBinary(Landroid/icu/util/CodePointTrie$Type;Landroid/icu/util/CodePointTrie$ValueWidth;Ljava/nio/ByteBuffer;)Landroid/icu/util/CodePointTrie; +HSPLandroid/icu/util/CodePointTrie;->internalSmallIndex(Landroid/icu/util/CodePointTrie$Type;I)I +HSPLandroid/icu/util/CodePointTrie;->maybeFilterValue(IIILandroid/icu/util/CodePointMap$ValueFilter;)I +HSPLandroid/icu/util/CodePointTrie;->asciiGet(I)I +HSPLandroid/icu/util/CodePointTrie;->cpIndex(I)I +HSPLandroid/icu/util/CodePointTrie;->fastIndex(I)I +HSPLandroid/icu/util/CodePointTrie;->get(I)I +HSPLandroid/icu/util/CodePointTrie;->getRange(ILandroid/icu/util/CodePointMap$ValueFilter;Landroid/icu/util/CodePointMap$Range;)Z +HSPLandroid/icu/util/CodePointTrie;->getType()Landroid/icu/util/CodePointTrie$Type; +HSPLandroid/icu/util/CodePointTrie;->getValueWidth()Landroid/icu/util/CodePointTrie$ValueWidth; +HSPLandroid/icu/util/CodePointTrie;->smallIndex(Landroid/icu/util/CodePointTrie$Type;I)I +HSPLandroid/icu/util/CodePointTrie;->toBinary(Ljava/io/OutputStream;)I +HSPLandroid/icu/util/CodePointMap$StringIterator;->getCodePoint()I +HSPLandroid/icu/util/CodePointMap$StringIterator;->getIndex()I +HSPLandroid/icu/util/CodePointMap$StringIterator;->getValue()I +HSPLandroid/icu/util/CodePointMap$StringIterator;->next()Z +HSPLandroid/icu/util/CodePointMap$StringIterator;->previous()Z +HSPLandroid/icu/util/CodePointMap$StringIterator;->reset(Ljava/lang/CharSequence;I)V +HSPLandroid/icu/util/CodePointMap$RangeIterator;->hasNext()Z +HSPLandroid/icu/util/CodePointMap$RangeIterator;->next()Landroid/icu/util/CodePointMap$Range; +HSPLandroid/icu/util/CodePointMap$RangeIterator;->next()Ljava/lang/Object; +HSPLandroid/icu/util/CodePointMap$RangeIterator;->remove()V +HSPLandroid/icu/util/CodePointMap$Range;->access$000(Landroid/icu/util/CodePointMap$Range;)I +HSPLandroid/icu/util/CodePointMap$Range;->access$002(Landroid/icu/util/CodePointMap$Range;I)I +HSPLandroid/icu/util/CodePointMap$Range;->access$100(Landroid/icu/util/CodePointMap$Range;)I +HSPLandroid/icu/util/CodePointMap$Range;->access$102(Landroid/icu/util/CodePointMap$Range;I)I +HSPLandroid/icu/util/CodePointMap$Range;->access$202(Landroid/icu/util/CodePointMap$Range;I)I +HSPLandroid/icu/util/CodePointMap$Range;->getEnd()I +HSPLandroid/icu/util/CodePointMap$Range;->getStart()I +HSPLandroid/icu/util/CodePointMap$Range;->getValue()I +HSPLandroid/icu/util/CodePointMap$Range;->set(III)V +HSPLandroid/icu/util/CodePointMap$ValueFilter;->apply(I)I +HSPLandroid/icu/util/CodePointMap$RangeOption;->valueOf(Ljava/lang/String;)Landroid/icu/util/CodePointMap$RangeOption; +HSPLandroid/icu/util/CodePointMap$RangeOption;->values()[Landroid/icu/util/CodePointMap$RangeOption; +HSPLandroid/icu/util/CodePointMap;->get(I)I +HSPLandroid/icu/util/CodePointMap;->getRange(ILandroid/icu/util/CodePointMap$RangeOption;ILandroid/icu/util/CodePointMap$ValueFilter;Landroid/icu/util/CodePointMap$Range;)Z +HSPLandroid/icu/util/CodePointMap;->getRange(ILandroid/icu/util/CodePointMap$ValueFilter;Landroid/icu/util/CodePointMap$Range;)Z +HSPLandroid/icu/util/CodePointMap;->iterator()Ljava/util/Iterator; +HSPLandroid/icu/util/CodePointMap;->stringIterator(Ljava/lang/CharSequence;I)Landroid/icu/util/CodePointMap$StringIterator;HSPLandroid/icu/util/Currency$1;-><init>()V HSPLandroid/icu/util/Currency$1;->createInstance(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; HSPLandroid/icu/util/Currency$1;->createInstance(Ljava/lang/String;Ljava/lang/Void;)Landroid/icu/util/Currency; HSPLandroid/icu/util/Currency$CurrencyUsage;-><init>(Ljava/lang/String;I)V @@ -24187,6 +24270,61 @@ HSPLandroid/icu/util/MeasureUnit;->addUnit(Ljava/lang/String;Ljava/lang/String;L HSPLandroid/icu/util/MeasureUnit;->equals(Ljava/lang/Object;)Z HSPLandroid/icu/util/MeasureUnit;->hashCode()I HSPLandroid/icu/util/MeasureUnit;->internalGetInstance(Ljava/lang/String;Ljava/lang/String;)Landroid/icu/util/MeasureUnit; +HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->addEntry([I[CIII)V +HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->findEntry([III)I +HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->findEntry([I[C[I[CII)I +HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->makeHashCode(I)I +HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->makeHashCode([CI)I +HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->makeHashCode([II)I +HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->modulo(II)I +HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->nextIndex(II)I +HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->extend([CIII)V +HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->extend([IIII)V +HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->findAllSameBlock([II)I +HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->findBlock([C[CI)I +HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->findBlock([C[II)I +HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->findBlock([I[II)I +HSPLandroid/icu/util/MutableCodePointTrie$MixedBlocks;->init(II)V +HSPLandroid/icu/util/MutableCodePointTrie$AllSameBlocks;->add(III)V +HSPLandroid/icu/util/MutableCodePointTrie$AllSameBlocks;->findMostUsed()I +HSPLandroid/icu/util/MutableCodePointTrie$AllSameBlocks;->findOrAdd(III)I +HSPLandroid/icu/util/MutableCodePointTrie;->access$000([II[III)Z +HSPLandroid/icu/util/MutableCodePointTrie;->access$100([CI[III)Z +HSPLandroid/icu/util/MutableCodePointTrie;->access$200([CI[CII)Z +HSPLandroid/icu/util/MutableCodePointTrie;->access$300([IIII)Z +HSPLandroid/icu/util/MutableCodePointTrie;->allValuesSameAs([IIII)Z +HSPLandroid/icu/util/MutableCodePointTrie;->allocDataBlock(I)I +HSPLandroid/icu/util/MutableCodePointTrie;->build(Landroid/icu/util/CodePointTrie$Type;Landroid/icu/util/CodePointTrie$ValueWidth;)Landroid/icu/util/CodePointTrie; +HSPLandroid/icu/util/MutableCodePointTrie;->clear()V +HSPLandroid/icu/util/MutableCodePointTrie;->compactData(I[IILandroid/icu/util/MutableCodePointTrie$MixedBlocks;)I +HSPLandroid/icu/util/MutableCodePointTrie;->compactIndex(ILandroid/icu/util/MutableCodePointTrie$MixedBlocks;)I +HSPLandroid/icu/util/MutableCodePointTrie;->compactTrie(I)I +HSPLandroid/icu/util/MutableCodePointTrie;->compactWholeDataBlocks(ILandroid/icu/util/MutableCodePointTrie$AllSameBlocks;)I +HSPLandroid/icu/util/MutableCodePointTrie;->ensureHighStart(I)V +HSPLandroid/icu/util/MutableCodePointTrie;->equalBlocks([CI[CII)Z +HSPLandroid/icu/util/MutableCodePointTrie;->equalBlocks([CI[III)Z +HSPLandroid/icu/util/MutableCodePointTrie;->equalBlocks([II[III)Z +HSPLandroid/icu/util/MutableCodePointTrie;->fillBlock(IIII)V +HSPLandroid/icu/util/MutableCodePointTrie;->findAllSameBlock([IIIII)I +HSPLandroid/icu/util/MutableCodePointTrie;->findHighStart()I +HSPLandroid/icu/util/MutableCodePointTrie;->findSameBlock([CII[CII)I +HSPLandroid/icu/util/MutableCodePointTrie;->fromCodePointMap(Landroid/icu/util/CodePointMap;)Landroid/icu/util/MutableCodePointTrie; +HSPLandroid/icu/util/MutableCodePointTrie;->getAllSameOverlap([IIII)I +HSPLandroid/icu/util/MutableCodePointTrie;->getDataBlock(I)I +HSPLandroid/icu/util/MutableCodePointTrie;->getOverlap([CI[CII)I +HSPLandroid/icu/util/MutableCodePointTrie;->getOverlap([CI[III)I +HSPLandroid/icu/util/MutableCodePointTrie;->getOverlap([II[III)I +HSPLandroid/icu/util/MutableCodePointTrie;->isStartOfSomeFastBlock(I[II)Z +HSPLandroid/icu/util/MutableCodePointTrie;->maskValues(I)V +HSPLandroid/icu/util/MutableCodePointTrie;->maybeFilterValue(IIILandroid/icu/util/CodePointMap$ValueFilter;)I +HSPLandroid/icu/util/MutableCodePointTrie;->writeBlock(II)V +HSPLandroid/icu/util/MutableCodePointTrie;->buildImmutable(Landroid/icu/util/CodePointTrie$Type;Landroid/icu/util/CodePointTrie$ValueWidth;)Landroid/icu/util/CodePointTrie; +HSPLandroid/icu/util/MutableCodePointTrie;->clone()Landroid/icu/util/MutableCodePointTrie; +HSPLandroid/icu/util/MutableCodePointTrie;->clone()Ljava/lang/Object; +HSPLandroid/icu/util/MutableCodePointTrie;->get(I)I +HSPLandroid/icu/util/MutableCodePointTrie;->getRange(ILandroid/icu/util/CodePointMap$ValueFilter;Landroid/icu/util/CodePointMap$Range;)Z +HSPLandroid/icu/util/MutableCodePointTrie;->set(II)V +HSPLandroid/icu/util/MutableCodePointTrie;->setRange(III)V HSPLandroid/icu/util/SimpleTimeZone;-><init>(ILjava/lang/String;IIIIIIIIIII)V HSPLandroid/icu/util/SimpleTimeZone;->clone()Ljava/lang/Object; HSPLandroid/icu/util/SimpleTimeZone;->cloneAsThawed()Landroid/icu/util/TimeZone; diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt index 4503046c1e0a..70beac8e6ddd 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -1397,15 +1397,11 @@ Landroid/security/IKeystoreService;->exist(Ljava/lang/String;I)I Landroid/security/IKeystoreService;->generateKey(Ljava/lang/String;Landroid/security/keymaster/KeymasterArguments;[BIILandroid/security/keymaster/KeyCharacteristics;)I Landroid/security/IKeystoreService;->get(Ljava/lang/String;I)[B Landroid/security/IKeystoreService;->getState(I)I -Landroid/security/IKeystoreService;->get_pubkey(Ljava/lang/String;)[B -Landroid/security/IKeystoreService;->import_key(Ljava/lang/String;[BII)I Landroid/security/IKeystoreService;->insert(Ljava/lang/String;[BII)I Landroid/security/IKeystoreService;->is_hardware_backed(Ljava/lang/String;)I Landroid/security/IKeystoreService;->list(Ljava/lang/String;I)[Ljava/lang/String; Landroid/security/IKeystoreService;->reset()I -Landroid/security/IKeystoreService;->sign(Ljava/lang/String;[B)[B Landroid/security/IKeystoreService;->ungrant(Ljava/lang/String;I)I -Landroid/security/IKeystoreService;->verify(Ljava/lang/String;[B[B)I Landroid/security/keymaster/KeymasterBlobArgument;-><init>(ILandroid/os/Parcel;)V Landroid/security/keymaster/KeymasterBlobArgument;-><init>(I[B)V Landroid/security/keymaster/KeymasterBlobArgument;->blob:[B diff --git a/core/java/android/app/DexLoadReporter.java b/core/java/android/app/DexLoadReporter.java index 0643414727cf..229bee55e911 100644 --- a/core/java/android/app/DexLoadReporter.java +++ b/core/java/android/app/DexLoadReporter.java @@ -87,7 +87,7 @@ import java.util.Set; } @Override - public void report(List<BaseDexClassLoader> classLoadersChain, List<String> classPaths) { + public void report(List<ClassLoader> classLoadersChain, List<String> classPaths) { if (classLoadersChain.size() != classPaths.size()) { Slog.wtf(TAG, "Bad call to DexLoadReporter: argument size mismatch"); return; @@ -113,12 +113,12 @@ import java.util.Set; registerSecondaryDexForProfiling(dexPathsForRegistration); } - private void notifyPackageManager(List<BaseDexClassLoader> classLoadersChain, + private void notifyPackageManager(List<ClassLoader> classLoadersChain, List<String> classPaths) { // Get the class loader names for the binder call. List<String> classLoadersNames = new ArrayList<>(classPaths.size()); - for (BaseDexClassLoader bdc : classLoadersChain) { - classLoadersNames.add(bdc.getClass().getName()); + for (ClassLoader classLoader : classLoadersChain) { + classLoadersNames.add(classLoader.getClass().getName()); } String packageName = ActivityThread.currentPackageName(); try { diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index bc5b32c69b59..da7d6643c3fb 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -475,7 +475,7 @@ interface IPackageManager { * @param classPaths the class paths corresponding to the class loaders names from * {@param classLoadersNames}. The the first element corresponds to the first class loader * and so on. A classpath is represented as a list of dex files separated by - * {@code File.pathSeparator}. + * {@code File.pathSeparator}, or null if the class loader's classpath is not known. * The dex files found in the first class path will be recorded in the usage file. * @param loaderIsa the ISA of the loader process */ diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java index c0fa1de6feeb..3d93afdd1423 100644 --- a/core/java/android/provider/CallLog.java +++ b/core/java/android/provider/CallLog.java @@ -509,6 +509,100 @@ public class CallLog { private static final int MIN_DURATION_FOR_NORMALIZED_NUMBER_UPDATE_MS = 1000 * 10; /** + * Value for {@link CallLog.Calls#BLOCK_REASON}, set as the default value when a call was + * not blocked by a CallScreeningService or any other system call blocking method. + */ + public static final int BLOCK_REASON_NOT_BLOCKED = 0; + + /** + * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is + * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked by a + * CallScreeningService. The {@link CallLog.Calls#CALL_SCREENING_COMPONENT_NAME} and + * {@link CallLog.Calls#CALL_SCREENING_APP_NAME} columns will indicate which call screening + * service was responsible for blocking the call. + */ + public static final int BLOCK_REASON_CALL_SCREENING_SERVICE = 1; + + /** + * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is + * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked because the user + * configured a contact to be sent directly to voicemail. + */ + public static final int BLOCK_REASON_DIRECT_TO_VOICEMAIL = 2; + + /** + * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is + * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked because it is + * in the BlockedNumbers provider. + */ + public static final int BLOCK_REASON_BLOCKED_NUMBER = 3; + + /** + * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is + * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked because the user + * has chosen to block all calls from unknown numbers. + */ + public static final int BLOCK_REASON_UNKNOWN_NUMBER = 4; + + /** + * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is + * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked because the user + * has chosen to block all calls from restricted numbers. + */ + public static final int BLOCK_REASON_RESTRICTED_NUMBER = 5; + + /** + * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is + * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked because the user + * has chosen to block all calls from pay phones. + */ + public static final int BLOCK_REASON_PAY_PHONE = 6; + + /** + * Value for {@link CallLog.Calls#BLOCK_REASON}, set when {@link CallLog.Calls#TYPE} is + * {@link CallLog.Calls#BLOCKED_TYPE} to indicate that a call was blocked because the user + * has chosen to block all calls from numbers not in their contacts. + */ + public static final int BLOCK_REASON_NOT_IN_CONTACTS = 7; + + /** + * The ComponentName of the CallScreeningService which blocked this call. Will be + * populated when the {@link CallLog.Calls#TYPE} is {@link CallLog.Calls#BLOCKED_TYPE}. + * <P>Type: TEXT</P> + */ + public static final String CALL_SCREENING_COMPONENT_NAME = "call_screening_component_name"; + + /** + * The name of the app which blocked a call. Will be populated when the + * {@link CallLog.Calls#TYPE} is {@link CallLog.Calls#BLOCKED_TYPE}. Provided as a + * convenience so that the call log can still indicate which app blocked a call, even if + * that app is no longer installed. + * <P>Type: TEXT</P> + */ + public static final String CALL_SCREENING_APP_NAME = "call_screening_app_name"; + + /** + * Where the {@link CallLog.Calls#TYPE} is {@link CallLog.Calls#BLOCKED_TYPE}, + * indicates the reason why a call is blocked. + * <P>Type: INTEGER</P> + * + * <p> + * Allowed values: + * <ul> + * <li>{@link CallLog.Calls#BLOCK_REASON_NOT_BLOCKED}</li> + * <li>{@link CallLog.Calls#BLOCK_REASON_CALL_SCREENING_SERVICE}</li> + * <li>{@link CallLog.Calls#BLOCK_REASON_DIRECT_TO_VOICEMAIL}</li> + * <li>{@link CallLog.Calls#BLOCK_REASON_BLOCKED_NUMBER}</li> + * <li>{@link CallLog.Calls#BLOCK_REASON_UNKNOWN_NUMBER}</li> + * <li>{@link CallLog.Calls#BLOCK_REASON_RESTRICTED_NUMBER}</li> + * <li>{@link CallLog.Calls#BLOCK_REASON_PAY_PHONE}</li> + * <li>{@link CallLog.Calls#BLOCK_REASON_NOT_IN_CONTACTS}</li> + * </ul> + * </p> + */ + public static final String BLOCK_REASON = "block_reason"; + + /** * Adds a call to the call log. * * @param ci the CallerInfo object to get the target contact from. Can be null @@ -530,12 +624,14 @@ public class CallLog { * {@hide} */ public static Uri addCall(CallerInfo ci, Context context, String number, - int presentation, int callType, int features, PhoneAccountHandle accountHandle, + int presentation, int callType, int features, + PhoneAccountHandle accountHandle, long start, int duration, Long dataUsage) { - return addCall(ci, context, number, /* postDialDigits =*/ "", /* viaNumber =*/ "", - presentation, callType, features, accountHandle, start, duration, - dataUsage, /* addForAllUsers =*/ false, /* userToBeInsertedTo =*/ null, - /* is_read =*/ false); + return addCall(ci, context, number, "" /* postDialDigits */, "" /* viaNumber */, + presentation, callType, features, accountHandle, start, duration, + dataUsage, false /* addForAllUsers */, null /* userToBeInsertedTo */, + false /* isRead */, Calls.BLOCK_REASON_NOT_BLOCKED /* callBlockReason */, + null /* callScreeningAppName */, null /* callScreeningComponentName */); } @@ -572,8 +668,10 @@ public class CallLog { int features, PhoneAccountHandle accountHandle, long start, int duration, Long dataUsage, boolean addForAllUsers, UserHandle userToBeInsertedTo) { return addCall(ci, context, number, postDialDigits, viaNumber, presentation, callType, - features, accountHandle, start, duration, dataUsage, addForAllUsers, - userToBeInsertedTo, /* is_read =*/ false); + features, accountHandle, start, duration, dataUsage, addForAllUsers, + userToBeInsertedTo, false /* isRead */ , Calls.BLOCK_REASON_NOT_BLOCKED + /* callBlockReason */, null /* callScreeningAppName */, + null /* callScreeningComponentName */); } /** @@ -602,8 +700,11 @@ public class CallLog { * @param userToBeInsertedTo {@link UserHandle} of user that the call is going to be * inserted to. null if it is inserted to the current user. The * value is ignored if @{link addForAllUsers} is true. - * @param is_read Flag to show if the missed call log has been read by the user or not. + * @param isRead Flag to show if the missed call log has been read by the user or not. * Used for call log restore of missed calls. + * @param callBlockReason The reason why the call is blocked. + * @param callScreeningAppName The call screening application name which block the call. + * @param callScreeningComponentName The call screening component name which block the call. * * @result The URI of the call log entry belonging to the user that made or received this * call. This could be of the shadow provider. Do not return it to non-system apps, @@ -615,7 +716,8 @@ public class CallLog { String postDialDigits, String viaNumber, int presentation, int callType, int features, PhoneAccountHandle accountHandle, long start, int duration, Long dataUsage, boolean addForAllUsers, UserHandle userToBeInsertedTo, - boolean is_read) { + boolean isRead, int callBlockReason, String callScreeningAppName, + String callScreeningComponentName) { if (VERBOSE_LOG) { Log.v(LOG_TAG, String.format("Add call: number=%s, user=%s, for all=%s", number, userToBeInsertedTo, addForAllUsers)); @@ -690,9 +792,13 @@ public class CallLog { values.put(ADD_FOR_ALL_USERS, addForAllUsers ? 1 : 0); if (callType == MISSED_TYPE) { - values.put(IS_READ, Integer.valueOf(is_read ? 1 : 0)); + values.put(IS_READ, Integer.valueOf(isRead ? 1 : 0)); } + values.put(BLOCK_REASON, callBlockReason); + values.put(CALL_SCREENING_APP_NAME, callScreeningAppName); + values.put(CALL_SCREENING_COMPONENT_NAME, callScreeningComponentName); + if ((ci != null) && (ci.contactIdOrZero > 0)) { // Update usage information for the number associated with the contact ID. // We need to use both the number and the ID for obtaining a data ID since other diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 0f31a8a7d00c..8518c7021ee7 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -248,6 +248,10 @@ <item>@string/wfcSpnFormat_spn_wifi</item> <item>@string/wfcSpnFormat_wifi_calling_bar_spn</item> <item>@string/wfcSpnFormat_spn_vowifi</item> + <item>@string/wfcSpnFormat_wifi_calling</item> + <item>@string/wfcSpnFormat_wifi</item> + <item>@string/wfcSpnFormat_wifi_calling_wo_hyphen</item> + <item>@string/wfcSpnFormat_vowifi</item> </string-array> <!-- Spn during Wi-Fi Calling: "<operator>" --> @@ -264,6 +268,14 @@ <string name="wfcSpnFormat_wifi_calling_bar_spn">WiFi Calling | <xliff:g id="spn" example="Operator">%s</xliff:g></string> <!-- Spn during Wi-Fi Calling: "<operator> VoWifi" --> <string name="wfcSpnFormat_spn_vowifi"><xliff:g id="spn" example="Operator">%s</xliff:g> VoWifi</string> + <!-- Spn during Wi-Fi Calling: "Wi-Fi Calling" --> + <string name="wfcSpnFormat_wifi_calling">Wi-Fi Calling</string> + <!-- Spn during Wi-Fi Calling: "Wi-Fi" --> + <string name="wfcSpnFormat_wifi">Wi-Fi</string> + <!-- Spn during Wi-Fi Calling: "WiFi Calling" (without hyphen) --> + <string name="wfcSpnFormat_wifi_calling_wo_hyphen">WiFi Calling</string> + <!-- Spn during Wi-Fi Calling: "VoWifi" --> + <string name="wfcSpnFormat_vowifi">VoWifi</string> <!-- WFC, summary for Disabled --> <string name="wifi_calling_off_summary">Off</string> diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index 799900f3bd6a..4e018833f1ff 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -30,6 +30,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; +import android.security.KeyStoreException; import android.security.keymaster.ExportResult; import android.security.keymaster.KeyCharacteristics; import android.security.keymaster.KeymasterArguments; @@ -40,14 +41,21 @@ import android.security.keymaster.OperationResult; import android.security.keystore.KeyExpiredException; import android.security.keystore.KeyNotYetValidException; import android.security.keystore.KeyPermanentlyInvalidatedException; +import android.security.keystore.KeyProperties; +import android.security.keystore.KeyProtection; import android.security.keystore.StrongBoxUnavailableException; import android.security.keystore.UserNotAuthenticatedException; import android.util.Log; - +import com.android.org.bouncycastle.asn1.ASN1InputStream; +import com.android.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import java.math.BigInteger; +import java.io.ByteArrayInputStream; +import java.io.IOException; import java.security.InvalidKeyException; import java.util.List; import java.util.Locale; +import sun.security.util.ObjectIdentifier; +import sun.security.x509.AlgorithmId; /** * @hide This should not be made public in its present form because it @@ -69,6 +77,7 @@ public class KeyStore { public static final int VALUE_CORRUPTED = 8; public static final int UNDEFINED_ACTION = 9; public static final int WRONG_PASSWORD = 10; + public static final int KEY_ALREADY_EXISTS = 16; public static final int CANNOT_ATTEST_IDS = -66; public static final int HARDWARE_TYPE_UNAVAILABLE = -68; @@ -228,7 +237,12 @@ public class KeyStore { if (value == null) { value = new byte[0]; } - return mBinder.insert(key, value, uid, flags); + int error = mBinder.insert(key, value, uid, flags); + if (error == KEY_ALREADY_EXISTS) { + mBinder.del(key, uid); + error = mBinder.insert(key, value, uid, flags); + } + return error; } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return SYSTEM_ERROR; @@ -355,53 +369,6 @@ public class KeyStore { return isEmpty(UserHandle.myUserId()); } - public boolean generate(String key, int uid, int keyType, int keySize, int flags, - byte[][] args) { - try { - return mBinder.generate(key, uid, keyType, keySize, flags, - new KeystoreArguments(args)) == NO_ERROR; - } catch (RemoteException e) { - Log.w(TAG, "Cannot connect to keystore", e); - return false; - } - } - - public boolean importKey(String keyName, byte[] key, int uid, int flags) { - try { - return mBinder.import_key(keyName, key, uid, flags) == NO_ERROR; - } catch (RemoteException e) { - Log.w(TAG, "Cannot connect to keystore", e); - return false; - } - } - - public byte[] sign(String key, byte[] data) { - try { - return mBinder.sign(key, data); - } catch (RemoteException e) { - Log.w(TAG, "Cannot connect to keystore", e); - return null; - } catch (android.os.ServiceSpecificException e) { - Log.w(TAG, "KeyStore exception", e); - return null; - } - - } - - public boolean verify(String key, byte[] data, byte[] signature) { - try { - signature = signature != null ? signature : new byte[0]; - return mBinder.verify(key, data, signature) == NO_ERROR; - } catch (RemoteException e) { - Log.w(TAG, "Cannot connect to keystore", e); - return false; - } catch (android.os.ServiceSpecificException e) { - Log.w(TAG, "KeyStore exception", e); - return false; - } - - } - public String grant(String key, int uid) { try { String grantAlias = mBinder.grant(key, uid); @@ -485,7 +452,12 @@ public class KeyStore { try { entropy = entropy != null ? entropy : new byte[0]; args = args != null ? args : new KeymasterArguments(); - return mBinder.generateKey(alias, args, entropy, uid, flags, outCharacteristics); + int error = mBinder.generateKey(alias, args, entropy, uid, flags, outCharacteristics); + if (error == KEY_ALREADY_EXISTS) { + mBinder.del(alias, uid); + error = mBinder.generateKey(alias, args, entropy, uid, flags, outCharacteristics); + } + return error; } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return SYSTEM_ERROR; @@ -517,8 +489,14 @@ public class KeyStore { public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData, int uid, int flags, KeyCharacteristics outCharacteristics) { try { - return mBinder.importKey(alias, args, format, keyData, uid, flags, + int error = mBinder.importKey(alias, args, format, keyData, uid, flags, outCharacteristics); + if (error == KEY_ALREADY_EXISTS) { + mBinder.del(alias, uid); + error = mBinder.importKey(alias, args, format, keyData, uid, flags, + outCharacteristics); + } + return error; } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return SYSTEM_ERROR; @@ -530,13 +508,78 @@ public class KeyStore { return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics); } + private String getAlgorithmFromPKCS8(byte[] keyData) { + try { + final ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(keyData)); + final PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject()); + final String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId(); + return new AlgorithmId(new ObjectIdentifier(algOid)).getName(); + } catch (IOException e) { + Log.e(TAG, "getAlgorithmFromPKCS8 Failed to parse key data"); + Log.e(TAG, Log.getStackTraceString(e)); + return null; + } + } + + private KeymasterArguments makeLegacyArguments(String algorithm) { + KeymasterArguments args = new KeymasterArguments(); + args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, + KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(algorithm)); + args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_SIGN); + args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_VERIFY); + args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT); + args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT); + args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE); + if (algorithm.equalsIgnoreCase(KeyProperties.KEY_ALGORITHM_RSA)) { + args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_OAEP); + args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT); + args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN); + args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PSS); + } + args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_NONE); + args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_MD5); + args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA1); + args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_224); + args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_256); + args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_384); + args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_512); + args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED); + args.addUnsignedLong(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME, + KeymasterArguments.UINT64_MAX_VALUE); + args.addUnsignedLong(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME, + KeymasterArguments.UINT64_MAX_VALUE); + args.addUnsignedLong(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, BigInteger.ZERO); + return args; + } + + public boolean importKey(String alias, byte[] keyData, int uid, int flags) { + String algorithm = getAlgorithmFromPKCS8(keyData); + if (algorithm == null) return false; + KeymasterArguments args = makeLegacyArguments(algorithm); + KeyCharacteristics out = new KeyCharacteristics(); + int result = importKey(alias, args, KeymasterDefs.KM_KEY_FORMAT_PKCS8, keyData, uid, + flags, out); + if (result != NO_ERROR) { + Log.e(TAG, Log.getStackTraceString( + new KeyStoreException(result, "legacy key import failed"))); + return false; + } + return true; + } + public int importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey, String wrappingKeyAlias, byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, int uid, KeyCharacteristics outCharacteristics) { try { - return mBinder.importWrappedKey(wrappedKeyAlias, wrappedKey, wrappingKeyAlias, + int error = mBinder.importWrappedKey(wrappedKeyAlias, wrappedKey, wrappingKeyAlias, maskingKey, args, rootSid, fingerprintSid, outCharacteristics); + if (error == KEY_ALREADY_EXISTS) { + mBinder.del(wrappedKeyAlias, -1); + error = mBinder.importWrappedKey(wrappedKeyAlias, wrappedKey, wrappingKeyAlias, + maskingKey, args, rootSid, fingerprintSid, outCharacteristics); + } + return error; } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return SYSTEM_ERROR; @@ -616,21 +659,6 @@ public class KeyStore { } /** - * Check if the operation referenced by {@code token} is currently authorized. - * - * @param token An operation token returned by a call to - * {@link #begin(String, int, boolean, KeymasterArguments, byte[], KeymasterArguments) begin}. - */ - public boolean isOperationAuthorized(IBinder token) { - try { - return mBinder.isOperationAuthorized(token); - } catch (RemoteException e) { - Log.w(TAG, "Cannot connect to keystore", e); - return false; - } - } - - /** * Add an authentication record to the keystore authorization table. * * @param authToken The packed bytes of a hw_auth_token_t to be provided to keymaster. diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index dc9a5adb5a0c..7fb161c8c4ae 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -2069,8 +2069,13 @@ final class ActivityManagerShellCommand extends ShellCommand { } FeatureInfo[] features = pm.getSystemAvailableFeatures(); - Arrays.sort(features, (o1, o2) -> - (o1.name == o2.name ? 0 : (o1.name == null ? -1 : o1.name.compareTo(o2.name)))); + Arrays.sort(features, (o1, o2) -> { + if (o1.name == o2.name) return 0; + if (o1.name == null) return -1; + if (o2.name == null) return 1; + return o1.name.compareTo(o2.name); + }); + for (int i = 0; i < features.length; i++) { if (features[i].name != null) { if (protoOutputStream != null) { diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java index deaa33485170..94c94a514dec 100644 --- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java +++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java @@ -165,7 +165,7 @@ public class PermissionMonitor { } @VisibleForTesting - int getDeviceFirstSdkInt() { + protected int getDeviceFirstSdkInt() { return Build.VERSION.FIRST_SDK_INT; } 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 753c2833b056..580e4f481a27 100644 --- a/services/core/java/com/android/server/pm/dex/DexManager.java +++ b/services/core/java/com/android/server/pm/dex/DexManager.java @@ -35,6 +35,7 @@ import android.util.Slog; import android.util.jar.StrictJarFile; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.server.pm.Installer; import com.android.server.pm.Installer.InstallerException; @@ -153,7 +154,7 @@ public class DexManager { * @param classPaths the class paths corresponding to the class loaders names from * {@param classLoadersNames}. The the first element corresponds to the first class loader * and so on. A classpath is represented as a list of dex files separated by - * {@code File.pathSeparator}. + * {@code File.pathSeparator}, or null if the class loader's classpath is not known. * The dex files found in the first class path will be recorded in the usage file. * @param loaderIsa the ISA of the app loading the dex files * @param loaderUserId the user id which runs the code loading the dex files @@ -169,7 +170,8 @@ public class DexManager { } } - private void notifyDexLoadInternal(ApplicationInfo loadingAppInfo, + @VisibleForTesting + /*package*/ void notifyDexLoadInternal(ApplicationInfo loadingAppInfo, List<String> classLoaderNames, List<String> classPaths, String loaderIsa, int loaderUserId) { if (classLoaderNames.size() != classPaths.size()) { @@ -186,8 +188,14 @@ public class DexManager { return; } + // The first classpath should never be null because the first classloader + // should always be an instance of BaseDexClassLoader. + String firstClassPath = classPaths.get(0); + if (firstClassPath == null) { + return; + } // The classpath is represented as a list of dex files separated by File.pathSeparator. - String[] dexPathsToRegister = classPaths.get(0).split(File.pathSeparator); + String[] dexPathsToRegister = firstClassPath.split(File.pathSeparator); // Encode the class loader contexts for the dexPathsToRegister. String[] classLoaderContexts = DexoptUtils.processContextForDexLoad( diff --git a/services/core/java/com/android/server/pm/dex/DexoptUtils.java b/services/core/java/com/android/server/pm/dex/DexoptUtils.java index e1310a2f1ab3..d2600b5060b5 100644 --- a/services/core/java/com/android/server/pm/dex/DexoptUtils.java +++ b/services/core/java/com/android/server/pm/dex/DexoptUtils.java @@ -318,7 +318,8 @@ public final class DexoptUtils { // is fine (they come over binder). Even if something changes we expect the sizes to be // very small and it shouldn't matter much. for (int i = 1; i < classLoadersNames.size(); i++) { - if (!ClassLoaderFactory.isValidClassLoaderName(classLoadersNames.get(i))) { + if (!ClassLoaderFactory.isValidClassLoaderName(classLoadersNames.get(i)) + || classPaths.get(i) == null) { return null; } String classpath = encodeClasspath(classPaths.get(i).split(File.pathSeparator)); 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 030f9cca265e..b30c04309955 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 @@ -69,6 +69,7 @@ public class DexManagerTests { private static final String PATH_CLASS_LOADER_NAME = PathClassLoader.class.getName(); private static final String DELEGATE_LAST_CLASS_LOADER_NAME = DelegateLastClassLoader.class.getName(); + private static final String UNSUPPORTED_CLASS_LOADER_NAME = "unsupported.class_loader"; @Rule public MockitoRule mockito = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS); @Mock Installer mInstaller; @@ -106,7 +107,7 @@ public class DexManagerTests { mDoesNotExist = new TestData("DOES.NOT.EXIST", isa, mUser1); mBarUser0UnsupportedClassLoader = new TestData(bar, isa, mUser0, - "unsupported.class_loader"); + UNSUPPORTED_CLASS_LOADER_NAME); mBarUser0DelegateLastClassLoader = new TestData(bar, isa, mUser0, DELEGATE_LAST_CLASS_LOADER_NAME); @@ -406,6 +407,24 @@ public class DexManagerTests { } @Test + public void testNotifySupportedAndUnsupportedClassLoader() { + String classPath = String.join(File.pathSeparator, mBarUser0.getSecondaryDexPaths()); + List<String> classLoaders = + Arrays.asList(PATH_CLASS_LOADER_NAME, UNSUPPORTED_CLASS_LOADER_NAME); + List<String> classPaths = Arrays.asList(classPath, classPath); + notifyDexLoad(mBarUser0, classLoaders, classPaths, mUser0); + + assertNoUseInfo(mBarUser0); + } + + @Test + public void testNotifyNullClassPath() { + notifyDexLoad(mBarUser0, null, mUser0); + + assertNoUseInfo(mBarUser0); + } + + @Test public void testNotifyVariableClassLoader() { // Record bar secondaries with the default PathClassLoader. List<String> secondaries = mBarUser0.getSecondaryDexPaths(); @@ -500,14 +519,17 @@ public class DexManagerTests { // By default, assume a single class loader in the chain. // This makes writing tests much easier. List<String> classLoaders = Arrays.asList(testData.mClassLoader); - List<String> classPaths = Arrays.asList(String.join(File.pathSeparator, dexPaths)); + List<String> classPaths = (dexPaths == null) + ? Arrays.asList((String) null) + : Arrays.asList(String.join(File.pathSeparator, dexPaths)); notifyDexLoad(testData, classLoaders, classPaths, loaderUserId); } - private void notifyDexLoad(TestData testData, List<String> classLoader, List<String> classPaths, - int loaderUserId) { - mDexManager.notifyDexLoad(testData.mPackageInfo.applicationInfo, classLoader, classPaths, - testData.mLoaderIsa, loaderUserId); + private void notifyDexLoad(TestData testData, List<String> classLoaders, + List<String> classPaths, int loaderUserId) { + // We call the internal function so any exceptions thrown cause test failures. + mDexManager.notifyDexLoadInternal(testData.mPackageInfo.applicationInfo, classLoaders, + classPaths, testData.mLoaderIsa, loaderUserId); } private PackageUseInfo getPackageUseInfo(TestData testData) { diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java index 150f7f0c948c..6e0f56c8e7c8 100644 --- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java @@ -353,6 +353,18 @@ public class DexoptUtilsTest { } @Test + public void testProcessContextForDexLoadNoClassPath() { + List<String> classLoaders = Arrays.asList( + DELEGATE_LAST_CLASS_LOADER_NAME, + PATH_CLASS_LOADER_NAME); + List<String> classPaths = Arrays.asList( + String.join(File.pathSeparator, "foo.dex", "bar.dex"), + null); + String[] context = DexoptUtils.processContextForDexLoad(classLoaders, classPaths); + assertNull(context); + } + + @Test public void testProcessContextForDexLoadIllegalCallEmptyList() { boolean gotException = false; try { diff --git a/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp index c39688cb8f2d..0c40a6b5fa84 100644 --- a/startop/view_compiler/Android.bp +++ b/startop/view_compiler/Android.bp @@ -62,3 +62,22 @@ cc_test_host { ], test_suites: ["general-tests"], } + +cc_binary_host { + name: "dex_testcase_generator", + defaults: ["viewcompiler_defaults"], + srcs: ["dex_testcase_generator.cc"], + static_libs: [ + "libviewcompiler", + ], +} + +genrule { + name: "generate_dex_testcases", + tools: [":dex_testcase_generator"], + cmd: "$(location :dex_testcase_generator) $(genDir)", + out: [ + "simple.dex", + "trivial.dex", + ], +} diff --git a/startop/view_compiler/README.md b/startop/view_compiler/README.md index 56595016cbb9..f8da02b53907 100644 --- a/startop/view_compiler/README.md +++ b/startop/view_compiler/README.md @@ -23,3 +23,31 @@ This tool is still in its early stages and has a number of limitations. application. * This only works for apps that do not use a custom layout inflater. * Other limitations yet to be discovered. + +## DexBuilder Tests + +The DexBuilder has several low-level end to end tests to verify generated DEX +code validates, runs, and has the correct behavior. There are, unfortunately, a +number of pieces that must be added to generate new tests. Here are the +components: + +* `dex_testcase_generator` - Written in C++ using `DexBuilder`. This runs as a + build step produce the DEX files that will be tested on device. See the + `genrule` named `generate_dex_testcases` in `Android.bp`. These files are then + copied over to the device by TradeFed when running tests. +* `DexBuilderTest` - This is a Java Language test harness that loads the + generated DEX files and exercises methods in the file. + +To add a new DEX file test, follow these steps: +1. Modify `dex_testcase_generator` to produce the DEX file. +2. Add the filename to the `out` list of the `generate_dex_testcases` rule in + `Android.bp`. +3. Add a new `push` option to `AndroidTest.xml` to copy the DEX file to the + device. +4. Modify `DexBuilderTest.java` to load and exercise the new test. + +In each case, you should be able to cargo-cult the existing test cases. + +In general, you can probably get by without adding a new generated DEX file, and +instead add more methods to the files that are already generated. In this case, +you can skip all of steps 2 and 3 above, and simplify steps 1 and 4. diff --git a/startop/view_compiler/TEST_MAPPING b/startop/view_compiler/TEST_MAPPING new file mode 100644 index 000000000000..5d675b76b395 --- /dev/null +++ b/startop/view_compiler/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit": [ + { + "name": "dex-builder-test" + } + ] +} diff --git a/startop/view_compiler/dex_builder_test/Android.bp b/startop/view_compiler/dex_builder_test/Android.bp new file mode 100644 index 000000000000..4449ea0f707e --- /dev/null +++ b/startop/view_compiler/dex_builder_test/Android.bp @@ -0,0 +1,29 @@ +// +// Copyright (C) 2018 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +android_test { + name: "dex-builder-test", + srcs: ["src/android/startop/test/DexBuilderTest.java"], + sdk_version: "current", + data: [":generate_dex_testcases"], + static_libs: [ + "android-support-test", + "guava", + ], + manifest: "AndroidManifest.xml", + test_config: "AndroidTest.xml", + test_suites: ["general-tests"], +} diff --git a/startop/view_compiler/dex_builder_test/AndroidManifest.xml b/startop/view_compiler/dex_builder_test/AndroidManifest.xml new file mode 100644 index 000000000000..6ac5fc5db345 --- /dev/null +++ b/startop/view_compiler/dex_builder_test/AndroidManifest.xml @@ -0,0 +1,29 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="android.startop.test" > + + <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" /> + + <application> + <uses-library android:name="android.test.runner" /> + </application> + + <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + android:targetPackage="android.startop.test" + android:label="DexBuilder Tests"/> + +</manifest> diff --git a/startop/view_compiler/dex_builder_test/AndroidTest.xml b/startop/view_compiler/dex_builder_test/AndroidTest.xml new file mode 100644 index 000000000000..6f90cf3b81a7 --- /dev/null +++ b/startop/view_compiler/dex_builder_test/AndroidTest.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<configuration description="Runs DexBuilder Tests."> + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="apct-instrumentation" /> + <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller"> + <option name="cleanup-apks" value="true" /> + <option name="test-file-name" value="dex-builder-test.apk" /> + </target_preparer> + + <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher"> + <option name="cleanup" value="true" /> + <option name="push" value="trivial.dex->/data/local/tmp/dex-builder-test/trivial.dex" /> + <option name="push" value="simple.dex->/data/local/tmp/dex-builder-test/simple.dex" /> + </target_preparer> + + <test class="com.android.tradefed.testtype.AndroidJUnitTest" > + <option name="package" value="android.startop.test" /> + <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" /> + </test> +</configuration> diff --git a/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java new file mode 100644 index 000000000000..87b25780aaa8 --- /dev/null +++ b/startop/view_compiler/dex_builder_test/src/android/startop/test/DexBuilderTest.java @@ -0,0 +1,68 @@ +/* + * 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.startop.test; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import com.google.common.io.ByteStreams; +import dalvik.system.InMemoryDexClassLoader; +import dalvik.system.PathClassLoader; +import java.io.InputStream; +import java.lang.reflect.Method; +import java.nio.ByteBuffer; +import org.junit.Assert; +import org.junit.Test; + +// Adding tests here requires changes in several other places. See README.md in +// the view_compiler directory for more information. +public class DexBuilderTest { + static ClassLoader loadDexFile(String filename) throws Exception { + return new PathClassLoader("/data/local/tmp/dex-builder-test/" + filename, + ClassLoader.getSystemClassLoader()); + } + + public void hello() {} + + @Test + public void loadTrivialDex() throws Exception { + ClassLoader loader = loadDexFile("trivial.dex"); + loader.loadClass("android.startop.test.testcases.Trivial"); + } + + @Test + public void return5() throws Exception { + ClassLoader loader = loadDexFile("simple.dex"); + Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests"); + Method method = clazz.getMethod("return5"); + Assert.assertEquals(5, method.invoke(null)); + } + + @Test + public void returnParam() throws Exception { + ClassLoader loader = loadDexFile("simple.dex"); + Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests"); + Method method = clazz.getMethod("returnParam", int.class); + Assert.assertEquals(5, method.invoke(null, 5)); + Assert.assertEquals(42, method.invoke(null, 42)); + } + + @Test + public void returnStringLength() throws Exception { + ClassLoader loader = loadDexFile("simple.dex"); + Class clazz = loader.loadClass("android.startop.test.testcases.SimpleTests"); + Method method = clazz.getMethod("returnStringLength", String.class); + Assert.assertEquals(13, method.invoke(null, "Hello, World!")); + } +} diff --git a/startop/view_compiler/dex_testcase_generator.cc b/startop/view_compiler/dex_testcase_generator.cc new file mode 100644 index 000000000000..898817b4768c --- /dev/null +++ b/startop/view_compiler/dex_testcase_generator.cc @@ -0,0 +1,85 @@ +/* + * 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. + */ + +#include "android-base/logging.h" +#include "dex_builder.h" + +#include <fstream> +#include <string> + +// Adding tests here requires changes in several other places. See README.md in +// the view_compiler directory for more information. + +using namespace startop::dex; +using namespace std; + +void GenerateTrivialDexFile(const string& outdir) { + DexBuilder dex_file; + + ClassBuilder cbuilder{dex_file.MakeClass("android.startop.test.testcases.Trivial")}; + cbuilder.set_source_file("dex_testcase_generator.cc#GenerateTrivialDexFile"); + + slicer::MemView image{dex_file.CreateImage()}; + std::ofstream out_file(outdir + "/trivial.dex"); + out_file.write(image.ptr<const char>(), image.size()); +} + +// Generates test cases that test around 1 instruction. +void GenerateSimpleTestCases(const string& outdir) { + DexBuilder dex_file; + + ClassBuilder cbuilder{dex_file.MakeClass("android.startop.test.testcases.SimpleTests")}; + cbuilder.set_source_file("dex_testcase_generator.cc#GenerateSimpleTestCases"); + + // int return5() { return 5; } + auto return5{cbuilder.CreateMethod("return5", Prototype{TypeDescriptor::Int()})}; + Value r{return5.MakeRegister()}; + return5.BuildConst4(r, 5); + return5.BuildReturn(r); + return5.Encode(); + + // // int returnParam(int x) { return x; } + auto returnParam{cbuilder.CreateMethod("returnParam", + Prototype{TypeDescriptor::Int(), TypeDescriptor::Int()})}; + returnParam.BuildReturn(Value::Parameter(0)); + returnParam.Encode(); + + // int returnStringLength(String x) { return x.length(); } + auto string_type{TypeDescriptor::FromClassname("java.lang.String")}; + MethodDeclData string_length{ + dex_file.GetOrDeclareMethod(string_type, "length", Prototype{TypeDescriptor::Int()})}; + + auto returnStringLength{ + cbuilder.CreateMethod("returnStringLength", Prototype{TypeDescriptor::Int(), string_type})}; + Value result = returnStringLength.MakeRegister(); + returnStringLength.AddInstruction( + Instruction::InvokeVirtual(string_length.id, result, Value::Parameter(0))); + returnStringLength.BuildReturn(result); + returnStringLength.Encode(); + + slicer::MemView image{dex_file.CreateImage()}; + std::ofstream out_file(outdir + "/simple.dex"); + out_file.write(image.ptr<const char>(), image.size()); +} + +int main(int argc, char** argv) { + CHECK_EQ(argc, 2); + + string outdir = argv[1]; + + GenerateTrivialDexFile(outdir); + GenerateSimpleTestCases(outdir); +} diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java index f62b170989ad..7db69407ad3d 100644 --- a/telecomm/java/android/telecom/CallScreeningService.java +++ b/telecomm/java/android/telecom/CallScreeningService.java @@ -18,6 +18,7 @@ package android.telecom; import android.annotation.SdkConstant; import android.app.Service; +import android.content.ComponentName; import android.content.Intent; import android.os.Handler; import android.os.IBinder; @@ -229,7 +230,8 @@ public abstract class CallScreeningService extends Service { callDetails.getTelecomCallId(), response.getRejectCall(), !response.getSkipCallLog(), - !response.getSkipNotification()); + !response.getSkipNotification(), + new ComponentName(getPackageName(), getClass().getName())); } else { mCallScreeningAdapter.allowCall(callDetails.getTelecomCallId()); } diff --git a/telecomm/java/android/telecom/Logging/EventManager.java b/telecomm/java/android/telecom/Logging/EventManager.java index 2bda6480b99e..1342038c6477 100644 --- a/telecomm/java/android/telecom/Logging/EventManager.java +++ b/telecomm/java/android/telecom/Logging/EventManager.java @@ -180,7 +180,7 @@ public class EventManager { } } - private final List<Event> mEvents = new LinkedList<>(); + private final List<Event> mEvents = Collections.synchronizedList(new LinkedList<>()); private final Loggable mRecordEntry; public EventRecord(Loggable recordEntry) { @@ -197,7 +197,7 @@ public class EventManager { } public List<Event> getEvents() { - return mEvents; + return new LinkedList<>(mEvents); } public List<EventTiming> extractEventTimings() { @@ -207,21 +207,24 @@ public class EventManager { LinkedList<EventTiming> result = new LinkedList<>(); Map<String, PendingResponse> pendingResponses = new HashMap<>(); - for (Event event : mEvents) { - if (requestResponsePairs.containsKey(event.eventId)) { - // This event expects a response, so add that expected response to the maps - // of pending events. - for (EventManager.TimedEventPair p : requestResponsePairs.get(event.eventId)) { - pendingResponses.put(p.mResponse, new PendingResponse(event.eventId, - event.time, p.mTimeoutMillis, p.mName)); + synchronized (mEvents) { + for (Event event : mEvents) { + if (requestResponsePairs.containsKey(event.eventId)) { + // This event expects a response, so add that expected response to the maps + // of pending events. + for (EventManager.TimedEventPair p : requestResponsePairs.get( + event.eventId)) { + pendingResponses.put(p.mResponse, new PendingResponse(event.eventId, + event.time, p.mTimeoutMillis, p.mName)); + } } - } - PendingResponse pendingResponse = pendingResponses.remove(event.eventId); - if (pendingResponse != null) { - long elapsedTime = event.time - pendingResponse.requestEventTimeMillis; - if (elapsedTime < pendingResponse.timeoutMillis) { - result.add(new EventTiming(pendingResponse.name, elapsedTime)); + PendingResponse pendingResponse = pendingResponses.remove(event.eventId); + if (pendingResponse != null) { + long elapsedTime = event.time - pendingResponse.requestEventTimeMillis; + if (elapsedTime < pendingResponse.timeoutMillis) { + result.add(new EventTiming(pendingResponse.name, elapsedTime)); + } } } } @@ -233,7 +236,8 @@ public class EventManager { pw.print(mRecordEntry.getDescription()); pw.increaseIndent(); - for (Event event : mEvents) { + // Iterate over copy of events so that this doesn't hold the lock for too long. + for (Event event : getEvents()) { pw.print(event.timestampString); pw.print(" - "); pw.print(event.eventId); diff --git a/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl b/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl index 2e0af27907b5..d255ed169c98 100644 --- a/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl +++ b/telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl @@ -16,6 +16,8 @@ package com.android.internal.telecom; +import android.content.ComponentName; + /** * Internal remote callback interface for call screening services. * @@ -30,5 +32,6 @@ oneway interface ICallScreeningAdapter { String callId, boolean shouldReject, boolean shouldAddToCallLog, - boolean shouldShowNotification); + boolean shouldShowNotification, + in ComponentName componentName); } diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index c2958d35709b..0280a759e943 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -1079,24 +1079,44 @@ public class CarrierConfigManager { "wfc_operator_error_codes_string_array"; /** - * Indexes of SPN format strings in wfcSpnFormats and wfcDataSpnFormats. + * Indexes of SPN format strings in wfcSpnFormats. * * <p>Available options are: * <ul> - * <li> 0: %s</li> - * <li> 1: %s Wi-Fi Calling</li> - * <li> 2: WLAN Call</li> - * <li> 3: %s WLAN Call</li> - * <li> 4: %s Wi-Fi</li> - * <li> 5: WiFi Calling | %s</li> - * <li> 6: %s VoWifi</li> + * <li> 0: %s</li> + * <li> 1: %s Wi-Fi Calling</li> + * <li> 2: WLAN Call</li> + * <li> 3: %s WLAN Call</li> + * <li> 4: %s Wi-Fi</li> + * <li> 5: WiFi Calling | %s</li> + * <li> 6: %s VoWifi</li> + * <li> 7: Wi-Fi Calling</li> + * <li> 8: Wi-Fi</li> + * <li> 9: WiFi Calling</li> + * <li> 10: VoWifi</li> * @hide */ public static final String KEY_WFC_SPN_FORMAT_IDX_INT = "wfc_spn_format_idx_int"; - /** @hide */ + + /** + * Indexes of data SPN format strings in wfcSpnFormats. + * + * @see KEY_WFC_SPN_FORMAT_IDX_INT for available options. + * @hide + */ public static final String KEY_WFC_DATA_SPN_FORMAT_IDX_INT = "wfc_data_spn_format_idx_int"; /** + * Indexes of SPN format strings in wfcSpnFormats used during flight mode. + * + * Set to -1 to use the value from KEY_WFC_SPN_FORMAT_IDX_INT also in this case. + * @see KEY_WFC_SPN_FORMAT_IDX_INT for other available options. + * @hide + */ + public static final String KEY_WFC_FLIGHT_MODE_SPN_FORMAT_IDX_INT = + "wfc_flight_mode_spn_format_idx_int"; + + /** * Use root locale when reading wfcSpnFormats. * * If true, then the root locale will always be used when reading wfcSpnFormats. This means the @@ -2466,6 +2486,7 @@ public class CarrierConfigManager { sDefaults.putStringArray(KEY_WFC_OPERATOR_ERROR_CODES_STRING_ARRAY, null); sDefaults.putInt(KEY_WFC_SPN_FORMAT_IDX_INT, 0); sDefaults.putInt(KEY_WFC_DATA_SPN_FORMAT_IDX_INT, 0); + sDefaults.putInt(KEY_WFC_FLIGHT_MODE_SPN_FORMAT_IDX_INT, -1); sDefaults.putBoolean(KEY_WFC_SPN_USE_ROOT_LOCALE, false); sDefaults.putString(KEY_WFC_EMERGENCY_ADDRESS_CARRIER_APP_STRING, ""); sDefaults.putBoolean(KEY_CONFIG_WIFI_DISABLE_IN_ECBM, false); diff --git a/telephony/java/com/android/internal/telephony/NetworkScanResult.java b/telephony/java/com/android/internal/telephony/NetworkScanResult.java index 95f39d7f878a..d07d77ca742a 100644 --- a/telephony/java/com/android/internal/telephony/NetworkScanResult.java +++ b/telephony/java/com/android/internal/telephony/NetworkScanResult.java @@ -19,6 +19,7 @@ package com.android.internal.telephony; import android.os.Parcel; import android.os.Parcelable; import android.telephony.CellInfo; + import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -106,6 +107,17 @@ public final class NetworkScanResult implements Parcelable { } @Override + public String toString() { + return new StringBuilder() + .append("{") + .append("scanStatus=" + scanStatus) + .append(", scanError=" + scanError) + .append(", networkInfos=" + networkInfos) + .append("}") + .toString(); + } + + @Override public int hashCode () { return ((scanStatus * 31) + (scanError * 23) diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java index f12756a8062f..af7123b84842 100644 --- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java @@ -30,7 +30,9 @@ import static android.os.Process.SYSTEM_UID; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.content.Context; @@ -63,24 +65,13 @@ public class PermissionMonitorTest { @Mock private PackageManager mPackageManager; private PermissionMonitor mPermissionMonitor; - private int mMockFirstSdkInt; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(MOCK_PACKAGE_NAMES); - // Try to use spy() here for stubbing getDeviceFirstSdkInt value but the spies are loaded - // by a custom class loader that's different from the loader used for loading the real - // thing. That means those two classes are not in the same package, so a package private - // method is not accessible. Hence, using override method to control FIRST_SDK_INT value - // instead of spy function for testing. - mPermissionMonitor = new PermissionMonitor(mContext, null) { - @Override - int getDeviceFirstSdkInt() { - return mMockFirstSdkInt; - } - }; + mPermissionMonitor = spy(new PermissionMonitor(mContext, null)); } private boolean hasBgPermission(String partition, int targetSdkVersion, int uid, @@ -166,13 +157,13 @@ public class PermissionMonitorTest { @Test public void testHasUseBackgroundNetworksPermissionSystemUid() throws Exception { - mMockFirstSdkInt = VERSION_P; + doReturn(VERSION_P).when(mPermissionMonitor).getDeviceFirstSdkInt(); assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID)); assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CHANGE_WIFI_STATE)); assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_P, SYSTEM_UID, CONNECTIVITY_USE_RESTRICTED_NETWORKS)); - mMockFirstSdkInt = VERSION_Q; + doReturn(VERSION_Q).when(mPermissionMonitor).getDeviceFirstSdkInt(); assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID)); assertFalse(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, CHANGE_WIFI_STATE)); assertTrue(hasBgPermission(PARTITION_SYSTEM, VERSION_Q, SYSTEM_UID, |