diff options
242 files changed, 4356 insertions, 3418 deletions
diff --git a/Android.bp b/Android.bp index 07b301867129..759014ffc936 100644 --- a/Android.bp +++ b/Android.bp @@ -1179,6 +1179,48 @@ doc_defaults { create_stubs: false, } +metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.xml) " + + "--hide-package com.android.okhttp " + + "--hide-package com.android.org.conscrypt --hide-package com.android.server " + + "--hide RequiresPermission " + + "--hide MissingPermission --hide BroadcastBehavior " + + "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " + + "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo" + +doc_defaults { + name: "metalava-api-stubs-default", + srcs: [ + ":opt-telephony-srcs", + ":opt-net-voip-srcs", + ":openjdk_javadoc_files", + ":non_openjdk_javadoc_files", + ":android_icu4j_src_files_for_docs", + ], + srcs_lib: "framework", + srcs_lib_whitelist_dirs: frameworks_base_subdirs, + srcs_lib_whitelist_pkgs: packages_to_document, + libs: [ + "core-oj", + "core-libart", + "conscrypt", + "bouncycastle", + "okhttp", + "ext", + "framework", + "voip-common", + "android.test.mock.impl", + ], + local_sourcepaths: frameworks_base_subdirs, + installable: false, + metalava_enabled: true, + metalava_annotations_enabled: true, + metalava_previous_api: ":last-released-public-api", + metalava_merge_annotations_dirs: [ + "metalava-manual", + "ojluni-annotated-stubs", + ], +} + droiddoc { name: "doc-comment-check-docs", defaults: ["framework-docs-default"], @@ -1406,26 +1448,21 @@ java_library_static { } droiddoc { - name: "hiddenapi-lists", - defaults: ["api-stubs-default"], + name: "hiddenapi-lists-docs", + defaults: ["metalava-api-stubs-default"], arg_files: [ "core/res/AndroidManifest.xml", - ":api-version-xml", - "core/java/overview.html", - ":current-support-api", - "api/current.txt", ], dex_api_filename: "public-dex.txt", private_dex_api_filename: "private-dex.txt", removed_dex_api_filename: "removed-dex.txt", - args: framework_docs_args + - " -referenceonly" + - " -nodocs" + - " -showUnannotated" + - " -showAnnotation android.annotation.SystemApi" + - " -showAnnotation android.annotation.TestApi", + args: metalava_framework_docs_args + + " --show-unannotated " + + " --show-annotation android.annotation.SystemApi " + + " --show-annotation android.annotation.TestApi " } + droiddoc { name: "hiddenapi-mappings", defaults: ["api-stubs-default"], @@ -1469,48 +1506,6 @@ filegroup { ], } -metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.xml) " + - "--hide-package com.android.okhttp " + - "--hide-package com.android.org.conscrypt --hide-package com.android.server " + - "--hide RequiresPermission " + - "--hide MissingPermission --hide BroadcastBehavior " + - "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " + - "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo" - -doc_defaults { - name: "metalava-api-stubs-default", - srcs: [ - ":opt-telephony-srcs", - ":opt-net-voip-srcs", - ":openjdk_javadoc_files", - ":non_openjdk_javadoc_files", - ":android_icu4j_src_files_for_docs", - ], - srcs_lib: "framework", - srcs_lib_whitelist_dirs: frameworks_base_subdirs, - srcs_lib_whitelist_pkgs: packages_to_document, - libs: [ - "core-oj", - "core-libart", - "conscrypt", - "bouncycastle", - "okhttp", - "ext", - "framework", - "voip-common", - "android.test.mock.impl", - ], - local_sourcepaths: frameworks_base_subdirs, - installable: false, - metalava_enabled: true, - metalava_annotations_enabled: true, - metalava_previous_api: ":last-released-public-api", - metalava_merge_annotations_dirs: [ - "metalava-manual", - "ojluni-annotated-stubs", - ], -} - droiddoc { name: "api-stubs-docs", defaults: ["metalava-api-stubs-default"], diff --git a/api/current.txt b/api/current.txt index 3a523f663670..4d692eee1dd3 100644 --- a/api/current.txt +++ b/api/current.txt @@ -8713,6 +8713,8 @@ package android.bluetooth.le { method public byte[] getServiceData(); method public byte[] getServiceDataMask(); method public android.os.ParcelUuid getServiceDataUuid(); + method public android.os.ParcelUuid getServiceSolicitationUuid(); + method public android.os.ParcelUuid getServiceSolicitationUuidMask(); method public android.os.ParcelUuid getServiceUuid(); method public android.os.ParcelUuid getServiceUuidMask(); method public boolean matches(android.bluetooth.le.ScanResult); @@ -8729,6 +8731,8 @@ package android.bluetooth.le { method public android.bluetooth.le.ScanFilter.Builder setManufacturerData(int, byte[], byte[]); method public android.bluetooth.le.ScanFilter.Builder setServiceData(android.os.ParcelUuid, byte[]); method public android.bluetooth.le.ScanFilter.Builder setServiceData(android.os.ParcelUuid, byte[], byte[]); + method public android.bluetooth.le.ScanFilter.Builder setServiceSolicitationUuid(android.os.ParcelUuid); + method public android.bluetooth.le.ScanFilter.Builder setServiceSolicitationUuid(android.os.ParcelUuid, android.os.ParcelUuid); method public android.bluetooth.le.ScanFilter.Builder setServiceUuid(android.os.ParcelUuid); method public android.bluetooth.le.ScanFilter.Builder setServiceUuid(android.os.ParcelUuid, android.os.ParcelUuid); } @@ -8741,6 +8745,7 @@ package android.bluetooth.le { method public byte[] getManufacturerSpecificData(int); method public java.util.Map<android.os.ParcelUuid, byte[]> getServiceData(); method public byte[] getServiceData(android.os.ParcelUuid); + method public java.util.List<android.os.ParcelUuid> getServiceSolicitationUuids(); method public java.util.List<android.os.ParcelUuid> getServiceUuids(); method public int getTxPowerLevel(); } diff --git a/api/system-current.txt b/api/system-current.txt index 416835358e18..3d8c49440a96 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4542,11 +4542,9 @@ package android.service.autofill { public abstract class AutofillFieldClassificationService extends android.app.Service { method public android.os.IBinder onBind(android.content.Intent); method public float[][] onGetScores(java.lang.String, android.os.Bundle, java.util.List<android.view.autofill.AutofillValue>, java.util.List<java.lang.String>); - field public static final java.lang.String RESOURCE_AVAILABLE_ALGORITHMS = "autofill_field_classification_available_algorithms"; - field public static final java.lang.String RESOURCE_DEFAULT_ALGORITHM = "autofill_field_classification_default_algorithm"; field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutofillFieldClassificationService"; - field public static final deprecated java.lang.String SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS = "android.autofill.field_classification.available_algorithms"; - field public static final deprecated java.lang.String SERVICE_META_DATA_KEY_DEFAULT_ALGORITHM = "android.autofill.field_classification.default_algorithm"; + field public static final java.lang.String SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS = "android.autofill.field_classification.available_algorithms"; + field public static final java.lang.String SERVICE_META_DATA_KEY_DEFAULT_ALGORITHM = "android.autofill.field_classification.default_algorithm"; } } diff --git a/api/test-current.txt b/api/test-current.txt index 7947ed997331..3a9d6a4c5e5b 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -335,6 +335,10 @@ package android.content.res { package android.database.sqlite { + public class SQLiteCompatibilityWalFlags { + method public static void reset(); + } + public final class SQLiteDebug { method public static void dump(android.util.Printer, java.lang.String[]); method public static android.database.sqlite.SQLiteDebug.PagerStats getDatabaseInfo(); diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index f27f7fb9fc0a..6065bbfc3f90 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -151,16 +151,12 @@ message Atom { SystemUptime system_uptime = 10015; CpuActiveTime cpu_active_time = 10016; CpuClusterTime cpu_cluster_time = 10017; - DiskSpace disk_space = 10018 [deprecated=true]; + DiskSpace disk_space = 10018; RemainingBatteryCapacity remaining_battery_capacity = 10019; FullBatteryCapacity full_battery_capacity = 10020; Temperature temperature = 10021; BinderCalls binder_calls = 10022; BinderCallsExceptions binder_calls_exceptions = 10023; - DiskStats disk_stats = 10024; - DirectoryUsage directory_usage = 10025; - AppSize app_size = 10026; - CategorySize category_size = 10027; } // DO NOT USE field numbers above 100,000 in AOSP. Field numbers above @@ -2186,83 +2182,3 @@ message BinderCallsExceptions { // Total number of exceptions. optional int64 exception_count = 2; } - - -/** - * Pulls disk information, such as write speed and latency. - */ -message DiskStats { - // Time taken to open, write 512B to, and close a file. - // -1 if error performing the check. - optional int64 data_write_latency_millis = 1; - - optional bool file_based_encryption = 2; - - // Recent disk write speed in kB/s. - // -1 if error querying storageed. - // 0 if data is unavailable. - optional int32 recent_disk_write_speed = 3; -} - - -/** - * Free and total bytes of the Data, Cache, and System partition. - */ -message DirectoryUsage { - enum Directory { - UNKNOWN = 0; - DATA = 1; - CACHE = 2; - SYSTEM = 3; - } - optional Directory directory = 1; - optional int64 free_bytes = 2; - optional int64 total_bytes = 3; -} - - -/** - * Size of an application: apk size, data size, and cache size. - * Reads from a cached file produced daily by DiskStatsLoggingService.java. - * Information is only reported for apps with the primary user (user 0). - * Sizes are aggregated by package name. - */ -message AppSize { - // Including uids will involve modifying diskstats logic. - optional string package_name = 1; - // App size in bytes. -1 if unavailable. - optional int64 app_size_bytes = 2; - // App data size in bytes. -1 if unavailable. - optional int64 app_data_size_bytes = 3; - // App cache size in bytes. -1 if unavailable. - optional int64 app_cache_size_bytes = 4; - // Time that the cache file was produced. - // Uses System.currentTimeMillis(), which is wall clock time. - optional int64 cache_time_millis = 5; -} - - -/** - * Size of a particular category. Eg: photos, videos. - * Reads from a cached file produced daily by DiskStatsLoggingService.java. - */ -message CategorySize { - enum Category { - UNKNOWN = 0; - APP_SIZE = 1; - APP_DATA_SIZE = 2; - APP_CACHE_SIZE = 3; - PHOTOS = 4; - VIDEOS = 5; - AUDIO = 6; - DOWNLOADS = 7; - SYSTEM = 8; - OTHER = 9; - } - optional Category category = 1; - // Category size in bytes. - optional int64 size_bytes = 2; - // Time that the cache file was produced. - // Uses System.currentTimeMillis(), which is wall clock time. - optional int64 cache_time_millis = 3; -} diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp index 95510f54f974..e6e84550cf5f 100644 --- a/cmds/statsd/src/external/StatsPullerManager.cpp +++ b/cmds/statsd/src/external/StatsPullerManager.cpp @@ -149,6 +149,9 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { // system_uptime {android::util::SYSTEM_UPTIME, {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::SYSTEM_UPTIME)}}, + // disk_space + {android::util::DISK_SPACE, + {{}, {}, 1 * NS_PER_SEC, new StatsCompanionServicePuller(android::util::DISK_SPACE)}}, // remaining_battery_capacity {android::util::REMAINING_BATTERY_CAPACITY, {{}, @@ -180,31 +183,7 @@ const std::map<int, PullAtomInfo> StatsPullerManager::kAllPullAtomInfo = { {{}, {}, 1 * NS_PER_SEC, - new StatsCompanionServicePuller(android::util::BINDER_CALLS_EXCEPTIONS)}}, - // Disk Stats - {android::util::DISK_STATS, - {{}, - {}, - 1 * NS_PER_SEC, - new StatsCompanionServicePuller(android::util::DISK_STATS)}}, - // Directory usage - {android::util::DIRECTORY_USAGE, - {{}, - {}, - 1 * NS_PER_SEC, - new StatsCompanionServicePuller(android::util::DIRECTORY_USAGE)}}, - // Size of app's code, data, and cache - {android::util::APP_SIZE, - {{}, - {}, - 1 * NS_PER_SEC, - new StatsCompanionServicePuller(android::util::APP_SIZE)}}, - // Size of specific categories of files. Eg. Music. - {android::util::CATEGORY_SIZE, - {{}, - {}, - 1 * NS_PER_SEC, - new StatsCompanionServicePuller(android::util::CATEGORY_SIZE)}}, + new StatsCompanionServicePuller(android::util::BINDER_CALLS_EXCEPTIONS)}} }; StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) { diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt index 65a0a4b9930b..6f06edc0b911 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -2172,47 +2172,7 @@ Lcom/android/internal/statusbar/IStatusBarService;->removeIcon(Ljava/lang/String Lcom/android/internal/statusbar/IStatusBarService;->setIconVisibility(Ljava/lang/String;Z)V Lcom/android/internal/telecom/ITelecomService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telecom/ITelecomService; Lcom/android/internal/telecom/ITelecomService;->getCallState()I -Lcom/android/internal/telephony/CallerInfo;-><init>()V -Lcom/android/internal/telephony/CallerInfo;->contactIdOrZero:J -Lcom/android/internal/telephony/CallerInfo;->getCallerInfo(Landroid/content/Context;Landroid/net/Uri;)Lcom/android/internal/telephony/CallerInfo; -Lcom/android/internal/telephony/CallerInfo;->getCallerInfo(Landroid/content/Context;Ljava/lang/String;)Lcom/android/internal/telephony/CallerInfo; -Lcom/android/internal/telephony/CallerInfo;->getCallerInfo(Landroid/content/Context;Ljava/lang/String;I)Lcom/android/internal/telephony/CallerInfo; -Lcom/android/internal/telephony/CallerInfo;->name:Ljava/lang/String; -Lcom/android/internal/telephony/CallerInfo;->numberLabel:Ljava/lang/String; -Lcom/android/internal/telephony/CallerInfo;->numberType:I -Lcom/android/internal/telephony/CallerInfo;->phoneNumber:Ljava/lang/String; -Lcom/android/internal/telephony/EncodeException;-><init>(C)V -Lcom/android/internal/telephony/EncodeException;-><init>(Ljava/lang/String;)V -Lcom/android/internal/telephony/GsmAlphabet$LanguagePairCount;-><init>(I)V -Lcom/android/internal/telephony/GsmAlphabet$LanguagePairCount;->languageCode:I -Lcom/android/internal/telephony/GsmAlphabet$LanguagePairCount;->septetCounts:[I -Lcom/android/internal/telephony/GsmAlphabet$LanguagePairCount;->unencodableCounts:[I Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails;-><init>()V -Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails;->codeUnitCount:I -Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails;->codeUnitSize:I -Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails;->codeUnitsRemaining:I -Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails;->languageShiftTable:I -Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails;->languageTable:I -Lcom/android/internal/telephony/GsmAlphabet$TextEncodingDetails;->msgCount:I -Lcom/android/internal/telephony/GsmAlphabet;->charToGsm(C)I -Lcom/android/internal/telephony/GsmAlphabet;->charToGsm(CZ)I -Lcom/android/internal/telephony/GsmAlphabet;->countGsmSeptets(CZ)I -Lcom/android/internal/telephony/GsmAlphabet;->findGsmSeptetLimitIndex(Ljava/lang/String;IIII)I -Lcom/android/internal/telephony/GsmAlphabet;->gsm7BitPackedToString([BIIIII)Ljava/lang/String; -Lcom/android/internal/telephony/GsmAlphabet;->gsm8BitUnpackedToString([BII)Ljava/lang/String; -Lcom/android/internal/telephony/GsmAlphabet;->gsm8BitUnpackedToString([BIILjava/lang/String;)Ljava/lang/String; -Lcom/android/internal/telephony/GsmAlphabet;->gsmToChar(I)C -Lcom/android/internal/telephony/GsmAlphabet;->packSmsChar([BII)V -Lcom/android/internal/telephony/GsmAlphabet;->sCharsToGsmTables:[Landroid/util/SparseIntArray; -Lcom/android/internal/telephony/GsmAlphabet;->sCharsToShiftTables:[Landroid/util/SparseIntArray; -Lcom/android/internal/telephony/GsmAlphabet;->sEnabledLockingShiftTables:[I -Lcom/android/internal/telephony/GsmAlphabet;->sEnabledSingleShiftTables:[I -Lcom/android/internal/telephony/GsmAlphabet;->sHighestEnabledSingleShiftCode:I -Lcom/android/internal/telephony/GsmAlphabet;->sLanguageShiftTables:[Ljava/lang/String; -Lcom/android/internal/telephony/GsmAlphabet;->sLanguageTables:[Ljava/lang/String; -Lcom/android/internal/telephony/GsmAlphabet;->stringToGsm7BitPacked(Ljava/lang/String;IZII)[B -Lcom/android/internal/telephony/GsmAlphabet;->stringToGsm7BitPackedWithHeader(Ljava/lang/String;[BII)[B -Lcom/android/internal/telephony/GsmAlphabet;->stringToGsm8BitPacked(Ljava/lang/String;)[B Lcom/android/internal/telephony/ICarrierConfigLoader;->getConfigForSubId(ILjava/lang/String;)Landroid/os/PersistableBundle; Lcom/android/internal/telephony/IMms$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IMms; Lcom/android/internal/telephony/IPhoneStateListener$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IPhoneStateListener; @@ -2287,67 +2247,13 @@ Lcom/android/internal/telephony/IWapPushManager$Stub;->asInterface(Landroid/os/I Lcom/android/internal/telephony/IWapPushManager;->addPackage(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IZZ)Z Lcom/android/internal/telephony/IWapPushManager;->deletePackage(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z Lcom/android/internal/telephony/IWapPushManager;->updatePackage(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;IZZ)Z -Lcom/android/internal/telephony/OperatorInfo;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V -Lcom/android/internal/telephony/OperatorInfo;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/android/internal/telephony/OperatorInfo$State;)V -Lcom/android/internal/telephony/OperatorInfo;->mOperatorAlphaLong:Ljava/lang/String; -Lcom/android/internal/telephony/OperatorInfo;->mOperatorAlphaShort:Ljava/lang/String; -Lcom/android/internal/telephony/OperatorInfo;->mOperatorNumeric:Ljava/lang/String; -Lcom/android/internal/telephony/OperatorInfo;->mState:Lcom/android/internal/telephony/OperatorInfo$State; -Lcom/android/internal/telephony/OperatorInfo;->rilStateToState(Ljava/lang/String;)Lcom/android/internal/telephony/OperatorInfo$State; -Lcom/android/internal/telephony/SmsAddress;->origBytes:[B -Lcom/android/internal/telephony/SmsConstants$MessageClass;->CLASS_0:Lcom/android/internal/telephony/SmsConstants$MessageClass; -Lcom/android/internal/telephony/SmsConstants$MessageClass;->CLASS_1:Lcom/android/internal/telephony/SmsConstants$MessageClass; -Lcom/android/internal/telephony/SmsConstants$MessageClass;->CLASS_2:Lcom/android/internal/telephony/SmsConstants$MessageClass; -Lcom/android/internal/telephony/SmsConstants$MessageClass;->CLASS_3:Lcom/android/internal/telephony/SmsConstants$MessageClass; -Lcom/android/internal/telephony/SmsConstants$MessageClass;->UNKNOWN:Lcom/android/internal/telephony/SmsConstants$MessageClass; Lcom/android/internal/telephony/SmsHeader$ConcatRef;-><init>()V -Lcom/android/internal/telephony/SmsHeader$ConcatRef;->msgCount:I -Lcom/android/internal/telephony/SmsHeader$ConcatRef;->refNumber:I -Lcom/android/internal/telephony/SmsHeader$ConcatRef;->seqNumber:I Lcom/android/internal/telephony/SmsHeader$PortAddrs;-><init>()V -Lcom/android/internal/telephony/SmsHeader$PortAddrs;->destPort:I -Lcom/android/internal/telephony/SmsHeader$PortAddrs;->origPort:I -Lcom/android/internal/telephony/SmsHeader;-><init>()V -Lcom/android/internal/telephony/SmsHeader;->concatRef:Lcom/android/internal/telephony/SmsHeader$ConcatRef; -Lcom/android/internal/telephony/SmsHeader;->fromByteArray([B)Lcom/android/internal/telephony/SmsHeader; -Lcom/android/internal/telephony/SmsHeader;->languageShiftTable:I -Lcom/android/internal/telephony/SmsHeader;->languageTable:I -Lcom/android/internal/telephony/SmsHeader;->portAddrs:Lcom/android/internal/telephony/SmsHeader$PortAddrs; -Lcom/android/internal/telephony/SmsHeader;->toByteArray(Lcom/android/internal/telephony/SmsHeader;)[B -Lcom/android/internal/telephony/SmsMessageBase$SubmitPduBase;->encodedMessage:[B -Lcom/android/internal/telephony/SmsMessageBase$SubmitPduBase;->encodedScAddress:[B Lcom/android/internal/telephony/SmsMessageBase;-><init>()V -Lcom/android/internal/telephony/SmsMessageBase;->getDisplayMessageBody()Ljava/lang/String; -Lcom/android/internal/telephony/SmsMessageBase;->getDisplayOriginatingAddress()Ljava/lang/String; -Lcom/android/internal/telephony/SmsMessageBase;->getMessageBody()Ljava/lang/String; -Lcom/android/internal/telephony/SmsMessageBase;->getOriginatingAddress()Ljava/lang/String; -Lcom/android/internal/telephony/SmsMessageBase;->getProtocolIdentifier()I -Lcom/android/internal/telephony/SmsMessageBase;->getPseudoSubject()Ljava/lang/String; -Lcom/android/internal/telephony/SmsMessageBase;->getServiceCenterAddress()Ljava/lang/String; -Lcom/android/internal/telephony/SmsMessageBase;->getStatus()I -Lcom/android/internal/telephony/SmsMessageBase;->getTimestampMillis()J -Lcom/android/internal/telephony/SmsMessageBase;->getUserData()[B -Lcom/android/internal/telephony/SmsMessageBase;->getUserDataHeader()Lcom/android/internal/telephony/SmsHeader; -Lcom/android/internal/telephony/SmsMessageBase;->isReplace()Z -Lcom/android/internal/telephony/SmsMessageBase;->isReplyPathPresent()Z -Lcom/android/internal/telephony/SmsMessageBase;->isStatusReportMessage()Z -Lcom/android/internal/telephony/SmsMessageBase;->mIsMwi:Z -Lcom/android/internal/telephony/SmsMessageBase;->mMessageBody:Ljava/lang/String; -Lcom/android/internal/telephony/SmsMessageBase;->mMessageRef:I -Lcom/android/internal/telephony/SmsMessageBase;->mMwiDontStore:Z -Lcom/android/internal/telephony/SmsMessageBase;->mMwiSense:Z -Lcom/android/internal/telephony/SmsMessageBase;->mOriginatingAddress:Lcom/android/internal/telephony/SmsAddress; -Lcom/android/internal/telephony/SmsMessageBase;->mPdu:[B -Lcom/android/internal/telephony/SmsMessageBase;->mScAddress:Ljava/lang/String; -Lcom/android/internal/telephony/SmsMessageBase;->mUserDataHeader:Lcom/android/internal/telephony/SmsHeader; -Lcom/android/internal/telephony/SmsRawData;-><init>([B)V -Lcom/android/internal/telephony/SmsRawData;->CREATOR:Landroid/os/Parcelable$Creator; -Lcom/android/internal/telephony/SmsRawData;->getBytes()[B Lcom/android/internal/textservice/ITextServicesManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V Lcom/android/internal/util/HexDump;->toHexString([BZ)Ljava/lang/String; Lcom/android/internal/view/BaseIWindow;-><init>()V Lcom/android/internal/view/IInputMethodManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V -Lcom/android/internal/view/IInputMethodManager$Stub$Proxy;->getEnabledInputMethodList()Ljava/util/List; Lcom/android/internal/view/IInputMethodManager$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethodManager; Lcom/android/internal/view/IInputMethodSession$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/view/IInputMethodSession; Lcom/android/internal/widget/ILockSettings$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/widget/ILockSettings; diff --git a/config/hiddenapi-vendor-list.txt b/config/hiddenapi-vendor-list.txt index 9e6abe425d3e..54cc07a878ed 100644 --- a/config/hiddenapi-vendor-list.txt +++ b/config/hiddenapi-vendor-list.txt @@ -260,17 +260,7 @@ Lcom/android/internal/location/ILocationProvider;->sendExtraCommand(Ljava/lang/S Lcom/android/internal/location/ILocationProvider;->setRequest(Lcom/android/internal/location/ProviderRequest;Landroid/os/WorkSource;)V Lcom/android/internal/R$styleable;->NumberPicker:[I Lcom/android/internal/R$styleable;->TwoLineListItem:[I -Lcom/android/internal/telephony/GsmAlphabet;->gsm7BitPackedToString([BII)Ljava/lang/String; -Lcom/android/internal/telephony/GsmAlphabet;->stringToGsm7BitPacked(Ljava/lang/String;)[B Lcom/android/internal/telephony/ITelephony;->getDataEnabled(I)Z -Lcom/android/internal/telephony/OperatorInfo$State;->CURRENT:Lcom/android/internal/telephony/OperatorInfo$State; -Lcom/android/internal/telephony/OperatorInfo$State;->FORBIDDEN:Lcom/android/internal/telephony/OperatorInfo$State; -Lcom/android/internal/telephony/OperatorInfo;-><init>(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V -Lcom/android/internal/telephony/OperatorInfo;->CREATOR:Landroid/os/Parcelable$Creator; -Lcom/android/internal/telephony/OperatorInfo;->getOperatorAlphaLong()Ljava/lang/String; -Lcom/android/internal/telephony/OperatorInfo;->getOperatorAlphaShort()Ljava/lang/String; -Lcom/android/internal/telephony/OperatorInfo;->getOperatorNumeric()Ljava/lang/String; -Lcom/android/internal/telephony/OperatorInfo;->getState()Lcom/android/internal/telephony/OperatorInfo$State; Ljava/lang/System;->arraycopy([BI[BII)V Ljava/net/Inet4Address;->ALL:Ljava/net/InetAddress; Ljava/net/Inet4Address;->ANY:Ljava/net/InetAddress; diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java index c3fae7d470a3..c5d435b76139 100644 --- a/core/java/android/bluetooth/le/ScanFilter.java +++ b/core/java/android/bluetooth/le/ScanFilter.java @@ -58,6 +58,11 @@ public final class ScanFilter implements Parcelable { private final ParcelUuid mServiceUuidMask; @Nullable + private final ParcelUuid mServiceSolicitationUuid; + @Nullable + private final ParcelUuid mServiceSolicitationUuidMask; + + @Nullable private final ParcelUuid mServiceDataUuid; @Nullable private final byte[] mServiceData; @@ -75,12 +80,15 @@ public final class ScanFilter implements Parcelable { private ScanFilter(String name, String deviceAddress, ParcelUuid uuid, - ParcelUuid uuidMask, ParcelUuid serviceDataUuid, + ParcelUuid uuidMask, ParcelUuid solicitationUuid, + ParcelUuid solicitationUuidMask, ParcelUuid serviceDataUuid, byte[] serviceData, byte[] serviceDataMask, int manufacturerId, byte[] manufacturerData, byte[] manufacturerDataMask) { mDeviceName = name; mServiceUuid = uuid; mServiceUuidMask = uuidMask; + mServiceSolicitationUuid = solicitationUuid; + mServiceSolicitationUuidMask = solicitationUuidMask; mDeviceAddress = deviceAddress; mServiceDataUuid = serviceDataUuid; mServiceData = serviceData; @@ -113,6 +121,14 @@ public final class ScanFilter implements Parcelable { dest.writeParcelable(mServiceUuidMask, flags); } } + dest.writeInt(mServiceSolicitationUuid == null ? 0 : 1); + if (mServiceSolicitationUuid != null) { + dest.writeParcelable(mServiceSolicitationUuid, flags); + dest.writeInt(mServiceSolicitationUuidMask == null ? 0 : 1); + if (mServiceSolicitationUuidMask != null) { + dest.writeParcelable(mServiceSolicitationUuidMask, flags); + } + } dest.writeInt(mServiceDataUuid == null ? 0 : 1); if (mServiceDataUuid != null) { dest.writeParcelable(mServiceDataUuid, flags); @@ -172,6 +188,17 @@ public final class ScanFilter implements Parcelable { } } if (in.readInt() == 1) { + ParcelUuid solicitationUuid = in.readParcelable( + ParcelUuid.class.getClassLoader()); + builder.setServiceSolicitationUuid(solicitationUuid); + if (in.readInt() == 1) { + ParcelUuid solicitationUuidMask = in.readParcelable( + ParcelUuid.class.getClassLoader()); + builder.setServiceSolicitationUuid(solicitationUuid, + solicitationUuidMask); + } + } + if (in.readInt() == 1) { ParcelUuid servcieDataUuid = in.readParcelable(ParcelUuid.class.getClassLoader()); if (in.readInt() == 1) { @@ -231,6 +258,22 @@ public final class ScanFilter implements Parcelable { return mServiceUuidMask; } + /** + * Returns the filter set on the service Solicitation uuid. + */ + @Nullable + public ParcelUuid getServiceSolicitationUuid() { + return mServiceSolicitationUuid; + } + + /** + * Returns the filter set on the service Solicitation uuid mask. + */ + @Nullable + public ParcelUuid getServiceSolicitationUuidMask() { + return mServiceSolicitationUuidMask; + } + @Nullable public String getDeviceAddress() { return mDeviceAddress; @@ -288,7 +331,7 @@ public final class ScanFilter implements Parcelable { // Scan record is null but there exist filters on it. if (scanRecord == null && (mDeviceName != null || mServiceUuid != null || mManufacturerData != null - || mServiceData != null)) { + || mServiceData != null || mServiceSolicitationUuid != null)) { return false; } @@ -303,6 +346,13 @@ public final class ScanFilter implements Parcelable { return false; } + // solicitation UUID match. + if (mServiceSolicitationUuid != null && !matchesServiceSolicitationUuids( + mServiceSolicitationUuid, mServiceSolicitationUuidMask, + scanRecord.getServiceSolicitationUuids())) { + return false; + } + // Service data match if (mServiceDataUuid != null) { if (!matchesPartialData(mServiceData, mServiceDataMask, @@ -350,6 +400,36 @@ public final class ScanFilter implements Parcelable { return BitUtils.maskedEquals(data, uuid, mask); } + /** + * Check if the solicitation uuid pattern is contained in a list of parcel uuids. + * + */ + private static boolean matchesServiceSolicitationUuids(ParcelUuid solicitationUuid, + ParcelUuid parcelSolicitationUuidMask, List<ParcelUuid> solicitationUuids) { + if (solicitationUuid == null) { + return true; + } + if (solicitationUuids == null) { + return false; + } + + for (ParcelUuid parcelSolicitationUuid : solicitationUuids) { + UUID solicitationUuidMask = parcelSolicitationUuidMask == null + ? null : parcelSolicitationUuidMask.getUuid(); + if (matchesServiceUuid(solicitationUuid.getUuid(), solicitationUuidMask, + parcelSolicitationUuid.getUuid())) { + return true; + } + } + return false; + } + + // Check if the solicitation uuid pattern matches the particular service solicitation uuid. + private static boolean matchesServiceSolicitationUuid(UUID solicitationUuid, + UUID solicitationUuidMask, UUID data) { + return BitUtils.maskedEquals(data, solicitationUuid, solicitationUuidMask); + } + // Check whether the data pattern matches the parsed data. private boolean matchesPartialData(byte[] data, byte[] dataMask, byte[] parsedData) { if (parsedData == null || parsedData.length < data.length) { @@ -376,6 +456,8 @@ public final class ScanFilter implements Parcelable { return "BluetoothLeScanFilter [mDeviceName=" + mDeviceName + ", mDeviceAddress=" + mDeviceAddress + ", mUuid=" + mServiceUuid + ", mUuidMask=" + mServiceUuidMask + + ", mServiceSolicitationUuid=" + mServiceSolicitationUuid + + ", mServiceSolicitationUuidMask=" + mServiceSolicitationUuidMask + ", mServiceDataUuid=" + Objects.toString(mServiceDataUuid) + ", mServiceData=" + Arrays.toString(mServiceData) + ", mServiceDataMask=" + Arrays.toString(mServiceDataMask) + ", mManufacturerId=" + mManufacturerId @@ -391,7 +473,8 @@ public final class ScanFilter implements Parcelable { mServiceDataUuid, Arrays.hashCode(mServiceData), Arrays.hashCode(mServiceDataMask), - mServiceUuid, mServiceUuidMask); + mServiceUuid, mServiceUuidMask, + mServiceSolicitationUuid, mServiceSolicitationUuidMask); } @Override @@ -412,7 +495,10 @@ public final class ScanFilter implements Parcelable { && Objects.deepEquals(mServiceData, other.mServiceData) && Objects.deepEquals(mServiceDataMask, other.mServiceDataMask) && Objects.equals(mServiceUuid, other.mServiceUuid) - && Objects.equals(mServiceUuidMask, other.mServiceUuidMask); + && Objects.equals(mServiceUuidMask, other.mServiceUuidMask) + && Objects.equals(mServiceSolicitationUuid, other.mServiceSolicitationUuid) + && Objects.equals(mServiceSolicitationUuidMask, + other.mServiceSolicitationUuidMask); } /** @@ -435,6 +521,9 @@ public final class ScanFilter implements Parcelable { private ParcelUuid mServiceUuid; private ParcelUuid mUuidMask; + private ParcelUuid mServiceSolicitationUuid; + private ParcelUuid mServiceSolicitationUuidMask; + private ParcelUuid mServiceDataUuid; private byte[] mServiceData; private byte[] mServiceDataMask; @@ -493,6 +582,36 @@ public final class ScanFilter implements Parcelable { return this; } + + /** + * Set filter on service solicitation uuid. + */ + public Builder setServiceSolicitationUuid(ParcelUuid serviceSolicitationUuid) { + mServiceSolicitationUuid = serviceSolicitationUuid; + return this; + } + + + /** + * Set filter on partial service Solicitation uuid. The {@code SolicitationUuidMask} is the + * bit mask for the {@code serviceSolicitationUuid}. Set any bit in the mask to 1 to + * indicate a match is needed for the bit in {@code serviceSolicitationUuid}, and 0 to + * ignore that bit. + * + * @throws IllegalArgumentException If {@code serviceSolicitationUuid} is {@code null} but + * {@code serviceSolicitationUuidMask} is not {@code null}. + */ + public Builder setServiceSolicitationUuid(ParcelUuid serviceSolicitationUuid, + ParcelUuid solicitationUuidMask) { + if (mServiceSolicitationUuidMask != null && mServiceSolicitationUuid == null) { + throw new IllegalArgumentException( + "SolicitationUuid is null while SolicitationUuidMask is not null!"); + } + mServiceSolicitationUuid = serviceSolicitationUuid; + mServiceSolicitationUuidMask = solicitationUuidMask; + return this; + } + /** * Set filtering on service data. * @@ -598,7 +717,8 @@ public final class ScanFilter implements Parcelable { */ public ScanFilter build() { return new ScanFilter(mDeviceName, mDeviceAddress, - mServiceUuid, mUuidMask, + mServiceUuid, mUuidMask, mServiceSolicitationUuid, + mServiceSolicitationUuidMask, mServiceDataUuid, mServiceData, mServiceDataMask, mManufacturerId, mManufacturerData, mManufacturerDataMask); } diff --git a/core/java/android/bluetooth/le/ScanRecord.java b/core/java/android/bluetooth/le/ScanRecord.java index 07ed18d90ee6..7988008f03c0 100644 --- a/core/java/android/bluetooth/le/ScanRecord.java +++ b/core/java/android/bluetooth/le/ScanRecord.java @@ -51,6 +51,9 @@ public final class ScanRecord { private static final int DATA_TYPE_SERVICE_DATA_16_BIT = 0x16; private static final int DATA_TYPE_SERVICE_DATA_32_BIT = 0x20; private static final int DATA_TYPE_SERVICE_DATA_128_BIT = 0x21; + private static final int DATA_TYPE_SERVICE_SOLICITATION_UUIDS_16_BIT = 0x14; + private static final int DATA_TYPE_SERVICE_SOLICITATION_UUIDS_32_BIT = 0x1F; + private static final int DATA_TYPE_SERVICE_SOLICITATION_UUIDS_128_BIT = 0x15; private static final int DATA_TYPE_MANUFACTURER_SPECIFIC_DATA = 0xFF; // Flags of the advertising data. @@ -58,6 +61,8 @@ public final class ScanRecord { @Nullable private final List<ParcelUuid> mServiceUuids; + @Nullable + private final List<ParcelUuid> mServiceSolicitationUuids; private final SparseArray<byte[]> mManufacturerSpecificData; @@ -89,6 +94,15 @@ public final class ScanRecord { } /** + * Returns a list of service solicitation UUIDs within the advertisement that are used to + * identify the Bluetooth GATT services. + */ + @Nullable + public List<ParcelUuid> getServiceSolicitationUuids() { + return mServiceSolicitationUuids; + } + + /** * Returns a sparse array of manufacturer identifier and its corresponding manufacturer specific * data. */ @@ -151,10 +165,12 @@ public final class ScanRecord { } private ScanRecord(List<ParcelUuid> serviceUuids, + List<ParcelUuid> serviceSolicitationUuids, SparseArray<byte[]> manufacturerData, Map<ParcelUuid, byte[]> serviceData, int advertiseFlags, int txPowerLevel, String localName, byte[] bytes) { + mServiceSolicitationUuids = serviceSolicitationUuids; mServiceUuids = serviceUuids; mManufacturerSpecificData = manufacturerData; mServiceData = serviceData; @@ -184,6 +200,7 @@ public final class ScanRecord { int currentPos = 0; int advertiseFlag = -1; List<ParcelUuid> serviceUuids = new ArrayList<ParcelUuid>(); + List<ParcelUuid> serviceSolicitationUuids = new ArrayList<ParcelUuid>(); String localName = null; int txPowerLevel = Integer.MIN_VALUE; @@ -220,6 +237,18 @@ public final class ScanRecord { parseServiceUuid(scanRecord, currentPos, dataLength, BluetoothUuid.UUID_BYTES_128_BIT, serviceUuids); break; + case DATA_TYPE_SERVICE_SOLICITATION_UUIDS_16_BIT: + parseServiceSolicitationUuid(scanRecord, currentPos, dataLength, + BluetoothUuid.UUID_BYTES_16_BIT, serviceSolicitationUuids); + break; + case DATA_TYPE_SERVICE_SOLICITATION_UUIDS_32_BIT: + parseServiceSolicitationUuid(scanRecord, currentPos, dataLength, + BluetoothUuid.UUID_BYTES_32_BIT, serviceSolicitationUuids); + break; + case DATA_TYPE_SERVICE_SOLICITATION_UUIDS_128_BIT: + parseServiceSolicitationUuid(scanRecord, currentPos, dataLength, + BluetoothUuid.UUID_BYTES_128_BIT, serviceSolicitationUuids); + break; case DATA_TYPE_LOCAL_NAME_SHORT: case DATA_TYPE_LOCAL_NAME_COMPLETE: localName = new String( @@ -265,19 +294,23 @@ public final class ScanRecord { if (serviceUuids.isEmpty()) { serviceUuids = null; } - return new ScanRecord(serviceUuids, manufacturerData, serviceData, - advertiseFlag, txPowerLevel, localName, scanRecord); + if (serviceSolicitationUuids.isEmpty()) { + serviceSolicitationUuids = null; + } + return new ScanRecord(serviceUuids, serviceSolicitationUuids, manufacturerData, + serviceData, advertiseFlag, txPowerLevel, localName, scanRecord); } catch (Exception e) { Log.e(TAG, "unable to parse scan record: " + Arrays.toString(scanRecord)); // As the record is invalid, ignore all the parsed results for this packet // and return an empty record with raw scanRecord bytes in results - return new ScanRecord(null, null, null, -1, Integer.MIN_VALUE, null, scanRecord); + return new ScanRecord(null, null, null, null, -1, Integer.MIN_VALUE, null, scanRecord); } } @Override public String toString() { return "ScanRecord [mAdvertiseFlags=" + mAdvertiseFlags + ", mServiceUuids=" + mServiceUuids + + ", mServiceSolicitationUuids=" + mServiceSolicitationUuids + ", mManufacturerSpecificData=" + BluetoothLeUtils.toString( mManufacturerSpecificData) + ", mServiceData=" + BluetoothLeUtils.toString(mServiceData) @@ -297,6 +330,20 @@ public final class ScanRecord { return currentPos; } + /** + * Parse service Solicitation UUIDs. + */ + private static int parseServiceSolicitationUuid(byte[] scanRecord, int currentPos, + int dataLength, int uuidLength, List<ParcelUuid> serviceSolicitationUuids) { + while (dataLength > 0) { + byte[] uuidBytes = extractBytes(scanRecord, currentPos, uuidLength); + serviceSolicitationUuids.add(BluetoothUuid.parseUuidFrom(uuidBytes)); + dataLength -= uuidLength; + currentPos += uuidLength; + } + return currentPos; + } + // Helper method to extract bytes from byte array. private static byte[] extractBytes(byte[] scanRecord, int start, int length) { byte[] bytes = new byte[length]; diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 085d77d5c1cd..f5339efb8d60 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -236,9 +236,15 @@ public abstract class ContentProvider implements ComponentCallbacks2 { // However, the caller may be expecting to access them my index. Hence, // we have to execute the query as if allowed to get a cursor with the // columns. We then use the column names to return an empty cursor. - Cursor cursor = ContentProvider.this.query( - uri, projection, queryArgs, - CancellationSignal.fromTransport(cancellationSignal)); + Cursor cursor; + final String original = setCallingPackage(callingPkg); + try { + cursor = ContentProvider.this.query( + uri, projection, queryArgs, + CancellationSignal.fromTransport(cancellationSignal)); + } finally { + setCallingPackage(original); + } if (cursor == null) { return null; } @@ -260,6 +266,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { @Override public String getType(Uri uri) { + // getCallingPackage() isn't available in getType(), as the javadoc states. validateIncomingUri(uri); uri = maybeGetUriWithoutUserId(uri); Trace.traceBegin(TRACE_TAG_DATABASE, "getType"); @@ -276,7 +283,12 @@ public abstract class ContentProvider implements ComponentCallbacks2 { int userId = getUserIdFromUri(uri); uri = maybeGetUriWithoutUserId(uri); if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) { - return rejectInsert(uri, initialValues); + final String original = setCallingPackage(callingPkg); + try { + return rejectInsert(uri, initialValues); + } finally { + setCallingPackage(original); + } } Trace.traceBegin(TRACE_TAG_DATABASE, "insert"); final String original = setCallingPackage(callingPkg); @@ -440,6 +452,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 { @Override public String[] getStreamTypes(Uri uri, String mimeTypeFilter) { + // getCallingPackage() isn't available in getType(), as the javadoc states. validateIncomingUri(uri); uri = maybeGetUriWithoutUserId(uri); Trace.traceBegin(TRACE_TAG_DATABASE, "getStreamTypes"); diff --git a/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java b/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java index 06c069c583b5..8ea1db25a9a7 100644 --- a/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java +++ b/core/java/android/database/sqlite/SQLiteCompatibilityWalFlags.java @@ -16,6 +16,7 @@ package android.database.sqlite; +import android.annotation.TestApi; import android.app.ActivityThread; import android.app.Application; import android.provider.Settings; @@ -33,6 +34,7 @@ import com.android.internal.annotations.VisibleForTesting; * for consistent behavior across all connections opened in the process. * @hide */ +@TestApi public class SQLiteCompatibilityWalFlags { private static final String TAG = "SQLiteCompatibilityWalFlags"; @@ -45,6 +47,9 @@ public class SQLiteCompatibilityWalFlags { // This flag is used to avoid recursive initialization due to circular dependency on Settings private static volatile boolean sCallingGlobalSettings; + private SQLiteCompatibilityWalFlags() { + } + /** * @hide */ @@ -140,6 +145,7 @@ public class SQLiteCompatibilityWalFlags { * @hide */ @VisibleForTesting + @TestApi public static void reset() { sInitialized = false; sFlagsSet = false; diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index fb916d38f3ba..ce1879620ce3 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -3840,7 +3840,7 @@ public class ConnectivityManager { @UnsupportedAppUsage public static boolean setProcessDefaultNetworkForHostResolution(Network network) { return NetworkUtils.bindProcessToNetworkForHostResolution( - network == null ? NETID_UNSET : network.netId); + (network == null) ? NETID_UNSET : network.getNetIdForResolv()); } /** diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index 142023d40c0e..bf2344d4a9f6 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -100,21 +100,29 @@ public class Network implements Parcelable { // anytime and (b) receivers should be explicit about attempts to bypass // Private DNS so that the intent of the code is easily determined and // code search audits are possible. - private boolean mPrivateDnsBypass = false; + private final transient boolean mPrivateDnsBypass; /** * @hide */ @UnsupportedAppUsage public Network(int netId) { + this(netId, false); + } + + /** + * @hide + */ + public Network(int netId, boolean privateDnsBypass) { this.netId = netId; + this.mPrivateDnsBypass = privateDnsBypass; } /** * @hide */ public Network(Network that) { - this.netId = that.netId; + this(that.netId, that.mPrivateDnsBypass); } /** @@ -133,8 +141,7 @@ public class Network implements Parcelable { * Operates the same as {@code InetAddress.getByName} except that host * resolution is done on this network. * - * @param host - * the hostName to be resolved to an address or {@code null}. + * @param host the hostname to be resolved to an address or {@code null}. * @return the {@code InetAddress} instance representing the host. * @throws UnknownHostException * if the address lookup fails. @@ -144,14 +151,14 @@ public class Network implements Parcelable { } /** - * Specify whether or not Private DNS should be bypassed when attempting + * Obtain a Network object for which Private DNS is to be bypassed when attempting * to use {@link #getAllByName(String)}/{@link #getByName(String)} methods on the given * instance for hostname resolution. * * @hide */ - public void setPrivateDnsBypass(boolean bypass) { - mPrivateDnsBypass = bypass; + public Network getPrivateDnsBypassingCopy() { + return new Network(netId, true); } /** diff --git a/core/java/android/net/SntpClient.java b/core/java/android/net/SntpClient.java index 10c0ce25e97b..b8d7cf167ca8 100644 --- a/core/java/android/net/SntpClient.java +++ b/core/java/android/net/SntpClient.java @@ -85,19 +85,16 @@ public class SntpClient { * @return true if the transaction was successful. */ public boolean requestTime(String host, int timeout, Network network) { - // This flag only affects DNS resolution and not other socket semantics, - // therefore it's safe to set unilaterally rather than take more - // defensive measures like making a copy. - network.setPrivateDnsBypass(true); + final Network networkForResolv = network.getPrivateDnsBypassingCopy(); InetAddress address = null; try { - address = network.getByName(host); + address = networkForResolv.getByName(host); } catch (Exception e) { EventLogTags.writeNtpFailure(host, e.toString()); if (DBG) Log.d(TAG, "request time failed: " + e); return false; } - return requestTime(address, NTP_PORT, timeout, network); + return requestTime(address, NTP_PORT, timeout, networkForResolv); } public boolean requestTime(InetAddress address, int port, int timeout, Network network) { diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index a463afa2e110..22dd4fc362ba 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -139,6 +139,8 @@ public class TrafficStats { public static final int TAG_SYSTEM_GPS = 0xFFFFFF44; /** @hide */ public static final int TAG_SYSTEM_PAC = 0xFFFFFF45; + /** @hide */ + public static final int TAG_SYSTEM_DHCP_SERVER = 0xFFFFFF46; private static INetworkStatsService sStatsService; diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java index 7e7666adfeed..cc6bb12a0894 100644 --- a/core/java/android/os/Parcel.java +++ b/core/java/android/os/Parcel.java @@ -846,11 +846,19 @@ public final class Parcel { return; } Set<Map.Entry<String,Object>> entries = val.entrySet(); - writeInt(entries.size()); + int size = entries.size(); + writeInt(size); + for (Map.Entry<String,Object> e : entries) { writeValue(e.getKey()); writeValue(e.getValue()); + size--; } + + if (size != 0) { + throw new BadParcelableException("Map size does not match number of entries!"); + } + } /** diff --git a/core/java/android/os/StatsLogEventWrapper.java b/core/java/android/os/StatsLogEventWrapper.java index 59ea28fc2fbd..d4d3dc838d91 100644 --- a/core/java/android/os/StatsLogEventWrapper.java +++ b/core/java/android/os/StatsLogEventWrapper.java @@ -120,15 +120,6 @@ public final class StatsLogEventWrapper implements Parcelable { mStorage.write(bytes, 0, bytes.length); } - /** - * Adds a boolean by adding either a 1 or 0 to the output. - */ - public void writeBoolean(boolean val) { - int toWrite = val ? 1 : 0; - mStorage.write(EVENT_TYPE_INT); - write4Bytes(toWrite); - } - private StatsLogEventWrapper(Parcel in) { readFromParcel(in); } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index bffed8dcfdf2..7df42ebe1de6 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -9556,6 +9556,17 @@ public final class Settings { public static final String TETHER_OFFLOAD_DISABLED = "tether_offload_disabled"; /** + * Use the old dnsmasq DHCP server for tethering instead of the framework implementation. + * + * Integer values are interpreted as boolean, and the absence of an explicit setting + * is interpreted as |true|. + * TODO: make the default |false| + * @hide + */ + public static final String TETHER_ENABLE_LEGACY_DHCP_SERVER = + "tether_enable_legacy_dhcp_server"; + + /** * List of certificate (hex string representation of the application's certificate - SHA-1 * or SHA-256) and carrier app package pairs which are whitelisted to prompt the user for * install when a sim card with matching UICC carrier privilege rules is inserted. The diff --git a/core/java/android/service/autofill/AutofillFieldClassificationService.java b/core/java/android/service/autofill/AutofillFieldClassificationService.java index e5e1c926fbcd..1cd76d2e9ec9 100644 --- a/core/java/android/service/autofill/AutofillFieldClassificationService.java +++ b/core/java/android/service/autofill/AutofillFieldClassificationService.java @@ -65,36 +65,16 @@ public abstract class AutofillFieldClassificationService extends Service { /** * Manifest metadata key for the resource string containing the name of the default field * classification algorithm. - * - * @deprecated Use {@link #RESOURCE_DEFAULT_ALGORITHM} instead. */ - @Deprecated public static final String SERVICE_META_DATA_KEY_DEFAULT_ALGORITHM = "android.autofill.field_classification.default_algorithm"; - /** * Manifest metadata key for the resource string array containing the names of all field * classification algorithms provided by the service. - * - * @deprecated Use {@link #RESOURCE_AVAILABLE_ALGORITHMS} instead. */ - @Deprecated public static final String SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS = "android.autofill.field_classification.available_algorithms"; - /** - * Name of the resource string containing the name of the default field - * classification algorithm. - */ - public static final String RESOURCE_DEFAULT_ALGORITHM = - "autofill_field_classification_default_algorithm"; - - /** - * Name of the resource string array containing the names of all field - * classification algorithms provided by the service. - */ - public static final String RESOURCE_AVAILABLE_ALGORITHMS = - "autofill_field_classification_available_algorithms"; /** {@hide} **/ public static final String EXTRA_SCORES = "scores"; diff --git a/core/java/android/service/autofill/FillRequest.java b/core/java/android/service/autofill/FillRequest.java index 4bd6e5c5731a..1d0c987403db 100644 --- a/core/java/android/service/autofill/FillRequest.java +++ b/core/java/android/service/autofill/FillRequest.java @@ -123,6 +123,10 @@ public final class FillRequest implements Parcelable { /** * Gets the contexts associated with each previous fill request. + * + * <p><b>Note:</b> Starting on Android {@link android.os.Build.VERSION_CODES#Q}, it could also + * include contexts from requests whose {@link SaveInfo} had the + * {@link SaveInfo#FLAG_DELAY_SAVE} flag. */ public @NonNull List<FillContext> getFillContexts() { return mContexts; diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java index b845250bb792..f5719568c1ad 100644 --- a/core/java/android/service/autofill/SaveInfo.java +++ b/core/java/android/service/autofill/SaveInfo.java @@ -246,7 +246,7 @@ public final class SaveInfo implements Parcelable { * multiple screens to implement an autofillable workflow (for example, one screen for the * username field, another for password). */ - // TODO(b/112051762): improve documentation: add example, document relationship with other + // TODO(b/113281366): improve documentation: add example, document relationship with other // flagss, etc... public static final int FLAG_DELAY_SAVE = 0x4; diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 07f74f0506b2..d0795c95a8ad 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -11725,7 +11725,6 @@ public class BatteryStatsImpl extends BatteryStats { Slog.d(TAG, "UID=" + uid + " rx_bytes=" + rxBytes + " rx_time=" + timeRxMs); } counter.getRxTimeCounter().addCountLocked(timeRxMs); - leftOverRxTimeMs -= timeRxMs; } if (totalTxBytes > 0 && txBytes > 0) { @@ -11734,7 +11733,6 @@ public class BatteryStatsImpl extends BatteryStats { Slog.d(TAG, "UID=" + uid + " tx_bytes=" + txBytes + " tx_time=" + timeTxMs); } counter.getTxTimeCounters()[0].addCountLocked(timeTxMs); - leftOverTxTimeMs -= timeTxMs; } } } diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp index 3fcedd0264ae..6ebf35c8e1dc 100644 --- a/core/jni/android/graphics/ColorFilter.cpp +++ b/core/jni/android/graphics/ColorFilter.cpp @@ -22,8 +22,6 @@ #include "SkColorFilter.h" #include "SkColorMatrixFilter.h" -#include <Caches.h> - namespace android { using namespace uirenderer; diff --git a/core/jni/android/graphics/Matrix.cpp b/core/jni/android/graphics/Matrix.cpp index f8bb77a9650c..755fcfb27141 100644 --- a/core/jni/android/graphics/Matrix.cpp +++ b/core/jni/android/graphics/Matrix.cpp @@ -20,7 +20,6 @@ #include "SkMatrix.h" #include "core_jni_helpers.h" -#include <Caches.h> #include <jni.h> namespace android { diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp index cff772002b14..68f5bef18de1 100644 --- a/core/jni/android/graphics/Shader.cpp +++ b/core/jni/android/graphics/Shader.cpp @@ -6,7 +6,6 @@ #include "SkBlendMode.h" #include "core_jni_helpers.h" -#include <Caches.h> #include <jni.h> using namespace android::uirenderer; diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp index d098a355085e..3e464c61665f 100644 --- a/core/jni/android/graphics/SurfaceTexture.cpp +++ b/core/jni/android/graphics/SurfaceTexture.cpp @@ -36,6 +36,7 @@ #include "jni.h" #include <nativehelper/JNIHelp.h> #include <nativehelper/ScopedLocalRef.h> +#include "surfacetexture/SurfaceTexture.h" // ---------------------------------------------------------------------------- @@ -80,10 +81,10 @@ static bool isProtectedContext() { // ---------------------------------------------------------------------------- static void SurfaceTexture_setSurfaceTexture(JNIEnv* env, jobject thiz, - const sp<GLConsumer>& surfaceTexture) + const sp<SurfaceTexture>& surfaceTexture) { - GLConsumer* const p = - (GLConsumer*)env->GetLongField(thiz, fields.surfaceTexture); + SurfaceTexture* const p = + (SurfaceTexture*)env->GetLongField(thiz, fields.surfaceTexture); if (surfaceTexture.get()) { surfaceTexture->incStrong((void*)SurfaceTexture_setSurfaceTexture); } @@ -108,10 +109,10 @@ static void SurfaceTexture_setProducer(JNIEnv* env, jobject thiz, } static void SurfaceTexture_setFrameAvailableListener(JNIEnv* env, - jobject thiz, sp<GLConsumer::FrameAvailableListener> listener) + jobject thiz, sp<SurfaceTexture::FrameAvailableListener> listener) { - GLConsumer::FrameAvailableListener* const p = - (GLConsumer::FrameAvailableListener*) + SurfaceTexture::FrameAvailableListener* const p = + (SurfaceTexture::FrameAvailableListener*) env->GetLongField(thiz, fields.frameAvailableListener); if (listener.get()) { listener->incStrong((void*)SurfaceTexture_setSurfaceTexture); @@ -122,8 +123,8 @@ static void SurfaceTexture_setFrameAvailableListener(JNIEnv* env, env->SetLongField(thiz, fields.frameAvailableListener, (jlong)listener.get()); } -sp<GLConsumer> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz) { - return (GLConsumer*)env->GetLongField(thiz, fields.surfaceTexture); +sp<SurfaceTexture> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz) { + return (SurfaceTexture*)env->GetLongField(thiz, fields.surfaceTexture); } sp<IGraphicBufferProducer> SurfaceTexture_getProducer(JNIEnv* env, jobject thiz) { @@ -131,7 +132,7 @@ sp<IGraphicBufferProducer> SurfaceTexture_getProducer(JNIEnv* env, jobject thiz) } sp<ANativeWindow> android_SurfaceTexture_getNativeWindow(JNIEnv* env, jobject thiz) { - sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); + sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(env, thiz)); sp<Surface> surfaceTextureClient(surfaceTexture != NULL ? new Surface(producer) : NULL); return surfaceTextureClient; @@ -144,7 +145,7 @@ bool android_SurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz) { // ---------------------------------------------------------------------------- -class JNISurfaceTextureContext : public GLConsumer::FrameAvailableListener +class JNISurfaceTextureContext : public SurfaceTexture::FrameAvailableListener { public: JNISurfaceTextureContext(JNIEnv* env, jobject weakThiz, jclass clazz); @@ -266,12 +267,12 @@ static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jboolean isDetached, consumer->setMaxBufferCount(1); } - sp<GLConsumer> surfaceTexture; + sp<SurfaceTexture> surfaceTexture; if (isDetached) { - surfaceTexture = new GLConsumer(consumer, GL_TEXTURE_EXTERNAL_OES, + surfaceTexture = new SurfaceTexture(consumer, GL_TEXTURE_EXTERNAL_OES, true, !singleBufferMode); } else { - surfaceTexture = new GLConsumer(consumer, texName, + surfaceTexture = new SurfaceTexture(consumer, texName, GL_TEXTURE_EXTERNAL_OES, true, !singleBufferMode); } @@ -306,7 +307,7 @@ static void SurfaceTexture_init(JNIEnv* env, jobject thiz, jboolean isDetached, static void SurfaceTexture_finalize(JNIEnv* env, jobject thiz) { - sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); + sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); surfaceTexture->setFrameAvailableListener(0); SurfaceTexture_setFrameAvailableListener(env, thiz, 0); SurfaceTexture_setSurfaceTexture(env, thiz, 0); @@ -315,13 +316,13 @@ static void SurfaceTexture_finalize(JNIEnv* env, jobject thiz) static void SurfaceTexture_setDefaultBufferSize( JNIEnv* env, jobject thiz, jint width, jint height) { - sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); + sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); surfaceTexture->setDefaultBufferSize(width, height); } static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject thiz) { - sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); + sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); status_t err = surfaceTexture->updateTexImage(); if (err == INVALID_OPERATION) { jniThrowException(env, IllegalStateException, "Unable to update texture contents (see " @@ -333,7 +334,7 @@ static void SurfaceTexture_updateTexImage(JNIEnv* env, jobject thiz) static void SurfaceTexture_releaseTexImage(JNIEnv* env, jobject thiz) { - sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); + sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); status_t err = surfaceTexture->releaseTexImage(); if (err == INVALID_OPERATION) { jniThrowException(env, IllegalStateException, "Unable to release texture contents (see " @@ -345,20 +346,20 @@ static void SurfaceTexture_releaseTexImage(JNIEnv* env, jobject thiz) static jint SurfaceTexture_detachFromGLContext(JNIEnv* env, jobject thiz) { - sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); + sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); return surfaceTexture->detachFromContext(); } static jint SurfaceTexture_attachToGLContext(JNIEnv* env, jobject thiz, jint tex) { - sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); + sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); return surfaceTexture->attachToContext((GLuint)tex); } static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject thiz, jfloatArray jmtx) { - sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); + sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); float* mtx = env->GetFloatArrayElements(jmtx, NULL); surfaceTexture->getTransformMatrix(mtx); env->ReleaseFloatArrayElements(jmtx, mtx, 0); @@ -366,19 +367,19 @@ static void SurfaceTexture_getTransformMatrix(JNIEnv* env, jobject thiz, static jlong SurfaceTexture_getTimestamp(JNIEnv* env, jobject thiz) { - sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); + sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); return surfaceTexture->getTimestamp(); } static void SurfaceTexture_release(JNIEnv* env, jobject thiz) { - sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); + sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); surfaceTexture->abandon(); } static jboolean SurfaceTexture_isReleased(JNIEnv* env, jobject thiz) { - sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); + sp<SurfaceTexture> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, thiz)); return surfaceTexture->isAbandoned(); } diff --git a/core/jni/android_view_TextureLayer.cpp b/core/jni/android_view_TextureLayer.cpp index d3a447f1f7dc..1ccb6a8f610c 100644 --- a/core/jni/android_view_TextureLayer.cpp +++ b/core/jni/android_view_TextureLayer.cpp @@ -67,8 +67,7 @@ static void TextureLayer_setTransform(JNIEnv* env, jobject clazz, static void TextureLayer_setSurfaceTexture(JNIEnv* env, jobject clazz, jlong layerUpdaterPtr, jobject surface) { DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerUpdaterPtr); - sp<GLConsumer> surfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface)); - layer->setSurfaceTexture(surfaceTexture); + layer->setSurfaceTexture(SurfaceTexture_getSurfaceTexture(env, surface)); } static void TextureLayer_updateSurfaceTexture(JNIEnv* env, jobject clazz, diff --git a/core/jni/include/android_runtime/android_graphics_SurfaceTexture.h b/core/jni/include/android_runtime/android_graphics_SurfaceTexture.h index c534d4bb9e0a..0ad25876a008 100644 --- a/core/jni/include/android_runtime/android_graphics_SurfaceTexture.h +++ b/core/jni/include/android_runtime/android_graphics_SurfaceTexture.h @@ -23,14 +23,14 @@ namespace android { -class GLConsumer; class IGraphicBufferProducer; +class SurfaceTexture; extern sp<ANativeWindow> android_SurfaceTexture_getNativeWindow(JNIEnv* env, jobject thiz); extern bool android_SurfaceTexture_isInstanceOf(JNIEnv* env, jobject thiz); -/* Gets the underlying GLConsumer from a SurfaceTexture Java object. */ -extern sp<GLConsumer> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz); +/* Gets the underlying C++ SurfaceTexture object from a SurfaceTexture Java object. */ +extern sp<SurfaceTexture> SurfaceTexture_getSurfaceTexture(JNIEnv* env, jobject thiz); /* gets the producer end of the SurfaceTexture */ extern sp<IGraphicBufferProducer> SurfaceTexture_getProducer(JNIEnv* env, jobject thiz); diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 289c898a923c..836e8244f6e6 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3498,6 +3498,9 @@ empty string is passed in --> <string name="config_wlan_network_service_package" translatable="false"></string> + <!-- Telephony qualified networks service package name to bind to by default. --> + <string name="config_qualified_networks_service_package" translatable="false"></string> + <!-- Wear devices: Controls the radios affected by Activity Mode. --> <string-array name="config_wearActivityModeRadios"> <item>"wifi"</item> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 53588303fcd5..8ac247461712 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -273,6 +273,7 @@ <java-symbol type="string" name="config_wlan_network_service_package" /> <java-symbol type="string" name="config_wwan_data_service_package" /> <java-symbol type="string" name="config_wlan_data_service_package" /> + <java-symbol type="string" name="config_qualified_networks_service_package" /> <java-symbol type="bool" name="config_networkSamplingWakesDevice" /> <java-symbol type="bool" name="config_showMenuShortcutsWhenKeyboardPresent" /> <java-symbol type="bool" name="config_sip_wifi_only" /> diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java index 71627ab3c0b6..189a4aa4fe28 100644 --- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java +++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java @@ -422,6 +422,7 @@ public class SettingsBackupTest { Settings.Global.TETHER_DUN_REQUIRED, Settings.Global.TETHER_OFFLOAD_DISABLED, Settings.Global.TETHER_SUPPORTED, + Settings.Global.TETHER_ENABLE_LEGACY_DHCP_SERVER, Settings.Global.TEXT_CLASSIFIER_CONSTANTS, Settings.Global.THEATER_MODE_ON, Settings.Global.TIME_ONLY_MODE_CONSTANTS, diff --git a/keystore/java/android/security/keystore/AttestationUtils.java b/keystore/java/android/security/keystore/AttestationUtils.java index 3d2a2718a9c8..bd497c1e4efa 100644 --- a/keystore/java/android/security/keystore/AttestationUtils.java +++ b/keystore/java/android/security/keystore/AttestationUtils.java @@ -29,6 +29,7 @@ import android.security.keymaster.KeymasterArguments; import android.security.keymaster.KeymasterCertificateChain; import android.security.keymaster.KeymasterDefs; import android.telephony.TelephonyManager; +import android.text.TextUtils; import android.util.ArraySet; import java.io.ByteArrayInputStream; @@ -128,14 +129,14 @@ public abstract class AttestationUtils { @NonNull public static KeymasterArguments prepareAttestationArgumentsIfMisprovisioned( Context context, @NonNull int[] idTypes, @NonNull byte[] attestationChallenge) throws DeviceIdAttestationException { - if (!isPotentiallyMisprovisionedDevice(context)) { - return null; - } Resources resources = context.getResources(); String misprovisionedBrand = resources.getString( com.android.internal.R.string.config_misprovisionedBrandValue); + if (!TextUtils.isEmpty(misprovisionedBrand) && !isPotentiallyMisprovisionedDevice(context)){ + return null; + } return prepareAttestationArguments( - context, idTypes, attestationChallenge, misprovisionedBrand); + context, idTypes, attestationChallenge, misprovisionedBrand); } @NonNull private static boolean isPotentiallyMisprovisionedDevice(Context context) { diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 83e90b654ff6..62ab7900737e 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -175,9 +175,7 @@ cc_defaults { "pipeline/skia/SkiaRecordingCanvas.cpp", "pipeline/skia/SkiaVulkanPipeline.cpp", "pipeline/skia/VectorDrawableAtlas.cpp", - "renderstate/PixelBufferState.cpp", "renderstate/RenderState.cpp", - "renderstate/TextureState.cpp", "renderthread/CacheManager.cpp", "renderthread/CanvasContext.cpp", "renderthread/DrawFrameTask.cpp", @@ -189,6 +187,9 @@ cc_defaults { "renderthread/TimeLord.cpp", "renderthread/Frame.cpp", "service/GraphicsStatsService.cpp", + "surfacetexture/EGLConsumer.cpp", + "surfacetexture/ImageConsumer.cpp", + "surfacetexture/SurfaceTexture.cpp", "thread/TaskManager.cpp", "utils/Blur.cpp", "utils/Color.cpp", @@ -200,7 +201,6 @@ cc_defaults { "AnimationContext.cpp", "Animator.cpp", "AnimatorManager.cpp", - "Caches.cpp", "CanvasState.cpp", "CanvasTransform.cpp", "ClipArea.cpp", @@ -209,7 +209,6 @@ cc_defaults { "DeviceInfo.cpp", "FrameInfo.cpp", "FrameInfoVisualizer.cpp", - "GlLayer.cpp", "GpuMemoryTracker.cpp", "HardwareBitmapUploader.cpp", "Interpolator.cpp", @@ -219,7 +218,6 @@ cc_defaults { "Matrix.cpp", "EglReadback.cpp", "PathParser.cpp", - "PixelBuffer.cpp", "ProfileData.cpp", "ProfileDataContainer.cpp", "Properties.cpp", @@ -230,9 +228,7 @@ cc_defaults { "ResourceCache.cpp", "SkiaCanvas.cpp", "Snapshot.cpp", - "Texture.cpp", "VectorDrawable.cpp", - "VkLayer.cpp", "protos/graphicsstats.proto", ], diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp deleted file mode 100644 index 254144448859..000000000000 --- a/libs/hwui/Caches.cpp +++ /dev/null @@ -1,103 +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. - */ - -#include "Caches.h" - -#include "GlLayer.h" -#include "Properties.h" -#include "renderstate/RenderState.h" -#include "utils/GLUtils.h" - -#include <cutils/properties.h> -#include <utils/Log.h> -#include <utils/String8.h> - -namespace android { -namespace uirenderer { - -Caches* Caches::sInstance = nullptr; - -/////////////////////////////////////////////////////////////////////////////// -// Macros -/////////////////////////////////////////////////////////////////////////////// - -#if DEBUG_CACHE_FLUSH -#define FLUSH_LOGD(...) ALOGD(__VA_ARGS__) -#else -#define FLUSH_LOGD(...) -#endif - -/////////////////////////////////////////////////////////////////////////////// -// Constructors/destructor -/////////////////////////////////////////////////////////////////////////////// - -Caches::Caches(RenderState& renderState) : mInitialized(false) { - INIT_LOGD("Creating OpenGL renderer caches"); - init(); - initStaticProperties(); -} - -bool Caches::init() { - if (mInitialized) return false; - - ATRACE_NAME("Caches::init"); - - mRegionMesh = nullptr; - - mInitialized = true; - - mPixelBufferState = new PixelBufferState(); - mTextureState = new TextureState(); - mTextureState->constructTexture(*this); - - return true; -} - -void Caches::initStaticProperties() { - // OpenGL ES 3.0+ specific features - gpuPixelBuffersEnabled = extensions().hasPixelBufferObjects() && - property_get_bool(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, true); -} - -void Caches::terminate() { - if (!mInitialized) return; - mRegionMesh.reset(nullptr); - - clearGarbage(); - - delete mPixelBufferState; - mPixelBufferState = nullptr; - delete mTextureState; - mTextureState = nullptr; - mInitialized = false; -} - -/////////////////////////////////////////////////////////////////////////////// -// Memory management -/////////////////////////////////////////////////////////////////////////////// - -void Caches::clearGarbage() {} - -void Caches::flush(FlushMode mode) { - clearGarbage(); - glFinish(); - // Errors during cleanup should be considered non-fatal, dump them and - // and move on. TODO: All errors or just errors like bad surface? - GLUtils::dumpGLErrors(); -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h deleted file mode 100644 index 642f9dc50eb1..000000000000 --- a/libs/hwui/Caches.h +++ /dev/null @@ -1,135 +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. - */ - -#pragma once - -#include "DeviceInfo.h" -#include "Extensions.h" -#include "ResourceCache.h" -#include "renderstate/PixelBufferState.h" -#include "renderstate/TextureState.h" -#include "thread/TaskManager.h" -#include "thread/TaskProcessor.h" - -#include <memory> -#include <vector> - -#include <GLES3/gl3.h> - -#include <utils/KeyedVector.h> - -#include <cutils/compiler.h> - -#include <SkPath.h> - -#include <vector> - -namespace android { -namespace uirenderer { - -/////////////////////////////////////////////////////////////////////////////// -// Caches -/////////////////////////////////////////////////////////////////////////////// - -class RenderNode; -class RenderState; - -class ANDROID_API Caches { -public: - static Caches& createInstance(RenderState& renderState) { - LOG_ALWAYS_FATAL_IF(sInstance, "double create of Caches attempted"); - sInstance = new Caches(renderState); - return *sInstance; - } - - static Caches& getInstance() { - LOG_ALWAYS_FATAL_IF(!sInstance, "instance not yet created"); - return *sInstance; - } - - static bool hasInstance() { return sInstance != nullptr; } - -private: - explicit Caches(RenderState& renderState); - static Caches* sInstance; - -public: - enum class FlushMode { Layers = 0, Moderate, Full }; - - /** - * Initialize caches. - */ - bool init(); - - bool isInitialized() { return mInitialized; } - - /** - * Flush the cache. - * - * @param mode Indicates how much of the cache should be flushed - */ - void flush(FlushMode mode); - - /** - * Destroys all resources associated with this cache. This should - * be called after a flush(FlushMode::Full). - */ - void terminate(); - - /** - * Call this on each frame to ensure that garbage is deleted from - * GPU memory. - */ - void clearGarbage(); - - /** - * Returns the GL RGBA internal format to use for the current device - * If the device supports linear blending and needSRGB is true, - * this function returns GL_SRGB8_ALPHA8, otherwise it returns GL_RGBA - */ - constexpr GLint rgbaInternalFormat(bool needSRGB = true) const { - return extensions().hasLinearBlending() && needSRGB ? GL_SRGB8_ALPHA8 : GL_RGBA; - } - -public: - TaskManager tasks; - - bool gpuPixelBuffersEnabled; - - const Extensions& extensions() const { return DeviceInfo::get()->extensions(); } - PixelBufferState& pixelBufferState() { return *mPixelBufferState; } - TextureState& textureState() { return *mTextureState; } - -private: - void initStaticProperties(); - - static void eventMarkNull(GLsizei length, const GLchar* marker) {} - static void startMarkNull(GLsizei length, const GLchar* marker) {} - static void endMarkNull() {} - - // Used to render layers - std::unique_ptr<TextureVertex[]> mRegionMesh; - - bool mInitialized; - - // TODO: move below to RenderState - PixelBufferState* mPixelBufferState = nullptr; - TextureState* mTextureState = nullptr; - -}; // class Caches - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp index 569de76f294e..00916559a9c2 100644 --- a/libs/hwui/DeferredLayerUpdater.cpp +++ b/libs/hwui/DeferredLayerUpdater.cpp @@ -15,27 +15,20 @@ */ #include "DeferredLayerUpdater.h" -#include "GlLayer.h" -#include "VkLayer.h" #include "renderstate/RenderState.h" -#include "renderthread/EglManager.h" -#include "renderthread/RenderTask.h" #include "utils/PaintUtils.h" namespace android { namespace uirenderer { -DeferredLayerUpdater::DeferredLayerUpdater(RenderState& renderState, CreateLayerFn createLayerFn, - Layer::Api layerApi) +DeferredLayerUpdater::DeferredLayerUpdater(RenderState& renderState) : mRenderState(renderState) , mBlend(false) , mSurfaceTexture(nullptr) , mTransform(nullptr) , mGLContextAttached(false) , mUpdateTexImage(false) - , mLayer(nullptr) - , mLayerApi(layerApi) - , mCreateLayerFn(createLayerFn) { + , mLayer(nullptr) { renderState.registerDeferredLayerUpdater(this); } @@ -50,13 +43,9 @@ void DeferredLayerUpdater::destroyLayer() { return; } - if (mSurfaceTexture.get() && mLayerApi == Layer::Api::OpenGL && mGLContextAttached) { - status_t err = mSurfaceTexture->detachFromContext(); + if (mSurfaceTexture.get() && mGLContextAttached) { + mSurfaceTexture->detachFromView(); mGLContextAttached = false; - if (err != 0) { - // TODO: Elevate to fatal exception - ALOGE("Failed to detach SurfaceTexture from context %d", err); - } } mLayer->postDecStrong(); @@ -75,99 +64,53 @@ void DeferredLayerUpdater::setPaint(const SkPaint* paint) { void DeferredLayerUpdater::apply() { if (!mLayer) { - mLayer = mCreateLayerFn(mRenderState, mWidth, mHeight, mColorFilter, mAlpha, mMode, mBlend); + mLayer = new Layer(mRenderState, mColorFilter, mAlpha, mMode); } mLayer->setColorFilter(mColorFilter); mLayer->setAlpha(mAlpha, mMode); if (mSurfaceTexture.get()) { - if (mLayer->getApi() == Layer::Api::Vulkan) { - if (mUpdateTexImage) { - mUpdateTexImage = false; - doUpdateVkTexImage(); - } - } else { - LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::OpenGL, - "apply surfaceTexture with non GL backend %x, GL %x, VK %x", - mLayer->getApi(), Layer::Api::OpenGL, Layer::Api::Vulkan); - if (!mGLContextAttached) { - mGLContextAttached = true; - mUpdateTexImage = true; - mSurfaceTexture->attachToContext(static_cast<GlLayer*>(mLayer)->getTextureId()); - } - if (mUpdateTexImage) { - mUpdateTexImage = false; - doUpdateTexImage(); + if (!mGLContextAttached) { + mGLContextAttached = true; + mUpdateTexImage = true; + mSurfaceTexture->attachToView(); + } + if (mUpdateTexImage) { + mUpdateTexImage = false; + sk_sp<SkImage> layerImage; + SkMatrix textureTransform; + android_dataspace dataSpace; + bool queueEmpty = true; + // If the SurfaceTexture queue is in synchronous mode, need to discard all + // but latest frame. Since we can't tell which mode it is in, + // do this unconditionally. + do { + layerImage = mSurfaceTexture->dequeueImage(textureTransform, dataSpace, &queueEmpty, + mRenderState); + } while (layerImage.get() && (!queueEmpty)); + if (layerImage.get()) { + // force filtration if buffer size != layer size + bool forceFilter = mWidth != layerImage->width() || mHeight != layerImage->height(); + updateLayer(forceFilter, textureTransform, dataSpace, layerImage); } - GLenum renderTarget = mSurfaceTexture->getCurrentTextureTarget(); - static_cast<GlLayer*>(mLayer)->setRenderTarget(renderTarget); } + if (mTransform) { - mLayer->getTransform().load(*mTransform); + mLayer->getTransform() = *mTransform; setTransform(nullptr); } } } -void DeferredLayerUpdater::doUpdateTexImage() { - LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::OpenGL, - "doUpdateTexImage non GL backend %x, GL %x, VK %x", mLayer->getApi(), - Layer::Api::OpenGL, Layer::Api::Vulkan); - if (mSurfaceTexture->updateTexImage() == NO_ERROR) { - float transform[16]; - - int64_t frameNumber = mSurfaceTexture->getFrameNumber(); - // If the GLConsumer queue is in synchronous mode, need to discard all - // but latest frame, using the frame number to tell when we no longer - // have newer frames to target. Since we can't tell which mode it is in, - // do this unconditionally. - int dropCounter = 0; - while (mSurfaceTexture->updateTexImage() == NO_ERROR) { - int64_t newFrameNumber = mSurfaceTexture->getFrameNumber(); - if (newFrameNumber == frameNumber) break; - frameNumber = newFrameNumber; - dropCounter++; - } - - bool forceFilter = false; - sp<GraphicBuffer> buffer = mSurfaceTexture->getCurrentBuffer(); - if (buffer != nullptr) { - // force filtration if buffer size != layer size - forceFilter = mWidth != static_cast<int>(buffer->getWidth()) || - mHeight != static_cast<int>(buffer->getHeight()); - } - -#if DEBUG_RENDERER - if (dropCounter > 0) { - RENDERER_LOGD("Dropped %d frames on texture layer update", dropCounter); - } -#endif - mSurfaceTexture->getTransformMatrix(transform); - - updateLayer(forceFilter, transform, mSurfaceTexture->getCurrentDataSpace()); - } -} - -void DeferredLayerUpdater::doUpdateVkTexImage() { - LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::Vulkan, - "updateLayer non Vulkan backend %x, GL %x, VK %x", mLayer->getApi(), - Layer::Api::OpenGL, Layer::Api::Vulkan); - - static const mat4 identityMatrix; - updateLayer(false, identityMatrix.data, HAL_DATASPACE_UNKNOWN); - - VkLayer* vkLayer = static_cast<VkLayer*>(mLayer); - vkLayer->updateTexture(); -} - -void DeferredLayerUpdater::updateLayer(bool forceFilter, const float* textureTransform, - android_dataspace dataspace) { +void DeferredLayerUpdater::updateLayer(bool forceFilter, const SkMatrix& textureTransform, + android_dataspace dataspace, const sk_sp<SkImage>& layerImage) { mLayer->setBlend(mBlend); mLayer->setForceFilter(forceFilter); mLayer->setSize(mWidth, mHeight); - mLayer->getTexTransform().load(textureTransform); + mLayer->getTexTransform() = textureTransform; mLayer->setDataSpace(dataspace); + mLayer->setImage(layerImage); } void DeferredLayerUpdater::detachSurfaceTexture() { diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h index fe3ee7a2b4c6..4c323b861002 100644 --- a/libs/hwui/DeferredLayerUpdater.h +++ b/libs/hwui/DeferredLayerUpdater.h @@ -17,18 +17,19 @@ #pragma once #include <SkColorFilter.h> +#include <SkImage.h> #include <SkMatrix.h> #include <cutils/compiler.h> -#include <gui/GLConsumer.h> +#include <map> #include <system/graphics.h> #include <utils/StrongPointer.h> #include <GLES2/gl2.h> #include <GLES2/gl2ext.h> +#include "surfacetexture/SurfaceTexture.h" #include "Layer.h" #include "Rect.h" -#include "renderthread/RenderThread.h" namespace android { namespace uirenderer { @@ -41,12 +42,7 @@ class DeferredLayerUpdater : public VirtualLightRefBase { public: // Note that DeferredLayerUpdater assumes it is taking ownership of the layer // and will not call incrementRef on it as a result. - typedef std::function<Layer*(RenderState& renderState, uint32_t layerWidth, - uint32_t layerHeight, sk_sp<SkColorFilter> colorFilter, int alpha, - SkBlendMode mode, bool blend)> - CreateLayerFn; - ANDROID_API explicit DeferredLayerUpdater(RenderState& renderState, CreateLayerFn createLayerFn, - Layer::Api layerApi); + ANDROID_API explicit DeferredLayerUpdater(RenderState& renderState); ANDROID_API ~DeferredLayerUpdater(); @@ -70,13 +66,13 @@ public: return false; } - ANDROID_API void setSurfaceTexture(const sp<GLConsumer>& texture) { - if (texture.get() != mSurfaceTexture.get()) { - mSurfaceTexture = texture; + ANDROID_API void setSurfaceTexture(const sp<SurfaceTexture>& consumer) { + if (consumer.get() != mSurfaceTexture.get()) { + mSurfaceTexture = consumer; - GLenum target = texture->getCurrentTextureTarget(); + GLenum target = consumer->getCurrentTextureTarget(); LOG_ALWAYS_FATAL_IF(target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES, - "set unsupported GLConsumer with target %x", target); + "set unsupported SurfaceTexture with target %x", target); } } @@ -97,12 +93,11 @@ public: void detachSurfaceTexture(); - void updateLayer(bool forceFilter, const float* textureTransform, android_dataspace dataspace); + void updateLayer(bool forceFilter, const SkMatrix& textureTransform, + android_dataspace dataspace, const sk_sp<SkImage>& layerImage); void destroyLayer(); - Layer::Api getBackingLayerApi() { return mLayerApi; } - private: RenderState& mRenderState; @@ -113,17 +108,12 @@ private: sk_sp<SkColorFilter> mColorFilter; int mAlpha = 255; SkBlendMode mMode = SkBlendMode::kSrcOver; - sp<GLConsumer> mSurfaceTexture; + sp<SurfaceTexture> mSurfaceTexture; SkMatrix* mTransform; bool mGLContextAttached; bool mUpdateTexImage; Layer* mLayer; - Layer::Api mLayerApi; - CreateLayerFn mCreateLayerFn; - - void doUpdateTexImage(); - void doUpdateVkTexImage(); }; } /* namespace uirenderer */ diff --git a/libs/hwui/GlLayer.cpp b/libs/hwui/GlLayer.cpp deleted file mode 100644 index 432bb8526465..000000000000 --- a/libs/hwui/GlLayer.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "GlLayer.h" - -#include "Caches.h" -#include "RenderNode.h" -#include "renderstate/RenderState.h" - -namespace android { -namespace uirenderer { - -GlLayer::GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight, - sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend) - : Layer(renderState, Api::OpenGL, colorFilter, alpha, mode) - , caches(Caches::getInstance()) - , texture(caches) { - texture.mWidth = layerWidth; - texture.mHeight = layerHeight; - texture.blend = blend; -} - -GlLayer::~GlLayer() { - // There's a rare possibility that Caches could have been destroyed already - // since this method is queued up as a task. - // Since this is a reset method, treat this as non-fatal. - if (caches.isInitialized() && texture.mId) { - texture.deleteTexture(); - } -} - -void GlLayer::onGlContextLost() { - texture.deleteTexture(); -} - -void GlLayer::setRenderTarget(GLenum renderTarget) { - if (renderTarget != getRenderTarget()) { - // new render target: bind with new target, and update filter/wrap - texture.mTarget = renderTarget; - if (texture.mId) { - caches.textureState().bindTexture(texture.target(), texture.mId); - } - texture.setFilter(GL_NEAREST, false, true); - texture.setWrap(GL_CLAMP_TO_EDGE, false, true); - } -} - -void GlLayer::generateTexture() { - if (!texture.mId) { - glGenTextures(1, &texture.mId); - } -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/GlLayer.h b/libs/hwui/GlLayer.h deleted file mode 100644 index 9f70fdae6790..000000000000 --- a/libs/hwui/GlLayer.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "Layer.h" - -#include "Texture.h" - -namespace android { -namespace uirenderer { - -// Forward declarations -class Caches; - -/** - * A layer has dimensions and is backed by an OpenGL texture or FBO. - */ -class GlLayer : public Layer { -public: - GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight, - sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend); - virtual ~GlLayer(); - - uint32_t getWidth() const override { return texture.mWidth; } - - uint32_t getHeight() const override { return texture.mHeight; } - - void setSize(uint32_t width, uint32_t height) override { - texture.updateLayout(width, height, texture.internalFormat(), texture.format(), - texture.target()); - } - - void setBlend(bool blend) override { texture.blend = blend; } - - bool isBlend() const override { return texture.blend; } - - inline GLuint getTextureId() const { return texture.id(); } - - inline GLenum getRenderTarget() const { return texture.target(); } - - void setRenderTarget(GLenum renderTarget); - - void generateTexture(); - - /** - * Lost the GL context but the layer is still around, mark it invalid internally - * so the dtor knows not to do any GL work - */ - void onGlContextLost(); - -private: - Caches& caches; - - /** - * The texture backing this layer. - */ - Texture texture; -}; // struct GlLayer - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/GpuMemoryTracker.cpp b/libs/hwui/GpuMemoryTracker.cpp index 612bfde1a3fa..a9a7af8f22f3 100644 --- a/libs/hwui/GpuMemoryTracker.cpp +++ b/libs/hwui/GpuMemoryTracker.cpp @@ -14,7 +14,6 @@ * limitations under the License. */ -#include "Texture.h" #include "utils/StringUtils.h" #include <GpuMemoryTracker.h> @@ -117,22 +116,6 @@ void GpuMemoryTracker::onFrameCompleted() { ATRACE_INT(buf, stats.count); } } - - std::vector<const Texture*> freeList; - for (const auto& obj : gObjectSet) { - if (obj->objectType() == GpuObjectType::Texture) { - const Texture* texture = static_cast<Texture*>(obj); - if (texture->cleanup) { - ALOGE("Leaked texture marked for cleanup! id=%u, size %ux%u", texture->id(), - texture->width(), texture->height()); - freeList.push_back(texture); - } - } - } - for (auto& texture : freeList) { - const_cast<Texture*>(texture)->deleteTexture(); - delete texture; - } } } // namespace uirenderer diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp index fb8f0337c95e..f59a2e6ee5c1 100644 --- a/libs/hwui/Layer.cpp +++ b/libs/hwui/Layer.cpp @@ -17,17 +17,17 @@ #include "Layer.h" #include "renderstate/RenderState.h" +#include "utils/Color.h" #include <SkToSRGBColorFilter.h> namespace android { namespace uirenderer { -Layer::Layer(RenderState& renderState, Api api, sk_sp<SkColorFilter> colorFilter, int alpha, - SkBlendMode mode) +Layer::Layer(RenderState& renderState, sk_sp<SkColorFilter> colorFilter, int alpha, + SkBlendMode mode) : GpuMemoryTracker(GpuObjectType::Layer) , mRenderState(renderState) - , mApi(api) , mColorFilter(colorFilter) , alpha(alpha) , mode(mode) { @@ -36,6 +36,8 @@ Layer::Layer(RenderState& renderState, Api api, sk_sp<SkColorFilter> colorFilter incStrong(nullptr); buildColorSpaceWithFilter(); renderState.registerLayer(this); + texTransform.setIdentity(); + transform.setIdentity(); } Layer::~Layer() { diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h index 31878ac23642..c4e4c1c96ba6 100644 --- a/libs/hwui/Layer.h +++ b/libs/hwui/Layer.h @@ -23,8 +23,9 @@ #include <SkColorFilter.h> #include <SkColorSpace.h> #include <SkPaint.h> - -#include "Matrix.h" +#include <SkImage.h> +#include <SkMatrix.h> +#include <system/graphics.h> namespace android { namespace uirenderer { @@ -40,24 +41,19 @@ class RenderState; */ class Layer : public VirtualLightRefBase, GpuMemoryTracker { public: - enum class Api { - OpenGL = 0, - Vulkan = 1, - }; - - Api getApi() const { return mApi; } + Layer(RenderState& renderState, sk_sp<SkColorFilter>, int alpha, SkBlendMode mode); ~Layer(); - virtual uint32_t getWidth() const = 0; + virtual uint32_t getWidth() const { return mWidth; } - virtual uint32_t getHeight() const = 0; + virtual uint32_t getHeight() const { return mHeight; } - virtual void setSize(uint32_t width, uint32_t height) = 0; + virtual void setSize(uint32_t width, uint32_t height) { mWidth = width; mHeight = height; } - virtual void setBlend(bool blend) = 0; + virtual void setBlend(bool blend) { mBlend = blend; } - virtual bool isBlend() const = 0; + virtual bool isBlend() const { return mBlend; } inline void setForceFilter(bool forceFilter) { this->forceFilter = forceFilter; } @@ -84,9 +80,9 @@ public: inline sk_sp<SkColorFilter> getColorSpaceWithFilter() const { return mColorSpaceWithFilter; } - inline mat4& getTexTransform() { return texTransform; } + inline SkMatrix& getTexTransform() { return texTransform; } - inline mat4& getTransform() { return transform; } + inline SkMatrix& getTransform() { return transform; } /** * Posts a decStrong call to the appropriate thread. @@ -94,16 +90,17 @@ public: */ void postDecStrong(); + inline void setImage(const sk_sp<SkImage>& image) { this->layerImage = image; } + + inline sk_sp<SkImage> getImage() const { return this->layerImage; } + protected: - Layer(RenderState& renderState, Api api, sk_sp<SkColorFilter>, int alpha, SkBlendMode mode); RenderState& mRenderState; private: void buildColorSpaceWithFilter(); - Api mApi; - /** * Color filter used to draw this layer. Optional. */ @@ -137,12 +134,32 @@ private: /** * Optional texture coordinates transform. */ - mat4 texTransform; + SkMatrix texTransform; /** * Optional transform. */ - mat4 transform; + SkMatrix transform; + + /** + * An image backing the layer. + */ + sk_sp<SkImage> layerImage; + + /** + * layer width. + */ + uint32_t mWidth = 0; + + /** + * layer height. + */ + uint32_t mHeight = 0; + + /** + * enable blending + */ + bool mBlend = false; }; // struct Layer diff --git a/libs/hwui/PixelBuffer.cpp b/libs/hwui/PixelBuffer.cpp deleted file mode 100644 index 910a9889db1f..000000000000 --- a/libs/hwui/PixelBuffer.cpp +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2013 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 "PixelBuffer.h" - -#include "Debug.h" -#include "Extensions.h" -#include "Properties.h" -#include "renderstate/RenderState.h" -#include "utils/GLUtils.h" - -#include <utils/Log.h> - -namespace android { -namespace uirenderer { - -/////////////////////////////////////////////////////////////////////////////// -// CPU pixel buffer -/////////////////////////////////////////////////////////////////////////////// - -class CpuPixelBuffer : public PixelBuffer { -public: - CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height); - - uint8_t* map(AccessMode mode = kAccessMode_ReadWrite) override; - - void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) override; - -protected: - void unmap() override; - -private: - std::unique_ptr<uint8_t[]> mBuffer; -}; - -CpuPixelBuffer::CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height) - : PixelBuffer(format, width, height) - , mBuffer(new uint8_t[width * height * formatSize(format)]) {} - -uint8_t* CpuPixelBuffer::map(AccessMode mode) { - if (mAccessMode == kAccessMode_None) { - mAccessMode = mode; - } - return mBuffer.get(); -} - -void CpuPixelBuffer::unmap() { - mAccessMode = kAccessMode_None; -} - -void CpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) { - glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat, GL_UNSIGNED_BYTE, - &mBuffer[offset]); -} - -/////////////////////////////////////////////////////////////////////////////// -// GPU pixel buffer -/////////////////////////////////////////////////////////////////////////////// - -class GpuPixelBuffer : public PixelBuffer { -public: - GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height); - ~GpuPixelBuffer(); - - uint8_t* map(AccessMode mode = kAccessMode_ReadWrite) override; - - void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) override; - -protected: - void unmap() override; - -private: - GLuint mBuffer; - uint8_t* mMappedPointer; - Caches& mCaches; -}; - -GpuPixelBuffer::GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height) - : PixelBuffer(format, width, height) - , mMappedPointer(nullptr) - , mCaches(Caches::getInstance()) { - glGenBuffers(1, &mBuffer); - - mCaches.pixelBufferState().bind(mBuffer); - glBufferData(GL_PIXEL_UNPACK_BUFFER, getSize(), nullptr, GL_DYNAMIC_DRAW); - mCaches.pixelBufferState().unbind(); -} - -GpuPixelBuffer::~GpuPixelBuffer() { - glDeleteBuffers(1, &mBuffer); -} - -uint8_t* GpuPixelBuffer::map(AccessMode mode) { - if (mAccessMode == kAccessMode_None) { - mCaches.pixelBufferState().bind(mBuffer); - mMappedPointer = (uint8_t*)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, getSize(), mode); - if (CC_UNLIKELY(!mMappedPointer)) { - GLUtils::dumpGLErrors(); - LOG_ALWAYS_FATAL("Failed to map PBO"); - } - mAccessMode = mode; - mCaches.pixelBufferState().unbind(); - } - - return mMappedPointer; -} - -void GpuPixelBuffer::unmap() { - if (mAccessMode != kAccessMode_None) { - if (mMappedPointer) { - mCaches.pixelBufferState().bind(mBuffer); - GLboolean status = glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); - if (status == GL_FALSE) { - ALOGE("Corrupted GPU pixel buffer"); - } - } - mAccessMode = kAccessMode_None; - mMappedPointer = nullptr; - } -} - -void GpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) { - // If the buffer is not mapped, unmap() will not bind it - mCaches.pixelBufferState().bind(mBuffer); - unmap(); - glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat, GL_UNSIGNED_BYTE, - reinterpret_cast<void*>(offset)); - mCaches.pixelBufferState().unbind(); -} - -/////////////////////////////////////////////////////////////////////////////// -// Factory -/////////////////////////////////////////////////////////////////////////////// - -PixelBuffer* PixelBuffer::create(GLenum format, uint32_t width, uint32_t height, BufferType type) { - if (type == kBufferType_Auto && Caches::getInstance().gpuPixelBuffersEnabled) { - return new GpuPixelBuffer(format, width, height); - } - return new CpuPixelBuffer(format, width, height); -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/PixelBuffer.h b/libs/hwui/PixelBuffer.h deleted file mode 100644 index e7e341b90ad3..000000000000 --- a/libs/hwui/PixelBuffer.h +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright (C) 2013 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. - */ - -#ifndef ANDROID_HWUI_PIXEL_BUFFER_H -#define ANDROID_HWUI_PIXEL_BUFFER_H - -#include <GLES3/gl3.h> - -#include <log/log.h> - -namespace android { -namespace uirenderer { - -/** - * Represents a pixel buffer. A pixel buffer will be backed either by a - * PBO on OpenGL ES 3.0 and higher or by an array of uint8_t on other - * versions. If the buffer is backed by a PBO it will of type - * GL_PIXEL_UNPACK_BUFFER. - * - * To read from or write into a PixelBuffer you must first map the - * buffer using the map(AccessMode) method. This method returns a - * pointer to the beginning of the buffer. - * - * Before the buffer can be used by the GPU, for instance to upload - * a texture, you must first unmap the buffer. To do so, call the - * unmap() method. - * - * Mapping and unmapping a PixelBuffer can have the side effect of - * changing the currently active GL_PIXEL_UNPACK_BUFFER. It is - * therefore recommended to call Caches::unbindPixelbuffer() after - * using a PixelBuffer to upload to a texture. - */ -class PixelBuffer { -public: - enum BufferType { kBufferType_Auto, kBufferType_CPU }; - - enum AccessMode { - kAccessMode_None = 0, - kAccessMode_Read = GL_MAP_READ_BIT, - kAccessMode_Write = GL_MAP_WRITE_BIT, - kAccessMode_ReadWrite = GL_MAP_READ_BIT | GL_MAP_WRITE_BIT - }; - - /** - * Creates a new PixelBuffer object with the specified format and - * dimensions. The buffer is immediately allocated. - * - * The buffer type specifies how the buffer should be allocated. - * By default this method will automatically choose whether to allocate - * a CPU or GPU buffer. - */ - static PixelBuffer* create(GLenum format, uint32_t width, uint32_t height, - BufferType type = kBufferType_Auto); - - virtual ~PixelBuffer() {} - - /** - * Returns the format of this render buffer. - */ - GLenum getFormat() const { return mFormat; } - - /** - * Maps this before with the specified access mode. This method - * returns a pointer to the region of memory where the buffer was - * mapped. - * - * If the buffer is already mapped when this method is invoked, - * this method will return the previously mapped pointer. The - * access mode can only be changed by calling unmap() first. - * - * The specified access mode cannot be kAccessMode_None. - */ - virtual uint8_t* map(AccessMode mode = kAccessMode_ReadWrite) = 0; - - /** - * Returns the current access mode for this buffer. If the buffer - * is not mapped, this method returns kAccessMode_None. - */ - AccessMode getAccessMode() const { return mAccessMode; } - - /** - * Upload the specified rectangle of this pixel buffer as a - * GL_TEXTURE_2D texture. Calling this method will trigger - * an unmap() if necessary. - */ - virtual void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) = 0; - - /** - * Upload the specified rectangle of this pixel buffer as a - * GL_TEXTURE_2D texture. Calling this method will trigger - * an unmap() if necessary. - * - * This is a convenience function provided to save callers the - * trouble of computing the offset parameter. - */ - void upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height) { - upload(x, y, width, height, getOffset(x, y)); - } - - /** - * Returns the width of the render buffer in pixels. - */ - uint32_t getWidth() const { return mWidth; } - - /** - * Returns the height of the render buffer in pixels. - */ - uint32_t getHeight() const { return mHeight; } - - /** - * Returns the size of this pixel buffer in bytes. - */ - uint32_t getSize() const { return mWidth * mHeight * formatSize(mFormat); } - - /** - * Returns the offset of a pixel in this pixel buffer, in bytes. - */ - uint32_t getOffset(uint32_t x, uint32_t y) const { - return (y * mWidth + x) * formatSize(mFormat); - } - - /** - * Returns the number of bytes per pixel in the specified format. - * - * Supported formats: - * GL_ALPHA - * GL_RGBA - */ - static uint32_t formatSize(GLenum format) { - switch (format) { - case GL_ALPHA: - return 1; - case GL_RGBA: - return 4; - } - return 0; - } - - /** - * Returns the alpha channel offset in the specified format. - * - * Supported formats: - * GL_ALPHA - * GL_RGBA - */ - static uint32_t formatAlphaOffset(GLenum format) { - switch (format) { - case GL_ALPHA: - return 0; - case GL_RGBA: - return 3; - } - - ALOGE("unsupported format: %d", format); - return 0; - } - -protected: - /** - * Creates a new render buffer in the specified format and dimensions. - * The format must be GL_ALPHA or GL_RGBA. - */ - PixelBuffer(GLenum format, uint32_t width, uint32_t height) - : mFormat(format), mWidth(width), mHeight(height), mAccessMode(kAccessMode_None) {} - - /** - * Unmaps this buffer, if needed. After the buffer is unmapped, - * the pointer previously returned by map() becomes invalid and - * should not be used. - */ - virtual void unmap() = 0; - - GLenum mFormat; - - uint32_t mWidth; - uint32_t mHeight; - - AccessMode mAccessMode; - -}; // class PixelBuffer - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_PIXEL_BUFFER_H diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h index 0766e3b7ed28..7966845ff814 100644 --- a/libs/hwui/RenderProperties.h +++ b/libs/hwui/RenderProperties.h @@ -16,7 +16,6 @@ #pragma once -#include "Caches.h" #include "DeviceInfo.h" #include "Outline.h" #include "Rect.h" diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp index 464a58d0c0f8..65bee476f14d 100644 --- a/libs/hwui/ResourceCache.cpp +++ b/libs/hwui/ResourceCache.cpp @@ -15,7 +15,6 @@ */ #include "ResourceCache.h" -#include "Caches.h" namespace android { @@ -112,13 +111,9 @@ void ResourceCache::destructorLocked(Res_png_9patch* resource) { ResourceReference* ref = index >= 0 ? mCache->valueAt(index) : nullptr; if (ref == nullptr) { // If we're not tracking this resource, just delete it - if (Caches::hasInstance()) { - // DEAD CODE - } else { - // A Res_png_9patch is actually an array of byte that's larger - // than sizeof(Res_png_9patch). It must be freed as an array. - delete[](int8_t*) resource; - } + // A Res_png_9patch is actually an array of byte that's larger + // than sizeof(Res_png_9patch). It must be freed as an array. + delete[](int8_t*) resource; return; } ref->destroyed = true; @@ -135,14 +130,10 @@ void ResourceCache::deleteResourceReferenceLocked(const void* resource, Resource if (ref->destroyed) { switch (ref->resourceType) { case kNinePatch: { - if (Caches::hasInstance()) { - // DEAD CODE - } else { - // A Res_png_9patch is actually an array of byte that's larger - // than sizeof(Res_png_9patch). It must be freed as an array. - int8_t* patch = (int8_t*)resource; - delete[] patch; - } + // A Res_png_9patch is actually an array of byte that's larger + // than sizeof(Res_png_9patch). It must be freed as an array. + int8_t* patch = (int8_t*)resource; + delete[] patch; } break; } } diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp deleted file mode 100644 index 1e90eebe3bb8..000000000000 --- a/libs/hwui/Texture.cpp +++ /dev/null @@ -1,413 +0,0 @@ -/* - * Copyright (C) 2013 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 "Texture.h" -#include "Caches.h" -#include "utils/GLUtils.h" -#include "utils/MathUtils.h" -#include "utils/TraceUtils.h" - -#include <utils/Log.h> - -#include <math/mat4.h> - -#include <SkCanvas.h> - -namespace android { -namespace uirenderer { - -// Number of bytes used by a texture in the given format -static int bytesPerPixel(GLint glFormat) { - switch (glFormat) { - // The wrapped-texture case, usually means a SurfaceTexture - case 0: - return 0; - case GL_LUMINANCE: - case GL_ALPHA: - return 1; - case GL_SRGB8: - case GL_RGB: - return 3; - case GL_SRGB8_ALPHA8: - case GL_RGBA: - return 4; - case GL_RGBA16F: - return 8; - default: - LOG_ALWAYS_FATAL("UNKNOWN FORMAT 0x%x", glFormat); - } -} - -void Texture::setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture, bool force) { - if (force || wrapS != mWrapS || wrapT != mWrapT) { - mWrapS = wrapS; - mWrapT = wrapT; - - if (bindTexture) { - mCaches.textureState().bindTexture(mTarget, mId); - } - - glTexParameteri(mTarget, GL_TEXTURE_WRAP_S, wrapS); - glTexParameteri(mTarget, GL_TEXTURE_WRAP_T, wrapT); - } -} - -void Texture::setFilterMinMag(GLenum min, GLenum mag, bool bindTexture, bool force) { - if (force || min != mMinFilter || mag != mMagFilter) { - mMinFilter = min; - mMagFilter = mag; - - if (bindTexture) { - mCaches.textureState().bindTexture(mTarget, mId); - } - - if (mipMap && min == GL_LINEAR) min = GL_LINEAR_MIPMAP_LINEAR; - - glTexParameteri(mTarget, GL_TEXTURE_MIN_FILTER, min); - glTexParameteri(mTarget, GL_TEXTURE_MAG_FILTER, mag); - } -} - -void Texture::deleteTexture() { - mCaches.textureState().deleteTexture(mId); - mId = 0; - mTarget = GL_NONE; - if (mEglImageHandle != EGL_NO_IMAGE_KHR) { - EGLDisplay eglDisplayHandle = eglGetCurrentDisplay(); - eglDestroyImageKHR(eglDisplayHandle, mEglImageHandle); - mEglImageHandle = EGL_NO_IMAGE_KHR; - } -} - -bool Texture::updateLayout(uint32_t width, uint32_t height, GLint internalFormat, GLint format, - GLenum target) { - if (mWidth == width && mHeight == height && mFormat == format && - mInternalFormat == internalFormat && mTarget == target) { - return false; - } - mWidth = width; - mHeight = height; - mFormat = format; - mInternalFormat = internalFormat; - mTarget = target; - notifySizeChanged(mWidth * mHeight * bytesPerPixel(internalFormat)); - return true; -} - -void Texture::resetCachedParams() { - mWrapS = GL_REPEAT; - mWrapT = GL_REPEAT; - mMinFilter = GL_NEAREST_MIPMAP_LINEAR; - mMagFilter = GL_LINEAR; -} - -void Texture::upload(GLint internalFormat, uint32_t width, uint32_t height, GLenum format, - GLenum type, const void* pixels) { - GL_CHECKPOINT(MODERATE); - - // We don't have color space information, we assume the data is gamma encoded - mIsLinear = false; - - bool needsAlloc = updateLayout(width, height, internalFormat, format, GL_TEXTURE_2D); - if (!mId) { - glGenTextures(1, &mId); - needsAlloc = true; - resetCachedParams(); - } - mCaches.textureState().bindTexture(GL_TEXTURE_2D, mId); - if (needsAlloc) { - glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, mWidth, mHeight, 0, format, type, pixels); - } else if (pixels) { - glTexSubImage2D(GL_TEXTURE_2D, 0, internalFormat, mWidth, mHeight, 0, format, type, pixels); - } - GL_CHECKPOINT(MODERATE); -} - -void Texture::uploadHardwareBitmapToTexture(GraphicBuffer* buffer) { - EGLDisplay eglDisplayHandle = eglGetCurrentDisplay(); - if (mEglImageHandle != EGL_NO_IMAGE_KHR) { - eglDestroyImageKHR(eglDisplayHandle, mEglImageHandle); - mEglImageHandle = EGL_NO_IMAGE_KHR; - } - mEglImageHandle = eglCreateImageKHR(eglDisplayHandle, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, - buffer->getNativeBuffer(), 0); - glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, mEglImageHandle); -} - -static void uploadToTexture(bool resize, GLint internalFormat, GLenum format, GLenum type, - GLsizei stride, GLsizei bpp, GLsizei width, GLsizei height, - const GLvoid* data) { - const bool useStride = - stride != width && Caches::getInstance().extensions().hasUnpackRowLength(); - if ((stride == width) || useStride) { - if (useStride) { - glPixelStorei(GL_UNPACK_ROW_LENGTH, stride); - } - - if (resize) { - glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, data); - } else { - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data); - } - - if (useStride) { - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - } - } else { - // With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer - // if the stride doesn't match the width - - GLvoid* temp = (GLvoid*)malloc(width * height * bpp); - if (!temp) return; - - uint8_t* pDst = (uint8_t*)temp; - uint8_t* pSrc = (uint8_t*)data; - for (GLsizei i = 0; i < height; i++) { - memcpy(pDst, pSrc, width * bpp); - pDst += width * bpp; - pSrc += stride * bpp; - } - - if (resize) { - glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, type, temp); - } else { - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, temp); - } - - free(temp); - } -} - -void Texture::colorTypeToGlFormatAndType(const Caches& caches, SkColorType colorType, bool needSRGB, - GLint* outInternalFormat, GLint* outFormat, - GLint* outType) { - switch (colorType) { - case kAlpha_8_SkColorType: - *outFormat = GL_ALPHA; - *outInternalFormat = GL_ALPHA; - *outType = GL_UNSIGNED_BYTE; - break; - case kRGB_565_SkColorType: - if (needSRGB) { - // We would ideally use a GL_RGB/GL_SRGB8 texture but the - // intermediate Skia bitmap needs to be ARGB_8888 - *outFormat = GL_RGBA; - *outInternalFormat = caches.rgbaInternalFormat(); - *outType = GL_UNSIGNED_BYTE; - } else { - *outFormat = GL_RGB; - *outInternalFormat = GL_RGB; - *outType = GL_UNSIGNED_SHORT_5_6_5; - } - break; - // ARGB_4444 is upconverted to RGBA_8888 - case kARGB_4444_SkColorType: - case kN32_SkColorType: - *outFormat = GL_RGBA; - *outInternalFormat = caches.rgbaInternalFormat(needSRGB); - *outType = GL_UNSIGNED_BYTE; - break; - case kGray_8_SkColorType: - *outFormat = GL_LUMINANCE; - *outInternalFormat = GL_LUMINANCE; - *outType = GL_UNSIGNED_BYTE; - break; - case kRGBA_F16_SkColorType: - if (caches.extensions().getMajorGlVersion() >= 3) { - // This format is always linear - *outFormat = GL_RGBA; - *outInternalFormat = GL_RGBA16F; - *outType = GL_HALF_FLOAT; - } else { - *outFormat = GL_RGBA; - *outInternalFormat = caches.rgbaInternalFormat(true); - *outType = GL_UNSIGNED_BYTE; - } - break; - default: - LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", colorType); - break; - } -} - -SkBitmap Texture::uploadToN32(const SkBitmap& bitmap, bool hasLinearBlending, - sk_sp<SkColorSpace> sRGB) { - SkBitmap rgbaBitmap; - rgbaBitmap.allocPixels(SkImageInfo::MakeN32(bitmap.width(), bitmap.height(), - bitmap.info().alphaType(), - hasLinearBlending ? sRGB : nullptr)); - rgbaBitmap.eraseColor(0); - - if (bitmap.colorType() == kRGBA_F16_SkColorType) { - // Drawing RGBA_F16 onto ARGB_8888 is not supported - bitmap.readPixels(rgbaBitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()), - rgbaBitmap.getPixels(), rgbaBitmap.rowBytes(), 0, 0); - } else { - SkCanvas canvas(rgbaBitmap); - canvas.drawBitmap(bitmap, 0.0f, 0.0f, nullptr); - } - - return rgbaBitmap; -} - -bool Texture::hasUnsupportedColorType(const SkImageInfo& info, bool hasLinearBlending) { - return info.colorType() == kARGB_4444_SkColorType || - (info.colorType() == kRGB_565_SkColorType && hasLinearBlending && - info.colorSpace()->isSRGB()) || - (info.colorType() == kRGBA_F16_SkColorType && - Caches::getInstance().extensions().getMajorGlVersion() < 3); -} - -void Texture::upload(Bitmap& bitmap) { - ATRACE_FORMAT("Upload %ux%u Texture", bitmap.width(), bitmap.height()); - - // We could also enable mipmapping if both bitmap dimensions are powers - // of 2 but we'd have to deal with size changes. Let's keep this simple - const bool canMipMap = mCaches.extensions().hasNPot(); - - // If the texture had mipmap enabled but not anymore, - // force a glTexImage2D to discard the mipmap levels - bool needsAlloc = canMipMap && mipMap && !bitmap.hasHardwareMipMap(); - bool setDefaultParams = false; - - if (!mId) { - glGenTextures(1, &mId); - needsAlloc = true; - setDefaultParams = true; - } - - bool hasLinearBlending = mCaches.extensions().hasLinearBlending(); - bool needSRGB = transferFunctionCloseToSRGB(bitmap.info().colorSpace()); - - GLint internalFormat, format, type; - colorTypeToGlFormatAndType(mCaches, bitmap.colorType(), needSRGB && hasLinearBlending, - &internalFormat, &format, &type); - - // Some devices don't support GL_RGBA16F, so we need to compare the color type - // and internal GL format to decide what to do with 16 bit bitmaps - bool rgba16fNeedsConversion = - bitmap.colorType() == kRGBA_F16_SkColorType && internalFormat != GL_RGBA16F; - - // RGBA16F is always linear extended sRGB - if (internalFormat == GL_RGBA16F) { - mIsLinear = true; - } - - mConnector.reset(); - - // Alpha masks don't have color profiles - // If an RGBA16F bitmap needs conversion, we know the target will be sRGB - if (!mIsLinear && internalFormat != GL_ALPHA && !rgba16fNeedsConversion) { - SkColorSpace* colorSpace = bitmap.info().colorSpace(); - // If the bitmap is sRGB we don't need conversion - if (colorSpace != nullptr && !colorSpace->isSRGB()) { - SkMatrix44 xyzMatrix(SkMatrix44::kUninitialized_Constructor); - if (!colorSpace->toXYZD50(&xyzMatrix)) { - ALOGW("Incompatible color space!"); - } else { - SkColorSpaceTransferFn fn; - if (!colorSpace->isNumericalTransferFn(&fn)) { - ALOGW("Incompatible color space, no numerical transfer function!"); - } else { - float data[16]; - xyzMatrix.asColMajorf(data); - - ColorSpace::TransferParameters p = {fn.fG, fn.fA, fn.fB, fn.fC, - fn.fD, fn.fE, fn.fF}; - ColorSpace src("Unnamed", mat4f((const float*)&data[0]).upperLeft(), p); - mConnector.reset(new ColorSpaceConnector(src, ColorSpace::sRGB())); - - // A non-sRGB color space might have a transfer function close enough to sRGB - // that we can save shader instructions by using an sRGB sampler - // This is only possible if we have hardware support for sRGB textures - if (needSRGB && internalFormat == GL_RGBA && mCaches.extensions().hasSRGB() && - !bitmap.isHardware()) { - internalFormat = GL_SRGB8_ALPHA8; - } - } - } - } - } - - GLenum target = bitmap.isHardware() ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D; - needsAlloc |= updateLayout(bitmap.width(), bitmap.height(), internalFormat, format, target); - - blend = !bitmap.isOpaque(); - mCaches.textureState().bindTexture(mTarget, mId); - - // TODO: Handle sRGB gray bitmaps - if (CC_UNLIKELY(hasUnsupportedColorType(bitmap.info(), hasLinearBlending))) { - SkBitmap skBitmap; - bitmap.getSkBitmap(&skBitmap); - sk_sp<SkColorSpace> sRGB = SkColorSpace::MakeSRGB(); - SkBitmap rgbaBitmap = uploadToN32(skBitmap, hasLinearBlending, std::move(sRGB)); - uploadToTexture(needsAlloc, internalFormat, format, type, rgbaBitmap.rowBytesAsPixels(), - rgbaBitmap.bytesPerPixel(), rgbaBitmap.width(), rgbaBitmap.height(), - rgbaBitmap.getPixels()); - } else if (bitmap.isHardware()) { - uploadHardwareBitmapToTexture(bitmap.graphicBuffer()); - } else { - uploadToTexture(needsAlloc, internalFormat, format, type, bitmap.rowBytesAsPixels(), - bitmap.info().bytesPerPixel(), bitmap.width(), bitmap.height(), - bitmap.pixels()); - } - - if (canMipMap) { - mipMap = bitmap.hasHardwareMipMap(); - if (mipMap) { - glGenerateMipmap(GL_TEXTURE_2D); - } - } - - if (setDefaultParams) { - setFilter(GL_NEAREST); - setWrap(GL_CLAMP_TO_EDGE); - } -} - -void Texture::wrap(GLuint id, uint32_t width, uint32_t height, GLint internalFormat, GLint format, - GLenum target) { - mId = id; - mWidth = width; - mHeight = height; - mFormat = format; - mInternalFormat = internalFormat; - mTarget = target; - mConnector.reset(); - // We're wrapping an existing texture, so don't double count this memory - notifySizeChanged(0); -} - -TransferFunctionType Texture::getTransferFunctionType() const { - if (mConnector.get() != nullptr && mInternalFormat != GL_SRGB8_ALPHA8) { - const ColorSpace::TransferParameters& p = mConnector->getSource().getTransferParameters(); - if (MathUtils::isZero(p.e) && MathUtils::isZero(p.f)) { - if (MathUtils::areEqual(p.a, 1.0f) && MathUtils::isZero(p.b) && - MathUtils::isZero(p.c) && MathUtils::isZero(p.d)) { - if (MathUtils::areEqual(p.g, 1.0f)) { - return TransferFunctionType::None; - } - return TransferFunctionType::Gamma; - } - return TransferFunctionType::Limited; - } - return TransferFunctionType::Full; - } - return TransferFunctionType::None; -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h deleted file mode 100644 index 5b7e4e261f30..000000000000 --- a/libs/hwui/Texture.h +++ /dev/null @@ -1,228 +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. - */ - -#ifndef ANDROID_HWUI_TEXTURE_H -#define ANDROID_HWUI_TEXTURE_H - -#include "GpuMemoryTracker.h" -#include "hwui/Bitmap.h" -#include "utils/Color.h" - -#include <memory> - -#include <math/mat3.h> - -#include <ui/ColorSpace.h> - -#include <EGL/egl.h> -#include <EGL/eglext.h> -#include <GLES2/gl2.h> -#include <GLES3/gl3.h> -#include <SkBitmap.h> - -namespace android { - -class GraphicBuffer; - -namespace uirenderer { - -class Caches; -class UvMapper; -class Layer; - -/** - * Represents an OpenGL texture. - */ -class Texture : public GpuMemoryTracker { -public: - static SkBitmap uploadToN32(const SkBitmap& bitmap, bool hasLinearBlending, - sk_sp<SkColorSpace> sRGB); - static bool hasUnsupportedColorType(const SkImageInfo& info, bool hasLinearBlending); - static void colorTypeToGlFormatAndType(const Caches& caches, SkColorType colorType, - bool needSRGB, GLint* outInternalFormat, - GLint* outFormat, GLint* outType); - - explicit Texture(Caches& caches) : GpuMemoryTracker(GpuObjectType::Texture), mCaches(caches) {} - - virtual ~Texture() {} - - inline void setWrap(GLenum wrap, bool bindTexture = false, bool force = false) { - setWrapST(wrap, wrap, bindTexture, force); - } - - virtual void setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture = false, - bool force = false); - - inline void setFilter(GLenum filter, bool bindTexture = false, bool force = false) { - setFilterMinMag(filter, filter, bindTexture, force); - } - - virtual void setFilterMinMag(GLenum min, GLenum mag, bool bindTexture = false, - bool force = false); - - /** - * Convenience method to call glDeleteTextures() on this texture's id. - */ - void deleteTexture(); - - /** - * Sets the width, height, and format of the texture along with allocating - * the texture ID. Does nothing if the width, height, and format are already - * the requested values. - * - * The image data is undefined after calling this. - */ - void resize(uint32_t width, uint32_t height, GLint internalFormat, GLint format) { - upload(internalFormat, width, height, format, - internalFormat == GL_RGBA16F ? GL_HALF_FLOAT : GL_UNSIGNED_BYTE, nullptr); - } - - /** - * Updates this Texture with the contents of the provided Bitmap, - * also setting the appropriate width, height, and format. It is not necessary - * to call resize() prior to this. - * - * Note this does not set the generation from the Bitmap. - */ - void upload(Bitmap& source); - - /** - * Basically glTexImage2D/glTexSubImage2D. - */ - void upload(GLint internalFormat, uint32_t width, uint32_t height, GLenum format, GLenum type, - const void* pixels); - - /** - * Wraps an existing texture. - */ - void wrap(GLuint id, uint32_t width, uint32_t height, GLint internalFormat, GLint format, - GLenum target); - - GLuint id() const { return mId; } - - uint32_t width() const { return mWidth; } - - uint32_t height() const { return mHeight; } - - GLint format() const { return mFormat; } - - GLint internalFormat() const { return mInternalFormat; } - - GLenum target() const { return mTarget; } - - /** - * Returns nullptr if this texture does not require color space conversion - * to sRGB, or a valid pointer to a ColorSpaceConnector if a conversion - * is required. - */ - constexpr const ColorSpaceConnector* getColorSpaceConnector() const { return mConnector.get(); } - - constexpr bool hasColorSpaceConversion() const { return mConnector.get() != nullptr; } - - TransferFunctionType getTransferFunctionType() const; - - /** - * Returns true if this texture uses a linear encoding format. - */ - constexpr bool isLinear() const { return mIsLinear; } - - /** - * Generation of the backing bitmap, - */ - uint32_t generation = 0; - /** - * Indicates whether the texture requires blending. - */ - bool blend = false; - /** - * Indicates whether this texture should be cleaned up after use. - */ - bool cleanup = false; - /** - * Optional, size of the original bitmap. - */ - uint32_t bitmapSize = 0; - /** - * Indicates whether this texture will use trilinear filtering. - */ - bool mipMap = false; - - /** - * Optional, pointer to a texture coordinates mapper. - */ - const UvMapper* uvMapper = nullptr; - - /** - * Whether or not the Texture is marked in use and thus not evictable for - * the current frame. This is reset at the start of a new frame. - */ - void* isInUse = nullptr; - -private: - // TODO: Temporarily grant private access to GlLayer, remove once - // GlLayer can be de-tangled from being a dual-purpose render target - // and external texture wrapper - friend class GlLayer; - - // Returns true if the texture layout (size, format, etc.) changed, false if it was the same - bool updateLayout(uint32_t width, uint32_t height, GLint internalFormat, GLint format, - GLenum target); - void uploadHardwareBitmapToTexture(GraphicBuffer* buffer); - void resetCachedParams(); - - GLuint mId = 0; - uint32_t mWidth = 0; - uint32_t mHeight = 0; - GLint mFormat = 0; - GLint mInternalFormat = 0; - GLenum mTarget = GL_NONE; - EGLImageKHR mEglImageHandle = EGL_NO_IMAGE_KHR; - - /* See GLES spec section 3.8.14 - * "In the initial state, the value assigned to TEXTURE_MIN_FILTER is - * NEAREST_MIPMAP_LINEAR and the value for TEXTURE_MAG_FILTER is LINEAR. - * s, t, and r wrap modes are all set to REPEAT." - */ - GLenum mWrapS = GL_REPEAT; - GLenum mWrapT = GL_REPEAT; - GLenum mMinFilter = GL_NEAREST_MIPMAP_LINEAR; - GLenum mMagFilter = GL_LINEAR; - - // Indicates whether the content of the texture is in linear space - bool mIsLinear = false; - - Caches& mCaches; - - std::unique_ptr<ColorSpaceConnector> mConnector; -}; // struct Texture - -class AutoTexture { -public: - explicit AutoTexture(Texture* texture) : texture(texture) {} - ~AutoTexture() { - if (texture && texture->cleanup) { - texture->deleteTexture(); - delete texture; - } - } - - Texture* const texture; -}; // class AutoTexture - -}; // namespace uirenderer -}; // namespace android - -#endif // ANDROID_HWUI_TEXTURE_H diff --git a/libs/hwui/VkLayer.cpp b/libs/hwui/VkLayer.cpp deleted file mode 100644 index 30fba7ae7d9b..000000000000 --- a/libs/hwui/VkLayer.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "VkLayer.h" - -#include "renderstate/RenderState.h" - -#include <SkCanvas.h> -#include <SkSurface.h> - -namespace android { -namespace uirenderer { - -void VkLayer::updateTexture() { - sk_sp<SkSurface> surface; - SkImageInfo info = SkImageInfo::MakeS32(mWidth, mHeight, kPremul_SkAlphaType); - surface = SkSurface::MakeRenderTarget(mRenderState.getGrContext(), SkBudgeted::kNo, info); - surface->getCanvas()->clear(SK_ColorBLUE); - mImage = surface->makeImageSnapshot(); -} - -void VkLayer::onVkContextDestroyed() { - mImage = nullptr; -} - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/VkLayer.h b/libs/hwui/VkLayer.h deleted file mode 100644 index e9664d04b7a5..000000000000 --- a/libs/hwui/VkLayer.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "Layer.h" - -#include <SkImage.h> - -namespace android { -namespace uirenderer { -/** - * A layer has dimensions and is backed by a VkImage. - */ -class VkLayer : public Layer { -public: - VkLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight, - sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, bool blend) - : Layer(renderState, Api::Vulkan, colorFilter, alpha, mode) - , mWidth(layerWidth) - , mHeight(layerHeight) - , mBlend(blend) {} - - virtual ~VkLayer() {} - - uint32_t getWidth() const override { return mWidth; } - - uint32_t getHeight() const override { return mHeight; } - - void setSize(uint32_t width, uint32_t height) override { - mWidth = width; - mHeight = height; - } - - void setBlend(bool blend) override { mBlend = blend; } - - bool isBlend() const override { return mBlend; } - - sk_sp<SkImage> getImage() { return mImage; } - - void updateTexture(); - - // If we've destroyed the vulkan context (VkInstance, VkDevice, etc.), we must make sure to - // destroy any VkImages that were made with that context. - void onVkContextDestroyed(); - -private: - int mWidth; - int mHeight; - bool mBlend; - - sk_sp<SkImage> mImage; - -}; // struct VkLayer - -}; // namespace uirenderer -}; // namespace android diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index 7a8d026df3b4..e7d12de44c0c 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -15,11 +15,11 @@ */ #include "Bitmap.h" -#include "Caches.h" #include "HardwareBitmapUploader.h" #include "Properties.h" #include "renderthread/RenderProxy.h" #include "utils/Color.h" +#include <utils/Trace.h> #include <sys/mman.h> diff --git a/libs/hwui/pipeline/skia/DumpOpsCanvas.h b/libs/hwui/pipeline/skia/DumpOpsCanvas.h index 1f83d1a201b0..dcfe6b371171 100644 --- a/libs/hwui/pipeline/skia/DumpOpsCanvas.h +++ b/libs/hwui/pipeline/skia/DumpOpsCanvas.h @@ -94,11 +94,6 @@ protected: mOutput << mIdent << "drawPosTextH" << std::endl; } - void onDrawTextOnPath(const void*, size_t, const SkPath&, const SkMatrix*, - const SkPaint&) override { - mOutput << mIdent << "drawTextOnPath" << std::endl; - } - void onDrawTextRSXform(const void*, size_t, const SkRSXform[], const SkRect*, const SkPaint&) override { mOutput << mIdent << "drawTextRSXform" << std::endl; diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp index c41f6a6f0ee6..fb66b50f0159 100644 --- a/libs/hwui/pipeline/skia/LayerDrawable.cpp +++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp @@ -15,8 +15,6 @@ */ #include "LayerDrawable.h" -#include "GlLayer.h" -#include "VkLayer.h" #include "GrBackendSurface.h" #include "SkColorFilter.h" @@ -41,35 +39,14 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer return false; } // transform the matrix based on the layer - SkMatrix layerTransform; - layer->getTransform().copyTo(layerTransform); - sk_sp<SkImage> layerImage; + SkMatrix layerTransform = layer->getTransform(); + sk_sp<SkImage> layerImage = layer->getImage(); const int layerWidth = layer->getWidth(); const int layerHeight = layer->getHeight(); - if (layer->getApi() == Layer::Api::OpenGL) { - GlLayer* glLayer = static_cast<GlLayer*>(layer); - GrGLTextureInfo externalTexture; - externalTexture.fTarget = glLayer->getRenderTarget(); - externalTexture.fID = glLayer->getTextureId(); - // The format may not be GL_RGBA8, but given the DeferredLayerUpdater and GLConsumer don't - // expose that info we use it as our default. Further, given that we only use this texture - // as a source this will not impact how Skia uses the texture. The only potential affect - // this is anticipated to have is that for some format types if we are not bound as an OES - // texture we may get invalid results for SKP capture if we read back the texture. - externalTexture.fFormat = GL_RGBA8; - GrBackendTexture backendTexture(layerWidth, layerHeight, GrMipMapped::kNo, externalTexture); - layerImage = SkImage::MakeFromTexture(context, backendTexture, kTopLeft_GrSurfaceOrigin, - kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr); - } else { - SkASSERT(layer->getApi() == Layer::Api::Vulkan); - VkLayer* vkLayer = static_cast<VkLayer*>(layer); - canvas->clear(SK_ColorGREEN); - layerImage = vkLayer->getImage(); - } if (layerImage) { SkMatrix textureMatrixInv; - layer->getTexTransform().copyTo(textureMatrixInv); + textureMatrixInv = layer->getTexTransform(); // TODO: after skia bug https://bugs.chromium.org/p/skia/issues/detail?id=7075 is fixed // use bottom left origin and remove flipV and invert transformations. SkMatrix flipV; @@ -95,6 +72,9 @@ bool LayerDrawable::DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer paint.setAlpha(layer->getAlpha()); paint.setBlendMode(layer->getMode()); paint.setColorFilter(layer->getColorSpaceWithFilter()); + if (layer->getForceFilter()) { + paint.setFilterQuality(kLow_SkFilterQuality); + } const bool nonIdentityMatrix = !matrix.isIdentity(); if (nonIdentityMatrix) { diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp index 78f5a71dee3b..2ae37233098e 100644 --- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp @@ -17,7 +17,6 @@ #include "SkiaOpenGLPipeline.h" #include "DeferredLayerUpdater.h" -#include "GlLayer.h" #include "LayerDrawable.h" #include "SkiaPipeline.h" #include "SkiaProfileRenderer.h" @@ -187,18 +186,9 @@ bool SkiaOpenGLPipeline::copyLayerInto(DeferredLayerUpdater* deferredLayer, SkBi return false; } -static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight, - sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, - bool blend) { - GlLayer* layer = - new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend); - layer->generateTexture(); - return layer; -} - DeferredLayerUpdater* SkiaOpenGLPipeline::createTextureLayer() { mRenderThread.requireGlContext(); - return new DeferredLayerUpdater(mRenderThread.renderState(), createLayer, Layer::Api::OpenGL); + return new DeferredLayerUpdater(mRenderThread.renderState()); } void SkiaOpenGLPipeline::onStop() { diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp index b2519fe59891..5f2eee4523fc 100644 --- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp @@ -20,7 +20,6 @@ #include "Readback.h" #include "SkiaPipeline.h" #include "SkiaProfileRenderer.h" -#include "VkLayer.h" #include "renderstate/RenderState.h" #include "renderthread/Frame.h" @@ -114,16 +113,10 @@ bool SkiaVulkanPipeline::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bi return false; } -static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight, - sk_sp<SkColorFilter> colorFilter, int alpha, SkBlendMode mode, - bool blend) { - return new VkLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend); -} - DeferredLayerUpdater* SkiaVulkanPipeline::createTextureLayer() { mVkManager.initialize(); - return new DeferredLayerUpdater(mRenderThread.renderState(), createLayer, Layer::Api::Vulkan); + return new DeferredLayerUpdater(mRenderThread.renderState()); } void SkiaVulkanPipeline::onStop() {} diff --git a/libs/hwui/renderstate/PixelBufferState.cpp b/libs/hwui/renderstate/PixelBufferState.cpp deleted file mode 100644 index 3a6efb833c47..000000000000 --- a/libs/hwui/renderstate/PixelBufferState.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "renderstate/PixelBufferState.h" - -namespace android { -namespace uirenderer { - -PixelBufferState::PixelBufferState() : mCurrentPixelBuffer(0) {} - -bool PixelBufferState::bind(GLuint buffer) { - if (mCurrentPixelBuffer != buffer) { - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, buffer); - mCurrentPixelBuffer = buffer; - return true; - } - return false; -} - -bool PixelBufferState::unbind() { - if (mCurrentPixelBuffer) { - glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); - mCurrentPixelBuffer = 0; - return true; - } - return false; -} - -} /* namespace uirenderer */ -} /* namespace android */ diff --git a/libs/hwui/renderstate/PixelBufferState.h b/libs/hwui/renderstate/PixelBufferState.h deleted file mode 100644 index f7ae6c575f6a..000000000000 --- a/libs/hwui/renderstate/PixelBufferState.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef RENDERSTATE_PIXELBUFFERSTATE_H -#define RENDERSTATE_PIXELBUFFERSTATE_H - -#include <GLES3/gl3.h> - -namespace android { -namespace uirenderer { - -class PixelBufferState { - friend class Caches; // TODO: move to RenderState -public: - bool bind(GLuint buffer); - bool unbind(); - -private: - PixelBufferState(); - GLuint mCurrentPixelBuffer; -}; - -} /* namespace uirenderer */ -} /* namespace android */ - -#endif // RENDERSTATE_PIXELBUFFERSTATE_H diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp index 3be84f588a20..b524bcb096da 100644 --- a/libs/hwui/renderstate/RenderState.cpp +++ b/libs/hwui/renderstate/RenderState.cpp @@ -16,8 +16,6 @@ #include "renderstate/RenderState.h" #include <GpuMemoryTracker.h> #include "DeferredLayerUpdater.h" -#include "GlLayer.h" -#include "VkLayer.h" #include "Snapshot.h" #include "renderthread/CanvasContext.h" @@ -39,44 +37,11 @@ RenderState::RenderState(renderthread::RenderThread& thread) RenderState::~RenderState() { } -void RenderState::onGLContextCreated() { +void RenderState::onContextCreated() { GpuMemoryTracker::onGpuContextCreated(); - - // This is delayed because the first access of Caches makes GL calls - if (!mCaches) { - mCaches = &Caches::createInstance(*this); - } - mCaches->init(); } -static void layerLostGlContext(Layer* layer) { - LOG_ALWAYS_FATAL_IF(layer->getApi() != Layer::Api::OpenGL, - "layerLostGlContext on non GL layer"); - static_cast<GlLayer*>(layer)->onGlContextLost(); -} - -void RenderState::onGLContextDestroyed() { - // TODO: reset all cached state in state objects - std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerLostGlContext); - - mCaches->terminate(); - - destroyLayersInUpdater(); - GpuMemoryTracker::onGpuContextDestroyed(); -} - -void RenderState::onVkContextCreated() { - GpuMemoryTracker::onGpuContextCreated(); -} - -static void layerDestroyedVkContext(Layer* layer) { - LOG_ALWAYS_FATAL_IF(layer->getApi() != Layer::Api::Vulkan, - "layerLostVkContext on non Vulkan layer"); - static_cast<VkLayer*>(layer)->onVkContextDestroyed(); -} - -void RenderState::onVkContextDestroyed() { - std::for_each(mActiveLayers.begin(), mActiveLayers.end(), layerDestroyedVkContext); +void RenderState::onContextDestroyed() { destroyLayersInUpdater(); GpuMemoryTracker::onGpuContextDestroyed(); } @@ -85,10 +50,6 @@ GrContext* RenderState::getGrContext() const { return mRenderThread.getGrContext(); } -void RenderState::flush(Caches::FlushMode mode) { - if (mCaches) mCaches->flush(mode); -} - void RenderState::onBitmapDestroyed(uint32_t pixelRefId) { // DEAD CODE } @@ -126,42 +87,6 @@ void RenderState::deleteFramebuffer(GLuint fbo) { glDeleteFramebuffers(1, &fbo); } -void RenderState::invokeFunctor(Functor* functor, DrawGlInfo::Mode mode, DrawGlInfo* info) { - if (mode == DrawGlInfo::kModeProcessNoContext) { - // If there's no context we don't need to interrupt as there's - // no gl state to save/restore - (*functor)(mode, info); - } else { - interruptForFunctorInvoke(); - (*functor)(mode, info); - resumeFromFunctorInvoke(); - } -} - -void RenderState::interruptForFunctorInvoke() { - mCaches->textureState().resetActiveTexture(); - debugOverdraw(false, false); - // TODO: We need a way to know whether the functor is sRGB aware (b/32072673) - if (mCaches->extensions().hasLinearBlending() && mCaches->extensions().hasSRGBWriteControl()) { - glDisable(GL_FRAMEBUFFER_SRGB_EXT); - } -} - -void RenderState::resumeFromFunctorInvoke() { - if (mCaches->extensions().hasLinearBlending() && mCaches->extensions().hasSRGBWriteControl()) { - glEnable(GL_FRAMEBUFFER_SRGB_EXT); - } - - glViewport(0, 0, mViewportWidth, mViewportHeight); - glBindFramebuffer(GL_FRAMEBUFFER, mFramebuffer); - debugOverdraw(false, false); - - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - - mCaches->textureState().activateTexture(0); - mCaches->textureState().resetBoundTextures(); -} - void RenderState::debugOverdraw(bool enable, bool clear) { // DEAD CODE } @@ -190,5 +115,9 @@ void RenderState::dump() { // DEAD CODE } +renderthread::RenderThread& RenderState::getRenderThread() { + return mRenderThread; +} + } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h index 97785a46dcd7..f39aa4b96547 100644 --- a/libs/hwui/renderstate/RenderState.h +++ b/libs/hwui/renderstate/RenderState.h @@ -16,8 +16,6 @@ #ifndef RENDERSTATE_H #define RENDERSTATE_H -#include "Caches.h" -#include "renderstate/PixelBufferState.h" #include "utils/Macros.h" #include <GLES2/gl2.h> @@ -34,7 +32,6 @@ class GrContext; namespace android { namespace uirenderer { -class Caches; class Layer; class DeferredLayerUpdater; @@ -44,22 +41,16 @@ class CanvasContext; class RenderThread; } -// TODO: Replace Cache's GL state tracking with this. For now it's more a thin // wrapper of Caches for users to migrate to. class RenderState { PREVENT_COPY_AND_ASSIGN(RenderState); friend class renderthread::RenderThread; - friend class Caches; friend class renderthread::CacheManager; public: - void onGLContextCreated(); - void onGLContextDestroyed(); + void onContextCreated(); + void onContextDestroyed(); - void onVkContextCreated(); - void onVkContextDestroyed(); - - void flush(Caches::FlushMode flushMode); void onBitmapDestroyed(uint32_t pixelRefId); void setViewport(GLsizei width, GLsizei height); @@ -70,8 +61,6 @@ public: GLuint createFramebuffer(); void deleteFramebuffer(GLuint fbo); - void invokeFunctor(Functor* functor, DrawGlInfo::Mode mode, DrawGlInfo* info); - void debugOverdraw(bool enable, bool clear); void registerLayer(Layer* layer) { mActiveLayers.insert(layer); } @@ -101,16 +90,15 @@ public: void dump(); + renderthread::RenderThread& getRenderThread(); + private: - void interruptForFunctorInvoke(); - void resumeFromFunctorInvoke(); void destroyLayersInUpdater(); explicit RenderState(renderthread::RenderThread& thread); ~RenderState(); renderthread::RenderThread& mRenderThread; - Caches* mCaches = nullptr; std::set<Layer*> mActiveLayers; std::set<DeferredLayerUpdater*> mActiveLayerUpdaters; diff --git a/libs/hwui/renderstate/TextureState.cpp b/libs/hwui/renderstate/TextureState.cpp deleted file mode 100644 index 470b4f5de97f..000000000000 --- a/libs/hwui/renderstate/TextureState.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "renderstate/TextureState.h" - -#include "Caches.h" -#include "utils/TraceUtils.h" - -#include <GLES3/gl3.h> -#include <SkBitmap.h> -#include <SkCanvas.h> -#include <memory> - -namespace android { -namespace uirenderer { - -// Width of mShadowLutTexture, defines how accurate the shadow alpha lookup table is -static const int SHADOW_LUT_SIZE = 128; - -// Must define as many texture units as specified by kTextureUnitsCount -const GLenum kTextureUnits[] = {GL_TEXTURE0, GL_TEXTURE1, GL_TEXTURE2, GL_TEXTURE3}; - -TextureState::TextureState() : mTextureUnit(0) { - glActiveTexture(kTextureUnits[0]); - resetBoundTextures(); - - GLint maxTextureUnits; - glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits); - LOG_ALWAYS_FATAL_IF(maxTextureUnits < kTextureUnitsCount, - "At least %d texture units are required!", kTextureUnitsCount); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); -} - -TextureState::~TextureState() { - if (mShadowLutTexture != nullptr) { - mShadowLutTexture->deleteTexture(); - } -} - -/** - * Maps shadow geometry 'alpha' varying (1 for darkest, 0 for transparent) to - * darkness at that spot. Input values of 0->1 should be mapped within the same - * range, but can affect the curve for a different visual falloff. - * - * This is used to populate the shadow LUT texture for quick lookup in the - * shadow shader. - */ -static float computeShadowOpacity(float ratio) { - // exponential falloff function provided by UX - float val = 1 - ratio; - return exp(-val * val * 4.0) - 0.018; -} - -void TextureState::constructTexture(Caches& caches) { - if (mShadowLutTexture == nullptr) { - mShadowLutTexture.reset(new Texture(caches)); - - unsigned char bytes[SHADOW_LUT_SIZE]; - for (int i = 0; i < SHADOW_LUT_SIZE; i++) { - float inputRatio = i / (SHADOW_LUT_SIZE - 1.0f); - bytes[i] = computeShadowOpacity(inputRatio) * 255; - } - mShadowLutTexture->upload(GL_ALPHA, SHADOW_LUT_SIZE, 1, GL_ALPHA, GL_UNSIGNED_BYTE, &bytes); - mShadowLutTexture->setFilter(GL_LINEAR); - mShadowLutTexture->setWrap(GL_CLAMP_TO_EDGE); - } -} - -void TextureState::activateTexture(GLuint textureUnit) { - LOG_ALWAYS_FATAL_IF(textureUnit >= kTextureUnitsCount, - "Tried to use texture unit index %d, only %d exist", textureUnit, - kTextureUnitsCount); - if (mTextureUnit != textureUnit) { - glActiveTexture(kTextureUnits[textureUnit]); - mTextureUnit = textureUnit; - } -} - -void TextureState::resetActiveTexture() { - mTextureUnit = -1; -} - -void TextureState::bindTexture(GLuint texture) { - if (mBoundTextures[mTextureUnit] != texture) { - glBindTexture(GL_TEXTURE_2D, texture); - mBoundTextures[mTextureUnit] = texture; - } -} - -void TextureState::bindTexture(GLenum target, GLuint texture) { - if (target == GL_TEXTURE_2D) { - bindTexture(texture); - } else { - // GLConsumer directly calls glBindTexture() with - // target=GL_TEXTURE_EXTERNAL_OES, don't cache this target - // since the cached state could be stale - glBindTexture(target, texture); - } -} - -void TextureState::deleteTexture(GLuint texture) { - // When glDeleteTextures() is called on a currently bound texture, - // OpenGL ES specifies that the texture is then considered unbound - // Consider the following series of calls: - // - // glGenTextures -> creates texture name 2 - // glBindTexture(2) - // glDeleteTextures(2) -> 2 is now unbound - // glGenTextures -> can return 2 again - // - // If we don't call glBindTexture(2) after the second glGenTextures - // call, any texture operation will be performed on the default - // texture (name=0) - - unbindTexture(texture); - - glDeleteTextures(1, &texture); -} - -void TextureState::resetBoundTextures() { - for (int i = 0; i < kTextureUnitsCount; i++) { - mBoundTextures[i] = 0; - } -} - -void TextureState::unbindTexture(GLuint texture) { - for (int i = 0; i < kTextureUnitsCount; i++) { - if (mBoundTextures[i] == texture) { - mBoundTextures[i] = 0; - } - } -} - -} /* namespace uirenderer */ -} /* namespace android */ diff --git a/libs/hwui/renderstate/TextureState.h b/libs/hwui/renderstate/TextureState.h deleted file mode 100644 index f1996d431fa2..000000000000 --- a/libs/hwui/renderstate/TextureState.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#ifndef RENDERSTATE_TEXTURESTATE_H -#define RENDERSTATE_TEXTURESTATE_H - -#include "Texture.h" -#include "Vertex.h" - -#include <GLES2/gl2.h> -#include <GLES2/gl2ext.h> -#include <memory> - -namespace android { -namespace uirenderer { - -class Texture; - -class TextureState { - friend class Caches; // TODO: move to RenderState -public: - void constructTexture(Caches& caches); - - /** - * Activate the specified texture unit. The texture unit must - * be specified using an integer number (0 for GL_TEXTURE0 etc.) - */ - void activateTexture(GLuint textureUnit); - - /** - * Invalidate the cached value of the active texture unit. - */ - void resetActiveTexture(); - - /** - * Binds the specified texture as a GL_TEXTURE_2D texture. - * All texture bindings must be performed with this method or - * bindTexture(GLenum, GLuint). - */ - void bindTexture(GLuint texture); - - /** - * Binds the specified texture with the specified render target. - * All texture bindings must be performed with this method or - * bindTexture(GLuint). - */ - void bindTexture(GLenum target, GLuint texture); - - /** - * Deletes the specified texture and clears it from the cache - * of bound textures. - * All textures must be deleted using this method. - */ - void deleteTexture(GLuint texture); - - /** - * Signals that the cache of bound textures should be cleared. - * Other users of the context may have altered which textures are bound. - */ - void resetBoundTextures(); - - /** - * Clear the cache of bound textures. - */ - void unbindTexture(GLuint texture); - - Texture* getShadowLutTexture() { return mShadowLutTexture.get(); } - -private: - // total number of texture units available for use - static const int kTextureUnitsCount = 4; - - TextureState(); - ~TextureState(); - GLuint mTextureUnit; - - // Caches texture bindings for the GL_TEXTURE_2D target - GLuint mBoundTextures[kTextureUnitsCount]; - - std::unique_ptr<Texture> mShadowLutTexture; -}; - -} /* namespace uirenderer */ -} /* namespace android */ - -#endif // RENDERSTATE_BLEND_H diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp index bec80b1e6011..c45eedad775c 100644 --- a/libs/hwui/renderthread/CacheManager.cpp +++ b/libs/hwui/renderthread/CacheManager.cpp @@ -21,6 +21,7 @@ #include "RenderThread.h" #include "pipeline/skia/ShaderCache.h" #include "pipeline/skia/SkiaMemoryTracer.h" +#include "Properties.h" #include "renderstate/RenderState.h" #include <GrContextOptions.h> @@ -214,11 +215,12 @@ void CacheManager::dumpMemoryUsage(String8& log, const RenderState* renderState) log.appendFormat(" Layer Info:\n"); } + const char* layerType = Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL + ? "GlLayer" : "VkLayer"; size_t layerMemoryTotal = 0; for (std::set<Layer*>::iterator it = renderState->mActiveLayers.begin(); it != renderState->mActiveLayers.end(); it++) { const Layer* layer = *it; - const char* layerType = layer->getApi() == Layer::Api::OpenGL ? "GlLayer" : "VkLayer"; log.appendFormat(" %s size %dx%d\n", layerType, layer->getWidth(), layer->getHeight()); layerMemoryTotal += layer->getWidth() * layer->getHeight() * 4; diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 5d7252304bf2..8b07d1dadeb6 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -18,7 +18,6 @@ #include <GpuMemoryTracker.h> #include "AnimationContext.h" -#include "Caches.h" #include "EglManager.h" #include "Frame.h" #include "LayerUpdateQueue.h" @@ -495,13 +494,6 @@ void CanvasContext::draw() { } GpuMemoryTracker::onFrameCompleted(); -#ifdef BUGREPORT_FONT_CACHE_USAGE - auto renderType = Properties::getRenderPipelineType(); - if (RenderPipelineType::OpenGL == renderType) { - Caches& caches = Caches::getInstance(); - caches.fontRenderer.getFontRenderer().historyTracker().frameCompleted(); - } -#endif } // Called by choreographer to do an RT-driven animation diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index cd21822df5b1..5f8d7ad3373a 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -18,6 +18,7 @@ #include <cutils/properties.h> #include <log/log.h> +#include <private/gui/SyncFeatures.h> #include <utils/Trace.h> #include "utils/StringUtils.h" @@ -464,6 +465,109 @@ bool EglManager::setPreserveBuffer(EGLSurface surface, bool preserve) { return preserved; } +status_t EglManager::fenceWait(sp<Fence>& fence) { + if (!hasEglContext()) { + ALOGE("EglManager::fenceWait: EGLDisplay not initialized"); + return INVALID_OPERATION; + } + + if (SyncFeatures::getInstance().useWaitSync() && + SyncFeatures::getInstance().useNativeFenceSync()) { + // Block GPU on the fence. + // Create an EGLSyncKHR from the current fence. + int fenceFd = fence->dup(); + if (fenceFd == -1) { + ALOGE("EglManager::fenceWait: error dup'ing fence fd: %d", errno); + return -errno; + } + EGLint attribs[] = { + EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, + EGL_NONE + }; + EGLSyncKHR sync = eglCreateSyncKHR(mEglDisplay, + EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); + if (sync == EGL_NO_SYNC_KHR) { + close(fenceFd); + ALOGE("EglManager::fenceWait: error creating EGL fence: %#x", eglGetError()); + return UNKNOWN_ERROR; + } + + // XXX: The spec draft is inconsistent as to whether this should + // return an EGLint or void. Ignore the return value for now, as + // it's not strictly needed. + eglWaitSyncKHR(mEglDisplay, sync, 0); + EGLint eglErr = eglGetError(); + eglDestroySyncKHR(mEglDisplay, sync); + if (eglErr != EGL_SUCCESS) { + ALOGE("EglManager::fenceWait: error waiting for EGL fence: %#x", eglErr); + return UNKNOWN_ERROR; + } + } else { + // Block CPU on the fence. + status_t err = fence->waitForever("EglManager::fenceWait"); + if (err != NO_ERROR) { + ALOGE("EglManager::fenceWait: error waiting for fence: %d", err); + return err; + } + } + return OK; +} + +status_t EglManager::createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, + sp<Fence>& nativeFence) { + if (!hasEglContext()) { + ALOGE("EglManager::createReleaseFence: EGLDisplay not initialized"); + return INVALID_OPERATION; + } + + if (SyncFeatures::getInstance().useNativeFenceSync()) { + EGLSyncKHR sync = eglCreateSyncKHR(mEglDisplay, + EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr); + if (sync == EGL_NO_SYNC_KHR) { + ALOGE("EglManager::createReleaseFence: error creating EGL fence: %#x", + eglGetError()); + return UNKNOWN_ERROR; + } + glFlush(); + int fenceFd = eglDupNativeFenceFDANDROID(mEglDisplay, sync); + eglDestroySyncKHR(mEglDisplay, sync); + if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { + ALOGE("EglManager::createReleaseFence: error dup'ing native fence " + "fd: %#x", eglGetError()); + return UNKNOWN_ERROR; + } + nativeFence = new Fence(fenceFd); + *eglFence = EGL_NO_SYNC_KHR; + } else if (useFenceSync && SyncFeatures::getInstance().useFenceSync()) { + if (*eglFence != EGL_NO_SYNC_KHR) { + // There is already a fence for the current slot. We need to + // wait on that before replacing it with another fence to + // ensure that all outstanding buffer accesses have completed + // before the producer accesses it. + EGLint result = eglClientWaitSyncKHR(mEglDisplay, *eglFence, 0, 1000000000); + if (result == EGL_FALSE) { + ALOGE("EglManager::createReleaseFence: error waiting for previous fence: %#x", + eglGetError()); + return UNKNOWN_ERROR; + } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { + ALOGE("EglManager::createReleaseFence: timeout waiting for previous fence"); + return TIMED_OUT; + } + eglDestroySyncKHR(mEglDisplay, *eglFence); + } + + // Create a fence for the outstanding accesses in the current + // OpenGL ES context. + *eglFence = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_FENCE_KHR, nullptr); + if (*eglFence == EGL_NO_SYNC_KHR) { + ALOGE("EglManager::createReleaseFence: error creating fence: %#x", eglGetError()); + return UNKNOWN_ERROR; + } + glFlush(); + } + return OK; +} + } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h index 8e8bb8b68a1c..507673adf26e 100644 --- a/libs/hwui/renderthread/EglManager.h +++ b/libs/hwui/renderthread/EglManager.h @@ -17,8 +17,10 @@ #define EGLMANAGER_H #include <EGL/egl.h> +#include <EGL/eglext.h> #include <SkRect.h> #include <cutils/compiler.h> +#include <ui/Fence.h> #include <ui/GraphicBuffer.h> #include <utils/StrongPointer.h> @@ -66,6 +68,14 @@ public: EGLDisplay eglDisplay() const { return mEglDisplay; } + // Inserts a wait on fence command into the OpenGL ES command stream. If EGL extension + // support is missing, block the CPU on the fence. + status_t fenceWait(sp<Fence>& fence); + + // Creates a fence that is signaled, when all the pending GL commands are flushed. + // Depending on installed extensions, the result is either Android native fence or EGL fence. + status_t createReleaseFence(bool useFenceSync, EGLSyncKHR* eglFence, sp<Fence>& nativeFence); + private: void initExtensions(); diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp index c1284ec02655..65f95ad3f0d4 100644 --- a/libs/hwui/renderthread/RenderThread.cpp +++ b/libs/hwui/renderthread/RenderThread.cpp @@ -178,7 +178,7 @@ void RenderThread::requireGlContext() { return; } mEglManager->initialize(); - renderState().onGLContextCreated(); + renderState().onContextCreated(); #ifdef HWUI_GLES_WRAP_ENABLED debug::GlesDriver* driver = debug::GlesDriver::get(); @@ -200,7 +200,7 @@ void RenderThread::requireGlContext() { void RenderThread::destroyGlContext() { if (mEglManager->hasEglContext()) { setGrContext(nullptr); - renderState().onGLContextDestroyed(); + renderState().onContextDestroyed(); mEglManager->destroy(); } } diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp index 1517f579a084..0c49dc03425e 100644 --- a/libs/hwui/renderthread/VulkanManager.cpp +++ b/libs/hwui/renderthread/VulkanManager.cpp @@ -40,7 +40,7 @@ namespace renderthread { VulkanManager::VulkanManager(RenderThread& thread) : mRenderThread(thread) {} void VulkanManager::destroy() { - mRenderThread.renderState().onVkContextDestroyed(); + mRenderThread.renderState().onContextDestroyed(); mRenderThread.setGrContext(nullptr); if (VK_NULL_HANDLE != mCommandPool) { @@ -404,7 +404,7 @@ void VulkanManager::initialize() { mSwapBehavior = SwapBehavior::BufferAge; } - mRenderThread.renderState().onVkContextCreated(); + mRenderThread.renderState().onContextCreated(); } // Returns the next BackbufferInfo to use for the next draw. The function will make sure all @@ -981,6 +981,22 @@ int VulkanManager::getAge(VulkanSurface* surface) { return surface->mCurrentTime - lastUsed; } +status_t VulkanManager::fenceWait(sp<Fence>& fence) { + //TODO: Insert a wait on fence command into the Vulkan command buffer. + // Block CPU on the fence. + status_t err = fence->waitForever("VulkanManager::fenceWait"); + if (err != NO_ERROR) { + ALOGE("VulkanManager::fenceWait: error waiting for fence: %d", err); + return err; + } + return OK; +} + +status_t VulkanManager::createReleaseFence(sp<Fence>& nativeFence) { + //TODO: Create a fence that is signaled, when all the pending Vulkan commands are flushed. + return OK; +} + } /* namespace renderthread */ } /* namespace uirenderer */ } /* namespace android */ diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h index 5524c39d7a0c..ebc11a50685e 100644 --- a/libs/hwui/renderthread/VulkanManager.h +++ b/libs/hwui/renderthread/VulkanManager.h @@ -23,6 +23,8 @@ #include <vulkan/vulkan.h> #include <SkSurface.h> +#include <ui/Fence.h> +#include <utils/StrongPointer.h> #include <vk/GrVkBackendContext.h> class GrVkExtensions; @@ -110,6 +112,12 @@ public: // Presents the current VkImage. void swapBuffers(VulkanSurface* surface); + // Inserts a wait on fence command into the Vulkan command buffer. + status_t fenceWait(sp<Fence>& fence); + + // Creates a fence that is signaled, when all the pending Vulkan commands are flushed. + status_t createReleaseFence(sp<Fence>& nativeFence); + private: friend class RenderThread; diff --git a/libs/hwui/surfacetexture/EGLConsumer.cpp b/libs/hwui/surfacetexture/EGLConsumer.cpp new file mode 100644 index 000000000000..c8220c6cb0d4 --- /dev/null +++ b/libs/hwui/surfacetexture/EGLConsumer.cpp @@ -0,0 +1,675 @@ +/* + * 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 <inttypes.h> + +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> +#include <cutils/compiler.h> +#include <gui/BufferItem.h> +#include <gui/BufferQueue.h> +#include <private/gui/SyncFeatures.h> +#include "EGLConsumer.h" +#include "SurfaceTexture.h" + +#include <utils/Log.h> +#include <utils/String8.h> +#include <utils/Trace.h> + +#define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content" +#define EGL_PROTECTED_CONTENT_EXT 0x32C0 + +namespace android { + +// Macros for including the SurfaceTexture name in log messages +#define EGC_LOGV(x, ...) ALOGV("[%s] " x, st.mName.string(), ##__VA_ARGS__) +#define EGC_LOGD(x, ...) ALOGD("[%s] " x, st.mName.string(), ##__VA_ARGS__) +#define EGC_LOGW(x, ...) ALOGW("[%s] " x, st.mName.string(), ##__VA_ARGS__) +#define EGC_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__) + +static const struct { + uint32_t width, height; + char const* bits; +} kDebugData = {15, 12, + "_______________" + "_______________" + "_____XX_XX_____" + "__X_X_____X_X__" + "__X_XXXXXXX_X__" + "__XXXXXXXXXXX__" + "___XX_XXX_XX___" + "____XXXXXXX____" + "_____X___X_____" + "____X_____X____" + "_______________" + "_______________"}; + +Mutex EGLConsumer::sStaticInitLock; +sp<GraphicBuffer> EGLConsumer::sReleasedTexImageBuffer; + +static bool hasEglProtectedContentImpl() { + EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); + const char* exts = eglQueryString(dpy, EGL_EXTENSIONS); + size_t cropExtLen = strlen(PROT_CONTENT_EXT_STR); + size_t extsLen = strlen(exts); + bool equal = !strcmp(PROT_CONTENT_EXT_STR, exts); + bool atStart = !strncmp(PROT_CONTENT_EXT_STR " ", exts, cropExtLen + 1); + bool atEnd = (cropExtLen + 1) < extsLen && + !strcmp(" " PROT_CONTENT_EXT_STR, exts + extsLen - (cropExtLen + 1)); + bool inMiddle = strstr(exts, " " PROT_CONTENT_EXT_STR " "); + return equal || atStart || atEnd || inMiddle; +} + +static bool hasEglProtectedContent() { + // Only compute whether the extension is present once the first time this + // function is called. + static bool hasIt = hasEglProtectedContentImpl(); + return hasIt; +} + +EGLConsumer::EGLConsumer() : mEglDisplay(EGL_NO_DISPLAY), mEglContext(EGL_NO_CONTEXT) {} + +status_t EGLConsumer::updateTexImage(SurfaceTexture& st) { + // Make sure the EGL state is the same as in previous calls. + status_t err = checkAndUpdateEglStateLocked(st); + if (err != NO_ERROR) { + return err; + } + + BufferItem item; + + // Acquire the next buffer. + // In asynchronous mode the list is guaranteed to be one buffer + // deep, while in synchronous mode we use the oldest buffer. + err = st.acquireBufferLocked(&item, 0); + if (err != NO_ERROR) { + if (err == BufferQueue::NO_BUFFER_AVAILABLE) { + // We always bind the texture even if we don't update its contents. + EGC_LOGV("updateTexImage: no buffers were available"); + glBindTexture(st.mTexTarget, st.mTexName); + err = NO_ERROR; + } else { + EGC_LOGE("updateTexImage: acquire failed: %s (%d)", strerror(-err), err); + } + return err; + } + + // Release the previous buffer. + err = updateAndReleaseLocked(item, nullptr, st); + if (err != NO_ERROR) { + // We always bind the texture. + glBindTexture(st.mTexTarget, st.mTexName); + return err; + } + + // Bind the new buffer to the GL texture, and wait until it's ready. + return bindTextureImageLocked(st); +} + +status_t EGLConsumer::releaseTexImage(SurfaceTexture& st) { + // Make sure the EGL state is the same as in previous calls. + status_t err = NO_ERROR; + + // if we're detached, no need to validate EGL's state -- we won't use it. + if (st.mOpMode == SurfaceTexture::OpMode::attachedToGL) { + err = checkAndUpdateEglStateLocked(st, true); + if (err != NO_ERROR) { + return err; + } + } + + // Update the EGLConsumer state. + int buf = st.mCurrentTexture; + if (buf != BufferQueue::INVALID_BUFFER_SLOT) { + EGC_LOGV("releaseTexImage: (slot=%d, mOpMode=%d)", buf, (int)st.mOpMode); + + // if we're detached, we just use the fence that was created in detachFromContext() + // so... basically, nothing more to do here. + if (st.mOpMode == SurfaceTexture::OpMode::attachedToGL) { + // Do whatever sync ops we need to do before releasing the slot. + err = syncForReleaseLocked(mEglDisplay, st); + if (err != NO_ERROR) { + EGC_LOGE("syncForReleaseLocked failed (slot=%d), err=%d", buf, err); + return err; + } + } + + err = st.releaseBufferLocked(buf, st.mSlots[buf].mGraphicBuffer, mEglDisplay, + EGL_NO_SYNC_KHR); + if (err < NO_ERROR) { + EGC_LOGE("releaseTexImage: failed to release buffer: %s (%d)", strerror(-err), err); + return err; + } + + if (mReleasedTexImage == nullptr) { + mReleasedTexImage = new EglImage(getDebugTexImageBuffer()); + } + + st.mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT; + mCurrentTextureImage = mReleasedTexImage; + st.mCurrentCrop.makeInvalid(); + st.mCurrentTransform = 0; + st.mCurrentTimestamp = 0; + st.mCurrentDataSpace = HAL_DATASPACE_UNKNOWN; + st.mCurrentFence = Fence::NO_FENCE; + st.mCurrentFenceTime = FenceTime::NO_FENCE; + + // detached, don't touch the texture (and we may not even have an + // EGLDisplay here. + if (st.mOpMode == SurfaceTexture::OpMode::attachedToGL) { + // This binds a dummy buffer (mReleasedTexImage). + status_t result = bindTextureImageLocked(st); + if (result != NO_ERROR) { + return result; + } + } + } + + return NO_ERROR; +} + +sp<GraphicBuffer> EGLConsumer::getDebugTexImageBuffer() { + Mutex::Autolock _l(sStaticInitLock); + if (CC_UNLIKELY(sReleasedTexImageBuffer == nullptr)) { + // The first time, create the debug texture in case the application + // continues to use it. + sp<GraphicBuffer> buffer = new GraphicBuffer( + kDebugData.width, kDebugData.height, PIXEL_FORMAT_RGBA_8888, + GraphicBuffer::USAGE_SW_WRITE_RARELY, "[EGLConsumer debug texture]"); + uint32_t* bits; + buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, reinterpret_cast<void**>(&bits)); + uint32_t stride = buffer->getStride(); + uint32_t height = buffer->getHeight(); + memset(bits, 0, stride * height * 4); + for (uint32_t y = 0; y < kDebugData.height; y++) { + for (uint32_t x = 0; x < kDebugData.width; x++) { + bits[x] = (kDebugData.bits[y + kDebugData.width + x] == 'X') ? 0xFF000000 + : 0xFFFFFFFF; + } + bits += stride; + } + buffer->unlock(); + sReleasedTexImageBuffer = buffer; + } + return sReleasedTexImageBuffer; +} + +void EGLConsumer::onAcquireBufferLocked(BufferItem* item, SurfaceTexture& st) { + // If item->mGraphicBuffer is not null, this buffer has not been acquired + // before, so any prior EglImage created is using a stale buffer. This + // replaces any old EglImage with a new one (using the new buffer). + int slot = item->mSlot; + if (item->mGraphicBuffer != nullptr || mEglSlots[slot].mEglImage.get() == nullptr) { + mEglSlots[slot].mEglImage = new EglImage(st.mSlots[slot].mGraphicBuffer); + } +} + +void EGLConsumer::onReleaseBufferLocked(int buf) { + mEglSlots[buf].mEglFence = EGL_NO_SYNC_KHR; +} + +status_t EGLConsumer::updateAndReleaseLocked(const BufferItem& item, PendingRelease* pendingRelease, + SurfaceTexture& st) { + status_t err = NO_ERROR; + + int slot = item.mSlot; + + if (st.mOpMode != SurfaceTexture::OpMode::attachedToGL) { + EGC_LOGE( + "updateAndRelease: EGLConsumer is not attached to an OpenGL " + "ES context"); + st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR); + return INVALID_OPERATION; + } + + // Confirm state. + err = checkAndUpdateEglStateLocked(st); + if (err != NO_ERROR) { + st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR); + return err; + } + + // Ensure we have a valid EglImageKHR for the slot, creating an EglImage + // if nessessary, for the gralloc buffer currently in the slot in + // ConsumerBase. + // We may have to do this even when item.mGraphicBuffer == NULL (which + // means the buffer was previously acquired). + err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay); + if (err != NO_ERROR) { + EGC_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d", mEglDisplay, + slot); + st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, mEglDisplay, EGL_NO_SYNC_KHR); + return UNKNOWN_ERROR; + } + + // Do whatever sync ops we need to do before releasing the old slot. + if (slot != st.mCurrentTexture) { + err = syncForReleaseLocked(mEglDisplay, st); + if (err != NO_ERROR) { + // Release the buffer we just acquired. It's not safe to + // release the old buffer, so instead we just drop the new frame. + // As we are still under lock since acquireBuffer, it is safe to + // release by slot. + st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, mEglDisplay, + EGL_NO_SYNC_KHR); + return err; + } + } + + EGC_LOGV( + "updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", st.mCurrentTexture, + mCurrentTextureImage != nullptr ? mCurrentTextureImage->graphicBufferHandle() : nullptr, + slot, st.mSlots[slot].mGraphicBuffer->handle); + + // Hang onto the pointer so that it isn't freed in the call to + // releaseBufferLocked() if we're in shared buffer mode and both buffers are + // the same. + sp<EglImage> nextTextureImage = mEglSlots[slot].mEglImage; + + // release old buffer + if (st.mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { + if (pendingRelease == nullptr) { + status_t status = st.releaseBufferLocked( + st.mCurrentTexture, mCurrentTextureImage->graphicBuffer(), mEglDisplay, + mEglSlots[st.mCurrentTexture].mEglFence); + if (status < NO_ERROR) { + EGC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status), + status); + err = status; + // keep going, with error raised [?] + } + } else { + pendingRelease->currentTexture = st.mCurrentTexture; + pendingRelease->graphicBuffer = mCurrentTextureImage->graphicBuffer(); + pendingRelease->display = mEglDisplay; + pendingRelease->fence = mEglSlots[st.mCurrentTexture].mEglFence; + pendingRelease->isPending = true; + } + } + + // Update the EGLConsumer state. + st.mCurrentTexture = slot; + mCurrentTextureImage = nextTextureImage; + st.mCurrentCrop = item.mCrop; + st.mCurrentTransform = item.mTransform; + st.mCurrentScalingMode = item.mScalingMode; + st.mCurrentTimestamp = item.mTimestamp; + st.mCurrentDataSpace = item.mDataSpace; + st.mCurrentFence = item.mFence; + st.mCurrentFenceTime = item.mFenceTime; + st.mCurrentFrameNumber = item.mFrameNumber; + + st.computeCurrentTransformMatrixLocked(); + + return err; +} + +status_t EGLConsumer::bindTextureImageLocked(SurfaceTexture& st) { + if (mEglDisplay == EGL_NO_DISPLAY) { + ALOGE("bindTextureImage: invalid display"); + return INVALID_OPERATION; + } + + GLenum error; + while ((error = glGetError()) != GL_NO_ERROR) { + EGC_LOGW("bindTextureImage: clearing GL error: %#04x", error); + } + + glBindTexture(st.mTexTarget, st.mTexName); + if (st.mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureImage == nullptr) { + EGC_LOGE("bindTextureImage: no currently-bound texture"); + return NO_INIT; + } + + status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay); + if (err != NO_ERROR) { + EGC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay, + st.mCurrentTexture); + return UNKNOWN_ERROR; + } + mCurrentTextureImage->bindToTextureTarget(st.mTexTarget); + + // In the rare case that the display is terminated and then initialized + // again, we can't detect that the display changed (it didn't), but the + // image is invalid. In this case, repeat the exact same steps while + // forcing the creation of a new image. + if ((error = glGetError()) != GL_NO_ERROR) { + glBindTexture(st.mTexTarget, st.mTexName); + status_t result = mCurrentTextureImage->createIfNeeded(mEglDisplay, true); + if (result != NO_ERROR) { + EGC_LOGW("bindTextureImage: can't create image on display=%p slot=%d", mEglDisplay, + st.mCurrentTexture); + return UNKNOWN_ERROR; + } + mCurrentTextureImage->bindToTextureTarget(st.mTexTarget); + if ((error = glGetError()) != GL_NO_ERROR) { + EGC_LOGE("bindTextureImage: error binding external image: %#04x", error); + return UNKNOWN_ERROR; + } + } + + // Wait for the new buffer to be ready. + return doGLFenceWaitLocked(st); +} + +status_t EGLConsumer::checkAndUpdateEglStateLocked(SurfaceTexture& st, bool contextCheck) { + EGLDisplay dpy = eglGetCurrentDisplay(); + EGLContext ctx = eglGetCurrentContext(); + + if (!contextCheck) { + // if this is the first time we're called, mEglDisplay/mEglContext have + // never been set, so don't error out (below). + if (mEglDisplay == EGL_NO_DISPLAY) { + mEglDisplay = dpy; + } + if (mEglContext == EGL_NO_CONTEXT) { + mEglContext = ctx; + } + } + + if (mEglDisplay != dpy || dpy == EGL_NO_DISPLAY) { + EGC_LOGE("checkAndUpdateEglState: invalid current EGLDisplay"); + return INVALID_OPERATION; + } + + if (mEglContext != ctx || ctx == EGL_NO_CONTEXT) { + EGC_LOGE("checkAndUpdateEglState: invalid current EGLContext"); + return INVALID_OPERATION; + } + + mEglDisplay = dpy; + mEglContext = ctx; + return NO_ERROR; +} + +status_t EGLConsumer::detachFromContext(SurfaceTexture& st) { + EGLDisplay dpy = eglGetCurrentDisplay(); + EGLContext ctx = eglGetCurrentContext(); + + if (mEglDisplay != dpy && mEglDisplay != EGL_NO_DISPLAY) { + EGC_LOGE("detachFromContext: invalid current EGLDisplay"); + return INVALID_OPERATION; + } + + if (mEglContext != ctx && mEglContext != EGL_NO_CONTEXT) { + EGC_LOGE("detachFromContext: invalid current EGLContext"); + return INVALID_OPERATION; + } + + if (dpy != EGL_NO_DISPLAY && ctx != EGL_NO_CONTEXT) { + status_t err = syncForReleaseLocked(dpy, st); + if (err != OK) { + return err; + } + + glDeleteTextures(1, &st.mTexName); + } + + mEglDisplay = EGL_NO_DISPLAY; + mEglContext = EGL_NO_CONTEXT; + + return OK; +} + +status_t EGLConsumer::attachToContext(uint32_t tex, SurfaceTexture& st) { + // Initialize mCurrentTextureImage if there is a current buffer from past attached state. + int slot = st.mCurrentTexture; + if (slot != BufferItem::INVALID_BUFFER_SLOT) { + if (!mEglSlots[slot].mEglImage.get()) { + mEglSlots[slot].mEglImage = new EglImage(st.mSlots[slot].mGraphicBuffer); + } + mCurrentTextureImage = mEglSlots[slot].mEglImage; + } + + EGLDisplay dpy = eglGetCurrentDisplay(); + EGLContext ctx = eglGetCurrentContext(); + + if (dpy == EGL_NO_DISPLAY) { + EGC_LOGE("attachToContext: invalid current EGLDisplay"); + return INVALID_OPERATION; + } + + if (ctx == EGL_NO_CONTEXT) { + EGC_LOGE("attachToContext: invalid current EGLContext"); + return INVALID_OPERATION; + } + + // We need to bind the texture regardless of whether there's a current + // buffer. + glBindTexture(st.mTexTarget, GLuint(tex)); + + mEglDisplay = dpy; + mEglContext = ctx; + st.mTexName = tex; + st.mOpMode = SurfaceTexture::OpMode::attachedToGL; + + if (mCurrentTextureImage != nullptr) { + // This may wait for a buffer a second time. This is likely required if + // this is a different context, since otherwise the wait could be skipped + // by bouncing through another context. For the same context the extra + // wait is redundant. + status_t err = bindTextureImageLocked(st); + if (err != NO_ERROR) { + return err; + } + } + + return OK; +} + +status_t EGLConsumer::syncForReleaseLocked(EGLDisplay dpy, SurfaceTexture& st) { + EGC_LOGV("syncForReleaseLocked"); + + if (st.mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { + if (SyncFeatures::getInstance().useNativeFenceSync()) { + EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr); + if (sync == EGL_NO_SYNC_KHR) { + EGC_LOGE("syncForReleaseLocked: error creating EGL fence: %#x", eglGetError()); + return UNKNOWN_ERROR; + } + glFlush(); + int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync); + eglDestroySyncKHR(dpy, sync); + if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) { + EGC_LOGE( + "syncForReleaseLocked: error dup'ing native fence " + "fd: %#x", + eglGetError()); + return UNKNOWN_ERROR; + } + sp<Fence> fence(new Fence(fenceFd)); + status_t err = st.addReleaseFenceLocked(st.mCurrentTexture, + mCurrentTextureImage->graphicBuffer(), fence); + if (err != OK) { + EGC_LOGE( + "syncForReleaseLocked: error adding release fence: " + "%s (%d)", + strerror(-err), err); + return err; + } + } else if (st.mUseFenceSync && SyncFeatures::getInstance().useFenceSync()) { + EGLSyncKHR fence = mEglSlots[st.mCurrentTexture].mEglFence; + if (fence != EGL_NO_SYNC_KHR) { + // There is already a fence for the current slot. We need to + // wait on that before replacing it with another fence to + // ensure that all outstanding buffer accesses have completed + // before the producer accesses it. + EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000); + if (result == EGL_FALSE) { + EGC_LOGE( + "syncForReleaseLocked: error waiting for previous " + "fence: %#x", + eglGetError()); + return UNKNOWN_ERROR; + } else if (result == EGL_TIMEOUT_EXPIRED_KHR) { + EGC_LOGE( + "syncForReleaseLocked: timeout waiting for previous " + "fence"); + return TIMED_OUT; + } + eglDestroySyncKHR(dpy, fence); + } + + // Create a fence for the outstanding accesses in the current + // OpenGL ES context. + fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr); + if (fence == EGL_NO_SYNC_KHR) { + EGC_LOGE("syncForReleaseLocked: error creating fence: %#x", eglGetError()); + return UNKNOWN_ERROR; + } + glFlush(); + mEglSlots[st.mCurrentTexture].mEglFence = fence; + } + } + + return OK; +} + +status_t EGLConsumer::doGLFenceWaitLocked(SurfaceTexture& st) const { + EGLDisplay dpy = eglGetCurrentDisplay(); + EGLContext ctx = eglGetCurrentContext(); + + if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) { + EGC_LOGE("doGLFenceWait: invalid current EGLDisplay"); + return INVALID_OPERATION; + } + + if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) { + EGC_LOGE("doGLFenceWait: invalid current EGLContext"); + return INVALID_OPERATION; + } + + if (st.mCurrentFence->isValid()) { + if (SyncFeatures::getInstance().useWaitSync() && + SyncFeatures::getInstance().useNativeFenceSync()) { + // Create an EGLSyncKHR from the current fence. + int fenceFd = st.mCurrentFence->dup(); + if (fenceFd == -1) { + EGC_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno); + return -errno; + } + EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE}; + EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs); + if (sync == EGL_NO_SYNC_KHR) { + close(fenceFd); + EGC_LOGE("doGLFenceWait: error creating EGL fence: %#x", eglGetError()); + return UNKNOWN_ERROR; + } + + // XXX: The spec draft is inconsistent as to whether this should + // return an EGLint or void. Ignore the return value for now, as + // it's not strictly needed. + eglWaitSyncKHR(dpy, sync, 0); + EGLint eglErr = eglGetError(); + eglDestroySyncKHR(dpy, sync); + if (eglErr != EGL_SUCCESS) { + EGC_LOGE("doGLFenceWait: error waiting for EGL fence: %#x", eglErr); + return UNKNOWN_ERROR; + } + } else { + status_t err = st.mCurrentFence->waitForever("EGLConsumer::doGLFenceWaitLocked"); + if (err != NO_ERROR) { + EGC_LOGE("doGLFenceWait: error waiting for fence: %d", err); + return err; + } + } + } + + return NO_ERROR; +} + +void EGLConsumer::onFreeBufferLocked(int slotIndex) { + mEglSlots[slotIndex].mEglImage.clear(); +} + +void EGLConsumer::onAbandonLocked() { + mCurrentTextureImage.clear(); +} + +EGLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer) + : mGraphicBuffer(graphicBuffer), mEglImage(EGL_NO_IMAGE_KHR), mEglDisplay(EGL_NO_DISPLAY) {} + +EGLConsumer::EglImage::~EglImage() { + if (mEglImage != EGL_NO_IMAGE_KHR) { + if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) { + ALOGE("~EglImage: eglDestroyImageKHR failed"); + } + eglTerminate(mEglDisplay); + } +} + +status_t EGLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay, bool forceCreation) { + // If there's an image and it's no longer valid, destroy it. + bool haveImage = mEglImage != EGL_NO_IMAGE_KHR; + bool displayInvalid = mEglDisplay != eglDisplay; + if (haveImage && (displayInvalid || forceCreation)) { + if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) { + ALOGE("createIfNeeded: eglDestroyImageKHR failed"); + } + eglTerminate(mEglDisplay); + mEglImage = EGL_NO_IMAGE_KHR; + mEglDisplay = EGL_NO_DISPLAY; + } + + // If there's no image, create one. + if (mEglImage == EGL_NO_IMAGE_KHR) { + mEglDisplay = eglDisplay; + mEglImage = createImage(mEglDisplay, mGraphicBuffer); + } + + // Fail if we can't create a valid image. + if (mEglImage == EGL_NO_IMAGE_KHR) { + mEglDisplay = EGL_NO_DISPLAY; + const sp<GraphicBuffer>& buffer = mGraphicBuffer; + ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d", + buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(), + buffer->getPixelFormat()); + return UNKNOWN_ERROR; + } + + return OK; +} + +void EGLConsumer::EglImage::bindToTextureTarget(uint32_t texTarget) { + glEGLImageTargetTexture2DOES(texTarget, static_cast<GLeglImageOES>(mEglImage)); +} + +EGLImageKHR EGLConsumer::EglImage::createImage(EGLDisplay dpy, + const sp<GraphicBuffer>& graphicBuffer) { + EGLClientBuffer cbuf = static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer()); + const bool createProtectedImage = + (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) && hasEglProtectedContent(); + EGLint attrs[] = { + EGL_IMAGE_PRESERVED_KHR, + EGL_TRUE, + createProtectedImage ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE, + createProtectedImage ? EGL_TRUE : EGL_NONE, + EGL_NONE, + }; + eglInitialize(dpy, nullptr, nullptr); + EGLImageKHR image = + eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs); + if (image == EGL_NO_IMAGE_KHR) { + EGLint error = eglGetError(); + ALOGE("error creating EGLImage: %#x", error); + eglTerminate(dpy); + } + return image; +} + +}; // namespace android diff --git a/libs/hwui/surfacetexture/EGLConsumer.h b/libs/hwui/surfacetexture/EGLConsumer.h new file mode 100644 index 000000000000..eccb08298f6f --- /dev/null +++ b/libs/hwui/surfacetexture/EGLConsumer.h @@ -0,0 +1,311 @@ +/* + * 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. + */ + +#pragma once + +#include <EGL/egl.h> +#include <EGL/eglext.h> + +#include <gui/BufferQueueDefs.h> + +#include <ui/FenceTime.h> +#include <ui/GraphicBuffer.h> +#include <utils/Mutex.h> + +namespace android { + +class SurfaceTexture; + +/* + * EGLConsumer implements the parts of SurfaceTexture that deal with + * textures attached to an GL context. + */ +class EGLConsumer { +public: + EGLConsumer(); + + /** + * updateTexImage acquires the most recently queued buffer, and sets the + * image contents of the target texture to it. + * + * This call may only be made while the OpenGL ES context to which the + * target texture belongs is bound to the calling thread. + * + * This calls doGLFenceWait to ensure proper synchronization. + */ + status_t updateTexImage(SurfaceTexture& st); + + /* + * releaseTexImage releases the texture acquired in updateTexImage(). + * This is intended to be used in single buffer mode. + * + * This call may only be made while the OpenGL ES context to which the + * target texture belongs is bound to the calling thread. + */ + status_t releaseTexImage(SurfaceTexture& st); + + /** + * detachFromContext detaches the EGLConsumer from the calling thread's + * current OpenGL ES context. This context must be the same as the context + * that was current for previous calls to updateTexImage. + * + * Detaching a EGLConsumer from an OpenGL ES context will result in the + * deletion of the OpenGL ES texture object into which the images were being + * streamed. After a EGLConsumer has been detached from the OpenGL ES + * context calls to updateTexImage will fail returning INVALID_OPERATION + * until the EGLConsumer is attached to a new OpenGL ES context using the + * attachToContext method. + */ + status_t detachFromContext(SurfaceTexture& st); + + /** + * attachToContext attaches a EGLConsumer that is currently in the + * 'detached' state to the current OpenGL ES context. A EGLConsumer is + * in the 'detached' state iff detachFromContext has successfully been + * called and no calls to attachToContext have succeeded since the last + * detachFromContext call. Calls to attachToContext made on a + * EGLConsumer that is not in the 'detached' state will result in an + * INVALID_OPERATION error. + * + * The tex argument specifies the OpenGL ES texture object name in the + * new context into which the image contents will be streamed. A successful + * call to attachToContext will result in this texture object being bound to + * the texture target and populated with the image contents that were + * current at the time of the last call to detachFromContext. + */ + status_t attachToContext(uint32_t tex, SurfaceTexture& st); + + /** + * onAcquireBufferLocked amends the ConsumerBase method to update the + * mEglSlots array in addition to the ConsumerBase behavior. + */ + void onAcquireBufferLocked(BufferItem* item, SurfaceTexture& st); + + /** + * onReleaseBufferLocked amends the ConsumerBase method to update the + * mEglSlots array in addition to the ConsumerBase. + */ + void onReleaseBufferLocked(int slot); + + /** + * onFreeBufferLocked frees up the given buffer slot. If the slot has been + * initialized this will release the reference to the GraphicBuffer in that + * slot and destroy the EGLImage in that slot. Otherwise it has no effect. + */ + void onFreeBufferLocked(int slotIndex); + + /** + * onAbandonLocked amends the ConsumerBase method to clear + * mCurrentTextureImage in addition to the ConsumerBase behavior. + */ + void onAbandonLocked(); + +protected: + struct PendingRelease { + PendingRelease() + : isPending(false) + , currentTexture(-1) + , graphicBuffer() + , display(nullptr) + , fence(nullptr) {} + + bool isPending; + int currentTexture; + sp<GraphicBuffer> graphicBuffer; + EGLDisplay display; + EGLSyncKHR fence; + }; + + /** + * This releases the buffer in the slot referenced by mCurrentTexture, + * then updates state to refer to the BufferItem, which must be a + * newly-acquired buffer. If pendingRelease is not null, the parameters + * which would have been passed to releaseBufferLocked upon the successful + * completion of the method will instead be returned to the caller, so that + * it may call releaseBufferLocked itself later. + */ + status_t updateAndReleaseLocked(const BufferItem& item, PendingRelease* pendingRelease, + SurfaceTexture& st); + + /** + * Binds mTexName and the current buffer to mTexTarget. Uses + * mCurrentTexture if it's set, mCurrentTextureImage if not. If the + * bind succeeds, this calls doGLFenceWait. + */ + status_t bindTextureImageLocked(SurfaceTexture& st); + + /** + * Gets the current EGLDisplay and EGLContext values, and compares them + * to mEglDisplay and mEglContext. If the fields have been previously + * set, the values must match; if not, the fields are set to the current + * values. + * The contextCheck argument is used to ensure that a GL context is + * properly set; when set to false, the check is not performed. + */ + status_t checkAndUpdateEglStateLocked(SurfaceTexture& st, bool contextCheck = false); + + /** + * EglImage is a utility class for tracking and creating EGLImageKHRs. There + * is primarily just one image per slot, but there is also special cases: + * - For releaseTexImage, we use a debug image (mReleasedTexImage) + * - After freeBuffer, we must still keep the current image/buffer + * Reference counting EGLImages lets us handle all these cases easily while + * also only creating new EGLImages from buffers when required. + */ + class EglImage : public LightRefBase<EglImage> { + public: + EglImage(sp<GraphicBuffer> graphicBuffer); + + /** + * createIfNeeded creates an EGLImage if required (we haven't created + * one yet, or the EGLDisplay or crop-rect has changed). + */ + status_t createIfNeeded(EGLDisplay display, bool forceCreate = false); + + /** + * This calls glEGLImageTargetTexture2DOES to bind the image to the + * texture in the specified texture target. + */ + void bindToTextureTarget(uint32_t texTarget); + + const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; } + const native_handle* graphicBufferHandle() { + return mGraphicBuffer == nullptr ? nullptr : mGraphicBuffer->handle; + } + + private: + // Only allow instantiation using ref counting. + friend class LightRefBase<EglImage>; + virtual ~EglImage(); + + // createImage creates a new EGLImage from a GraphicBuffer. + EGLImageKHR createImage(EGLDisplay dpy, const sp<GraphicBuffer>& graphicBuffer); + + // Disallow copying + EglImage(const EglImage& rhs); + void operator=(const EglImage& rhs); + + // mGraphicBuffer is the buffer that was used to create this image. + sp<GraphicBuffer> mGraphicBuffer; + + // mEglImage is the EGLImage created from mGraphicBuffer. + EGLImageKHR mEglImage; + + // mEGLDisplay is the EGLDisplay that was used to create mEglImage. + EGLDisplay mEglDisplay; + + // mCropRect is the crop rectangle passed to EGL when mEglImage + // was created. + Rect mCropRect; + }; + + /** + * doGLFenceWaitLocked inserts a wait command into the OpenGL ES command + * stream to ensure that it is safe for future OpenGL ES commands to + * access the current texture buffer. + */ + status_t doGLFenceWaitLocked(SurfaceTexture& st) const; + + /** + * syncForReleaseLocked performs the synchronization needed to release the + * current slot from an OpenGL ES context. If needed it will set the + * current slot's fence to guard against a producer accessing the buffer + * before the outstanding accesses have completed. + */ + status_t syncForReleaseLocked(EGLDisplay dpy, SurfaceTexture& st); + + /** + * returns a graphic buffer used when the texture image has been released + */ + static sp<GraphicBuffer> getDebugTexImageBuffer(); + + /** + * The default consumer usage flags that EGLConsumer always sets on its + * BufferQueue instance; these will be OR:d with any additional flags passed + * from the EGLConsumer user. In particular, EGLConsumer will always + * consume buffers as hardware textures. + */ + static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE; + + /** + * mCurrentTextureImage is the EglImage/buffer of the current texture. It's + * possible that this buffer is not associated with any buffer slot, so we + * must track it separately in order to support the getCurrentBuffer method. + */ + sp<EglImage> mCurrentTextureImage; + + /** + * EGLSlot contains the information and object references that + * EGLConsumer maintains about a BufferQueue buffer slot. + */ + struct EglSlot { + EglSlot() : mEglFence(EGL_NO_SYNC_KHR) {} + + /** + * mEglImage is the EGLImage created from mGraphicBuffer. + */ + sp<EglImage> mEglImage; + + /** + * mFence is the EGL sync object that must signal before the buffer + * associated with this buffer slot may be dequeued. It is initialized + * to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based + * on a compile-time option) set to a new sync object in updateTexImage. + */ + EGLSyncKHR mEglFence; + }; + + /** + * mEglDisplay is the EGLDisplay with which this EGLConsumer is currently + * associated. It is intialized to EGL_NO_DISPLAY and gets set to the + * current display when updateTexImage is called for the first time and when + * attachToContext is called. + */ + EGLDisplay mEglDisplay; + + /** + * mEglContext is the OpenGL ES context with which this EGLConsumer is + * currently associated. It is initialized to EGL_NO_CONTEXT and gets set + * to the current GL context when updateTexImage is called for the first + * time and when attachToContext is called. + */ + EGLContext mEglContext; + + /** + * mEGLSlots stores the buffers that have been allocated by the BufferQueue + * for each buffer slot. It is initialized to null pointers, and gets + * filled in with the result of BufferQueue::acquire when the + * client dequeues a buffer from a + * slot that has not yet been used. The buffer allocated to a slot will also + * be replaced if the requested buffer usage or geometry differs from that + * of the buffer allocated to a slot. + */ + EglSlot mEglSlots[BufferQueueDefs::NUM_BUFFER_SLOTS]; + + /** + * protects static initialization + */ + static Mutex sStaticInitLock; + + /** + * mReleasedTexImageBuffer is a dummy buffer used when in single buffer + * mode and releaseTexImage() has been called + */ + static sp<GraphicBuffer> sReleasedTexImageBuffer; + sp<EglImage> mReleasedTexImage; +}; + +}; // namespace android diff --git a/libs/hwui/surfacetexture/ImageConsumer.cpp b/libs/hwui/surfacetexture/ImageConsumer.cpp new file mode 100644 index 000000000000..c86cd962ebed --- /dev/null +++ b/libs/hwui/surfacetexture/ImageConsumer.cpp @@ -0,0 +1,152 @@ +/* + * 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 "ImageConsumer.h" +#include <gui/BufferQueue.h> +#include "Properties.h" +#include "SurfaceTexture.h" +#include "renderstate/RenderState.h" +#include "renderthread/EglManager.h" +#include "renderthread/RenderThread.h" +#include "renderthread/VulkanManager.h" + +// Macro for including the SurfaceTexture name in log messages +#define IMG_LOGE(x, ...) ALOGE("[%s] " x, st.mName.string(), ##__VA_ARGS__) + +namespace android { + +void ImageConsumer::onFreeBufferLocked(int slotIndex) { + mImageSlots[slotIndex].mImage.reset(); +} + +void ImageConsumer::onAcquireBufferLocked(BufferItem* item) { + // If item->mGraphicBuffer is not null, this buffer has not been acquired + // before, so any prior SkImage is created with a stale buffer. This resets the stale SkImage. + if (item->mGraphicBuffer != nullptr) { + mImageSlots[item->mSlot].mImage.reset(); + } +} + +void ImageConsumer::onReleaseBufferLocked(int buf) { + mImageSlots[buf].mEglFence = EGL_NO_SYNC_KHR; +} + +void ImageConsumer::ImageSlot::createIfNeeded(sp<GraphicBuffer> graphicBuffer) { + if (!mImage.get()) { + mImage = graphicBuffer.get() + ? SkImage::MakeFromAHardwareBuffer( + reinterpret_cast<AHardwareBuffer*>(graphicBuffer.get()), + kPremul_SkAlphaType, SkColorSpace::MakeSRGB()) + : nullptr; + } +} + +sk_sp<SkImage> ImageConsumer::dequeueImage(bool* queueEmpty, SurfaceTexture& st, + uirenderer::RenderState& renderState) { + BufferItem item; + status_t err; + err = st.acquireBufferLocked(&item, 0); + if (err != OK) { + if (err != BufferQueue::NO_BUFFER_AVAILABLE) { + IMG_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err); + } else { + int slot = st.mCurrentTexture; + if (slot != BufferItem::INVALID_BUFFER_SLOT) { + *queueEmpty = true; + mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer); + return mImageSlots[slot].mImage; + } + } + return nullptr; + } + + int slot = item.mSlot; + if (item.mFence->isValid()) { + // Wait on the producer fence for the buffer to be ready. + if (uirenderer::Properties::getRenderPipelineType() == + uirenderer::RenderPipelineType::SkiaGL) { + err = renderState.getRenderThread().eglManager().fenceWait(item.mFence); + } else { + err = renderState.getRenderThread().vulkanManager().fenceWait(item.mFence); + } + if (err != OK) { + st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, EGL_NO_DISPLAY, + EGL_NO_SYNC_KHR); + return nullptr; + } + } + + // Release old buffer. + if (st.mCurrentTexture != BufferItem::INVALID_BUFFER_SLOT) { + // If needed, set the released slot's fence to guard against a producer accessing the + // buffer before the outstanding accesses have completed. + sp<Fence> releaseFence; + EGLDisplay display = EGL_NO_DISPLAY; + if (uirenderer::Properties::getRenderPipelineType() == + uirenderer::RenderPipelineType::SkiaGL) { + auto& eglManager = renderState.getRenderThread().eglManager(); + display = eglManager.eglDisplay(); + err = eglManager.createReleaseFence(st.mUseFenceSync, &mImageSlots[slot].mEglFence, + releaseFence); + } else { + err = renderState.getRenderThread().vulkanManager().createReleaseFence(releaseFence); + } + if (OK != err) { + st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, EGL_NO_DISPLAY, + EGL_NO_SYNC_KHR); + return nullptr; + } + + if (releaseFence.get()) { + status_t err = st.addReleaseFenceLocked( + st.mCurrentTexture, st.mSlots[st.mCurrentTexture].mGraphicBuffer, releaseFence); + if (err != OK) { + IMG_LOGE("dequeueImage: error adding release fence: %s (%d)", strerror(-err), err); + st.releaseBufferLocked(slot, st.mSlots[slot].mGraphicBuffer, EGL_NO_DISPLAY, + EGL_NO_SYNC_KHR); + return nullptr; + } + } + + // Finally release the old buffer. + status_t status = st.releaseBufferLocked( + st.mCurrentTexture, st.mSlots[st.mCurrentTexture].mGraphicBuffer, display, + mImageSlots[st.mCurrentTexture].mEglFence); + if (status < NO_ERROR) { + IMG_LOGE("dequeueImage: failed to release buffer: %s (%d)", strerror(-status), status); + err = status; + // Keep going, with error raised. + } + } + + // Update the state. + st.mCurrentTexture = slot; + st.mCurrentCrop = item.mCrop; + st.mCurrentTransform = item.mTransform; + st.mCurrentScalingMode = item.mScalingMode; + st.mCurrentTimestamp = item.mTimestamp; + st.mCurrentDataSpace = item.mDataSpace; + st.mCurrentFence = item.mFence; + st.mCurrentFenceTime = item.mFenceTime; + st.mCurrentFrameNumber = item.mFrameNumber; + st.computeCurrentTransformMatrixLocked(); + + *queueEmpty = false; + mImageSlots[slot].createIfNeeded(st.mSlots[slot].mGraphicBuffer); + return mImageSlots[slot].mImage; +} + +} /* namespace android */ diff --git a/libs/hwui/surfacetexture/ImageConsumer.h b/libs/hwui/surfacetexture/ImageConsumer.h new file mode 100644 index 000000000000..31ee8db52874 --- /dev/null +++ b/libs/hwui/surfacetexture/ImageConsumer.h @@ -0,0 +1,97 @@ +/* + * 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. + */ + +#pragma once + +#include <EGL/egl.h> +#include <EGL/eglext.h> + +#include <gui/BufferQueueDefs.h> + +#include <SkImage.h> +#include <cutils/compiler.h> +#include <gui/BufferItem.h> +#include <system/graphics.h> + +namespace android { + +namespace uirenderer { +class RenderState; +} + +class SurfaceTexture; + +/* + * ImageConsumer implements the parts of SurfaceTexture that deal with + * images consumed by HWUI view system. + */ +class ImageConsumer { +public: + sk_sp<SkImage> dequeueImage(bool* queueEmpty, SurfaceTexture& cb, + uirenderer::RenderState& renderState); + + /** + * onAcquireBufferLocked amends the ConsumerBase method to update the + * mImageSlots array in addition to the ConsumerBase behavior. + */ + void onAcquireBufferLocked(BufferItem* item); + + /** + * onReleaseBufferLocked amends the ConsumerBase method to update the + * mImageSlots array in addition to the ConsumerBase. + */ + void onReleaseBufferLocked(int slot); + + /** + * onFreeBufferLocked frees up the given buffer slot. If the slot has been + * initialized this will release the reference to the GraphicBuffer in that + * slot and destroy the SkImage in that slot. Otherwise it has no effect. + */ + void onFreeBufferLocked(int slotIndex); + +private: + /** + * ImageSlot contains the information and object references that + * ImageConsumer maintains about a BufferQueue buffer slot. + */ + struct ImageSlot { + ImageSlot() : mEglFence(EGL_NO_SYNC_KHR) {} + + // mImage is the SkImage created from mGraphicBuffer. + sk_sp<SkImage> mImage; + + /** + * mEglFence is the EGL sync object that must signal before the buffer + * associated with this buffer slot may be dequeued. + */ + EGLSyncKHR mEglFence; + + void createIfNeeded(sp<GraphicBuffer> graphicBuffer); + }; + + /** + * ImageConsumer stores the SkImages that have been allocated by the BufferQueue + * for each buffer slot. It is initialized to null pointers, and gets + * filled in with the result of BufferQueue::acquire when the + * client dequeues a buffer from a + * slot that has not yet been used. The buffer allocated to a slot will also + * be replaced if the requested buffer usage or geometry differs from that + * of the buffer allocated to a slot. + */ + ImageSlot mImageSlots[BufferQueueDefs::NUM_BUFFER_SLOTS]; +}; + +}; /* namespace android */ diff --git a/libs/hwui/surfacetexture/SurfaceTexture.cpp b/libs/hwui/surfacetexture/SurfaceTexture.cpp new file mode 100644 index 000000000000..4bff715822e8 --- /dev/null +++ b/libs/hwui/surfacetexture/SurfaceTexture.cpp @@ -0,0 +1,496 @@ +/* + * 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 <cutils/compiler.h> +#include <gui/BufferQueue.h> +#include <math/mat4.h> +#include <system/window.h> + +#include <utils/Trace.h> + +#include "Matrix.h" +#include "SurfaceTexture.h" + +namespace android { + +// Macros for including the SurfaceTexture name in log messages +#define SFT_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__) +#define SFT_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__) +#define SFT_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__) +#define SFT_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__) + +static const mat4 mtxIdentity; + +SurfaceTexture::SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t tex, + uint32_t texTarget, bool useFenceSync, bool isControlledByApp) + : ConsumerBase(bq, isControlledByApp) + , mCurrentCrop(Rect::EMPTY_RECT) + , mCurrentTransform(0) + , mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE) + , mCurrentFence(Fence::NO_FENCE) + , mCurrentTimestamp(0) + , mCurrentDataSpace(HAL_DATASPACE_UNKNOWN) + , mCurrentFrameNumber(0) + , mDefaultWidth(1) + , mDefaultHeight(1) + , mFilteringEnabled(true) + , mTexName(tex) + , mUseFenceSync(useFenceSync) + , mTexTarget(texTarget) + , mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT) + , mOpMode(OpMode::attachedToGL) { + SFT_LOGV("SurfaceTexture"); + + memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix)); + + mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); +} + +SurfaceTexture::SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t texTarget, + bool useFenceSync, bool isControlledByApp) + : ConsumerBase(bq, isControlledByApp) + , mCurrentCrop(Rect::EMPTY_RECT) + , mCurrentTransform(0) + , mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE) + , mCurrentFence(Fence::NO_FENCE) + , mCurrentTimestamp(0) + , mCurrentDataSpace(HAL_DATASPACE_UNKNOWN) + , mCurrentFrameNumber(0) + , mDefaultWidth(1) + , mDefaultHeight(1) + , mFilteringEnabled(true) + , mTexName(0) + , mUseFenceSync(useFenceSync) + , mTexTarget(texTarget) + , mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT) + , mOpMode(OpMode::detached) { + SFT_LOGV("SurfaceTexture"); + + memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix)); + + mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS); +} + +status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h) { + Mutex::Autolock lock(mMutex); + if (mAbandoned) { + SFT_LOGE("setDefaultBufferSize: SurfaceTexture is abandoned!"); + return NO_INIT; + } + mDefaultWidth = w; + mDefaultHeight = h; + return mConsumer->setDefaultBufferSize(w, h); +} + +status_t SurfaceTexture::updateTexImage() { + ATRACE_CALL(); + SFT_LOGV("updateTexImage"); + Mutex::Autolock lock(mMutex); + + if (mAbandoned) { + SFT_LOGE("updateTexImage: SurfaceTexture is abandoned!"); + return NO_INIT; + } + + return mEGLConsumer.updateTexImage(*this); +} + +status_t SurfaceTexture::releaseTexImage() { + // releaseTexImage can be invoked even when not attached to a GL context. + ATRACE_CALL(); + SFT_LOGV("releaseTexImage"); + Mutex::Autolock lock(mMutex); + + if (mAbandoned) { + SFT_LOGE("releaseTexImage: SurfaceTexture is abandoned!"); + return NO_INIT; + } + + return mEGLConsumer.releaseTexImage(*this); +} + +status_t SurfaceTexture::acquireBufferLocked(BufferItem* item, nsecs_t presentWhen, + uint64_t maxFrameNumber) { + status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen, maxFrameNumber); + if (err != NO_ERROR) { + return err; + } + + switch (mOpMode) { + case OpMode::attachedToView: + mImageConsumer.onAcquireBufferLocked(item); + break; + case OpMode::attachedToGL: + mEGLConsumer.onAcquireBufferLocked(item, *this); + break; + case OpMode::detached: + break; + } + + return NO_ERROR; +} + +status_t SurfaceTexture::releaseBufferLocked(int buf, sp<GraphicBuffer> graphicBuffer, + EGLDisplay display, EGLSyncKHR eglFence) { + // release the buffer if it hasn't already been discarded by the + // BufferQueue. This can happen, for example, when the producer of this + // buffer has reallocated the original buffer slot after this buffer + // was acquired. + status_t err = ConsumerBase::releaseBufferLocked(buf, graphicBuffer, display, eglFence); + // We could be releasing an EGL buffer, even if not currently attached to a GL context. + mImageConsumer.onReleaseBufferLocked(buf); + mEGLConsumer.onReleaseBufferLocked(buf); + return err; +} + +status_t SurfaceTexture::detachFromContext() { + ATRACE_CALL(); + SFT_LOGV("detachFromContext"); + Mutex::Autolock lock(mMutex); + + if (mAbandoned) { + SFT_LOGE("detachFromContext: abandoned SurfaceTexture"); + return NO_INIT; + } + + if (mOpMode != OpMode::attachedToGL) { + SFT_LOGE("detachFromContext: SurfaceTexture is not attached to a GL context"); + return INVALID_OPERATION; + } + + status_t err = mEGLConsumer.detachFromContext(*this); + if (err == OK) { + mOpMode = OpMode::detached; + } + + return err; +} + +status_t SurfaceTexture::attachToContext(uint32_t tex) { + ATRACE_CALL(); + SFT_LOGV("attachToContext"); + Mutex::Autolock lock(mMutex); + + if (mAbandoned) { + SFT_LOGE("attachToContext: abandoned SurfaceTexture"); + return NO_INIT; + } + + if (mOpMode != OpMode::detached) { + SFT_LOGE( + "attachToContext: SurfaceTexture is already attached to a " + "context"); + return INVALID_OPERATION; + } + + if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { + // release possible ImageConsumer cache + mImageConsumer.onFreeBufferLocked(mCurrentTexture); + } + + return mEGLConsumer.attachToContext(tex, *this); +} + +void SurfaceTexture::attachToView() { + ATRACE_CALL(); + Mutex::Autolock _l(mMutex); + if (mAbandoned) { + SFT_LOGE("attachToView: abandoned SurfaceTexture"); + return; + } + if (mOpMode == OpMode::detached) { + mOpMode = OpMode::attachedToView; + + if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { + // release possible EGLConsumer texture cache + mEGLConsumer.onFreeBufferLocked(mCurrentTexture); + mEGLConsumer.onAbandonLocked(); + } + } else { + SFT_LOGE("attachToView: already attached"); + } +} + +void SurfaceTexture::detachFromView() { + ATRACE_CALL(); + Mutex::Autolock _l(mMutex); + + if (mAbandoned) { + SFT_LOGE("detachFromView: abandoned SurfaceTexture"); + return; + } + + if (mOpMode == OpMode::attachedToView) { + mOpMode = OpMode::detached; + } else { + SFT_LOGE("detachFromView: not attached to View"); + } +} + +uint32_t SurfaceTexture::getCurrentTextureTarget() const { + return mTexTarget; +} + +void SurfaceTexture::getTransformMatrix(float mtx[16]) { + Mutex::Autolock lock(mMutex); + memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix)); +} + +void SurfaceTexture::setFilteringEnabled(bool enabled) { + Mutex::Autolock lock(mMutex); + if (mAbandoned) { + SFT_LOGE("setFilteringEnabled: SurfaceTexture is abandoned!"); + return; + } + bool needsRecompute = mFilteringEnabled != enabled; + mFilteringEnabled = enabled; + + if (needsRecompute && mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT) { + SFT_LOGD("setFilteringEnabled called with no current item"); + } + + if (needsRecompute && mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) { + computeCurrentTransformMatrixLocked(); + } +} + +void SurfaceTexture::computeCurrentTransformMatrixLocked() { + SFT_LOGV("computeCurrentTransformMatrixLocked"); + sp<GraphicBuffer> buf = (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT) + ? nullptr + : mSlots[mCurrentTexture].mGraphicBuffer; + if (buf == nullptr) { + SFT_LOGD("computeCurrentTransformMatrixLocked: no current item"); + } + computeTransformMatrix(mCurrentTransformMatrix, buf, mCurrentCrop, mCurrentTransform, + mFilteringEnabled); +} + +void SurfaceTexture::computeTransformMatrix(float outTransform[16], const sp<GraphicBuffer>& buf, + const Rect& cropRect, uint32_t transform, + bool filtering) { + // Transform matrices + static const mat4 mtxFlipH(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); + static const mat4 mtxFlipV(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1); + static const mat4 mtxRot90(0, 1, 0, 0, -1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1); + + mat4 xform; + if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) { + xform *= mtxFlipH; + } + if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) { + xform *= mtxFlipV; + } + if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) { + xform *= mtxRot90; + } + + if (!cropRect.isEmpty() && buf.get()) { + float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f; + float bufferWidth = buf->getWidth(); + float bufferHeight = buf->getHeight(); + float shrinkAmount = 0.0f; + if (filtering) { + // In order to prevent bilinear sampling beyond the edge of the + // crop rectangle we may need to shrink it by 2 texels in each + // dimension. Normally this would just need to take 1/2 a texel + // off each end, but because the chroma channels of YUV420 images + // are subsampled we may need to shrink the crop region by a whole + // texel on each side. + switch (buf->getPixelFormat()) { + case PIXEL_FORMAT_RGBA_8888: + case PIXEL_FORMAT_RGBX_8888: + case PIXEL_FORMAT_RGBA_FP16: + case PIXEL_FORMAT_RGBA_1010102: + case PIXEL_FORMAT_RGB_888: + case PIXEL_FORMAT_RGB_565: + case PIXEL_FORMAT_BGRA_8888: + // We know there's no subsampling of any channels, so we + // only need to shrink by a half a pixel. + shrinkAmount = 0.5; + break; + + default: + // If we don't recognize the format, we must assume the + // worst case (that we care about), which is YUV420. + shrinkAmount = 1.0; + break; + } + } + + // Only shrink the dimensions that are not the size of the buffer. + if (cropRect.width() < bufferWidth) { + tx = (float(cropRect.left) + shrinkAmount) / bufferWidth; + sx = (float(cropRect.width()) - (2.0f * shrinkAmount)) / bufferWidth; + } + if (cropRect.height() < bufferHeight) { + ty = (float(bufferHeight - cropRect.bottom) + shrinkAmount) / bufferHeight; + sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) / bufferHeight; + } + + mat4 crop(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, 1, 0, tx, ty, 0, 1); + xform = crop * xform; + } + + // SurfaceFlinger expects the top of its window textures to be at a Y + // coordinate of 0, so SurfaceTexture must behave the same way. We don't + // want to expose this to applications, however, so we must add an + // additional vertical flip to the transform after all the other transforms. + xform = mtxFlipV * xform; + + memcpy(outTransform, xform.asArray(), sizeof(xform)); +} + +Rect SurfaceTexture::scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight) { + Rect outCrop = crop; + + uint32_t newWidth = static_cast<uint32_t>(crop.width()); + uint32_t newHeight = static_cast<uint32_t>(crop.height()); + + if (newWidth * bufferHeight > newHeight * bufferWidth) { + newWidth = newHeight * bufferWidth / bufferHeight; + ALOGV("too wide: newWidth = %d", newWidth); + } else if (newWidth * bufferHeight < newHeight * bufferWidth) { + newHeight = newWidth * bufferHeight / bufferWidth; + ALOGV("too tall: newHeight = %d", newHeight); + } + + uint32_t currentWidth = static_cast<uint32_t>(crop.width()); + uint32_t currentHeight = static_cast<uint32_t>(crop.height()); + + // The crop is too wide + if (newWidth < currentWidth) { + uint32_t dw = currentWidth - newWidth; + auto halfdw = dw / 2; + outCrop.left += halfdw; + // Not halfdw because it would subtract 1 too few when dw is odd + outCrop.right -= (dw - halfdw); + // The crop is too tall + } else if (newHeight < currentHeight) { + uint32_t dh = currentHeight - newHeight; + auto halfdh = dh / 2; + outCrop.top += halfdh; + // Not halfdh because it would subtract 1 too few when dh is odd + outCrop.bottom -= (dh - halfdh); + } + + ALOGV("getCurrentCrop final crop [%d,%d,%d,%d]", outCrop.left, outCrop.top, outCrop.right, + outCrop.bottom); + + return outCrop; +} + +nsecs_t SurfaceTexture::getTimestamp() { + SFT_LOGV("getTimestamp"); + Mutex::Autolock lock(mMutex); + return mCurrentTimestamp; +} + +android_dataspace SurfaceTexture::getCurrentDataSpace() { + SFT_LOGV("getCurrentDataSpace"); + Mutex::Autolock lock(mMutex); + return mCurrentDataSpace; +} + +uint64_t SurfaceTexture::getFrameNumber() { + SFT_LOGV("getFrameNumber"); + Mutex::Autolock lock(mMutex); + return mCurrentFrameNumber; +} + +Rect SurfaceTexture::getCurrentCrop() const { + Mutex::Autolock lock(mMutex); + return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) + ? scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight) + : mCurrentCrop; +} + +uint32_t SurfaceTexture::getCurrentTransform() const { + Mutex::Autolock lock(mMutex); + return mCurrentTransform; +} + +uint32_t SurfaceTexture::getCurrentScalingMode() const { + Mutex::Autolock lock(mMutex); + return mCurrentScalingMode; +} + +sp<Fence> SurfaceTexture::getCurrentFence() const { + Mutex::Autolock lock(mMutex); + return mCurrentFence; +} + +std::shared_ptr<FenceTime> SurfaceTexture::getCurrentFenceTime() const { + Mutex::Autolock lock(mMutex); + return mCurrentFenceTime; +} + +void SurfaceTexture::freeBufferLocked(int slotIndex) { + SFT_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); + if (slotIndex == mCurrentTexture) { + mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT; + } + // The slotIndex buffer could have EGL or SkImage cache, but there is no way to tell for sure. + // Buffers can be freed after SurfaceTexture has detached from GL context or View. + mImageConsumer.onFreeBufferLocked(slotIndex); + mEGLConsumer.onFreeBufferLocked(slotIndex); + ConsumerBase::freeBufferLocked(slotIndex); +} + +void SurfaceTexture::abandonLocked() { + SFT_LOGV("abandonLocked"); + mEGLConsumer.onAbandonLocked(); + ConsumerBase::abandonLocked(); +} + +status_t SurfaceTexture::setConsumerUsageBits(uint64_t usage) { + return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS); +} + +void SurfaceTexture::dumpLocked(String8& result, const char* prefix) const { + result.appendFormat( + "%smTexName=%d mCurrentTexture=%d\n" + "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n", + prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left, mCurrentCrop.top, + mCurrentCrop.right, mCurrentCrop.bottom, mCurrentTransform); + + ConsumerBase::dumpLocked(result, prefix); +} + +sk_sp<SkImage> SurfaceTexture::dequeueImage(SkMatrix& transformMatrix, android_dataspace& dataSpace, + bool* queueEmpty, + uirenderer::RenderState& renderState) { + Mutex::Autolock _l(mMutex); + + if (mAbandoned) { + SFT_LOGE("dequeueImage: SurfaceTexture is abandoned!"); + return nullptr; + } + + if (mOpMode != OpMode::attachedToView) { + SFT_LOGE("dequeueImage: SurfaceTexture is not attached to a View"); + return nullptr; + } + + auto image = mImageConsumer.dequeueImage(queueEmpty, *this, renderState); + if (image.get()) { + uirenderer::mat4(mCurrentTransformMatrix).copyTo(transformMatrix); + dataSpace = mCurrentDataSpace; + } + return image; +} + +}; // namespace android diff --git a/libs/hwui/surfacetexture/SurfaceTexture.h b/libs/hwui/surfacetexture/SurfaceTexture.h new file mode 100644 index 000000000000..db392a9f8476 --- /dev/null +++ b/libs/hwui/surfacetexture/SurfaceTexture.h @@ -0,0 +1,452 @@ +/* + * 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. + */ + +#pragma once + +#include <gui/BufferQueueDefs.h> +#include <gui/ConsumerBase.h> + +#include <ui/FenceTime.h> +#include <ui/GraphicBuffer.h> + +#include <utils/Mutex.h> +#include <utils/String8.h> + +#include "EGLConsumer.h" +#include "ImageConsumer.h" + +namespace android { + +namespace uirenderer { +class RenderState; +} + +/* + * SurfaceTexture consumes buffers of graphics data from a BufferQueue, + * and makes them available to HWUI render thread as a SkImage and to + * an application GL render thread as an OpenGL texture. + * + * When attached to an application GL render thread, a typical usage + * pattern is to set up the SurfaceTexture with the + * desired options, and call updateTexImage() when a new frame is desired. + * If a new frame is available, the texture will be updated. If not, + * the previous contents are retained. + * + * When attached to a HWUI render thread, the TextureView implementation + * calls dequeueImage, which either pulls a new SkImage or returns the + * last cached SkImage if BufferQueue is empty. + * When attached to HWUI render thread, SurfaceTexture is compatible to + * both Vulkan and GL drawing pipelines. + */ +class ANDROID_API SurfaceTexture : public ConsumerBase { +public: + enum { TEXTURE_EXTERNAL = 0x8D65 }; // GL_TEXTURE_EXTERNAL_OES + typedef ConsumerBase::FrameAvailableListener FrameAvailableListener; + + /** + * SurfaceTexture constructs a new SurfaceTexture object. If the constructor with + * the tex parameter is used, tex indicates the name of the OpenGL ES + * texture to which images are to be streamed. texTarget specifies the + * OpenGL ES texture target to which the texture will be bound in + * updateTexImage. useFenceSync specifies whether fences should be used to + * synchronize access to buffers if that behavior is enabled at + * compile-time. + * + * A SurfaceTexture may be detached from one OpenGL ES context and then + * attached to a different context using the detachFromContext and + * attachToContext methods, respectively. The intention of these methods is + * purely to allow a SurfaceTexture to be transferred from one consumer + * context to another. If such a transfer is not needed there is no + * requirement that either of these methods be called. + * + * If the constructor with the tex parameter is used, the SurfaceTexture is + * created in a state where it is considered attached to an OpenGL ES + * context for the purposes of the attachToContext and detachFromContext + * methods. However, despite being considered "attached" to a context, the + * specific OpenGL ES context doesn't get latched until the first call to + * updateTexImage. After that point, all calls to updateTexImage must be + * made with the same OpenGL ES context current. + * + * If the constructor without the tex parameter is used, the SurfaceTexture is + * created in a detached state, and attachToContext must be called before + * calls to updateTexImage. + */ + SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t tex, uint32_t texureTarget, + bool useFenceSync, bool isControlledByApp); + + SurfaceTexture(const sp<IGraphicBufferConsumer>& bq, uint32_t texureTarget, bool useFenceSync, + bool isControlledByApp); + + /** + * updateTexImage acquires the most recently queued buffer, and sets the + * image contents of the target texture to it. + * + * This call may only be made while the OpenGL ES context to which the + * target texture belongs is bound to the calling thread. + * + * This calls doGLFenceWait to ensure proper synchronization. + */ + status_t updateTexImage(); + + /** + * releaseTexImage releases the texture acquired in updateTexImage(). + * This is intended to be used in single buffer mode. + * + * This call may only be made while the OpenGL ES context to which the + * target texture belongs is bound to the calling thread. + */ + status_t releaseTexImage(); + + /** + * getTransformMatrix retrieves the 4x4 texture coordinate transform matrix + * associated with the texture image set by the most recent call to + * updateTexImage. + * + * This transform matrix maps 2D homogeneous texture coordinates of the form + * (s, t, 0, 1) with s and t in the inclusive range [0, 1] to the texture + * coordinate that should be used to sample that location from the texture. + * Sampling the texture outside of the range of this transform is undefined. + * + * This transform is necessary to compensate for transforms that the stream + * content producer may implicitly apply to the content. By forcing users of + * a SurfaceTexture to apply this transform we avoid performing an extra + * copy of the data that would be needed to hide the transform from the + * user. + * + * The matrix is stored in column-major order so that it may be passed + * directly to OpenGL ES via the glLoadMatrixf or glUniformMatrix4fv + * functions. + */ + void getTransformMatrix(float mtx[16]); + + /** + * Computes the transform matrix documented by getTransformMatrix + * from the BufferItem sub parts. + */ + static void computeTransformMatrix(float outTransform[16], const sp<GraphicBuffer>& buf, + const Rect& cropRect, uint32_t transform, bool filtering); + + /** + * Scale the crop down horizontally or vertically such that it has the + * same aspect ratio as the buffer does. + */ + static Rect scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight); + + /** + * getTimestamp retrieves the timestamp associated with the texture image + * set by the most recent call to updateTexImage. + * + * The timestamp is in nanoseconds, and is monotonically increasing. Its + * other semantics (zero point, etc) are source-dependent and should be + * documented by the source. + */ + int64_t getTimestamp(); + + /** + * getDataSpace retrieves the DataSpace associated with the texture image + * set by the most recent call to updateTexImage. + */ + android_dataspace getCurrentDataSpace(); + + /** + * getFrameNumber retrieves the frame number associated with the texture + * image set by the most recent call to updateTexImage. + * + * The frame number is an incrementing counter set to 0 at the creation of + * the BufferQueue associated with this consumer. + */ + uint64_t getFrameNumber(); + + /** + * setDefaultBufferSize is used to set the size of buffers returned by + * requestBuffers when a with and height of zero is requested. + * A call to setDefaultBufferSize() may trigger requestBuffers() to + * be called from the client. + * The width and height parameters must be no greater than the minimum of + * GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv). + * An error due to invalid dimensions might not be reported until + * updateTexImage() is called. + */ + status_t setDefaultBufferSize(uint32_t width, uint32_t height); + + /** + * setFilteringEnabled sets whether the transform matrix should be computed + * for use with bilinear filtering. + */ + void setFilteringEnabled(bool enabled); + + /** + * getCurrentTextureTarget returns the texture target of the current + * texture as returned by updateTexImage(). + */ + uint32_t getCurrentTextureTarget() const; + + /** + * getCurrentCrop returns the cropping rectangle of the current buffer. + */ + Rect getCurrentCrop() const; + + /** + * getCurrentTransform returns the transform of the current buffer. + */ + uint32_t getCurrentTransform() const; + + /** + * getCurrentScalingMode returns the scaling mode of the current buffer. + */ + uint32_t getCurrentScalingMode() const; + + /** + * getCurrentFence returns the fence indicating when the current buffer is + * ready to be read from. + */ + sp<Fence> getCurrentFence() const; + + /** + * getCurrentFence returns the FenceTime indicating when the current + * buffer is ready to be read from. + */ + std::shared_ptr<FenceTime> getCurrentFenceTime() const; + + /** + * setConsumerUsageBits overrides the ConsumerBase method to OR + * DEFAULT_USAGE_FLAGS to usage. + */ + status_t setConsumerUsageBits(uint64_t usage); + + /** + * detachFromContext detaches the SurfaceTexture from the calling thread's + * current OpenGL ES context. This context must be the same as the context + * that was current for previous calls to updateTexImage. + * + * Detaching a SurfaceTexture from an OpenGL ES context will result in the + * deletion of the OpenGL ES texture object into which the images were being + * streamed. After a SurfaceTexture has been detached from the OpenGL ES + * context calls to updateTexImage will fail returning INVALID_OPERATION + * until the SurfaceTexture is attached to a new OpenGL ES context using the + * attachToContext method. + */ + status_t detachFromContext(); + + /** + * attachToContext attaches a SurfaceTexture that is currently in the + * 'detached' state to the current OpenGL ES context. A SurfaceTexture is + * in the 'detached' state iff detachFromContext has successfully been + * called and no calls to attachToContext have succeeded since the last + * detachFromContext call. Calls to attachToContext made on a + * SurfaceTexture that is not in the 'detached' state will result in an + * INVALID_OPERATION error. + * + * The tex argument specifies the OpenGL ES texture object name in the + * new context into which the image contents will be streamed. A successful + * call to attachToContext will result in this texture object being bound to + * the texture target and populated with the image contents that were + * current at the time of the last call to detachFromContext. + */ + status_t attachToContext(uint32_t tex); + + sk_sp<SkImage> dequeueImage(SkMatrix& transformMatrix, android_dataspace& dataSpace, + bool* queueEmpty, uirenderer::RenderState& renderState); + + /** + * attachToView attaches a SurfaceTexture that is currently in the + * 'detached' state to HWUI View system. + */ + void attachToView(); + + /** + * detachFromView detaches a SurfaceTexture from HWUI View system. + */ + void detachFromView(); + +protected: + /** + * abandonLocked overrides the ConsumerBase method to clear + * mCurrentTextureImage in addition to the ConsumerBase behavior. + */ + virtual void abandonLocked(); + + /** + * dumpLocked overrides the ConsumerBase method to dump SurfaceTexture- + * specific info in addition to the ConsumerBase behavior. + */ + virtual void dumpLocked(String8& result, const char* prefix) const override; + + /** + * acquireBufferLocked overrides the ConsumerBase method to update the + * mEglSlots array in addition to the ConsumerBase behavior. + */ + virtual status_t acquireBufferLocked(BufferItem* item, nsecs_t presentWhen, + uint64_t maxFrameNumber = 0) override; + + /** + * releaseBufferLocked overrides the ConsumerBase method to update the + * mEglSlots array in addition to the ConsumerBase. + */ + virtual status_t releaseBufferLocked(int slot, const sp<GraphicBuffer> graphicBuffer, + EGLDisplay display, EGLSyncKHR eglFence) override; + + /** + * freeBufferLocked frees up the given buffer slot. If the slot has been + * initialized this will release the reference to the GraphicBuffer in that + * slot and destroy the EGLImage in that slot. Otherwise it has no effect. + * + * This method must be called with mMutex locked. + */ + virtual void freeBufferLocked(int slotIndex); + + /** + * computeCurrentTransformMatrixLocked computes the transform matrix for the + * current texture. It uses mCurrentTransform and the current GraphicBuffer + * to compute this matrix and stores it in mCurrentTransformMatrix. + * mCurrentTextureImage must not be NULL. + */ + void computeCurrentTransformMatrixLocked(); + + /** + * The default consumer usage flags that SurfaceTexture always sets on its + * BufferQueue instance; these will be OR:d with any additional flags passed + * from the SurfaceTexture user. In particular, SurfaceTexture will always + * consume buffers as hardware textures. + */ + static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE; + + /** + * mCurrentCrop is the crop rectangle that applies to the current texture. + * It gets set each time updateTexImage is called. + */ + Rect mCurrentCrop; + + /** + * mCurrentTransform is the transform identifier for the current texture. It + * gets set each time updateTexImage is called. + */ + uint32_t mCurrentTransform; + + /** + * mCurrentScalingMode is the scaling mode for the current texture. It gets + * set each time updateTexImage is called. + */ + uint32_t mCurrentScalingMode; + + /** + * mCurrentFence is the fence received from BufferQueue in updateTexImage. + */ + sp<Fence> mCurrentFence; + + /** + * The FenceTime wrapper around mCurrentFence. + */ + std::shared_ptr<FenceTime> mCurrentFenceTime{FenceTime::NO_FENCE}; + + /** + * mCurrentTransformMatrix is the transform matrix for the current texture. + * It gets computed by computeTransformMatrix each time updateTexImage is + * called. + */ + float mCurrentTransformMatrix[16]; + + /** + * mCurrentTimestamp is the timestamp for the current texture. It + * gets set each time updateTexImage is called. + */ + int64_t mCurrentTimestamp; + + /** + * mCurrentDataSpace is the dataspace for the current texture. It + * gets set each time updateTexImage is called. + */ + android_dataspace mCurrentDataSpace; + + /** + * mCurrentFrameNumber is the frame counter for the current texture. + * It gets set each time updateTexImage is called. + */ + uint64_t mCurrentFrameNumber; + + uint32_t mDefaultWidth, mDefaultHeight; + + /** + * mFilteringEnabled indicates whether the transform matrix is computed for + * use with bilinear filtering. It defaults to true and is changed by + * setFilteringEnabled(). + */ + bool mFilteringEnabled; + + /** + * mTexName is the name of the OpenGL texture to which streamed images will + * be bound when updateTexImage is called. It is set at construction time + * and can be changed with a call to attachToContext. + */ + uint32_t mTexName; + + /** + * mUseFenceSync indicates whether creation of the EGL_KHR_fence_sync + * extension should be used to prevent buffers from being dequeued before + * it's safe for them to be written. It gets set at construction time and + * never changes. + */ + const bool mUseFenceSync; + + /** + * mTexTarget is the GL texture target with which the GL texture object is + * associated. It is set in the constructor and never changed. It is + * almost always GL_TEXTURE_EXTERNAL_OES except for one use case in Android + * Browser. In that case it is set to GL_TEXTURE_2D to allow + * glCopyTexSubImage to read from the texture. This is a hack to work + * around a GL driver limitation on the number of FBO attachments, which the + * browser's tile cache exceeds. + */ + const uint32_t mTexTarget; + + /** + * mCurrentTexture is the buffer slot index of the buffer that is currently + * bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT, + * indicating that no buffer slot is currently bound to the texture. Note, + * however, that a value of INVALID_BUFFER_SLOT does not necessarily mean + * that no buffer is bound to the texture. A call to setBufferCount will + * reset mCurrentTexture to INVALID_BUFFER_SLOT. + */ + int mCurrentTexture; + + enum class OpMode { detached, attachedToView, attachedToGL }; + /** + * mOpMode indicates whether the SurfaceTexture is currently attached to + * an OpenGL ES context or the HWUI view system. For legacy reasons, this is initialized to, + * "attachedToGL" indicating that the SurfaceTexture is considered to be attached to + * whatever GL context is current at the time of the first updateTexImage call. + * It is set to "detached" by detachFromContext, and then set to "attachedToGL" again by + * attachToContext. + * attachToView/detachFromView are used to attach/detach from HWUI view system. + */ + OpMode mOpMode; + + /** + * mEGLConsumer has SurfaceTexture logic used when attached to GL context. + */ + EGLConsumer mEGLConsumer; + + /** + * mImageConsumer has SurfaceTexture logic used when attached to HWUI view system. + */ + ImageConsumer mImageConsumer; + + friend class ImageConsumer; + friend class EGLConsumer; +}; + +// ---------------------------------------------------------------------------- +}; // namespace android diff --git a/libs/hwui/tests/common/LeakChecker.cpp b/libs/hwui/tests/common/LeakChecker.cpp index 5b361548eeda..d2d37dcb34f2 100644 --- a/libs/hwui/tests/common/LeakChecker.cpp +++ b/libs/hwui/tests/common/LeakChecker.cpp @@ -16,7 +16,6 @@ #include "LeakChecker.h" -#include "Caches.h" #include "TestUtils.h" #include <memunreachable/memunreachable.h> @@ -71,9 +70,6 @@ void LeakChecker::checkForLeaks() { // thread-local caches so some leaks will not be properly tagged as leaks UnreachableMemoryInfo rtMemInfo; TestUtils::runOnRenderThread([&rtMemInfo](renderthread::RenderThread& thread) { - if (Caches::hasInstance()) { - Caches::getInstance().tasks.stop(); - } // Check for leaks if (!GetUnreachableMemory(rtMemInfo)) { cerr << "Failed to get unreachable memory!" << endl; diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp index 69586345319e..66b9b85bdbe7 100644 --- a/libs/hwui/tests/common/TestUtils.cpp +++ b/libs/hwui/tests/common/TestUtils.cpp @@ -67,16 +67,14 @@ sp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater( renderthread::RenderThread& renderThread, uint32_t width, uint32_t height, const SkMatrix& transform) { sp<DeferredLayerUpdater> layerUpdater = createTextureLayerUpdater(renderThread); - layerUpdater->backingLayer()->getTransform().load(transform); + layerUpdater->backingLayer()->getTransform() = transform; layerUpdater->setSize(width, height); layerUpdater->setTransform(&transform); // updateLayer so it's ready to draw - layerUpdater->updateLayer(true, Matrix4::identity().data, HAL_DATASPACE_UNKNOWN); - if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) { - static_cast<GlLayer*>(layerUpdater->backingLayer()) - ->setRenderTarget(GL_TEXTURE_EXTERNAL_OES); - } + SkMatrix identity; + identity.setIdentity(); + layerUpdater->updateLayer(true, identity, HAL_DATASPACE_UNKNOWN, nullptr); return layerUpdater; } @@ -117,7 +115,6 @@ void TestUtils::TestTask::run() { if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) { renderThread.vulkanManager().destroy(); } else { - renderThread.renderState().flush(Caches::FlushMode::Full); renderThread.destroyGlContext(); } } diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h index 743f8093bfa8..0e6582c59a36 100644 --- a/libs/hwui/tests/common/TestUtils.h +++ b/libs/hwui/tests/common/TestUtils.h @@ -18,7 +18,6 @@ #include <DeviceInfo.h> #include <DisplayList.h> -#include <GlLayer.h> #include <Matrix.h> #include <Properties.h> #include <Rect.h> diff --git a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp index f29830f0e34b..6c8775b1bdbb 100644 --- a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp +++ b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp @@ -15,12 +15,13 @@ */ #include "DeferredLayerUpdater.h" -#include "GlLayer.h" #include "Properties.h" #include "tests/common/TestUtils.h" #include <gtest/gtest.h> +#include <SkBitmap.h> +#include <SkImage.h> using namespace android; using namespace android::uirenderer; @@ -31,10 +32,6 @@ RENDERTHREAD_TEST(DeferredLayerUpdater, updateLayer) { layerUpdater->setBlend(true); // updates are deferred so the backing layer should still be in its default state - if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) { - GlLayer* glLayer = static_cast<GlLayer*>(layerUpdater->backingLayer()); - EXPECT_EQ((uint32_t)GL_NONE, glLayer->getRenderTarget()); - } EXPECT_EQ(0u, layerUpdater->backingLayer()->getWidth()); EXPECT_EQ(0u, layerUpdater->backingLayer()->getHeight()); EXPECT_FALSE(layerUpdater->backingLayer()->getForceFilter()); @@ -42,19 +39,13 @@ RENDERTHREAD_TEST(DeferredLayerUpdater, updateLayer) { EXPECT_EQ(Matrix4::identity(), layerUpdater->backingLayer()->getTexTransform()); // push the deferred updates to the layer - Matrix4 scaledMatrix; - scaledMatrix.loadScale(0.5, 0.5, 0.0); - layerUpdater->updateLayer(true, scaledMatrix.data, HAL_DATASPACE_UNKNOWN); - if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) { - GlLayer* glLayer = static_cast<GlLayer*>(layerUpdater->backingLayer()); - glLayer->setRenderTarget(GL_TEXTURE_EXTERNAL_OES); - } + SkMatrix scaledMatrix = SkMatrix::MakeScale(0.5, 0.5); + SkBitmap bitmap; + bitmap.allocN32Pixels(16, 16); + sk_sp<SkImage> layerImage = SkImage::MakeFromBitmap(bitmap); + layerUpdater->updateLayer(true, scaledMatrix, HAL_DATASPACE_UNKNOWN, layerImage); // the backing layer should now have all the properties applied. - if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) { - GlLayer* glLayer = static_cast<GlLayer*>(layerUpdater->backingLayer()); - EXPECT_EQ((uint32_t)GL_TEXTURE_EXTERNAL_OES, glLayer->getRenderTarget()); - } EXPECT_EQ(100u, layerUpdater->backingLayer()->getWidth()); EXPECT_EQ(100u, layerUpdater->backingLayer()->getHeight()); EXPECT_TRUE(layerUpdater->backingLayer()->getForceFilter()); diff --git a/libs/hwui/tests/unit/FatalTestCanvas.h b/libs/hwui/tests/unit/FatalTestCanvas.h index 9693ce7b6784..89f0c52b49ec 100644 --- a/libs/hwui/tests/unit/FatalTestCanvas.h +++ b/libs/hwui/tests/unit/FatalTestCanvas.h @@ -42,10 +42,6 @@ public: const SkPaint& paint) { ADD_FAILURE() << "onDrawPosTextH not expected in this test"; } - void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, - const SkMatrix* matrix, const SkPaint& paint) { - ADD_FAILURE() << "onDrawTextOnPath not expected in this test"; - } void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform[], const SkRect* cullRect, const SkPaint& paint) { ADD_FAILURE() << "onDrawTextRSXform not expected in this test"; diff --git a/libs/hwui/tests/unit/main.cpp b/libs/hwui/tests/unit/main.cpp index 9e6d9a8c27de..aecceb3609f5 100644 --- a/libs/hwui/tests/unit/main.cpp +++ b/libs/hwui/tests/unit/main.cpp @@ -17,12 +17,13 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "Caches.h" #include "debug/GlesDriver.h" #include "debug/NullGlesDriver.h" #include "hwui/Typeface.h" #include "Properties.h" #include "tests/common/LeakChecker.h" +#include "thread/TaskProcessor.h" +#include "thread/Task.h" #include "thread/TaskManager.h" #include <signal.h> diff --git a/libs/hwui/utils/PaintUtils.h b/libs/hwui/utils/PaintUtils.h index f8e8a0a18284..ebf2343c5518 100644 --- a/libs/hwui/utils/PaintUtils.h +++ b/libs/hwui/utils/PaintUtils.h @@ -16,6 +16,7 @@ #ifndef PAINT_UTILS_H #define PAINT_UTILS_H +#include <GLES2/gl2.h> #include <utils/Blur.h> #include <SkColorFilter.h> diff --git a/native/android/Android.bp b/native/android/Android.bp index 4fb5e748aaac..43847cc4ab06 100644 --- a/native/android/Android.bp +++ b/native/android/Android.bp @@ -64,6 +64,7 @@ cc_library_shared { "libsensor", "libandroid_runtime", "libnetd_client", + "libhwui", ], static_libs: [ diff --git a/native/android/surface_texture.cpp b/native/android/surface_texture.cpp index b26688190ccd..ced2792775d4 100644 --- a/native/android/surface_texture.cpp +++ b/native/android/surface_texture.cpp @@ -21,15 +21,16 @@ #include <utils/Log.h> -#include <gui/GLConsumer.h> #include <gui/Surface.h> #include <android_runtime/android_graphics_SurfaceTexture.h> +#include "surfacetexture/SurfaceTexture.h" + using namespace android; struct ASurfaceTexture { - sp<GLConsumer> consumer; + sp<SurfaceTexture> consumer; sp<IGraphicBufferProducer> producer; }; diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java index 9f89d3cf14b9..149de1361ae1 100644 --- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java +++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java @@ -33,7 +33,6 @@ import android.net.NetworkRequest; import android.net.Proxy; import android.net.Uri; import android.net.captiveportal.CaptivePortalProbeSpec; -import android.net.dns.ResolvUtil; import android.net.http.SslError; import android.net.wifi.WifiInfo; import android.os.Build; @@ -132,9 +131,9 @@ public class CaptivePortalLoginActivity extends Activity { } // Also initializes proxy system properties. + mNetwork = mNetwork.getPrivateDnsBypassingCopy(); mCm.bindProcessToNetwork(mNetwork); - mCm.setProcessDefaultNetworkForHostResolution( - ResolvUtil.getNetworkWithUseLocalNameserversFlag(mNetwork)); + mCm.setProcessDefaultNetworkForHostResolution(mNetwork); // Proxy system properties must be initialized before setContentView is called because // setContentView initializes the WebView logic which in turn reads the system properties. @@ -334,7 +333,6 @@ public class CaptivePortalLoginActivity extends Activity { // TODO: reuse NetworkMonitor facilities for consistent captive portal detection. new Thread(new Runnable() { public void run() { - final Network network = ResolvUtil.makeNetworkWithPrivateDnsBypass(mNetwork); // Give time for captive portal to open. try { Thread.sleep(1000); @@ -344,7 +342,7 @@ public class CaptivePortalLoginActivity extends Activity { int httpResponseCode = 500; String locationHeader = null; try { - urlConnection = (HttpURLConnection) network.openConnection(mUrl); + urlConnection = (HttpURLConnection) mNetwork.openConnection(mUrl); urlConnection.setInstanceFollowRedirects(false); urlConnection.setConnectTimeout(SOCKET_TIMEOUT_MS); urlConnection.setReadTimeout(SOCKET_TIMEOUT_MS); diff --git a/packages/ExtServices/AndroidManifest.xml b/packages/ExtServices/AndroidManifest.xml index a7217ecabc35..ff70e9712bcc 100644 --- a/packages/ExtServices/AndroidManifest.xml +++ b/packages/ExtServices/AndroidManifest.xml @@ -55,6 +55,12 @@ <intent-filter> <action android:name="android.service.autofill.AutofillFieldClassificationService" /> </intent-filter> + <meta-data + android:name="android.autofill.field_classification.default_algorithm" + android:resource="@string/autofill_field_classification_default_algorithm" /> + <meta-data + android:name="android.autofill.field_classification.available_algorithms" + android:resource="@array/autofill_field_classification_available_algorithms" /> </service> <library android:name="android.ext.services"/> diff --git a/packages/SettingsLib/src/com/android/settingslib/CustomDialogPreference.java b/packages/SettingsLib/src/com/android/settingslib/CustomDialogPreference.java index cf1c2c348367..3bade25b712a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/CustomDialogPreference.java +++ b/packages/SettingsLib/src/com/android/settingslib/CustomDialogPreference.java @@ -20,11 +20,12 @@ import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; -import androidx.preference.PreferenceDialogFragment; -import androidx.preference.DialogPreference; import android.util.AttributeSet; import android.view.View; +import androidx.preference.DialogPreference; +import androidx.preference.PreferenceDialogFragment; + public class CustomDialogPreference extends DialogPreference { private CustomPreferenceDialogFragment mFragment; diff --git a/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java b/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java index 04c39540cf27..dfaff6108c89 100644 --- a/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java +++ b/packages/SettingsLib/src/com/android/settingslib/CustomEditTextPreference.java @@ -23,13 +23,14 @@ import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.os.Bundle; -import androidx.annotation.CallSuper; -import androidx.preference.EditTextPreferenceDialogFragment; -import androidx.preference.EditTextPreference; import android.util.AttributeSet; import android.view.View; import android.widget.EditText; +import androidx.annotation.CallSuper; +import androidx.preference.EditTextPreference; +import androidx.preference.EditTextPreferenceDialogFragment; + public class CustomEditTextPreference extends EditTextPreference { private CustomPreferenceDialogFragment mFragment; diff --git a/packages/SettingsLib/src/com/android/settingslib/DeviceInfoUtils.java b/packages/SettingsLib/src/com/android/settingslib/DeviceInfoUtils.java index c98bc39fe574..bc5a2c05e379 100644 --- a/packages/SettingsLib/src/com/android/settingslib/DeviceInfoUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/DeviceInfoUtils.java @@ -16,6 +16,8 @@ package com.android.settingslib; +import static android.content.Context.TELEPHONY_SERVICE; + import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; @@ -30,6 +32,7 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.text.format.DateFormat; import android.util.Log; + import androidx.annotation.VisibleForTesting; import java.io.BufferedReader; @@ -43,8 +46,6 @@ import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; -import static android.content.Context.TELEPHONY_SERVICE; - public class DeviceInfoUtils { private static final String TAG = "DeviceInfoUtils"; diff --git a/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java index 8055caaad536..4cbeb8a48f8f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java @@ -24,16 +24,15 @@ import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; -import android.content.res.Resources.Theme; import android.content.res.TypedArray; import android.net.Uri; import android.provider.Settings.Global; import android.text.TextUtils; import android.util.Log; -import android.util.TypedValue; import android.view.Menu; import android.view.MenuItem; import android.view.MenuItem.OnMenuItemClickListener; + import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java index 7f518c1d71d3..bd54edd80697 100644 --- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java @@ -35,7 +35,6 @@ import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; -import androidx.annotation.VisibleForTesting; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.ForegroundColorSpan; @@ -43,6 +42,8 @@ import android.text.style.ImageSpan; import android.view.MenuItem; import android.widget.TextView; +import androidx.annotation.VisibleForTesting; + import com.android.internal.widget.LockPatternUtils; import java.util.List; diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java index 79e011c6e7ed..ad7e995412aa 100644 --- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java +++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java @@ -16,15 +16,16 @@ package com.android.settingslib; +import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; + import android.content.Context; import android.os.UserHandle; -import androidx.core.content.res.TypedArrayUtils; -import androidx.preference.PreferenceManager; -import androidx.preference.PreferenceViewHolder; import android.util.AttributeSet; import android.view.View; -import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; +import androidx.core.content.res.TypedArrayUtils; +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceViewHolder; /** * Preference class that supports being disabled by a user restriction diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java index a930bb8373ba..4b84920e7884 100644 --- a/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java +++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java @@ -16,19 +16,18 @@ package com.android.settingslib; +import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; + import android.content.Context; import android.content.res.TypedArray; -import android.graphics.drawable.Drawable; import android.os.UserHandle; -import androidx.preference.Preference; -import androidx.preference.PreferenceViewHolder; import android.text.TextUtils; import android.util.AttributeSet; import android.util.TypedValue; -import android.view.View; import android.widget.TextView; -import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; +import androidx.preference.Preference; +import androidx.preference.PreferenceViewHolder; /** * Helper class for managing settings preferences that can be disabled diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java index fe6d9fe77b73..0ed507c46372 100644 --- a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java +++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java @@ -21,15 +21,16 @@ import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import android.content.Context; import android.content.res.TypedArray; import android.os.UserHandle; -import androidx.preference.SwitchPreference; -import androidx.core.content.res.TypedArrayUtils; -import androidx.preference.PreferenceManager; -import androidx.preference.PreferenceViewHolder; import android.util.AttributeSet; import android.util.TypedValue; import android.view.View; import android.widget.TextView; +import androidx.core.content.res.TypedArrayUtils; +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceViewHolder; +import androidx.preference.SwitchPreference; + /** * Version of SwitchPreference that can be disabled by a device admin * using a user restriction. diff --git a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java index b8516dc9514f..a3ab4fdb6538 100644 --- a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java +++ b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java @@ -22,6 +22,7 @@ import android.net.ConnectivityManager; import android.os.SystemProperties; import android.os.UserHandle; import android.telephony.CarrierConfigManager; + import androidx.annotation.VisibleForTesting; public class TetherUtil { diff --git a/packages/SettingsLib/src/com/android/settingslib/TwoTargetPreference.java b/packages/SettingsLib/src/com/android/settingslib/TwoTargetPreference.java index 3a26f4649b64..02895a479352 100644 --- a/packages/SettingsLib/src/com/android/settingslib/TwoTargetPreference.java +++ b/packages/SettingsLib/src/com/android/settingslib/TwoTargetPreference.java @@ -18,13 +18,14 @@ package com.android.settingslib; import android.annotation.IntDef; import android.content.Context; -import androidx.preference.Preference; -import androidx.preference.PreferenceViewHolder; import android.util.AttributeSet; import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; +import androidx.preference.Preference; +import androidx.preference.PreferenceViewHolder; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/packages/SettingsLib/src/com/android/settingslib/animation/AppearAnimationUtils.java b/packages/SettingsLib/src/com/android/settingslib/animation/AppearAnimationUtils.java index df76125a99f2..efac6bc3572d 100644 --- a/packages/SettingsLib/src/com/android/settingslib/animation/AppearAnimationUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/animation/AppearAnimationUtils.java @@ -19,15 +19,12 @@ package com.android.settingslib.animation; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; -import android.animation.ValueAnimator; import android.content.Context; import android.view.RenderNodeAnimator; import android.view.View; -import android.view.ViewPropertyAnimator; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; -import com.android.internal.widget.LockPatternView; import com.android.settingslib.R; /** diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java index 21bac88e802b..663b1f5e4789 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java @@ -51,6 +51,11 @@ import android.util.IconDrawableFactory; import android.util.Log; import android.util.SparseArray; +import androidx.annotation.VisibleForTesting; +import androidx.lifecycle.Lifecycle; +import androidx.lifecycle.LifecycleObserver; +import androidx.lifecycle.OnLifecycleEvent; + import com.android.internal.R; import com.android.internal.util.ArrayUtils; @@ -71,11 +76,6 @@ import java.util.Objects; import java.util.UUID; import java.util.regex.Pattern; -import androidx.annotation.VisibleForTesting; -import androidx.lifecycle.Lifecycle; -import androidx.lifecycle.LifecycleObserver; -import androidx.lifecycle.OnLifecycleEvent; - /** * Keeps track of information about all installed applications, lazy-loading * as needed. diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java b/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java index b15f35ddc240..b457406dda03 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/StorageStatsSource.java @@ -21,6 +21,7 @@ import android.app.usage.StorageStatsManager; import android.content.Context; import android.content.pm.PackageManager; import android.os.UserHandle; + import androidx.annotation.VisibleForTesting; import java.io.IOException; diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java index 10fd6836f829..e071b7c5267b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java @@ -18,7 +18,6 @@ package com.android.settingslib.bluetooth; import android.bluetooth.BluetoothA2dp; import android.bluetooth.BluetoothAdapter; -import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHeadset; import android.bluetooth.BluetoothHearingAid; diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java index d8379757ea42..ee80aa159ab1 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java @@ -5,9 +5,10 @@ import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.graphics.drawable.Drawable; -import androidx.annotation.DrawableRes; import android.util.Pair; +import androidx.annotation.DrawableRes; + import com.android.settingslib.R; import com.android.settingslib.graph.BluetoothDeviceLayerDrawable; diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java index 68e1dfcfe959..649900bc97bd 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java @@ -16,6 +16,7 @@ package com.android.settingslib.bluetooth; +import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothHearingAid; @@ -27,7 +28,7 @@ import android.os.ParcelUuid; import android.os.SystemClock; import android.text.TextUtils; import android.util.Log; -import android.bluetooth.BluetoothAdapter; + import androidx.annotation.VisibleForTesting; import com.android.settingslib.R; diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java index 47bd853361ee..5a64e02cece4 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java @@ -31,8 +31,8 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.Objects; +import java.util.Set; /** * CachedBluetoothDeviceManager manages the set of remote Bluetooth devices. diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java index 6eaa62049e4c..1eeb4f058d1d 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HearingAidProfile.java @@ -16,10 +16,10 @@ package com.android.settingslib.bluetooth; -import android.bluetooth.BluetoothHearingAid; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothHearingAid; import android.bluetooth.BluetoothProfile; import android.content.Context; import android.util.Log; diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java index 4b4db753aba9..f9f623395801 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HfpClientProfile.java @@ -16,10 +16,10 @@ package com.android.settingslib.bluetooth; -import android.bluetooth.BluetoothHeadsetClient; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothHeadsetClient; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothUuid; import android.content.Context; diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java index 1c50953bac12..51601a509b9d 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothManager.java @@ -75,6 +75,8 @@ public class LocalBluetoothManager { mCachedDeviceManager, context); mProfileManager = new LocalBluetoothProfileManager(context, mLocalAdapter, mCachedDeviceManager, mEventManager); + + mProfileManager.updateLocalProfiles(); mEventManager.readPairedDevices(); } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java index 8bb8210631ed..36d209e96269 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManager.java @@ -35,8 +35,10 @@ import android.bluetooth.BluetoothUuid; import android.content.Context; import android.content.Intent; import android.os.ParcelUuid; -import androidx.annotation.VisibleForTesting; import android.util.Log; + +import androidx.annotation.VisibleForTesting; + import com.android.internal.R; import com.android.internal.util.CollectionUtils; @@ -119,7 +121,6 @@ public class LocalBluetoothProfileManager { // pass this reference to adapter and event manager (circular dependency) adapter.setProfileManager(this); - updateLocalProfiles(); if (DEBUG) Log.d(TAG, "LocalBluetoothProfileManager construction complete"); } diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java index e5c0b147f97b..dfd16224ef8f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/OppProfile.java @@ -16,12 +16,12 @@ package com.android.settingslib.bluetooth; -import com.android.settingslib.R; - import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothProfile; +import com.android.settingslib.R; + /** * OppProfile handles Bluetooth OPP. */ diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java index ad3506fc2611..b295f2425280 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/PbapClientProfile.java @@ -16,10 +16,10 @@ package com.android.settingslib.bluetooth; -import android.bluetooth.BluetoothPbapClient; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothPbapClient; import android.bluetooth.BluetoothProfile; import android.bluetooth.BluetoothUuid; import android.content.Context; diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java index f0e259e86456..61602c6463ee 100644 --- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java +++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/SapProfile.java @@ -19,8 +19,8 @@ package com.android.settingslib.bluetooth; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothClass; import android.bluetooth.BluetoothDevice; -import android.bluetooth.BluetoothSap; import android.bluetooth.BluetoothProfile; +import android.bluetooth.BluetoothSap; import android.bluetooth.BluetoothUuid; import android.content.Context; import android.os.ParcelUuid; diff --git a/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java index f4d647d61005..9572fb3c629d 100644 --- a/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java +++ b/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java @@ -1,6 +1,7 @@ package com.android.settingslib.core; import android.content.Context; + import androidx.preference.Preference; import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceScreen; diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/EventLogWriter.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/EventLogWriter.java index 72273046ef29..78963f3e1bfa 100644 --- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/EventLogWriter.java +++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/EventLogWriter.java @@ -18,7 +18,6 @@ package com.android.settingslib.core.instrumentation; import android.content.Context; import android.metrics.LogMaker; -import android.util.Log; import android.util.Pair; import com.android.internal.logging.MetricsLogger; diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SharedPreferencesLogger.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SharedPreferencesLogger.java index a79f125d4c99..a28e45ce08f7 100644 --- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SharedPreferencesLogger.java +++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/SharedPreferencesLogger.java @@ -20,11 +20,12 @@ import android.content.Context; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.os.AsyncTask; -import androidx.annotation.VisibleForTesting; import android.text.TextUtils; import android.util.Log; import android.util.Pair; +import androidx.annotation.VisibleForTesting; + import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import java.util.Map; diff --git a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java index cb1ca59d2f43..06d7c4d9cbc3 100644 --- a/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java +++ b/packages/SettingsLib/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixin.java @@ -16,17 +16,18 @@ package com.android.settingslib.core.instrumentation; +import static com.android.settingslib.core.instrumentation.Instrumentable.METRICS_CATEGORY_UNKNOWN; + import android.app.Activity; +import android.content.Intent; +import android.os.SystemClock; + import androidx.lifecycle.Lifecycle.Event; import androidx.lifecycle.LifecycleObserver; import androidx.lifecycle.OnLifecycleEvent; -import android.content.Intent; -import android.os.SystemClock; import com.android.internal.logging.nano.MetricsProto; -import static com.android.settingslib.core.instrumentation.Instrumentable.METRICS_CATEGORY_UNKNOWN; - /** * Logs visibility change of a fragment. */ diff --git a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/Lifecycle.java b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/Lifecycle.java index 7ec757a56217..56de280a0049 100644 --- a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/Lifecycle.java +++ b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/Lifecycle.java @@ -18,19 +18,20 @@ package com.android.settingslib.core.lifecycle; import static androidx.lifecycle.Lifecycle.Event.ON_ANY; import android.annotation.UiThread; -import androidx.lifecycle.LifecycleOwner; -import androidx.lifecycle.LifecycleRegistry; -import androidx.lifecycle.OnLifecycleEvent; import android.content.Context; import android.os.Bundle; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.preference.PreferenceScreen; import android.util.Log; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.lifecycle.LifecycleOwner; +import androidx.lifecycle.LifecycleRegistry; +import androidx.lifecycle.OnLifecycleEvent; +import androidx.preference.PreferenceScreen; + import com.android.settingslib.core.lifecycle.events.OnAttach; import com.android.settingslib.core.lifecycle.events.OnCreate; import com.android.settingslib.core.lifecycle.events.OnCreateOptionsMenu; diff --git a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnCreate.java b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnCreate.java index ada1537250b6..ae6741194662 100644 --- a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnCreate.java +++ b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnCreate.java @@ -16,12 +16,10 @@ package com.android.settingslib.core.lifecycle.events; -import androidx.lifecycle.Lifecycle; -import androidx.lifecycle.OnLifecycleEvent; import android.os.Bundle; /** - * @deprecated use {@link OnLifecycleEvent(Lifecycle.Event) } + * @deprecated use {@link androidx.lifecycle.OnLifecycleEvent} */ @Deprecated public interface OnCreate { diff --git a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnPrepareOptionsMenu.java b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnPrepareOptionsMenu.java index b9f13713c59f..92ae9fdd50a9 100644 --- a/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnPrepareOptionsMenu.java +++ b/packages/SettingsLib/src/com/android/settingslib/core/lifecycle/events/OnPrepareOptionsMenu.java @@ -17,7 +17,6 @@ package com.android.settingslib.core.lifecycle.events; import android.view.Menu; -import android.view.MenuInflater; public interface OnPrepareOptionsMenu { void onPrepareOptionsMenu(Menu menu); diff --git a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java index 75c2533d5d43..8fac3fd0570c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java +++ b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java @@ -20,9 +20,6 @@ import android.content.Context; import android.content.res.XmlResourceParser; import android.icu.text.TimeZoneFormat; import android.icu.text.TimeZoneNames; -import androidx.annotation.VisibleForTesting; -import androidx.core.text.BidiFormatter; -import androidx.core.text.TextDirectionHeuristicsCompat; import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.TextUtils; @@ -31,6 +28,10 @@ import android.text.style.TtsSpan; import android.util.Log; import android.view.View; +import androidx.annotation.VisibleForTesting; +import androidx.core.text.BidiFormatter; +import androidx.core.text.TextDirectionHeuristicsCompat; + import com.android.settingslib.R; import libcore.util.TimeZoneFinder; diff --git a/packages/SettingsLib/src/com/android/settingslib/development/AbstractEnableAdbPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/development/AbstractEnableAdbPreferenceController.java index b512448454f8..caabf9af35f6 100644 --- a/packages/SettingsLib/src/com/android/settingslib/development/AbstractEnableAdbPreferenceController.java +++ b/packages/SettingsLib/src/com/android/settingslib/development/AbstractEnableAdbPreferenceController.java @@ -22,13 +22,14 @@ import android.content.Context; import android.content.Intent; import android.os.UserManager; import android.provider.Settings; +import android.text.TextUtils; + import androidx.annotation.VisibleForTesting; -import androidx.preference.SwitchPreference; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; import androidx.preference.TwoStatePreference; -import android.text.TextUtils; import com.android.settingslib.core.ConfirmationDialogController; diff --git a/packages/SettingsLib/src/com/android/settingslib/development/AbstractLogdSizePreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/development/AbstractLogdSizePreferenceController.java index e2f6b7b87560..5a823976cd0e 100644 --- a/packages/SettingsLib/src/com/android/settingslib/development/AbstractLogdSizePreferenceController.java +++ b/packages/SettingsLib/src/com/android/settingslib/development/AbstractLogdSizePreferenceController.java @@ -19,6 +19,7 @@ package com.android.settingslib.development; import android.content.Context; import android.content.Intent; import android.os.SystemProperties; + import androidx.annotation.VisibleForTesting; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.preference.ListPreference; diff --git a/packages/SettingsLib/src/com/android/settingslib/development/AbstractLogpersistPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/development/AbstractLogpersistPreferenceController.java index f277c16a1e2c..87226746668e 100644 --- a/packages/SettingsLib/src/com/android/settingslib/development/AbstractLogpersistPreferenceController.java +++ b/packages/SettingsLib/src/com/android/settingslib/development/AbstractLogpersistPreferenceController.java @@ -22,12 +22,13 @@ import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.os.SystemProperties; +import android.text.TextUtils; + import androidx.annotation.VisibleForTesting; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.preference.ListPreference; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; -import android.text.TextUtils; import com.android.settingslib.R; import com.android.settingslib.core.ConfirmationDialogController; diff --git a/packages/SettingsLib/src/com/android/settingslib/development/DeveloperOptionsPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/development/DeveloperOptionsPreferenceController.java index 15d5522bbd7b..f757aa4e4dab 100644 --- a/packages/SettingsLib/src/com/android/settingslib/development/DeveloperOptionsPreferenceController.java +++ b/packages/SettingsLib/src/com/android/settingslib/development/DeveloperOptionsPreferenceController.java @@ -17,6 +17,7 @@ package com.android.settingslib.development; import android.content.Context; + import androidx.preference.Preference; import androidx.preference.PreferenceScreen; diff --git a/packages/SettingsLib/src/com/android/settingslib/development/DevelopmentSettingsEnabler.java b/packages/SettingsLib/src/com/android/settingslib/development/DevelopmentSettingsEnabler.java index 13d28fc6ef04..b191f888aa1a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/development/DevelopmentSettingsEnabler.java +++ b/packages/SettingsLib/src/com/android/settingslib/development/DevelopmentSettingsEnabler.java @@ -21,6 +21,7 @@ import android.content.Intent; import android.os.Build; import android.os.UserManager; import android.provider.Settings; + import androidx.localbroadcastmanager.content.LocalBroadcastManager; public class DevelopmentSettingsEnabler { diff --git a/packages/SettingsLib/src/com/android/settingslib/development/SystemPropPoker.java b/packages/SettingsLib/src/com/android/settingslib/development/SystemPropPoker.java index dba22d0c6af3..3f16be184c41 100644 --- a/packages/SettingsLib/src/com/android/settingslib/development/SystemPropPoker.java +++ b/packages/SettingsLib/src/com/android/settingslib/development/SystemPropPoker.java @@ -21,9 +21,10 @@ import android.os.IBinder; import android.os.Parcel; import android.os.RemoteException; import android.os.ServiceManager; +import android.util.Log; + import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; -import android.util.Log; public class SystemPropPoker { private static final String TAG = "SystemPropPoker"; diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractBluetoothAddressPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractBluetoothAddressPreferenceController.java index 821b4d5da049..745591235dbb 100644 --- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractBluetoothAddressPreferenceController.java +++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractBluetoothAddressPreferenceController.java @@ -19,10 +19,11 @@ package com.android.settingslib.deviceinfo; import android.annotation.SuppressLint; import android.bluetooth.BluetoothAdapter; import android.content.Context; +import android.text.TextUtils; + import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; -import android.text.TextUtils; import com.android.settingslib.R; import com.android.settingslib.core.lifecycle.Lifecycle; diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractImsStatusPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractImsStatusPreferenceController.java index 10260de289d3..a5f403690dab 100644 --- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractImsStatusPreferenceController.java +++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractImsStatusPreferenceController.java @@ -21,13 +21,14 @@ import android.content.Context; import android.net.ConnectivityManager; import android.net.wifi.WifiManager; import android.os.PersistableBundle; -import androidx.annotation.VisibleForTesting; -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + import com.android.settingslib.R; import com.android.settingslib.core.lifecycle.Lifecycle; diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractIpAddressPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractIpAddressPreferenceController.java index 45cd86667f1e..24da72ea611a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractIpAddressPreferenceController.java +++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractIpAddressPreferenceController.java @@ -20,6 +20,7 @@ import android.content.Context; import android.net.ConnectivityManager; import android.net.LinkProperties; import android.net.wifi.WifiManager; + import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractSerialNumberPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractSerialNumberPreferenceController.java index 60b29fb8682f..d28792ef30de 100644 --- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractSerialNumberPreferenceController.java +++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractSerialNumberPreferenceController.java @@ -18,10 +18,11 @@ package com.android.settingslib.deviceinfo; import android.content.Context; import android.os.Build; +import android.text.TextUtils; + import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; -import android.text.TextUtils; import com.android.settingslib.core.AbstractPreferenceController; diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractUptimePreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractUptimePreferenceController.java index ba93970cf24e..5f7226969699 100644 --- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractUptimePreferenceController.java +++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractUptimePreferenceController.java @@ -20,10 +20,11 @@ import android.content.Context; import android.os.Handler; import android.os.Message; import android.os.SystemClock; +import android.text.format.DateUtils; + import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; -import android.text.format.DateUtils; import com.android.settingslib.core.AbstractPreferenceController; import com.android.settingslib.core.lifecycle.Lifecycle; diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractWifiMacAddressPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractWifiMacAddressPreferenceController.java index ffbda3ae76ae..9699294df587 100644 --- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractWifiMacAddressPreferenceController.java +++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractWifiMacAddressPreferenceController.java @@ -22,10 +22,11 @@ import android.net.ConnectivityManager; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.provider.Settings; +import android.text.TextUtils; + import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; -import android.text.TextUtils; import com.android.settingslib.R; import com.android.settingslib.core.lifecycle.Lifecycle; diff --git a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java index af8fd4c46a64..e0ca1ab0c07c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/display/DisplayDensityUtils.java @@ -16,11 +16,8 @@ package com.android.settingslib.display; -import com.android.settingslib.R; - import android.content.Context; import android.content.res.Resources; -import android.hardware.display.DisplayManager; import android.os.AsyncTask; import android.os.RemoteException; import android.os.UserHandle; @@ -31,6 +28,8 @@ import android.view.Display; import android.view.IWindowManager; import android.view.WindowManagerGlobal; +import com.android.settingslib.R; + import java.util.Arrays; /** diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java index 94efc71e6467..9feacac60365 100644 --- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java +++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java @@ -28,11 +28,11 @@ import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; +import androidx.annotation.VisibleForTesting; + import com.android.internal.telephony.SmsApplication; import com.android.internal.util.ArrayUtils; -import androidx.annotation.VisibleForTesting; - /** * Handles getting/changing the whitelist for the exceptions to battery saving features. */ diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawable.java b/packages/SettingsLib/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawable.java index d0804bb88162..f01eb2a5606e 100644 --- a/packages/SettingsLib/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawable.java +++ b/packages/SettingsLib/src/com/android/settingslib/graph/BluetoothDeviceLayerDrawable.java @@ -19,18 +19,13 @@ package com.android.settingslib.graph; import android.annotation.NonNull; import android.content.Context; import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Matrix; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; -import android.graphics.Rect; -import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; -import androidx.annotation.VisibleForTesting; import android.view.Gravity; -import android.view.View; + +import androidx.annotation.VisibleForTesting; import com.android.settingslib.R; import com.android.settingslib.Utils; diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeEnablerManager.java b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeEnablerManager.java index 628e70af8318..117b48ff852d 100644 --- a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeEnablerManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeEnablerManager.java @@ -19,16 +19,17 @@ package com.android.settingslib.inputmethod; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Configuration; -import androidx.preference.PreferenceFragment; -import androidx.preference.Preference; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceScreen; -import androidx.preference.TwoStatePreference; import android.text.TextUtils; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodSubtype; +import androidx.preference.Preference; +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceFragment; +import androidx.preference.PreferenceScreen; +import androidx.preference.TwoStatePreference; + import com.android.settingslib.R; import java.text.Collator; diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeEnablerManagerCompat.java b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeEnablerManagerCompat.java index ad1368c7731d..6f8c7ac22077 100644 --- a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeEnablerManagerCompat.java +++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeEnablerManagerCompat.java @@ -24,6 +24,12 @@ import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodSubtype; +import androidx.preference.Preference; +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceScreen; +import androidx.preference.TwoStatePreference; + import com.android.settingslib.R; import java.text.Collator; @@ -31,12 +37,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import androidx.preference.Preference; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceFragmentCompat; -import androidx.preference.PreferenceScreen; -import androidx.preference.TwoStatePreference; - public class InputMethodAndSubtypeEnablerManagerCompat implements Preference.OnPreferenceChangeListener { diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtil.java b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtil.java index 026bbd47711a..057123bcd224 100644 --- a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtil.java +++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtil.java @@ -25,15 +25,16 @@ import android.content.res.Configuration; import android.icu.text.ListFormatter; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; -import androidx.preference.PreferenceFragment; -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; -import androidx.preference.TwoStatePreference; import android.text.TextUtils; import android.util.Log; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragment; +import androidx.preference.PreferenceScreen; +import androidx.preference.TwoStatePreference; + import com.android.internal.app.LocaleHelper; import java.util.HashMap; diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompat.java b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompat.java index 9ad2adbcc432..692dfbff50f6 100644 --- a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompat.java +++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodAndSubtypeUtilCompat.java @@ -30,6 +30,11 @@ import android.util.Log; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; +import androidx.preference.Preference; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceScreen; +import androidx.preference.TwoStatePreference; + import com.android.internal.app.LocaleHelper; import java.util.HashMap; @@ -38,11 +43,6 @@ import java.util.List; import java.util.Locale; import java.util.Map; -import androidx.preference.Preference; -import androidx.preference.PreferenceFragmentCompat; -import androidx.preference.PreferenceScreen; -import androidx.preference.TwoStatePreference; - // TODO: Consolidate this with {@link InputMethodSettingValuesWrapper}. public class InputMethodAndSubtypeUtilCompat { diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java index 2dec6c341f92..221e0dd94e9b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java +++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodPreference.java @@ -24,9 +24,6 @@ import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.os.UserHandle; -import androidx.preference.Preference; -import androidx.preference.Preference.OnPreferenceChangeListener; -import androidx.preference.Preference.OnPreferenceClickListener; import android.text.TextUtils; import android.util.Log; import android.view.inputmethod.InputMethodInfo; @@ -34,6 +31,10 @@ import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodSubtype; import android.widget.Toast; +import androidx.preference.Preference; +import androidx.preference.Preference.OnPreferenceChangeListener; +import androidx.preference.Preference.OnPreferenceClickListener; + import com.android.internal.annotations.VisibleForTesting; import com.android.settingslib.R; import com.android.settingslib.RestrictedLockUtils; diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodSubtypePreference.java b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodSubtypePreference.java index bb4358115921..69bfffb55616 100644 --- a/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodSubtypePreference.java +++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/InputMethodSubtypePreference.java @@ -17,11 +17,12 @@ package com.android.settingslib.inputmethod; import android.content.Context; -import androidx.preference.Preference; import android.text.TextUtils; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodSubtype; +import androidx.preference.Preference; + import com.android.internal.annotations.VisibleForTesting; import java.text.Collator; diff --git a/packages/SettingsLib/src/com/android/settingslib/inputmethod/SwitchWithNoTextPreference.java b/packages/SettingsLib/src/com/android/settingslib/inputmethod/SwitchWithNoTextPreference.java index 2b38697a65ce..2360298822ba 100644 --- a/packages/SettingsLib/src/com/android/settingslib/inputmethod/SwitchWithNoTextPreference.java +++ b/packages/SettingsLib/src/com/android/settingslib/inputmethod/SwitchWithNoTextPreference.java @@ -17,6 +17,7 @@ package com.android.settingslib.inputmethod; import android.content.Context; + import androidx.preference.SwitchPreference; public class SwitchWithNoTextPreference extends SwitchPreference { diff --git a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java index 444c19c94c9f..42306f6d46d0 100644 --- a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java +++ b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlGeneratorFromXml.java @@ -16,11 +16,12 @@ package com.android.settingslib.license; -import androidx.annotation.VisibleForTesting; import android.text.TextUtils; import android.util.Log; import android.util.Xml; +import androidx.annotation.VisibleForTesting; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; diff --git a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java index d3b19031d0dc..360c19c2b795 100644 --- a/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java +++ b/packages/SettingsLib/src/com/android/settingslib/license/LicenseHtmlLoaderCompat.java @@ -36,7 +36,8 @@ public class LicenseHtmlLoaderCompat extends AsyncLoaderCompat<File> { "/vendor/etc/NOTICE.xml.gz", "/odm/etc/NOTICE.xml.gz", "/oem/etc/NOTICE.xml.gz", - "/product/etc/NOTICE.xml.gz"}; + "/product/etc/NOTICE.xml.gz", + "/product_services/etc/NOTICE.xml.gz"}; static final String NOTICE_HTML_FILE_NAME = "NOTICE.html"; private final Context mContext; diff --git a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java index 96bed93165fb..b8e1251dd79a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java +++ b/packages/SettingsLib/src/com/android/settingslib/location/RecentLocationApps.java @@ -25,10 +25,12 @@ import android.graphics.drawable.Drawable; import android.os.Process; import android.os.UserHandle; import android.os.UserManager; -import androidx.annotation.VisibleForTesting; import android.text.format.DateUtils; import android.util.IconDrawableFactory; import android.util.Log; + +import androidx.annotation.VisibleForTesting; + import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; diff --git a/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoaderCompat.java b/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoaderCompat.java index 3adbd4d01ca0..c3241bbd2123 100644 --- a/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoaderCompat.java +++ b/packages/SettingsLib/src/com/android/settingslib/net/ChartDataLoaderCompat.java @@ -30,10 +30,10 @@ import android.net.NetworkTemplate; import android.os.Bundle; import android.os.RemoteException; -import com.android.settingslib.AppItem; - import androidx.loader.content.AsyncTaskLoader; +import com.android.settingslib.AppItem; + /** * Loader for historical chart data for both network and UID details. */ diff --git a/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java b/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java index 224b9679a9a2..c14f5588cddf 100644 --- a/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java +++ b/packages/SettingsLib/src/com/android/settingslib/net/UidDetailProvider.java @@ -28,9 +28,9 @@ import android.content.res.Resources; import android.graphics.drawable.Drawable; import android.net.ConnectivityManager; import android.net.TrafficStats; -import android.os.UserManager; -import android.os.UserHandle; import android.os.RemoteException; +import android.os.UserHandle; +import android.os.UserManager; import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/ZenDurationDialog.java b/packages/SettingsLib/src/com/android/settingslib/notification/ZenDurationDialog.java index 0ef46a1c28fd..b9197fe1ebd5 100644 --- a/packages/SettingsLib/src/com/android/settingslib/notification/ZenDurationDialog.java +++ b/packages/SettingsLib/src/com/android/settingslib/notification/ZenDurationDialog.java @@ -33,6 +33,9 @@ import android.widget.RadioGroup; import android.widget.ScrollView; import android.widget.TextView; +import androidx.annotation.VisibleForTesting; +import androidx.appcompat.app.AlertDialog; + import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto; import com.android.internal.policy.PhoneWindow; @@ -40,9 +43,6 @@ import com.android.settingslib.R; import java.util.Arrays; -import androidx.annotation.VisibleForTesting; -import androidx.appcompat.app.AlertDialog; - public class ZenDurationDialog { private static final int[] MINUTE_BUCKETS = ZenModeConfig.MINUTE_BUCKETS; @VisibleForTesting protected static final int MIN_BUCKET_MINUTES = MINUTE_BUCKETS[0]; diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionController.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionController.java index 6a8b01a23688..ec774872ce67 100644 --- a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionController.java +++ b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionController.java @@ -24,9 +24,10 @@ import android.os.IBinder; import android.os.RemoteException; import android.service.settings.suggestions.ISuggestionService; import android.service.settings.suggestions.Suggestion; +import android.util.Log; + import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; -import android.util.Log; import java.util.List; diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixin.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixin.java index ee8b6fe60478..6597daa9acaf 100644 --- a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixin.java +++ b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixin.java @@ -17,15 +17,16 @@ package com.android.settingslib.suggestions; import android.app.LoaderManager; -import androidx.lifecycle.OnLifecycleEvent; import android.content.ComponentName; import android.content.Context; import android.content.Loader; import android.os.Bundle; import android.service.settings.suggestions.Suggestion; -import androidx.annotation.Nullable; import android.util.Log; +import androidx.annotation.Nullable; +import androidx.lifecycle.OnLifecycleEvent; + import com.android.settingslib.core.lifecycle.Lifecycle; import java.util.List; diff --git a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixinCompat.java b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixinCompat.java index 179121739896..eea49bcb2384 100644 --- a/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixinCompat.java +++ b/packages/SettingsLib/src/com/android/settingslib/suggestions/SuggestionControllerMixinCompat.java @@ -23,15 +23,15 @@ import android.os.Bundle; import android.service.settings.suggestions.Suggestion; import android.util.Log; -import com.android.settingslib.core.lifecycle.Lifecycle; - -import java.util.List; - import androidx.annotation.Nullable; import androidx.lifecycle.OnLifecycleEvent; import androidx.loader.app.LoaderManager; import androidx.loader.content.Loader; +import com.android.settingslib.core.lifecycle.Lifecycle; + +import java.util.List; + /** * Manages IPC communication to SettingsIntelligence for suggestion related services. */ diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java b/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java index 7cdbe719df78..9451b3620418 100644 --- a/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java +++ b/packages/SettingsLib/src/com/android/settingslib/users/AppRestrictionsHelper.java @@ -31,12 +31,13 @@ import android.graphics.drawable.Drawable; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; -import androidx.annotation.VisibleForTesting; import android.text.TextUtils; import android.util.Log; import android.view.inputmethod.InputMethodInfo; import android.view.inputmethod.InputMethodManager; +import androidx.annotation.VisibleForTesting; + import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/IconCache.java b/packages/SettingsLib/src/com/android/settingslib/utils/IconCache.java index f0548ff7a923..c8c8ac22089a 100644 --- a/packages/SettingsLib/src/com/android/settingslib/utils/IconCache.java +++ b/packages/SettingsLib/src/com/android/settingslib/utils/IconCache.java @@ -19,6 +19,7 @@ package com.android.settingslib.utils; import android.content.Context; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; + import androidx.annotation.VisibleForTesting; import androidx.collection.ArrayMap; diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java b/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java index e16da84ce713..fa59688d1523 100644 --- a/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java +++ b/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java @@ -22,9 +22,10 @@ import android.icu.text.MeasureFormat; import android.icu.text.MeasureFormat.FormatWidth; import android.icu.util.Measure; import android.icu.util.MeasureUnit; -import androidx.annotation.Nullable; import android.text.TextUtils; +import androidx.annotation.Nullable; + import com.android.settingslib.R; import java.time.Instant; diff --git a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java index 87a56c7548d2..f02044dc52e0 100644 --- a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java +++ b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java @@ -17,13 +17,14 @@ package com.android.settingslib.widget; import android.content.Context; -import androidx.core.content.res.TypedArrayUtils; -import androidx.preference.Preference; -import androidx.preference.PreferenceViewHolder; import android.text.method.LinkMovementMethod; import android.util.AttributeSet; import android.widget.TextView; +import androidx.core.content.res.TypedArrayUtils; +import androidx.preference.Preference; +import androidx.preference.PreferenceViewHolder; + import com.android.settingslib.R; /** diff --git a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreferenceMixin.java b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreferenceMixin.java index 5883754fa2ed..2987c1597193 100644 --- a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreferenceMixin.java +++ b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreferenceMixin.java @@ -17,6 +17,7 @@ package com.android.settingslib.widget; import android.content.Context; + import androidx.preference.PreferenceFragment; import androidx.preference.PreferenceScreen; diff --git a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreferenceMixinCompat.java b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreferenceMixinCompat.java index 260ac838cb32..d45e56d486ae 100644 --- a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreferenceMixinCompat.java +++ b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreferenceMixinCompat.java @@ -18,13 +18,13 @@ package com.android.settingslib.widget; import android.content.Context; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceScreen; + import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.LifecycleObserver; import com.android.settingslib.core.lifecycle.events.SetPreferenceScreen; -import androidx.preference.PreferenceFragmentCompat; -import androidx.preference.PreferenceScreen; - public class FooterPreferenceMixinCompat implements LifecycleObserver, SetPreferenceScreen { private final PreferenceFragmentCompat mFragment; diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java index 18a44ed735bd..e950e8e670d7 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java @@ -48,14 +48,12 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; -import androidx.annotation.NonNull; -import android.text.Spannable; -import android.text.SpannableString; import android.text.TextUtils; -import android.text.style.TtsSpan; import android.util.ArraySet; import android.util.Log; +import androidx.annotation.NonNull; + import com.android.internal.annotations.VisibleForTesting; import com.android.settingslib.R; import com.android.settingslib.utils.ThreadUtils; diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java index aa29f5ab2ea6..f3c43cce0f83 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java @@ -25,9 +25,6 @@ import android.graphics.drawable.StateListDrawable; import android.net.wifi.WifiConfiguration; import android.os.Looper; import android.os.UserHandle; -import androidx.annotation.VisibleForTesting; -import androidx.preference.Preference; -import androidx.preference.PreferenceViewHolder; import android.text.TextUtils; import android.util.AttributeSet; import android.util.SparseArray; @@ -35,9 +32,12 @@ import android.view.View; import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; +import androidx.preference.PreferenceViewHolder; + import com.android.settingslib.R; import com.android.settingslib.TronUtils; -import com.android.settingslib.TwoTargetPreference; import com.android.settingslib.Utils; import com.android.settingslib.wifi.AccessPoint.Speed; diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/TestAccessPointBuilder.java b/packages/SettingsLib/src/com/android/settingslib/wifi/TestAccessPointBuilder.java index 5862e6f19e16..afea5d2078b0 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/TestAccessPointBuilder.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/TestAccessPointBuilder.java @@ -24,6 +24,7 @@ import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; import android.os.Bundle; import android.os.Parcelable; + import androidx.annotation.Keep; import com.android.settingslib.wifi.AccessPoint.Speed; diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java index 6211d1214fcc..9050b4b0a15b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java @@ -41,15 +41,16 @@ import android.os.Message; import android.os.Process; import android.os.SystemClock; import android.provider.Settings; -import androidx.annotation.GuardedBy; -import androidx.annotation.NonNull; -import androidx.annotation.VisibleForTesting; import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.widget.Toast; +import androidx.annotation.GuardedBy; +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; + import com.android.settingslib.R; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.core.lifecycle.LifecycleObserver; diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTrackerFactory.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTrackerFactory.java index e73d952cd645..93e4fce6e74b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTrackerFactory.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTrackerFactory.java @@ -16,6 +16,7 @@ package com.android.settingslib.wifi; import android.content.Context; + import androidx.annotation.Keep; import androidx.annotation.NonNull; diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java index 4792317c9f1e..4e6c005457c0 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiUtils.java @@ -21,6 +21,7 @@ import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiInfo; import android.os.SystemClock; + import androidx.annotation.VisibleForTesting; import com.android.settingslib.R; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java index 710dbc221f07..bf49ef3615ba 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java @@ -20,8 +20,11 @@ import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NO import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT; import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT; import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS; + import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; + import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doReturn; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java index f00ae0b08019..79d682d67a4a 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedPreferenceHelperTest.java @@ -24,11 +24,12 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; -import androidx.preference.Preference; -import androidx.preference.PreferenceViewHolder; import android.view.View; import android.widget.TextView; +import androidx.preference.Preference; +import androidx.preference.PreferenceViewHolder; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TetherUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TetherUtilTest.java index fc0203a1a0c8..e70baa197123 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TetherUtilTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TetherUtilTest.java @@ -23,9 +23,9 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import android.content.Context; +import android.net.ConnectivityManager; import android.os.UserHandle; import android.os.UserManager; -import android.net.ConnectivityManager; import org.junit.Before; import org.junit.Test; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TwoTargetPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TwoTargetPreferenceTest.java index efd7de351ebe..c0b69f2260eb 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TwoTargetPreferenceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TwoTargetPreferenceTest.java @@ -19,16 +19,19 @@ package com.android.settingslib; import static com.android.settingslib.TwoTargetPreference.ICON_SIZE_DEFAULT; import static com.android.settingslib.TwoTargetPreference.ICON_SIZE_MEDIUM; import static com.android.settingslib.TwoTargetPreference.ICON_SIZE_SMALL; + import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import android.content.Context; -import androidx.preference.PreferenceViewHolder; import android.view.View; import android.view.ViewGroup; import android.widget.LinearLayout; +import androidx.preference.PreferenceViewHolder; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java index babe82e00ae6..47e51f399e03 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java @@ -20,6 +20,7 @@ import static android.Manifest.permission.WRITE_SECURE_SETTINGS; import static com.android.settingslib.Utils.STORAGE_MANAGER_SHOW_OPT_IN_PROPERTY; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java index 2dbabe0b76cc..19ce424257ac 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ApplicationsStateRoboTest.java @@ -25,7 +25,6 @@ import static org.robolectric.shadow.api.Shadow.extract; import android.annotation.UserIdInt; import android.app.ApplicationPackageManager; -import android.app.usage.IStorageStatsManager; import android.app.usage.StorageStats; import android.app.usage.StorageStatsManager; import android.content.ComponentName; @@ -42,10 +41,10 @@ import android.os.Handler; import android.os.UserHandle; import android.util.IconDrawableFactory; +import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.applications.ApplicationsState.AppEntry; import com.android.settingslib.applications.ApplicationsState.Callbacks; import com.android.settingslib.applications.ApplicationsState.Session; -import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.testutils.shadow.ShadowUserManager; import org.junit.Before; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java index 060b716bb435..d8c459c07b75 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/applications/ServiceListingTest.java @@ -17,6 +17,7 @@ package com.android.settingslib.applications; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java index f223176795b8..5550b7e5e865 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/LocalBluetoothProfileManagerTest.java @@ -79,6 +79,8 @@ public class LocalBluetoothProfileManagerTest { mContext)); mShadowBluetoothAdapter = Shadow.extract(BluetoothAdapter.getDefaultAdapter()); when(mDeviceManager.findDevice(mDevice)).thenReturn(mCachedBluetoothDevice); + mProfileManager = new LocalBluetoothProfileManager(mContext, mLocalBluetoothAdapter, + mDeviceManager, mEventManager); } /** @@ -88,20 +90,26 @@ public class LocalBluetoothProfileManagerTest { public void constructor_initiateHidAndHidDeviceProfile() { mShadowBluetoothAdapter.setSupportedProfiles(generateList( new int[] {BluetoothProfile.HID_HOST, BluetoothProfile.HID_DEVICE})); - mProfileManager = new LocalBluetoothProfileManager(mContext, mLocalBluetoothAdapter, - mDeviceManager, mEventManager); + mProfileManager.updateLocalProfiles(); assertThat(mProfileManager.getHidProfile()).isNotNull(); assertThat(mProfileManager.getHidDeviceProfile()).isNotNull(); } + @Test + public void constructor_doNotUpdateProfiles() { + mProfileManager = spy(new LocalBluetoothProfileManager(mContext, mLocalBluetoothAdapter, + mDeviceManager, mEventManager)); + + verify(mProfileManager, never()).updateLocalProfiles(); + } + /** * Verify updateLocalProfiles() for a local A2DP source adds A2dpProfile */ @Test public void updateLocalProfiles_addA2dpToLocalProfiles() { - mProfileManager = new LocalBluetoothProfileManager(mContext, mLocalBluetoothAdapter, - mDeviceManager, mEventManager); + mProfileManager.updateLocalProfiles(); assertThat(mProfileManager.getA2dpProfile()).isNull(); assertThat(mProfileManager.getHeadsetProfile()).isNull(); @@ -120,8 +128,7 @@ public class LocalBluetoothProfileManagerTest { public void updateProfiles_addHidProfileForRemoteDevice() { mShadowBluetoothAdapter.setSupportedProfiles(generateList( new int[] {BluetoothProfile.HID_HOST})); - mProfileManager = new LocalBluetoothProfileManager(mContext, mLocalBluetoothAdapter, - mDeviceManager, mEventManager); + mProfileManager.updateLocalProfiles(); ParcelUuid[] uuids = new ParcelUuid[]{BluetoothUuid.Hid}; ParcelUuid[] localUuids = new ParcelUuid[]{}; List<LocalBluetoothProfile> profiles = new ArrayList<>(); @@ -143,8 +150,7 @@ public class LocalBluetoothProfileManagerTest { public void stateChangedHandler_receiveA2dpConnectionStateChanged_shouldDispatchCallback() { mShadowBluetoothAdapter.setSupportedProfiles(generateList( new int[] {BluetoothProfile.A2DP})); - mProfileManager = new LocalBluetoothProfileManager(mContext, mLocalBluetoothAdapter, - mDeviceManager, mEventManager); + mProfileManager.updateLocalProfiles(); // Refer to BluetoothControllerImpl, it will call setReceiverHandler after // LocalBluetoothProfileManager created. mEventManager.setReceiverHandler(null); @@ -167,8 +173,7 @@ public class LocalBluetoothProfileManagerTest { public void stateChangedHandler_receiveHeadsetConnectionStateChanged_shouldDispatchCallback() { mShadowBluetoothAdapter.setSupportedProfiles(generateList( new int[] {BluetoothProfile.HEADSET})); - mProfileManager = new LocalBluetoothProfileManager(mContext, mLocalBluetoothAdapter, - mDeviceManager, mEventManager); + mProfileManager.updateLocalProfiles(); // Refer to BluetoothControllerImpl, it will call setReceiverHandler after // LocalBluetoothProfileManager created. mEventManager.setReceiverHandler(null); @@ -191,8 +196,7 @@ public class LocalBluetoothProfileManagerTest { public void stateChangedHandler_receiveHAPConnectionStateChanged_shouldDispatchCallback() { mShadowBluetoothAdapter.setSupportedProfiles(generateList( new int[] {BluetoothProfile.HEARING_AID})); - mProfileManager = new LocalBluetoothProfileManager(mContext, mLocalBluetoothAdapter, - mDeviceManager, mEventManager); + mProfileManager.updateLocalProfiles(); // Refer to BluetoothControllerImpl, it will call setReceiverHandler after // LocalBluetoothProfileManager created. mEventManager.setReceiverHandler(null); @@ -215,8 +219,7 @@ public class LocalBluetoothProfileManagerTest { public void stateChangedHandler_receivePanConnectionStateChanged_shouldNotDispatchCallback() { mShadowBluetoothAdapter.setSupportedProfiles(generateList( new int[] {BluetoothProfile.PAN})); - mProfileManager = new LocalBluetoothProfileManager(mContext, mLocalBluetoothAdapter, - mDeviceManager, mEventManager); + mProfileManager.updateLocalProfiles(); // Refer to BluetoothControllerImpl, it will call setReceiverHandler after // LocalBluetoothProfileManager created. mEventManager.setReceiverHandler(null); @@ -239,8 +242,7 @@ public class LocalBluetoothProfileManagerTest { public void stateChangedHandler_receivePanConnectionStateChangedWithoutProfile_shouldNotRefresh () { mShadowBluetoothAdapter.setSupportedProfiles(null); - mProfileManager = new LocalBluetoothProfileManager(mContext, mLocalBluetoothAdapter, - mDeviceManager, mEventManager); + mProfileManager.updateLocalProfiles(); // Refer to BluetoothControllerImpl, it will call setReceiverHandler after // LocalBluetoothProfileManager created. mEventManager.setReceiverHandler(null); @@ -262,8 +264,7 @@ public class LocalBluetoothProfileManagerTest { public void stateChangedHandler_receivePanConnectionStateChangedWithProfile_shouldRefresh() { mShadowBluetoothAdapter.setSupportedProfiles(generateList( new int[] {BluetoothProfile.PAN})); - mProfileManager = new LocalBluetoothProfileManager(mContext, mLocalBluetoothAdapter, - mDeviceManager, mEventManager); + mProfileManager.updateLocalProfiles(); // Refer to BluetoothControllerImpl, it will call setReceiverHandler after // LocalBluetoothProfileManager created. mEventManager.setReceiverHandler(null); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java index 5c19e61d44dc..f4fd77930506 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/MetricsFeatureProviderTest.java @@ -16,6 +16,7 @@ package com.android.settingslib.core.instrumentation; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.verify; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java index 017d37388340..be671e6d4e22 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/SharedPreferenceLoggerTest.java @@ -15,10 +15,15 @@ */ package com.android.settingslib.core.instrumentation; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.ACTION_SETTINGS_PREFERENCE_CHANGE; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_FLOAT_VALUE; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE; -import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_SETTINGS_PREFERENCE_CHANGE_NAME; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent + .ACTION_SETTINGS_PREFERENCE_CHANGE; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent + .FIELD_SETTINGS_PREFERENCE_CHANGE_FLOAT_VALUE; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent + .FIELD_SETTINGS_PREFERENCE_CHANGE_INT_VALUE; +import static com.android.internal.logging.nano.MetricsProto.MetricsEvent + .FIELD_SETTINGS_PREFERENCE_CHANGE_NAME; + import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.argThat; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java index f34c33844d11..f78573a79f1c 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/instrumentation/VisibilityLoggerMixinTest.java @@ -16,6 +16,7 @@ package com.android.settingslib.core.instrumentation; import static com.android.settingslib.core.instrumentation.Instrumentable.METRICS_CATEGORY_UNKNOWN; + import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyInt; @@ -30,6 +31,7 @@ import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; + import androidx.fragment.app.FragmentActivity; import com.android.internal.logging.nano.MetricsProto; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java index 28828a00cce6..c23ad79a52fe 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/lifecycle/LifecycleTest.java @@ -16,6 +16,7 @@ package com.android.settingslib.core.lifecycle; import static androidx.lifecycle.Lifecycle.Event.ON_START; + import static com.google.common.truth.Truth.assertThat; import android.content.Context; @@ -25,6 +26,8 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.widget.LinearLayout; +import androidx.lifecycle.LifecycleOwner; + import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.core.lifecycle.events.OnAttach; import com.android.settingslib.core.lifecycle.events.OnCreateOptionsMenu; @@ -43,8 +46,6 @@ import org.junit.runner.RunWith; import org.robolectric.Robolectric; import org.robolectric.android.controller.ActivityController; -import androidx.lifecycle.LifecycleOwner; - @RunWith(SettingsLibRobolectricTestRunner.class) public class LifecycleTest { diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java index 7c653351974a..2a60839990c4 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java @@ -17,6 +17,7 @@ package com.android.settingslib.development; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Answers.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; @@ -26,9 +27,10 @@ import android.content.Context; import android.content.pm.PackageManager; import android.os.UserManager; import android.provider.Settings; -import androidx.preference.SwitchPreference; + import androidx.preference.Preference; import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; import com.android.settingslib.SettingsLibRobolectricTestRunner; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogdSizePreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogdSizePreferenceControllerTest.java index ae3072ca86b8..2f78899ff92d 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogdSizePreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogdSizePreferenceControllerTest.java @@ -40,6 +40,7 @@ import static org.mockito.Mockito.verify; import android.content.Context; import android.os.SystemProperties; + import androidx.preference.ListPreference; import androidx.preference.PreferenceScreen; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogpersistPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogpersistPreferenceControllerTest.java index b0aaa256fdab..ed128e098c6f 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogpersistPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/LogpersistPreferenceControllerTest.java @@ -17,12 +17,14 @@ package com.android.settingslib.development; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; -import androidx.lifecycle.LifecycleOwner; import android.os.SystemProperties; + +import androidx.lifecycle.LifecycleOwner; import androidx.preference.ListPreference; import androidx.preference.Preference; import androidx.preference.PreferenceScreen; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/BluetoothAddressPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/BluetoothAddressPreferenceControllerTest.java index 8ec7149ce1a8..234b4d5ac604 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/BluetoothAddressPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/BluetoothAddressPreferenceControllerTest.java @@ -22,6 +22,7 @@ import static org.mockito.Mockito.doReturn; import android.bluetooth.BluetoothAdapter; import android.content.Context; + import androidx.preference.Preference; import androidx.preference.PreferenceScreen; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ConnectivityPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ConnectivityPreferenceControllerTest.java index 7c127e5cd5b7..aee956cf5518 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ConnectivityPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ConnectivityPreferenceControllerTest.java @@ -17,6 +17,7 @@ package com.android.settingslib.deviceinfo; import static com.google.common.truth.Truth.assertWithMessage; + import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.nullable; import static org.mockito.Mockito.doReturn; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ImsStatusPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ImsStatusPreferenceControllerTest.java index cb7861b30562..2b490ee63856 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ImsStatusPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/ImsStatusPreferenceControllerTest.java @@ -17,17 +17,19 @@ package com.android.settingslib.deviceinfo; import static com.google.common.truth.Truth.assertWithMessage; + import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import android.content.Context; import android.os.PersistableBundle; -import androidx.preference.Preference; -import androidx.preference.PreferenceScreen; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.core.lifecycle.Lifecycle; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/IpAddressPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/IpAddressPreferenceControllerTest.java index 8f144cdf3a15..1d957c3b5e5b 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/IpAddressPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/IpAddressPreferenceControllerTest.java @@ -23,6 +23,7 @@ import static org.mockito.Mockito.doReturn; import android.content.Context; import android.net.ConnectivityManager; import android.net.wifi.WifiManager; + import androidx.preference.Preference; import androidx.preference.PreferenceScreen; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SerialNumberPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SerialNumberPreferenceControllerTest.java index 69fb86e88d5b..dc77400e2547 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SerialNumberPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SerialNumberPreferenceControllerTest.java @@ -17,9 +17,11 @@ package com.android.settingslib.deviceinfo; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.when; import android.content.Context; + import androidx.preference.Preference; import androidx.preference.PreferenceScreen; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java index eaae40553d6e..eb77cb6271e9 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/SimStatusImeiInfoPreferenceControllerTest.java @@ -17,6 +17,7 @@ package com.android.settingslib.deviceinfo; import static com.google.common.truth.Truth.assertThat; + import static org.robolectric.shadow.api.Shadow.extract; import android.net.ConnectivityManager; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/UptimePreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/UptimePreferenceControllerTest.java index 20ce46599bff..2e0348daaa51 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/UptimePreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/UptimePreferenceControllerTest.java @@ -23,9 +23,10 @@ import static org.mockito.Mockito.verify; import android.content.Context; import android.os.SystemClock; +import android.text.format.DateUtils; + import androidx.preference.Preference; import androidx.preference.PreferenceScreen; -import android.text.format.DateUtils; import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.core.lifecycle.Lifecycle; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java index 757df5b12518..359ea7791922 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/deviceinfo/WifiMacAddressPreferenceControllerTest.java @@ -18,6 +18,7 @@ package com.android.settingslib.deviceinfo; import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; + import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; @@ -27,6 +28,7 @@ import android.net.ConnectivityManager; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.provider.Settings; + import androidx.preference.Preference; import androidx.preference.PreferenceScreen; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/display/BrightnessUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/display/BrightnessUtilsTest.java index eb7ad6d919cf..ca621ca66829 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/display/BrightnessUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/display/BrightnessUtilsTest.java @@ -17,6 +17,7 @@ package com.android.settingslib.display; import static com.android.settingslib.display.BrightnessUtils.GAMMA_SPACE_MAX; + import static com.google.common.truth.Truth.assertThat; import com.android.settingslib.SettingsLibRobolectricTestRunner; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java index c495511d4eb0..59a3dd61475c 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawer/CategoryKeyTest.java @@ -24,7 +24,6 @@ import com.android.settingslib.SettingsLibRobolectricTestRunner; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.RobolectricTestRunner; import java.util.Set; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java index ba5a2c5e5fe7..de96af4fa6a1 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/BatterySaverUtilsTest.java @@ -17,8 +17,8 @@ package com.android.settingslib.fuelgauge; import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java index 23087a971611..9b1fe5f6029d 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java @@ -17,6 +17,7 @@ package com.android.settingslib.fuelgauge; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doNothing; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java index 8a54aeec6d79..9c168f7b1a45 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAppsTest.java @@ -1,6 +1,7 @@ package com.android.settingslib.location; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Matchers.isA; import static org.mockito.Mockito.when; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java index ccd2f538c731..89c319a7e483 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/EnableZenModeDialogTest.java @@ -20,6 +20,7 @@ import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertTrue; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/ZenDurationDialogTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/ZenDurationDialogTest.java index f47f41c31a7f..81476564f9b9 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/ZenDurationDialogTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/notification/ZenDurationDialogTest.java @@ -19,26 +19,15 @@ package com.android.settingslib.notification; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.anyObject; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; + import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.when; -import android.app.Activity; -import android.app.Fragment; -import android.app.NotificationManager; -import android.content.Context; import android.content.ContentResolver; -import android.content.DialogInterface; -import android.content.res.Resources; -import android.net.Uri; +import android.content.Context; import android.provider.Settings; import android.service.notification.Condition; import android.view.LayoutInflater; import android.view.View; -import android.widget.Button; import androidx.appcompat.app.AlertDialog; @@ -47,9 +36,6 @@ import com.android.settingslib.SettingsLibRobolectricTestRunner; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.robolectric.Robolectric; import org.robolectric.RuntimeEnvironment; @RunWith(SettingsLibRobolectricTestRunner.class) diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinCompatTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinCompatTest.java index 1ee3afa9c1ce..449451a63e2d 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinCompatTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinCompatTest.java @@ -18,7 +18,9 @@ package com.android.settingslib.suggestions; import static androidx.lifecycle.Lifecycle.Event.ON_START; import static androidx.lifecycle.Lifecycle.Event.ON_STOP; + import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -26,6 +28,9 @@ import static org.mockito.Mockito.when; import android.content.ComponentName; import android.content.Context; +import androidx.lifecycle.LifecycleOwner; +import androidx.loader.app.LoaderManager; + import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.core.lifecycle.Lifecycle; @@ -38,9 +43,6 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; -import androidx.lifecycle.LifecycleOwner; -import androidx.loader.app.LoaderManager; - @RunWith(SettingsLibRobolectricTestRunner.class) @Config(shadows = ShadowSuggestionController.class) public class SuggestionControllerMixinCompatTest { diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinTest.java index f486989f5a56..aac582f9b3ac 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/suggestions/SuggestionControllerMixinTest.java @@ -18,16 +18,19 @@ package com.android.settingslib.suggestions; import static androidx.lifecycle.Lifecycle.Event.ON_START; import static androidx.lifecycle.Lifecycle.Event.ON_STOP; + import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.LoaderManager; -import androidx.lifecycle.LifecycleOwner; import android.content.ComponentName; import android.content.Context; +import androidx.lifecycle.LifecycleOwner; + import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.core.lifecycle.Lifecycle; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/FragmentTestUtils.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/FragmentTestUtils.java index 8ba8606b8e08..d8e73b7db322 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/FragmentTestUtils.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/FragmentTestUtils.java @@ -19,12 +19,12 @@ package com.android.settingslib.testutils; import android.os.Bundle; import android.widget.LinearLayout; -import org.robolectric.Robolectric; - import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; +import org.robolectric.Robolectric; + /** * Utilities for creating Fragments for testing. * <p> diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/UserManagerHelperRoboTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/UserManagerHelperRoboTest.java index 890abefddd73..4705cd2b183b 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/UserManagerHelperRoboTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/users/UserManagerHelperRoboTest.java @@ -22,14 +22,13 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityManager; - import android.content.Context; import android.content.pm.UserInfo; import android.os.UserHandle; import android.os.UserManager; -import com.android.settingslib.testutils.shadow.ShadowActivityManager; import com.android.settingslib.SettingsLibRobolectricTestRunner; +import com.android.settingslib.testutils.shadow.ShadowActivityManager; import org.junit.After; import org.junit.Before; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java index f2ef99c42df5..6a9579b770ce 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java @@ -17,6 +17,7 @@ package com.android.settingslib.utils; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.spy; import android.content.Context; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java index 743951a6ed7a..e4bbbcb0b207 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/StringUtilTest.java @@ -17,6 +17,7 @@ package com.android.settingslib.utils; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Mockito.spy; import android.content.Context; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinCompatTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinCompatTest.java index 1abbaba441ee..f56c111d86ea 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinCompatTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinCompatTest.java @@ -17,12 +17,18 @@ package com.android.settingslib.widget; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import androidx.lifecycle.LifecycleOwner; +import androidx.preference.PreferenceFragmentCompat; +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceScreen; + import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.core.lifecycle.Lifecycle; @@ -33,11 +39,6 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.shadows.ShadowApplication; -import androidx.lifecycle.LifecycleOwner; -import androidx.preference.PreferenceFragmentCompat; -import androidx.preference.PreferenceManager; -import androidx.preference.PreferenceScreen; - @RunWith(SettingsLibRobolectricTestRunner.class) public class FooterPreferenceMixinCompatTest { diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java index 8604d186f2dd..366b720fc87b 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceMixinTest.java @@ -17,12 +17,18 @@ package com.android.settingslib.widget; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import androidx.lifecycle.LifecycleOwner; +import androidx.preference.PreferenceFragment; +import androidx.preference.PreferenceManager; +import androidx.preference.PreferenceScreen; + import com.android.settingslib.SettingsLibRobolectricTestRunner; import com.android.settingslib.core.lifecycle.Lifecycle; @@ -33,11 +39,6 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.shadows.ShadowApplication; -import androidx.lifecycle.LifecycleOwner; -import androidx.preference.PreferenceFragment; -import androidx.preference.PreferenceManager; -import androidx.preference.PreferenceScreen; - @RunWith(SettingsLibRobolectricTestRunner.class) public class FooterPreferenceMixinTest { diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java index 3280089a88f6..84a043e15eb5 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/FooterPreferenceTest.java @@ -19,11 +19,12 @@ package com.android.settingslib.widget; import static com.google.common.truth.Truth.assertThat; import android.content.Context; -import androidx.preference.PreferenceViewHolder; import android.text.method.LinkMovementMethod; import android.view.LayoutInflater; import android.widget.TextView; +import androidx.preference.PreferenceViewHolder; + import com.android.settingslib.R; import com.android.settingslib.SettingsLibRobolectricTestRunner; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/AccessPointPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/AccessPointPreferenceTest.java index ee2c2ffc4b4b..86443bde4667 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/AccessPointPreferenceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/AccessPointPreferenceTest.java @@ -16,6 +16,7 @@ package com.android.settingslib.wifi; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java index d25adde98694..07c50fde00fa 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiUtilsTest.java @@ -16,6 +16,7 @@ package com.android.settingslib.wifi; import static com.google.common.truth.Truth.assertThat; + import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.any; import static org.mockito.Mockito.doReturn; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NoisyVelocityTracker.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NoisyVelocityTracker.java deleted file mode 100644 index 9c9b929ab7bf..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NoisyVelocityTracker.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.systemui.statusbar.phone; - -import android.util.Log; -import android.util.Pools; -import android.view.MotionEvent; - -import java.util.ArrayDeque; -import java.util.Iterator; - -/** - * A very simple low-pass velocity filter for motion events for noisy touch screens. - */ -public class NoisyVelocityTracker implements VelocityTrackerInterface { - - private static final Pools.SynchronizedPool<NoisyVelocityTracker> sNoisyPool = - new Pools.SynchronizedPool<>(2); - - private static final float DECAY = 0.75f; - private static final boolean DEBUG = false; - - private final int MAX_EVENTS = 8; - private ArrayDeque<MotionEventCopy> mEventBuf = new ArrayDeque<MotionEventCopy>(MAX_EVENTS); - private float mVX, mVY = 0; - - private static class MotionEventCopy { - public MotionEventCopy(float x2, float y2, long eventTime) { - this.x = x2; - this.y = y2; - this.t = eventTime; - } - float x, y; - long t; - } - - public static NoisyVelocityTracker obtain() { - NoisyVelocityTracker instance = sNoisyPool.acquire(); - return (instance != null) ? instance : new NoisyVelocityTracker(); - } - - private NoisyVelocityTracker() { - } - - public void addMovement(MotionEvent event) { - if (mEventBuf.size() == MAX_EVENTS) { - mEventBuf.remove(); - } - mEventBuf.add(new MotionEventCopy(event.getRawX(), event.getRawY(), event.getEventTime())); - } - - public void computeCurrentVelocity(int units) { - if (NoisyVelocityTracker.DEBUG) { - Log.v("FlingTracker", "computing velocities for " + mEventBuf.size() + " events"); - } - mVX = mVY = 0; - MotionEventCopy last = null; - int i = 0; - float totalweight = 0f; - float weight = 10f; - for (final Iterator<MotionEventCopy> iter = mEventBuf.iterator(); - iter.hasNext();) { - final MotionEventCopy event = iter.next(); - if (last != null) { - final float dt = (float) (event.t - last.t) / units; - final float dx = (event.x - last.x); - final float dy = (event.y - last.y); - if (NoisyVelocityTracker.DEBUG) { - Log.v("FlingTracker", String.format( - " [%d] (t=%d %.1f,%.1f) dx=%.1f dy=%.1f dt=%f vx=%.1f vy=%.1f", - i, event.t, event.x, event.y, - dx, dy, dt, - (dx/dt), - (dy/dt) - )); - } - if (event.t == last.t) { - // Really not sure what to do with events that happened at the same time, - // so we'll skip subsequent events. - continue; - } - mVX += weight * dx / dt; - mVY += weight * dy / dt; - totalweight += weight; - weight *= DECAY; - } - last = event; - i++; - } - if (totalweight > 0) { - mVX /= totalweight; - mVY /= totalweight; - } else { - // so as not to contaminate the velocities with NaN - mVX = mVY = 0; - } - - if (NoisyVelocityTracker.DEBUG) { - Log.v("FlingTracker", "computed: vx=" + mVX + " vy=" + mVY); - } - } - - public float getXVelocity() { - if (Float.isNaN(mVX) || Float.isInfinite(mVX)) { - mVX = 0; - } - return mVX; - } - - public float getYVelocity() { - if (Float.isNaN(mVY) || Float.isInfinite(mVX)) { - mVY = 0; - } - return mVY; - } - - public void recycle() { - mEventBuf.clear(); - sNoisyPool.release(this); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index bef34f6b9125..57c243957b48 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -29,6 +29,7 @@ import android.util.AttributeSet; import android.util.Log; import android.view.InputDevice; import android.view.MotionEvent; +import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewTreeObserver; @@ -103,7 +104,7 @@ public abstract class PanelView extends FrameLayout { private ValueAnimator mHeightAnimator; private ObjectAnimator mPeekAnimator; - private VelocityTrackerInterface mVelocityTracker; + private final VelocityTracker mVelocityTracker = VelocityTracker.obtain(); private FlingAnimationUtils mFlingAnimationUtils; private FlingAnimationUtils mFlingAnimationUtilsClosing; private FlingAnimationUtils mFlingAnimationUtilsDismissing; @@ -226,10 +227,6 @@ public abstract class PanelView extends FrameLayout { mUnlockFalsingThreshold = res.getDimensionPixelSize(R.dimen.unlock_falsing_threshold); } - private void trackMovement(MotionEvent event) { - if (mVelocityTracker != null) mVelocityTracker.addMovement(event); - } - public void setTouchAndAnimationDisabled(boolean disabled) { mTouchDisabled = disabled; if (mTouchDisabled) { @@ -310,10 +307,7 @@ public abstract class PanelView extends FrameLayout { mTouchAboveFalsingThreshold = false; mCollapsedAndHeadsUpOnDown = isFullyCollapsed() && mHeadsUpManager.hasPinnedHeadsUp(); - if (mVelocityTracker == null) { - initVelocityTracker(); - } - trackMovement(event); + mVelocityTracker.addMovement(event); if (!mGestureWaitForTouchSlop || (mHeightAnimator != null && !mHintAnimationRunning) || mPeekAnimator != null) { mTouchSlopExceeded = (mHeightAnimator != null && !mHintAnimationRunning) @@ -347,7 +341,7 @@ public abstract class PanelView extends FrameLayout { } break; case MotionEvent.ACTION_MOVE: - trackMovement(event); + mVelocityTracker.addMovement(event); float h = y - mInitialTouchY; // If the panel was collapsed when touching, we only need to check for the @@ -392,7 +386,7 @@ public abstract class PanelView extends FrameLayout { case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: - trackMovement(event); + mVelocityTracker.addMovement(event); endMotionEvent(event, x, y, false /* forceCancel */); break; } @@ -458,14 +452,11 @@ public abstract class PanelView extends FrameLayout { || Math.abs(y - mInitialTouchY) > mTouchSlop || event.getActionMasked() == MotionEvent.ACTION_CANCEL || forceCancel) { - float vel = 0f; - float vectorVel = 0f; - if (mVelocityTracker != null) { - mVelocityTracker.computeCurrentVelocity(1000); - vel = mVelocityTracker.getYVelocity(); - vectorVel = (float) Math.hypot( - mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity()); - } + mVelocityTracker.computeCurrentVelocity(1000); + float vel = mVelocityTracker.getYVelocity(); + float vectorVel = (float) Math.hypot( + mVelocityTracker.getXVelocity(), mVelocityTracker.getYVelocity()); + boolean expand = flingExpands(vel, vectorVel, x, y) || event.getActionMasked() == MotionEvent.ACTION_CANCEL || forceCancel; @@ -502,17 +493,11 @@ public abstract class PanelView extends FrameLayout { onTrackingStopped(expands); } - if (mVelocityTracker != null) { - mVelocityTracker.recycle(); - mVelocityTracker = null; - } + mVelocityTracker.clear(); mPeekTouching = false; } protected float getCurrentExpandVelocity() { - if (mVelocityTracker == null) { - return 0; - } mVelocityTracker.computeCurrentVelocity(1000); return mVelocityTracker.getYVelocity(); } @@ -588,8 +573,7 @@ public abstract class PanelView extends FrameLayout { mHasLayoutedSinceDown = false; mUpdateFlingOnLayout = false; mTouchAboveFalsingThreshold = false; - initVelocityTracker(); - trackMovement(event); + mVelocityTracker.addMovement(event); break; case MotionEvent.ACTION_POINTER_UP: final int upPointer = event.getPointerId(event.getActionIndex()); @@ -604,15 +588,12 @@ public abstract class PanelView extends FrameLayout { case MotionEvent.ACTION_POINTER_DOWN: if (mStatusBarStateController.getState() == StatusBarState.KEYGUARD) { mMotionAborted = true; - if (mVelocityTracker != null) { - mVelocityTracker.recycle(); - mVelocityTracker = null; - } + mVelocityTracker.clear(); } break; case MotionEvent.ACTION_MOVE: final float h = y - mInitialTouchY; - trackMovement(event); + mVelocityTracker.addMovement(event); if (scrolledToBottom || mTouchStartedInEmptyArea || mAnimatingOnDown) { float hAbs = Math.abs(h); if ((h < -mTouchSlop || (mAnimatingOnDown && hAbs > mTouchSlop)) @@ -625,10 +606,7 @@ public abstract class PanelView extends FrameLayout { break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: - if (mVelocityTracker != null) { - mVelocityTracker.recycle(); - mVelocityTracker = null; - } + mVelocityTracker.clear(); break; } return false; @@ -656,13 +634,6 @@ public abstract class PanelView extends FrameLayout { } } - private void initVelocityTracker() { - if (mVelocityTracker != null) { - mVelocityTracker.recycle(); - } - mVelocityTracker = VelocityTrackerFactory.obtain(getContext()); - } - protected boolean isScrolledToBottom() { return true; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PlatformVelocityTracker.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PlatformVelocityTracker.java deleted file mode 100644 index f589c3dcb82f..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PlatformVelocityTracker.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.systemui.statusbar.phone; - -import android.util.Pools; -import android.view.MotionEvent; -import android.view.VelocityTracker; - -/** - * An implementation of {@link VelocityTrackerInterface} using the platform-standard - * {@link VelocityTracker}. - */ -public class PlatformVelocityTracker implements VelocityTrackerInterface { - - private static final Pools.SynchronizedPool<PlatformVelocityTracker> sPool = - new Pools.SynchronizedPool<>(2); - - private VelocityTracker mTracker; - - public static PlatformVelocityTracker obtain() { - PlatformVelocityTracker tracker = sPool.acquire(); - if (tracker == null) { - tracker = new PlatformVelocityTracker(); - } - tracker.setTracker(VelocityTracker.obtain()); - return tracker; - } - - public void setTracker(VelocityTracker tracker) { - mTracker = tracker; - } - - @Override - public void addMovement(MotionEvent event) { - mTracker.addMovement(event); - } - - @Override - public void computeCurrentVelocity(int units) { - mTracker.computeCurrentVelocity(units); - } - - @Override - public float getXVelocity() { - return mTracker.getXVelocity(); - } - - @Override - public float getYVelocity() { - return mTracker.getYVelocity(); - } - - @Override - public void recycle() { - mTracker.recycle(); - sPool.release(this); - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/VelocityTrackerFactory.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/VelocityTrackerFactory.java deleted file mode 100644 index e153b856f093..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/VelocityTrackerFactory.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.systemui.statusbar.phone; - -import android.content.Context; - -import com.android.systemui.R; - -/** - * A class to generate {@link VelocityTrackerInterface}, depending on the configuration. - */ -public class VelocityTrackerFactory { - - public static final String PLATFORM_IMPL = "platform"; - public static final String NOISY_IMPL = "noisy"; - - public static VelocityTrackerInterface obtain(Context ctx) { - String tracker = ctx.getResources().getString(R.string.velocity_tracker_impl); - switch (tracker) { - case NOISY_IMPL: - return NoisyVelocityTracker.obtain(); - case PLATFORM_IMPL: - return PlatformVelocityTracker.obtain(); - default: - throw new IllegalStateException("Invalid tracker: " + tracker); - } - } -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/VelocityTrackerInterface.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/VelocityTrackerInterface.java deleted file mode 100644 index a54b05414c80..000000000000 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/VelocityTrackerInterface.java +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License - */ - -package com.android.systemui.statusbar.phone; - -import android.view.MotionEvent; - -/** - * An interface for a velocity tracker to delegate. To be implemented by different velocity tracking - * algorithms. - */ -public interface VelocityTrackerInterface { - public void addMovement(MotionEvent event); - public void computeCurrentVelocity(int units); - public float getXVelocity(); - public float getYVelocity(); - public void recycle(); -} diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index 5771748d6ea3..af33bd02c745 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -978,12 +978,12 @@ public final class AutofillManagerService extends SystemService { throw new IllegalArgumentException(packageName + " is not a valid package", e); } - // TODO(b/112051762): rather than always call AM here, call it on demand on + // TODO(b/113281366): rather than always call AM here, call it on demand on // getPreviousSessionsLocked()? That way we save space / time here, and don't set // a callback on AM unnecessarily (see TODO below :-) final ActivityManagerInternal am = LocalServices .getService(ActivityManagerInternal.class); - // TODO(b/112051762): add a callback method on AM to be notified when a task is finished + // TODO(b/113281366): add a callback method on AM to be notified when a task is finished // so we can clean up sessions kept alive final int taskId = am.getTaskIdForActivity(activityToken, false); final int sessionId; diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java index 48b3798c863d..8c8352f81df5 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java @@ -617,7 +617,7 @@ final class AutofillManagerServiceImpl { ArrayList<Session> previousSessions = null; for (int i = 0; i < size; i++) { final Session previousSession = mSessions.valueAt(i); - // TODO(b/112051762): only return sessions asked to be kept alive / add CTS test + // TODO(b/113281366): only return sessions asked to be kept alive / add CTS test if (previousSession.taskId == session.taskId && previousSession.id != session.id) { if (previousSessions == null) { previousSessions = new ArrayList<>(size); @@ -625,7 +625,7 @@ final class AutofillManagerServiceImpl { previousSessions.add(previousSession); } } - // TODO(b/112051762): remove returned sessions / add CTS test + // TODO(b/113281366): remove returned sessions / add CTS test return previousSessions; } diff --git a/services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java b/services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java index 8ee65711feb4..293f908e2708 100644 --- a/services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java +++ b/services/autofill/java/com/android/server/autofill/FieldClassificationStrategy.java @@ -17,8 +17,8 @@ package com.android.server.autofill; import static com.android.server.autofill.Helper.sDebug; import static com.android.server.autofill.Helper.sVerbose; -import static android.service.autofill.AutofillFieldClassificationService.RESOURCE_AVAILABLE_ALGORITHMS; -import static android.service.autofill.AutofillFieldClassificationService.RESOURCE_DEFAULT_ALGORITHM; +import static android.service.autofill.AutofillFieldClassificationService.SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS; +import static android.service.autofill.AutofillFieldClassificationService.SERVICE_META_DATA_KEY_DEFAULT_ALGORITHM; import android.Manifest; import android.annotation.MainThread; @@ -226,7 +226,7 @@ final class FieldClassificationStrategy { */ @Nullable String[] getAvailableAlgorithms() { - return getMetadataValue(RESOURCE_AVAILABLE_ALGORITHMS, "array", + return getMetadataValue(SERVICE_META_DATA_KEY_AVAILABLE_ALGORITHMS, (res, id) -> res.getStringArray(id)); } @@ -235,12 +235,11 @@ final class FieldClassificationStrategy { */ @Nullable String getDefaultAlgorithm() { - return getMetadataValue(RESOURCE_DEFAULT_ALGORITHM, "string", - (res, id) -> res.getString(id)); + return getMetadataValue(SERVICE_META_DATA_KEY_DEFAULT_ALGORITHM, (res, id) -> res.getString(id)); } @Nullable - private <T> T getMetadataValue(String field, String type, MetadataParser<T> parser) { + private <T> T getMetadataValue(String field, MetadataParser<T> parser) { final ServiceInfo serviceInfo = getServiceInfo(); if (serviceInfo == null) return null; @@ -254,7 +253,7 @@ final class FieldClassificationStrategy { return null; } - final int resourceId = res.getIdentifier(field, type, serviceInfo.packageName); + final int resourceId = serviceInfo.metaData.getInt(field); return parser.get(res, resourceId); } diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 5a10c1e4b42a..5b7332d0c636 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -75,6 +75,7 @@ import android.service.autofill.ValueFinder; import android.util.ArrayMap; import android.util.ArraySet; import android.util.LocalLog; +import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.TimeUtils; @@ -329,12 +330,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState fillContextWithAllowedValuesLocked(mContexts.get(i), flags); } - // Dispatch a snapshot of the current contexts list since it may change - // until the dispatch happens. The items in the list don't need to be cloned - // since we don't hold on them anywhere else. The client state is not touched - // by us, so no need to copy. - request = new FillRequest(requestId, new ArrayList<>(mContexts), mClientState, - flags); + final ArrayList<FillContext> contexts = + mergePreviousSessionLocked(/* forSave= */ false); + request = new FillRequest(requestId, contexts, mClientState, flags); } mRemoteFillService.onFillRequest(request); @@ -1465,7 +1463,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState } if ((saveInfo.getFlags() & SaveInfo.FLAG_DELAY_SAVE) != 0) { - // TODO(b/112051762): log metrics + // TODO(b/113281366): log metrics if (sDebug) Slog.v(TAG, "showSaveLocked(): service asked to delay save"); return false; } @@ -1890,13 +1888,38 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState // Remove pending fill requests as the session is finished. cancelCurrentRequestLocked(); - // Merge the previous sessions that the service asked to be kept alive + final ArrayList<FillContext> contexts = mergePreviousSessionLocked( /* forSave= */ true); + + final SaveRequest saveRequest = + new SaveRequest(contexts, mClientState, mSelectedDatasetIds); + mRemoteFillService.onSaveRequest(saveRequest); + } + + // TODO(b/113281366): rather than merge it here, it might be better to simply reuse the old + // session instead of creating a new one. But we need to consider what would happen on corner + // cases such as "Main Activity M -> activity A with username -> activity B with password" + // If user follows the normal workflow, than session A would be merged with session B as + // expected. But if when on Activity A the user taps back or somehow launches another activity, + // session A could be merged with the wrong session. + /** + * Gets a list of contexts that includes not only this session's contexts but also the contexts + * from previous sessions that were asked by the service to be delayed (if any). + * + * <p>As a side-effect: + * <ul> + * <li>If the current {@link #mClientState} is {@code null}, sets it with the last non- + * {@code null} client state from previous sessions. + * <li>When {@code forSave} is {@code true}, calls {@link #updateValuesForSaveLocked()} in the + * previous sessions. + * </ul> + */ + @NonNull + private ArrayList<FillContext> mergePreviousSessionLocked(boolean forSave) { final ArrayList<Session> previousSessions = mService.getPreviousSessionsLocked(this); final ArrayList<FillContext> contexts; - final Bundle clientState; if (previousSessions != null) { if (sDebug) { - Slog.d(TAG, "callSaveLocked(): Merging the content of " + previousSessions.size() + Slog.d(TAG, "mergeSessions(): Merging the content of " + previousSessions.size() + " sessions for task " + taskId); } contexts = new ArrayList<>(); @@ -1904,31 +1927,35 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState final Session previousSession = previousSessions.get(i); final ArrayList<FillContext> previousContexts = previousSession.mContexts; if (previousContexts == null) { - Slog.w(TAG, "callSaveLocked(): Not merging null contexts from " + Slog.w(TAG, "mergeSessions(): Not merging null contexts from " + previousSession.id); continue; } - previousSession.updateValuesForSaveLocked(); - if (sVerbose) { - Slog.v(TAG, "callSaveLocked(): adding " + previousContexts.size() + if (forSave) { + previousSession.updateValuesForSaveLocked(); + } + if (sDebug) { + Slog.d(TAG, "mergeSessions(): adding " + previousContexts.size() + " context from previous session #" + previousSession.id); } contexts.addAll(previousContexts); + if (mClientState == null && previousSession.mClientState != null) { + if (sDebug) { + Slog.d(TAG, "mergeSessions(): setting client state from previous session" + + previousSession.id); + } + mClientState = previousSession.mClientState; + } } contexts.addAll(mContexts); - // TODO(b/112051762): decided what to do with client state / add CTS test - clientState = mClientState; } else { // Dispatch a snapshot of the current contexts list since it may change // until the dispatch happens. The items in the list don't need to be cloned // since we don't hold on them anywhere else. The client state is not touched // by us, so no need to copy. contexts = new ArrayList<>(mContexts); - clientState = mClientState; } - - final SaveRequest saveRequest = new SaveRequest(contexts, clientState, mSelectedDatasetIds); - mRemoteFillService.onSaveRequest(saveRequest); + return contexts; } /** diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java index 713da305ed55..aaca85b85943 100644 --- a/services/core/java/com/android/server/Watchdog.java +++ b/services/core/java/com/android/server/Watchdog.java @@ -17,34 +17,33 @@ package com.android.server; import android.app.IActivityController; -import android.os.Binder; -import android.os.Build; -import android.os.RemoteException; -import android.system.ErrnoException; -import android.system.Os; -import android.system.OsConstants; -import android.system.StructRlimit; -import com.android.internal.os.ZygoteConnectionConstants; -import com.android.server.am.ActivityManagerService; - import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.hidl.manager.V1_0.IServiceManager; +import android.os.Binder; +import android.os.Build; import android.os.Debug; import android.os.Handler; import android.os.IPowerManager; import android.os.Looper; import android.os.Process; +import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; -import android.os.SystemProperties; +import android.system.ErrnoException; +import android.system.Os; +import android.system.OsConstants; +import android.system.StructRlimit; import android.util.EventLog; import android.util.Log; import android.util.Slog; +import com.android.internal.os.ZygoteConnectionConstants; +import com.android.server.am.ActivityManagerService; + import java.io.File; import java.io.FileWriter; import java.io.IOException; @@ -62,6 +61,8 @@ import java.util.List; public class Watchdog extends Thread { static final String TAG = "Watchdog"; + private static final boolean DEBUG = true; // STOPSHIP disable it (b/113252928) + // Set this to true to use debug default values. static final boolean DB = false; @@ -478,6 +479,7 @@ public class Watchdog extends Thread { continue; } else if (waitState == WAITED_HALF) { if (!waitedHalf) { + if (DEBUG) Slog.d(TAG, "WAITED_HALF"); // We've waited half the deadlock-detection interval. Pull a stack // trace and wait another half. ArrayList<Integer> pids = new ArrayList<Integer>(); diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java index 0a7d3fdb5973..0e63d0c557f6 100644 --- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java +++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java @@ -46,7 +46,7 @@ class ActivityManagerDebugConfig { // Available log categories in the activity manager package. static final boolean DEBUG_ADD_REMOVE = DEBUG_ALL_ACTIVITIES || false; - static final boolean DEBUG_ANR = false; + static final boolean DEBUG_ANR = true; // STOPSHIP disable it (b/113252928) static final boolean DEBUG_APP = DEBUG_ALL_ACTIVITIES || false; static final boolean DEBUG_BACKGROUND_CHECK = DEBUG_ALL || false; static final boolean DEBUG_BACKUP = DEBUG_ALL || false; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 82805eda1562..1bc0524eb2f9 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1618,6 +1618,9 @@ public class ActivityManagerService extends IActivityManager.Stub break; } case DISPATCH_UIDS_CHANGED_UI_MSG: { + if (false) { // DO NOT SUBMIT WITH TRUE + maybeTriggerWatchdog(); + } dispatchUidsChanged(); } break; case DISPATCH_OOM_ADJ_OBSERVER_MSG: { @@ -21551,4 +21554,20 @@ public class ActivityManagerService extends IActivityManager.Stub return superImpl.apply(permName, uid); } } + + /** + * If debug.trigger.watchdog is set to 1, sleep 10 minutes with the AM lock held, which would + * cause a watchdog kill. + */ + void maybeTriggerWatchdog() { + if (SystemProperties.getInt("debug.trigger.watchdog", 0) == 1) { + Slog.w(TAG, "TRIGGERING WATCHDOG"); + synchronized (ActivityManagerService.this) { + try { + Thread.sleep(600 * 1000); + } catch (InterruptedException e) { + } + } + } + } } diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java index c0beb37577fc..b8f057db290a 100644 --- a/services/core/java/com/android/server/connectivity/DnsManager.java +++ b/services/core/java/com/android/server/connectivity/DnsManager.java @@ -35,7 +35,6 @@ import android.net.LinkProperties; import android.net.Network; import android.net.NetworkUtils; import android.net.Uri; -import android.net.dns.ResolvUtil; import android.os.Binder; import android.os.INetworkManagementService; import android.os.UserHandle; @@ -174,15 +173,6 @@ public class DnsManager { return new PrivateDnsConfig(useTls); } - public static PrivateDnsConfig tryBlockingResolveOf(Network network, String name) { - try { - final InetAddress[] ips = ResolvUtil.blockingResolveAllLocally(network, name); - return new PrivateDnsConfig(name, ips); - } catch (UnknownHostException uhe) { - return new PrivateDnsConfig(name, null); - } - } - public static Uri[] getPrivateDnsSettingsUris() { return new Uri[]{ Settings.Global.getUriFor(PRIVATE_DNS_DEFAULT_MODE), diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java index 843ba2e23224..ca9b25699c1c 100644 --- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java +++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java @@ -43,7 +43,6 @@ import android.net.TrafficStats; import android.net.Uri; import android.net.captiveportal.CaptivePortalProbeResult; import android.net.captiveportal.CaptivePortalProbeSpec; -import android.net.dns.ResolvUtil; import android.net.metrics.IpConnectivityLog; import android.net.metrics.NetworkEvent; import android.net.metrics.ValidationProbeEvent; @@ -326,7 +325,7 @@ public class NetworkMonitor extends StateMachine { mConnectivityServiceHandler = handler; mDependencies = deps; mNetworkAgentInfo = networkAgentInfo; - mNetwork = deps.getNetwork(networkAgentInfo); + mNetwork = deps.getNetwork(networkAgentInfo).getPrivateDnsBypassingCopy(); mNetId = mNetwork.netId; mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); @@ -800,9 +799,7 @@ public class NetworkMonitor extends StateMachine { private void resolveStrictModeHostname() { try { // Do a blocking DNS resolution using the network-assigned nameservers. - // Do not set AI_ADDRCONFIG in ai_flags so we get all address families in advance. - final InetAddress[] ips = ResolvUtil.blockingResolveAllLocally( - mNetwork, mPrivateDnsProviderHostname, 0 /* aiFlags */); + final InetAddress[] ips = mNetwork.getAllByName(mPrivateDnsProviderHostname); mPrivateDnsConfig = new PrivateDnsConfig(mPrivateDnsProviderHostname, ips); validationLog("Strict mode hostname resolved: " + mPrivateDnsConfig); } catch (UnknownHostException uhe) { @@ -860,14 +857,13 @@ public class NetworkMonitor extends StateMachine { // to complete, regardless of how many IP addresses a host has. private static class OneAddressPerFamilyNetwork extends Network { public OneAddressPerFamilyNetwork(Network network) { - super(network); + // Always bypass Private DNS. + super(network.getPrivateDnsBypassingCopy()); } @Override public InetAddress[] getAllByName(String host) throws UnknownHostException { - // Always bypass Private DNS. - final List<InetAddress> addrs = Arrays.asList( - ResolvUtil.blockingResolveAllLocally(this, host)); + final List<InetAddress> addrs = Arrays.asList(super.getAllByName(host)); // Ensure the address family of the first address is tried first. LinkedHashMap<Class, InetAddress> addressByFamily = new LinkedHashMap<>(); diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java index 2c9a494dbecd..c145d646bc63 100644 --- a/services/core/java/com/android/server/content/ContentService.java +++ b/services/core/java/com/android/server/content/ContentService.java @@ -1305,14 +1305,16 @@ public final class ContentService extends IContentService.Stub { } final ActivityManagerInternal ami = LocalServices.getService(ActivityManagerInternal.class); - final int procState = (ami != null) - ? ami.getUidProcessState(callingUid) - : ActivityManager.PROCESS_STATE_NONEXISTENT; + if (ami == null) { + return ContentResolver.SYNC_EXEMPTION_NONE; + } + final int procState = ami.getUidProcessState(callingUid); + final boolean isUidActive = ami.isUidActive(callingUid); if (procState <= ActivityManager.PROCESS_STATE_TOP) { return ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP; } - if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) { + if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND || isUidActive) { return ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET; } return ContentResolver.SYNC_EXEMPTION_NONE; diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index 59673d09a6bb..556038f3f646 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -19,6 +19,7 @@ import android.annotation.Nullable; import android.app.ActivityManagerInternal; import android.app.AlarmManager; import android.app.AlarmManager.OnAlarmListener; +import android.app.PendingIntent; import android.app.ProcessMemoryState; import android.app.StatsManager; import android.bluetooth.BluetoothActivityEnergyInfo; @@ -43,7 +44,6 @@ import android.os.FileUtils; import android.os.IBinder; import android.os.IStatsCompanionService; import android.os.IStatsManager; -import android.os.IStoraged; import android.os.Parcelable; import android.os.Process; import android.os.RemoteException; @@ -55,7 +55,6 @@ import android.os.SynchronousResultReceiver; import android.os.SystemClock; import android.os.UserHandle; import android.os.UserManager; -import android.os.storage.StorageManager; import android.telephony.ModemActivityInfo; import android.telephony.TelephonyManager; import android.util.ArrayMap; @@ -66,10 +65,10 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.net.NetworkStatsFactory; import com.android.internal.os.BinderCallsStats.ExportedCallStat; import com.android.internal.os.KernelCpuSpeedReader; -import com.android.internal.os.KernelUidCpuActiveTimeReader; +import com.android.internal.os.KernelUidCpuTimeReader; import com.android.internal.os.KernelUidCpuClusterTimeReader; +import com.android.internal.os.KernelUidCpuActiveTimeReader; import com.android.internal.os.KernelUidCpuFreqTimeReader; -import com.android.internal.os.KernelUidCpuTimeReader; import com.android.internal.os.KernelWakelockReader; import com.android.internal.os.KernelWakelockStats; import com.android.internal.os.PowerProfile; @@ -77,18 +76,9 @@ import com.android.internal.util.DumpUtils; import com.android.server.BinderCallsStatsService; import com.android.server.LocalServices; import com.android.server.SystemService; -import com.android.server.storage.DiskStatsFileLogger; -import com.android.server.storage.DiskStatsLoggingService; - -import libcore.io.IoUtils; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; import java.io.File; import java.io.FileDescriptor; -import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; @@ -874,6 +864,14 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pulledData.add(e); } + private void pullDiskSpace(int tagId, List<StatsLogEventWrapper> pulledData) { + StatsLogEventWrapper e = new StatsLogEventWrapper(SystemClock.elapsedRealtimeNanos(), tagId, 3); + e.writeLong(mStatFsData.getAvailableBytes()); + e.writeLong(mStatFsSystem.getAvailableBytes()); + e.writeLong(mStatFsTemp.getAvailableBytes()); + pulledData.add(e); + } + private void pullSystemUpTime(int tagId, List<StatsLogEventWrapper> pulledData) { StatsLogEventWrapper e = new StatsLogEventWrapper(SystemClock.elapsedRealtimeNanos(), tagId, 1); e.writeLong(SystemClock.uptimeMillis()); @@ -944,183 +942,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } - private void pullDiskStats(int tagId, List<StatsLogEventWrapper> pulledData) { - // Run a quick-and-dirty performance test: write 512 bytes - byte[] junk = new byte[512]; - for (int i = 0; i < junk.length; i++) junk[i] = (byte) i; // Write nonzero bytes - - File tmp = new File(Environment.getDataDirectory(), "system/statsdperftest.tmp"); - FileOutputStream fos = null; - IOException error = null; - - long before = SystemClock.elapsedRealtime(); - try { - fos = new FileOutputStream(tmp); - fos.write(junk); - } catch (IOException e) { - error = e; - } finally { - try { - if (fos != null) fos.close(); - } catch (IOException e) { - // Do nothing. - } - } - - long latency = SystemClock.elapsedRealtime() - before; - if (tmp.exists()) tmp.delete(); - - if (error != null) { - Slog.e(TAG, "Error performing diskstats latency test"); - latency = -1; - } - // File based encryption. - boolean fileBased = StorageManager.isFileEncryptedNativeOnly(); - - //Recent disk write speed. Binder call to storaged. - int writeSpeed = -1; - try { - IBinder binder = ServiceManager.getService("storaged"); - if (binder == null) { - Slog.e(TAG, "storaged not found"); - } - IStoraged storaged = IStoraged.Stub.asInterface(binder); - writeSpeed = storaged.getRecentPerf(); - } catch (RemoteException e) { - Slog.e(TAG, "storaged not found"); - } - - // Add info pulledData. - long elapsedNanos = SystemClock.elapsedRealtimeNanos(); - StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */); - e.writeLong(latency); - e.writeBoolean(fileBased); - e.writeInt(writeSpeed); - pulledData.add(e); - } - - private void pullDirectoryUsage(int tagId, List<StatsLogEventWrapper> pulledData) { - long elapsedNanos = SystemClock.elapsedRealtimeNanos(); - StatFs statFsData = new StatFs(Environment.getDataDirectory().getAbsolutePath()); - StatFs statFsSystem = new StatFs(Environment.getRootDirectory().getAbsolutePath()); - StatFs statFsCache = new StatFs(Environment.getDownloadCacheDirectory().getAbsolutePath()); - - StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */); - e.writeInt(StatsLog.DIRECTORY_USAGE__DIRECTORY__DATA); - e.writeLong(statFsData.getAvailableBytes()); - e.writeLong(statFsData.getTotalBytes()); - pulledData.add(e); - - e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */); - e.writeInt(StatsLog.DIRECTORY_USAGE__DIRECTORY__CACHE); - e.writeLong(statFsCache.getAvailableBytes()); - e.writeLong(statFsCache.getTotalBytes()); - pulledData.add(e); - - e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */); - e.writeInt(StatsLog.DIRECTORY_USAGE__DIRECTORY__SYSTEM); - e.writeLong(statFsSystem.getAvailableBytes()); - e.writeLong(statFsSystem.getTotalBytes()); - pulledData.add(e); - } - - private void pullAppSize(int tagId, List<StatsLogEventWrapper> pulledData) { - long elapsedNanos = SystemClock.elapsedRealtimeNanos(); - try { - String jsonStr = IoUtils.readFileAsString(DiskStatsLoggingService.DUMPSYS_CACHE_PATH); - JSONObject json = new JSONObject(jsonStr); - long cache_time = json.optLong(DiskStatsFileLogger.LAST_QUERY_TIMESTAMP_KEY, -1L); - JSONArray pkg_names = json.getJSONArray(DiskStatsFileLogger.PACKAGE_NAMES_KEY); - JSONArray app_sizes = json.getJSONArray(DiskStatsFileLogger.APP_SIZES_KEY); - JSONArray app_data_sizes = json.getJSONArray(DiskStatsFileLogger.APP_DATA_KEY); - JSONArray app_cache_sizes = json.getJSONArray(DiskStatsFileLogger.APP_CACHES_KEY); - // Sanity check: Ensure all 4 lists have the same length. - int length = pkg_names.length(); - if (app_sizes.length() != length || app_data_sizes.length() != length - || app_cache_sizes.length() != length) { - Slog.e(TAG, "formatting error in diskstats cache file!"); - return; - } - for (int i = 0; i < length; i++) { - StatsLogEventWrapper e = - new StatsLogEventWrapper(elapsedNanos, tagId, 5 /* fields */); - e.writeString(pkg_names.getString(i)); - e.writeLong(app_sizes.optLong(i, -1L)); - e.writeLong(app_data_sizes.optLong(i, -1L)); - e.writeLong(app_cache_sizes.optLong(i, -1L)); - e.writeLong(cache_time); - pulledData.add(e); - } - } catch (IOException | JSONException e) { - Slog.e(TAG, "exception reading diskstats cache file", e); - } - } - - private void pullCategorySize(int tagId, List<StatsLogEventWrapper> pulledData) { - long elapsedNanos = SystemClock.elapsedRealtimeNanos(); - try { - String jsonStr = IoUtils.readFileAsString(DiskStatsLoggingService.DUMPSYS_CACHE_PATH); - JSONObject json = new JSONObject(jsonStr); - long cacheTime = json.optLong(DiskStatsFileLogger.LAST_QUERY_TIMESTAMP_KEY, -1L); - - StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */); - e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__APP_SIZE); - e.writeLong(json.optLong(DiskStatsFileLogger.APP_SIZE_AGG_KEY, -1L)); - e.writeLong(cacheTime); - pulledData.add(e); - - e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */); - e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__APP_DATA_SIZE); - e.writeLong(json.optLong(DiskStatsFileLogger.APP_DATA_SIZE_AGG_KEY, -1L)); - e.writeLong(cacheTime); - pulledData.add(e); - - e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */); - e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__APP_CACHE_SIZE); - e.writeLong(json.optLong(DiskStatsFileLogger.APP_CACHE_AGG_KEY, -1L)); - e.writeLong(cacheTime); - pulledData.add(e); - - e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */); - e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__PHOTOS); - e.writeLong(json.optLong(DiskStatsFileLogger.PHOTOS_KEY, -1L)); - e.writeLong(cacheTime); - pulledData.add(e); - - e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */); - e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__VIDEOS); - e.writeLong(json.optLong(DiskStatsFileLogger.VIDEOS_KEY, -1L)); - e.writeLong(cacheTime); - pulledData.add(e); - - e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */); - e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__AUDIO); - e.writeLong(json.optLong(DiskStatsFileLogger.AUDIO_KEY, -1L)); - e.writeLong(cacheTime); - pulledData.add(e); - - e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */); - e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__DOWNLOADS); - e.writeLong(json.optLong(DiskStatsFileLogger.DOWNLOADS_KEY, -1L)); - e.writeLong(cacheTime); - pulledData.add(e); - - e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */); - e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__SYSTEM); - e.writeLong(json.optLong(DiskStatsFileLogger.SYSTEM_KEY, -1L)); - e.writeLong(cacheTime); - pulledData.add(e); - - e = new StatsLogEventWrapper(elapsedNanos, tagId, 3 /* fields */); - e.writeInt(StatsLog.CATEGORY_SIZE__CATEGORY__OTHER); - e.writeLong(json.optLong(DiskStatsFileLogger.MISC_KEY, -1L)); - e.writeLong(cacheTime); - pulledData.add(e); - } catch (IOException | JSONException e) { - Slog.e(TAG, "exception reading diskstats cache file", e); - } - } - /** * Pulls various data. */ @@ -1195,6 +1016,10 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pullSystemElapsedRealtime(tagId, ret); break; } + case StatsLog.DISK_SPACE: { + pullDiskSpace(tagId, ret); + break; + } case StatsLog.PROCESS_MEMORY_STATE: { pullProcessMemoryState(tagId, ret); break; @@ -1207,22 +1032,6 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pullBinderCallsStatsExceptions(tagId, ret); break; } - case StatsLog.DISK_STATS: { - pullDiskStats(tagId, ret); - break; - } - case StatsLog.DIRECTORY_USAGE: { - pullDirectoryUsage(tagId, ret); - break; - } - case StatsLog.APP_SIZE: { - pullAppSize(tagId, ret); - break; - } - case StatsLog.CATEGORY_SIZE: { - pullCategorySize(tagId, ret); - break; - } default: Slog.w(TAG, "No such tagId data as " + tagId); return null; diff --git a/services/net/java/android/net/dhcp/DhcpLeaseRepository.java b/services/net/java/android/net/dhcp/DhcpLeaseRepository.java index 7e57c9f46350..9f77ed0ae5dd 100644 --- a/services/net/java/android/net/dhcp/DhcpLeaseRepository.java +++ b/services/net/java/android/net/dhcp/DhcpLeaseRepository.java @@ -29,7 +29,7 @@ import android.annotation.Nullable; import android.net.IpPrefix; import android.net.MacAddress; import android.net.util.SharedLog; -import android.os.SystemClock; +import android.net.dhcp.DhcpServer.Clock; import android.util.ArrayMap; import java.net.Inet4Address; @@ -73,15 +73,6 @@ class DhcpLeaseRepository { private int mNumAddresses; private long mLeaseTimeMs; - public static class Clock { - /** - * @see SystemClock#elapsedRealtime() - */ - public long elapsedRealtime() { - return SystemClock.elapsedRealtime(); - } - } - /** * Next timestamp when committed or declined leases should be checked for expired ones. This * will always be lower than or equal to the time for the first lease to expire: it's OK not to diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java index 888821a8ad92..175e27eb9467 100644 --- a/services/net/java/android/net/dhcp/DhcpPacket.java +++ b/services/net/java/android/net/dhcp/DhcpPacket.java @@ -9,6 +9,7 @@ import android.os.Build; import android.os.SystemProperties; import android.system.OsConstants; import android.text.TextUtils; + import com.android.internal.annotations.VisibleForTesting; import java.io.UnsupportedEncodingException; @@ -351,6 +352,14 @@ public abstract class DhcpPacket { } /** + * Convenience method to return the client ID if it was set explicitly, or null otherwise. + */ + @Nullable + public byte[] getExplicitClientIdOrNull() { + return hasExplicitClientId() ? getClientId() : null; + } + + /** * Returns the client ID. If not set explicitly, this follows RFC 2132 and creates a client ID * based on the hardware address. */ diff --git a/services/net/java/android/net/dhcp/DhcpPacketListener.java b/services/net/java/android/net/dhcp/DhcpPacketListener.java index 498fd93fff59..6f620c5ce30e 100644 --- a/services/net/java/android/net/dhcp/DhcpPacketListener.java +++ b/services/net/java/android/net/dhcp/DhcpPacketListener.java @@ -16,15 +16,14 @@ package android.net.dhcp; +import android.annotation.NonNull; import android.annotation.Nullable; import android.net.util.FdEventsReader; -import android.net.util.PacketReader; import android.os.Handler; import android.system.Os; import java.io.FileDescriptor; import java.net.Inet4Address; -import java.net.InetAddress; import java.net.InetSocketAddress; /** @@ -35,19 +34,20 @@ abstract class DhcpPacketListener extends FdEventsReader<DhcpPacketListener.Payl static final class Payload { final byte[] bytes = new byte[DhcpPacket.MAX_LENGTH]; Inet4Address srcAddr; + int srcPort; } - public DhcpPacketListener(Handler handler) { + public DhcpPacketListener(@NonNull Handler handler) { super(handler, new Payload()); } @Override - protected int recvBufSize(Payload buffer) { + protected int recvBufSize(@NonNull Payload buffer) { return buffer.bytes.length; } @Override - protected final void handlePacket(Payload recvbuf, int length) { + protected final void handlePacket(@NonNull Payload recvbuf, int length) { if (recvbuf.srcAddr == null) { return; } @@ -55,30 +55,34 @@ abstract class DhcpPacketListener extends FdEventsReader<DhcpPacketListener.Payl try { final DhcpPacket packet = DhcpPacket.decodeFullPacket(recvbuf.bytes, length, DhcpPacket.ENCAP_BOOTP); - onReceive(packet, recvbuf.srcAddr); + onReceive(packet, recvbuf.srcAddr, recvbuf.srcPort); } catch (DhcpPacket.ParseException e) { logParseError(recvbuf.bytes, length, e); } } @Override - protected int readPacket(FileDescriptor fd, Payload packetBuffer) throws Exception { + protected int readPacket(@NonNull FileDescriptor fd, @NonNull Payload packetBuffer) + throws Exception { final InetSocketAddress addr = new InetSocketAddress(); final int read = Os.recvfrom( fd, packetBuffer.bytes, 0, packetBuffer.bytes.length, 0 /* flags */, addr); // Buffers with null srcAddr will be dropped in handlePacket() packetBuffer.srcAddr = inet4AddrOrNull(addr); + packetBuffer.srcPort = addr.getPort(); return read; } @Nullable - private static Inet4Address inet4AddrOrNull(InetSocketAddress addr) { + private static Inet4Address inet4AddrOrNull(@NonNull InetSocketAddress addr) { return addr.getAddress() instanceof Inet4Address ? (Inet4Address) addr.getAddress() : null; } - protected abstract void onReceive(DhcpPacket packet, Inet4Address srcAddr); - protected abstract void logParseError(byte[] packet, int length, DhcpPacket.ParseException e); + protected abstract void onReceive(@NonNull DhcpPacket packet, @NonNull Inet4Address srcAddr, + int srcPort); + protected abstract void logParseError(@NonNull byte[] packet, int length, + @NonNull DhcpPacket.ParseException e); } diff --git a/services/net/java/android/net/dhcp/DhcpServer.java b/services/net/java/android/net/dhcp/DhcpServer.java new file mode 100644 index 000000000000..095a5eb72289 --- /dev/null +++ b/services/net/java/android/net/dhcp/DhcpServer.java @@ -0,0 +1,518 @@ +/* + * 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.dhcp; + +import static android.net.NetworkUtils.getBroadcastAddress; +import static android.net.NetworkUtils.getPrefixMaskAsInet4Address; +import static android.net.TrafficStats.TAG_SYSTEM_DHCP_SERVER; +import static android.net.dhcp.DhcpPacket.DHCP_CLIENT; +import static android.net.dhcp.DhcpPacket.DHCP_SERVER; +import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP; +import static android.net.dhcp.DhcpPacket.INFINITE_LEASE; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.IPPROTO_UDP; +import static android.system.OsConstants.SOCK_DGRAM; +import static android.system.OsConstants.SOL_SOCKET; +import static android.system.OsConstants.SO_BINDTODEVICE; +import static android.system.OsConstants.SO_BROADCAST; +import static android.system.OsConstants.SO_REUSEADDR; + +import static java.lang.Integer.toUnsignedLong; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.MacAddress; +import android.net.NetworkUtils; +import android.net.TrafficStats; +import android.net.util.InterfaceParams; +import android.net.util.SharedLog; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.SystemClock; +import android.system.ErrnoException; +import android.system.Os; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.HexDump; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.net.Inet4Address; +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.util.ArrayList; + +/** + * A DHCPv4 server. + * + * <p>This server listens for and responds to packets on a single interface. It considers itself + * authoritative for all leases on the subnet, which means that DHCP requests for unknown leases of + * unknown hosts receive a reply instead of being ignored. + * + * <p>The server is single-threaded (including send/receive operations): all internal operations are + * done on the provided {@link Looper}. Public methods are thread-safe and will schedule operations + * on the looper asynchronously. + * @hide + */ +public class DhcpServer { + private static final String REPO_TAG = "Repository"; + + // Lease time to transmit to client instead of a negative time in case a lease expired before + // the server could send it (if the server process is suspended for example). + private static final int EXPIRED_FALLBACK_LEASE_TIME_SECS = 120; + + private static final int CMD_START_DHCP_SERVER = 1; + private static final int CMD_STOP_DHCP_SERVER = 2; + private static final int CMD_UPDATE_PARAMS = 3; + + @NonNull + private final ServerHandler mHandler; + @NonNull + private final InterfaceParams mIface; + @NonNull + private final DhcpLeaseRepository mLeaseRepo; + @NonNull + private final SharedLog mLog; + @NonNull + private final Dependencies mDeps; + @NonNull + private final Clock mClock; + @NonNull + private final DhcpPacketListener mPacketListener; + + @Nullable + private FileDescriptor mSocket; + @NonNull + private DhcpServingParams mServingParams; + + public static class Clock { + /** + * @see SystemClock#elapsedRealtime() + */ + public long elapsedRealtime() { + return SystemClock.elapsedRealtime(); + } + } + + public interface Dependencies { + void sendPacket(@NonNull FileDescriptor fd, @NonNull ByteBuffer buffer, + @NonNull InetAddress dst) throws ErrnoException, IOException; + DhcpLeaseRepository makeLeaseRepository(@NonNull DhcpServingParams servingParams, + @NonNull SharedLog log, @NonNull Clock clock); + DhcpPacketListener makePacketListener(); + Clock makeClock(); + void addArpEntry(@NonNull Inet4Address ipv4Addr, @NonNull MacAddress ethAddr, + @NonNull String ifname, @NonNull FileDescriptor fd) throws IOException; + } + + private class DependenciesImpl implements Dependencies { + @Override + public void sendPacket(@NonNull FileDescriptor fd, @NonNull ByteBuffer buffer, + @NonNull InetAddress dst) throws ErrnoException, IOException { + Os.sendto(fd, buffer, 0, dst, DhcpPacket.DHCP_CLIENT); + } + + @Override + public DhcpLeaseRepository makeLeaseRepository(@NonNull DhcpServingParams servingParams, + @NonNull SharedLog log, @NonNull Clock clock) { + return new DhcpLeaseRepository( + DhcpServingParams.makeIpPrefix(servingParams.serverAddr), + servingParams.excludedAddrs, + servingParams.dhcpLeaseTimeSecs*1000, log.forSubComponent(REPO_TAG), clock); + } + + @Override + public DhcpPacketListener makePacketListener() { + return new PacketListener(); + } + + @Override + public Clock makeClock() { + return new Clock(); + } + + @Override + public void addArpEntry(@NonNull Inet4Address ipv4Addr, @NonNull MacAddress ethAddr, + @NonNull String ifname, @NonNull FileDescriptor fd) throws IOException { + NetworkUtils.addArpEntry(ipv4Addr, ethAddr, ifname, fd); + } + } + + private static class MalformedPacketException extends Exception { + MalformedPacketException(String message, Throwable t) { + super(message, t); + } + } + + public DhcpServer(@NonNull Looper looper, @NonNull InterfaceParams iface, + @NonNull DhcpServingParams params, @NonNull SharedLog log) { + this(looper, iface, params, log, null); + } + + @VisibleForTesting + DhcpServer(@NonNull Looper looper, @NonNull InterfaceParams iface, + @NonNull DhcpServingParams params, @NonNull SharedLog log, + @Nullable Dependencies deps) { + if (deps == null) { + deps = new DependenciesImpl(); + } + mHandler = new ServerHandler(looper); + mIface = iface; + mServingParams = params; + mLog = log; + mDeps = deps; + mClock = deps.makeClock(); + mPacketListener = deps.makePacketListener(); + mLeaseRepo = deps.makeLeaseRepository(mServingParams, mLog, mClock); + } + + /** + * Start listening for and responding to packets. + */ + public void start() { + mHandler.sendEmptyMessage(CMD_START_DHCP_SERVER); + } + + /** + * Update serving parameters. All subsequently received requests will be handled with the new + * parameters, and current leases that are incompatible with the new parameters are dropped. + */ + public void updateParams(@NonNull DhcpServingParams params) { + sendMessage(CMD_UPDATE_PARAMS, params); + } + + /** + * Stop listening for packets. + * + * <p>As the server is stopped asynchronously, some packets may still be processed shortly after + * calling this method. + */ + public void stop() { + mHandler.sendEmptyMessage(CMD_STOP_DHCP_SERVER); + } + + private void sendMessage(int what, @Nullable Object obj) { + mHandler.sendMessage(mHandler.obtainMessage(what, obj)); + } + + private class ServerHandler extends Handler { + public ServerHandler(@NonNull Looper looper) { + super(looper); + } + + @Override + public void handleMessage(@NonNull Message msg) { + switch (msg.what) { + case CMD_UPDATE_PARAMS: + final DhcpServingParams params = (DhcpServingParams) msg.obj; + mServingParams = params; + mLeaseRepo.updateParams( + DhcpServingParams.makeIpPrefix(mServingParams.serverAddr), + params.excludedAddrs, + params.dhcpLeaseTimeSecs); + break; + case CMD_START_DHCP_SERVER: + // This is a no-op if the listener is already started + mPacketListener.start(); + break; + case CMD_STOP_DHCP_SERVER: + // This is a no-op if the listener was not started + mPacketListener.stop(); + break; + } + } + } + + @VisibleForTesting + void processPacket(@NonNull DhcpPacket packet, int srcPort) { + final String packetType = packet.getClass().getSimpleName(); + if (srcPort != DHCP_CLIENT) { + mLog.logf("Ignored packet of type %s sent from client port %d", packetType, srcPort); + return; + } + + mLog.log("Received packet of type " + packetType); + final Inet4Address sid = packet.mServerIdentifier; + if (sid != null && !sid.equals(mServingParams.serverAddr.getAddress())) { + mLog.log("Packet ignored due to wrong server identifier: " + sid); + return; + } + + try { + if (packet instanceof DhcpDiscoverPacket) { + processDiscover((DhcpDiscoverPacket) packet); + } else if (packet instanceof DhcpRequestPacket) { + processRequest((DhcpRequestPacket) packet); + } else if (packet instanceof DhcpReleasePacket) { + processRelease((DhcpReleasePacket) packet); + } else { + mLog.e("Unknown packet type: " + packet.getClass().getSimpleName()); + } + } catch (MalformedPacketException e) { + // Not an internal error: only logging exception message, not stacktrace + mLog.e("Ignored malformed packet: " + e.getMessage()); + } + } + + private void processDiscover(@NonNull DhcpDiscoverPacket packet) + throws MalformedPacketException { + final DhcpLease lease; + final MacAddress clientMac = getMacAddr(packet); + try { + lease = mLeaseRepo.getOffer(packet.getExplicitClientIdOrNull(), clientMac, + packet.mRelayIp, packet.mRequestedIp, packet.mHostName); + } catch (DhcpLeaseRepository.OutOfAddressesException e) { + transmitNak(packet, "Out of addresses to offer"); + return; + } catch (DhcpLeaseRepository.InvalidAddressException e) { + transmitNak(packet, "Lease requested from an invalid subnet"); + return; + } + + transmitOffer(packet, lease, clientMac); + } + + private void processRequest(@NonNull DhcpRequestPacket packet) throws MalformedPacketException { + // If set, packet SID matches with this server's ID as checked in processPacket(). + final boolean sidSet = packet.mServerIdentifier != null; + final DhcpLease lease; + final MacAddress clientMac = getMacAddr(packet); + try { + lease = mLeaseRepo.requestLease(packet.getExplicitClientIdOrNull(), clientMac, + packet.mClientIp, packet.mRequestedIp, sidSet, packet.mHostName); + } catch (DhcpLeaseRepository.InvalidAddressException e) { + transmitNak(packet, "Invalid requested address"); + return; + } + + transmitAck(packet, lease, clientMac); + } + + private void processRelease(@Nullable DhcpReleasePacket packet) + throws MalformedPacketException { + final byte[] clientId = packet.getExplicitClientIdOrNull(); + final MacAddress macAddr = getMacAddr(packet); + // Don't care about success (there is no ACK/NAK); logging is already done in the repository + mLeaseRepo.releaseLease(clientId, macAddr, packet.mClientIp); + } + + private Inet4Address getAckOrOfferDst(@NonNull DhcpPacket request, @NonNull DhcpLease lease, + boolean broadcastFlag) { + // Unless relayed or broadcast, send to client IP if already configured on the client, or to + // the lease address if the client has no configured address + if (!isEmpty(request.mRelayIp)) { + return request.mRelayIp; + } else if (broadcastFlag) { + return (Inet4Address) Inet4Address.ALL; + } else if (!isEmpty(request.mClientIp)) { + return request.mClientIp; + } else { + return lease.getNetAddr(); + } + } + + /** + * Determine whether the broadcast flag should be set in the BOOTP packet flags. This does not + * apply to NAK responses, which should always have it set. + */ + private static boolean getBroadcastFlag(@NonNull DhcpPacket request, @NonNull DhcpLease lease) { + // No broadcast flag if the client already has a configured IP to unicast to. RFC2131 #4.1 + // has some contradictions regarding broadcast behavior if a client already has an IP + // configured and sends a request with both ciaddr (renew/rebind) and the broadcast flag + // set. Sending a unicast response to ciaddr matches previous behavior and is more + // efficient. + // If the client has no configured IP, broadcast if requested by the client or if the lease + // address cannot be used to send a unicast reply either. + return isEmpty(request.mClientIp) && (request.mBroadcast || isEmpty(lease.getNetAddr())); + } + + private boolean transmitOffer(@NonNull DhcpPacket request, @NonNull DhcpLease lease, + @NonNull MacAddress clientMac) { + final boolean broadcastFlag = getBroadcastFlag(request, lease); + final int timeout = getLeaseTimeout(lease); + final Inet4Address prefixMask = + getPrefixMaskAsInet4Address(mServingParams.serverAddr.getPrefixLength()); + final Inet4Address broadcastAddr = getBroadcastAddress( + mServingParams.getServerInet4Addr(), mServingParams.serverAddr.getPrefixLength()); + final ByteBuffer offerPacket = DhcpPacket.buildOfferPacket( + ENCAP_BOOTP, request.mTransId, broadcastFlag, mServingParams.getServerInet4Addr(), + lease.getNetAddr(), request.mClientMac, timeout, + prefixMask, + broadcastAddr, + new ArrayList<>(mServingParams.defaultRouters), + new ArrayList<>(mServingParams.dnsServers), + mServingParams.getServerInet4Addr(), null /* domainName */); + + return transmitOfferOrAckPacket(offerPacket, request, lease, clientMac, broadcastFlag); + } + + private boolean transmitAck(@NonNull DhcpPacket request, @NonNull DhcpLease lease, + @NonNull MacAddress clientMac) { + // TODO: replace DhcpPacket's build methods with real builders and use common code with + // transmitOffer above + final boolean broadcastFlag = getBroadcastFlag(request, lease); + final int timeout = getLeaseTimeout(lease); + final ByteBuffer ackPacket = DhcpPacket.buildAckPacket(ENCAP_BOOTP, request.mTransId, + broadcastFlag, mServingParams.getServerInet4Addr(), lease.getNetAddr(), + request.mClientMac, timeout, mServingParams.getPrefixMaskAsAddress(), + mServingParams.getBroadcastAddress(), + new ArrayList<>(mServingParams.defaultRouters), + new ArrayList<>(mServingParams.dnsServers), + mServingParams.getServerInet4Addr(), null /* domainName */); + + return transmitOfferOrAckPacket(ackPacket, request, lease, clientMac, broadcastFlag); + } + + private boolean transmitNak(DhcpPacket request, String message) { + mLog.w("Transmitting NAK: " + message); + // Always set broadcast flag for NAK: client may not have a correct IP + final ByteBuffer nakPacket = DhcpPacket.buildNakPacket( + ENCAP_BOOTP, request.mTransId, mServingParams.getServerInet4Addr(), + request.mClientMac, true /* broadcast */, message); + + final Inet4Address dst = isEmpty(request.mRelayIp) + ? (Inet4Address) Inet4Address.ALL + : request.mRelayIp; + return transmitPacket(nakPacket, DhcpNakPacket.class.getSimpleName(), dst); + } + + private boolean transmitOfferOrAckPacket(@NonNull ByteBuffer buf, @NonNull DhcpPacket request, + @NonNull DhcpLease lease, @NonNull MacAddress clientMac, boolean broadcastFlag) { + mLog.logf("Transmitting %s with lease %s", request.getClass().getSimpleName(), lease); + // Client may not yet respond to ARP for the lease address, which may be the destination + // address. Add an entry to the ARP cache to save future ARP probes and make sure the + // packet reaches its destination. + if (!addArpEntry(clientMac, lease.getNetAddr())) { + // Logging for error already done + return false; + } + final Inet4Address dst = getAckOrOfferDst(request, lease, broadcastFlag); + return transmitPacket(buf, request.getClass().getSimpleName(), dst); + } + + private boolean transmitPacket(@NonNull ByteBuffer buf, @NonNull String packetTypeTag, + @NonNull Inet4Address dst) { + try { + mDeps.sendPacket(mSocket, buf, dst); + } catch (ErrnoException | IOException e) { + mLog.e("Can't send packet " + packetTypeTag, e); + return false; + } + return true; + } + + private boolean addArpEntry(@NonNull MacAddress macAddr, @NonNull Inet4Address inetAddr) { + try { + mDeps.addArpEntry(inetAddr, macAddr, mIface.name, mSocket); + return true; + } catch (IOException e) { + mLog.e("Error adding client to ARP table", e); + return false; + } + } + + /** + * Get the remaining lease time in seconds, starting from {@link Clock#elapsedRealtime()}. + * + * <p>This is an unsigned 32-bit integer, so it cannot be read as a standard (signed) Java int. + * The return value is only intended to be used to populate the lease time field in a DHCP + * response, considering that lease time is an unsigned 32-bit integer field in DHCP packets. + * + * <p>Lease expiration times are tracked internally with millisecond precision: this method + * returns a rounded down value. + */ + private int getLeaseTimeout(@NonNull DhcpLease lease) { + final long remainingTimeSecs = (lease.getExpTime() - mClock.elapsedRealtime()) / 1000; + if (remainingTimeSecs < 0) { + mLog.e("Processing expired lease " + lease); + return EXPIRED_FALLBACK_LEASE_TIME_SECS; + } + + if (remainingTimeSecs >= toUnsignedLong(INFINITE_LEASE)) { + return INFINITE_LEASE; + } + + return (int) remainingTimeSecs; + } + + /** + * Get the client MAC address from a packet. + * + * @throws MalformedPacketException The address in the packet uses an unsupported format. + */ + @NonNull + private MacAddress getMacAddr(@NonNull DhcpPacket packet) throws MalformedPacketException { + try { + return MacAddress.fromBytes(packet.getClientMac()); + } catch (IllegalArgumentException e) { + final String message = "Invalid MAC address in packet: " + + HexDump.dumpHexString(packet.getClientMac()); + throw new MalformedPacketException(message, e); + } + } + + private static boolean isEmpty(@NonNull Inet4Address address) { + return address == null || Inet4Address.ANY.equals(address); + } + + private class PacketListener extends DhcpPacketListener { + public PacketListener() { + super(mHandler); + } + + @Override + protected void onReceive(DhcpPacket packet, Inet4Address srcAddr, int srcPort) { + processPacket(packet, srcPort); + } + + @Override + protected void logError(String msg, Exception e) { + mLog.e("Error receiving packet: " + msg, e); + } + + @Override + protected void logParseError(byte[] packet, int length, DhcpPacket.ParseException e) { + mLog.e("Error parsing packet", e); + } + + @Override + protected FileDescriptor createFd() { + // TODO: have and use an API to set a socket tag without going through the thread tag + final int oldTag = TrafficStats.getAndSetThreadStatsTag(TAG_SYSTEM_DHCP_SERVER); + try { + mSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + Os.setsockoptInt(mSocket, SOL_SOCKET, SO_REUSEADDR, 1); + // SO_BINDTODEVICE actually takes a string. This works because the first member + // of struct ifreq is a NULL-terminated interface name. + // TODO: add a setsockoptString() + Os.setsockoptIfreq(mSocket, SOL_SOCKET, SO_BINDTODEVICE, mIface.name); + Os.setsockoptInt(mSocket, SOL_SOCKET, SO_BROADCAST, 1); + Os.bind(mSocket, Inet4Address.ANY, DHCP_SERVER); + NetworkUtils.protectFromVpn(mSocket); + + return mSocket; + } catch (IOException | ErrnoException e) { + mLog.e("Error creating UDP socket", e); + DhcpServer.this.stop(); + return null; + } finally { + TrafficStats.setThreadStatsTag(oldTag); + } + } + } +} diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java index b77da28401d6..3cdef1e73ae4 100644 --- a/services/net/java/android/net/ip/IpClient.java +++ b/services/net/java/android/net/ip/IpClient.java @@ -431,6 +431,7 @@ public class IpClient extends StateMachine { public ProvisioningConfiguration(ProvisioningConfiguration other) { mEnableIPv4 = other.mEnableIPv4; mEnableIPv6 = other.mEnableIPv6; + mUsingMultinetworkPolicyTracker = other.mUsingMultinetworkPolicyTracker; mUsingIpReachabilityMonitor = other.mUsingIpReachabilityMonitor; mRequestedPreDhcpActionMs = other.mRequestedPreDhcpActionMs; mInitialConfig = InitialConfiguration.copy(other.mInitialConfig); diff --git a/services/net/java/android/net/util/FdEventsReader.java b/services/net/java/android/net/util/FdEventsReader.java index 575444f89bc3..8bbf449f6374 100644 --- a/services/net/java/android/net/util/FdEventsReader.java +++ b/services/net/java/android/net/util/FdEventsReader.java @@ -89,7 +89,7 @@ public abstract class FdEventsReader<BufferType> { mBuffer = buffer; } - public final void start() { + public void start() { if (onCorrectThread()) { createAndRegisterFd(); } else { @@ -100,7 +100,7 @@ public abstract class FdEventsReader<BufferType> { } } - public final void stop() { + public void stop() { if (onCorrectThread()) { unregisterAndDestroyFd(); } else { diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 97068a6c844a..0cf1aecb19fb 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -1994,18 +1994,25 @@ public class CarrierConfigManager { * the binding intent go to. * @hide */ - public static final String KEY_CARRIER_NETWORK_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING - = "carrier_network_service_wlan_package_override_string"; + public static final String KEY_CARRIER_NETWORK_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING = + "carrier_network_service_wlan_package_override_string"; /** * Decides when clients try to bind to wwan (cellular) network service, which package name will * the binding intent go to. * @hide */ - public static final String KEY_CARRIER_NETWORK_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING - = "carrier_network_service_wwan_package_override_string"; + public static final String KEY_CARRIER_NETWORK_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING = + "carrier_network_service_wwan_package_override_string"; /** + * The package name of qualified networks service that telephony binds to. + * + * @hide + */ + public static final String KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_PACKAGE_OVERRIDE_STRING = + "carrier_qualified_networks_service_package_override_string"; + /** * A list of 4 LTE RSCP thresholds above which a signal level is considered POOR, * MODERATE, GOOD, or EXCELLENT, to be used in SignalStrength reporting. * @@ -2094,6 +2101,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_CARRIER_USE_IMS_FIRST_FOR_EMERGENCY_BOOL, true); sDefaults.putString(KEY_CARRIER_NETWORK_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING, ""); sDefaults.putString(KEY_CARRIER_NETWORK_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING, ""); + sDefaults.putString(KEY_CARRIER_QUALIFIED_NETWORKS_SERVICE_PACKAGE_OVERRIDE_STRING, ""); sDefaults.putString(KEY_CARRIER_DATA_SERVICE_WWAN_PACKAGE_OVERRIDE_STRING, ""); sDefaults.putString(KEY_CARRIER_DATA_SERVICE_WLAN_PACKAGE_OVERRIDE_STRING, ""); sDefaults.putString(KEY_CARRIER_INSTANT_LETTERING_INVALID_CHARS_STRING, ""); diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 82e3a9df23d6..dab62f157e78 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -2843,9 +2843,11 @@ public class TelephonyManager { } /** - * Return if the current radio is LTE on CDMA. This - * is a tri-state return value as for a period of time - * the mode may be unknown. + * Return if the current radio is LTE on CDMA. This is a tri-state return value as for a period + * of time the mode may be unknown. + * + * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the + * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} * * @return {@link PhoneConstants#LTE_ON_CDMA_UNKNOWN}, {@link PhoneConstants#LTE_ON_CDMA_FALSE} * or {@link PhoneConstants#LTE_ON_CDMA_TRUE} @@ -5630,6 +5632,9 @@ public class TelephonyManager { /** * Sets the network selection mode to automatic. * + * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the + * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} + * * <p>Requires Permission: * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling * app has carrier privileges (see {@link #hasCarrierPrivileges}). @@ -5652,27 +5657,36 @@ public class TelephonyManager { /** * Perform a radio scan and return the list of available networks. * - * The return value is a list of the OperatorInfo of the networks found. Note that this - * scan can take a long time (sometimes minutes) to happen. + * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the + * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} + * + * <p> Note that this scan can take a long time (sometimes minutes) to happen. * * <p>Requires Permission: - * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling - * app has carrier privileges (see {@link #hasCarrierPrivileges}). + * {@link android.Manifest.permission#MODIFY_PHONE_STATE} or that the calling app has carrier + * privileges (see {@link #hasCarrierPrivileges}) + * + * @return {@link CellNetworkScanResult} with the status + * {@link CellNetworkScanResult#STATUS_SUCCESS} and a list of + * {@link com.android.internal.telephony.OperatorInfo} if it's available. Otherwise, the failure + * caused will be included in the result. * * @hide - * TODO: Add an overload that takes no args. */ - public CellNetworkScanResult getCellNetworkScanResults(int subId) { + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + public CellNetworkScanResult getAvailableNetworks() { try { ITelephony telephony = getITelephony(); - if (telephony != null) - return telephony.getCellNetworkScanResults(subId); + if (telephony != null) { + return telephony.getCellNetworkScanResults(getSubId()); + } } catch (RemoteException ex) { - Rlog.e(TAG, "getCellNetworkScanResults RemoteException", ex); + Rlog.e(TAG, "getAvailableNetworks RemoteException", ex); } catch (NullPointerException ex) { - Rlog.e(TAG, "getCellNetworkScanResults NPE", ex); + Rlog.e(TAG, "getAvailableNetworks NPE", ex); } - return null; + return new CellNetworkScanResult( + CellNetworkScanResult.STATUS_UNKNOWN_ERROR, null /* OperatorInfo */); } /** @@ -5722,6 +5736,9 @@ public class TelephonyManager { /** * Ask the radio to connect to the input network and change selection mode to manual. * + * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the + * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} + * * <p>Requires Permission: * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the calling * app has carrier privileges (see {@link #hasCarrierPrivileges}). @@ -7474,6 +7491,9 @@ public class TelephonyManager { /** * Returns the current {@link ServiceState} information. * + * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the + * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} + * * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}). */ @@ -7941,8 +7961,12 @@ public class TelephonyManager { } /** - * Check if phone is in emergency callback mode - * @return true if phone is in emergency callback mode + * Checks if phone is in emergency callback mode. + * + * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the + * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()} + * + * @return true if phone is in emergency callback mode. * @hide */ @SystemApi diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java index f646028b4eb3..0abe45ce448c 100644 --- a/telephony/java/com/android/internal/telephony/CallerInfo.java +++ b/telephony/java/com/android/internal/telephony/CallerInfo.java @@ -16,6 +16,7 @@ package com.android.internal.telephony; +import android.annotation.UnsupportedAppUsage; import android.content.ContentResolver; import android.content.Context; import android.database.Cursor; @@ -83,7 +84,9 @@ public class CallerInfo { * field here, NOT name. We're NOT always guaranteed to have a name * for a connection, but the number should be displayable. */ + @UnsupportedAppUsage public String name; + @UnsupportedAppUsage public String phoneNumber; public String normalizedNumber; public String geoDescription; @@ -95,12 +98,15 @@ public class CallerInfo { public String phoneLabel; /* Split up the phoneLabel into number type and label name */ + @UnsupportedAppUsage public int numberType; + @UnsupportedAppUsage public String numberLabel; public int photoResource; // Contact ID, which will be 0 if a contact comes from the corp CP2. + @UnsupportedAppUsage public long contactIdOrZero; public boolean needUpdate; public Uri contactRefUri; @@ -155,6 +161,7 @@ public class CallerInfo { private boolean mIsEmergency; private boolean mIsVoiceMail; + @UnsupportedAppUsage public CallerInfo() { // TODO: Move all the basic initialization here? mIsEmergency = false; @@ -300,6 +307,7 @@ public class CallerInfo { * @return the CallerInfo which contains the caller id for the given * number. The returned CallerInfo is null if no number is supplied. */ + @UnsupportedAppUsage public static CallerInfo getCallerInfo(Context context, Uri contactRef) { CallerInfo info = null; ContentResolver cr = CallerInfoAsyncQuery.getCurrentProfileContentResolver(context); @@ -324,6 +332,7 @@ public class CallerInfo { * a matching number is not found, then a generic caller info is returned, * with all relevant fields empty or null. */ + @UnsupportedAppUsage public static CallerInfo getCallerInfo(Context context, String number) { if (VDBG) Rlog.v(TAG, "getCallerInfo() based on number..."); @@ -342,6 +351,7 @@ public class CallerInfo { * a matching number is not found, then a generic caller info is returned, * with all relevant fields empty or null. */ + @UnsupportedAppUsage public static CallerInfo getCallerInfo(Context context, String number, int subId) { if (TextUtils.isEmpty(number)) { diff --git a/telephony/java/com/android/internal/telephony/EncodeException.java b/telephony/java/com/android/internal/telephony/EncodeException.java index 0436ba0a070b..4e3fac1a2aea 100644 --- a/telephony/java/com/android/internal/telephony/EncodeException.java +++ b/telephony/java/com/android/internal/telephony/EncodeException.java @@ -16,6 +16,8 @@ package com.android.internal.telephony; +import android.annotation.UnsupportedAppUsage; + /** * {@hide} */ @@ -24,10 +26,12 @@ public class EncodeException extends Exception { super(); } + @UnsupportedAppUsage public EncodeException(String s) { super(s); } + @UnsupportedAppUsage public EncodeException(char c) { super("Unencodable char: '" + c + "'"); } diff --git a/telephony/java/com/android/internal/telephony/GsmAlphabet.java b/telephony/java/com/android/internal/telephony/GsmAlphabet.java index 478516952c1a..69ff329e2d07 100644 --- a/telephony/java/com/android/internal/telephony/GsmAlphabet.java +++ b/telephony/java/com/android/internal/telephony/GsmAlphabet.java @@ -20,6 +20,7 @@ import android.content.res.Resources; import android.text.TextUtils; import android.util.SparseIntArray; +import android.annotation.UnsupportedAppUsage; import android.telephony.Rlog; import java.nio.ByteBuffer; @@ -84,6 +85,7 @@ public class GsmAlphabet { /** *The number of SMS's required to encode the text. */ + @UnsupportedAppUsage public int msgCount; /** @@ -92,28 +94,33 @@ public class GsmAlphabet { * septets for the standard ASCII and GSM encodings, and 16 * bits for Unicode. */ + @UnsupportedAppUsage public int codeUnitCount; /** * How many code units are still available without spilling * into an additional message. */ + @UnsupportedAppUsage public int codeUnitsRemaining; /** * The encoding code unit size (specified using * android.telephony.SmsMessage ENCODING_*). */ + @UnsupportedAppUsage public int codeUnitSize; /** * The GSM national language table to use, or 0 for the default 7-bit alphabet. */ + @UnsupportedAppUsage public int languageTable; /** * The GSM national language shift table to use, or 0 for the default 7-bit extension table. */ + @UnsupportedAppUsage public int languageShiftTable; @Override @@ -138,6 +145,7 @@ public class GsmAlphabet { * @param c the character to convert * @return the GSM 7 bit table index for the specified character */ + @UnsupportedAppUsage public static int charToGsm(char c) { try { @@ -160,6 +168,7 @@ public class GsmAlphabet { * @throws EncodeException encode error when throwException is true * @return the GSM 7 bit table index for the specified character */ + @UnsupportedAppUsage public static int charToGsm(char c, boolean throwException) throws EncodeException { int ret; @@ -215,6 +224,7 @@ public class GsmAlphabet { * @param gsmChar the GSM 7 bit table index to convert * @return the decoded character */ + @UnsupportedAppUsage public static char gsmToChar(int gsmChar) { if (gsmChar >= 0 && gsmChar < 128) { @@ -293,6 +303,7 @@ public class GsmAlphabet { * @return Byte array containing header and encoded data. * @throws EncodeException if String is too large to encode */ + @UnsupportedAppUsage public static byte[] stringToGsm7BitPackedWithHeader(String data, byte[] header, int languageTable, int languageShiftTable) throws EncodeException { @@ -327,6 +338,7 @@ public class GsmAlphabet { * @return the encoded string * @throws EncodeException if String is too large to encode */ + @UnsupportedAppUsage public static byte[] stringToGsm7BitPacked(String data) throws EncodeException { return stringToGsm7BitPacked(data, 0, true, 0, 0); @@ -377,6 +389,7 @@ public class GsmAlphabet { * * @throws EncodeException if String is too large to encode */ + @UnsupportedAppUsage public static byte[] stringToGsm7BitPacked(String data, int startingSeptetOffset, boolean throwException, int languageTable, int languageShiftTable) throws EncodeException { @@ -428,6 +441,7 @@ public class GsmAlphabet { * (septet index * 7) * @param value the 7-bit character to store */ + @UnsupportedAppUsage private static void packSmsChar(byte[] packedChars, int bitOffset, int value) { int byteOffset = bitOffset / 8; @@ -451,6 +465,7 @@ public class GsmAlphabet { * @param lengthSeptets string length in septets, not bytes * @return String representation or null on decoding exception */ + @UnsupportedAppUsage public static String gsm7BitPackedToString(byte[] pdu, int offset, int lengthSeptets) { return gsm7BitPackedToString(pdu, offset, lengthSeptets, 0, 0, 0); @@ -472,6 +487,7 @@ public class GsmAlphabet { * GSM extension table * @return String representation or null on decoding exception */ + @UnsupportedAppUsage public static String gsm7BitPackedToString(byte[] pdu, int offset, int lengthSeptets, int numPaddingBits, int languageTable, int shiftTable) { StringBuilder ret = new StringBuilder(lengthSeptets); @@ -555,6 +571,7 @@ public class GsmAlphabet { * @param length the number of bytes to decode * @return the decoded string */ + @UnsupportedAppUsage public static String gsm8BitUnpackedToString(byte[] data, int offset, int length) { return gsm8BitUnpackedToString(data, offset, length, ""); @@ -570,6 +587,7 @@ public class GsmAlphabet { * Additionally, in some country(ex. Korea), there are non-ASCII or MBCS characters. * If a character set is given, characters in data are treat as MBCS. */ + @UnsupportedAppUsage public static String gsm8BitUnpackedToString(byte[] data, int offset, int length, String characterset) { boolean isMbcs = false; @@ -649,6 +667,7 @@ public class GsmAlphabet { * @param s the string to encode * @return the 8-bit GSM encoded byte array for the string */ + @UnsupportedAppUsage public static byte[] stringToGsm8BitPacked(String s) { byte[] ret; @@ -736,6 +755,7 @@ public class GsmAlphabet { * @return the number of septets for this character * @throws EncodeException the character can't be encoded and throwsException is true */ + @UnsupportedAppUsage public static int countGsmSeptets(char c, boolean throwsException) throws EncodeException { if (sCharsToGsmTables[0].get(c, -1) != -1) { @@ -978,6 +998,7 @@ public class GsmAlphabet { * @return index of first character that won't fit, or the length * of the entire string if everything fits */ + @UnsupportedAppUsage public static int findGsmSeptetLimitIndex(String s, int start, int limit, int langTable, int langShiftTable) { int accumulator = 0; @@ -1076,18 +1097,23 @@ public class GsmAlphabet { } /** Reverse mapping from Unicode characters to indexes into language tables. */ + @UnsupportedAppUsage private static final SparseIntArray[] sCharsToGsmTables; /** Reverse mapping from Unicode characters to indexes into language shift tables. */ + @UnsupportedAppUsage private static final SparseIntArray[] sCharsToShiftTables; /** OEM configured list of enabled national language single shift tables for encoding. */ + @UnsupportedAppUsage private static int[] sEnabledSingleShiftTables; /** OEM configured list of enabled national language locking shift tables for encoding. */ + @UnsupportedAppUsage private static int[] sEnabledLockingShiftTables; /** Highest language code to include in array of single shift counters. */ + @UnsupportedAppUsage private static int sHighestEnabledSingleShiftCode; /** Flag to bypass check for country-specific overlays (for test cases only). */ @@ -1098,9 +1124,13 @@ public class GsmAlphabet { * the single shift tables that it can be paired with. */ private static class LanguagePairCount { + @UnsupportedAppUsage final int languageCode; + @UnsupportedAppUsage final int[] septetCounts; + @UnsupportedAppUsage final int[] unencodableCounts; + @UnsupportedAppUsage LanguagePairCount(int code) { this.languageCode = code; int maxSingleShiftCode = sHighestEnabledSingleShiftCode; @@ -1130,6 +1160,7 @@ public class GsmAlphabet { * GSM default 7 bit alphabet plus national language locking shift character tables. * Comment lines above strings indicate the lower four bits of the table position. */ + @UnsupportedAppUsage private static final String[] sLanguageTables = { /* 3GPP TS 23.038 V9.1.1 section 6.2.1 - GSM 7 bit Default Alphabet 01.....23.....4.....5.....6.....7.....8.....9.....A.B.....C.....D.E.....F.....0.....1 */ @@ -1323,6 +1354,7 @@ public class GsmAlphabet { /** * GSM default extension table plus national language single shift character tables. */ + @UnsupportedAppUsage private static final String[] sLanguageShiftTables = new String[]{ /* 6.2.1.1 GSM 7 bit Default Alphabet Extension Table 0123456789A.....BCDEF0123456789ABCDEF0123456789ABCDEF.0123456789ABCDEF0123456789ABCDEF */ diff --git a/telephony/java/com/android/internal/telephony/OperatorInfo.java b/telephony/java/com/android/internal/telephony/OperatorInfo.java index a29d7c161990..d0245a0a07b4 100644 --- a/telephony/java/com/android/internal/telephony/OperatorInfo.java +++ b/telephony/java/com/android/internal/telephony/OperatorInfo.java @@ -16,6 +16,7 @@ package com.android.internal.telephony; +import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -26,37 +27,48 @@ public class OperatorInfo implements Parcelable { public enum State { UNKNOWN, AVAILABLE, + @UnsupportedAppUsage CURRENT, + @UnsupportedAppUsage FORBIDDEN; } + @UnsupportedAppUsage private String mOperatorAlphaLong; + @UnsupportedAppUsage private String mOperatorAlphaShort; + @UnsupportedAppUsage private String mOperatorNumeric; + @UnsupportedAppUsage private State mState = State.UNKNOWN; + @UnsupportedAppUsage public String getOperatorAlphaLong() { return mOperatorAlphaLong; } + @UnsupportedAppUsage public String getOperatorAlphaShort() { return mOperatorAlphaShort; } + @UnsupportedAppUsage public String getOperatorNumeric() { return mOperatorNumeric; } + @UnsupportedAppUsage public State getState() { return mState; } + @UnsupportedAppUsage OperatorInfo(String operatorAlphaLong, String operatorAlphaShort, String operatorNumeric, @@ -70,6 +82,7 @@ public class OperatorInfo implements Parcelable { } + @UnsupportedAppUsage public OperatorInfo(String operatorAlphaLong, String operatorAlphaShort, String operatorNumeric, @@ -78,6 +91,7 @@ public class OperatorInfo implements Parcelable { operatorNumeric, rilStateToState(stateString)); } + @UnsupportedAppUsage public OperatorInfo(String operatorAlphaLong, String operatorAlphaShort, String operatorNumeric) { @@ -87,6 +101,7 @@ public class OperatorInfo implements Parcelable { /** * See state strings defined in ril.h RIL_REQUEST_QUERY_AVAILABLE_NETWORKS */ + @UnsupportedAppUsage private static State rilStateToState(String s) { if (s.equals("unknown")) { return State.UNKNOWN; @@ -140,6 +155,7 @@ public class OperatorInfo implements Parcelable { * Implement the Parcelable interface * Method to deserialize a OperatorInfo object, or an array thereof. */ + @UnsupportedAppUsage public static final Creator<OperatorInfo> CREATOR = new Creator<OperatorInfo>() { @Override diff --git a/telephony/java/com/android/internal/telephony/SmsAddress.java b/telephony/java/com/android/internal/telephony/SmsAddress.java index b3892cb0b342..2a8de8c8502e 100644 --- a/telephony/java/com/android/internal/telephony/SmsAddress.java +++ b/telephony/java/com/android/internal/telephony/SmsAddress.java @@ -16,6 +16,8 @@ package com.android.internal.telephony; +import android.annotation.UnsupportedAppUsage; + public abstract class SmsAddress { // From TS 23.040 9.1.2.5 and TS 24.008 table 10.5.118 // and C.S0005-D table 2.7.1.3.2.4-2 @@ -29,6 +31,7 @@ public abstract class SmsAddress { public int ton; public String address; + @UnsupportedAppUsage public byte[] origBytes; /** diff --git a/telephony/java/com/android/internal/telephony/SmsConstants.java b/telephony/java/com/android/internal/telephony/SmsConstants.java index 0aba468b5e1f..19f52b0ef429 100644 --- a/telephony/java/com/android/internal/telephony/SmsConstants.java +++ b/telephony/java/com/android/internal/telephony/SmsConstants.java @@ -15,6 +15,8 @@ */ package com.android.internal.telephony; +import android.annotation.UnsupportedAppUsage; + /** * SMS Constants and must be the same as the corresponding * deprecated version in SmsMessage. @@ -58,10 +60,15 @@ public class SmsConstants { * See TS 23.038. */ public enum MessageClass{ + @UnsupportedAppUsage UNKNOWN, + @UnsupportedAppUsage CLASS_0, + @UnsupportedAppUsage CLASS_1, + @UnsupportedAppUsage CLASS_2, + @UnsupportedAppUsage CLASS_3; } diff --git a/telephony/java/com/android/internal/telephony/SmsHeader.java b/telephony/java/com/android/internal/telephony/SmsHeader.java index b519b70088fb..9fe1718df6b6 100644 --- a/telephony/java/com/android/internal/telephony/SmsHeader.java +++ b/telephony/java/com/android/internal/telephony/SmsHeader.java @@ -22,6 +22,7 @@ import com.android.internal.util.HexDump; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import android.annotation.UnsupportedAppUsage; import java.util.ArrayList; /** @@ -72,14 +73,19 @@ public class SmsHeader { public static final int PORT_WAP_WSP = 9200; public static class PortAddrs { + @UnsupportedAppUsage public int destPort; + @UnsupportedAppUsage public int origPort; public boolean areEightBits; } public static class ConcatRef { + @UnsupportedAppUsage public int refNumber; + @UnsupportedAppUsage public int seqNumber; + @UnsupportedAppUsage public int msgCount; public boolean isEightBits; } @@ -98,17 +104,22 @@ public class SmsHeader { public byte[] data; } + @UnsupportedAppUsage public PortAddrs portAddrs; + @UnsupportedAppUsage public ConcatRef concatRef; public ArrayList<SpecialSmsMsg> specialSmsMsgList = new ArrayList<SpecialSmsMsg>(); public ArrayList<MiscElt> miscEltList = new ArrayList<MiscElt>(); /** 7 bit national language locking shift table, or 0 for GSM default 7 bit alphabet. */ + @UnsupportedAppUsage public int languageTable; /** 7 bit national language single shift table, or 0 for GSM default 7 bit extension table. */ + @UnsupportedAppUsage public int languageShiftTable; + @UnsupportedAppUsage public SmsHeader() {} /** @@ -117,6 +128,7 @@ public class SmsHeader { * @param data is user data header bytes * @return SmsHeader object */ + @UnsupportedAppUsage public static SmsHeader fromByteArray(byte[] data) { ByteArrayInputStream inStream = new ByteArrayInputStream(data); SmsHeader smsHeader = new SmsHeader(); @@ -198,6 +210,7 @@ public class SmsHeader { * (see TS 23.040 9.2.3.24) * @return Byte array representing the SmsHeader */ + @UnsupportedAppUsage public static byte[] toByteArray(SmsHeader smsHeader) { if ((smsHeader.portAddrs == null) && (smsHeader.concatRef == null) && diff --git a/telephony/java/com/android/internal/telephony/SmsMessageBase.java b/telephony/java/com/android/internal/telephony/SmsMessageBase.java index e5821dcd94a5..7b1ead9722b8 100644 --- a/telephony/java/com/android/internal/telephony/SmsMessageBase.java +++ b/telephony/java/com/android/internal/telephony/SmsMessageBase.java @@ -22,6 +22,7 @@ import com.android.internal.telephony.SmsHeader; import java.text.BreakIterator; import java.util.Arrays; +import android.annotation.UnsupportedAppUsage; import android.provider.Telephony; import android.telephony.SmsMessage; import android.text.Emoji; @@ -32,12 +33,15 @@ import android.text.Emoji; */ public abstract class SmsMessageBase { /** {@hide} The address of the SMSC. May be null */ + @UnsupportedAppUsage protected String mScAddress; /** {@hide} The address of the sender */ + @UnsupportedAppUsage protected SmsAddress mOriginatingAddress; /** {@hide} The message body as a string. May be null if the message isn't text */ + @UnsupportedAppUsage protected String mMessageBody; /** {@hide} */ @@ -56,23 +60,28 @@ public abstract class SmsMessageBase { protected long mScTimeMillis; /** {@hide} The raw PDU of the message */ + @UnsupportedAppUsage protected byte[] mPdu; /** {@hide} The raw bytes for the user data section of the message */ protected byte[] mUserData; /** {@hide} */ + @UnsupportedAppUsage protected SmsHeader mUserDataHeader; // "Message Waiting Indication Group" // 23.038 Section 4 /** {@hide} */ + @UnsupportedAppUsage protected boolean mIsMwi; /** {@hide} */ + @UnsupportedAppUsage protected boolean mMwiSense; /** {@hide} */ + @UnsupportedAppUsage protected boolean mMwiDontStore; /** @@ -86,11 +95,14 @@ public abstract class SmsMessageBase { protected int mIndexOnIcc = -1; /** TP-Message-Reference - Message Reference of sent message. @hide */ + @UnsupportedAppUsage public int mMessageRef; // TODO(): This class is duplicated in SmsMessage.java. Refactor accordingly. public static abstract class SubmitPduBase { + @UnsupportedAppUsage public byte[] encodedScAddress; // Null if not applicable. + @UnsupportedAppUsage public byte[] encodedMessage; @Override @@ -106,6 +118,7 @@ public abstract class SmsMessageBase { * Returns the address of the SMS service center that relayed this message * or null if there is none. */ + @UnsupportedAppUsage public String getServiceCenterAddress() { return mScAddress; } @@ -114,6 +127,7 @@ public abstract class SmsMessageBase { * Returns the originating address (sender) of this SMS message in String * form or null if unavailable */ + @UnsupportedAppUsage public String getOriginatingAddress() { if (mOriginatingAddress == null) { return null; @@ -127,6 +141,7 @@ public abstract class SmsMessageBase { * was from an email gateway. Returns null if originating address * unavailable. */ + @UnsupportedAppUsage public String getDisplayOriginatingAddress() { if (mIsEmail) { return mEmailFrom; @@ -139,6 +154,7 @@ public abstract class SmsMessageBase { * Returns the message body as a String, if it exists and is text based. * @return message body is there is one, otherwise null */ + @UnsupportedAppUsage public String getMessageBody() { return mMessageBody; } @@ -152,6 +168,7 @@ public abstract class SmsMessageBase { * Returns the message body, or email message body if this message was from * an email gateway. Returns null if message body unavailable. */ + @UnsupportedAppUsage public String getDisplayMessageBody() { if (mIsEmail) { return mEmailBody; @@ -164,6 +181,7 @@ public abstract class SmsMessageBase { * Unofficial convention of a subject line enclosed in parens empty string * if not present */ + @UnsupportedAppUsage public String getPseudoSubject() { return mPseudoSubject == null ? "" : mPseudoSubject; } @@ -171,6 +189,7 @@ public abstract class SmsMessageBase { /** * Returns the service centre timestamp in currentTimeMillis() format */ + @UnsupportedAppUsage public long getTimestampMillis() { return mScTimeMillis; } @@ -204,12 +223,14 @@ public abstract class SmsMessageBase { /** * Get protocol identifier. */ + @UnsupportedAppUsage public abstract int getProtocolIdentifier(); /** * See TS 23.040 9.2.3.9 returns true if this is a "replace short message" * SMS */ + @UnsupportedAppUsage public abstract boolean isReplace(); /** @@ -242,6 +263,7 @@ public abstract class SmsMessageBase { * returns the user data section minus the user data header if one was * present. */ + @UnsupportedAppUsage public byte[] getUserData() { return mUserData; } @@ -251,6 +273,7 @@ public abstract class SmsMessageBase { * * {@hide} */ + @UnsupportedAppUsage public SmsHeader getUserDataHeader() { return mUserDataHeader; } @@ -279,17 +302,20 @@ public abstract class SmsMessageBase { * See TS 23.040, 9.9.2.3.15 for a description of other possible * values. */ + @UnsupportedAppUsage public abstract int getStatus(); /** * Return true iff the message is a SMS-STATUS-REPORT message. */ + @UnsupportedAppUsage public abstract boolean isStatusReportMessage(); /** * Returns true iff the <code>TP-Reply-Path</code> bit is set in * this message. */ + @UnsupportedAppUsage public abstract boolean isReplyPathPresent(); /** diff --git a/telephony/java/com/android/internal/telephony/SmsRawData.java b/telephony/java/com/android/internal/telephony/SmsRawData.java index 891d942b9a13..18727f3a14fa 100644 --- a/telephony/java/com/android/internal/telephony/SmsRawData.java +++ b/telephony/java/com/android/internal/telephony/SmsRawData.java @@ -17,6 +17,7 @@ package com.android.internal.telephony; +import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -27,6 +28,7 @@ public class SmsRawData implements Parcelable { byte[] data; //Static Methods + @UnsupportedAppUsage public static final Parcelable.Creator<SmsRawData> CREATOR = new Parcelable.Creator<SmsRawData> (){ public SmsRawData createFromParcel(Parcel source) { @@ -43,10 +45,12 @@ public class SmsRawData implements Parcelable { }; // Constructor + @UnsupportedAppUsage public SmsRawData(byte[] data) { this.data = data; } + @UnsupportedAppUsage public byte[] getBytes() { return data; } diff --git a/tests/net/java/android/net/dhcp/DhcpLeaseRepositoryTest.java b/tests/net/java/android/net/dhcp/DhcpLeaseRepositoryTest.java index edadd6ead667..590bd6733c9f 100644 --- a/tests/net/java/android/net/dhcp/DhcpLeaseRepositoryTest.java +++ b/tests/net/java/android/net/dhcp/DhcpLeaseRepositoryTest.java @@ -34,8 +34,8 @@ import static java.net.InetAddress.parseNumericAddress; import android.annotation.NonNull; import android.net.IpPrefix; import android.net.MacAddress; -import android.net.dhcp.DhcpLeaseRepository.Clock; import android.net.util.SharedLog; +import android.net.dhcp.DhcpServer.Clock; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; diff --git a/tests/net/java/android/net/dhcp/DhcpServerTest.java b/tests/net/java/android/net/dhcp/DhcpServerTest.java new file mode 100644 index 000000000000..66db5a8ddc50 --- /dev/null +++ b/tests/net/java/android/net/dhcp/DhcpServerTest.java @@ -0,0 +1,314 @@ +/* + * 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.dhcp; + +import static android.net.dhcp.DhcpPacket.DHCP_CLIENT; +import static android.net.dhcp.DhcpPacket.ENCAP_BOOTP; +import static android.net.dhcp.DhcpPacket.INADDR_ANY; +import static android.net.dhcp.DhcpPacket.INADDR_BROADCAST; + +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertNull; +import static junit.framework.Assert.assertTrue; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import static java.net.InetAddress.parseNumericAddress; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.LinkAddress; +import android.net.MacAddress; +import android.net.dhcp.DhcpLeaseRepository.InvalidAddressException; +import android.net.dhcp.DhcpLeaseRepository.OutOfAddressesException; +import android.net.dhcp.DhcpServer.Clock; +import android.net.dhcp.DhcpServer.Dependencies; +import android.net.util.InterfaceParams; +import android.net.util.SharedLog; +import android.os.test.TestLooper; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.net.Inet4Address; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class DhcpServerTest { + private static final String PROP_DEXMAKER_SHARE_CLASSLOADER = "dexmaker.share_classloader"; + private static final String TEST_IFACE = "testiface"; + private static final MacAddress TEST_IFACE_MAC = MacAddress.fromString("11:22:33:44:55:66"); + private static final InterfaceParams TEST_IFACEPARAMS = + new InterfaceParams(TEST_IFACE, 1, TEST_IFACE_MAC); + + private static final Inet4Address TEST_SERVER_ADDR = parseAddr("192.168.0.2"); + private static final LinkAddress TEST_SERVER_LINKADDR = new LinkAddress(TEST_SERVER_ADDR, 20); + private static final Set<Inet4Address> TEST_DEFAULT_ROUTERS = new HashSet<>( + Arrays.asList(parseAddr("192.168.0.123"), parseAddr("192.168.0.124"))); + private static final Set<Inet4Address> TEST_DNS_SERVERS = new HashSet<>( + Arrays.asList(parseAddr("192.168.0.126"), parseAddr("192.168.0.127"))); + private static final Set<Inet4Address> TEST_EXCLUDED_ADDRS = new HashSet<>( + Arrays.asList(parseAddr("192.168.0.200"), parseAddr("192.168.0.201"))); + private static final long TEST_LEASE_TIME_SECS = 3600L; + private static final int TEST_MTU = 1500; + + private static final int TEST_TRANSACTION_ID = 123; + private static final byte[] TEST_CLIENT_MAC_BYTES = new byte [] { 1, 2, 3, 4, 5, 6 }; + private static final MacAddress TEST_CLIENT_MAC = MacAddress.fromBytes(TEST_CLIENT_MAC_BYTES); + private static final Inet4Address TEST_CLIENT_ADDR = parseAddr("192.168.0.42"); + + private static final long TEST_CLOCK_TIME = 1234L; + private static final int TEST_LEASE_EXPTIME_SECS = 3600; + private static final DhcpLease TEST_LEASE = new DhcpLease(null, TEST_CLIENT_MAC, + TEST_CLIENT_ADDR, TEST_LEASE_EXPTIME_SECS*1000L + TEST_CLOCK_TIME, null /* hostname */); + + @NonNull @Mock + private Dependencies mDeps; + @NonNull @Mock + private DhcpLeaseRepository mRepository; + @NonNull @Mock + private Clock mClock; + @NonNull @Mock + private DhcpPacketListener mPacketListener; + + @NonNull @Captor + private ArgumentCaptor<ByteBuffer> mSentPacketCaptor; + @NonNull @Captor + private ArgumentCaptor<Inet4Address> mResponseDstAddrCaptor; + + @NonNull + private TestLooper mLooper; + @NonNull + private DhcpServer mServer; + + @Nullable + private String mPrevShareClassloaderProp; + + @Before + public void setUp() throws Exception { + // Allow mocking package-private classes + mPrevShareClassloaderProp = System.getProperty(PROP_DEXMAKER_SHARE_CLASSLOADER); + System.setProperty(PROP_DEXMAKER_SHARE_CLASSLOADER, "true"); + MockitoAnnotations.initMocks(this); + + when(mDeps.makeLeaseRepository(any(), any(), any())).thenReturn(mRepository); + when(mDeps.makeClock()).thenReturn(mClock); + when(mDeps.makePacketListener()).thenReturn(mPacketListener); + doNothing().when(mDeps) + .sendPacket(any(), mSentPacketCaptor.capture(), mResponseDstAddrCaptor.capture()); + when(mClock.elapsedRealtime()).thenReturn(TEST_CLOCK_TIME); + + final DhcpServingParams servingParams = new DhcpServingParams.Builder() + .setDefaultRouters(TEST_DEFAULT_ROUTERS) + .setDhcpLeaseTimeSecs(TEST_LEASE_TIME_SECS) + .setDnsServers(TEST_DNS_SERVERS) + .setServerAddr(TEST_SERVER_LINKADDR) + .setLinkMtu(TEST_MTU) + .setExcludedAddrs(TEST_EXCLUDED_ADDRS) + .build(); + + mLooper = new TestLooper(); + mServer = new DhcpServer(mLooper.getLooper(), TEST_IFACEPARAMS, servingParams, + new SharedLog(DhcpServerTest.class.getSimpleName()), mDeps); + + mServer.start(); + mLooper.dispatchAll(); + } + + @After + public void tearDown() { + // Calling stop() several times is not an issue + mServer.stop(); + System.setProperty(PROP_DEXMAKER_SHARE_CLASSLOADER, + (mPrevShareClassloaderProp == null ? "" : mPrevShareClassloaderProp)); + } + + @Test + public void testStart() throws Exception { + verify(mPacketListener, times(1)).start(); + } + + @Test + public void testStop() throws Exception { + mServer.stop(); + mLooper.dispatchAll(); + verify(mPacketListener, times(1)).stop(); + } + + @Test + public void testDiscover() throws Exception { + // TODO: refactor packet construction to eliminate unnecessary/confusing/duplicate fields + when(mRepository.getOffer(isNull() /* clientId */, eq(TEST_CLIENT_MAC), + eq(INADDR_ANY) /* relayAddr */, isNull() /* reqAddr */, isNull() /* hostname */)) + .thenReturn(TEST_LEASE); + + final DhcpDiscoverPacket discover = new DhcpDiscoverPacket(TEST_TRANSACTION_ID, + (short) 0 /* secs */, INADDR_ANY /* relayIp */, TEST_CLIENT_MAC_BYTES, + false /* broadcast */, INADDR_ANY /* srcIp */); + mServer.processPacket(discover, DHCP_CLIENT); + + assertResponseSentTo(TEST_CLIENT_ADDR); + final DhcpOfferPacket packet = assertOffer(getPacket()); + assertMatchesTestLease(packet); + } + + @Test + public void testDiscover_OutOfAddresses() throws Exception { + when(mRepository.getOffer(isNull() /* clientId */, eq(TEST_CLIENT_MAC), + eq(INADDR_ANY) /* relayAddr */, isNull() /* reqAddr */, isNull() /* hostname */)) + .thenThrow(new OutOfAddressesException("Test exception")); + + final DhcpDiscoverPacket discover = new DhcpDiscoverPacket(TEST_TRANSACTION_ID, + (short) 0 /* secs */, INADDR_ANY /* relayIp */, TEST_CLIENT_MAC_BYTES, + false /* broadcast */, INADDR_ANY /* srcIp */); + mServer.processPacket(discover, DHCP_CLIENT); + + assertResponseSentTo(INADDR_BROADCAST); + final DhcpNakPacket packet = assertNak(getPacket()); + assertMatchesClient(packet); + } + + private DhcpRequestPacket makeRequestSelectingPacket() { + final DhcpRequestPacket request = new DhcpRequestPacket(TEST_TRANSACTION_ID, + (short) 0 /* secs */, INADDR_ANY /* clientIp */, INADDR_ANY /* relayIp */, + TEST_CLIENT_MAC_BYTES, false /* broadcast */); + request.mServerIdentifier = TEST_SERVER_ADDR; + request.mRequestedIp = TEST_CLIENT_ADDR; + return request; + } + + @Test + public void testRequest_Selecting_Ack() throws Exception { + when(mRepository.requestLease(isNull() /* clientId */, eq(TEST_CLIENT_MAC), + eq(INADDR_ANY) /* clientAddr */, eq(TEST_CLIENT_ADDR) /* reqAddr */, + eq(true) /* sidSet */, isNull() /* hostname */)) + .thenReturn(TEST_LEASE); + + final DhcpRequestPacket request = makeRequestSelectingPacket(); + mServer.processPacket(request, DHCP_CLIENT); + + assertResponseSentTo(TEST_CLIENT_ADDR); + final DhcpAckPacket packet = assertAck(getPacket()); + assertMatchesTestLease(packet); + } + + @Test + public void testRequest_Selecting_Nak() throws Exception { + when(mRepository.requestLease(isNull(), eq(TEST_CLIENT_MAC), + eq(INADDR_ANY) /* clientAddr */, eq(TEST_CLIENT_ADDR) /* reqAddr */, + eq(true) /* sidSet */, isNull() /* hostname */)) + .thenThrow(new InvalidAddressException("Test error")); + + final DhcpRequestPacket request = makeRequestSelectingPacket(); + mServer.processPacket(request, DHCP_CLIENT); + + assertResponseSentTo(INADDR_BROADCAST); + final DhcpNakPacket packet = assertNak(getPacket()); + assertMatchesClient(packet); + } + + @Test + public void testRequest_Selecting_WrongClientPort() throws Exception { + final DhcpRequestPacket request = makeRequestSelectingPacket(); + mServer.processPacket(request, 50000); + + verify(mRepository, never()).requestLease(any(), any(), any(), any(), anyBoolean(), any()); + verify(mDeps, never()).sendPacket(any(), any(), any()); + } + + @Test + public void testRelease() throws Exception { + final DhcpReleasePacket release = new DhcpReleasePacket(TEST_TRANSACTION_ID, + TEST_SERVER_ADDR, TEST_CLIENT_ADDR, + INADDR_ANY /* relayIp */, TEST_CLIENT_MAC_BYTES); + mServer.processPacket(release, DHCP_CLIENT); + + verify(mRepository, times(1)) + .releaseLease(isNull(), eq(TEST_CLIENT_MAC), eq(TEST_CLIENT_ADDR)); + } + + /* TODO: add more tests once packet construction is refactored, including: + * - usage of giaddr + * - usage of broadcast bit + * - other request states (init-reboot/renewing/rebinding) + */ + + private void assertMatchesTestLease(@NonNull DhcpPacket packet) { + assertMatchesClient(packet); + assertFalse(packet.hasExplicitClientId()); + assertEquals(TEST_SERVER_ADDR, packet.mServerIdentifier); + assertEquals(TEST_CLIENT_ADDR, packet.mYourIp); + assertNotNull(packet.mLeaseTime); + assertEquals(TEST_LEASE_EXPTIME_SECS, (int) packet.mLeaseTime); + assertNull(packet.mHostName); + } + + private void assertMatchesClient(@NonNull DhcpPacket packet) { + assertEquals(TEST_TRANSACTION_ID, packet.mTransId); + assertEquals(TEST_CLIENT_MAC, MacAddress.fromBytes(packet.mClientMac)); + } + + private void assertResponseSentTo(@NonNull Inet4Address addr) { + assertEquals(addr, mResponseDstAddrCaptor.getValue()); + } + + private static DhcpNakPacket assertNak(@Nullable DhcpPacket packet) { + assertTrue(packet instanceof DhcpNakPacket); + return (DhcpNakPacket) packet; + } + + private static DhcpAckPacket assertAck(@Nullable DhcpPacket packet) { + assertTrue(packet instanceof DhcpAckPacket); + return (DhcpAckPacket) packet; + } + + private static DhcpOfferPacket assertOffer(@Nullable DhcpPacket packet) { + assertTrue(packet instanceof DhcpOfferPacket); + return (DhcpOfferPacket) packet; + } + + private DhcpPacket getPacket() throws Exception { + verify(mDeps, times(1)).sendPacket(any(), any(), any()); + return DhcpPacket.decodeFullPacket(mSentPacketCaptor.getValue(), ENCAP_BOOTP); + } + + private static Inet4Address parseAddr(@Nullable String inet4Addr) { + return (Inet4Address) parseNumericAddress(inet4Addr); + } +} diff --git a/tests/net/java/com/android/server/connectivity/NetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/NetworkMonitorTest.java index b01713006254..b399b0d51577 100644 --- a/tests/net/java/com/android/server/connectivity/NetworkMonitorTest.java +++ b/tests/net/java/com/android/server/connectivity/NetworkMonitorTest.java @@ -106,6 +106,7 @@ public class NetworkMonitorTest { anyString())).thenReturn(TEST_HTTP_URL); when(mDependencies.getSetting(any(), eq(Settings.Global.CAPTIVE_PORTAL_HTTPS_URL), anyString())).thenReturn(TEST_HTTPS_URL); + when(mNetwork.getPrivateDnsBypassingCopy()).thenReturn(mNetwork); when(mContext.getSystemService(Context.TELEPHONY_SERVICE)).thenReturn(mTelephony); when(mContext.getSystemService(Context.WIFI_SERVICE)).thenReturn(mWifi); diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java index 1e03891019f6..e37a85670972 100644 --- a/wifi/java/android/net/wifi/WifiInfo.java +++ b/wifi/java/android/net/wifi/WifiInfo.java @@ -17,14 +17,14 @@ package android.net.wifi; import android.annotation.UnsupportedAppUsage; -import android.os.Parcelable; -import android.os.Parcel; import android.net.NetworkInfo.DetailedState; import android.net.NetworkUtils; +import android.os.Parcel; +import android.os.Parcelable; import android.text.TextUtils; -import java.net.InetAddress; import java.net.Inet4Address; +import java.net.InetAddress; import java.net.UnknownHostException; import java.util.EnumMap; import java.util.Locale; @@ -540,9 +540,13 @@ public class WifiInfo implements Parcelable { dest.writeInt(mMeteredHint ? 1 : 0); dest.writeInt(mEphemeral ? 1 : 0); dest.writeInt(score); + dest.writeLong(txSuccess); dest.writeDouble(txSuccessRate); + dest.writeLong(txRetries); dest.writeDouble(txRetriesRate); + dest.writeLong(txBad); dest.writeDouble(txBadRate); + dest.writeLong(rxSuccess); dest.writeDouble(rxSuccessRate); mSupplicantState.writeToParcel(dest, flags); } @@ -570,9 +574,13 @@ public class WifiInfo implements Parcelable { info.mMeteredHint = in.readInt() != 0; info.mEphemeral = in.readInt() != 0; info.score = in.readInt(); + info.txSuccess = in.readLong(); info.txSuccessRate = in.readDouble(); + info.txRetries = in.readLong(); info.txRetriesRate = in.readDouble(); + info.txBad = in.readLong(); info.txBadRate = in.readDouble(); + info.rxSuccess = in.readLong(); info.rxSuccessRate = in.readDouble(); info.mSupplicantState = SupplicantState.CREATOR.createFromParcel(in); return info; diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index b56a7581e5fd..7a91347102fe 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -981,6 +981,7 @@ public class WifiManager { private AsyncChannel mAsyncChannel; private CountDownLatch mConnected; private Looper mLooper; + private boolean mVerboseLoggingEnabled = false; /* LocalOnlyHotspot callback message types */ /** @hide */ @@ -1013,6 +1014,7 @@ public class WifiManager { mService = service; mLooper = looper; mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion; + updateVerboseLoggingEnabledFromService(); } /** @@ -2475,7 +2477,7 @@ public class WifiManager { * * @hide */ - private static class SoftApCallbackProxy extends ISoftApCallback.Stub { + private class SoftApCallbackProxy extends ISoftApCallback.Stub { private final Handler mHandler; private final SoftApCallback mCallback; @@ -2486,8 +2488,10 @@ public class WifiManager { @Override public void onStateChanged(int state, int failureReason) { - Log.v(TAG, "SoftApCallbackProxy: onStateChanged: state=" + state + ", failureReason=" + - failureReason); + if (mVerboseLoggingEnabled) { + Log.v(TAG, "SoftApCallbackProxy: onStateChanged: state=" + state + + ", failureReason=" + failureReason); + } mHandler.post(() -> { mCallback.onStateChanged(state, failureReason); }); @@ -2495,7 +2499,9 @@ public class WifiManager { @Override public void onNumClientsChanged(int numClients) { - Log.v(TAG, "SoftApCallbackProxy: onNumClientsChanged: numClients=" + numClients); + if (mVerboseLoggingEnabled) { + Log.v(TAG, "SoftApCallbackProxy: onNumClientsChanged: numClients=" + numClients); + } mHandler.post(() -> { mCallback.onNumClientsChanged(numClients); }); @@ -3786,7 +3792,7 @@ public class WifiManager { * * @hide */ - private static class TrafficStateCallbackProxy extends ITrafficStateCallback.Stub { + private class TrafficStateCallbackProxy extends ITrafficStateCallback.Stub { private final Handler mHandler; private final TrafficStateCallback mCallback; @@ -3797,7 +3803,9 @@ public class WifiManager { @Override public void onStateChanged(int state) { - Log.v(TAG, "TrafficStateCallbackProxy: onStateChanged state=" + state); + if (mVerboseLoggingEnabled) { + Log.v(TAG, "TrafficStateCallbackProxy: onStateChanged state=" + state); + } mHandler.post(() -> { mCallback.onStateChanged(state); }); @@ -3854,4 +3862,12 @@ public class WifiManager { throw e.rethrowFromSystemServer(); } } + + /** + * Helper method to update the local verbose logging flag based on the verbose logging + * level from wifi service. + */ + private void updateVerboseLoggingEnabledFromService() { + mVerboseLoggingEnabled = getVerboseLoggingLevel() > 0; + } } diff --git a/wifi/tests/src/android/net/wifi/WifiInfoTest.java b/wifi/tests/src/android/net/wifi/WifiInfoTest.java new file mode 100644 index 000000000000..f5a8b29167bf --- /dev/null +++ b/wifi/tests/src/android/net/wifi/WifiInfoTest.java @@ -0,0 +1,60 @@ +/* + * 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.wifi; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import android.os.Parcel; +import android.support.test.filters.SmallTest; + +import org.junit.Test; + +/** + * Unit tests for {@link android.net.wifi.WifiInfo}. + */ +@SmallTest +public class WifiInfoTest { + private static final long TEST_TX_SUCCESS = 1; + private static final long TEST_TX_RETRIES = 2; + private static final long TEST_TX_BAD = 3; + private static final long TEST_RX_SUCCESS = 4; + + /** + * Verify parcel write/read with WifiInfo. + */ + @Test + public void testWifiInfoParcelWriteRead() throws Exception { + WifiInfo writeWifiInfo = new WifiInfo(); + writeWifiInfo.txSuccess = TEST_TX_SUCCESS; + writeWifiInfo.txRetries = TEST_TX_RETRIES; + writeWifiInfo.txBad = TEST_TX_BAD; + writeWifiInfo.rxSuccess = TEST_RX_SUCCESS; + + Parcel parcel = Parcel.obtain(); + writeWifiInfo.writeToParcel(parcel, 0); + // Rewind the pointer to the head of the parcel. + parcel.setDataPosition(0); + WifiInfo readWifiInfo = WifiInfo.CREATOR.createFromParcel(parcel); + + assertNotNull(readWifiInfo); + assertEquals(TEST_TX_SUCCESS, readWifiInfo.txSuccess); + assertEquals(TEST_TX_RETRIES, readWifiInfo.txRetries); + assertEquals(TEST_TX_BAD, readWifiInfo.txBad); + assertEquals(TEST_RX_SUCCESS, readWifiInfo.rxSuccess); + } +} diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java index 50580800c271..e40b657aded0 100644 --- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java +++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java @@ -93,6 +93,7 @@ public class WifiManagerTest { mWifiServiceMessenger = new Messenger(mHandler); mWifiManager = new WifiManager(mContext, mWifiService, mLooper.getLooper()); + verify(mWifiService).getVerboseLoggingLevel(); } /** |