Merge "Merge Android Pie into master"

This commit is contained in:
Xin Li
2018-08-07 16:51:24 +00:00
committed by Gerrit Code Review
8098 changed files with 712634 additions and 250954 deletions

View File

@@ -64,6 +64,7 @@ java_library {
"core/java/android/app/IAlarmManager.aidl",
"core/java/android/app/IAppTask.aidl",
"core/java/android/app/IApplicationThread.aidl",
"core/java/android/app/IAssistDataReceiver.aidl",
"core/java/android/app/ITaskStackListener.aidl",
"core/java/android/app/IBackupAgent.aidl",
"core/java/android/app/IEphemeralResolver.aidl",
@@ -98,6 +99,8 @@ java_library {
"core/java/android/app/backup/IRestoreObserver.aidl",
"core/java/android/app/backup/IRestoreSession.aidl",
"core/java/android/app/backup/ISelectBackupTransportCallback.aidl",
"core/java/android/app/slice/ISliceManager.aidl",
"core/java/android/app/slice/ISliceListener.aidl",
"core/java/android/app/timedetector/ITimeDetectorService.aidl",
"core/java/android/app/timezone/ICallback.aidl",
"core/java/android/app/timezone/IRulesManager.aidl",
@@ -113,10 +116,12 @@ java_library {
"core/java/android/content/IOnPrimaryClipChangedListener.aidl",
"core/java/android/content/IRestrictionsManager.aidl",
"core/java/android/content/ISyncAdapter.aidl",
"core/java/android/content/ISyncAdapterUnsyncableAccountCallback.aidl",
"core/java/android/content/ISyncContext.aidl",
"core/java/android/content/ISyncServiceAdapter.aidl",
"core/java/android/content/ISyncStatusObserver.aidl",
"core/java/android/content/om/IOverlayManager.aidl",
"core/java/android/content/pm/ICrossProfileApps.aidl",
"core/java/android/content/pm/IDexModuleRegisterCallback.aidl",
"core/java/android/content/pm/ILauncherApps.aidl",
"core/java/android/content/pm/IOnAppsChangedListener.aidl",
@@ -125,7 +130,6 @@ java_library {
"core/java/android/content/pm/IPackageDataObserver.aidl",
"core/java/android/content/pm/IPackageDeleteObserver.aidl",
"core/java/android/content/pm/IPackageDeleteObserver2.aidl",
"core/java/android/content/pm/IPackageInstallObserver.aidl",
"core/java/android/content/pm/IPackageInstallObserver2.aidl",
"core/java/android/content/pm/IPackageInstaller.aidl",
"core/java/android/content/pm/IPackageInstallerCallback.aidl",
@@ -144,12 +148,13 @@ java_library {
":libcamera_client_framework_aidl",
"core/java/android/hardware/IConsumerIrService.aidl",
"core/java/android/hardware/ISerialManager.aidl",
"core/java/android/hardware/biometrics/IBiometricPromptReceiver.aidl",
"core/java/android/hardware/display/IDisplayManager.aidl",
"core/java/android/hardware/display/IDisplayManagerCallback.aidl",
"core/java/android/hardware/display/IVirtualDisplayCallback.aidl",
"core/java/android/hardware/fingerprint/IFingerprintClientActiveCallback.aidl",
"core/java/android/hardware/fingerprint/IFingerprintService.aidl",
"core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl",
"core/java/android/hardware/fingerprint/IFingerprintClientActiveCallback.aidl",
"core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl",
"core/java/android/hardware/hdmi/IHdmiControlCallback.aidl",
"core/java/android/hardware/hdmi/IHdmiControlService.aidl",
@@ -171,7 +176,12 @@ java_library {
"core/java/android/hardware/location/IGeofenceHardwareCallback.aidl",
"core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl",
"core/java/android/hardware/location/IContextHubCallback.aidl",
"core/java/android/hardware/location/IContextHubClient.aidl",
"core/java/android/hardware/location/IContextHubClientCallback.aidl",
"core/java/android/hardware/location/IContextHubService.aidl",
"core/java/android/hardware/location/IContextHubTransactionCallback.aidl",
"core/java/android/hardware/radio/IAnnouncementListener.aidl",
"core/java/android/hardware/radio/ICloseHandle.aidl",
"core/java/android/hardware/radio/IRadioService.aidl",
"core/java/android/hardware/radio/ITuner.aidl",
"core/java/android/hardware/radio/ITunerCallback.aidl",
@@ -208,14 +218,12 @@ java_library {
"core/java/android/se/omapi/ISecureElementChannel.aidl",
"core/java/android/se/omapi/ISecureElementReader.aidl",
"core/java/android/se/omapi/ISecureElementSession.aidl",
"core/java/android/os/IBatteryPropertiesListener.aidl",
"core/java/android/os/IBatteryPropertiesRegistrar.aidl",
"core/java/android/os/ICancellationSignal.aidl",
"core/java/android/os/IDeviceIdentifiersPolicyService.aidl",
"core/java/android/os/IDeviceIdleController.aidl",
"core/java/android/os/IHardwarePropertiesManager.aidl",
"core/java/android/os/IIncidentManager.aidl",
"core/java/android/os/IIncidentReportCompletedListener.aidl",
"core/java/android/os/IIncidentReportStatusListener.aidl",
"core/java/android/os/IMaintenanceActivityListener.aidl",
"core/java/android/os/IMessenger.aidl",
@@ -229,6 +237,9 @@ java_library {
"core/java/android/os/IRecoverySystemProgressListener.aidl",
"core/java/android/os/IRemoteCallback.aidl",
"core/java/android/os/ISchedulingPolicyService.aidl",
"core/java/android/os/IStatsCompanionService.aidl",
"core/java/android/os/IStatsManager.aidl",
"core/java/android/os/ISystemUpdateManager.aidl",
"core/java/android/os/IThermalEventListener.aidl",
"core/java/android/os/IThermalService.aidl",
"core/java/android/os/IUpdateLock.aidl",
@@ -238,9 +249,10 @@ java_library {
"core/java/android/os/storage/IStorageEventListener.aidl",
"core/java/android/os/storage/IStorageShutdownObserver.aidl",
"core/java/android/os/storage/IObbActionListener.aidl",
"core/java/android/security/IKeystoreService.aidl",
":keystore_aidl",
"core/java/android/security/keymaster/IKeyAttestationApplicationIdProvider.aidl",
"core/java/android/service/autofill/IAutoFillService.aidl",
"core/java/android/service/autofill/IAutofillFieldClassificationService.aidl",
"core/java/android/service/autofill/IFillCallback.aidl",
"core/java/android/service/autofill/ISaveCallback.aidl",
"core/java/android/service/carrier/ICarrierService.aidl",
@@ -265,6 +277,7 @@ java_library {
"core/java/android/service/notification/IStatusBarNotificationHolder.aidl",
"core/java/android/service/notification/IConditionListener.aidl",
"core/java/android/service/notification/IConditionProvider.aidl",
"core/java/android/service/settings/suggestions/ISuggestionService.aidl",
"core/java/android/service/vr/IPersistentVrStateCallbacks.aidl",
"core/java/android/service/vr/IVrListener.aidl",
"core/java/android/service/vr/IVrManager.aidl",
@@ -305,6 +318,10 @@ java_library {
"core/java/android/service/chooser/IChooserTargetResult.aidl",
"core/java/android/service/resolver/IResolverRankerService.aidl",
"core/java/android/service/resolver/IResolverRankerResult.aidl",
"core/java/android/service/textclassifier/ITextClassificationCallback.aidl",
"core/java/android/service/textclassifier/ITextClassifierService.aidl",
"core/java/android/service/textclassifier/ITextLinksCallback.aidl",
"core/java/android/service/textclassifier/ITextSelectionCallback.aidl",
"core/java/android/view/accessibility/IAccessibilityInteractionConnection.aidl",
"core/java/android/view/accessibility/IAccessibilityInteractionConnectionCallback.aidl",
"core/java/android/view/accessibility/IAccessibilityManager.aidl",
@@ -322,6 +339,10 @@ java_library {
"core/java/android/view/IOnKeyguardExitResult.aidl",
"core/java/android/view/IPinnedStackController.aidl",
"core/java/android/view/IPinnedStackListener.aidl",
"core/java/android/view/IRemoteAnimationRunner.aidl",
"core/java/android/view/IRecentsAnimationController.aidl",
"core/java/android/view/IRecentsAnimationRunner.aidl",
"core/java/android/view/IRemoteAnimationFinishedCallback.aidl",
"core/java/android/view/IRotationWatcher.aidl",
"core/java/android/view/IWallpaperVisibilityListener.aidl",
"core/java/android/view/IWindow.aidl",
@@ -335,9 +356,9 @@ java_library {
"core/java/android/speech/IRecognitionService.aidl",
"core/java/android/speech/tts/ITextToSpeechCallback.aidl",
"core/java/android/speech/tts/ITextToSpeechService.aidl",
"core/java/com/android/internal/app/IAppOpsActiveCallback.aidl",
"core/java/com/android/internal/app/IAppOpsCallback.aidl",
"core/java/com/android/internal/app/IAppOpsService.aidl",
"core/java/com/android/internal/app/IAssistScreenshotReceiver.aidl",
"core/java/com/android/internal/app/IBatteryStats.aidl",
"core/java/com/android/internal/app/ISoundTriggerService.aidl",
"core/java/com/android/internal/app/IVoiceInteractionManagerService.aidl",
@@ -352,8 +373,8 @@ java_library {
"core/java/com/android/internal/appwidget/IAppWidgetHost.aidl",
"core/java/com/android/internal/backup/IBackupTransport.aidl",
"core/java/com/android/internal/backup/IObbBackupService.aidl",
"core/java/com/android/internal/car/ICarServiceHelper.aidl",
"core/java/com/android/internal/inputmethod/IInputContentUriToken.aidl",
"core/java/com/android/internal/net/INetworkWatchlistManager.aidl",
"core/java/com/android/internal/policy/IKeyguardDrawnCallback.aidl",
"core/java/com/android/internal/policy/IKeyguardDismissCallback.aidl",
"core/java/com/android/internal/policy/IKeyguardExitCallback.aidl",
@@ -383,7 +404,6 @@ java_library {
"core/java/com/android/internal/widget/ICheckCredentialProgressCallback.aidl",
"core/java/com/android/internal/widget/ILockSettings.aidl",
"core/java/com/android/internal/widget/IRemoteViewsFactory.aidl",
"core/java/com/android/internal/widget/IRemoteViewsAdapterConnection.aidl",
"keystore/java/android/security/IKeyChainAliasCallback.aidl",
"keystore/java/android/security/IKeyChainService.aidl",
"location/java/android/location/IBatchedLocationCallback.aidl",
@@ -401,9 +421,10 @@ java_library {
"location/java/android/location/IGpsGeofenceHardware.aidl",
"location/java/android/location/INetInitiatedListener.aidl",
"location/java/com/android/internal/location/ILocationProvider.aidl",
"media/java/android/media/IAudioService.aidl",
"media/java/android/media/IAudioFocusDispatcher.aidl",
"media/java/android/media/IAudioRoutesObserver.aidl",
"media/java/android/media/IAudioService.aidl",
"media/java/android/media/IAudioServerStateDispatcher.aidl",
"media/java/android/media/IMediaHTTPConnection.aidl",
"media/java/android/media/IMediaHTTPService.aidl",
"media/java/android/media/IMediaResourceMonitor.aidl",
@@ -412,7 +433,8 @@ java_library {
"media/java/android/media/IMediaScannerListener.aidl",
"media/java/android/media/IMediaScannerService.aidl",
"media/java/android/media/IPlaybackConfigDispatcher.aidl",
"media/java/android/media/IPlayer.aidl",
"media/java/android/media/ISessionTokensListener.aidl",
":libaudioclient_aidl",
"media/java/android/media/IRecordingConfigDispatcher.aidl",
"media/java/android/media/IRemoteDisplayCallback.aidl",
"media/java/android/media/IRemoteDisplayProvider.aidl",
@@ -439,6 +461,8 @@ java_library {
"media/java/android/media/session/ISessionController.aidl",
"media/java/android/media/session/ISessionControllerCallback.aidl",
"media/java/android/media/session/ISessionManager.aidl",
"media/java/android/media/soundtrigger/ISoundTriggerDetectionService.aidl",
"media/java/android/media/soundtrigger/ISoundTriggerDetectionServiceClient.aidl",
"media/java/android/media/tv/ITvInputClient.aidl",
"media/java/android/media/tv/ITvInputHardware.aidl",
"media/java/android/media/tv/ITvInputHardwareCallback.aidl",
@@ -475,7 +499,7 @@ java_library {
"telephony/java/android/telephony/ims/aidl/IImsRcsFeature.aidl",
"telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl",
"telephony/java/android/telephony/ims/aidl/IImsServiceControllerListener.aidl",
"telephony/java/android/telephony/ims/aidl/IImsSmsListener.aidl",
"telephony/java/android/telephony/ims/aidl/IImsSmsListener.aidl",
"telephony/java/android/telephony/mbms/IMbmsDownloadSessionCallback.aidl",
"telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl",
"telephony/java/android/telephony/mbms/IDownloadStatusListener.aidl",
@@ -546,13 +570,17 @@ java_library {
"telephony/java/com/android/internal/telephony/euicc/ISetDefaultSmdpAddressCallback.aidl",
"telephony/java/com/android/internal/telephony/euicc/ISetNicknameCallback.aidl",
"telephony/java/com/android/internal/telephony/euicc/ISwitchToProfileCallback.aidl",
"wifi/java/android/net/wifi/ISoftApCallback.aidl",
"wifi/java/android/net/wifi/IWifiManager.aidl",
"wifi/java/android/net/wifi/aware/IWifiAwareEventCallback.aidl",
"wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl",
"wifi/java/android/net/wifi/aware/IWifiAwareDiscoverySessionCallback.aidl",
"wifi/java/android/net/wifi/aware/IWifiAwareEventCallback.aidl",
"wifi/java/android/net/wifi/aware/IWifiAwareMacAddressProvider.aidl",
"wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl",
"wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl",
"wifi/java/android/net/wifi/rtt/IRttCallback.aidl",
"wifi/java/android/net/wifi/rtt/IWifiRttManager.aidl",
"wifi/java/android/net/wifi/hotspot2/IProvisioningCallback.aidl",
"wifi/java/android/net/wifi/IWifiScanner.aidl",
"wifi/java/android/net/wifi/IRttManager.aidl",
"packages/services/PacProcessor/com/android/net/IProxyService.aidl",
"packages/services/Proxy/com/android/net/IProxyCallback.aidl",
"packages/services/Proxy/com/android/net/IProxyPortListener.aidl",
@@ -561,7 +589,9 @@ java_library {
":libupdate_engine_aidl",
":storaged_aidl",
":netd_aidl",
":vold_aidl",
":installd_aidl",
"lowpan/java/android/net/lowpan/ILowpanEnergyScanCallback.aidl",
@@ -575,9 +605,14 @@ java_library {
"core/java/android/content/EventLogTags.logtags",
"core/java/android/speech/tts/EventLogTags.logtags",
"core/java/android/net/EventLogTags.logtags",
"core/java/android/os/EventLogTags.logtags",
"core/java/android/webkit/EventLogTags.logtags",
"core/java/com/android/internal/app/EventLogTags.logtags",
"core/java/com/android/internal/logging/EventLogTags.logtags",
"core/java/com/android/server/DropboxLogTags.logtags",
"core/java/org/chromium/arc/EventLogTags.logtags",
":framework-statslog-gen",
],
aidl: {
@@ -605,14 +640,25 @@ java_library {
"system/update_engine/binder_bindings",
"frameworks/native/aidl/binder",
"frameworks/av/camera/aidl",
"frameworks/av/media/libaudioclient/aidl",
"frameworks/native/aidl/gui",
"system/core/storaged/binder",
"system/netd/server/binder",
"system/vold/binder",
"system/bt/binder",
"system/security/keystore/binder",
],
generate_get_transaction_name: true
},
exclude_srcs: [
// See comment on framework-atb-backward-compatibility module below
"core/java/android/content/pm/AndroidTestBaseUpdater.java",
// See comment on framework-oahl-backward-compatibility module below
"core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java",
],
no_framework_libs: true,
libs: [
"conscrypt",
@@ -625,19 +671,25 @@ java_library {
"framework-protos",
"android.hidl.base-V1.0-java",
"android.hardware.cas-V1.0-java",
"android.hardware.contexthub-V1.0-java",
"android.hardware.health-V1.0-java-constants",
"android.hardware.thermal-V1.0-java-constants",
"android.hardware.tv.input-V1.0-java-constants",
"android.hardware.usb-V1.0-java-constants",
"android.hardware.usb-V1.1-java-constants",
"android.hardware.vibrator-V1.0-java-constants",
"android.hardware.vibrator-V1.1-java-constants",
"android.hardware.vibrator-V1.0-java",
"android.hardware.vibrator-V1.1-java",
"android.hardware.vibrator-V1.2-java",
"android.hardware.wifi-V1.0-java-constants",
"android.hardware.radio-V1.0-java",
"android.hardware.usb.gadget-V1.0-java",
],
// Loaded with System.loadLibrary by android.view.textclassifier
required: ["libtextclassifier"],
required: [
"libtextclassifier",
"libmedia2_jni",
],
javac_shard_size: 150,
@@ -647,6 +699,38 @@ java_library {
],
}
// A temporary build target that is conditionally included on the bootclasspath if
// org.apache.http.legacy library has been removed and which provides support for
// maintaining backwards compatibility for APKs that target pre-P and depend on
// org.apache.http.legacy classes. This is used iff REMOVE_OAHL_FROM_BCP=true is
// specified on the build command line.
java_library {
name: "framework-oahl-backward-compatibility",
installable: true,
srcs: [
"core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java",
],
}
// A temporary build target that is conditionally included on the bootclasspath if
// android.test.base library has been removed and which provides support for
// maintaining backwards compatibility for APKs that target pre-P and depend on
// android.test.base classes. This is used iff REMOVE_ATB_FROM_BCP=true is
// specified on the build command line.
java_library {
name: "framework-atb-backward-compatibility",
srcs: [
"core/java/android/content/pm/AndroidTestBaseUpdater.java",
],
}
genrule {
name: "framework-statslog-gen",
tools: ["stats-log-api-gen"],
cmd: "$(location stats-log-api-gen) --java $(out)",
out: ["android/util/StatsLogInternal.java"],
}
gensrcs {
name: "framework-javastream-protos",
depfile: true,
@@ -667,7 +751,10 @@ gensrcs {
" $(in) " +
"&& $(location soong_zip) -jar -o $(out) -C $(genDir)/$(in) -D $(genDir)/$(in)",
srcs: ["core/proto/**/*.proto"],
srcs: [
"core/proto/**/*.proto",
"libs/incident/**/*.proto",
],
output_extension: "srcjar",
}
@@ -681,10 +768,29 @@ java_library {
"libphonenumber-platform",
"nist-sip",
"tagsoup",
"rappor",
],
dxflags: ["--core-library"],
}
// ==== java proto host library ==============================
java_library_host {
name: "platformprotos",
srcs: [
"cmds/am/proto/instrumentation_data.proto",
"core/proto/**/*.proto",
"libs/incident/proto/**/*.proto",
"cmds/statsd/src/**/*.proto",
],
proto: {
include_dirs: ["external/protobuf/src"],
type: "full",
},
errorprone: {
javacflags: ["-Xep:MissingOverride:OFF"], // b/72714520
},
}
// ==== c++ proto device library ==============================
cc_library {
name: "libplatformprotos",
@@ -699,26 +805,22 @@ cc_library {
"-Werror",
"-Wno-unused-parameter",
],
srcs: [
"core/proto/**/*.proto",
"libs/incident/**/*.proto",
],
target: {
host: {
proto: {
type: "full",
},
srcs: [
"core/proto/**/*.proto",
"libs/incident/**/*.proto",
],
},
android: {
proto: {
type: "lite",
},
// We only build the protos that are optimized for the lite
// runtime, as well as the only protos that are actually
// needed by the device.
srcs: [
"core/proto/android/service/graphicsstats.proto",
],
shared: {
enabled: false,
},
@@ -726,6 +828,41 @@ cc_library {
},
}
gensrcs {
name: "gen-platform-proto-constants",
depfile: true,
tools: [
"aprotoc",
"protoc-gen-cppstream",
],
srcs: [
"core/proto/android/os/backtrace.proto",
"core/proto/android/os/batterytype.proto",
"core/proto/android/os/cpufreq.proto",
"core/proto/android/os/cpuinfo.proto",
"core/proto/android/os/kernelwake.proto",
"core/proto/android/os/pagetypeinfo.proto",
"core/proto/android/os/procrank.proto",
"core/proto/android/os/ps.proto",
"core/proto/android/os/system_properties.proto",
"core/proto/android/util/event_log_tags.proto",
],
// Append protoc-gen-cppstream tool's PATH otherwise aprotoc can't find the plugin tool
cmd: "mkdir -p $(genDir) " +
"&& $(location aprotoc) " +
" --plugin=$(location protoc-gen-cppstream) " +
" --dependency_out=$(depfile) " +
" --cppstream_out=$(genDir) " +
" -Iexternal/protobuf/src " +
" -I . " +
" $(in)",
output_extension: "proto.h",
}
subdirs = [
"cmds/*",
"core/*",
@@ -869,11 +1006,6 @@ framework_docs_args = "-android -manifest $(location core/res/AndroidManifest.xm
doc_defaults {
name: "api-stubs-default",
srcs: [
// test mock src files.
"test-mock/src/android/test/mock/**/*.java",
// test runner excluding mock src files.
"test-runner/src/**/*.java",
"test-base/src/**/*.java",
":opt-telephony-srcs",
":opt-net-voip-srcs",
":openjdk_javadoc_files",
@@ -920,15 +1052,6 @@ doc_defaults {
installable: false,
}
check_last_released_api_args = "-hide 2 -hide 3 -hide 4 -hide 5 -hide 6 -hide 24 -hide 25 -hide 26 -hide 27 " +
"-error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 " +
"-error 16 -error 17 -error 18"
check_current_api_args = "-error 2 -error 3 -error 4 -error 5 -error 6 " +
"-error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 "+
"-error 16 -error 17 -error 18 -error 19 -error 20 -error 21 -error 23 -error 24 " +
"-error 25 -error 26 -error 27"
droiddoc {
name: "api-stubs-docs",
defaults: ["api-stubs-default"],
@@ -947,12 +1070,17 @@ droiddoc {
last_released: {
api_file: ":last-released-public-api",
removed_api_file: "api/removed.txt",
args: check_last_released_api_args,
args: "-hide 2 -hide 3 -hide 4 -hide 5 -hide 6 -hide 24 -hide 25 -hide 26 -hide 27 " +
"-error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 " +
"-error 16 -error 17 -error 18 -error 31",
},
current: {
api_file: "api/current.txt",
removed_api_file: "api/removed.txt",
args: check_current_api_args,
args: "-error 2 -error 3 -error 4 -error 5 -error 6 " +
"-error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 " +
"-error 16 -error 17 -error 18 -error 19 -error 20 -error 21 -error 23 -error 24 " +
"-error 25 -error 26 -error 27",
},
},
}
@@ -969,8 +1097,6 @@ droiddoc {
],
api_tag_name: "SYSTEM",
api_filename: "system-api.txt",
private_api_filename: "system-private.txt",
private_dex_api_filename: "system-private-dex.txt",
removed_api_filename: "system-removed.txt",
exact_api_filename: "system-exact.txt",
args: framework_docs_args + " -referenceonly -showAnnotation android.annotation.SystemApi -nodocs",
@@ -978,12 +1104,17 @@ droiddoc {
last_released: {
api_file: ":last-released-system-api",
removed_api_file: "api/system-removed.txt",
args: check_last_released_api_args,
args: "-hide 2 -hide 3 -hide 4 -hide 5 -hide 6 -hide 24 -hide 25 -hide 26 -hide 27 " +
"-error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 " +
"-error 16 -error 17 -error 18 -error 31",
},
current: {
api_file: "api/system-current.txt",
removed_api_file: "api/system-removed.txt",
args: check_current_api_args,
args: "-error 2 -error 3 -error 4 -error 5 -error 6 " +
"-error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 " +
"-error 16 -error 17 -error 18 -error 19 -error 20 -error 21 -error 23 -error 24 " +
"-error 25 -error 26 -error 27",
},
},
}
@@ -1007,7 +1138,10 @@ droiddoc {
current: {
api_file: "api/test-current.txt",
removed_api_file: "api/test-removed.txt",
args: check_current_api_args,
args: "-error 2 -error 3 -error 4 -error 5 -error 6 " +
"-error 7 -error 8 -error 9 -error 10 -error 11 -error 12 -error 13 -error 14 -error 15 " +
"-error 16 -error 17 -error 18 -error 19 -error 20 -error 21 -error 23 -error 24 " +
"-error 25 -error 26 -error 27",
},
},
}
@@ -1022,7 +1156,7 @@ doc_defaults {
":non_openjdk_javadoc_files",
":android_icu4j_src_files_for_docs",
":gen-ojluni-jaif-annotated-srcs",
":frameworks-data-binding-srcs",
"test-mock/src/**/*.java",
"test-runner/src/**/*.java",
],
exclude_srcs: [
@@ -1132,6 +1266,21 @@ droiddoc {
static_doc_properties: "docs/source.properties",
}
droiddoc {
name: "offline-system-sdk-referenceonly-docs",
defaults: ["framework-docs-default"],
hdf: [
"android.whichdoc offline",
],
proofread_file: "offline-system-sdk-referenceonly-docs-proofrerad.txt",
args: framework_docs_args + " -hide 101 -hide 104 -hide 108" +
" -showAnnotation android.annotation.SystemApi " +
" -offlinemode -title \"Android System SDK\" -referenceonly",
write_sdk_values: true,
static_doc_index_redirect: "docs/docs-documentation-redirect.html",
static_doc_properties: "docs/source.properties",
}
droiddoc {
name: "online-sdk-docs",
defaults: ["framework-docs-default"],

View File

@@ -72,17 +72,10 @@ non_base_dirs := \
../opt/net/voip/src/java/android/net/rtp \
../opt/net/voip/src/java/android/net/sip \
framework_base_android_test_mock_src_files := \
$(call all-java-files-under, test-mock/src/android/test/mock)
framework_base_android_test_runner_excluding_mock_src_files := \
$(filter-out $(framework_base_android_test_mock_src_files), $(call all-java-files-under, test-runner/src))
# Find all files in specific directories (relative to frameworks/base)
# to document and check apis
files_to_check_apis := \
$(call find-other-java-files, \
test-base/src \
$(non_base_dirs) \
)
@@ -106,7 +99,8 @@ files_to_check_apis_generated := \
files_to_document := \
$(files_to_check_apis) \
$(call find-other-java-files,\
$(addprefix ../../, $(FRAMEWORKS_DATA_BINDING_JAVA_SRC_DIRS)) \
test-base/src \
test-mock/src \
test-runner/src)
# These are relative to frameworks/base
@@ -126,8 +120,6 @@ framework_docs_LOCAL_SRC_FILES := \
# These are relative to frameworks/base
framework_docs_LOCAL_API_CHECK_SRC_FILES := \
$(framework_base_android_test_mock_src_files) \
$(framework_base_android_test_runner_excluding_mock_src_files) \
$(files_to_check_apis) \
$(common_src_files) \
@@ -153,7 +145,6 @@ framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES := \
ext \
framework \
voip-common \
android.test.mock \
# Platform docs can refer to Support Library APIs, but we don't actually build
# them as part of the docs target, so we need to include them on the classpath.
@@ -251,6 +242,72 @@ framework_docs_LOCAL_DROIDDOC_OPTIONS += \
-federate SupportLib https://developer.android.com \
-federationapi SupportLib prebuilts/sdk/current/support-api.txt
# Federate AndroidX references against local API file.
framework_docs_LOCAL_DROIDDOC_OPTIONS += \
-federate AndroidX https://developer.android.com \
-federationapi AndroidX prebuilts/sdk/current/androidx-api.txt
# Get the highest numbered api txt for the given api level.
# $(1): the api level (e.g. public, system)
define highest_sdk_txt
$(HISTORICAL_SDK_VERSIONS_ROOT)/$(lastword $(call numerically_sort, \
$(patsubst \
$(HISTORICAL_SDK_VERSIONS_ROOT)/%,\
%,\
$(wildcard $(HISTORICAL_SDK_VERSIONS_ROOT)/*/$(1)/api/android.txt)\
) \
))
endef
# ==== Public API diff ===========================
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(framework_docs_LOCAL_API_CHECK_SRC_FILES)
LOCAL_GENERATED_SOURCES := $(framework_docs_LOCAL_GENERATED_SOURCES)
LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
LOCAL_JAVA_LIBRARIES := $(framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES)
LOCAL_MODULE_CLASS := $(framework_docs_LOCAL_MODULE_CLASS)
LOCAL_ADDITIONAL_JAVA_DIR := $(framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR)
LOCAL_ADDITIONAL_DEPENDENCIES := \
$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES) \
$(INTERNAL_PLATFORM_API_FILE)
LOCAL_MODULE := offline-sdk-referenceonly
# Basename, because apidiff adds .txt internally.
LOCAL_APIDIFF_OLDAPI := $(basename $(call highest_sdk_txt,public))
LOCAL_APIDIFF_NEWAPI := $(LOCAL_PATH)/../../$(basename $(INTERNAL_PLATFORM_API_FILE))
include $(BUILD_APIDIFF)
# Hack to get diffs included in docs output
out_zip := $(OUT_DOCS)/$(LOCAL_MODULE)-docs.zip
$(out_zip): $(full_target)
# ==== System API diff ===========================
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(framework_docs_LOCAL_API_CHECK_SRC_FILES)
LOCAL_GENERATED_SOURCES := $(framework_docs_LOCAL_GENERATED_SOURCES)
LOCAL_SRCJARS:=$(framework_docs_LOCAL_SRCJARS)
LOCAL_JAVA_LIBRARIES := $(framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES)
LOCAL_MODULE_CLASS := $(framework_docs_LOCAL_MODULE_CLASS)
LOCAL_ADDITIONAL_JAVA_DIR := $(framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR)
LOCAL_ADDITIONAL_DEPENDENCIES := \
$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES) \
$(INTERNAL_PLATFORM_SYSTEM_API_FILE)
LOCAL_MODULE := offline-system-sdk-referenceonly
# Basename, because apidiff adds .txt internally.
LOCAL_APIDIFF_OLDAPI := $(basename $(call highest_sdk_txt,system))
LOCAL_APIDIFF_NEWAPI := $(LOCAL_PATH)/../../$(basename $(INTERNAL_PLATFORM_SYSTEM_API_FILE))
include $(BUILD_APIDIFF)
# Hack to get diffs included in docs output
out_zip := $(OUT_DOCS)/$(LOCAL_MODULE)-docs.zip
$(out_zip): $(full_target)
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE))
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_SYSTEM_API_FILE))
@@ -264,21 +321,36 @@ $(OUT_DOCS)/offline-sdk-timestamp: $(OUT_DOCS)/offline-sdk-docs-docs.zip
$(hide) mkdir -p $(OUT_DOCS)/offline-sdk
( unzip -qo $< -d $(OUT_DOCS)/offline-sdk && touch -f $@ ) || exit 1
# ==== java proto host library ==============================
# ==== java proto device library (for test only) ==============================
include $(CLEAR_VARS)
LOCAL_MODULE := platformprotos
LOCAL_PROTOC_OPTIMIZE_TYPE := full
LOCAL_MODULE := platformprotosnano
LOCAL_MODULE_TAGS := tests
LOCAL_PROTOC_OPTIMIZE_TYPE := nano
LOCAL_PROTOC_FLAGS := \
-Iexternal/protobuf/src
LOCAL_SOURCE_FILES_ALL_GENERATED := true
LOCAL_PROTO_JAVA_OUTPUT_PARAMS := \
store_unknown_fields = true
LOCAL_SDK_VERSION := current
LOCAL_SRC_FILES := \
$(call all-proto-files-under, core/proto) \
$(call all-proto-files-under, libs/incident/proto)
# b/72714520
LOCAL_ERROR_PRONE_FLAGS := -Xep:MissingOverride:OFF
include $(BUILD_HOST_JAVA_LIBRARY)
$(call all-proto-files-under, libs/incident/proto/android/os)
include $(BUILD_STATIC_JAVA_LIBRARY)
# ==== java proto device library (for test only) ==============================
include $(CLEAR_VARS)
LOCAL_MODULE := platformprotoslite
LOCAL_MODULE_TAGS := tests
LOCAL_PROTOC_OPTIMIZE_TYPE := lite
LOCAL_PROTOC_FLAGS := \
-Iexternal/protobuf/src
LOCAL_SRC_FILES := \
$(call all-proto-files-under, core/proto) \
$(call all-proto-files-under, libs/incident/proto/android/os)
# Protos have lots of MissingOverride and similar.
LOCAL_ERROR_PRONE_FLAGS := -XepDisableAllChecks
include $(BUILD_STATIC_JAVA_LIBRARY)
# ==== hiddenapi lists =======================================
include $(CLEAR_VARS)
@@ -394,20 +466,6 @@ $(LOCAL_BLACKLIST): $(LOCAL_SRC_ALL) $(LOCAL_LIGHT_GREYLIST) $(LOCAL_DARK_GREYLI
$(call assert-has-no-overlap,$@,$(LOCAL_DARK_GREYLIST))
$(call assert-is-subset,$(LOCAL_SRC_FORCE_BLACKLIST),$@)
# Build AOSP blacklist
# ============================================================
include $(CLEAR_VARS)
LOCAL_LIGHT_GREYLIST_FILE := frameworks/base/config/hiddenapi-p-light-greylist.txt
LOCAL_BLACKLIST_FILE := $(TARGET_OUT_COMMON_INTERMEDIATES)/PACKAGING/hiddenapi-aosp-blacklist.txt
.PHONY: hiddenapi-aosp-blacklist
hiddenapi-aosp-blacklist: $(LOCAL_BLACKLIST_FILE)
$(LOCAL_BLACKLIST_FILE): $(LOCAL_LIGHT_GREYLIST_FILE) $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE)
LC_COLLATE=C comm -13 <(sort $(LOCAL_LIGHT_GREYLIST_FILE)) \
<(sort $(INTERNAL_PLATFORM_PRIVATE_DEX_API_FILE)) > $@
# Include subdirectory makefiles
# ============================================================

View File

@@ -243,6 +243,7 @@ $(call add-clean-step, rm -f $(OUT_DIR)/target/common/obj/APPS/FeatureSplit2_int
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/hardware)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/core/java/android/os/storage/*)
$(call add-clean-step, rm -rf $(OUT_DIR)/host/common/obj/JAVA_LIBRARIES/platformprotos_intermediates)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/statsdprotolite_intermediates)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/com.android.mediadrm.signer.jar)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/com.android.location.provider.jar)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/com.android.future.usb.accessory.jar)

View File

@@ -1,6 +1,7 @@
[Hook Scripts]
checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
-fw core/java/android/
graphics/java/android
core/tests/coretests/src/android/
packages/PrintRecommendationService/
packages/PrintSpooler/
@@ -8,4 +9,8 @@ checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPL
services/usb/
telephony/
api_lint_hook = ${REPO_ROOT}/frameworks/base/tools/apilint/apilint_sha.sh ${PREUPLOAD_COMMIT}
strings_lint_hook = ${REPO_ROOT}/frameworks/base/tools/stringslint/stringslint_sha.sh ${PREUPLOAD_COMMIT}
hidden_api_txt_hook = ${REPO_ROOT}/frameworks/base/tools/hiddenapi/checksorted_sha.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT}

View File

@@ -4,12 +4,16 @@ include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SRC_FILES := \
$(call all-java-files-under, src) \
src/android/os/ISomeService.aidl
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test \
apct-perftests-utils \
legacy-android-test
guava
LOCAL_JAVA_LIBRARIES := android.test.base
LOCAL_PACKAGE_NAME := CorePerfTests
LOCAL_PRIVATE_PLATFORM_APIS := true
@@ -19,4 +23,6 @@ LOCAL_JNI_SHARED_LIBRARIES := libperftestscore_jni
# Use google-fonts/dancing-script for the performance metrics
LOCAL_ASSET_DIR := $(TOP)/external/google-fonts/dancing-script
LOCAL_COMPATIBILITY_SUITE += device-tests
include $(BUILD_PACKAGE)

View File

@@ -2,9 +2,20 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.perftests.core">
<permission android:name="com.android.perftests.core.TestPermission" />
<uses-permission android:name="com.android.perftests.core.TestPermission" />
<uses-permission
android:name="android.permission.GET_ACCOUNTS" />
<application>
<uses-library android:name="android.test.runner" />
<activity android:name="android.perftests.utils.StubActivity" />
<activity android:name="android.perftests.utils.StubActivity">
<intent-filter>
<action android:name="com.android.perftests.core.PERFTEST" />
</intent-filter>
</activity>
<service android:name="android.os.SomeService" android:exported="false" android:process=":some_service" />
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2018 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<configuration description="Runs CorePerfTests metric instrumentation.">
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="apct-metric-instrumentation" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CorePerfTests.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.perftests.core" />
<option name="hidden-api-checks" value="false"/>
</test>
</configuration>

View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.accounts;
import static junit.framework.Assert.fail;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.Log;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class AccountManagerPerfTest {
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void testGetAccounts() {
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final Context context = InstrumentationRegistry.getTargetContext();
if (context.checkSelfPermission(Manifest.permission.GET_ACCOUNTS)
!= PackageManager.PERMISSION_GRANTED) {
fail("Missing required GET_ACCOUNTS permission");
}
AccountManager accountManager = AccountManager.get(context);
while (state.keepRunning()) {
accountManager.getAccounts();
}
}
}

View File

@@ -0,0 +1,134 @@
/*
* 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.app;
import android.content.Context;
import android.content.Intent;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.perftests.utils.StubActivity;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
// Due to b/71353150, you might get "java.lang.AssertionError: Binder ProxyMap has too many
// entries", but it's flaky. Adding "Runtime.getRuntime().gc()" between each iteration solves
// the problem, but it doesn't seem like it's currently needed.
@RunWith(AndroidJUnit4.class)
@LargeTest
public class PendingIntentPerfTest {
private Context mContext;
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private Intent mIntent;
@Before
public void setUp() {
mContext = InstrumentationRegistry.getTargetContext();
mIntent = StubActivity.createLaunchIntent(mContext);
}
/**
* Benchmark time to create a PendingIntent.
*/
@Test
public void create() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
state.pauseTiming();
state.resumeTiming();
final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, mIntent,
0);
state.pauseTiming();
pendingIntent.cancel();
state.resumeTiming();
}
}
/**
* Benchmark time to create a PendingIntent with FLAG_CANCEL_CURRENT, already having an active
* PendingIntent.
*/
@Test
public void createWithCancelFlag() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
state.pauseTiming();
final PendingIntent previousPendingIntent = PendingIntent.getActivity(mContext, 0,
mIntent, 0);
state.resumeTiming();
final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, mIntent,
PendingIntent.FLAG_CANCEL_CURRENT);
state.pauseTiming();
pendingIntent.cancel();
state.resumeTiming();
}
}
/**
* Benchmark time to create a PendingIntent with FLAG_UPDATE_CURRENT, already having an active
* PendingIntent.
*/
@Test
public void createWithUpdateFlag() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
state.pauseTiming();
final PendingIntent previousPendingIntent = PendingIntent.getActivity(mContext, 0,
mIntent, 0);
state.resumeTiming();
final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, mIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
state.pauseTiming();
previousPendingIntent.cancel();
pendingIntent.cancel();
state.resumeTiming();
}
}
/**
* Benchmark time to cancel a PendingIntent.
*/
@Test
public void cancel() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
state.pauseTiming();
final PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0,
mIntent, 0);
state.resumeTiming();
pendingIntent.cancel();
}
}
}

View File

@@ -0,0 +1,176 @@
/*
* 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
*/
package android.database;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.ArrayMap;
import android.util.Log;
import com.android.internal.util.Preconditions;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertEquals;
/**
* Performance tests for measuring amount of data written during typical DB operations
*
* <p>To run: bit CorePerfTests:android.database.SQLiteDatabaseIoPerfTest
*/
@RunWith(AndroidJUnit4.class)
@LargeTest
public class SQLiteDatabaseIoPerfTest {
private static final String TAG = "SQLiteDatabaseIoPerfTest";
private static final String DB_NAME = "db_io_perftest";
private static final int DEFAULT_DATASET_SIZE = 500;
private Long mWriteBytes;
private SQLiteDatabase mDatabase;
private Context mContext;
@Before
public void setUp() {
mContext = InstrumentationRegistry.getTargetContext();
mContext.deleteDatabase(DB_NAME);
mDatabase = mContext.openOrCreateDatabase(DB_NAME, Context.MODE_PRIVATE, null);
mDatabase.execSQL("CREATE TABLE T1 "
+ "(_ID INTEGER PRIMARY KEY, COL_A INTEGER, COL_B VARCHAR(100), COL_C REAL)");
}
@After
public void tearDown() {
mDatabase.close();
mContext.deleteDatabase(DB_NAME);
}
@Test
public void testDatabaseModifications() {
startMeasuringWrites();
ContentValues cv = new ContentValues();
String[] whereArg = new String[1];
for (int i = 0; i < DEFAULT_DATASET_SIZE; i++) {
cv.put("_ID", i);
cv.put("COL_A", i);
cv.put("COL_B", "NewValue");
cv.put("COL_C", 1.0);
assertEquals(i, mDatabase.insert("T1", null, cv));
}
cv = new ContentValues();
for (int i = 0; i < DEFAULT_DATASET_SIZE; i++) {
cv.put("COL_B", "UpdatedValue");
cv.put("COL_C", 1.1);
whereArg[0] = String.valueOf(i);
assertEquals(1, mDatabase.update("T1", cv, "_ID=?", whereArg));
}
for (int i = 0; i < DEFAULT_DATASET_SIZE; i++) {
whereArg[0] = String.valueOf(i);
assertEquals(1, mDatabase.delete("T1", "_ID=?", whereArg));
}
// Make sure all changes are written to disk
mDatabase.close();
long bytes = endMeasuringWrites();
sendResults("testDatabaseModifications" , bytes);
}
@Test
public void testInsertsWithTransactions() {
startMeasuringWrites();
final int txSize = 10;
ContentValues cv = new ContentValues();
for (int i = 0; i < DEFAULT_DATASET_SIZE * 5; i++) {
if (i % txSize == 0) {
mDatabase.beginTransaction();
}
if (i % txSize == txSize-1) {
mDatabase.setTransactionSuccessful();
mDatabase.endTransaction();
}
cv.put("_ID", i);
cv.put("COL_A", i);
cv.put("COL_B", "NewValue");
cv.put("COL_C", 1.0);
assertEquals(i, mDatabase.insert("T1", null, cv));
}
// Make sure all changes are written to disk
mDatabase.close();
long bytes = endMeasuringWrites();
sendResults("testInsertsWithTransactions" , bytes);
}
private void startMeasuringWrites() {
Preconditions.checkState(mWriteBytes == null, "Measurement already started");
mWriteBytes = getIoStats().get("write_bytes");
}
private long endMeasuringWrites() {
Preconditions.checkState(mWriteBytes != null, "Measurement wasn't started");
Long newWriteBytes = getIoStats().get("write_bytes");
return newWriteBytes - mWriteBytes;
}
private void sendResults(String testName, long writeBytes) {
Log.i(TAG, testName + " write_bytes: " + writeBytes);
Bundle status = new Bundle();
status.putLong("write_bytes", writeBytes);
InstrumentationRegistry.getInstrumentation().sendStatus(Activity.RESULT_OK, status);
}
private static Map<String, Long> getIoStats() {
String ioStat = "/proc/self/io";
Map<String, Long> results = new ArrayMap<>();
try {
List<String> lines = Files.readAllLines(new File(ioStat).toPath());
for (String line : lines) {
line = line.trim();
String[] split = line.split(":");
if (split.length == 2) {
try {
String key = split[0].trim();
Long value = Long.valueOf(split[1].trim());
results.put(key, value);
} catch (NumberFormatException e) {
Log.e(TAG, "Cannot parse number from " + line);
}
} else if (line.isEmpty()) {
Log.e(TAG, "Cannot parse line " + line);
}
}
} catch (IOException e) {
Log.e(TAG, "Can't read: " + ioStat, e);
}
return results;
}
}

View File

@@ -0,0 +1,273 @@
/*
* 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
*/
package android.database;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Random;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* Performance tests for typical CRUD operations and loading rows into the Cursor
*
* <p>To run: bit CorePerfTests:android.database.SQLiteDatabasePerfTest
*/
@RunWith(AndroidJUnit4.class)
@LargeTest
public class SQLiteDatabasePerfTest {
// TODO b/64262688 Add Concurrency tests to compare WAL vs DELETE read/write
private static final String DB_NAME = "dbperftest";
private static final int DEFAULT_DATASET_SIZE = 1000;
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private SQLiteDatabase mDatabase;
private Context mContext;
@Before
public void setUp() {
mContext = InstrumentationRegistry.getTargetContext();
mContext.deleteDatabase(DB_NAME);
mDatabase = mContext.openOrCreateDatabase(DB_NAME, Context.MODE_PRIVATE, null);
mDatabase.execSQL("CREATE TABLE T1 "
+ "(_ID INTEGER PRIMARY KEY, COL_A INTEGER, COL_B VARCHAR(100), COL_C REAL)");
mDatabase.execSQL("CREATE TABLE T2 ("
+ "_ID INTEGER PRIMARY KEY, COL_A VARCHAR(100), T1_ID INTEGER,"
+ "FOREIGN KEY(T1_ID) REFERENCES T1 (_ID))");
}
@After
public void tearDown() {
mDatabase.close();
mContext.deleteDatabase(DB_NAME);
}
@Test
public void testSelect() {
insertT1TestDataSet();
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
Random rnd = new Random(0);
while (state.keepRunning()) {
int index = rnd.nextInt(DEFAULT_DATASET_SIZE);
try (Cursor cursor = mDatabase.rawQuery("SELECT _ID, COL_A, COL_B, COL_C FROM T1 "
+ "WHERE _ID=?", new String[]{String.valueOf(index)})) {
assertTrue(cursor.moveToNext());
assertEquals(index, cursor.getInt(0));
assertEquals(index, cursor.getInt(1));
assertEquals("T1Value" + index, cursor.getString(2));
assertEquals(1.1 * index, cursor.getDouble(3), 0.0000001d);
}
}
}
@Test
public void testSelectMultipleRows() {
insertT1TestDataSet();
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
Random rnd = new Random(0);
final int querySize = 50;
while (state.keepRunning()) {
int index = rnd.nextInt(DEFAULT_DATASET_SIZE - querySize - 1);
try (Cursor cursor = mDatabase.rawQuery("SELECT _ID, COL_A, COL_B, COL_C FROM T1 "
+ "WHERE _ID BETWEEN ? and ? ORDER BY _ID",
new String[]{String.valueOf(index), String.valueOf(index + querySize - 1)})) {
int i = 0;
while(cursor.moveToNext()) {
assertEquals(index, cursor.getInt(0));
assertEquals(index, cursor.getInt(1));
assertEquals("T1Value" + index, cursor.getString(2));
assertEquals(1.1 * index, cursor.getDouble(3), 0.0000001d);
index++;
i++;
}
assertEquals(querySize, i);
}
}
}
@Test
public void testCursorIterateForward() {
// A larger dataset is needed to exceed default CursorWindow size
int datasetSize = DEFAULT_DATASET_SIZE * 50;
insertT1TestDataSet(datasetSize);
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
try (Cursor cursor = mDatabase
.rawQuery("SELECT _ID, COL_A, COL_B, COL_C FROM T1 ORDER BY _ID", null)) {
int i = 0;
while(cursor.moveToNext()) {
assertEquals(i, cursor.getInt(0));
assertEquals(i, cursor.getInt(1));
assertEquals("T1Value" + i, cursor.getString(2));
assertEquals(1.1 * i, cursor.getDouble(3), 0.0000001d);
i++;
}
assertEquals(datasetSize, i);
}
}
}
@Test
public void testCursorIterateBackwards() {
// A larger dataset is needed to exceed default CursorWindow size
int datasetSize = DEFAULT_DATASET_SIZE * 50;
insertT1TestDataSet(datasetSize);
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
try (Cursor cursor = mDatabase
.rawQuery("SELECT _ID, COL_A, COL_B, COL_C FROM T1 ORDER BY _ID", null)) {
int i = datasetSize - 1;
while(cursor.moveToPosition(i)) {
assertEquals(i, cursor.getInt(0));
assertEquals(i, cursor.getInt(1));
assertEquals("T1Value" + i, cursor.getString(2));
assertEquals(1.1 * i, cursor.getDouble(3), 0.0000001d);
i--;
}
assertEquals(-1, i);
}
}
}
@Test
public void testInnerJoin() {
mDatabase.setForeignKeyConstraintsEnabled(true);
mDatabase.beginTransaction();
insertT1TestDataSet();
insertT2TestDataSet();
mDatabase.setTransactionSuccessful();
mDatabase.endTransaction();
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
Random rnd = new Random(0);
while (state.keepRunning()) {
int index = rnd.nextInt(1000);
try (Cursor cursor = mDatabase.rawQuery(
"SELECT T1._ID, T1.COL_A, T1.COL_B, T1.COL_C, T2.COL_A FROM T1 "
+ "INNER JOIN T2 on T2.T1_ID=T1._ID WHERE T1._ID = ?",
new String[]{String.valueOf(index)})) {
assertTrue(cursor.moveToNext());
assertEquals(index, cursor.getInt(0));
assertEquals(index, cursor.getInt(1));
assertEquals("T1Value" + index, cursor.getString(2));
assertEquals(1.1 * index, cursor.getDouble(3), 0.0000001d);
assertEquals("T2Value" + index, cursor.getString(4));
}
}
}
@Test
public void testInsert() {
insertT1TestDataSet();
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
ContentValues cv = new ContentValues();
cv.put("_ID", DEFAULT_DATASET_SIZE);
cv.put("COL_B", "NewValue");
cv.put("COL_C", 1.1);
String[] deleteArgs = new String[]{String.valueOf(DEFAULT_DATASET_SIZE)};
while (state.keepRunning()) {
assertEquals(DEFAULT_DATASET_SIZE, mDatabase.insert("T1", null, cv));
state.pauseTiming();
assertEquals(1, mDatabase.delete("T1", "_ID=?", deleteArgs));
state.resumeTiming();
}
}
@Test
public void testDelete() {
insertT1TestDataSet();
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
String[] deleteArgs = new String[]{String.valueOf(DEFAULT_DATASET_SIZE)};
Object[] insertsArgs = new Object[]{DEFAULT_DATASET_SIZE, DEFAULT_DATASET_SIZE,
"ValueToDelete", 1.1};
while (state.keepRunning()) {
state.pauseTiming();
mDatabase.execSQL("INSERT INTO T1 VALUES (?, ?, ?, ?)", insertsArgs);
state.resumeTiming();
assertEquals(1, mDatabase.delete("T1", "_ID=?", deleteArgs));
}
}
@Test
public void testUpdate() {
insertT1TestDataSet();
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
Random rnd = new Random(0);
int i = 0;
ContentValues cv = new ContentValues();
String[] argArray = new String[1];
while (state.keepRunning()) {
int id = rnd.nextInt(DEFAULT_DATASET_SIZE);
cv.put("COL_A", i);
cv.put("COL_B", "UpdatedValue");
cv.put("COL_C", i);
argArray[0] = String.valueOf(id);
assertEquals(1, mDatabase.update("T1", cv, "_ID=?", argArray));
i++;
}
}
private void insertT1TestDataSet() {
insertT1TestDataSet(DEFAULT_DATASET_SIZE);
}
private void insertT1TestDataSet(int size) {
mDatabase.beginTransaction();
for (int i = 0; i < size; i++) {
mDatabase.execSQL("INSERT INTO T1 VALUES (?, ?, ?, ?)",
new Object[]{i, i, "T1Value" + i, i * 1.1});
}
mDatabase.setTransactionSuccessful();
mDatabase.endTransaction();
}
private void insertT2TestDataSet() {
mDatabase.beginTransaction();
for (int i = 0; i < DEFAULT_DATASET_SIZE; i++) {
mDatabase.execSQL("INSERT INTO T2 VALUES (?, ?, ?)",
new Object[]{i, "T2Value" + i, i});
}
mDatabase.setTransactionSuccessful();
mDatabase.endTransaction();
}
}

View File

@@ -51,7 +51,6 @@ public class CanvasPerfTest {
while (state.keepRunning()) {
canvas = node.start(200, 200);
canvas.setHighContrastText(false);
int save = canvas.save();
canvas.clipRect(1, 1, 199, 199);
canvas.insertReorderBarrier();

View File

@@ -80,11 +80,11 @@ public class PaintMeasureTextTest {
}
while (state.keepRunning()) {
state.pauseTiming();
if (mCacheMode == DONT_USE_CACHE) {
state.pauseTiming();
Canvas.freeTextLayoutCaches();
state.resumeTiming();
}
state.resumeTiming();
paint.measureText(mText);
}

View File

@@ -0,0 +1,78 @@
/*
* 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.os;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import com.android.internal.os.BinderCallsStats;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.assertNull;
/**
* Performance tests for {@link BinderCallsStats}
*/
@RunWith(AndroidJUnit4.class)
@LargeTest
public class BinderCallsStatsPerfTest {
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private BinderCallsStats mBinderCallsStats;
@Before
public void setUp() {
mBinderCallsStats = new BinderCallsStats(true);
}
@After
public void tearDown() {
}
@Test
public void timeCallSession() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
Binder b = new Binder();
int i = 0;
while (state.keepRunning()) {
BinderCallsStats.CallSession s = mBinderCallsStats.callStarted(b, i % 100);
mBinderCallsStats.callEnded(s);
i++;
}
}
@Test
public void timeCallSessionTrackingDisabled() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
Binder b = new Binder();
mBinderCallsStats = new BinderCallsStats(false);
while (state.keepRunning()) {
BinderCallsStats.CallSession s = mBinderCallsStats.callStarted(b, 0);
mBinderCallsStats.callEnded(s);
}
}
}

View File

@@ -0,0 +1,5 @@
package android.os;
interface ISomeService {
void readDisk(int times);
}

View File

@@ -0,0 +1,114 @@
/*
* 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.
*/
package android.os;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class PackageManagerPerfTest {
private static final String PERMISSION_NAME_EXISTS =
"com.android.perftests.core.TestPermission";
private static final String PERMISSION_NAME_DOESNT_EXIST =
"com.android.perftests.core.TestBadPermission";
private static final ComponentName TEST_ACTIVITY =
new ComponentName("com.android.perftests.core", "android.perftests.utils.StubActivity");
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void testCheckPermissionExists() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager();
final String packageName = TEST_ACTIVITY.getPackageName();
while (state.keepRunning()) {
int ret = pm.checkPermission(PERMISSION_NAME_EXISTS, packageName);
}
}
@Test
public void testCheckPermissionDoesntExist() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager();
final String packageName = TEST_ACTIVITY.getPackageName();
while (state.keepRunning()) {
int ret = pm.checkPermission(PERMISSION_NAME_DOESNT_EXIST, packageName);
}
}
@Test
public void testQueryIntentActivities() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager();
final Intent intent = new Intent("com.android.perftests.core.PERFTEST");
while (state.keepRunning()) {
pm.queryIntentActivities(intent, 0);
}
}
@Test
public void testGetPackageInfo() throws Exception {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager();
final String packageName = TEST_ACTIVITY.getPackageName();
while (state.keepRunning()) {
pm.getPackageInfo(packageName, 0);
}
}
@Test
public void testGetApplicationInfo() throws Exception {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager();
final String packageName = TEST_ACTIVITY.getPackageName();
while (state.keepRunning()) {
pm.getApplicationInfo(packageName, 0);
}
}
@Test
public void testGetActivityInfo() throws Exception {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final PackageManager pm = InstrumentationRegistry.getTargetContext().getPackageManager();
while (state.keepRunning()) {
pm.getActivityInfo(TEST_ACTIVITY, 0);
}
}
}

View File

@@ -27,6 +27,10 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class ParcelPerfTest {
@@ -167,4 +171,80 @@ public class ParcelPerfTest {
Parcel.obtain().recycle();
}
}
@Test
public void timeWriteException() {
timeWriteException(false);
}
@Test
public void timeWriteExceptionWithStackTraceParceling() {
timeWriteException(true);
}
@Test
public void timeReadException() {
timeReadException(false);
}
@Test
public void timeReadExceptionWithStackTraceParceling() {
timeReadException(true);
}
private void timeWriteException(boolean enableParceling) {
if (enableParceling) {
Parcel.setStackTraceParceling(true);
}
try {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
Parcel p = Parcel.obtain();
SecurityException e = new SecurityException("TestMessage");
while (state.keepRunning()) {
p.setDataPosition(0);
p.writeException(e);
}
} finally {
if (enableParceling) {
Parcel.setStackTraceParceling(false);
}
}
}
private void timeReadException(boolean enableParceling) {
if (enableParceling) {
Parcel.setStackTraceParceling(true);
}
try {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
Parcel p = Parcel.obtain();
String msg = "TestMessage";
p.writeException(new SecurityException(msg));
p.setDataPosition(0);
// First verify that remote cause is set (if parceling is enabled)
try {
p.readException();
} catch (SecurityException e) {
assertEquals(e.getMessage(), msg);
if (enableParceling) {
assertTrue(e.getCause() instanceof RemoteException);
} else {
assertNull(e.getCause());
}
}
while (state.keepRunning()) {
p.setDataPosition(0);
try {
p.readException();
} catch (SecurityException expected) {
}
}
} finally {
if (enableParceling) {
Parcel.setStackTraceParceling(false);
}
}
}
}

View File

@@ -0,0 +1,41 @@
/*
* 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.os;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class PssPerfTest {
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void testPss() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
Debug.getPss();
}
}
}

View File

@@ -0,0 +1,42 @@
package android.os;
import android.app.Service;
import android.content.Intent;
import java.io.File;
import java.io.IOException;
/** Service in separate process available for calling over binder. */
public class SomeService extends Service {
private File mTempFile;
@Override
public void onCreate() {
super.onCreate();
try {
mTempFile = File.createTempFile("foo", "bar");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private final ISomeService.Stub mBinder =
new ISomeService.Stub() {
public void readDisk(int times) {
for (int i = 0; i < times; i++) {
mTempFile.exists();
}
}
};
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onDestroy() {
super.onDestroy();
mTempFile.delete();
}
}

View File

@@ -0,0 +1,127 @@
/*
* 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.
*/
package android.os;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.net.Uri;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import com.google.common.util.concurrent.SettableFuture;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(AndroidJUnit4.class)
@LargeTest
public class StrictModeTest {
@Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void timeVmViolation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder().detectAll().penaltyLog().build());
causeVmViolations(state);
}
@Test
public void timeVmViolationNoStrictMode() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
causeVmViolations(state);
}
private static void causeVmViolations(BenchmarkState state) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(Uri.parse("content://com.example/foobar"), "image/jpeg");
final Context context = InstrumentationRegistry.getTargetContext();
while (state.keepRunning()) {
context.startActivity(intent);
}
}
@Test
public void timeThreadViolation() throws IOException {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
StrictMode.setThreadPolicy(
new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());
causeThreadViolations(state);
}
@Test
public void timeThreadViolationNoStrictMode() throws IOException {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
causeThreadViolations(state);
}
private static void causeThreadViolations(BenchmarkState state) throws IOException {
final File test = File.createTempFile("foo", "bar");
while (state.keepRunning()) {
test.exists();
}
test.delete();
}
@Test
public void timeCrossBinderThreadViolation() throws Exception {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
StrictMode.setThreadPolicy(
new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());
causeCrossProcessThreadViolations(state);
}
@Test
public void timeCrossBinderThreadViolationNoStrictMode() throws Exception {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
causeCrossProcessThreadViolations(state);
}
private static void causeCrossProcessThreadViolations(BenchmarkState state)
throws ExecutionException, InterruptedException, RemoteException {
final Context context = InstrumentationRegistry.getTargetContext();
SettableFuture<IBinder> binder = SettableFuture.create();
ServiceConnection connection =
new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
binder.set(service);
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
binder.set(null);
}
};
context.bindService(
new Intent(context, SomeService.class), connection, Context.BIND_AUTO_CREATE);
ISomeService someService = ISomeService.Stub.asInterface(binder.get());
while (state.keepRunning()) {
// Violate strictmode heavily.
someService.readDisk(10);
}
context.unbindService(connection);
}
}

View File

@@ -0,0 +1,150 @@
/*
* 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.
*/
package android.text;
import static android.text.Layout.Alignment.ALIGN_NORMAL;
import android.graphics.Canvas;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.support.test.filters.LargeTest;
import android.text.NonEditableTextGenerator.TextType;
import android.view.DisplayListCanvas;
import android.view.RenderNode;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Random;
/**
* Performance test for {@link BoringLayout} create and draw.
*/
@LargeTest
@RunWith(Parameterized.class)
public class BoringLayoutCreateDrawPerfTest {
private static final boolean[] BOOLEANS = new boolean[]{false, true};
private static final float SPACING_ADD = 10f;
private static final float SPACING_MULT = 1.5f;
@Parameterized.Parameters(name = "cached={3},{1}chars,{0}")
public static Collection cases() {
final List<Object[]> params = new ArrayList<>();
for (int length : new int[]{128}) {
for (boolean cached : BOOLEANS) {
for (TextType textType : new TextType[]{TextType.STRING,
TextType.SPANNABLE_BUILDER}) {
params.add(new Object[]{textType.name(), length, textType, cached});
}
}
}
return params;
}
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private final int mLength;
private final TextType mTextType;
private final boolean mCached;
private final TextPaint mTextPaint;
public BoringLayoutCreateDrawPerfTest(String label, int length, TextType textType,
boolean cached) {
mLength = length;
mCached = cached;
mTextType = textType;
mTextPaint = new TextPaint();
mTextPaint.setTextSize(10);
}
/**
* Measures the creation time for {@link BoringLayout}.
*/
@Test
public void timeCreate() throws Exception {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
state.pauseTiming();
Canvas.freeTextLayoutCaches();
final CharSequence text = createRandomText();
// isBoring result is calculated in another test, we want to measure only the
// create time for Boring without isBoring check. Therefore it is calculated here.
final BoringLayout.Metrics metrics = BoringLayout.isBoring(text, mTextPaint);
if (mCached) createLayout(text, metrics);
state.resumeTiming();
while (state.keepRunning()) {
state.pauseTiming();
if (!mCached) Canvas.freeTextLayoutCaches();
state.resumeTiming();
createLayout(text, metrics);
}
}
/**
* Measures the draw time for {@link BoringLayout} or {@link StaticLayout}.
*/
@Test
public void timeDraw() throws Throwable {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
state.pauseTiming();
Canvas.freeTextLayoutCaches();
final RenderNode node = RenderNode.create("benchmark", null);
final CharSequence text = createRandomText();
final BoringLayout.Metrics metrics = BoringLayout.isBoring(text, mTextPaint);
final Layout layout = createLayout(text, metrics);
state.resumeTiming();
while (state.keepRunning()) {
state.pauseTiming();
final DisplayListCanvas canvas = node.start(1200, 200);
final int save = canvas.save();
if (!mCached) Canvas.freeTextLayoutCaches();
state.resumeTiming();
layout.draw(canvas);
state.pauseTiming();
canvas.restoreToCount(save);
node.end(canvas);
state.resumeTiming();
}
}
private CharSequence createRandomText() {
return new NonEditableTextGenerator(new Random(0))
.setSequenceLength(mLength)
.setCreateBoring(true)
.setTextType(mTextType)
.build();
}
private Layout createLayout(CharSequence text,
BoringLayout.Metrics metrics) {
return BoringLayout.make(text, mTextPaint, Integer.MAX_VALUE /*width*/,
ALIGN_NORMAL, SPACING_MULT, SPACING_ADD, metrics, true /*includePad*/);
}
}

View File

@@ -0,0 +1,109 @@
/*
* 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.
*/
package android.text;
import android.graphics.Canvas;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.support.test.filters.LargeTest;
import android.text.NonEditableTextGenerator.TextType;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Random;
/**
* Performance test for {@link BoringLayout#isBoring(CharSequence, TextPaint)}.
*/
@LargeTest
@RunWith(Parameterized.class)
public class BoringLayoutIsBoringPerfTest {
private static final boolean[] BOOLEANS = new boolean[]{false, true};
@Parameterized.Parameters(name = "cached={4},{1}chars,{0}")
public static Collection cases() {
final List<Object[]> params = new ArrayList<>();
for (int length : new int[]{128}) {
for (boolean boring : BOOLEANS) {
for (boolean cached : BOOLEANS) {
for (TextType textType : new TextType[]{TextType.STRING,
TextType.SPANNABLE_BUILDER}) {
params.add(new Object[]{
(boring ? "Boring" : "NotBoring") + "," + textType.name(),
length, boring, textType, cached});
}
}
}
}
return params;
}
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private final int mLength;
private final TextType mTextType;
private final boolean mCreateBoring;
private final boolean mCached;
private final TextPaint mTextPaint;
public BoringLayoutIsBoringPerfTest(String label, int length, boolean boring, TextType textType,
boolean cached) {
mLength = length;
mCreateBoring = boring;
mCached = cached;
mTextType = textType;
mTextPaint = new TextPaint();
mTextPaint.setTextSize(10);
}
/**
* Measure the time for the {@link BoringLayout#isBoring(CharSequence, TextPaint)}.
*/
@Test
public void timeIsBoring() throws Exception {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
state.pauseTiming();
Canvas.freeTextLayoutCaches();
final CharSequence text = createRandomText();
if (mCached) BoringLayout.isBoring(text, mTextPaint);
state.resumeTiming();
while (state.keepRunning()) {
state.pauseTiming();
if (!mCached) Canvas.freeTextLayoutCaches();
state.resumeTiming();
BoringLayout.isBoring(text, mTextPaint);
}
}
private CharSequence createRandomText() {
return new NonEditableTextGenerator(new Random(0))
.setSequenceLength(mLength)
.setCreateBoring(mCreateBoring)
.setTextType(mTextType)
.build();
}
}

View File

@@ -16,35 +16,28 @@
package android.text;
import android.app.Activity;
import static android.text.Layout.Alignment.ALIGN_NORMAL;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.FontMetricsInt;
import android.os.Bundle;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.perftests.utils.StubActivity;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.text.style.ReplacementSpan;
import android.util.ArraySet;
import static android.text.Layout.Alignment.ALIGN_NORMAL;
import java.util.Arrays;
import java.util.Collection;
import java.util.Locale;
import java.util.Random;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameters;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import java.util.Arrays;
import java.util.Collection;
import java.util.Random;
@LargeTest
@RunWith(Parameterized.class)

View File

@@ -0,0 +1,138 @@
package android.text;
import static android.text.Spanned.SPAN_INCLUSIVE_INCLUSIVE;
import android.text.style.BulletSpan;
import java.util.Random;
/**
*
*/
public class NonEditableTextGenerator {
enum TextType {
STRING,
SPANNED,
SPANNABLE_BUILDER
}
private boolean mCreateBoring;
private TextType mTextType;
private int mSequenceLength;
private final Random mRandom;
public NonEditableTextGenerator(Random random) {
mRandom = random;
}
public NonEditableTextGenerator setCreateBoring(boolean createBoring) {
mCreateBoring = createBoring;
return this;
}
public NonEditableTextGenerator setTextType(TextType textType) {
mTextType = textType;
return this;
}
public NonEditableTextGenerator setSequenceLength(int sequenceLength) {
mSequenceLength = sequenceLength;
return this;
}
/**
* Sample charSequence generated:
* NRjPzjvUadHmH ExoEoTqfx pCLw qtndsqfpk AqajVCbgjGZ igIeC dfnXRgA
*/
public CharSequence build() {
final RandomCharSequenceGenerator sequenceGenerator = new RandomCharSequenceGenerator(
mRandom);
if (mSequenceLength > 0) {
sequenceGenerator.setSequenceLength(mSequenceLength);
}
final CharSequence charSequence = sequenceGenerator.buildLatinSequence();
switch (mTextType) {
case SPANNED:
case SPANNABLE_BUILDER:
return createSpannable(charSequence);
case STRING:
default:
return createString(charSequence);
}
}
private Spannable createSpannable(CharSequence charSequence) {
final Spannable spannable = (mTextType == TextType.SPANNABLE_BUILDER) ?
new SpannableStringBuilder(charSequence) : new SpannableString(charSequence);
if (!mCreateBoring) {
// add a paragraph style to make it non boring
spannable.setSpan(new BulletSpan(), 0, spannable.length(), SPAN_INCLUSIVE_INCLUSIVE);
}
spannable.setSpan(new Object(), 0, spannable.length(), SPAN_INCLUSIVE_INCLUSIVE);
spannable.setSpan(new Object(), 0, 1, SPAN_INCLUSIVE_INCLUSIVE);
return spannable;
}
private String createString(CharSequence charSequence) {
if (mCreateBoring) {
return charSequence.toString();
} else {
// BoringLayout checks to see if there is a surrogate pair and if so tells that
// the charSequence is not suitable for boring. Add an emoji to make it non boring.
// Emoji is added instead of RTL, since emoji stays in the same run and is a more
// common case.
return charSequence.toString() + "\uD83D\uDC68\uD83C\uDFFF";
}
}
public static class RandomCharSequenceGenerator {
private static final int DEFAULT_MIN_WORD_LENGTH = 3;
private static final int DEFAULT_MAX_WORD_LENGTH = 15;
private static final int DEFAULT_SEQUENCE_LENGTH = 256;
private int mMinWordLength = DEFAULT_MIN_WORD_LENGTH;
private int mMaxWordLength = DEFAULT_MAX_WORD_LENGTH;
private int mSequenceLength = DEFAULT_SEQUENCE_LENGTH;
private final Random mRandom;
public RandomCharSequenceGenerator(Random random) {
mRandom = random;
}
public RandomCharSequenceGenerator setSequenceLength(int sequenceLength) {
mSequenceLength = sequenceLength;
return this;
}
public CharSequence buildLatinSequence() {
final StringBuilder result = new StringBuilder();
while (result.length() < mSequenceLength) {
// add random word
result.append(buildLatinWord());
result.append(' ');
}
return result.substring(0, mSequenceLength);
}
public CharSequence buildLatinWord() {
final StringBuilder result = new StringBuilder();
// create a random length that is (mMinWordLength + random amount of chars) where
// total size is less than mMaxWordLength
final int length = mRandom.nextInt(mMaxWordLength - mMinWordLength) + mMinWordLength;
while (result.length() < length) {
// add random letter
int base = mRandom.nextInt(2) == 0 ? 'A' : 'a';
result.append(Character.toChars(mRandom.nextInt(26) + base));
}
return result.toString();
}
}
}

View File

@@ -0,0 +1,131 @@
/*
* 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.
*/
package android.text;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.support.test.filters.LargeTest;
import android.view.DisplayListCanvas;
import android.view.RenderNode;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Random;
/**
* Performance test for single line measure and draw using {@link Paint} and {@link Canvas}.
*/
@LargeTest
@RunWith(Parameterized.class)
public class PaintMeasureDrawPerfTest {
private static final boolean[] BOOLEANS = new boolean[]{false, true};
@Parameterized.Parameters(name = "cached={1},{0}chars")
public static Collection cases() {
final List<Object[]> params = new ArrayList<>();
for (int length : new int[]{128}) {
for (boolean cached : BOOLEANS) {
params.add(new Object[]{length, cached});
}
}
return params;
}
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private final int mLength;
private final boolean mCached;
private final TextPaint mTextPaint;
public PaintMeasureDrawPerfTest(int length, boolean cached) {
mLength = length;
mCached = cached;
mTextPaint = new TextPaint();
mTextPaint.setTextSize(10);
}
/**
* Measure the time for {@link Paint#measureText(String)}
*/
@Test
public void timeMeasure() throws Exception {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
state.pauseTiming();
Canvas.freeTextLayoutCaches();
final String text = createRandomText();
if (mCached) mTextPaint.measureText(text);
state.resumeTiming();
while (state.keepRunning()) {
state.pauseTiming();
if (!mCached) Canvas.freeTextLayoutCaches();
state.resumeTiming();
mTextPaint.measureText(text);
}
}
/**
* Measures the time for {@link Canvas#drawText(String, float, float, Paint)}
*/
@Test
public void timeDraw() throws Throwable {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
state.pauseTiming();
Canvas.freeTextLayoutCaches();
final RenderNode node = RenderNode.create("benchmark", null);
final String text = createRandomText();
if (mCached) mTextPaint.measureText(text);
state.resumeTiming();
while (state.keepRunning()) {
state.pauseTiming();
final DisplayListCanvas canvas = node.start(1200, 200);
final int save = canvas.save();
if (!mCached) Canvas.freeTextLayoutCaches();
state.resumeTiming();
canvas.drawText(text, 0 /*x*/, 100 /*y*/, mTextPaint);
state.pauseTiming();
canvas.restoreToCount(save);
node.end(canvas);
state.resumeTiming();
}
}
private String createRandomText() {
return (String) new NonEditableTextGenerator(new Random(0))
.setSequenceLength(mLength)
.setCreateBoring(true)
.setTextType(NonEditableTextGenerator.TextType.STRING)
.build();
}
}

View File

@@ -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.
*/
package android.text;
import static android.text.TextDirectionHeuristics.LTR;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import android.app.Activity;
import android.os.Bundle;
import android.support.test.InstrumentationRegistry;
import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.Typeface;
import android.text.Layout;
import android.text.style.TextAppearanceSpan;
import android.view.DisplayListCanvas;
import android.view.RenderNode;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.nio.CharBuffer;
import java.util.Random;
@LargeTest
@RunWith(AndroidJUnit4.class)
public class PrecomputedTextMemoryUsageTest {
private static final int WORD_LENGTH = 9; // Random word has 9 characters.
private static final boolean NO_STYLE_TEXT = false;
private static TextPaint PAINT = new TextPaint();
private static int TRIAL_COUNT = 100;
public PrecomputedTextMemoryUsageTest() {}
private TextPerfUtils mTextUtil = new TextPerfUtils();
@Before
public void setUp() {
mTextUtil.resetRandom(0 /* seed */);
}
private void reportMemoryUsage(int memoryUsage, String key) {
Bundle status = new Bundle();
status.putInt(key + "_median", memoryUsage);
InstrumentationRegistry.getInstrumentation().sendStatus(Activity.RESULT_OK, status);
}
private int median(int[] values) {
return values.length % 2 == 0 ?
(values[values.length / 2] + values[values.length / 2 - 1]) / 2:
values[values.length / 2];
}
@Test
public void testMemoryUsage_NoHyphenation() {
int[] memories = new int[TRIAL_COUNT];
final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
.build();
// Report median of randomly generated PrecomputedText.
for (int i = 0; i < TRIAL_COUNT; ++i) {
memories[i] = PrecomputedText.create(
mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), param)
.getMemoryUsage();
}
reportMemoryUsage(median(memories), "MemoryUsage_NoHyphenation");
}
@Test
public void testMemoryUsage_Hyphenation() {
int[] memories = new int[TRIAL_COUNT];
final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.build();
// Report median of randomly generated PrecomputedText.
for (int i = 0; i < TRIAL_COUNT; ++i) {
memories[i] = PrecomputedText.create(
mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), param)
.getMemoryUsage();
}
reportMemoryUsage(median(memories), "MemoryUsage_Hyphenation");
}
@Test
public void testMemoryUsage_NoHyphenation_WidthOnly() {
int[] memories = new int[TRIAL_COUNT];
final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
.build();
// Report median of randomly generated PrecomputedText.
for (int i = 0; i < TRIAL_COUNT; ++i) {
CharSequence cs = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
PrecomputedText.ParagraphInfo[] paragraphInfo =
PrecomputedText.createMeasuredParagraphs(cs, param, 0, cs.length(), false);
memories[i] = 0;
for (PrecomputedText.ParagraphInfo info : paragraphInfo) {
memories[i] += info.measured.getMemoryUsage();
}
}
reportMemoryUsage(median(memories), "MemoryUsage_NoHyphenation_WidthOnly");
}
@Test
public void testMemoryUsage_Hyphenatation_WidthOnly() {
int[] memories = new int[TRIAL_COUNT];
final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.build();
// Report median of randomly generated PrecomputedText.
for (int i = 0; i < TRIAL_COUNT; ++i) {
CharSequence cs = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
PrecomputedText.ParagraphInfo[] paragraphInfo =
PrecomputedText.createMeasuredParagraphs(cs, param, 0, cs.length(), false);
memories[i] = 0;
for (PrecomputedText.ParagraphInfo info : paragraphInfo) {
memories[i] += info.measured.getMemoryUsage();
}
}
reportMemoryUsage(median(memories), "MemoryUsage_Hyphenation_WidthOnly");
}
}

View File

@@ -0,0 +1,201 @@
/*
* 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.text;
import static android.text.TextDirectionHeuristics.LTR;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.Typeface;
import android.text.Layout;
import android.text.style.TextAppearanceSpan;
import android.view.DisplayListCanvas;
import android.view.RenderNode;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.nio.CharBuffer;
import java.util.Random;
@LargeTest
@RunWith(AndroidJUnit4.class)
public class PrecomputedTextPerfTest {
private static final int WORD_LENGTH = 9; // Random word has 9 characters.
private static final int WORDS_IN_LINE = 8; // Roughly, 8 words in a line.
private static final boolean NO_STYLE_TEXT = false;
private static final boolean STYLE_TEXT = true;
private static TextPaint PAINT = new TextPaint();
private static final int TEXT_WIDTH = WORDS_IN_LINE * WORD_LENGTH * (int) PAINT.getTextSize();
public PrecomputedTextPerfTest() {}
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private TextPerfUtils mTextUtil = new TextPerfUtils();
@Before
public void setUp() {
mTextUtil.resetRandom(0 /* seed */);
}
@Test
public void testCreate_NoStyled_Hyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.build();
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
state.resumeTiming();
PrecomputedText.create(text, param);
}
}
@Test
public void testCreate_NoStyled_NoHyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
.build();
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
state.resumeTiming();
PrecomputedText.create(text, param);
}
}
@Test
public void testCreate_NoStyled_Hyphenation_WidthOnly() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.build();
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
state.resumeTiming();
PrecomputedText.create(text, param);
}
}
@Test
public void testCreate_NoStyled_NoHyphenation_WidthOnly() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
.build();
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
state.resumeTiming();
PrecomputedText.create(text, param);
}
}
@Test
public void testCreate_Styled_Hyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.build();
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT);
state.resumeTiming();
PrecomputedText.create(text, param);
}
}
@Test
public void testCreate_Styled_NoHyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
.build();
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT);
state.resumeTiming();
PrecomputedText.create(text, param);
}
}
@Test
public void testCreate_Styled_Hyphenation_WidthOnly() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.build();
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT);
state.resumeTiming();
PrecomputedText.create(text, param);
}
}
@Test
public void testCreate_Styled_NoHyphenation_WidthOnly() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final PrecomputedText.Params param = new PrecomputedText.Params.Builder(PAINT)
.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
.build();
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT);
state.resumeTiming();
PrecomputedText.create(text, param);
}
}
}

View File

@@ -0,0 +1,151 @@
/*
* 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.
*/
package android.text;
import static android.text.Layout.Alignment.ALIGN_NORMAL;
import android.graphics.Canvas;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.support.test.filters.LargeTest;
import android.text.NonEditableTextGenerator.TextType;
import android.view.DisplayListCanvas;
import android.view.RenderNode;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Random;
/**
* Performance test for multi line, single style {@link StaticLayout} creation/draw.
*/
@LargeTest
@RunWith(Parameterized.class)
public class StaticLayoutCreateDrawPerfTest {
private static final boolean[] BOOLEANS = new boolean[]{false, true};
private static final float SPACING_ADD = 10f;
private static final float SPACING_MULT = 1.5f;
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Parameterized.Parameters(name = "cached={3},{1}chars,{0}")
public static Collection cases() {
final List<Object[]> params = new ArrayList<>();
for (int length : new int[]{128}) {
for (boolean cached : BOOLEANS) {
for (TextType textType : new TextType[]{TextType.STRING,
TextType.SPANNABLE_BUILDER}) {
params.add(new Object[]{textType.name(), length, textType, cached});
}
}
}
return params;
}
private final int mLineWidth;
private final int mLength;
private final TextType mTextType;
private final boolean mCached;
private final TextPaint mTextPaint;
public StaticLayoutCreateDrawPerfTest(String label, int length, TextType textType,
boolean cached) {
mLength = length;
mTextType = textType;
mCached = cached;
mTextPaint = new TextPaint();
mTextPaint.setTextSize(10);
mLineWidth = Integer.MAX_VALUE;
}
/**
* Measures the creation time for a multi line {@link StaticLayout}.
*/
@Test
public void timeCreate() throws Exception {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
state.pauseTiming();
Canvas.freeTextLayoutCaches();
final CharSequence text = createRandomText(mLength);
createLayout(text);
state.resumeTiming();
while (state.keepRunning()) {
state.pauseTiming();
if (!mCached) Canvas.freeTextLayoutCaches();
state.resumeTiming();
createLayout(text);
}
}
/**
* Measures the draw time for a multi line {@link StaticLayout}.
*/
@Test
public void timeDraw() throws Exception {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
state.pauseTiming();
Canvas.freeTextLayoutCaches();
final RenderNode node = RenderNode.create("benchmark", null);
final CharSequence text = createRandomText(mLength);
final Layout layout = createLayout(text);
state.resumeTiming();
while (state.keepRunning()) {
state.pauseTiming();
final DisplayListCanvas canvas = node.start(1200, 200);
int save = canvas.save();
if (!mCached) Canvas.freeTextLayoutCaches();
state.resumeTiming();
layout.draw(canvas);
state.pauseTiming();
canvas.restoreToCount(save);
node.end(canvas);
state.resumeTiming();
}
}
private Layout createLayout(CharSequence text) {
return StaticLayout.Builder.obtain(text, 0 /*start*/, text.length() /*end*/, mTextPaint,
mLineWidth)
.setAlignment(ALIGN_NORMAL)
.setIncludePad(true)
.setLineSpacing(SPACING_ADD, SPACING_MULT)
.build();
}
private CharSequence createRandomText(int length) {
return new NonEditableTextGenerator(new Random(0))
.setSequenceLength(length)
.setTextType(mTextType)
.build();
}
}

View File

@@ -0,0 +1,134 @@
/*
* 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.text;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.TimeUnit;
@LargeTest
@RunWith(AndroidJUnit4.class)
public class StaticLayoutMultithreadPerfTest {
private static final int WORD_LENGTH = 9; // Random word has 9 characters.
private static final int WORDS_IN_LINE = 8; // Roughly, 8 words in a line.
private static final boolean NO_STYLE_TEXT = false;
private static TextPaint PAINT = new TextPaint();
private static final int TEXT_WIDTH = WORDS_IN_LINE * WORD_LENGTH * (int) PAINT.getTextSize();
public StaticLayoutMultithreadPerfTest() {}
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private CountDownLatch mStartLatch;
private AtomicBoolean mThreadState; // True for running, False for stopped.
private static final long TIMEOUT_MS = 5000;
private Thread[] startBackgroundThread(int numOfThreads) {
mStartLatch = new CountDownLatch(numOfThreads);
mThreadState = new AtomicBoolean(true);
Thread[] threads = new Thread[numOfThreads];
for (int i = 0; i < numOfThreads; ++i) {
final int seed = i + 1;
threads[i] = new Thread(new Runnable() {
@Override
public void run() {
final TextPerfUtils util = new TextPerfUtils();
util.resetRandom(seed);
mStartLatch.countDown();
while (mThreadState.get()) {
final CharSequence text = util.nextRandomParagraph(
WORD_LENGTH, NO_STYLE_TEXT);
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
.build();
}
}
});
}
for (int i = 0; i < numOfThreads; ++i) {
threads[i].start();
}
try {
mStartLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return threads;
}
private void finishThreads(Thread[] threads) {
mThreadState.set(false);
for (Thread thread : threads) {
try {
thread.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
mStartLatch = null;
mThreadState = null;
}
private void runRandomTest(int numOfTotalThreads) {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final TextPerfUtils util = new TextPerfUtils();
Thread[] threads = startBackgroundThread(numOfTotalThreads - 1);
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = util.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
state.resumeTiming();
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
.build();
}
finishThreads(threads);
}
@Test
public void testCreate_RandomText_Thread_1() {
runRandomTest(1);
}
@Test
public void testCreate_RandomText_Thread_2() {
runRandomTest(2);
}
@Test
public void testCreate_RandomText_Thread_4() {
runRandomTest(4);
}
}

View File

@@ -0,0 +1,402 @@
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package android.text;
import static android.text.TextDirectionHeuristics.LTR;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.Typeface;
import android.text.Layout;
import android.text.style.TextAppearanceSpan;
import android.view.DisplayListCanvas;
import android.view.RenderNode;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.nio.CharBuffer;
import java.util.Random;
@LargeTest
@RunWith(AndroidJUnit4.class)
public class StaticLayoutPerfTest {
private static final int WORD_LENGTH = 9; // Random word has 9 characters.
private static final int WORDS_IN_LINE = 8; // Roughly, 8 words in a line.
private static final boolean NO_STYLE_TEXT = false;
private static final boolean STYLE_TEXT = true;
private static TextPaint PAINT = new TextPaint();
private static final int TEXT_WIDTH = WORDS_IN_LINE * WORD_LENGTH * (int) PAINT.getTextSize();
public StaticLayoutPerfTest() {}
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private TextPerfUtils mTextUtil = new TextPerfUtils();
@Before
public void setUp() {
mTextUtil.resetRandom(0 /* seed */);
}
private PrecomputedText makeMeasured(CharSequence text, TextPaint paint) {
PrecomputedText.Params param = new PrecomputedText.Params.Builder(paint).build();
return PrecomputedText.create(text, param);
}
private PrecomputedText makeMeasured(CharSequence text, TextPaint paint, int strategy,
int frequency) {
PrecomputedText.Params param = new PrecomputedText.Params.Builder(paint)
.setHyphenationFrequency(frequency).setBreakStrategy(strategy).build();
return PrecomputedText.create(text, param);
}
@Test
public void testCreate_FixedText_NoStyle_Greedy_NoHyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
while (state.keepRunning()) {
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
.build();
}
}
@Test
public void testCreate_RandomText_NoStyled_Greedy_NoHyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
state.resumeTiming();
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
.build();
}
}
@Test
public void testCreate_RandomText_NoStyled_Greedy_Hyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
state.resumeTiming();
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
.build();
}
}
@Test
public void testCreate_RandomText_NoStyled_Balanced_NoHyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
state.resumeTiming();
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
.build();
}
}
@Test
public void testCreate_RandomText_NoStyled_Balanced_Hyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
state.resumeTiming();
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
.build();
}
}
@Test
public void testCreate_RandomText_Styled_Greedy_NoHyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT);
state.resumeTiming();
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
.build();
}
}
@Test
public void testCreate_PrecomputedText_NoStyled_Greedy_NoHyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
state.pauseTiming();
final PrecomputedText text = makeMeasured(
mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT,
Layout.BREAK_STRATEGY_SIMPLE, Layout.HYPHENATION_FREQUENCY_NONE);
state.resumeTiming();
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
.build();
}
}
@Test
public void testCreate_PrecomputedText_NoStyled_Greedy_Hyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
state.pauseTiming();
final PrecomputedText text = makeMeasured(
mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT,
Layout.BREAK_STRATEGY_SIMPLE, Layout.HYPHENATION_FREQUENCY_NORMAL);
state.resumeTiming();
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
.build();
}
}
@Test
public void testCreate_PrecomputedText_NoStyled_Balanced_NoHyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
state.pauseTiming();
final PrecomputedText text = makeMeasured(
mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT,
Layout.BREAK_STRATEGY_BALANCED, Layout.HYPHENATION_FREQUENCY_NONE);
state.resumeTiming();
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
.build();
}
}
@Test
public void testCreate_PrecomputedText_NoStyled_Balanced_Hyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
state.pauseTiming();
final PrecomputedText text = makeMeasured(
mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT,
Layout.BREAK_STRATEGY_BALANCED, Layout.HYPHENATION_FREQUENCY_NORMAL);
state.resumeTiming();
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED)
.build();
}
}
@Test
public void testCreate_PrecomputedText_Styled_Greedy_NoHyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
while (state.keepRunning()) {
state.pauseTiming();
final PrecomputedText text = makeMeasured(
mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT,
Layout.BREAK_STRATEGY_SIMPLE, Layout.HYPHENATION_FREQUENCY_NONE);
state.resumeTiming();
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
.build();
}
}
@Test
public void testDraw_FixedText_NoStyled() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
final RenderNode node = RenderNode.create("benchmark", null);
while (state.keepRunning()) {
state.pauseTiming();
final StaticLayout layout =
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
final DisplayListCanvas c = node.start(1200, 200);
state.resumeTiming();
layout.draw(c);
}
}
@Test
public void testDraw_RandomText_Styled() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final RenderNode node = RenderNode.create("benchmark", null);
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT);
final StaticLayout layout =
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
final DisplayListCanvas c = node.start(1200, 200);
state.resumeTiming();
layout.draw(c);
}
}
@Test
public void testDraw_RandomText_NoStyled() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final RenderNode node = RenderNode.create("benchmark", null);
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
final StaticLayout layout =
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
final DisplayListCanvas c = node.start(1200, 200);
state.resumeTiming();
layout.draw(c);
}
}
@Test
public void testDraw_RandomText_Styled_WithoutCache() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final RenderNode node = RenderNode.create("benchmark", null);
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT);
final StaticLayout layout =
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
final DisplayListCanvas c = node.start(1200, 200);
Canvas.freeTextLayoutCaches();
state.resumeTiming();
layout.draw(c);
}
}
@Test
public void testDraw_RandomText_NoStyled_WithoutCache() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final RenderNode node = RenderNode.create("benchmark", null);
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
final StaticLayout layout =
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
final DisplayListCanvas c = node.start(1200, 200);
Canvas.freeTextLayoutCaches();
state.resumeTiming();
layout.draw(c);
}
}
@Test
public void testDraw_PrecomputedText_Styled() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final RenderNode node = RenderNode.create("benchmark", null);
while (state.keepRunning()) {
state.pauseTiming();
final PrecomputedText text = makeMeasured(
mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT);
final StaticLayout layout =
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
final DisplayListCanvas c = node.start(1200, 200);
state.resumeTiming();
layout.draw(c);
}
}
@Test
public void testDraw_PrecomputedText_NoStyled() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final RenderNode node = RenderNode.create("benchmark", null);
while (state.keepRunning()) {
state.pauseTiming();
final PrecomputedText text = makeMeasured(
mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT);
final StaticLayout layout =
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
final DisplayListCanvas c = node.start(1200, 200);
state.resumeTiming();
layout.draw(c);
}
}
@Test
public void testDraw_PrecomputedText_Styled_WithoutCache() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final RenderNode node = RenderNode.create("benchmark", null);
while (state.keepRunning()) {
state.pauseTiming();
final PrecomputedText text = makeMeasured(
mTextUtil.nextRandomParagraph(WORD_LENGTH, STYLE_TEXT), PAINT);
final StaticLayout layout =
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
final DisplayListCanvas c = node.start(1200, 200);
Canvas.freeTextLayoutCaches();
state.resumeTiming();
layout.draw(c);
}
}
@Test
public void testDraw_PrecomputedText_NoStyled_WithoutCache() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final RenderNode node = RenderNode.create("benchmark", null);
while (state.keepRunning()) {
state.pauseTiming();
final PrecomputedText text = makeMeasured(
mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), PAINT);
final StaticLayout layout =
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH).build();
final DisplayListCanvas c = node.start(1200, 200);
Canvas.freeTextLayoutCaches();
state.resumeTiming();
layout.draw(c);
}
}
}

View File

@@ -0,0 +1,93 @@
/*
* 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.text;
import static android.text.TextDirectionHeuristics.LTR;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import android.content.res.ColorStateList;
import android.graphics.Canvas;
import android.graphics.Typeface;
import android.text.Layout;
import android.text.style.TextAppearanceSpan;
import android.view.DisplayListCanvas;
import android.view.RenderNode;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.nio.CharBuffer;
import java.util.Random;
public class TextPerfUtils {
private static final int PARA_LENGTH = 500; // Number of characters in a paragraph.
private Random mRandom = new Random(0);
private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
private static final int ALPHABET_LENGTH = ALPHABET.length();
private static final ColorStateList TEXT_COLOR = ColorStateList.valueOf(0x00000000);
private static final String[] FAMILIES = { "sans-serif", "serif", "monospace" };
private static final int[] STYLES = {
Typeface.NORMAL, Typeface.BOLD, Typeface.ITALIC, Typeface.BOLD_ITALIC
};
private final char[] mBuffer = new char[PARA_LENGTH];
public void resetRandom(long seed) {
mRandom = new Random(seed);
}
public CharSequence nextRandomParagraph(int wordLen, boolean applyRandomStyle) {
for (int i = 0; i < PARA_LENGTH; i++) {
if (i % (wordLen + 1) == wordLen) {
mBuffer[i] = ' ';
} else {
mBuffer[i] = ALPHABET.charAt(mRandom.nextInt(ALPHABET_LENGTH));
}
}
CharSequence cs = CharBuffer.wrap(mBuffer);
if (!applyRandomStyle) {
return cs;
}
SpannableStringBuilder ssb = new SpannableStringBuilder(cs);
for (int i = 0; i < ssb.length(); i += wordLen + 1) {
final int spanStart = i;
final int spanEnd = (i + wordLen) > ssb.length() ? ssb.length() : i + wordLen;
final TextAppearanceSpan span = new TextAppearanceSpan(
FAMILIES[mRandom.nextInt(FAMILIES.length)],
STYLES[mRandom.nextInt(STYLES.length)],
24 + mRandom.nextInt(32), // text size. min 24 max 56
TEXT_COLOR, TEXT_COLOR);
ssb.setSpan(span, spanStart, spanEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
}
return ssb;
}
}

View File

@@ -0,0 +1,151 @@
/*
* 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.
*/
package android.text;
import static android.view.View.MeasureSpec.AT_MOST;
import static android.view.View.MeasureSpec.UNSPECIFIED;
import android.graphics.Canvas;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.text.NonEditableTextGenerator.TextType;
import android.view.DisplayListCanvas;
import android.view.RenderNode;
import android.widget.TextView;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
import java.util.Random;
/**
* Performance test for {@link TextView} measure/draw.
*/
@LargeTest
@RunWith(Parameterized.class)
public class TextViewSetTextMeasurePerfTest {
private static final boolean[] BOOLEANS = new boolean[]{false, true};
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Parameterized.Parameters(name = "cached={3},{1}chars,{0}")
public static Collection cases() {
final List<Object[]> params = new ArrayList<>();
for (int length : new int[]{128}) {
for (boolean cached : BOOLEANS) {
for (TextType textType : new TextType[]{TextType.STRING,
TextType.SPANNABLE_BUILDER}) {
params.add(new Object[]{textType.name(), length, textType, cached});
}
}
}
return params;
}
private final int mLineWidth;
private final int mLength;
private final TextType mTextType;
private final boolean mCached;
private final TextPaint mTextPaint;
public TextViewSetTextMeasurePerfTest(String label, int length, TextType textType,
boolean cached) {
mLength = length;
mTextType = textType;
mCached = cached;
mTextPaint = new TextPaint();
mTextPaint.setTextSize(10);
mLineWidth = Integer.MAX_VALUE;
}
/**
* Measures the time to setText and measure for a {@link TextView}.
*/
@Test
public void timeCreate() throws Exception {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
state.pauseTiming();
Canvas.freeTextLayoutCaches();
final CharSequence text = createRandomText(mLength);
final TextView textView = new TextView(InstrumentationRegistry.getTargetContext());
textView.setText(text);
state.resumeTiming();
while (state.keepRunning()) {
state.pauseTiming();
textView.setTextLocale(Locale.UK);
textView.setTextLocale(Locale.US);
if (!mCached) Canvas.freeTextLayoutCaches();
state.resumeTiming();
textView.setText(text);
textView.measure(AT_MOST | mLineWidth, UNSPECIFIED);
}
}
/**
* Measures the time to draw for a {@link TextView}.
*/
@Test
public void timeDraw() throws Exception {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
state.pauseTiming();
Canvas.freeTextLayoutCaches();
final RenderNode node = RenderNode.create("benchmark", null);
final CharSequence text = createRandomText(mLength);
final TextView textView = new TextView(InstrumentationRegistry.getTargetContext());
textView.setText(text);
state.resumeTiming();
while (state.keepRunning()) {
state.pauseTiming();
final DisplayListCanvas canvas = node.start(1200, 200);
int save = canvas.save();
textView.setTextLocale(Locale.UK);
textView.setTextLocale(Locale.US);
if (!mCached) Canvas.freeTextLayoutCaches();
state.resumeTiming();
textView.draw(canvas);
state.pauseTiming();
canvas.restoreToCount(save);
node.end(canvas);
state.resumeTiming();
}
}
private CharSequence createRandomText(int length) {
return new NonEditableTextGenerator(new Random(0))
.setSequenceLength(length)
.setCreateBoring(false)
.setTextType(mTextType)
.build();
}
}

View File

@@ -16,31 +16,26 @@
package android.widget;
import android.app.Activity;
import android.os.Bundle;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.perftests.utils.StubActivity;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.rule.ActivityTestRule;
import android.text.Selection;
import android.view.KeyEvent;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import java.util.Arrays;
import java.util.Collection;
import java.util.Locale;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameters;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import java.util.Arrays;
import java.util.Collection;
@LargeTest
@RunWith(Parameterized.class)

View File

@@ -16,31 +16,26 @@
package android.widget;
import android.app.Activity;
import android.os.Bundle;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.perftests.utils.StubActivity;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.rule.ActivityTestRule;
import android.text.Selection;
import android.view.KeyEvent;
import android.view.View.MeasureSpec;
import android.view.ViewGroup;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import java.util.Arrays;
import java.util.Collection;
import java.util.Locale;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameters;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import java.util.Arrays;
import java.util.Collection;
@LargeTest
@RunWith(Parameterized.class)

View File

@@ -0,0 +1,156 @@
/*
* 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
*/
package android.widget;
import static android.view.View.MeasureSpec.AT_MOST;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.UNSPECIFIED;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Typeface;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.TextAppearanceSpan;
import android.view.LayoutInflater;
import com.android.perftests.core.R;
import java.util.Random;
import java.util.Locale;
import org.junit.Test;
import org.junit.Rule;
import org.junit.runner.RunWith;
import static org.junit.Assert.assertTrue;
@LargeTest
@RunWith(AndroidJUnit4.class)
public class TextViewOnMeasurePerfTest {
private static final String MULTILINE_TEXT =
"Lorem ipsum dolor sit amet, \n"+
"consectetur adipiscing elit, \n" +
"sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. \n" +
"Ut enim ad minim veniam, \n" +
"quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n" +
"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat " +
"nulla pariatur.\n" +
"Excepteur sint occaecat cupidatat non proident, \n" +
"sunt in culpa qui officia deserunt mollit anim id est laborum.\n";
private static final int VIEW_WIDTH = 1000;
private static final int VIEW_HEIGHT = 1000;
private static final CharSequence COMPLEX_MULTILINE_TEXT;
static {
final SpannableStringBuilder ssb = new SpannableStringBuilder();
// To emphasize, append multiline text 10 times.
for (int i = 0; i < 10; ++i) {
ssb.append(MULTILINE_TEXT);
}
final ColorStateList[] COLORS = {
ColorStateList.valueOf(0xFFFF0000), // RED
ColorStateList.valueOf(0xFF00FF00), // GREEN
ColorStateList.valueOf(0xFF0000FF), // BLUE
};
final int[] STYLES = {
Typeface.NORMAL, Typeface.BOLD, Typeface.ITALIC, Typeface.BOLD_ITALIC
};
final String[] FAMILIES = { "sans-serif", "serif", "monospace" };
// Append random span to text.
final Random random = new Random(0);
for (int pos = 0; pos < ssb.length();) {
final TextAppearanceSpan span = new TextAppearanceSpan(
FAMILIES[random.nextInt(FAMILIES.length)],
STYLES[random.nextInt(STYLES.length)],
24 + random.nextInt(32), // text size. minimum 24
COLORS[random.nextInt(COLORS.length)],
COLORS[random.nextInt(COLORS.length)]);
int spanLength = 1 + random.nextInt(9); // Up to 9 span length.
if (pos + spanLength > ssb.length()) {
spanLength = ssb.length() - pos;
}
ssb.setSpan(span, pos, pos + spanLength, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
pos += spanLength;
}
COMPLEX_MULTILINE_TEXT = ssb;
}
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
@Test
public void testMeasure_AtMost() throws Throwable {
final Context context = InstrumentationRegistry.getTargetContext();
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final TextView textView = new TextView(context);
textView.setText(COMPLEX_MULTILINE_TEXT);
while (state.keepRunning()) {
// Changing locale to invalidate internal layout.
textView.setTextLocale(Locale.UK);
textView.setTextLocale(Locale.US);
textView.measure(AT_MOST | VIEW_WIDTH, AT_MOST | VIEW_HEIGHT);
}
}
@Test
public void testMeasure_Exactly() throws Throwable {
final Context context = InstrumentationRegistry.getTargetContext();
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final TextView textView = new TextView(context);
textView.setText(COMPLEX_MULTILINE_TEXT);
while (state.keepRunning()) {
// Changing locale to invalidate internal layout.
textView.setTextLocale(Locale.UK);
textView.setTextLocale(Locale.US);
textView.measure(EXACTLY | VIEW_WIDTH, EXACTLY | VIEW_HEIGHT);
}
}
@Test
public void testMeasure_Unspecified() throws Throwable {
final Context context = InstrumentationRegistry.getTargetContext();
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final TextView textView = new TextView(context);
textView.setText(COMPLEX_MULTILINE_TEXT);
while (state.keepRunning()) {
// Changing locale to invalidate internal layout.
textView.setTextLocale(Locale.UK);
textView.setTextLocale(Locale.US);
textView.measure(UNSPECIFIED, UNSPECIFIED);
}
}
}

View File

@@ -0,0 +1,455 @@
/*
* 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.widget;
import static android.view.View.MeasureSpec.AT_MOST;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.UNSPECIFIED;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Typeface;
import android.graphics.Canvas;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import android.text.PrecomputedText;
import android.text.Layout;
import android.text.BoringLayout;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextPaint;
import android.text.style.TextAppearanceSpan;
import android.view.LayoutInflater;
import android.text.TextPerfUtils;
import android.view.View.MeasureSpec;
import android.view.DisplayListCanvas;
import android.view.RenderNode;
import com.android.perftests.core.R;
import java.util.Random;
import java.util.Locale;
import org.junit.Before;
import org.junit.Test;
import org.junit.Rule;
import org.junit.runner.RunWith;
import static org.junit.Assert.assertTrue;
import static android.widget.TextView.UNKNOWN_BORING;
@LargeTest
@RunWith(AndroidJUnit4.class)
public class TextViewPrecomputedTextPerfTest {
private static final int WORD_LENGTH = 9; // Random word has 9 characters.
private static final int WORDS_IN_LINE = 8; // Roughly, 8 words in a line.
private static final boolean NO_STYLE_TEXT = false;
private static final boolean STYLE_TEXT = true;
private static TextPaint PAINT = new TextPaint();
private static final int TEXT_WIDTH = WORDS_IN_LINE * WORD_LENGTH * (int) PAINT.getTextSize();
public TextViewPrecomputedTextPerfTest() {}
private static class TestableTextView extends TextView {
public TestableTextView(Context ctx) {
super(ctx);
}
public void onMeasure(int w, int h) {
super.onMeasure(w, h);
}
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
}
@Rule
public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
private TextPerfUtils mTextUtil = new TextPerfUtils();
@Before
public void setUp() {
mTextUtil.resetRandom(0 /* seed */);
}
private static Context getContext() {
return InstrumentationRegistry.getTargetContext();
}
@Test
public void testNewLayout_RandomText() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
BoringLayout.Metrics metrics = new BoringLayout.Metrics();
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
final TextView textView = new TextView(getContext());
textView.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED);
textView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL);
textView.setText(text);
Canvas.freeTextLayoutCaches();
state.resumeTiming();
textView.makeNewLayout(TEXT_WIDTH, TEXT_WIDTH, UNKNOWN_BORING, UNKNOWN_BORING,
TEXT_WIDTH, false);
}
}
@Test
public void testNewLayout_RandomText_Selectable() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
BoringLayout.Metrics metrics = new BoringLayout.Metrics();
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
final TextView textView = new TextView(getContext());
textView.setTextIsSelectable(true);
textView.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED);
textView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL);
textView.setText(text);
Canvas.freeTextLayoutCaches();
state.resumeTiming();
textView.makeNewLayout(TEXT_WIDTH, TEXT_WIDTH, UNKNOWN_BORING, UNKNOWN_BORING,
TEXT_WIDTH, false);
}
}
@Test
public void testNewLayout_PrecomputedText() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
BoringLayout.Metrics metrics = new BoringLayout.Metrics();
while (state.keepRunning()) {
state.pauseTiming();
final PrecomputedText.Params params = new PrecomputedText.Params.Builder(PAINT)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED).build();
final CharSequence text = PrecomputedText.create(
mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), params);
final TextView textView = new TextView(getContext());
textView.setTextMetricsParams(params);
textView.setText(text);
Canvas.freeTextLayoutCaches();
state.resumeTiming();
textView.makeNewLayout(TEXT_WIDTH, TEXT_WIDTH, UNKNOWN_BORING, UNKNOWN_BORING,
TEXT_WIDTH, false);
}
}
@Test
public void testNewLayout_PrecomputedText_Selectable() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
BoringLayout.Metrics metrics = new BoringLayout.Metrics();
while (state.keepRunning()) {
state.pauseTiming();
final PrecomputedText.Params params = new PrecomputedText.Params.Builder(PAINT)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED).build();
final CharSequence text = PrecomputedText.create(
mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), params);
final TextView textView = new TextView(getContext());
textView.setTextIsSelectable(true);
textView.setTextMetricsParams(params);
textView.setText(text);
Canvas.freeTextLayoutCaches();
state.resumeTiming();
textView.makeNewLayout(TEXT_WIDTH, TEXT_WIDTH, UNKNOWN_BORING, UNKNOWN_BORING,
TEXT_WIDTH, false);
}
}
@Test
public void testSetText_RandomText() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
BoringLayout.Metrics metrics = new BoringLayout.Metrics();
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
final TextView textView = new TextView(getContext());
textView.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED);
textView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL);
Canvas.freeTextLayoutCaches();
state.resumeTiming();
textView.setText(text);
}
}
@Test
public void testSetText_RandomText_Selectable() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
BoringLayout.Metrics metrics = new BoringLayout.Metrics();
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
final TextView textView = new TextView(getContext());
textView.setTextIsSelectable(true);
textView.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED);
textView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL);
Canvas.freeTextLayoutCaches();
state.resumeTiming();
textView.setText(text);
}
}
@Test
public void testSetText_PrecomputedText() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
BoringLayout.Metrics metrics = new BoringLayout.Metrics();
while (state.keepRunning()) {
state.pauseTiming();
final PrecomputedText.Params params = new PrecomputedText.Params.Builder(PAINT)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED).build();
final CharSequence text = PrecomputedText.create(
mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), params);
final TextView textView = new TextView(getContext());
textView.setTextMetricsParams(params);
Canvas.freeTextLayoutCaches();
state.resumeTiming();
textView.setText(text);
}
}
@Test
public void testSetText_PrecomputedText_Selectable() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
BoringLayout.Metrics metrics = new BoringLayout.Metrics();
while (state.keepRunning()) {
state.pauseTiming();
final PrecomputedText.Params params = new PrecomputedText.Params.Builder(PAINT)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED).build();
final CharSequence text = PrecomputedText.create(
mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), params);
final TextView textView = new TextView(getContext());
textView.setTextIsSelectable(true);
textView.setTextMetricsParams(params);
Canvas.freeTextLayoutCaches();
state.resumeTiming();
textView.setText(text);
}
}
@Test
public void testOnMeasure_RandomText() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
int width = MeasureSpec.makeMeasureSpec(TEXT_WIDTH, MeasureSpec.AT_MOST);
int height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
final TestableTextView textView = new TestableTextView(getContext());
textView.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED);
textView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL);
textView.setText(text);
textView.nullLayouts();
Canvas.freeTextLayoutCaches();
state.resumeTiming();
textView.onMeasure(width, height);
}
}
@Test
public void testOnMeasure_RandomText_Selectable() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
int width = MeasureSpec.makeMeasureSpec(TEXT_WIDTH, MeasureSpec.AT_MOST);
int height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
final TestableTextView textView = new TestableTextView(getContext());
textView.setTextIsSelectable(true);
textView.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED);
textView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL);
textView.setText(text);
textView.nullLayouts();
Canvas.freeTextLayoutCaches();
state.resumeTiming();
textView.onMeasure(width, height);
}
}
@Test
public void testOnMeasure_PrecomputedText() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
int width = MeasureSpec.makeMeasureSpec(TEXT_WIDTH, MeasureSpec.AT_MOST);
int height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
while (state.keepRunning()) {
state.pauseTiming();
final PrecomputedText.Params params = new PrecomputedText.Params.Builder(PAINT)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED).build();
final CharSequence text = PrecomputedText.create(
mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), params);
final TestableTextView textView = new TestableTextView(getContext());
textView.setTextMetricsParams(params);
textView.setText(text);
textView.nullLayouts();
Canvas.freeTextLayoutCaches();
state.resumeTiming();
textView.onMeasure(width, height);
}
}
@Test
public void testOnMeasure_PrecomputedText_Selectable() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
int width = MeasureSpec.makeMeasureSpec(TEXT_WIDTH, MeasureSpec.AT_MOST);
int height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
while (state.keepRunning()) {
state.pauseTiming();
final PrecomputedText.Params params = new PrecomputedText.Params.Builder(PAINT)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED).build();
final CharSequence text = PrecomputedText.create(
mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), params);
final TestableTextView textView = new TestableTextView(getContext());
textView.setTextIsSelectable(true);
textView.setTextMetricsParams(params);
textView.setText(text);
textView.nullLayouts();
Canvas.freeTextLayoutCaches();
state.resumeTiming();
textView.onMeasure(width, height);
}
}
@Test
public void testOnDraw_RandomText() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
int width = MeasureSpec.makeMeasureSpec(TEXT_WIDTH, MeasureSpec.AT_MOST);
int height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
final RenderNode node = RenderNode.create("benchmark", null);
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
final TestableTextView textView = new TestableTextView(getContext());
textView.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED);
textView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL);
textView.setText(text);
textView.measure(width, height);
textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight());
final DisplayListCanvas c = node.start(
textView.getMeasuredWidth(), textView.getMeasuredHeight());
textView.nullLayouts();
Canvas.freeTextLayoutCaches();
state.resumeTiming();
textView.onDraw(c);
}
}
@Test
public void testOnDraw_RandomText_Selectable() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
int width = MeasureSpec.makeMeasureSpec(TEXT_WIDTH, MeasureSpec.AT_MOST);
int height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
final RenderNode node = RenderNode.create("benchmark", null);
while (state.keepRunning()) {
state.pauseTiming();
final CharSequence text = mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
final TestableTextView textView = new TestableTextView(getContext());
textView.setTextIsSelectable(true);
textView.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED);
textView.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL);
textView.setText(text);
textView.measure(width, height);
textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight());
final DisplayListCanvas c = node.start(
textView.getMeasuredWidth(), textView.getMeasuredHeight());
textView.nullLayouts();
Canvas.freeTextLayoutCaches();
state.resumeTiming();
textView.onDraw(c);
}
}
@Test
public void testOnDraw_PrecomputedText() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
int width = MeasureSpec.makeMeasureSpec(TEXT_WIDTH, MeasureSpec.AT_MOST);
int height = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
final RenderNode node = RenderNode.create("benchmark", null);
while (state.keepRunning()) {
state.pauseTiming();
final PrecomputedText.Params params = new PrecomputedText.Params.Builder(PAINT)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED).build();
final CharSequence text = PrecomputedText.create(
mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), params);
final TestableTextView textView = new TestableTextView(getContext());
textView.setTextMetricsParams(params);
textView.setText(text);
textView.measure(width, height);
textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight());
final DisplayListCanvas c = node.start(
textView.getMeasuredWidth(), textView.getMeasuredHeight());
textView.nullLayouts();
Canvas.freeTextLayoutCaches();
state.resumeTiming();
textView.onDraw(c);
}
}
@Test
public void testOnDraw_PrecomputedText_Selectable() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
int width = MeasureSpec.makeMeasureSpec(MeasureSpec.AT_MOST, TEXT_WIDTH);
int height = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0);
final RenderNode node = RenderNode.create("benchmark", null);
while (state.keepRunning()) {
state.pauseTiming();
final PrecomputedText.Params params = new PrecomputedText.Params.Builder(PAINT)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL)
.setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED).build();
final CharSequence text = PrecomputedText.create(
mTextUtil.nextRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT), params);
final TestableTextView textView = new TestableTextView(getContext());
textView.setTextIsSelectable(true);
textView.setTextMetricsParams(params);
textView.setText(text);
textView.measure(width, height);
textView.layout(0, 0, textView.getMeasuredWidth(), textView.getMeasuredHeight());
final DisplayListCanvas c = node.start(
textView.getMeasuredWidth(), textView.getMeasuredHeight());
textView.nullLayouts();
Canvas.freeTextLayoutCaches();
state.resumeTiming();
textView.onDraw(c);
}
}
}

View File

@@ -16,27 +16,21 @@
package android.widget;
import android.app.Activity;
import android.os.Bundle;
import android.perftests.utils.PerfStatusReporter;
import android.util.Log;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
import android.perftests.utils.StubActivity;
import android.support.test.filters.LargeTest;
import android.support.test.runner.AndroidJUnit4;
import android.support.test.rule.ActivityTestRule;
import android.support.test.InstrumentationRegistry;
import java.util.Locale;
import java.util.Collection;
import java.util.Arrays;
import org.junit.Test;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.junit.runner.RunWith;
import java.util.Arrays;
import java.util.Collection;
import java.util.Locale;
@LargeTest
@RunWith(Parameterized.class)

View File

@@ -20,11 +20,14 @@ LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-test
android-support-test \
ub-uiautomator
LOCAL_PACKAGE_NAME := MultiUserPerfTests
LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_COMPATIBILITY_SUITE += device-tests
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2018 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<configuration description="Runs MultiUserPerfTests metric instrumentation.">
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="apct-metric-instrumentation" />
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="MultiUserPerfTests.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.perftests.multiuser" />
<option name="hidden-api-checks" value="false"/>
</test>
</configuration>

View File

@@ -17,13 +17,16 @@ package android.multiuser;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.test.InstrumentationRegistry;
import android.support.test.uiautomator.UiDevice;
import java.io.IOException;
import java.util.ArrayList;
// Based on //platform/frameworks/base/apct-tests/perftests/utils/BenchmarkState.java
public class BenchmarkRunner {
private static long COOL_OFF_PERIOD_MS = 2000;
private static final long COOL_OFF_PERIOD_MS = 1000;
private static final int NUM_ITERATIONS = 4;
@@ -70,9 +73,13 @@ public class BenchmarkRunner {
}
private void prepareForNextRun() {
// TODO: Once http://b/63115387 is fixed, look into using "am wait-for-broadcast-idle"
// command instead of waiting for a fixed amount of time.
SystemClock.sleep(COOL_OFF_PERIOD_MS);
try {
UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
.executeShellCommand("am wait-for-broadcast-idle");
} catch (IOException e) {
throw new IllegalStateException("Cannot execute shell command", e);
}
mStartTimeNs = System.nanoTime();
mPausedDurationNs = 0;
}

View File

@@ -25,7 +25,6 @@ import android.util.Log;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
/**
@@ -78,10 +77,7 @@ public final class BenchmarkState {
// Statistics. These values will be filled when the benchmark has finished.
// The computation needs double precision, but long int is fine for final reporting.
private long mMedian = 0;
private double mMean = 0.0;
private double mStandardDeviation = 0.0;
private long mMin = 0;
private Stats mStats;
// Individual duration in nano seconds.
private ArrayList<Long> mResults = new ArrayList<>();
@@ -90,36 +86,6 @@ public final class BenchmarkState {
return TimeUnit.MILLISECONDS.toNanos(ms);
}
/**
* Calculates statistics.
*/
private void calculateSatistics() {
final int size = mResults.size();
if (size <= 1) {
throw new IllegalStateException("At least two results are necessary.");
}
Collections.sort(mResults);
mMedian = size % 2 == 0 ? (mResults.get(size / 2) + mResults.get(size / 2 + 1)) / 2 :
mResults.get(size / 2);
mMin = mResults.get(0);
for (int i = 0; i < size; ++i) {
long result = mResults.get(i);
mMean += result;
if (result < mMin) {
mMin = result;
}
}
mMean /= (double) size;
for (int i = 0; i < size; ++i) {
final double tmp = mResults.get(i) - mMean;
mStandardDeviation += tmp * tmp;
}
mStandardDeviation = Math.sqrt(mStandardDeviation / (double) (size - 1));
}
// Stops the benchmark timer.
// This method can be called only when the timer is running.
public void pauseTiming() {
@@ -173,7 +139,7 @@ public final class BenchmarkState {
if (ENABLE_PROFILING) {
Debug.stopMethodTracing();
}
calculateSatistics();
mStats = new Stats(mResults);
mState = FINISHED;
return false;
}
@@ -224,28 +190,28 @@ public final class BenchmarkState {
if (mState != FINISHED) {
throw new IllegalStateException("The benchmark hasn't finished");
}
return (long) mMean;
return (long) mStats.getMean();
}
private long median() {
if (mState != FINISHED) {
throw new IllegalStateException("The benchmark hasn't finished");
}
return mMedian;
return mStats.getMedian();
}
private long min() {
if (mState != FINISHED) {
throw new IllegalStateException("The benchmark hasn't finished");
}
return mMin;
return mStats.getMin();
}
private long standardDeviation() {
if (mState != FINISHED) {
throw new IllegalStateException("The benchmark hasn't finished");
}
return (long) mStandardDeviation;
return (long) mStats.getStandardDeviation();
}
private String summaryLine() {

View File

@@ -0,0 +1,159 @@
/*
* 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.perftests.utils;
import android.app.Activity;
import android.app.Instrumentation;
import android.os.Bundle;
import android.util.Log;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
/**
* Provides a benchmark framework.
*
* This differs from BenchmarkState in that rather than the class measuring the the elapsed time,
* the test passes in the elapsed time.
*
* Example usage:
*
* public void sampleMethod() {
* ManualBenchmarkState state = new ManualBenchmarkState();
*
* int[] src = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
* long elapsedTime = 0;
* while (state.keepRunning(elapsedTime)) {
* long startTime = System.nanoTime();
* int[] dest = new int[src.length];
* System.arraycopy(src, 0, dest, 0, src.length);
* elapsedTime = System.nanoTime() - startTime;
* }
* System.out.println(state.summaryLine());
* }
*
* Or use the PerfManualStatusReporter TestRule.
*
* Make sure that the overhead of checking the clock does not noticeably affect the results.
*/
public final class ManualBenchmarkState {
private static final String TAG = ManualBenchmarkState.class.getSimpleName();
// TODO: Tune these values.
// warm-up for duration
private static final long WARMUP_DURATION_NS = TimeUnit.SECONDS.toNanos(5);
// minimum iterations to warm-up for
private static final int WARMUP_MIN_ITERATIONS = 8;
// target testing for duration
private static final long TARGET_TEST_DURATION_NS = TimeUnit.SECONDS.toNanos(16);
private static final int MAX_TEST_ITERATIONS = 1000000;
private static final int MIN_TEST_ITERATIONS = 10;
private static final int NOT_STARTED = 0; // The benchmark has not started yet.
private static final int WARMUP = 1; // The benchmark is warming up.
private static final int RUNNING = 2; // The benchmark is running.
private static final int FINISHED = 3; // The benchmark has stopped.
private int mState = NOT_STARTED; // Current benchmark state.
private long mWarmupStartTime = 0;
private int mWarmupIterations = 0;
private int mMaxIterations = 0;
// Individual duration in nano seconds.
private ArrayList<Long> mResults = new ArrayList<>();
// Statistics. These values will be filled when the benchmark has finished.
// The computation needs double precision, but long int is fine for final reporting.
private Stats mStats;
private void beginBenchmark(long warmupDuration, int iterations) {
mMaxIterations = (int) (TARGET_TEST_DURATION_NS / (warmupDuration / iterations));
mMaxIterations = Math.min(MAX_TEST_ITERATIONS,
Math.max(mMaxIterations, MIN_TEST_ITERATIONS));
mState = RUNNING;
}
/**
* Judges whether the benchmark needs more samples.
*
* For the usage, see class comment.
*/
public boolean keepRunning(long duration) {
if (duration < 0) {
throw new RuntimeException("duration is negative: " + duration);
}
switch (mState) {
case NOT_STARTED:
mState = WARMUP;
mWarmupStartTime = System.nanoTime();
return true;
case WARMUP: {
final long timeSinceStartingWarmup = System.nanoTime() - mWarmupStartTime;
++mWarmupIterations;
if (mWarmupIterations >= WARMUP_MIN_ITERATIONS
&& timeSinceStartingWarmup >= WARMUP_DURATION_NS) {
beginBenchmark(timeSinceStartingWarmup, mWarmupIterations);
}
return true;
}
case RUNNING: {
mResults.add(duration);
final boolean keepRunning = mResults.size() < mMaxIterations;
if (!keepRunning) {
mStats = new Stats(mResults);
mState = FINISHED;
}
return keepRunning;
}
case FINISHED:
throw new IllegalStateException("The benchmark has finished.");
default:
throw new IllegalStateException("The benchmark is in an unknown state.");
}
}
private String summaryLine() {
final StringBuilder sb = new StringBuilder();
sb.append("Summary: ");
sb.append("median=").append(mStats.getMedian()).append("ns, ");
sb.append("mean=").append(mStats.getMean()).append("ns, ");
sb.append("min=").append(mStats.getMin()).append("ns, ");
sb.append("max=").append(mStats.getMax()).append("ns, ");
sb.append("sigma=").append(mStats.getStandardDeviation()).append(", ");
sb.append("iteration=").append(mResults.size()).append(", ");
sb.append("values=").append(mResults.toString());
return sb.toString();
}
public void sendFullStatusReport(Instrumentation instrumentation, String key) {
if (mState != FINISHED) {
throw new IllegalStateException("The benchmark hasn't finished");
}
Log.i(TAG, key + summaryLine());
final Bundle status = new Bundle();
status.putLong(key + "_median", mStats.getMedian());
status.putLong(key + "_mean", (long) mStats.getMean());
status.putLong(key + "_percentile90", mStats.getPercentile90());
status.putLong(key + "_percentile95", mStats.getPercentile95());
status.putLong(key + "_stddev", (long) mStats.getStandardDeviation());
instrumentation.sendStatus(Activity.RESULT_OK, status);
}
}

View File

@@ -0,0 +1,73 @@
/*
* 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.perftests.utils;
import android.support.test.InstrumentationRegistry;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
/**
* Use this rule to make sure we report the status after the test success.
*
* <code>
*
* @Rule public PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter();
* @Test public void functionName() {
* ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState();
*
* int[] src = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
* long elapsedTime = 0;
* while (state.keepRunning(elapsedTime)) {
* long startTime = System.nanoTime();
* int[] dest = new int[src.length];
* System.arraycopy(src, 0, dest, 0, src.length);
* elapsedTime = System.nanoTime() - startTime;
* }
* }
* </code>
*
* When test succeeded, the status report will use the key as
* "functionName_*"
*/
public class PerfManualStatusReporter implements TestRule {
private final ManualBenchmarkState mState;
public PerfManualStatusReporter() {
mState = new ManualBenchmarkState();
}
public ManualBenchmarkState getBenchmarkState() {
return mState;
}
@Override
public Statement apply(Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
base.evaluate();
mState.sendFullStatusReport(InstrumentationRegistry.getInstrumentation(),
description.getMethodName());
}
};
}
}

View File

@@ -0,0 +1,95 @@
/*
* 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.perftests.utils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Stats {
private long mMedian, mMin, mMax, mPercentile90, mPercentile95;
private double mMean, mStandardDeviation;
/* Calculate stats in constructor. */
public Stats(List<Long> values) {
// make a copy since we're modifying it
values = new ArrayList<>(values);
final int size = values.size();
if (size < 2) {
throw new IllegalArgumentException("At least two results are necessary.");
}
Collections.sort(values);
mMin = values.get(0);
mMax = values.get(values.size() - 1);
mMedian = size % 2 == 0 ? (values.get(size / 2) + values.get(size / 2 - 1)) / 2 :
values.get(size / 2);
mPercentile90 = getPercentile(values, 90);
mPercentile95 = getPercentile(values, 95);
for (int i = 0; i < size; ++i) {
long result = values.get(i);
mMean += result;
}
mMean /= (double) size;
for (int i = 0; i < size; ++i) {
final double tmp = values.get(i) - mMean;
mStandardDeviation += tmp * tmp;
}
mStandardDeviation = Math.sqrt(mStandardDeviation / (double) (size - 1));
}
public double getMean() {
return mMean;
}
public long getMedian() {
return mMedian;
}
public long getMax() {
return mMax;
}
public long getMin() {
return mMin;
}
public double getStandardDeviation() {
return mStandardDeviation;
}
public long getPercentile90() {
return mPercentile90;
}
public long getPercentile95() {
return mPercentile95;
}
private static long getPercentile(List<Long> values, int percentile) {
if (percentile < 0 || percentile > 100) {
throw new IllegalArgumentException(
"invalid percentile " + percentile + ", should be 0-100");
}
int idx = (values.size() - 1) * percentile / 100;
return values.get(idx);
}
}

View File

@@ -17,6 +17,14 @@
package android.perftests.utils;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
public class StubActivity extends Activity {
}
public static Intent createLaunchIntent(Context context) {
final Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setClass(context, StubActivity.class);
return intent;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -54,6 +54,54 @@ package android.app.admin {
}
package android.app.job {
public class JobInfo implements android.os.Parcelable {
method public deprecated long getEstimatedNetworkBytes();
}
public static final class JobInfo.Builder {
method public deprecated android.app.job.JobInfo.Builder setEstimatedNetworkBytes(long);
method public deprecated android.app.job.JobInfo.Builder setIsPrefetch(boolean);
}
public final class JobWorkItem implements android.os.Parcelable {
ctor public deprecated JobWorkItem(android.content.Intent, long);
method public deprecated long getEstimatedNetworkBytes();
}
}
package android.app.slice {
public final class Slice implements android.os.Parcelable {
field public static final deprecated java.lang.String EXTRA_SLIDER_VALUE = "android.app.slice.extra.SLIDER_VALUE";
field public static final deprecated java.lang.String SUBTYPE_SLIDER = "slider";
}
public static class Slice.Builder {
ctor public deprecated Slice.Builder(android.net.Uri);
method public deprecated android.app.slice.Slice.Builder addTimestamp(long, java.lang.String, java.util.List<java.lang.String>);
method public deprecated android.app.slice.Slice.Builder setSpec(android.app.slice.SliceSpec);
}
public final class SliceItem implements android.os.Parcelable {
method public deprecated long getTimestamp();
field public static final deprecated java.lang.String FORMAT_TIMESTAMP = "long";
}
public class SliceManager {
method public deprecated android.app.slice.Slice bindSlice(android.net.Uri, java.util.List<android.app.slice.SliceSpec>);
method public deprecated android.app.slice.Slice bindSlice(android.content.Intent, java.util.List<android.app.slice.SliceSpec>);
method public deprecated void pinSlice(android.net.Uri, java.util.List<android.app.slice.SliceSpec>);
}
public abstract class SliceProvider extends android.content.ContentProvider {
method public deprecated android.app.slice.Slice onBindSlice(android.net.Uri, java.util.List<android.app.slice.SliceSpec>);
}
}
package android.app.usage {
public final class StorageStats implements android.os.Parcelable {
@@ -150,6 +198,34 @@ package android.graphics {
public class Canvas {
method public deprecated boolean clipRegion(android.graphics.Region, android.graphics.Region.Op);
method public deprecated boolean clipRegion(android.graphics.Region);
method public deprecated int save(int);
field public static final deprecated int CLIP_SAVE_FLAG = 2; // 0x2
field public static final deprecated int CLIP_TO_LAYER_SAVE_FLAG = 16; // 0x10
field public static final deprecated int FULL_COLOR_LAYER_SAVE_FLAG = 8; // 0x8
field public static final deprecated int HAS_ALPHA_LAYER_SAVE_FLAG = 4; // 0x4
field public static final deprecated int MATRIX_SAVE_FLAG = 1; // 0x1
}
public final class ImageDecoder implements java.lang.AutoCloseable {
method public deprecated boolean getAsAlphaMask();
method public deprecated boolean getConserveMemory();
method public deprecated boolean getDecodeAsAlphaMask();
method public deprecated boolean getMutable();
method public deprecated boolean getRequireUnpremultiplied();
method public deprecated android.graphics.ImageDecoder setAsAlphaMask(boolean);
method public deprecated void setConserveMemory(boolean);
method public deprecated android.graphics.ImageDecoder setDecodeAsAlphaMask(boolean);
method public deprecated android.graphics.ImageDecoder setMutable(boolean);
method public deprecated android.graphics.ImageDecoder setRequireUnpremultiplied(boolean);
method public deprecated android.graphics.ImageDecoder setResize(int, int);
method public deprecated android.graphics.ImageDecoder setResize(int);
field public static final deprecated int ERROR_SOURCE_ERROR = 3; // 0x3
field public static final deprecated int ERROR_SOURCE_EXCEPTION = 1; // 0x1
field public static final deprecated int ERROR_SOURCE_INCOMPLETE = 2; // 0x2
}
public static deprecated class ImageDecoder.IncompleteException extends java.io.IOException {
ctor public ImageDecoder.IncompleteException();
}
public deprecated class LayerRasterizer extends android.graphics.Rasterizer {
@@ -173,6 +249,16 @@ package android.graphics {
}
package android.graphics.drawable {
public class AnimatedImageDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Animatable2 {
method public deprecated int getLoopCount(int);
method public deprecated void setLoopCount(int);
field public static final deprecated int LOOP_INFINITE = -1; // 0xffffffff
}
}
package android.hardware {
public final class HardwareBuffer implements java.lang.AutoCloseable android.os.Parcelable {
@@ -235,23 +321,14 @@ package android.net {
public static abstract class NetworkBadging.Badging implements java.lang.annotation.Annotation {
}
public abstract class PskKeyManager implements javax.net.ssl.KeyManager {
ctor public PskKeyManager();
method public java.lang.String chooseClientKeyIdentity(java.lang.String, java.net.Socket);
method public java.lang.String chooseClientKeyIdentity(java.lang.String, javax.net.ssl.SSLEngine);
method public java.lang.String chooseServerKeyIdentityHint(java.net.Socket);
method public java.lang.String chooseServerKeyIdentityHint(javax.net.ssl.SSLEngine);
method public javax.crypto.SecretKey getKey(java.lang.String, java.lang.String, java.net.Socket);
method public javax.crypto.SecretKey getKey(java.lang.String, java.lang.String, javax.net.ssl.SSLEngine);
field public static final int MAX_IDENTITY_HINT_LENGTH_BYTES = 128; // 0x80
field public static final int MAX_IDENTITY_LENGTH_BYTES = 128; // 0x80
field public static final int MAX_KEY_LENGTH_BYTES = 256; // 0x100
}
public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
method public static deprecated org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache);
}
public class TrafficStats {
method public static deprecated void setThreadStatsUidSelf();
}
}
package android.os {
@@ -270,6 +347,20 @@ package android.os {
ctor public RecoverySystem();
}
public static final class StrictMode.ThreadPolicy.Builder {
method public android.os.StrictMode.ThreadPolicy.Builder penaltyListener(android.os.StrictMode.OnThreadViolationListener, java.util.concurrent.Executor);
}
public static final class StrictMode.VmPolicy.Builder {
method public android.os.StrictMode.VmPolicy.Builder penaltyListener(android.os.StrictMode.OnVmViolationListener, java.util.concurrent.Executor);
}
public final class SystemClock {
method public static java.time.Clock elapsedRealtimeClock();
method public static java.time.Clock uptimeClock();
method public static deprecated java.time.Clock uptimeMillisClock();
}
public class TestLooperManager {
method public deprecated android.os.MessageQueue getQueue();
}
@@ -442,17 +533,14 @@ package android.speech.tts {
}
package android.test.mock {
package android.telephony {
public class MockContext extends android.content.Context {
method public android.content.SharedPreferences getSharedPreferences(java.io.File, int);
method public java.io.File getSharedPreferencesPath(java.lang.String);
public class NetworkScan {
method public deprecated void stop() throws android.os.RemoteException;
}
public deprecated class MockPackageManager extends android.content.pm.PackageManager {
method public deprecated java.lang.String getDefaultBrowserPackageName(int);
method public deprecated boolean setDefaultBrowserPackageName(java.lang.String, int);
method public boolean setInstantAppCookie(byte[]);
public class TelephonyManager {
method public deprecated android.telephony.NetworkScan requestNetworkScan(android.telephony.NetworkScanRequest, android.telephony.TelephonyScanManager.NetworkScanCallback);
}
}
@@ -519,14 +607,6 @@ package android.view {
}
package android.view.accessibility {
public final class AccessibilityWindowInfo implements android.os.Parcelable {
method public boolean inPictureInPicture();
}
}
package android.webkit {
public class WebViewClient {

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,5 @@
package android.app {
public abstract deprecated class EphemeralResolverService extends android.app.InstantAppResolverService {
ctor public EphemeralResolverService();
method public android.os.Looper getLooper();
method public abstract deprecated java.util.List<android.content.pm.EphemeralResolveInfo> onEphemeralResolveInfoList(int[], int);
method public android.content.pm.EphemeralResolveInfo onGetEphemeralIntentFilter(java.lang.String);
method public java.util.List<android.content.pm.EphemeralResolveInfo> onGetEphemeralResolveInfo(int[]);
}
public class Notification implements android.os.Parcelable {
method public static java.lang.Class<? extends android.app.Notification.Style> getNotificationStyleClass(java.lang.String);
}
@@ -31,10 +23,7 @@ package android.content {
public class Intent implements java.lang.Cloneable android.os.Parcelable {
field public static final deprecated java.lang.String ACTION_DEVICE_INITIALIZATION_WIZARD = "android.intent.action.DEVICE_INITIALIZATION_WIZARD";
field public static final deprecated java.lang.String ACTION_EPHEMERAL_RESOLVER_SETTINGS = "android.intent.action.EPHEMERAL_RESOLVER_SETTINGS";
field public static final deprecated java.lang.String ACTION_INSTALL_EPHEMERAL_PACKAGE = "android.intent.action.INSTALL_EPHEMERAL_PACKAGE";
field public static final deprecated java.lang.String ACTION_MASTER_CLEAR = "android.intent.action.MASTER_CLEAR";
field public static final deprecated java.lang.String ACTION_RESOLVE_EPHEMERAL_PACKAGE = "android.intent.action.RESOLVE_EPHEMERAL_PACKAGE";
field public static final deprecated java.lang.String ACTION_SERVICE_STATE = "android.intent.action.SERVICE_STATE";
field public static final deprecated java.lang.String EXTRA_CDMA_DEFAULT_ROAMING_INDICATOR = "cdmaDefaultRoamingIndicator";
field public static final deprecated java.lang.String EXTRA_CDMA_ROAMING_INDICATOR = "cdmaRoamingIndicator";
@@ -62,51 +51,16 @@ package android.content {
}
package android.content.pm {
public final deprecated class EphemeralIntentFilter implements android.os.Parcelable {
ctor public EphemeralIntentFilter(java.lang.String, java.util.List<android.content.IntentFilter>);
method public int describeContents();
method public java.util.List<android.content.IntentFilter> getFilters();
method public java.lang.String getSplitName();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.pm.EphemeralIntentFilter> CREATOR;
}
public final deprecated class EphemeralResolveInfo implements android.os.Parcelable {
ctor public deprecated EphemeralResolveInfo(android.net.Uri, java.lang.String, java.util.List<android.content.IntentFilter>);
ctor public deprecated EphemeralResolveInfo(android.content.pm.EphemeralResolveInfo.EphemeralDigest, java.lang.String, java.util.List<android.content.pm.EphemeralIntentFilter>);
ctor public EphemeralResolveInfo(android.content.pm.EphemeralResolveInfo.EphemeralDigest, java.lang.String, java.util.List<android.content.pm.EphemeralIntentFilter>, int);
ctor public EphemeralResolveInfo(java.lang.String, java.lang.String, java.util.List<android.content.pm.EphemeralIntentFilter>);
method public int describeContents();
method public byte[] getDigestBytes();
method public int getDigestPrefix();
method public deprecated java.util.List<android.content.IntentFilter> getFilters();
method public java.util.List<android.content.pm.EphemeralIntentFilter> getIntentFilters();
method public java.lang.String getPackageName();
method public int getVersionCode();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.pm.EphemeralResolveInfo> CREATOR;
field public static final java.lang.String SHA_ALGORITHM = "SHA-256";
}
public static final class EphemeralResolveInfo.EphemeralDigest implements android.os.Parcelable {
ctor public EphemeralResolveInfo.EphemeralDigest(java.lang.String);
method public int describeContents();
method public byte[][] getDigestBytes();
method public int[] getDigestPrefix();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.pm.EphemeralResolveInfo.EphemeralDigest> CREATOR;
}
}
package android.media.tv {
public final class TvInputManager {
method public android.media.tv.TvInputManager.Hardware acquireTvInputHardware(int, android.media.tv.TvInputManager.HardwareCallback, android.media.tv.TvInputInfo);
}
public static final class TvInputManager.Hardware {
method public boolean dispatchKeyEventToHdmi(android.view.KeyEvent);
}
}
package android.net.wifi {
@@ -122,29 +76,6 @@ package android.net.wifi {
field public boolean untrusted;
}
public class WifiConnectionStatistics implements android.os.Parcelable {
ctor public WifiConnectionStatistics();
ctor public WifiConnectionStatistics(android.net.wifi.WifiConnectionStatistics);
method public int describeContents();
method public void incrementOrAddUntrusted(java.lang.String, int, int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.wifi.WifiConnectionStatistics> CREATOR;
field public int num24GhzConnected;
field public int num5GhzConnected;
field public int numAutoJoinAttempt;
field public int numAutoRoamAttempt;
field public int numWifiManagerJoinAttempt;
field public java.util.HashMap<java.lang.String, android.net.wifi.WifiNetworkConnectionStatistics> untrustedNetworkHistory;
}
public class WifiManager {
method public deprecated java.util.List<android.net.wifi.BatchedScanResult> getBatchedScanResults();
method public android.net.wifi.WifiConnectionStatistics getConnectionStatistics();
method public deprecated boolean isBatchedScanSupported();
method public deprecated boolean setWifiApEnabled(android.net.wifi.WifiConfiguration, boolean);
method public deprecated boolean startLocationRestrictedScan(android.os.WorkSource);
}
}
package android.os {
@@ -160,6 +91,38 @@ package android.os {
}
package android.security.keystore.recovery {
public final class KeyChainSnapshot implements android.os.Parcelable {
method public deprecated byte[] getTrustedHardwarePublicKey();
}
public class RecoveryController {
method public deprecated byte[] generateAndStoreKey(java.lang.String, byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
method public deprecated java.security.Key generateKey(java.lang.String, byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException;
method public deprecated java.util.List<java.lang.String> getAliases(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
method public deprecated android.security.keystore.recovery.KeyChainSnapshot getRecoveryData() throws android.security.keystore.recovery.InternalRecoveryServiceException;
method public deprecated int getRecoveryStatus(java.lang.String, java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException;
method public deprecated void initRecoveryService(java.lang.String, byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
method public deprecated void setRecoveryStatus(java.lang.String, java.lang.String, int) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.content.pm.PackageManager.NameNotFoundException;
}
public class RecoverySession implements java.lang.AutoCloseable {
method public deprecated java.util.Map<java.lang.String, byte[]> recoverKeys(byte[], java.util.List<android.security.keystore.recovery.WrappedApplicationKey>) throws android.security.keystore.recovery.DecryptionFailedException, android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.SessionExpiredException;
method public deprecated byte[] start(byte[], byte[], byte[], java.util.List<android.security.keystore.recovery.KeyChainProtectionParams>) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
method public deprecated byte[] start(java.security.cert.CertPath, byte[], byte[], java.util.List<android.security.keystore.recovery.KeyChainProtectionParams>) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException;
}
public final class WrappedApplicationKey implements android.os.Parcelable {
method public deprecated byte[] getAccount();
}
public static class WrappedApplicationKey.Builder {
method public deprecated android.security.keystore.recovery.WrappedApplicationKey.Builder setAccount(byte[]);
}
}
package android.service.notification {
public abstract class NotificationListenerService extends android.app.Service {

View File

@@ -1,3 +1,14 @@
package android {
public static final class Manifest.permission {
field public static final java.lang.String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
field public static final java.lang.String BRIGHTNESS_SLIDER_USAGE = "android.permission.BRIGHTNESS_SLIDER_USAGE";
field public static final java.lang.String CONFIGURE_DISPLAY_BRIGHTNESS = "android.permission.CONFIGURE_DISPLAY_BRIGHTNESS";
field public static final java.lang.String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
}
}
package android.animation {
public class ValueAnimator extends android.animation.Animator {
@@ -11,21 +22,103 @@ package android.app {
public class ActivityManager {
method public void addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int);
method public void alwaysShowUnsupportedCompileSdkWarning(android.content.ComponentName);
method public int getPackageImportance(java.lang.String);
method public long getTotalRam();
method public int getUidImportance(int);
method public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener);
method public void removeStacksInWindowingModes(int[]) throws java.lang.SecurityException;
method public void removeStacksWithActivityTypes(int[]) throws java.lang.SecurityException;
method public void resizeStack(int, android.graphics.Rect) throws java.lang.SecurityException;
method public void setTaskWindowingMode(int, int, boolean) throws java.lang.SecurityException;
method public void setTaskWindowingModeSplitScreenPrimary(int, int, boolean, boolean, android.graphics.Rect, boolean) throws java.lang.SecurityException;
method public static boolean supportsMultiWindow(android.content.Context);
method public static boolean supportsSplitScreenMultiWindow(android.content.Context);
field public static final int SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT = 1; // 0x1
field public static final int SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT = 0; // 0x0
}
public static abstract interface ActivityManager.OnUidImportanceListener {
method public abstract void onUidImportance(int, int);
}
public static class ActivityManager.StackId {
field public static final int INVALID_STACK_ID = -1; // 0xffffffff
}
public static class ActivityManager.TaskDescription implements android.os.Parcelable {
method public java.lang.String getIconFilename();
method public int getIconResource();
}
public class ActivityOptions {
method public void setLaunchStackId(int);
method public void setLaunchActivityType(int);
method public void setLaunchTaskId(int);
method public void setLaunchWindowingMode(int);
method public void setTaskOverlay(boolean, boolean);
}
public class AppOpsManager {
method public static java.lang.String[] getOpStrs();
method public boolean isOperationActive(int, int, java.lang.String);
method public void setMode(int, int, java.lang.String, int);
method public void startWatchingActive(int[], android.app.AppOpsManager.OnOpActiveChangedListener);
method public void stopWatchingActive(android.app.AppOpsManager.OnOpActiveChangedListener);
field public static final java.lang.String OPSTR_ACCEPT_HANDOVER = "android:accept_handover";
field public static final java.lang.String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications";
field public static final java.lang.String OPSTR_ACTIVATE_VPN = "android:activate_vpn";
field public static final java.lang.String OPSTR_ASSIST_SCREENSHOT = "android:assist_screenshot";
field public static final java.lang.String OPSTR_ASSIST_STRUCTURE = "android:assist_structure";
field public static final java.lang.String OPSTR_AUDIO_ACCESSIBILITY_VOLUME = "android:audio_accessibility_volume";
field public static final java.lang.String OPSTR_AUDIO_ALARM_VOLUME = "android:audio_alarm_volume";
field public static final java.lang.String OPSTR_AUDIO_BLUETOOTH_VOLUME = "android:audio_bluetooth_volume";
field public static final java.lang.String OPSTR_AUDIO_MASTER_VOLUME = "android:audio_master_volume";
field public static final java.lang.String OPSTR_AUDIO_MEDIA_VOLUME = "android:audio_media_volume";
field public static final java.lang.String OPSTR_AUDIO_NOTIFICATION_VOLUME = "android:audio_notification_volume";
field public static final java.lang.String OPSTR_AUDIO_RING_VOLUME = "android:audio_ring_volume";
field public static final java.lang.String OPSTR_AUDIO_VOICE_VOLUME = "android:audio_voice_volume";
field public static final java.lang.String OPSTR_BIND_ACCESSIBILITY_SERVICE = "android:bind_accessibility_service";
field public static final java.lang.String OPSTR_CHANGE_WIFI_STATE = "android:change_wifi_state";
field public static final java.lang.String OPSTR_GET_ACCOUNTS = "android:get_accounts";
field public static final java.lang.String OPSTR_GPS = "android:gps";
field public static final java.lang.String OPSTR_INSTANT_APP_START_FOREGROUND = "android:instant_app_start_foreground";
field public static final java.lang.String OPSTR_MANAGE_IPSEC_TUNNELS = "android:manage_ipsec_tunnels";
field public static final java.lang.String OPSTR_MUTE_MICROPHONE = "android:mute_microphone";
field public static final java.lang.String OPSTR_NEIGHBORING_CELLS = "android:neighboring_cells";
field public static final java.lang.String OPSTR_PLAY_AUDIO = "android:play_audio";
field public static final java.lang.String OPSTR_POST_NOTIFICATION = "android:post_notification";
field public static final java.lang.String OPSTR_PROJECT_MEDIA = "android:project_media";
field public static final java.lang.String OPSTR_READ_CLIPBOARD = "android:read_clipboard";
field public static final java.lang.String OPSTR_READ_ICC_SMS = "android:read_icc_sms";
field public static final java.lang.String OPSTR_RECEIVE_EMERGENCY_BROADCAST = "android:receive_emergency_broadcast";
field public static final java.lang.String OPSTR_REQUEST_DELETE_PACKAGES = "android:request_delete_packages";
field public static final java.lang.String OPSTR_REQUEST_INSTALL_PACKAGES = "android:request_install_packages";
field public static final java.lang.String OPSTR_RUN_ANY_IN_BACKGROUND = "android:run_any_in_background";
field public static final java.lang.String OPSTR_RUN_IN_BACKGROUND = "android:run_in_background";
field public static final java.lang.String OPSTR_START_FOREGROUND = "android:start_foreground";
field public static final java.lang.String OPSTR_TAKE_AUDIO_FOCUS = "android:take_audio_focus";
field public static final java.lang.String OPSTR_TAKE_MEDIA_BUTTONS = "android:take_media_buttons";
field public static final java.lang.String OPSTR_TOAST_WINDOW = "android:toast_window";
field public static final java.lang.String OPSTR_TURN_SCREEN_ON = "android:turn_screen_on";
field public static final java.lang.String OPSTR_VIBRATE = "android:vibrate";
field public static final java.lang.String OPSTR_WAKE_LOCK = "android:wake_lock";
field public static final java.lang.String OPSTR_WIFI_SCAN = "android:wifi_scan";
field public static final java.lang.String OPSTR_WRITE_CLIPBOARD = "android:write_clipboard";
field public static final java.lang.String OPSTR_WRITE_ICC_SMS = "android:write_icc_sms";
field public static final java.lang.String OPSTR_WRITE_SMS = "android:write_sms";
field public static final java.lang.String OPSTR_WRITE_WALLPAPER = "android:write_wallpaper";
field public static final int OP_RECORD_AUDIO = 27; // 0x1b
field public static final int OP_SYSTEM_ALERT_WINDOW = 24; // 0x18
}
public static abstract interface AppOpsManager.OnOpActiveChangedListener {
method public abstract void onOpActiveChanged(int, int, java.lang.String, boolean);
}
public final class NotificationChannelGroup implements android.os.Parcelable {
method public void setBlocked(boolean);
}
public class NotificationManager {
method public android.content.ComponentName getEffectsSuppressor();
}
@@ -37,8 +130,8 @@ package android.app {
public final class UiAutomation {
method public void destroy();
method public android.os.ParcelFileDescriptor[] executeShellCommandRw(java.lang.String);
method public boolean grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public boolean revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public deprecated boolean grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
method public deprecated boolean revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
}
public class UiModeManager {
@@ -46,6 +139,34 @@ package android.app {
method public boolean isUiModeLocked();
}
public class WindowConfiguration implements java.lang.Comparable android.os.Parcelable {
ctor public WindowConfiguration();
method public int compareTo(android.app.WindowConfiguration);
method public int describeContents();
method public int getActivityType();
method public android.graphics.Rect getAppBounds();
method public android.graphics.Rect getBounds();
method public int getWindowingMode();
method public void setActivityType(int);
method public void setAppBounds(android.graphics.Rect);
method public void setBounds(android.graphics.Rect);
method public void setTo(android.app.WindowConfiguration);
method public void setWindowingMode(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final int ACTIVITY_TYPE_ASSISTANT = 4; // 0x4
field public static final int ACTIVITY_TYPE_HOME = 2; // 0x2
field public static final int ACTIVITY_TYPE_RECENTS = 3; // 0x3
field public static final int ACTIVITY_TYPE_STANDARD = 1; // 0x1
field public static final int ACTIVITY_TYPE_UNDEFINED = 0; // 0x0
field public static final int WINDOWING_MODE_FREEFORM = 5; // 0x5
field public static final int WINDOWING_MODE_FULLSCREEN = 1; // 0x1
field public static final int WINDOWING_MODE_FULLSCREEN_OR_SPLIT_SCREEN_SECONDARY = 4; // 0x4
field public static final int WINDOWING_MODE_PINNED = 2; // 0x2
field public static final int WINDOWING_MODE_SPLIT_SCREEN_PRIMARY = 3; // 0x3
field public static final int WINDOWING_MODE_SPLIT_SCREEN_SECONDARY = 4; // 0x4
field public static final int WINDOWING_MODE_UNDEFINED = 0; // 0x0
}
}
package android.app.admin {
@@ -60,15 +181,36 @@ package android.app.admin {
method public boolean isDeviceManaged();
field public static final java.lang.String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_ALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_ALLOWED";
field public static final java.lang.String ACCOUNT_FEATURE_DEVICE_OR_PROFILE_OWNER_DISALLOWED = "android.account.DEVICE_OR_PROFILE_OWNER_DISALLOWED";
field public static final java.lang.String ACTION_DATA_SHARING_RESTRICTION_APPLIED = "android.app.action.DATA_SHARING_RESTRICTION_APPLIED";
field public static final java.lang.String EXTRA_RESTRICTION = "android.app.extra.RESTRICTION";
}
public static final class SecurityLog.SecurityEvent implements android.os.Parcelable {
ctor public SecurityLog.SecurityEvent(long, byte[]);
}
}
package android.app.backup {
public class BackupManager {
method public android.content.Intent getConfigurationIntent(java.lang.String);
method public android.content.Intent getDataManagementIntent(java.lang.String);
method public java.lang.String getDataManagementLabel(java.lang.String);
method public java.lang.String getDestinationString(java.lang.String);
}
}
package android.app.usage {
public class NetworkStatsManager {
method public void setPollForce(boolean);
}
public class StorageStatsManager {
method public boolean isQuotaSupported(java.util.UUID);
method public boolean isReservedSupported(java.util.UUID);
}
}
@@ -80,17 +222,20 @@ package android.content {
}
public abstract class Context {
method public abstract int getUserId();
}
public class ContextWrapper extends android.content.Context {
method public android.os.UserHandle getUser();
method public int getUserId();
method public void setAutofillCompatibilityEnabled(boolean);
}
}
package android.content.pm {
public class ActivityInfo extends android.content.pm.ComponentInfo implements android.os.Parcelable {
method public static boolean isTranslucentOrFloating(android.content.res.TypedArray);
field public static final int RESIZE_MODE_RESIZEABLE = 2; // 0x2
}
public class ApplicationInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
method public boolean isPrivilegedApp();
method public boolean isSystemApp();
@@ -103,8 +248,26 @@ package android.content.pm {
public abstract class PackageManager {
method public abstract java.lang.String getDefaultBrowserPackageNameAsUser(int);
method public abstract int getInstallReason(java.lang.String, android.os.UserHandle);
method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
method public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplicationsAsUser(int, int);
method public abstract java.lang.String[] getNamesForUids(int[]);
method public abstract java.lang.String getPermissionControllerPackageName();
method public abstract java.lang.String getServicesSystemSharedLibraryPackageName();
method public abstract java.lang.String getSharedSystemSharedLibraryPackageName();
method public abstract boolean isPermissionReviewModeEnabled();
field public static final java.lang.String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage";
field public static final java.lang.String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption";
field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000
field public static final int MATCH_KNOWN_PACKAGES = 4202496; // 0x402000
}
public class PermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
field public static final int PROTECTION_FLAG_SYSTEM_TEXT_CLASSIFIER = 65536; // 0x10000
field public static final int PROTECTION_FLAG_VENDOR_PRIVILEGED = 32768; // 0x8000
}
public final class ShortcutInfo implements android.os.Parcelable {
method public boolean isVisibleToPublisher();
}
public class ShortcutManager {
@@ -113,6 +276,14 @@ package android.content.pm {
}
package android.content.res {
public final class Configuration implements java.lang.Comparable android.os.Parcelable {
field public final android.app.WindowConfiguration windowConfiguration;
}
}
package android.database.sqlite {
public final class SQLiteDirectCursorDriver implements android.database.sqlite.SQLiteCursorDriver {
@@ -133,11 +304,20 @@ package android.database.sqlite {
method public static int getWALAutoCheckpoint();
method public static int getWALConnectionPoolSize();
method public static java.lang.String getWALSyncMode();
method public static boolean isCompatibilityWalSupported();
method public static int releaseMemory();
}
}
package android.graphics {
public final class ImageDecoder implements java.lang.AutoCloseable {
method public static android.graphics.ImageDecoder.Source createSource(android.content.res.Resources, java.io.InputStream, int);
}
}
package android.graphics.drawable {
public class AdaptiveIconDrawable extends android.graphics.drawable.Drawable implements android.graphics.drawable.Drawable.Callback {
@@ -170,6 +350,59 @@ package android.hardware.camera2 {
}
package android.hardware.display {
public final class AmbientBrightnessDayStats implements android.os.Parcelable {
method public int describeContents();
method public float[] getBucketBoundaries();
method public java.time.LocalDate getLocalDate();
method public float[] getStats();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.hardware.display.AmbientBrightnessDayStats> CREATOR;
}
public final class BrightnessChangeEvent implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessChangeEvent> CREATOR;
field public final float batteryLevel;
field public final float brightness;
field public final int colorTemperature;
field public final boolean isDefaultBrightnessConfig;
field public final boolean isUserSetBrightness;
field public final float lastBrightness;
field public final long[] luxTimestamps;
field public final float[] luxValues;
field public final boolean nightMode;
field public final java.lang.String packageName;
field public final float powerBrightnessFactor;
field public final long timeStamp;
}
public final class BrightnessConfiguration implements android.os.Parcelable {
method public int describeContents();
method public android.util.Pair<float[], float[]> getCurve();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.hardware.display.BrightnessConfiguration> CREATOR;
}
public static class BrightnessConfiguration.Builder {
ctor public BrightnessConfiguration.Builder(float[], float[]);
method public android.hardware.display.BrightnessConfiguration build();
method public android.hardware.display.BrightnessConfiguration.Builder setDescription(java.lang.String);
}
public final class DisplayManager {
method public java.util.List<android.hardware.display.AmbientBrightnessDayStats> getAmbientBrightnessStats();
method public android.hardware.display.BrightnessConfiguration getBrightnessConfiguration();
method public java.util.List<android.hardware.display.BrightnessChangeEvent> getBrightnessEvents();
method public android.hardware.display.BrightnessConfiguration getDefaultBrightnessConfiguration();
method public android.graphics.Point getStableDisplaySize();
method public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration);
}
}
package android.location {
public final class GnssClock implements android.os.Parcelable {
@@ -198,20 +431,20 @@ package android.location {
ctor public GnssMeasurement();
method public void reset();
method public void resetAutomaticGainControlLevel();
method public void resetCarrierCycles();
method public deprecated void resetCarrierCycles();
method public void resetCarrierFrequencyHz();
method public void resetCarrierPhase();
method public void resetCarrierPhaseUncertainty();
method public deprecated void resetCarrierPhase();
method public deprecated void resetCarrierPhaseUncertainty();
method public void resetSnrInDb();
method public void set(android.location.GnssMeasurement);
method public void setAccumulatedDeltaRangeMeters(double);
method public void setAccumulatedDeltaRangeState(int);
method public void setAccumulatedDeltaRangeUncertaintyMeters(double);
method public void setAutomaticGainControlLevelInDb(double);
method public void setCarrierCycles(long);
method public deprecated void setCarrierCycles(long);
method public void setCarrierFrequencyHz(float);
method public void setCarrierPhase(double);
method public void setCarrierPhaseUncertainty(double);
method public deprecated void setCarrierPhase(double);
method public deprecated void setCarrierPhaseUncertainty(double);
method public void setCn0DbHz(double);
method public void setConstellationType(int);
method public void setMultipathIndicator(int);
@@ -223,6 +456,7 @@ package android.location {
method public void setState(int);
method public void setSvid(int);
method public void setTimeOffsetNanos(double);
field public static final int ADR_STATE_ALL = 31; // 0x1f
}
public final class GnssMeasurementsEvent implements android.os.Parcelable {
@@ -242,7 +476,88 @@ package android.location {
}
public class LocationManager {
method public int getGnssYearOfHardware();
method public java.lang.String[] getBackgroundThrottlingWhitelist();
}
}
package android.media {
public final class AudioFocusRequest {
method public android.media.AudioManager.OnAudioFocusChangeListener getOnAudioFocusChangeListener();
}
public final class AudioFormat implements android.os.Parcelable {
method public static int channelCountFromInChannelMask(int);
method public static int channelCountFromOutChannelMask(int);
method public static int getBytesPerSample(int);
method public static boolean isEncodingLinearPcm(int);
}
public final class AudioPresentation {
ctor public AudioPresentation(int, int, java.util.Map<java.lang.String, java.lang.String>, java.lang.String, int, boolean, boolean, boolean);
method public int getPresentationId();
method public int getProgramId();
}
public final class BufferingParams implements android.os.Parcelable {
method public int describeContents();
method public int getInitialMarkMs();
method public int getResumePlaybackMarkMs();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.media.BufferingParams> CREATOR;
}
public static class BufferingParams.Builder {
ctor public BufferingParams.Builder();
ctor public BufferingParams.Builder(android.media.BufferingParams);
method public android.media.BufferingParams build();
method public android.media.BufferingParams.Builder setInitialMarkMs(int);
method public android.media.BufferingParams.Builder setResumePlaybackMarkMs(int);
}
public class MediaPlayer implements android.media.AudioRouting android.media.VolumeAutomation {
method public android.media.BufferingParams getBufferingParams();
method public void setBufferingParams(android.media.BufferingParams);
}
public final class PlaybackParams implements android.os.Parcelable {
method public int getAudioStretchMode();
method public android.media.PlaybackParams setAudioStretchMode(int);
}
public static final class VolumeShaper.Configuration.Builder {
method public android.media.VolumeShaper.Configuration.Builder setOptionFlags(int);
}
}
package android.media.audiofx {
public class AudioEffect {
method public static int byteArrayToInt(byte[]);
method public static short byteArrayToShort(byte[]);
method public int getParameter(byte[], byte[]) throws java.lang.IllegalStateException;
method public int getParameter(int, byte[]) throws java.lang.IllegalStateException;
method public int getParameter(int, int[]) throws java.lang.IllegalStateException;
method public int getParameter(int, short[]) throws java.lang.IllegalStateException;
method public int getParameter(int[], short[]) throws java.lang.IllegalStateException;
method public static byte[] intToByteArray(int);
method public static boolean isEffectTypeAvailable(java.util.UUID);
method public static boolean isError(int);
method public int setParameter(byte[], byte[]) throws java.lang.IllegalStateException;
method public int setParameter(int, int) throws java.lang.IllegalStateException;
method public int setParameter(int, short) throws java.lang.IllegalStateException;
method public int setParameter(int, byte[]) throws java.lang.IllegalStateException;
method public int setParameter(int[], int[]) throws java.lang.IllegalStateException;
method public int setParameter(int[], byte[]) throws java.lang.IllegalStateException;
method public void setParameterListener(android.media.audiofx.AudioEffect.OnParameterChangeListener);
method public static byte[] shortToByteArray(short);
field public static final java.util.UUID EFFECT_TYPE_NULL;
}
public static abstract interface AudioEffect.OnParameterChangeListener {
method public abstract void onParameterChange(android.media.audiofx.AudioEffect, int, byte[], byte[]);
}
}
@@ -269,9 +584,22 @@ package android.net {
package android.os {
public static class Build.VERSION {
field public static final int FIRST_SDK_INT;
field public static final int RESOURCES_SDK_INT;
}
public class DeviceIdleManager {
method public java.lang.String[] getSystemPowerWhitelist();
method public java.lang.String[] getSystemPowerWhitelistExceptIdle();
}
public class Environment {
method public static java.io.File buildPath(java.io.File, java.lang.String...);
}
public class IncidentManager {
method public void reportIncident(android.os.IncidentReportArgs);
method public void reportIncident(java.lang.String, byte[]);
}
public final class IncidentReportArgs implements android.os.Parcelable {
@@ -282,7 +610,6 @@ package android.os {
method public boolean containsSection(int);
method public int describeContents();
method public boolean isAll();
method public static android.os.IncidentReportArgs parseSetting(java.lang.String) throws java.lang.IllegalArgumentException;
method public void readFromParcel(android.os.Parcel);
method public int sectionCount();
method public void setAll(boolean);
@@ -290,24 +617,83 @@ package android.os {
field public static final android.os.Parcelable.Creator<android.os.IncidentReportArgs> CREATOR;
}
public final class PowerManager {
method public void nap(long);
}
public class Process {
method public static final int getThreadScheduler(int) throws java.lang.IllegalArgumentException;
}
public final class StrictMode {
method public static void setViolationListener(android.os.StrictMode.ViolationListener);
public final class RemoteCallback implements android.os.Parcelable {
ctor public RemoteCallback(android.os.RemoteCallback.OnResultListener);
ctor public RemoteCallback(android.os.RemoteCallback.OnResultListener, android.os.Handler);
method public int describeContents();
method public void sendResult(android.os.Bundle);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.os.RemoteCallback> CREATOR;
}
public static abstract interface StrictMode.ViolationListener {
method public abstract void onViolation(java.lang.String);
public static abstract interface RemoteCallback.OnResultListener {
method public abstract void onResult(android.os.Bundle);
}
public final class StrictMode {
method public static void setViolationLogger(android.os.StrictMode.ViolationLogger);
field public static final int DETECT_CUSTOM = 8; // 0x8
field public static final int DETECT_DISK_READ = 2; // 0x2
field public static final int DETECT_DISK_WRITE = 1; // 0x1
field public static final int DETECT_NETWORK = 4; // 0x4
field public static final int DETECT_RESOURCE_MISMATCH = 16; // 0x10
field public static final int DETECT_UNBUFFERED_IO = 32; // 0x20
field public static final int DETECT_VM_ACTIVITY_LEAKS = 1024; // 0x400
field public static final int DETECT_VM_CLEARTEXT_NETWORK = 16384; // 0x4000
field public static final int DETECT_VM_CLOSABLE_LEAKS = 512; // 0x200
field public static final int DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION = 32768; // 0x8000
field public static final int DETECT_VM_CURSOR_LEAKS = 256; // 0x100
field public static final int DETECT_VM_FILE_URI_EXPOSURE = 8192; // 0x2000
field public static final int DETECT_VM_INSTANCE_LEAKS = 2048; // 0x800
field public static final int DETECT_VM_NON_SDK_API_USAGE = 1073741824; // 0x40000000
field public static final int DETECT_VM_REGISTRATION_LEAKS = 4096; // 0x1000
field public static final int DETECT_VM_UNTAGGED_SOCKET = -2147483648; // 0x80000000
}
public static final class StrictMode.ViolationInfo implements android.os.Parcelable {
ctor public StrictMode.ViolationInfo(android.os.Parcel);
ctor public StrictMode.ViolationInfo(android.os.Parcel, boolean);
method public int describeContents();
method public void dump(android.util.Printer, java.lang.String);
method public int getPolicyMask();
method public java.lang.String getStackTrace();
method public int getViolationBit();
method public java.lang.String getViolationDetails();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.os.StrictMode.ViolationInfo> CREATOR;
field public java.lang.String broadcastIntentAction;
field public int durationMillis;
field public int numAnimationsRunning;
field public long numInstances;
field public java.lang.String[] tags;
field public int violationNumThisLoop;
field public long violationUptimeMillis;
}
public static abstract interface StrictMode.ViolationLogger {
method public abstract void log(android.os.StrictMode.ViolationInfo);
}
public class SystemProperties {
method public static java.lang.String get(java.lang.String, java.lang.String);
}
public final class UserHandle implements android.os.Parcelable {
method public static int getAppId(int);
method public int getIdentifier();
field public static final android.os.UserHandle SYSTEM;
}
public class UserManager {
method public static boolean isSplitSystemUser();
field public static final java.lang.String ACTION_USER_RESTRICTIONS_CHANGED = "android.os.action.USER_RESTRICTIONS_CHANGED";
}
@@ -332,8 +718,24 @@ package android.provider {
field public static final java.lang.String ACTION_ENTERPRISE_PRIVACY_SETTINGS = "android.settings.ENTERPRISE_PRIVACY_SETTINGS";
}
public static final class Settings.Global extends android.provider.Settings.NameValueTable {
field public static final java.lang.String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages";
field public static final java.lang.String HIDDEN_API_BLACKLIST_EXEMPTIONS = "hidden_api_blacklist_exemptions";
field public static final java.lang.String LOCATION_GLOBAL_KILL_SWITCH = "location_global_kill_switch";
field public static final java.lang.String LOW_POWER_MODE = "low_power";
field public static final java.lang.String LOW_POWER_MODE_STICKY = "low_power_sticky";
field public static final java.lang.String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package";
}
public static final class Settings.Secure extends android.provider.Settings.NameValueTable {
field public static final java.lang.String ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED = "accessibility_display_magnification_enabled";
field public static final java.lang.String AUTOFILL_FEATURE_FIELD_CLASSIFICATION = "autofill_field_classification";
field public static final java.lang.String AUTOFILL_SERVICE = "autofill_service";
field public static final java.lang.String AUTOFILL_USER_DATA_MAX_CATEGORY_COUNT = "autofill_user_data_max_category_count";
field public static final java.lang.String AUTOFILL_USER_DATA_MAX_FIELD_CLASSIFICATION_IDS_SIZE = "autofill_user_data_max_field_classification_size";
field public static final java.lang.String AUTOFILL_USER_DATA_MAX_USER_DATA_SIZE = "autofill_user_data_max_user_data_size";
field public static final java.lang.String AUTOFILL_USER_DATA_MAX_VALUE_LENGTH = "autofill_user_data_max_value_length";
field public static final java.lang.String AUTOFILL_USER_DATA_MIN_VALUE_LENGTH = "autofill_user_data_min_value_length";
field public static final java.lang.String DISABLED_PRINT_SERVICES = "disabled_print_services";
field public static final deprecated java.lang.String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES = "enabled_notification_policy_access_packages";
field public static final java.lang.String SYNC_PARENT_SOUNDS = "sync_parent_sounds";
@@ -347,6 +749,15 @@ package android.provider {
}
package android.security {
public class KeyStoreException extends java.lang.Exception {
ctor public KeyStoreException(int, java.lang.String);
method public int getErrorCode();
}
}
package android.security.keystore {
public abstract class AttestationUtils {
@@ -356,28 +767,70 @@ package android.security.keystore {
field public static final int ID_TYPE_SERIAL = 1; // 0x1
}
public static final class KeyGenParameterSpec.Builder {
method public android.security.keystore.KeyGenParameterSpec.Builder setUniqueIdIncluded(boolean);
}
public final class KeyProtection implements java.security.KeyStore.ProtectionParameter {
method public long getBoundToSpecificSecureUserId();
}
public static final class KeyProtection.Builder {
method public android.security.keystore.KeyProtection.Builder setBoundToSpecificSecureUserId(long);
}
}
package android.service.autofill {
public final class CharSequenceTransformation implements android.os.Parcelable android.service.autofill.Transformation {
public final class CharSequenceTransformation extends android.service.autofill.InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation {
method public void apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int) throws java.lang.Exception;
}
public final class ImageTransformation implements android.os.Parcelable android.service.autofill.Transformation {
public final class DateTransformation extends android.service.autofill.InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation {
method public void apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int) throws java.lang.Exception;
}
public final class LuhnChecksumValidator implements android.os.Parcelable android.service.autofill.Validator {
public final class DateValueSanitizer extends android.service.autofill.InternalSanitizer implements android.os.Parcelable android.service.autofill.Sanitizer {
method public android.view.autofill.AutofillValue sanitize(android.view.autofill.AutofillValue);
}
public final class FillResponse implements android.os.Parcelable {
method public int getFlags();
}
public final class ImageTransformation extends android.service.autofill.InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation {
method public void apply(android.service.autofill.ValueFinder, android.widget.RemoteViews, int) throws java.lang.Exception;
}
public abstract class InternalSanitizer implements android.os.Parcelable android.service.autofill.Sanitizer {
ctor public InternalSanitizer();
}
public abstract class InternalTransformation implements android.os.Parcelable android.service.autofill.Transformation {
ctor public InternalTransformation();
}
public abstract class InternalValidator implements android.os.Parcelable android.service.autofill.Validator {
ctor public InternalValidator();
method public abstract boolean isValid(android.service.autofill.ValueFinder);
}
public final class LuhnChecksumValidator extends android.service.autofill.InternalValidator implements android.os.Parcelable android.service.autofill.Validator {
method public boolean isValid(android.service.autofill.ValueFinder);
}
public final class RegexValidator implements android.os.Parcelable android.service.autofill.Validator {
public final class RegexValidator extends android.service.autofill.InternalValidator implements android.os.Parcelable android.service.autofill.Validator {
method public boolean isValid(android.service.autofill.ValueFinder);
}
public final class TextValueSanitizer extends android.service.autofill.InternalSanitizer implements android.os.Parcelable android.service.autofill.Sanitizer {
method public android.view.autofill.AutofillValue sanitize(android.view.autofill.AutofillValue);
}
public abstract interface ValueFinder {
method public abstract java.lang.String findByAutofillId(android.view.autofill.AutofillId);
method public default java.lang.String findByAutofillId(android.view.autofill.AutofillId);
method public abstract android.view.autofill.AutofillValue findRawValueByAutofillId(android.view.autofill.AutofillId);
}
}
@@ -397,6 +850,11 @@ package android.service.notification {
field public static final android.os.Parcelable.Creator<android.service.notification.Adjustment> CREATOR;
field public static final java.lang.String KEY_PEOPLE = "key_people";
field public static final java.lang.String KEY_SNOOZE_CRITERIA = "key_snooze_criteria";
field public static final java.lang.String KEY_USER_SENTIMENT = "key_user_sentiment";
}
public abstract class ConditionProviderService extends android.app.Service {
method public boolean isBound();
}
public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
@@ -410,6 +868,36 @@ package android.service.notification {
field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
}
public abstract class NotificationListenerService extends android.app.Service {
method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap, android.service.notification.NotificationStats, int);
}
public final class NotificationStats implements android.os.Parcelable {
ctor public NotificationStats();
ctor protected NotificationStats(android.os.Parcel);
method public int describeContents();
method public int getDismissalSurface();
method public boolean hasDirectReplied();
method public boolean hasExpanded();
method public boolean hasInteracted();
method public boolean hasSeen();
method public boolean hasSnoozed();
method public boolean hasViewedSettings();
method public void setDirectReplied();
method public void setDismissalSurface(int);
method public void setExpanded();
method public void setSeen();
method public void setSnoozed();
method public void setViewedSettings();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.service.notification.NotificationStats> CREATOR;
field public static final int DISMISSAL_AOD = 2; // 0x2
field public static final int DISMISSAL_NOT_DISMISSED = -1; // 0xffffffff
field public static final int DISMISSAL_OTHER = 0; // 0x0
field public static final int DISMISSAL_PEEK = 1; // 0x1
field public static final int DISMISSAL_SHADE = 3; // 0x3
}
public final class SnoozeCriterion implements android.os.Parcelable {
ctor public SnoozeCriterion(java.lang.String, java.lang.CharSequence, java.lang.CharSequence);
ctor protected SnoozeCriterion(android.os.Parcel);
@@ -451,10 +939,15 @@ package android.telephony {
public class ServiceState implements android.os.Parcelable {
method public void setCdmaSystemAndNetworkId(int, int);
method public void setCellBandwidths(int[]);
method public void setChannelNumber(int);
method public void setRilDataRadioTechnology(int);
method public void setRilVoiceRadioTechnology(int);
}
public class TelephonyManager {
method public int getCarrierIdListVersion();
method public void refreshUiccProfile();
method public void setCarrierTestOverride(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String);
field public static final int UNKNOWN_CARRIER_ID_LIST_VERSION = -1; // 0xffffffff
}
@@ -539,17 +1032,13 @@ package android.telephony.mbms.vendor {
}
package android.test.mock {
package android.text {
public class MockContext extends android.content.Context {
method public int getUserId();
}
public deprecated class MockPackageManager extends android.content.pm.PackageManager {
method public java.lang.String getDefaultBrowserPackageNameAsUser(int);
method public int getInstallReason(java.lang.String, android.os.UserHandle);
method public java.lang.String getPermissionControllerPackageName();
method public boolean isPermissionReviewModeEnabled();
public static final class Selection.MemoryTextWatcher implements android.text.TextWatcher {
ctor public Selection.MemoryTextWatcher();
method public void afterTextChanged(android.text.Editable);
method public void beforeTextChanged(java.lang.CharSequence, int, int, int);
method public void onTextChanged(java.lang.CharSequence, int, int, int);
}
}
@@ -690,25 +1179,25 @@ package android.util.proto {
field public static final long FIELD_COUNT_UNKNOWN = 0L; // 0x0L
field public static final int FIELD_ID_MASK = -8; // 0xfffffff8
field public static final int FIELD_ID_SHIFT = 3; // 0x3
field public static final long FIELD_TYPE_BOOL = 55834574848L; // 0xd00000000L
field public static final long FIELD_TYPE_BYTES = 64424509440L; // 0xf00000000L
field public static final long FIELD_TYPE_BOOL = 34359738368L; // 0x800000000L
field public static final long FIELD_TYPE_BYTES = 51539607552L; // 0xc00000000L
field public static final long FIELD_TYPE_DOUBLE = 4294967296L; // 0x100000000L
field public static final long FIELD_TYPE_ENUM = 68719476736L; // 0x1000000000L
field public static final long FIELD_TYPE_FIXED32 = 38654705664L; // 0x900000000L
field public static final long FIELD_TYPE_FIXED64 = 42949672960L; // 0xa00000000L
field public static final long FIELD_TYPE_ENUM = 60129542144L; // 0xe00000000L
field public static final long FIELD_TYPE_FIXED32 = 30064771072L; // 0x700000000L
field public static final long FIELD_TYPE_FIXED64 = 25769803776L; // 0x600000000L
field public static final long FIELD_TYPE_FLOAT = 8589934592L; // 0x200000000L
field public static final long FIELD_TYPE_INT32 = 12884901888L; // 0x300000000L
field public static final long FIELD_TYPE_INT64 = 17179869184L; // 0x400000000L
field public static final long FIELD_TYPE_INT32 = 21474836480L; // 0x500000000L
field public static final long FIELD_TYPE_INT64 = 12884901888L; // 0x300000000L
field public static final long FIELD_TYPE_MASK = 1095216660480L; // 0xff00000000L
field public static final long FIELD_TYPE_OBJECT = 73014444032L; // 0x1100000000L
field public static final long FIELD_TYPE_SFIXED32 = 47244640256L; // 0xb00000000L
field public static final long FIELD_TYPE_SFIXED64 = 51539607552L; // 0xc00000000L
field public static final long FIELD_TYPE_MESSAGE = 47244640256L; // 0xb00000000L
field public static final long FIELD_TYPE_SFIXED32 = 64424509440L; // 0xf00000000L
field public static final long FIELD_TYPE_SFIXED64 = 68719476736L; // 0x1000000000L
field public static final int FIELD_TYPE_SHIFT = 32; // 0x20
field public static final long FIELD_TYPE_SINT32 = 30064771072L; // 0x700000000L
field public static final long FIELD_TYPE_SINT64 = 34359738368L; // 0x800000000L
field public static final long FIELD_TYPE_STRING = 60129542144L; // 0xe00000000L
field public static final long FIELD_TYPE_UINT32 = 21474836480L; // 0x500000000L
field public static final long FIELD_TYPE_UINT64 = 25769803776L; // 0x600000000L
field public static final long FIELD_TYPE_SINT32 = 73014444032L; // 0x1100000000L
field public static final long FIELD_TYPE_SINT64 = 77309411328L; // 0x1200000000L
field public static final long FIELD_TYPE_STRING = 38654705664L; // 0x900000000L
field public static final long FIELD_TYPE_UINT32 = 55834574848L; // 0xd00000000L
field public static final long FIELD_TYPE_UINT64 = 17179869184L; // 0x400000000L
field public static final long FIELD_TYPE_UNKNOWN = 0L; // 0x0L
field public static final java.lang.String TAG = "ProtoOutputStream";
field public static final int WIRE_TYPE_END_GROUP = 4; // 0x4
@@ -732,6 +1221,15 @@ package android.view {
method public boolean isUiFocusable();
}
public final class Choreographer {
method public static long getFrameDelay();
method public void postCallback(int, java.lang.Runnable, java.lang.Object);
method public void postCallbackDelayed(int, java.lang.Runnable, java.lang.Object, long);
method public void removeCallbacks(int, java.lang.Runnable, java.lang.Object);
method public static void setFrameDelay(long);
field public static final int CALLBACK_ANIMATION = 1; // 0x1
}
public class FocusFinder {
method public static void sort(android.view.View[], int, int, android.view.ViewGroup, boolean);
}
@@ -754,6 +1252,7 @@ package android.view {
public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback {
method public android.view.View getTooltipView();
method public static boolean isDefaultFocusHighlightEnabled();
method public boolean isDefaultFocusHighlightNeeded(android.graphics.drawable.Drawable, android.graphics.drawable.Drawable);
method public boolean restoreFocusInCluster(int);
method public boolean restoreFocusNotInCluster();
@@ -781,6 +1280,7 @@ package android.view.accessibility {
public class AccessibilityNodeInfo implements android.os.Parcelable {
method public static void setNumInstancesInUseCounter(java.util.concurrent.atomic.AtomicInteger);
method public void writeToParcelNoRecycle(android.os.Parcel, int);
}
public final class AccessibilityWindowInfo implements android.os.Parcelable {
@@ -789,16 +1289,38 @@ package android.view.accessibility {
}
package android.view.animation {
public class AnimationUtils {
method public static void lockAnimationClock(long);
method public static void unlockAnimationClock();
}
}
package android.view.autofill {
public final class AutofillId implements android.os.Parcelable {
ctor public AutofillId(int);
ctor public AutofillId(android.view.autofill.AutofillId, int);
}
}
package android.view.inputmethod {
public final class InputMethodManager {
method public boolean isInputMethodPickerShown();
}
}
package android.widget {
public abstract class AbsListView extends android.widget.AdapterView implements android.widget.Filter.FilterListener android.text.TextWatcher android.view.ViewTreeObserver.OnGlobalLayoutListener android.view.ViewTreeObserver.OnTouchModeChangeListener {
method public final boolean shouldDrawSelector();
}
public class CalendarView extends android.widget.FrameLayout {
method public boolean getBoundsForDate(long, android.graphics.Rect);
}
@@ -809,6 +1331,17 @@ package android.widget {
field public static final int MODE_SPINNER = 1; // 0x1
}
public final class Magnifier {
method public android.graphics.Bitmap getContent();
method public static android.graphics.PointF getMagnifierDefaultSize();
method public android.graphics.Rect getWindowPositionOnScreen();
method public void setOnOperationCompleteCallback(android.widget.Magnifier.Callback);
}
public static abstract interface Magnifier.Callback {
method public abstract void onOperationComplete();
}
public class NumberPicker extends android.widget.LinearLayout {
method public java.lang.CharSequence getDisplayedValueForCurrentSelection();
}
@@ -821,6 +1354,10 @@ package android.widget {
method public boolean isPopupShowing();
}
public class TextClock extends android.widget.TextView {
method public void disableClockTick();
}
public class TimePicker extends android.widget.FrameLayout {
method public android.view.View getAmView();
method public android.view.View getHourView();

View File

@@ -28,6 +28,7 @@ message ResultsBundleEntry {
optional double value_double = 5;
optional sint64 value_long = 6;
optional ResultsBundle value_bundle = 7;
optional bytes value_bytes = 8;
}
message ResultsBundle {

View File

@@ -98,7 +98,8 @@ public class Am extends BaseCommand {
static final class MyShellCallback extends ShellCallback {
boolean mActive = true;
@Override public ParcelFileDescriptor onOpenOutputFile(String path, String seLinuxContext) {
@Override public ParcelFileDescriptor onOpenFile(String path, String seLinuxContext,
String mode) {
if (!mActive) {
System.err.println("Open attempt after active for: " + path);
return null;
@@ -159,7 +160,11 @@ public class Am extends BaseCommand {
} else if (opt.equals("-r")) {
instrument.rawMode = true;
} else if (opt.equals("-m")) {
instrument.proto = true;
instrument.protoStd = true;
} else if (opt.equals("-f")) {
instrument.protoFile = true;
if (peekNextArg() != null && !peekNextArg().startsWith("-"))
instrument.logPath = nextArg();
} else if (opt.equals("-e")) {
final String argKey = nextArgRequired();
final String argValue = nextArgRequired();

View File

@@ -25,23 +25,42 @@ import android.content.pm.IPackageManager;
import android.content.pm.InstrumentationInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.AndroidException;
import android.util.proto.ProtoOutputStream;
import android.view.IWindowManager;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
/**
* Runs the am instrument command
*
* Test Result Code:
* 1 - Test running
* 0 - Test passed
* -2 - assertion failure
* -1 - other exceptions
*
* Session Result Code:
* -1: Success
* other: Failure
*/
public class Instrument {
public static final String DEFAULT_LOG_DIR = "instrument-logs";
private final IActivityManager mAm;
private final IPackageManager mPm;
private final IWindowManager mWm;
@@ -50,7 +69,9 @@ public class Instrument {
public String profileFile = null;
public boolean wait = false;
public boolean rawMode = false;
public boolean proto = false;
boolean protoStd = false; // write proto to stdout
boolean protoFile = false; // write proto to a file
String logPath = null;
public boolean noWindowAnimation = false;
public boolean disableHiddenApiChecks = false;
public String abi = null;
@@ -183,18 +204,49 @@ public class Instrument {
* Printer for the protobuf based status reporting.
*/
private class ProtoStatusReporter implements StatusReporter {
private File mLog;
ProtoStatusReporter() {
if (protoFile) {
if (logPath == null) {
File logDir = new File(Environment.getLegacyExternalStorageDirectory(),
DEFAULT_LOG_DIR);
if (!logDir.exists() && !logDir.mkdirs()) {
System.err.format("Unable to create log directory: %s\n",
logDir.getAbsolutePath());
protoFile = false;
return;
}
SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd-hhmmss-SSS", Locale.US);
String fileName = String.format("log-%s.instrumentation_data_proto",
format.format(new Date()));
mLog = new File(logDir, fileName);
} else {
mLog = new File(Environment.getLegacyExternalStorageDirectory(), logPath);
File logDir = mLog.getParentFile();
if (!logDir.exists() && !logDir.mkdirs()) {
System.err.format("Unable to create log directory: %s\n",
logDir.getAbsolutePath());
protoFile = false;
return;
}
}
if (mLog.exists()) mLog.delete();
}
}
@Override
public void onInstrumentationStatusLocked(ComponentName name, int resultCode,
Bundle results) {
final ProtoOutputStream proto = new ProtoOutputStream();
final long token = proto.startRepeatedObject(InstrumentationData.Session.TEST_STATUS);
proto.writeSInt32(InstrumentationData.TestStatus.RESULT_CODE, resultCode);
final long token = proto.start(InstrumentationData.Session.TEST_STATUS);
proto.write(InstrumentationData.TestStatus.RESULT_CODE, resultCode);
writeBundle(proto, InstrumentationData.TestStatus.RESULTS, results);
proto.end(token);
proto.endRepeatedObject(token);
writeProtoToStdout(proto);
outputProto(proto);
}
@Override
@@ -202,80 +254,87 @@ public class Instrument {
Bundle results) {
final ProtoOutputStream proto = new ProtoOutputStream();
final long token = proto.startObject(InstrumentationData.Session.SESSION_STATUS);
proto.writeEnum(InstrumentationData.SessionStatus.STATUS_CODE,
final long token = proto.start(InstrumentationData.Session.SESSION_STATUS);
proto.write(InstrumentationData.SessionStatus.STATUS_CODE,
InstrumentationData.SESSION_FINISHED);
proto.writeSInt32(InstrumentationData.SessionStatus.RESULT_CODE, resultCode);
proto.write(InstrumentationData.SessionStatus.RESULT_CODE, resultCode);
writeBundle(proto, InstrumentationData.SessionStatus.RESULTS, results);
proto.end(token);
proto.endObject(token);
writeProtoToStdout(proto);
outputProto(proto);
}
@Override
public void onError(String errorText, boolean commandError) {
final ProtoOutputStream proto = new ProtoOutputStream();
final long token = proto.startObject(InstrumentationData.Session.SESSION_STATUS);
proto.writeEnum(InstrumentationData.SessionStatus.STATUS_CODE,
final long token = proto.start(InstrumentationData.Session.SESSION_STATUS);
proto.write(InstrumentationData.SessionStatus.STATUS_CODE,
InstrumentationData.SESSION_ABORTED);
proto.writeString(InstrumentationData.SessionStatus.ERROR_TEXT, errorText);
proto.write(InstrumentationData.SessionStatus.ERROR_TEXT, errorText);
proto.end(token);
proto.endObject(token);
writeProtoToStdout(proto);
outputProto(proto);
}
private void writeBundle(ProtoOutputStream proto, long fieldId, Bundle bundle) {
final long bundleToken = proto.startObject(fieldId);
final long bundleToken = proto.start(fieldId);
for (final String key: sorted(bundle.keySet())) {
final long entryToken = proto.startRepeatedObject(
InstrumentationData.ResultsBundle.ENTRIES);
proto.writeString(InstrumentationData.ResultsBundleEntry.KEY, key);
proto.write(InstrumentationData.ResultsBundleEntry.KEY, key);
final Object val = bundle.get(key);
if (val instanceof String) {
proto.writeString(InstrumentationData.ResultsBundleEntry.VALUE_STRING,
proto.write(InstrumentationData.ResultsBundleEntry.VALUE_STRING,
(String)val);
} else if (val instanceof Byte) {
proto.writeSInt32(InstrumentationData.ResultsBundleEntry.VALUE_INT,
proto.write(InstrumentationData.ResultsBundleEntry.VALUE_INT,
((Byte)val).intValue());
} else if (val instanceof Double) {
proto.writeDouble(InstrumentationData.ResultsBundleEntry.VALUE_DOUBLE,
((Double)val).doubleValue());
proto.write(InstrumentationData.ResultsBundleEntry.VALUE_DOUBLE, (double)val);
} else if (val instanceof Float) {
proto.writeFloat(InstrumentationData.ResultsBundleEntry.VALUE_FLOAT,
((Float)val).floatValue());
proto.write(InstrumentationData.ResultsBundleEntry.VALUE_FLOAT, (float)val);
} else if (val instanceof Integer) {
proto.writeSInt32(InstrumentationData.ResultsBundleEntry.VALUE_INT,
((Integer)val).intValue());
proto.write(InstrumentationData.ResultsBundleEntry.VALUE_INT, (int)val);
} else if (val instanceof Long) {
proto.writeSInt64(InstrumentationData.ResultsBundleEntry.VALUE_LONG,
((Long)val).longValue());
proto.write(InstrumentationData.ResultsBundleEntry.VALUE_LONG, (long)val);
} else if (val instanceof Short) {
proto.writeSInt32(InstrumentationData.ResultsBundleEntry.VALUE_INT,
((Short)val).intValue());
proto.write(InstrumentationData.ResultsBundleEntry.VALUE_INT, (short)val);
} else if (val instanceof Bundle) {
writeBundle(proto, InstrumentationData.ResultsBundleEntry.VALUE_BUNDLE,
(Bundle)val);
} else if (val instanceof byte[]) {
proto.write(InstrumentationData.ResultsBundleEntry.VALUE_BYTES, (byte[])val);
}
proto.endRepeatedObject(entryToken);
proto.end(entryToken);
}
proto.endObject(bundleToken);
proto.end(bundleToken);
}
private void writeProtoToStdout(ProtoOutputStream proto) {
try {
System.out.write(proto.getBytes());
System.out.flush();
} catch (IOException ex) {
System.err.println("Error writing finished response: ");
ex.printStackTrace(System.err);
private void outputProto(ProtoOutputStream proto) {
byte[] out = proto.getBytes();
if (protoStd) {
try {
System.out.write(out);
System.out.flush();
} catch (IOException ex) {
System.err.println("Error writing finished response: ");
ex.printStackTrace(System.err);
}
}
if (protoFile) {
try (OutputStream os = new FileOutputStream(mLog, true)) {
os.write(proto.getBytes());
os.flush();
} catch (IOException ex) {
System.err.format("Cannot write to %s:\n", mLog.getAbsolutePath());
ex.printStackTrace();
}
}
}
}
@@ -379,7 +438,7 @@ public class Instrument {
try {
// Choose which output we will do.
if (proto) {
if (protoFile || protoStd) {
reporter = new ProtoStatusReporter();
} else if (wait) {
reporter = new TextStatusReporter(rawMode);
@@ -401,7 +460,7 @@ public class Instrument {
mWm.setAnimationScale(2, 0.0f);
}
// Figure out which component we are tring to do.
// Figure out which component we are trying to do.
final ComponentName cn = parseComponentName(componentNameArg);
// Choose an ABI if necessary

View File

@@ -23,8 +23,8 @@ import android.app.backup.IBackupManager;
import android.app.backup.IBackupObserver;
import android.app.backup.IRestoreObserver;
import android.app.backup.IRestoreSession;
import android.app.backup.RestoreSet;
import android.app.backup.ISelectBackupTransportCallback;
import android.app.backup.RestoreSet;
import android.content.ComponentName;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
@@ -37,6 +37,7 @@ import android.util.ArraySet;
import com.android.internal.annotations.GuardedBy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.CountDownLatch;
@@ -296,6 +297,10 @@ public final class Bmgr {
super.backupFinished(status);
System.out.println("Backup finished with result: "
+ convertBackupStatusToString(status));
if (status == BackupManager.ERROR_BACKUP_CANCELLED) {
System.out.println("Backups can be cancelled if a backup is already running, check "
+ "backup dumpsys");
}
}
}
@@ -317,7 +322,7 @@ public final class Bmgr {
case BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED:
return "Size quota exceeded";
case BackupManager.ERROR_BACKUP_CANCELLED:
return "Backup Cancelled";
return "Backup cancelled";
default:
return "Unknown error";
}
@@ -339,18 +344,16 @@ public final class Bmgr {
System.err.println(PM_NOT_RUNNING_ERR);
}
if (installedPackages != null) {
List<String> packages = new ArrayList<>();
for (PackageInfo pi : installedPackages) {
try {
if (mBmgr.isAppEligibleForBackup(pi.packageName)) {
packages.add(pi.packageName);
}
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(BMGR_NOT_RUNNING_ERR);
}
String[] packages =
installedPackages.stream().map(p -> p.packageName).toArray(String[]::new);
String[] filteredPackages = {};
try {
filteredPackages = mBmgr.filterAppsEligibleForBackup(packages);
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(BMGR_NOT_RUNNING_ERR);
}
backupNowPackages(packages, nonIncrementalBackup);
backupNowPackages(Arrays.asList(filteredPackages), nonIncrementalBackup);
}
}

View File

@@ -24,16 +24,15 @@ LOCAL_SRC_FILES:= \
BootAnimationUtil.cpp \
ifeq ($(PRODUCT_IOT),true)
LOCAL_SRC_FILES += \
iot/iotbootanimation_main.cpp \
iot/BootAction.cpp
LOCAL_SHARED_LIBRARIES += \
libandroidthings \
libbase \
libbinder
libchrome \
LOCAL_STATIC_LIBRARIES += cpufeatures
LOCAL_SRC_FILES += \
iot/iotbootanimation_main.cpp \
iot/BootAction.cpp \
iot/BootParameters.cpp \
else
@@ -77,13 +76,19 @@ LOCAL_SHARED_LIBRARIES := \
libutils \
libbinder \
libui \
libskia \
libhwui \
libEGL \
libGLESv1_CM \
libgui \
libtinyalsa \
libbase
ifeq ($(PRODUCT_IOT),true)
LOCAL_INIT_RC := iot/bootanim_iot.rc
endif # PRODUCT_IOT
ifdef TARGET_32_BIT_SURFACEFLINGER
LOCAL_32_BIT_ONLY := true
endif

View File

@@ -66,9 +66,12 @@
namespace android {
static const char OEM_BOOTANIMATION_FILE[] = "/oem/media/bootanimation.zip";
static const char PRODUCT_BOOTANIMATION_FILE[] = "/product/media/bootanimation.zip";
static const char SYSTEM_BOOTANIMATION_FILE[] = "/system/media/bootanimation.zip";
static const char PRODUCT_ENCRYPTED_BOOTANIMATION_FILE[] = "/product/media/bootanimation-encrypted.zip";
static const char SYSTEM_ENCRYPTED_BOOTANIMATION_FILE[] = "/system/media/bootanimation-encrypted.zip";
static const char OEM_SHUTDOWNANIMATION_FILE[] = "/oem/media/shutdownanimation.zip";
static const char PRODUCT_SHUTDOWNANIMATION_FILE[] = "/product/media/shutdownanimation.zip";
static const char SYSTEM_SHUTDOWNANIMATION_FILE[] = "/system/media/shutdownanimation.zip";
static const char SYSTEM_DATA_DIR_PATH[] = "/data/system";
@@ -260,9 +263,9 @@ status_t BootAnimation::readyToRun() {
sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
dinfo.w, dinfo.h, PIXEL_FORMAT_RGB_565);
SurfaceComposerClient::openGlobalTransaction();
control->setLayer(0x40000000);
SurfaceComposerClient::closeGlobalTransaction();
SurfaceComposerClient::Transaction t;
t.setLayer(control, 0x40000000)
.apply();
sp<Surface> s = control->getSurface();
@@ -308,14 +311,20 @@ status_t BootAnimation::readyToRun() {
bool encryptedAnimation = atoi(decrypt) != 0 ||
!strcmp("trigger_restart_min_framework", decrypt);
if (!mShuttingDown && encryptedAnimation &&
(access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0)) {
mZipFileName = SYSTEM_ENCRYPTED_BOOTANIMATION_FILE;
return NO_ERROR;
if (!mShuttingDown && encryptedAnimation) {
static const char* encryptedBootFiles[] =
{PRODUCT_ENCRYPTED_BOOTANIMATION_FILE, SYSTEM_ENCRYPTED_BOOTANIMATION_FILE};
for (const char* f : encryptedBootFiles) {
if (access(f, R_OK) == 0) {
mZipFileName = f;
return NO_ERROR;
}
}
}
static const char* bootFiles[] = {OEM_BOOTANIMATION_FILE, SYSTEM_BOOTANIMATION_FILE};
static const char* bootFiles[] =
{PRODUCT_BOOTANIMATION_FILE, OEM_BOOTANIMATION_FILE, SYSTEM_BOOTANIMATION_FILE};
static const char* shutdownFiles[] =
{OEM_SHUTDOWNANIMATION_FILE, SYSTEM_SHUTDOWNANIMATION_FILE};
{PRODUCT_SHUTDOWNANIMATION_FILE, OEM_SHUTDOWNANIMATION_FILE, SYSTEM_SHUTDOWNANIMATION_FILE};
for (const char* f : (!mShuttingDown ? bootFiles : shutdownFiles)) {
if (access(f, R_OK) == 0) {

View File

@@ -30,7 +30,7 @@ The first line defines the general parameters of the animation:
It is followed by a number of rows of the form:
TYPE COUNT PAUSE PATH [#RGBHEX CLOCK]
TYPE COUNT PAUSE PATH [#RGBHEX [CLOCK1 [CLOCK2]]]
* **TYPE:** a single char indicating what type of animation segment this is:
+ `p` -- this part will play unless interrupted by the end of the boot
@@ -39,11 +39,38 @@ It is followed by a number of rows of the form:
* **PAUSE:** number of FRAMES to delay after this part ends
* **PATH:** directory in which to find the frames for this part (e.g. `part0`)
* **RGBHEX:** _(OPTIONAL)_ a background color, specified as `#RRGGBB`
* **CLOCK:** _(OPTIONAL)_ the y-coordinate at which to draw the current time (for watches)
* **CLOCK1, CLOCK2:** _(OPTIONAL)_ the coordinates at which to draw the current time (for watches):
+ If only `CLOCK1` is provided it is the y-coordinate of the clock and the x-coordinate
defaults to `c`
+ If both `CLOCK1` and `CLOCK2` are provided then `CLOCK1` is the x-coordinate and `CLOCK2` is
the y-coodinate
+ Values can be either a positive integer, a negative integer, or `c`
- `c` -- will centre the text
- `n` -- will position the text n pixels from the start; left edge for x-axis, bottom edge
for y-axis
- `-n` -- will position the text n pixels from the end; right edge for x-axis, top edge
for y-axis
- Examples:
* `-24` or `c -24` will position the text 24 pixels from the top of the screen,
centred horizontally
* `16 c` will position the text 16 pixels from the left of the screen, centred
vertically
* `-32 32` will position the text such that the bottom right corner is 32 pixels above
and 32 pixels left of the edges of the screen
There is also a special TYPE, `$SYSTEM`, that loads `/system/media/bootanimation.zip`
and plays that.
## clock_font.png
The file used to draw the time on top of the boot animation. The font format is as follows:
* The file specifies glyphs for the ascii characters 32-127 (0x20-0x7F), both regular weight and
bold weight.
* The image is divided into a grid of characters
* There are 16 columns and 6 rows
* Each row is divided in half: regular weight glyphs on the top half, bold glyphs on the bottom
* For a NxM image each character glyph will be N/16 pixels wide and M/(12*2) pixels high
## loading and playing frames
Each part is scanned and loaded directly from the zip archive. Within a part directory, every file

View File

@@ -18,17 +18,11 @@
#define LOG_TAG "BootAction"
#include <android-base/strings.h>
#include <cpu-features.h>
#include <dlfcn.h>
#include <pio/peripheral_manager_client.h>
#include <utils/Log.h>
using android::base::Split;
using android::base::Join;
using android::base::StartsWith;
using android::base::EndsWith;
namespace android {
BootAction::~BootAction() {
@@ -37,7 +31,8 @@ BootAction::~BootAction() {
}
}
bool BootAction::init(const std::string& libraryPath, const std::string& config) {
bool BootAction::init(const std::string& libraryPath,
const std::vector<ABootActionParameter>& parameters) {
APeripheralManagerClient* client = nullptr;
ALOGD("Connecting to peripheralmanager");
// Wait for peripheral manager to come up.
@@ -51,16 +46,12 @@ bool BootAction::init(const std::string& libraryPath, const std::string& config)
ALOGD("Peripheralmanager is up.");
APeripheralManagerClient_delete(client);
std::string path_to_lib = libraryPath;
if (!parseConfig(config, &path_to_lib)) {
return false;
}
ALOGI("Loading boot action %s", path_to_lib.c_str());
mLibHandle = dlopen(path_to_lib.c_str(), RTLD_NOW);
ALOGI("Loading boot action %s", libraryPath.c_str());
mLibHandle = dlopen(libraryPath.c_str(), RTLD_NOW);
if (mLibHandle == nullptr) {
ALOGE("Unable to load library at %s :: %s",
path_to_lib.c_str(), dlerror());
libraryPath.c_str(), dlerror());
return false;
}
@@ -87,7 +78,7 @@ bool BootAction::init(const std::string& libraryPath, const std::string& config)
}
ALOGD("Entering boot_action_init");
bool result = mLibInit();
bool result = mLibInit(parameters.data(), parameters.size());
ALOGD("Returned from boot_action_init");
return result;
}
@@ -115,61 +106,4 @@ bool BootAction::loadSymbol(const char* symbol, void** loaded) {
return true;
}
bool BootAction::parseConfig(const std::string& config, std::string* path) {
auto lines = Split(config, "\n");
if (lines.size() < 1) {
ALOGE("Config format invalid, expected one line, found %d",
lines.size());
return false;
}
size_t lineNumber = 0;
auto& line1 = lines.at(lineNumber);
while (StartsWith(line1, "#")) {
if (lines.size() < ++lineNumber) {
ALOGE("Config file contains no non-comment lines.");
return false;
}
line1 = lines.at(lineNumber);
}
const std::string libraryNameToken("LIBRARY_NAME=");
if (!StartsWith(line1, libraryNameToken.c_str())) {
ALOGE("Invalid config format, expected second line to start with %s "
"Instead found: %s", libraryNameToken.c_str(), line1.c_str());
return false;
}
std::string libraryName = line1.substr(libraryNameToken.length());
*path += "/";
*path += architectureDirectory();
*path += "/";
*path += libraryName;
return true;
}
const char* BootAction::architectureDirectory() {
switch(android_getCpuFamily()) {
case ANDROID_CPU_FAMILY_ARM:
return "arm";
case ANDROID_CPU_FAMILY_X86:
return "x86";
case ANDROID_CPU_FAMILY_MIPS:
return "mips";
case ANDROID_CPU_FAMILY_ARM64:
return "arm64";
case ANDROID_CPU_FAMILY_X86_64:
return "x86_64";
case ANDROID_CPU_FAMILY_MIPS64:
return "mips64";
default:
ALOGE("Unsupported cpu family: %d", android_getCpuFamily());
return "";
}
}
} // namespace android

View File

@@ -18,7 +18,9 @@
#define _BOOTANIMATION_BOOTACTION_H
#include <string>
#include <vector>
#include <boot_action/boot_action.h> // libandroidthings native API.
#include <utils/RefBase.h>
namespace android {
@@ -26,11 +28,10 @@ namespace android {
class BootAction : public RefBase {
public:
~BootAction();
// Parse the contents of the config file. We expect one line:
// LIBRARY_NAME=
//
// LIBRARY_NAME is the name of the shared library that contains the boot action.
bool init(const std::string& libraryPath, const std::string& config);
// libraryPath is a fully qualified path to the target .so library.
bool init(const std::string& libraryPath,
const std::vector<ABootActionParameter>& parameters);
// The animation is going to start playing partNumber for the playCount'th
// time, update the action as needed.
@@ -43,13 +44,12 @@ public:
void shutdown();
private:
typedef bool (*libInit)();
typedef bool (*libInit)(const ABootActionParameter* parameters,
size_t num_parameters);
typedef void (*libStartPart)(int partNumber, int playNumber);
typedef void (*libShutdown)();
bool parseConfig(const std::string& config, std::string* path);
bool loadSymbol(const char* symbol, void** loaded);
const char* architectureDirectory();
void* mLibHandle = nullptr;
libInit mLibInit = nullptr;

View File

@@ -0,0 +1,124 @@
/*
* 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 "BootParameters.h"
#define LOG_TAG "BootParameters"
#include <fcntl.h>
#include <string>
#include <android-base/file.h>
#include <base/json/json_parser.h>
#include <base/json/json_reader.h>
#include <base/json/json_value_converter.h>
#include <utils/Log.h>
using android::base::RemoveFileIfExists;
using android::base::ReadFileToString;
using base::JSONReader;
using base::JSONValueConverter;
using base::Value;
namespace android {
namespace {
// Brightness and volume are stored as integer strings in next_boot.json.
// They are divided by this constant to produce the actual float values in
// range [0.0, 1.0]. This constant must match its counterpart in
// DeviceManager.
constexpr const float kFloatScaleFactor = 1000.0f;
constexpr const char* kNextBootFile = "/data/misc/bootanimation/next_boot.json";
constexpr const char* kLastBootFile = "/data/misc/bootanimation/last_boot.json";
void swapBootConfigs() {
// rename() will fail if next_boot.json doesn't exist, so delete
// last_boot.json manually first.
std::string err;
if (!RemoveFileIfExists(kLastBootFile, &err))
ALOGE("Unable to delete last boot file: %s", err.c_str());
if (rename(kNextBootFile, kLastBootFile) && errno != ENOENT)
ALOGE("Unable to swap boot files: %s", strerror(errno));
int fd = open(kNextBootFile, O_CREAT, DEFFILEMODE);
if (fd == -1) {
ALOGE("Unable to create next boot file: %s", strerror(errno));
} else {
// Make next_boot.json writable to everyone so DeviceManagementService
// can save saved_parameters there.
if (fchmod(fd, DEFFILEMODE))
ALOGE("Unable to set next boot file permissions: %s", strerror(errno));
close(fd);
}
}
} // namespace
BootParameters::SavedBootParameters::SavedBootParameters()
: brightness(-kFloatScaleFactor), volume(-kFloatScaleFactor) {}
void BootParameters::SavedBootParameters::RegisterJSONConverter(
JSONValueConverter<SavedBootParameters>* converter) {
converter->RegisterIntField("brightness", &SavedBootParameters::brightness);
converter->RegisterIntField("volume", &SavedBootParameters::volume);
converter->RegisterRepeatedString("param_names",
&SavedBootParameters::param_names);
converter->RegisterRepeatedString("param_values",
&SavedBootParameters::param_values);
}
BootParameters::BootParameters() {
swapBootConfigs();
loadParameters();
}
void BootParameters::loadParameters() {
std::string contents;
if (!ReadFileToString(kLastBootFile, &contents)) {
if (errno != ENOENT)
ALOGE("Unable to read from %s: %s", kLastBootFile, strerror(errno));
return;
}
std::unique_ptr<Value> json = JSONReader::Read(contents);
if (json.get() == nullptr) {
return;
}
JSONValueConverter<SavedBootParameters> converter;
if (converter.Convert(*(json.get()), &mRawParameters)) {
mBrightness = mRawParameters.brightness / kFloatScaleFactor;
mVolume = mRawParameters.volume / kFloatScaleFactor;
if (mRawParameters.param_names.size() == mRawParameters.param_values.size()) {
for (size_t i = 0; i < mRawParameters.param_names.size(); i++) {
mParameters.push_back({
.key = mRawParameters.param_names[i]->c_str(),
.value = mRawParameters.param_values[i]->c_str()
});
}
} else {
ALOGW("Parameter names and values size mismatch");
}
}
}
} // namespace android

View File

@@ -0,0 +1,73 @@
/*
* 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.
*/
#ifndef _BOOTANIMATION_BOOT_PARAMETERS_H_
#define _BOOTANIMATION_BOOT_PARAMETERS_H_
#include <list>
#include <vector>
#include <base/json/json_value_converter.h>
#include <boot_action/boot_action.h> // libandroidthings native API.
namespace android {
// Provides access to the parameters set by DeviceManager.reboot().
class BootParameters {
public:
// Constructor loads the parameters for this boot and swaps the param files
// to clear the parameters for next boot.
BootParameters();
// Returns true if volume/brightness were explicitly set on reboot.
bool hasVolume() const { return mVolume >= 0; }
bool hasBrightness() const { return mBrightness >= 0; }
// Returns volume/brightness in [0,1], or -1 if unset.
float getVolume() const { return mVolume; }
float getBrightness() const { return mBrightness; }
// Returns the additional boot parameters that were set on reboot.
const std::vector<ABootActionParameter>& getParameters() const { return mParameters; }
private:
// Raw boot saved_parameters loaded from .json.
struct SavedBootParameters {
int brightness;
int volume;
std::vector<std::unique_ptr<std::string>> param_names;
std::vector<std::unique_ptr<std::string>> param_values;
SavedBootParameters();
static void RegisterJSONConverter(
::base::JSONValueConverter<SavedBootParameters>* converter);
};
void loadParameters();
float mVolume = -1.f;
float mBrightness = -1.f;
std::vector<ABootActionParameter> mParameters;
// ABootActionParameter is just a raw pointer so we need to keep the
// original strings around to avoid losing them.
SavedBootParameters mRawParameters;
};
} // namespace android
#endif // _BOOTANIMATION_BOOT_PARAMETERS_H_

View File

@@ -0,0 +1,2 @@
on post-fs-data
mkdir /data/misc/bootanimation 0777 root root

View File

@@ -16,7 +16,7 @@
#define LOG_TAG "IotBootAnimation"
#include <android-base/file.h>
#include <base/files/file_util.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
@@ -28,28 +28,40 @@
#include "BootAction.h"
#include "BootAnimationUtil.h"
#include "BootParameters.h"
using namespace android;
using android::base::ReadFileToString;
// Create a typedef for readability.
typedef android::BootAnimation::Animation Animation;
namespace {
class BootActionAnimationCallbacks : public android::BootAnimation::Callbacks {public:
constexpr const char* kDefaultLibName = "libbootaction.so";
class BootActionAnimationCallbacks : public android::BootAnimation::Callbacks {
public:
BootActionAnimationCallbacks(std::unique_ptr<BootParameters> bootParameters)
: mBootParameters(std::move(bootParameters)) {}
void init(const Vector<Animation::Part>&) override {
// Create and initialize BootActions if we have a boot_action.conf.
std::string bootActionConf;
if (ReadFileToString("/oem/app/etc/boot_action.conf", &bootActionConf)) {
mBootAction = new BootAction();
if (!mBootAction->init("/oem/app/lib", bootActionConf)) {
mBootAction = NULL;
}
} else {
ALOGI("No boot actions specified");
std::string library_path("/oem/lib/");
// This value is optionally provided by the user and will be written to
// /oem/oem.prop.
char property[PROP_VALUE_MAX] = {0};
property_get("ro.oem.bootactions.lib", property, kDefaultLibName);
library_path += property;
if (!::base::PathExists(::base::FilePath(library_path))) {
ALOGI("Skipping boot actions: %s does not exist", library_path.c_str());
return;
}
mBootAction = new BootAction();
if (!mBootAction->init(library_path, mBootParameters->getParameters())) {
mBootAction = NULL;
}
};
void playPart(int partNumber, const Animation::Part&, int playNumber) override {
@@ -60,6 +72,20 @@ class BootActionAnimationCallbacks : public android::BootAnimation::Callbacks {p
void shutdown() override {
if (mBootAction != nullptr) {
// If we have a bootaction we want to wait until we are actually
// told to shut down. If the animation exits early keep the action
// running.
char value[PROPERTY_VALUE_MAX] = {0};
for (int exitRequested = 0; exitRequested == 0; ) {
property_get("service.bootanim.exit", value, "0");
exitRequested = atoi(value);
// Poll value at 10hz.
if (exitRequested == 0) {
usleep(100000);
}
}
mBootAction->shutdown();
// Give it two seconds to shut down.
sleep(2);
@@ -68,6 +94,7 @@ class BootActionAnimationCallbacks : public android::BootAnimation::Callbacks {p
};
private:
std::unique_ptr<BootParameters> mBootParameters;
sp<BootAction> mBootAction = nullptr;
};
@@ -76,6 +103,9 @@ private:
int main() {
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_DISPLAY);
// Clear our params for next boot no matter what.
std::unique_ptr<BootParameters> bootParameters(new BootParameters());
if (bootAnimationDisabled()) {
ALOGI("boot animation disabled");
return 0;
@@ -86,7 +116,8 @@ int main() {
sp<ProcessState> proc(ProcessState::self());
ProcessState::self()->startThreadPool();
sp<BootAnimation> boot = new BootAnimation(new BootActionAnimationCallbacks());
sp<BootAnimation> boot = new BootAnimation(
new BootActionAnimationCallbacks(std::move(bootParameters)));
IPCThreadState::self()->joinThreadPool();
return 0;

View File

@@ -26,18 +26,18 @@ import android.database.Cursor;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.FileUtils;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.UserHandle;
import android.text.TextUtils;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import libcore.io.Streams;
import libcore.io.IoUtils;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
/**
* This class is a command line utility for manipulating content. A client
@@ -122,13 +122,14 @@ public class Content {
+ "\n"
+ "usage: adb shell content read --uri <URI> [--user <USER_ID>]\n"
+ " Example:\n"
+ " # cat default ringtone to a file, then pull to host\n"
+ " adb shell 'content read --uri content://settings/system/ringtone >"
+ " /mnt/sdcard/tmp.ogg' && adb pull /mnt/sdcard/tmp.ogg\n"
+ " adb shell 'content read --uri content://settings/system/ringtone_cache' > host.ogg\n"
+ "\n"
+ "usage: adb shell content write --uri <URI> [--user <USER_ID>]\n"
+ " Example:\n"
+ " adb shell 'content write --uri content://settings/system/ringtone_cache' < host.ogg\n"
+ "\n"
+ "usage: adb shell content gettype --uri <URI> [--user <USER_ID>]\n"
+ " Example:\n"
+ " # Show the mime-type of the URI\n"
+ " adb shell content gettype --uri content://media/internal/audio/media/\n"
+ "\n";
@@ -139,6 +140,7 @@ public class Content {
private static final String ARGUMENT_QUERY = "query";
private static final String ARGUMENT_CALL = "call";
private static final String ARGUMENT_READ = "read";
private static final String ARGUMENT_WRITE = "write";
private static final String ARGUMENT_GET_TYPE = "gettype";
private static final String ARGUMENT_WHERE = "--where";
private static final String ARGUMENT_BIND = "--bind";
@@ -179,6 +181,8 @@ public class Content {
return parseCallCommand();
} else if (ARGUMENT_READ.equals(operation)) {
return parseReadCommand();
} else if (ARGUMENT_WRITE.equals(operation)) {
return parseWriteCommand();
} else if (ARGUMENT_GET_TYPE.equals(operation)) {
return parseGetTypeCommand();
} else {
@@ -339,6 +343,25 @@ public class Content {
return new ReadCommand(uri, userId);
}
private WriteCommand parseWriteCommand() {
Uri uri = null;
int userId = UserHandle.USER_SYSTEM;
for (String argument; (argument = mTokenizer.nextArg())!= null;) {
if (ARGUMENT_URI.equals(argument)) {
uri = Uri.parse(argumentValueRequired(argument));
} else if (ARGUMENT_USER.equals(argument)) {
userId = Integer.parseInt(argumentValueRequired(argument));
} else {
throw new IllegalArgumentException("Unsupported argument: " + argument);
}
}
if (uri == null) {
throw new IllegalArgumentException("Content provider URI not specified."
+ " Did you specify --uri argument?");
}
return new WriteCommand(uri, userId);
}
public QueryCommand parseQueryCommand() {
Uri uri = null;
int userId = UserHandle.USER_SYSTEM;
@@ -535,7 +558,9 @@ public class Content {
@Override
public void onExecute(IContentProvider provider) throws Exception {
Bundle result = provider.call(null, mMethod, mArg, mExtras);
final int size = result.size(); // unpack
if (result != null) {
result.size(); // unpack
}
System.out.println("Result: " + result);
}
}
@@ -559,20 +584,21 @@ public class Content {
@Override
public void onExecute(IContentProvider provider) throws Exception {
final ParcelFileDescriptor fd = provider.openFile(null, mUri, "r", null, null);
copy(new FileInputStream(fd.getFileDescriptor()), System.out);
try (ParcelFileDescriptor fd = provider.openFile(null, mUri, "r", null, null)) {
FileUtils.copy(fd.getFileDescriptor(), FileDescriptor.out);
}
}
}
private static class WriteCommand extends Command {
public WriteCommand(Uri uri, int userId) {
super(uri, userId);
}
private static void copy(InputStream is, OutputStream os) throws IOException {
final byte[] buffer = new byte[8 * 1024];
int read;
try {
while ((read = is.read(buffer)) > -1) {
os.write(buffer, 0, read);
}
} finally {
IoUtils.closeQuietly(is);
IoUtils.closeQuietly(os);
@Override
public void onExecute(IContentProvider provider) throws Exception {
try (ParcelFileDescriptor fd = provider.openFile(null, mUri, "w", null, null)) {
FileUtils.copy(FileDescriptor.in, fd.getFileDescriptor());
}
}
}

View File

@@ -45,6 +45,8 @@ public final class Dpm extends BaseCommand {
private static final String COMMAND_SET_DEVICE_OWNER = "set-device-owner";
private static final String COMMAND_SET_PROFILE_OWNER = "set-profile-owner";
private static final String COMMAND_REMOVE_ACTIVE_ADMIN = "remove-active-admin";
private static final String COMMAND_CLEAR_FREEZE_PERIOD_RECORD = "clear-freeze-period-record";
private static final String COMMAND_FORCE_SECURITY_LOGS = "force-security-logs";
private IDevicePolicyManager mDevicePolicyManager;
private int mUserId = UserHandle.USER_SYSTEM;
@@ -75,7 +77,15 @@ public final class Dpm extends BaseCommand {
"\n" +
"dpm remove-active-admin: Disables an active admin, the admin must have declared" +
" android:testOnly in the application in its manifest. This will also remove" +
" device and profile owners\n");
" device and profile owners.\n" +
"\n" +
"dpm " + COMMAND_CLEAR_FREEZE_PERIOD_RECORD + ": clears framework-maintained " +
"record of past freeze periods that the device went through. For use during " +
"feature development to prevent triggering restriction on setting freeze " +
"periods.\n" +
"\n" +
"dpm " + COMMAND_FORCE_SECURITY_LOGS + ": makes all security logs available to " +
"the DPC and triggers DeviceAdminReceiver.onSecurityLogsAvailable() if needed.");
}
@Override
@@ -101,11 +111,29 @@ public final class Dpm extends BaseCommand {
case COMMAND_REMOVE_ACTIVE_ADMIN:
runRemoveActiveAdmin();
break;
case COMMAND_CLEAR_FREEZE_PERIOD_RECORD:
runClearFreezePeriodRecord();
break;
case COMMAND_FORCE_SECURITY_LOGS:
runForceSecurityLogs();
break;
default:
throw new IllegalArgumentException ("unknown command '" + command + "'");
}
}
private void runForceSecurityLogs() throws RemoteException, InterruptedException {
while (true) {
final long toWait = mDevicePolicyManager.forceSecurityLogs();
if (toWait == 0) {
break;
}
System.out.println("We have to wait for " + toWait + " milliseconds...");
Thread.sleep(toWait);
}
System.out.println("Success");
}
private void parseArgs(boolean canHaveName) {
String opt;
while ((opt = nextOption()) != null) {
@@ -190,6 +218,11 @@ public final class Dpm extends BaseCommand {
+ mComponent.toShortString() + " for user " + mUserId);
}
private void runClearFreezePeriodRecord() throws RemoteException {
mDevicePolicyManager.clearSystemUpdatePolicyFreezePeriodRecord();
System.out.println("Success");
}
private ComponentName parseComponentName(String component) {
ComponentName cn = ComponentName.unflattenFromString(component);
if (cn == null) {

View File

@@ -101,15 +101,16 @@ Device* Device::open(int32_t id, const char* name, int32_t vid, int32_t pid,
struct uhid_event ev;
memset(&ev, 0, sizeof(ev));
ev.type = UHID_CREATE;
strncpy((char*)ev.u.create.name, name, UHID_MAX_NAME_LENGTH);
ev.u.create.rd_data = descriptor.get();
ev.u.create.rd_size = descriptorSize;
ev.u.create.bus = BUS_BLUETOOTH;
ev.u.create.vendor = vid;
ev.u.create.product = pid;
ev.u.create.version = 0;
ev.u.create.country = 0;
ev.type = UHID_CREATE2;
strncpy((char*)ev.u.create2.name, name, UHID_MAX_NAME_LENGTH);
memcpy(&ev.u.create2.rd_data, descriptor.get(),
descriptorSize * sizeof(ev.u.create2.rd_data[0]));
ev.u.create2.rd_size = descriptorSize;
ev.u.create2.bus = BUS_BLUETOOTH;
ev.u.create2.vendor = vid;
ev.u.create2.product = pid;
ev.u.create2.version = 0;
ev.u.create2.country = 0;
errno = 0;
ssize_t ret = TEMP_FAILURE_RETRY(::write(fd, &ev, sizeof(ev)));
@@ -158,9 +159,9 @@ Device::~Device() {
void Device::sendReport(uint8_t* report, size_t reportSize) {
struct uhid_event ev;
memset(&ev, 0, sizeof(ev));
ev.type = UHID_INPUT;
ev.u.input.size = reportSize;
memcpy(&ev.u.input.data, report, reportSize);
ev.type = UHID_INPUT2;
ev.u.input2.size = reportSize;
memcpy(&ev.u.input2.data, report, reportSize);
ssize_t ret = TEMP_FAILURE_RETRY(::write(mFd, &ev, sizeof(ev)));
if (ret < 0 || ret != sizeof(ev)) {
LOGE("Failed to send hid event: %s", strerror(errno));

View File

@@ -2,15 +2,8 @@
#
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_MODULE := imelib
LOCAL_MODULE_STEM := ime
include $(BUILD_JAVA_LIBRARY)
include $(CLEAR_VARS)
LOCAL_MODULE := ime
LOCAL_MODULE_CLASS := EXECUTABLES
LOCAL_SRC_FILES := ime
LOCAL_REQUIRED_MODULES := imelib
include $(BUILD_PREBUILT)

View File

@@ -1,8 +1,2 @@
#!/system/bin/sh
# Script to start "pm" on the device, which has a very rudimentary
# shell.
#
base=/system
export CLASSPATH=$base/framework/ime.jar
exec app_process $base/bin com.android.commands.ime.Ime "$@"
exec cmd input_method ime "$@"

View File

@@ -1,248 +0,0 @@
/*
* Copyright (C) 2007 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.commands.ime;
import com.android.internal.view.IInputMethodManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.PrintStreamPrinter;
import android.util.Printer;
import android.view.inputmethod.InputMethodInfo;
import java.util.List;
public final class Ime {
IInputMethodManager mImm;
private String[] mArgs;
private int mNextArg;
private String mCurArgData;
private static final String IMM_NOT_RUNNING_ERR =
"Error: Could not access the Input Method Manager. Is the system running?";
public static void main(String[] args) {
new Ime().run(args);
}
public void run(String[] args) {
if (args.length < 1) {
showUsage();
return;
}
mImm = IInputMethodManager.Stub.asInterface(ServiceManager.getService("input_method"));
if (mImm == null) {
System.err.println(IMM_NOT_RUNNING_ERR);
return;
}
mArgs = args;
String op = args[0];
mNextArg = 1;
if ("list".equals(op)) {
runList();
return;
}
if ("enable".equals(op)) {
runSetEnabled(true);
return;
}
if ("disable".equals(op)) {
runSetEnabled(false);
return;
}
if ("set".equals(op)) {
runSet();
return;
}
if (op != null) {
System.err.println("Error: unknown command '" + op + "'");
}
showUsage();
}
/**
* Execute the list sub-command.
*/
private void runList() {
String opt;
boolean all = false;
boolean brief = false;
while ((opt=nextOption()) != null) {
if (opt.equals("-a")) {
all = true;
} else if (opt.equals("-s")) {
brief = true;
} else {
System.err.println("Error: Unknown option: " + opt);
showUsage();
return;
}
}
List<InputMethodInfo> methods;
if (!all) {
try {
methods = mImm.getEnabledInputMethodList();
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(IMM_NOT_RUNNING_ERR);
return;
}
} else {
try {
methods = mImm.getInputMethodList();
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(IMM_NOT_RUNNING_ERR);
return;
}
}
if (methods != null) {
Printer pr = new PrintStreamPrinter(System.out);
for (int i=0; i<methods.size(); i++) {
InputMethodInfo imi = methods.get(i);
if (brief) {
System.out.println(imi.getId());
} else {
System.out.println(imi.getId() + ":");
imi.dump(pr, " ");
}
}
}
}
private void runSetEnabled(boolean state) {
String id = nextArg();
if (id == null) {
System.err.println("Error: no input method ID specified");
showUsage();
return;
}
try {
boolean res = mImm.setInputMethodEnabled(id, state);
if (state) {
System.out.println("Input method " + id + ": "
+ (res ? "already enabled" : "now enabled"));
} else {
System.out.println("Input method " + id + ": "
+ (res ? "now disabled" : "already disabled"));
}
} catch (IllegalArgumentException e) {
System.err.println("Error: " + e.getMessage());
return;
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(IMM_NOT_RUNNING_ERR);
return;
}
}
private void runSet() {
String id = nextArg();
if (id == null) {
System.err.println("Error: no input method ID specified");
showUsage();
return;
}
try {
mImm.setInputMethod(null, id);
System.out.println("Input method " + id + " selected");
} catch (IllegalArgumentException e) {
System.err.println("Error: " + e.getMessage());
return;
} catch (RemoteException e) {
System.err.println(e.toString());
System.err.println(IMM_NOT_RUNNING_ERR);
return;
}
}
private String nextOption() {
if (mNextArg >= mArgs.length) {
return null;
}
String arg = mArgs[mNextArg];
if (!arg.startsWith("-")) {
return null;
}
mNextArg++;
if (arg.equals("--")) {
return null;
}
if (arg.length() > 1 && arg.charAt(1) != '-') {
if (arg.length() > 2) {
mCurArgData = arg.substring(2);
return arg.substring(0, 2);
} else {
mCurArgData = null;
return arg;
}
}
mCurArgData = null;
return arg;
}
private String nextOptionData() {
if (mCurArgData != null) {
return mCurArgData;
}
if (mNextArg >= mArgs.length) {
return null;
}
String data = mArgs[mNextArg];
mNextArg++;
return data;
}
private String nextArg() {
if (mNextArg >= mArgs.length) {
return null;
}
String arg = mArgs[mNextArg];
mNextArg++;
return arg;
}
private static void showUsage() {
System.err.println("usage: ime list [-a] [-s]");
System.err.println(" ime enable ID");
System.err.println(" ime disable ID");
System.err.println(" ime set ID");
System.err.println("");
System.err.println("The list command prints all enabled input methods. Use");
System.err.println("the -a option to see all input methods. Use");
System.err.println("the -s option to see only a single summary line of each.");
System.err.println("");
System.err.println("The enable command allows the given input method ID to be used.");
System.err.println("");
System.err.println("The disable command disallows the given input method ID from use.");
System.err.println("");
System.err.println("The set command switches to the given input method ID.");
}
}

View File

@@ -37,7 +37,7 @@ gen_src_dir := $(local-generated-sources-dir)
gen := $(gen_src_dir)/incident_sections.cpp
$(gen): $(HOST_OUT_EXECUTABLES)/incident-section-gen
$(gen): PRIVATE_CUSTOM_TOOL = \
$(HOST_OUT_EXECUTABLES)/incident-section-gen > $@
$(HOST_OUT_EXECUTABLES)/incident-section-gen incident > $@
$(gen): $(HOST_OUT_EXECUTABLES)/incident-section-gen
$(transform-generated-source)
LOCAL_GENERATED_SOURCES += $(gen)

View File

@@ -25,6 +25,7 @@
#include <binder/IServiceManager.h>
#include <utils/Looper.h>
#include <cstring>
#include <fcntl.h>
#include <getopt.h>
#include <stdio.h>
@@ -93,6 +94,33 @@ StatusListener::onReportFailed()
return Status::ok();
}
// ================================================================================
static void section_list(FILE* out) {
IncidentSection sections[INCIDENT_SECTION_COUNT];
int i = 0;
int j = 0;
// sort the sections based on id
while (i < INCIDENT_SECTION_COUNT) {
IncidentSection curr = INCIDENT_SECTIONS[i];
for (int k = 0; k < j; k++) {
if (curr.id > sections[k].id) {
continue;
}
IncidentSection tmp = curr;
curr = sections[k];
sections[k] = tmp;
}
sections[j] = curr;
i++;
j++;
}
fprintf(out, "available sections:\n");
for (int i = 0; i < INCIDENT_SECTION_COUNT; ++i) {
fprintf(out, "id: %4d, name: %s\n", sections[i].id, sections[i].name);
}
}
// ================================================================================
static IncidentSection const*
find_section(const char* name)
@@ -116,6 +144,26 @@ find_section(const char* name)
return NULL;
}
// ================================================================================
static int
get_dest(const char* arg)
{
if (strcmp(arg, "L") == 0
|| strcmp(arg, "LOCAL") == 0) {
return DEST_LOCAL;
}
if (strcmp(arg, "E") == 0
|| strcmp(arg, "EXPLICIT") == 0) {
return DEST_EXPLICIT;
}
if (strcmp(arg, "A") == 0
|| strcmp(arg, "AUTO") == 0
|| strcmp(arg, "AUTOMATIC") == 0) {
return DEST_AUTOMATIC;
}
return -1; // return the default value
}
// ================================================================================
static void
usage(FILE* out)
@@ -127,6 +175,8 @@ usage(FILE* out)
fprintf(out, "OPTIONS\n");
fprintf(out, " -b (default) print the report to stdout (in proto format)\n");
fprintf(out, " -d send the report into dropbox\n");
fprintf(out, " -l list available sections\n");
fprintf(out, " -p privacy spec, LOCAL, EXPLICIT or AUTOMATIC\n");
fprintf(out, "\n");
fprintf(out, " SECTION the field numbers of the incident report fields to include\n");
fprintf(out, "\n");
@@ -138,20 +188,27 @@ main(int argc, char** argv)
Status status;
IncidentReportArgs args;
enum { DEST_DROPBOX, DEST_STDOUT } destination = DEST_STDOUT;
int dest = -1; // default
// Parse the args
int opt;
while ((opt = getopt(argc, argv, "bhd")) != -1) {
while ((opt = getopt(argc, argv, "bhdlp:")) != -1) {
switch (opt) {
case 'b':
destination = DEST_STDOUT;
break;
case 'h':
usage(stdout);
return 0;
case 'l':
section_list(stdout);
return 0;
case 'b':
destination = DEST_STDOUT;
break;
case 'd':
destination = DEST_DROPBOX;
break;
case 'p':
dest = get_dest(optarg);
break;
default:
usage(stderr);
return 1;
@@ -179,8 +236,7 @@ main(int argc, char** argv)
}
}
}
args.setDest(dest);
// Start the thread pool.
sp<ProcessState> ps(ProcessState::self());
@@ -209,6 +265,7 @@ main(int argc, char** argv)
if (!status.isOk()) {
fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
return 1;
}
// Wait for the result and print out the data they send.

View File

@@ -0,0 +1,64 @@
cc_defaults {
name: "incident_helper_defaults",
cflags: [
"-Wall",
"-Werror",
"-g",
"-O0"
],
local_include_dirs: [
"src/",
"src/parsers/",
],
srcs: [
"src/parsers/*.cpp",
"src/TextParserBase.cpp",
"src/ih_util.cpp",
],
generated_headers: ["gen-platform-proto-constants"],
shared_libs: [
"libbase",
"liblog",
"libprotoutil",
"libutils",
],
}
cc_binary {
name: "incident_helper",
defaults: ["incident_helper_defaults"],
srcs: ["src/main.cpp"],
}
cc_test {
name: "incident_helper_test",
test_suites: ["device-tests"],
defaults: ["incident_helper_defaults"],
local_include_dirs: ["src/"],
srcs: [
"tests/*.cpp",
],
data: [
"testdata/*",
],
static_libs: [
"libgmock",
"libplatformprotos"
],
shared_libs: [
"libprotobuf-cpp-full"
],
proto: {
type: "full",
},
}

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<configuration description="Config for incident_helper_test">
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />
<option name="push" value="incident_helper_test->/data/nativetest/incident_helper_test" />
<option name="push" value="testdata->/data/nativetest/testdata" />
</target_preparer>
<option name="test-suite-tag" value="apct" />
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/nativetest" />
<option name="module-name" value="incident_helper_test" />
</test>
</configuration>

View File

@@ -0,0 +1,2 @@
jinyithu@google.com
kwekua@google.com

View File

@@ -0,0 +1,26 @@
# incident_helper
It is an executable used to help parsing text format data to protobuf.
## How to build, deploy, unit test
For the first time, build the test and create an empty directly on device:
```
root$ make -j incident_helper_test && adb shell mkdir /data/nativetest64/incident_helper_test
```
Run the test on a device
```
root$ mmm -j frameworks/base/cmds/incident_helper && \
adb push $OUT/data/nativetest64/incident_helper_test/* /data/nativetest64/incident_helper_test/ && \
adb shell /data/nativetest64/incident_helper_test/incident_helper_test 2>/dev/null
```
## How to adapt proto changes
If add a new proto file, add it in Android.bp under frameworks/base/ and make incident helper
```
root$ make -j48 incident_helper
```

View File

@@ -0,0 +1,55 @@
/*
* 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.
*/
#define LOG_TAG "incident_helper"
#include "TextParserBase.h"
#include <android-base/file.h>
using namespace android::base;
// ================================================================================
status_t NoopParser::Parse(const int in, const int out) const
{
string content;
if (!ReadFdToString(in, &content)) {
fprintf(stderr, "[%s]Failed to read data from incidentd\n", this->name.string());
return -1;
}
if (!WriteStringToFd(content, out)) {
fprintf(stderr, "[%s]Failed to write data to incidentd\n", this->name.string());
return -1;
}
return NO_ERROR;
}
// ================================================================================
status_t ReverseParser::Parse(const int in, const int out) const
{
string content;
if (!ReadFdToString(in, &content)) {
fprintf(stderr, "[%s]Failed to read data from incidentd\n", this->name.string());
return -1;
}
// reverse the content
reverse(content.begin(), content.end());
if (!WriteStringToFd(content, out)) {
fprintf(stderr, "[%s]Failed to write data to incidentd\n", this->name.string());
return -1;
}
return NO_ERROR;
}

View File

@@ -0,0 +1,72 @@
/*
* 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.
*/
#ifndef TEXT_PARSER_BASE_H
#define TEXT_PARSER_BASE_H
#include <utils/Errors.h>
#include <utils/String8.h>
using namespace android;
using namespace std;
/**
* Base class for text parser
*/
class TextParserBase {
public:
String8 name;
TextParserBase(String8 name) : name(name) {};
virtual ~TextParserBase() {};
virtual status_t Parse(const int in, const int out) const = 0;
};
/**
* No op parser returns what it reads
*/
class NoopParser : public TextParserBase {
public:
NoopParser() : TextParserBase(String8("NoopParser")) {};
~NoopParser() {};
virtual status_t Parse(const int in, const int out) const;
};
/**
* This parser is used for testing only, results in timeout.
*/
class TimeoutParser : public TextParserBase {
public:
TimeoutParser() : TextParserBase(String8("TimeoutParser")) {};
~TimeoutParser() {};
virtual status_t Parse(const int /** in */, const int /** out */) const { while (true); };
};
/**
* This parser is used for testing only, results in reversed input text.
*/
class ReverseParser : public TextParserBase {
public:
ReverseParser() : TextParserBase(String8("ReverseParser")) {};
~ReverseParser() {};
virtual status_t Parse(const int in, const int out) const;
};
#endif // TEXT_PARSER_BASE_H

View File

@@ -0,0 +1,458 @@
/*
* 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.
*/
#define LOG_TAG "incident_helper"
#include "ih_util.h"
#include <algorithm>
#include <sstream>
#include <unistd.h>
bool isValidChar(char c) {
uint8_t v = (uint8_t)c;
return (v >= (uint8_t)'a' && v <= (uint8_t)'z')
|| (v >= (uint8_t)'A' && v <= (uint8_t)'Z')
|| (v >= (uint8_t)'0' && v <= (uint8_t)'9')
|| (v == (uint8_t)'_');
}
std::string trim(const std::string& s, const std::string& charset) {
const auto head = s.find_first_not_of(charset);
if (head == std::string::npos) return "";
const auto tail = s.find_last_not_of(charset);
return s.substr(head, tail - head + 1);
}
static inline std::string toLowerStr(const std::string& s) {
std::string res(s);
std::transform(res.begin(), res.end(), res.begin(), ::tolower);
return res;
}
static inline std::string trimDefault(const std::string& s) {
return trim(s, DEFAULT_WHITESPACE);
}
static inline std::string trimHeader(const std::string& s) {
return toLowerStr(trimDefault(s));
}
static inline bool isNumber(const std::string& s) {
std::string::const_iterator it = s.begin();
while (it != s.end() && std::isdigit(*it)) ++it;
return !s.empty() && it == s.end();
}
// This is similiar to Split in android-base/file.h, but it won't add empty string
static void split(const std::string& line, std::vector<std::string>& words,
const trans_func& func, const std::string& delimiters) {
words.clear(); // clear the buffer before split
size_t base = 0;
size_t found;
while (true) {
found = line.find_first_of(delimiters, base);
if (found != base) {
std::string word = (*func) (line.substr(base, found - base));
if (!word.empty()) {
words.push_back(word);
}
}
if (found == line.npos) break;
base = found + 1;
}
}
header_t parseHeader(const std::string& line, const std::string& delimiters) {
header_t header;
trans_func f = &trimHeader;
split(line, header, f, delimiters);
return header;
}
record_t parseRecord(const std::string& line, const std::string& delimiters) {
record_t record;
trans_func f = &trimDefault;
split(line, record, f, delimiters);
return record;
}
bool getColumnIndices(std::vector<int>& indices, const char** headerNames, const std::string& line) {
indices.clear();
size_t lastIndex = 0;
int i = 0;
while (headerNames[i] != NULL) {
std::string s = headerNames[i];
lastIndex = line.find(s, lastIndex);
if (lastIndex == std::string::npos) {
fprintf(stderr, "Bad Task Header: %s\n", line.c_str());
return false;
}
lastIndex += s.length();
indices.push_back(lastIndex);
i++;
}
return true;
}
record_t parseRecordByColumns(const std::string& line, const std::vector<int>& indices, const std::string& delimiters) {
record_t record;
int lastIndex = 0;
int lastBeginning = 0;
int lineSize = (int)line.size();
for (std::vector<int>::const_iterator it = indices.begin(); it != indices.end(); ++it) {
int idx = *it;
if (idx <= lastIndex) {
// We saved up until lastIndex last time, so we should start at
// lastIndex + 1 this time.
idx = lastIndex + 1;
}
if (idx > lineSize) {
if (lastIndex < idx && lastIndex < lineSize) {
// There's a little bit more for us to save, which we'll do
// outside of the loop.
break;
}
// If we're past the end of the line AND we've already saved everything up to the end.
fprintf(stderr, "index wrong: lastIndex: %d, idx: %d, lineSize: %d\n", lastIndex, idx, lineSize);
record.clear(); // The indices are wrong, return empty.
return record;
}
while (idx < lineSize && delimiters.find(line[idx++]) == std::string::npos);
record.push_back(trimDefault(line.substr(lastIndex, idx - lastIndex)));
lastBeginning = lastIndex;
lastIndex = idx;
}
if (lineSize - lastIndex > 0) {
int beginning = lastIndex;
if (record.size() == indices.size()) {
// We've already encountered all of the columns...put whatever is
// left in the last column.
record.pop_back();
beginning = lastBeginning;
}
record.push_back(trimDefault(line.substr(beginning, lineSize - beginning)));
}
return record;
}
void printRecord(const record_t& record) {
fprintf(stderr, "Record: { ");
if (record.size() == 0) {
fprintf(stderr, "}\n");
return;
}
for(size_t i = 0; i < record.size(); ++i) {
if(i != 0) fprintf(stderr, "\", ");
fprintf(stderr, "\"%s", record[i].c_str());
}
fprintf(stderr, "\" }\n");
}
bool stripPrefix(std::string* line, const char* key, bool endAtDelimiter) {
const auto head = line->find_first_not_of(DEFAULT_WHITESPACE);
if (head == std::string::npos) return false;
int len = (int)line->length();
int i = 0;
int j = head;
while (key[i] != '\0') {
if (j >= len || key[i++] != line->at(j++)) {
return false;
}
}
if (endAtDelimiter) {
// this means if the line only have prefix or no delimiter, we still return false.
if (j == len || isValidChar(line->at(j))) return false;
}
line->assign(trimDefault(line->substr(j)));
return true;
}
bool stripSuffix(std::string* line, const char* key, bool endAtDelimiter) {
const auto tail = line->find_last_not_of(DEFAULT_WHITESPACE);
if (tail == std::string::npos) return false;
int i = 0;
while (key[++i] != '\0'); // compute the size of the key
int j = tail;
while (i > 0) {
if (j < 0 || key[--i] != line->at(j--)) {
return false;
}
}
if (endAtDelimiter) {
// this means if the line only have suffix or no delimiter, we still return false.
if (j < 0 || isValidChar(line->at(j))) return false;
}
line->assign(trimDefault(line->substr(0, j+1)));
return true;
}
std::string behead(std::string* line, const char cut) {
auto found = line->find_first_of(cut);
if (found == std::string::npos) {
std::string head = line->substr(0);
line->assign("");
return head;
}
std::string head = line->substr(0, found);
while(line->at(found) == cut) found++; // trim more cut of the rest
line->assign(line->substr(found));
return head;
}
int toInt(const std::string& s) {
return atoi(s.c_str());
}
long long toLongLong(const std::string& s) {
return atoll(s.c_str());
}
double toDouble(const std::string& s) {
return atof(s.c_str());
}
// ==============================================================================
Reader::Reader(const int fd)
{
mFile = fdopen(fd, "r");
mStatus = mFile == NULL ? "Invalid fd " + std::to_string(fd) : "";
}
Reader::~Reader()
{
if (mFile != NULL) fclose(mFile);
}
bool Reader::readLine(std::string* line) {
if (mFile == NULL) return false;
char* buf = NULL;
size_t len = 0;
ssize_t read = getline(&buf, &len, mFile);
if (read != -1) {
std::string s(buf);
line->assign(trim(s, DEFAULT_NEWLINE));
} else if (errno == EINVAL) {
mStatus = "Bad Argument";
}
free(buf);
return read != -1;
}
bool Reader::ok(std::string* error) {
error->assign(mStatus);
return mStatus.empty();
}
// ==============================================================================
Table::Table(const char* names[], const uint64_t ids[], const int count)
:mEnums(),
mEnumValuesByName()
{
std::map<std::string, uint64_t> fields;
for (int i = 0; i < count; i++) {
fields[names[i]] = ids[i];
}
mFields = fields;
}
Table::~Table()
{
}
void
Table::addEnumTypeMap(const char* field, const char* enumNames[], const int enumValues[], const int enumSize)
{
if (mFields.find(field) == mFields.end()) {
fprintf(stderr, "Field '%s' not found", field);
return;
}
std::map<std::string, int> enu;
for (int i = 0; i < enumSize; i++) {
enu[enumNames[i]] = enumValues[i];
}
mEnums[field] = enu;
}
void
Table::addEnumNameToValue(const char* enumName, const int enumValue)
{
mEnumValuesByName[enumName] = enumValue;
}
bool
Table::insertField(ProtoOutputStream* proto, const std::string& name, const std::string& value)
{
if (mFields.find(name) == mFields.end()) return false;
uint64_t found = mFields[name];
record_t repeats; // used for repeated fields
switch ((found & FIELD_COUNT_MASK) | (found & FIELD_TYPE_MASK)) {
case FIELD_COUNT_SINGLE | FIELD_TYPE_DOUBLE:
case FIELD_COUNT_SINGLE | FIELD_TYPE_FLOAT:
proto->write(found, toDouble(value));
break;
case FIELD_COUNT_SINGLE | FIELD_TYPE_STRING:
case FIELD_COUNT_SINGLE | FIELD_TYPE_BYTES:
proto->write(found, value);
break;
case FIELD_COUNT_SINGLE | FIELD_TYPE_INT64:
case FIELD_COUNT_SINGLE | FIELD_TYPE_SINT64:
case FIELD_COUNT_SINGLE | FIELD_TYPE_UINT64:
case FIELD_COUNT_SINGLE | FIELD_TYPE_FIXED64:
case FIELD_COUNT_SINGLE | FIELD_TYPE_SFIXED64:
proto->write(found, toLongLong(value));
break;
case FIELD_COUNT_SINGLE | FIELD_TYPE_BOOL:
if (strcmp(toLowerStr(value).c_str(), "true") == 0 || strcmp(value.c_str(), "1") == 0) {
proto->write(found, true);
break;
}
if (strcmp(toLowerStr(value).c_str(), "false") == 0 || strcmp(value.c_str(), "0") == 0) {
proto->write(found, false);
break;
}
return false;
case FIELD_COUNT_SINGLE | FIELD_TYPE_ENUM:
// if the field has its own enum mapping, use this, otherwise use general name to value mapping.
if (mEnums.find(name) != mEnums.end()) {
if (mEnums[name].find(value) != mEnums[name].end()) {
proto->write(found, mEnums[name][value]);
} else {
proto->write(found, 0); // TODO: should get the default enum value (Unknown)
}
} else if (mEnumValuesByName.find(value) != mEnumValuesByName.end()) {
proto->write(found, mEnumValuesByName[value]);
} else if (isNumber(value)) {
proto->write(found, toInt(value));
} else {
return false;
}
break;
case FIELD_COUNT_SINGLE | FIELD_TYPE_INT32:
case FIELD_COUNT_SINGLE | FIELD_TYPE_SINT32:
case FIELD_COUNT_SINGLE | FIELD_TYPE_UINT32:
case FIELD_COUNT_SINGLE | FIELD_TYPE_FIXED32:
case FIELD_COUNT_SINGLE | FIELD_TYPE_SFIXED32:
proto->write(found, toInt(value));
break;
// REPEATED TYPE below:
case FIELD_COUNT_REPEATED | FIELD_TYPE_INT32:
repeats = parseRecord(value, COMMA_DELIMITER);
for (size_t i=0; i<repeats.size(); i++) {
proto->write(found, toInt(repeats[i]));
}
break;
case FIELD_COUNT_REPEATED | FIELD_TYPE_STRING:
repeats = parseRecord(value, COMMA_DELIMITER);
for (size_t i=0; i<repeats.size(); i++) {
proto->write(found, repeats[i]);
}
break;
default:
return false;
}
return true;
}
// ================================================================================
Message::Message(Table* table)
:mTable(table),
mPreviousField(""),
mTokens(),
mSubMessages()
{
}
Message::~Message()
{
}
void
Message::addSubMessage(uint64_t fieldId, Message* fieldMsg)
{
for (auto iter = mTable->mFields.begin(); iter != mTable->mFields.end(); iter++) {
if (iter->second == fieldId) {
mSubMessages[iter->first] = fieldMsg;
return;
}
}
}
bool
Message::insertField(ProtoOutputStream* proto, const std::string& name, const std::string& value)
{
// If the field name can be found, it means the name is a primitive field.
if (mTable->mFields.find(name) != mTable->mFields.end()) {
endSession(proto);
// The only edge case is for example ro.hardware itself is a message, so a field called "value"
// would be defined in proto Ro::Hardware and it must be the first field.
if (mSubMessages.find(name) != mSubMessages.end()) {
startSession(proto, name);
return mSubMessages[name]->insertField(proto, "value", value);
} else {
return mTable->insertField(proto, name, value);
}
}
// Try to find the message field which is the prefix of name, so the value would be inserted
// recursively into the submessage.
std::string mutableName = name;
for (auto iter = mSubMessages.begin(); iter != mSubMessages.end(); iter++) {
std::string fieldName = iter->first;
std::string prefix = fieldName + "_"; // underscore is the delimiter in the name
if (stripPrefix(&mutableName, prefix.c_str())) {
if (mPreviousField != fieldName) {
endSession(proto);
startSession(proto, fieldName);
}
return mSubMessages[fieldName]->insertField(proto, mutableName, value);
}
}
// Can't find the name in proto definition, handle it separately.
return false;
}
void
Message::startSession(ProtoOutputStream* proto, const std::string& name)
{
uint64_t fieldId = mTable->mFields[name];
uint64_t token = proto->start(fieldId);
mPreviousField = name;
mTokens.push(token);
}
void
Message::endSession(ProtoOutputStream* proto)
{
if (mPreviousField == "") return;
if (mSubMessages.find(mPreviousField) != mSubMessages.end()) {
mSubMessages[mPreviousField]->endSession(proto);
}
proto->end(mTokens.top());
mTokens.pop();
mPreviousField = "";
}

View File

@@ -0,0 +1,201 @@
/*
* 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.
*/
#ifndef INCIDENT_HELPER_UTIL_H
#define INCIDENT_HELPER_UTIL_H
#include <map>
#include <stack>
#include <string>
#include <vector>
#include <android/util/ProtoOutputStream.h>
using namespace android::util;
typedef std::vector<std::string> header_t;
typedef std::vector<std::string> record_t;
typedef std::string (*trans_func) (const std::string&);
const std::string DEFAULT_WHITESPACE = " \t";
const std::string DEFAULT_NEWLINE = "\r\n";
const std::string TAB_DELIMITER = "\t";
const std::string COMMA_DELIMITER = ",";
const std::string PIPE_DELIMITER = "|";
const std::string PARENTHESES_DELIMITER = "()";
// returns true if c is a-zA-Z0-9 or underscore
bool isValidChar(char c);
// trim the string with the given charset
std::string trim(const std::string& s, const std::string& charset);
/**
* When a text has a table format like this
* line 1: HeadA HeadB HeadC
* line 2: v1 v2 v3
* line 3: v11 v12 v13
*
* We want to parse the line in structure given the delimiter.
* parseHeader is used to parse the firse line of the table and returns a list of strings in lower case
* parseRecord is used to parse other lines and returns a list of strings
* empty strings are skipped
*/
header_t parseHeader(const std::string& line, const std::string& delimiters = DEFAULT_WHITESPACE);
record_t parseRecord(const std::string& line, const std::string& delimiters = DEFAULT_WHITESPACE);
/**
* Gets the list of end indices of each word in the line and places it in the given vector,
* clearing out the vector beforehand. These indices can be used with parseRecordByColumns.
* Will return false if there was a problem getting the indices. headerNames
* must be NULL terminated.
*/
bool getColumnIndices(std::vector<int>& indices, const char* headerNames[], const std::string& line);
/**
* When a text-format table aligns by its vertical position, it is not possible to split them by purely delimiters.
* This function allows to parse record by its header's column position' indices, must in ascending order.
* At the same time, it still looks at the char at index, if it doesn't belong to delimiters, moves forward to find the delimiters.
*/
record_t parseRecordByColumns(const std::string& line, const std::vector<int>& indices, const std::string& delimiters = DEFAULT_WHITESPACE);
/** Prints record_t to stderr */
void printRecord(const record_t& record);
/**
* When the line starts/ends with the given key, the function returns true
* as well as the line argument is changed to the rest trimmed part of the original.
* e.g. "ZRAM: 6828K physical used for 31076K in swap (524284K total swap)" becomes
* "6828K physical used for 31076K in swap (524284K total swap)" when given key "ZRAM:",
* otherwise the line is not changed.
*
* In order to prevent two values have same prefix which cause entering to incorrect conditions,
* stripPrefix and stripSuffix can turn on a flag that requires the ending char in the line must not be a valid
* character or digits, this feature is off by default.
* i.e. ABC%some value, ABCD%other value
*/
bool stripPrefix(std::string* line, const char* key, bool endAtDelimiter = false);
bool stripSuffix(std::string* line, const char* key, bool endAtDelimiter = false);
/**
* behead the given line by the cut, return the head and reassign the line to be the rest.
*/
std::string behead(std::string* line, const char cut);
/**
* Converts string to the desired type
*/
int toInt(const std::string& s);
long long toLongLong(const std::string& s);
double toDouble(const std::string& s);
/**
* Reader class reads data from given fd in streaming fashion.
* The buffer size is controlled by capacity parameter.
*/
class Reader
{
public:
Reader(const int fd);
~Reader();
bool readLine(std::string* line);
bool ok(std::string* error);
private:
FILE* mFile;
std::string mStatus;
};
/**
* The Table class is constructed from two arrays generated by the given message with
* option (stream_proto.stream_msg).enable_fields_mapping = true.
* The names are each field's names in the message and must corresponding to the header/name of
* the text to be parsed, and the ids are the streaming proto encoded field ids.
*
* This class then allows users to insert the table values to proto based on its header.
*
* Advance feature: if some fields in the message are enums, user must explicitly add the
* mapping from enum name string to its enum values.
*/
class Message;
class Table
{
friend class Message;
public:
Table(const char* names[], const uint64_t ids[], const int count);
~Table();
// Add enum names to values for parsing purpose.
void addEnumTypeMap(const char* field, const char* enumNames[], const int enumValues[], const int enumSize);
// Manually add enum names to values mapping, useful when an Enum type is used by
// a number of fields, there must not be any enum name conflicts.
void addEnumNameToValue(const char* enumName, const int enumValue);
// Based on given name, find the right field id, parse the text value and insert to proto.
// Return false if the given name can't be found.
bool insertField(ProtoOutputStream* proto, const std::string& name, const std::string& value);
private:
std::map<std::string, uint64_t> mFields;
std::map<std::string, std::map<std::string, int>> mEnums;
std::map<std::string, int> mEnumValuesByName;
};
/**
* Reconstructs a typical proto message given its message Table, adds submessage fields explicitly.
* It allows user to insert nested proto values purely by the names. See insertField for detail.
*/
class Message
{
public:
Message(Table* table);
~Message();
// Reconstructs the typical proto message by adding its message fields.
void addSubMessage(uint64_t fieldId, Message* fieldMsg);
// Inserts value if the given name has the corresponding field in its message and return true.
// It will recursively search the name in submessages and find the correct field to insert.
// For example, when the name is dalvik_vm_heapsize, and the message's corresponding proto is:
// message Properties {
// message DalvikVm {
// int32 heapsize = 1;
// bool usejit = 2;
// }
// DalvikVm dalvik_vm = 1;
// string hack_in = 2;
// }
// The value will be inserted into field heapsize in dalvik_vm submessage.
//
// Also value belongs to same submessage MUST be inserted contiguously.
// For example, dalvik_vm_usejit must be inserted directly after dalvik_vm_heapsize, otherwise
// if hack_in attempts to be inserted before dalvik_vm_usejit, value of usejit isn't added as expected.
bool insertField(ProtoOutputStream* proto, const std::string& name, const std::string& value);
// Starts a new message field proto session.
void startSession(ProtoOutputStream* proto, const std::string& name);
// Ends the previous message field proto session.
void endSession(ProtoOutputStream* proto);
private:
Table* mTable;
std::string mPreviousField;
std::stack<uint64_t> mTokens;
std::map<std::string, Message*> mSubMessages;
};
#endif // INCIDENT_HELPER_UTIL_H

View File

@@ -0,0 +1,113 @@
/*
* 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.
*/
#define LOG_TAG "incident_helper"
#include "parsers/BatteryTypeParser.h"
#include "parsers/CpuFreqParser.h"
#include "parsers/CpuInfoParser.h"
#include "parsers/EventLogTagsParser.h"
#include "parsers/KernelWakesParser.h"
#include "parsers/PageTypeInfoParser.h"
#include "parsers/ProcrankParser.h"
#include "parsers/PsParser.h"
#include "parsers/SystemPropertiesParser.h"
#include <android-base/file.h>
#include <getopt.h>
#include <stdlib.h>
#include <unistd.h>
using namespace android::base;
using namespace std;
static void usage(FILE* out) {
fprintf(out, "incident_helper is not designed to run manually,");
fprintf(out, "it reads from stdin and writes to stdout, see README.md for details.\n");
fprintf(out, "usage: incident_helper -s SECTION\n");
fprintf(out, "REQUIRED:\n");
fprintf(out, " -s section id, must be positive\n");
}
//=============================================================================
static TextParserBase* selectParser(int section) {
switch (section) {
// IDs smaller than or equal to 0 are reserved for testing
case -1:
return new TimeoutParser();
case 0:
return new NoopParser();
case 1: // 1 is reserved for incident header so it won't be section id
return new ReverseParser();
/* ========================================================================= */
// IDs larger than 1 are section ids reserved in incident.proto
case 1000:
return new SystemPropertiesParser();
case 1100:
return new EventLogTagsParser();
case 2000:
return new ProcrankParser();
case 2001:
return new PageTypeInfoParser();
case 2002:
return new KernelWakesParser();
case 2003:
return new CpuInfoParser();
case 2004:
return new CpuFreqParser();
case 2005:
return new PsParser();
case 2006:
return new BatteryTypeParser();
default:
return NULL;
}
}
//=============================================================================
int main(int argc, char** argv) {
fprintf(stderr, "Start incident_helper...\n");
// Parse the args
int opt;
int sectionID = 0;
while ((opt = getopt(argc, argv, "hs:")) != -1) {
switch (opt) {
case 'h':
usage(stdout);
return 0;
case 's':
sectionID = atoi(optarg);
break;
}
}
fprintf(stderr, "Pasring section %d...\n", sectionID);
TextParserBase* parser = selectParser(sectionID);
if (parser != NULL) {
fprintf(stderr, "Running parser: %s\n", parser->name.string());
status_t err = parser->Parse(STDIN_FILENO, STDOUT_FILENO);
if (err != NO_ERROR) {
fprintf(stderr, "Parse error in section %d: %s\n", sectionID, strerror(-err));
return -1;
}
delete parser;
}
fprintf(stderr, "Finish section %d, exiting...\n", sectionID);
return 0;
}

View File

@@ -0,0 +1,60 @@
/*
* 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.
*/
#define LOG_TAG "incident_helper"
#include <android/util/ProtoOutputStream.h>
#include "frameworks/base/core/proto/android/os/batterytype.proto.h"
#include "ih_util.h"
#include "BatteryTypeParser.h"
using namespace android::os;
status_t
BatteryTypeParser::Parse(const int in, const int out) const
{
Reader reader(in);
string line;
bool readLine = false;
ProtoOutputStream proto;
// parse line by line
while (reader.readLine(&line)) {
if (line.empty()) continue;
if (readLine) {
fprintf(stderr, "Multiple lines in file. Unsure what to do.\n");
break;
}
proto.write(BatteryTypeProto::TYPE, line);
readLine = true;
}
if (!reader.ok(&line)) {
fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
return -1;
}
if (!proto.flush(out)) {
fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
return -1;
}
fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
return NO_ERROR;
}

View File

@@ -0,0 +1,36 @@
/*
* 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.
*/
#ifndef BATTERY_TYPE_PARSER_H
#define BATTERY_TYPE_PARSER_H
#include "TextParserBase.h"
using namespace android;
/**
* Battery type parser, parses text in file
* /sys/class/power_supply/bms/battery_type.
*/
class BatteryTypeParser : public TextParserBase {
public:
BatteryTypeParser() : TextParserBase(String8("BatteryTypeParser")) {};
~BatteryTypeParser() {};
virtual status_t Parse(const int in, const int out) const;
};
#endif // BATTERY_TYPE_PARSER_H

View File

@@ -0,0 +1,90 @@
/*
* 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.
*/
#define LOG_TAG "incident_helper"
#include <android/util/ProtoOutputStream.h>
#include <unistd.h>
#include "frameworks/base/core/proto/android/os/cpufreq.proto.h"
#include "ih_util.h"
#include "CpuFreqParser.h"
using namespace android::os;
status_t
CpuFreqParser::Parse(const int in, const int out) const
{
Reader reader(in);
string line;
// parse header
reader.readLine(&line);
header_t header = parseHeader(line, TAB_DELIMITER);
if (header.size() < 1) {
fprintf(stderr, "Bad header: %s\n", line.c_str());
return BAD_VALUE;
}
const int numCpus = (int)header.size() - 1;
vector<pair<int, long long>> cpucores[numCpus];
// parse freq and time
while (reader.readLine(&line)) {
if (line.empty()) continue;
record_t record = parseRecord(line, TAB_DELIMITER);
if (record.size() != header.size()) {
fprintf(stderr, "Bad line: %s\n", line.c_str());
continue;
}
int freq = toInt(record[0]);
for (int i=0; i<numCpus; i++) {
if (strcmp(record[i+1].c_str(), "N/A") == 0) {
continue;
}
cpucores[i].push_back(make_pair(freq, toLongLong(record[i+1])));
}
}
ProtoOutputStream proto;
long jiffyHz = sysconf(_SC_CLK_TCK);
proto.write(CpuFreqProto::JIFFY_HZ, (int)jiffyHz);
for (int i=0; i<numCpus; i++) {
uint64_t token = proto.start(CpuFreqProto::CPU_FREQS);
proto.write(CpuFreqProto::Stats::CPU_NAME, header[i+1]);
for (vector<pair<int, long long>>::iterator it = cpucores[i].begin(); it != cpucores[i].end(); it++) {
uint64_t stateToken = proto.start(CpuFreqProto::Stats::TIMES);
proto.write(CpuFreqProto::Stats::TimeInState::STATE_KHZ, it->first);
proto.write(CpuFreqProto::Stats::TimeInState::TIME_JIFFY, it->second);
proto.end(stateToken);
}
proto.end(token);
}
if (!reader.ok(&line)) {
fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
return -1;
}
if (!proto.flush(out)) {
fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
return -1;
}
fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
return NO_ERROR;
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef CPU_FREQ_PARSER_H
#define CPU_FREQ_PARSER_H
#include "TextParserBase.h"
using namespace android;
/**
* Cpu frequency parser, parses text in /sys/devices/system/cpu/cpufreq/all_time_in_state
*/
class CpuFreqParser : public TextParserBase {
public:
CpuFreqParser() : TextParserBase(String8("CpuFreqParser")) {};
~CpuFreqParser() {};
virtual status_t Parse(const int in, const int out) const;
};
#endif // CPU_FREQ_PARSER_H

View File

@@ -0,0 +1,162 @@
/*
* 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.
*/
#define LOG_TAG "incident_helper"
#include <android/util/ProtoOutputStream.h>
#include "frameworks/base/core/proto/android/os/cpuinfo.proto.h"
#include "ih_util.h"
#include "CpuInfoParser.h"
using namespace android::os;
static void writeSuffixLine(ProtoOutputStream* proto, uint64_t fieldId,
const string& line, const string& delimiter,
const int count, const char* names[], const uint64_t ids[])
{
record_t record = parseRecord(line, delimiter);
uint64_t token = proto->start(fieldId);
for (int i=0; i<(int)record.size(); i++) {
for (int j=0; j<count; j++) {
if (stripSuffix(&record[i], names[j], true)) {
proto->write(ids[j], toInt(record[i]));
break;
}
}
}
proto->end(token);
}
status_t
CpuInfoParser::Parse(const int in, const int out) const
{
Reader reader(in);
string line;
header_t header;
vector<int> columnIndices; // task table can't be split by purely delimiter, needs column positions.
record_t record;
int nline = 0;
int diff = 0;
bool nextToSwap = false;
bool nextToUsage = false;
ProtoOutputStream proto;
Table table(CpuInfoProto::Task::_FIELD_NAMES, CpuInfoProto::Task::_FIELD_IDS, CpuInfoProto::Task::_FIELD_COUNT);
table.addEnumTypeMap("s", CpuInfoProto::Task::_ENUM_STATUS_NAMES,
CpuInfoProto::Task::_ENUM_STATUS_VALUES, CpuInfoProto::Task::_ENUM_STATUS_COUNT);
table.addEnumTypeMap("pcy", CpuInfoProto::Task::_ENUM_POLICY_NAMES,
CpuInfoProto::Task::_ENUM_POLICY_VALUES, CpuInfoProto::Task::_ENUM_POLICY_COUNT);
// parse line by line
while (reader.readLine(&line)) {
if (line.empty()) continue;
nline++;
if (stripPrefix(&line, "Tasks:")) {
writeSuffixLine(&proto, CpuInfoProto::TASK_STATS, line, COMMA_DELIMITER,
CpuInfoProto::TaskStats::_FIELD_COUNT,
CpuInfoProto::TaskStats::_FIELD_NAMES,
CpuInfoProto::TaskStats::_FIELD_IDS);
continue;
}
if (stripPrefix(&line, "Mem:")) {
writeSuffixLine(&proto, CpuInfoProto::MEM, line, COMMA_DELIMITER,
CpuInfoProto::MemStats::_FIELD_COUNT,
CpuInfoProto::MemStats::_FIELD_NAMES,
CpuInfoProto::MemStats::_FIELD_IDS);
continue;
}
if (stripPrefix(&line, "Swap:")) {
writeSuffixLine(&proto, CpuInfoProto::SWAP, line, COMMA_DELIMITER,
CpuInfoProto::MemStats::_FIELD_COUNT,
CpuInfoProto::MemStats::_FIELD_NAMES,
CpuInfoProto::MemStats::_FIELD_IDS);
nextToSwap = true;
continue;
}
if (nextToSwap) {
writeSuffixLine(&proto, CpuInfoProto::CPU_USAGE, line, DEFAULT_WHITESPACE,
CpuInfoProto::CpuUsage::_FIELD_COUNT,
CpuInfoProto::CpuUsage::_FIELD_NAMES,
CpuInfoProto::CpuUsage::_FIELD_IDS);
nextToUsage = true;
nextToSwap = false;
continue;
}
// Header of tasks must be next to usage line
if (nextToUsage) {
// How to parse Header of Tasks:
// PID TID USER PR NI[%CPU]S VIRT RES PCY CMD NAME
// After parsing, header = { PID, TID, USER, PR, NI, CPU, S, VIRT, RES, PCY, CMD, NAME }
// And columnIndices will contain end index of each word.
header = parseHeader(line, "[ %]");
nextToUsage = false;
// NAME is not in the list since we need to modify the end of the CMD index.
const char* headerNames[] = { "PID", "TID", "USER", "PR", "NI", "CPU", "S", "VIRT", "RES", "PCY", "CMD", NULL };
if (!getColumnIndices(columnIndices, headerNames, line)) {
return -1;
}
// Need to remove the end index of CMD and use the start index of NAME because CMD values contain spaces.
// for example: ... CMD NAME
// ... Jit thread pool com.google.android.gms.feedback
// If use end index of CMD, parsed result = { "Jit", "thread pool com.google.android.gms.feedback" }
// If use start index of NAME, parsed result = { "Jit thread pool", "com.google.android.gms.feedback" }
int endCMD = columnIndices.back();
columnIndices.pop_back();
columnIndices.push_back(line.find("NAME", endCMD) - 1);
// Add NAME index to complete the column list.
columnIndices.push_back(columnIndices.back() + 4);
continue;
}
record = parseRecordByColumns(line, columnIndices);
diff = record.size() - header.size();
if (diff < 0) {
fprintf(stderr, "[%s]Line %d has %d missing fields\n%s\n", this->name.string(), nline, -diff, line.c_str());
printRecord(record);
continue;
} else if (diff > 0) {
fprintf(stderr, "[%s]Line %d has %d extra fields\n%s\n", this->name.string(), nline, diff, line.c_str());
printRecord(record);
continue;
}
uint64_t token = proto.start(CpuInfoProto::TASKS);
for (int i=0; i<(int)record.size(); i++) {
if (!table.insertField(&proto, header[i], record[i])) {
fprintf(stderr, "[%s]Line %d fails to insert field %s with value %s\n",
this->name.string(), nline, header[i].c_str(), record[i].c_str());
}
}
proto.end(token);
}
if (!reader.ok(&line)) {
fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
return -1;
}
if (!proto.flush(out)) {
fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
return -1;
}
fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
return NO_ERROR;
}

View File

@@ -0,0 +1,36 @@
/*
* 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.
*/
#ifndef CPU_INFO_PARSER_H
#define CPU_INFO_PARSER_H
#include "TextParserBase.h"
using namespace android;
/**
* Cpu info parser, parses text produced by command
* 'top -b -n 1 -H -s 6 -o pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name'
*/
class CpuInfoParser : public TextParserBase {
public:
CpuInfoParser() : TextParserBase(String8("CpuInfoParser")) {};
~CpuInfoParser() {};
virtual status_t Parse(const int in, const int out) const;
};
#endif // CPU_INFO_PARSER_H

View File

@@ -0,0 +1,84 @@
/*
* 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.
*/
#define LOG_TAG "incident_helper"
#include <android/util/ProtoOutputStream.h>
#include "frameworks/base/core/proto/android/util/event_log_tags.proto.h"
#include "ih_util.h"
#include "EventLogTagsParser.h"
status_t
EventLogTagsParser::Parse(const int in, const int out) const
{
Reader reader(in);
string line;
ProtoOutputStream proto;
// parse line by line
while (reader.readLine(&line)) {
if (line.empty()) continue;
string debug = line;
string tagNumber = behead(&line, ' ');
string tagName = behead(&line, ' ');
if (tagNumber == "" || tagName == "") {
fprintf(stderr, "Bad line, expect at least two parts: %s[%s, %s]\n",
debug.c_str(), tagNumber.c_str(), tagName.c_str());
continue;
}
uint64_t token = proto.start(EventLogTagMapProto::EVENT_LOG_TAGS);
proto.write(EventLogTag::TAG_NUMBER, toInt(tagNumber));
proto.write(EventLogTag::TAG_NAME, tagName);
record_t valueDescriptors = parseRecord(line, PARENTHESES_DELIMITER);
for (size_t i = 0; i < valueDescriptors.size(); i++) {
record_t valueDescriptor = parseRecord(valueDescriptors[i], PIPE_DELIMITER);
if (valueDescriptor.size() != 2 && valueDescriptor.size() != 3) {
// If the parts doesn't contains pipe, then skips it.
continue;
}
uint64_t descriptorToken = proto.start(EventLogTag::VALUE_DESCRIPTORS);
proto.write(EventLogTag::ValueDescriptor::NAME, valueDescriptor[0]);
proto.write(EventLogTag::ValueDescriptor::TYPE, toInt(valueDescriptor[1]));
if (valueDescriptor.size() == 3) {
char c = valueDescriptor[2][0];
int unit = 0;
if (c < '0' || c > '9') {
unit = (int) c;
} else {
unit = toInt(valueDescriptor[2]);
}
proto.write(EventLogTag::ValueDescriptor::UNIT, unit);
}
proto.end(descriptorToken);
}
proto.end(token);
}
if (!reader.ok(&line)) {
fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
return -1;
}
if (!proto.flush(out)) {
fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
return -1;
}
fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
return NO_ERROR;
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef EVENT_LOG_TAGS_PARSER_H
#define EVENT_LOG_TAGS_PARSER_H
#include "TextParserBase.h"
using namespace android;
/**
* event.logtags parser, parse file in /system/etc/event-log-tags
*/
class EventLogTagsParser : public TextParserBase {
public:
EventLogTagsParser() : TextParserBase(String8("EventLogTagsParser")) {};
~EventLogTagsParser() {};
virtual status_t Parse(const int in, const int out) const;
};
#endif // EVENT_LOG_TAGS_PARSER_H

View File

@@ -0,0 +1,83 @@
/*
* 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.
*/
#define LOG_TAG "incident_helper"
#include <android/util/ProtoOutputStream.h>
#include "frameworks/base/core/proto/android/os/kernelwake.proto.h"
#include "ih_util.h"
#include "KernelWakesParser.h"
using namespace android::os;
status_t
KernelWakesParser::Parse(const int in, const int out) const
{
Reader reader(in);
string line;
header_t header; // the header of /d/wakeup_sources
record_t record; // retain each record
int nline = 0;
ProtoOutputStream proto;
Table table(KernelWakeSourcesProto::WakeupSource::_FIELD_NAMES,
KernelWakeSourcesProto::WakeupSource::_FIELD_IDS,
KernelWakeSourcesProto::WakeupSource::_FIELD_COUNT);
// parse line by line
while (reader.readLine(&line)) {
if (line.empty()) continue;
// parse head line
if (nline++ == 0) {
header = parseHeader(line, TAB_DELIMITER);
continue;
}
// parse for each record, the line delimiter is \t only!
record = parseRecord(line, TAB_DELIMITER);
if (record.size() < header.size()) {
// TODO: log this to incident report!
fprintf(stderr, "[%s]Line %d has missing fields\n%s\n", this->name.string(), nline, line.c_str());
continue;
} else if (record.size() > header.size()) {
// TODO: log this to incident report!
fprintf(stderr, "[%s]Line %d has extra fields\n%s\n", this->name.string(), nline, line.c_str());
continue;
}
uint64_t token = proto.start(KernelWakeSourcesProto::WAKEUP_SOURCES);
for (int i=0; i<(int)record.size(); i++) {
if (!table.insertField(&proto, header[i], record[i])) {
fprintf(stderr, "[%s]Line %d has bad value %s of %s\n",
this->name.string(), nline, header[i].c_str(), record[i].c_str());
}
}
proto.end(token);
}
if (!reader.ok(&line)) {
fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
return -1;
}
if (!proto.flush(out)) {
fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
return -1;
}
fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
return NO_ERROR;
}

View File

@@ -0,0 +1,33 @@
/*
* 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.
*/
#ifndef KERNEL_WAKES_PARSER_H
#define KERNEL_WAKES_PARSER_H
#include "TextParserBase.h"
/**
* Kernel wakeup sources parser, parses text to protobuf in /d/wakeup_sources
*/
class KernelWakesParser : public TextParserBase {
public:
KernelWakesParser() : TextParserBase(String8("KernelWakeSources")) {};
~KernelWakesParser() {};
virtual status_t Parse(const int in, const int out) const;
};
#endif // KERNEL_WAKES_PARSER_H

View File

@@ -0,0 +1,128 @@
/*
* 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.
*/
#define LOG_TAG "incident_helper"
#include <android/util/ProtoOutputStream.h>
#include "frameworks/base/core/proto/android/os/pagetypeinfo.proto.h"
#include "ih_util.h"
#include "PageTypeInfoParser.h"
using namespace android::os;
status_t
PageTypeInfoParser::Parse(const int in, const int out) const
{
Reader reader(in);
string line;
bool migrateTypeSession = false;
int pageBlockOrder;
header_t blockHeader;
ProtoOutputStream proto;
Table table(PageTypeInfoProto::Block::_FIELD_NAMES,
PageTypeInfoProto::Block::_FIELD_IDS,
PageTypeInfoProto::Block::_FIELD_COUNT);
while (reader.readLine(&line)) {
if (line.empty()) {
migrateTypeSession = false;
blockHeader.clear();
continue;
}
if (stripPrefix(&line, "Page block order:")) {
pageBlockOrder = toInt(line);
proto.write(PageTypeInfoProto::PAGE_BLOCK_ORDER, pageBlockOrder);
continue;
}
if (stripPrefix(&line, "Pages per block:")) {
proto.write(PageTypeInfoProto::PAGES_PER_BLOCK, toInt(line));
continue;
}
if (stripPrefix(&line, "Free pages count per migrate type at order")) {
migrateTypeSession = true;
continue;
}
if (stripPrefix(&line, "Number of blocks type")) {
blockHeader = parseHeader(line);
continue;
}
record_t record = parseRecord(line, COMMA_DELIMITER);
if (migrateTypeSession && record.size() == 3) {
uint64_t token = proto.start(PageTypeInfoProto::MIGRATE_TYPES);
// expect part 0 starts with "Node"
if (stripPrefix(&record[0], "Node")) {
proto.write(PageTypeInfoProto::MigrateType::NODE, toInt(record[0]));
} else return BAD_VALUE;
// expect part 1 starts with "zone"
if (stripPrefix(&record[1], "zone")) {
proto.write(PageTypeInfoProto::MigrateType::ZONE, record[1]);
} else return BAD_VALUE;
// expect part 2 starts with "type"
if (stripPrefix(&record[2], "type")) {
// expect the rest of part 2 has number of (pageBlockOrder + 2) parts
// An example looks like:
// header line: type 0 1 2 3 4 5 6 7 8 9 10
// record line: Unmovable 426 279 226 1 1 1 0 0 2 2 0
// The pageBlockOrder = 10 and it's zero-indexed. so total parts
// are 10 + 1(zero-indexed) + 1(the type part) = 12.
record_t pageCounts = parseRecord(record[2]);
int pageCountsSize = pageBlockOrder + 2;
if ((int)pageCounts.size() != pageCountsSize) return BAD_VALUE;
proto.write(PageTypeInfoProto::MigrateType::TYPE, pageCounts[0]);
for (auto i=1; i<pageCountsSize; i++) {
proto.write(PageTypeInfoProto::MigrateType::FREE_PAGES_COUNT, toInt(pageCounts[i]));
}
} else return BAD_VALUE;
proto.end(token);
} else if (!blockHeader.empty() && record.size() == 2) {
uint64_t token = proto.start(PageTypeInfoProto::BLOCKS);
if (stripPrefix(&record[0], "Node")) {
proto.write(PageTypeInfoProto::Block::NODE, toInt(record[0]));
} else return BAD_VALUE;
if (stripPrefix(&record[1], "zone")) {
record_t blockCounts = parseRecord(record[1]);
proto.write(PageTypeInfoProto::Block::ZONE, blockCounts[0]);
for (size_t i=0; i<blockHeader.size(); i++) {
if (!table.insertField(&proto, blockHeader[i], blockCounts[i+1])) {
fprintf(stderr, "Header %s has bad data %s\n", blockHeader[i].c_str(),
blockCounts[i+1].c_str());
}
}
} else return BAD_VALUE;
proto.end(token);
}
}
if (!reader.ok(&line)) {
fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
return -1;
}
if (!proto.flush(out)) {
fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
return -1;
}
fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
return NO_ERROR;
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef PAGE_TYPE_INFO_PARSER_H
#define PAGE_TYPE_INFO_PARSER_H
#include "TextParserBase.h"
using namespace android;
/**
* PageTypeInfo parser, parses text to protobuf in /proc/pageinfotype
*/
class PageTypeInfoParser : public TextParserBase {
public:
PageTypeInfoParser() : TextParserBase(String8("PageTypeInfo")) {};
~PageTypeInfoParser() {};
virtual status_t Parse(const int in, const int out) const;
};
#endif // PAGE_TYPE_INFO_PARSER_H

View File

@@ -0,0 +1,112 @@
/*
* 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.
*/
#define LOG_TAG "incident_helper"
#include <android/util/ProtoOutputStream.h>
#include "frameworks/base/core/proto/android/os/procrank.proto.h"
#include "ih_util.h"
#include "ProcrankParser.h"
using namespace android::os;
status_t
ProcrankParser::Parse(const int in, const int out) const
{
Reader reader(in);
string line;
header_t header; // the header of /d/wakeup_sources
record_t record; // retain each record
int nline = 0;
ProtoOutputStream proto;
Table table(ProcrankProto::Process::_FIELD_NAMES, ProcrankProto::Process::_FIELD_IDS, ProcrankProto::Process::_FIELD_COUNT);
string zram, ram, total;
// parse line by line
while (reader.readLine(&line)) {
if (line.empty()) continue;
// parse head line
if (nline++ == 0) {
header = parseHeader(line);
continue;
}
if (stripPrefix(&line, "ZRAM:")) {
zram = line;
continue;
}
if (stripPrefix(&line, "RAM:")) {
ram = line;
continue;
}
record = parseRecord(line);
if (record.size() != header.size()) {
if (record[record.size() - 1] == "TOTAL") { // TOTAL record
total = line;
} else {
fprintf(stderr, "[%s]Line %d has missing fields\n%s\n", this->name.string(), nline,
line.c_str());
}
continue;
}
uint64_t token = proto.start(ProcrankProto::PROCESSES);
for (int i=0; i<(int)record.size(); i++) {
if (!table.insertField(&proto, header[i], record[i])) {
fprintf(stderr, "[%s]Line %d has bad value %s of %s\n",
this->name.string(), nline, header[i].c_str(), record[i].c_str());
}
}
proto.end(token);
}
// add summary
uint64_t token = proto.start(ProcrankProto::SUMMARY);
if (!total.empty()) {
record = parseRecord(total);
uint64_t token = proto.start(ProcrankProto::Summary::TOTAL);
for (int i=(int)record.size(); i>0; i--) {
table.insertField(&proto, header[header.size() - i].c_str(), record[record.size() - i].c_str());
}
proto.end(token);
}
if (!zram.empty()) {
uint64_t token = proto.start(ProcrankProto::Summary::ZRAM);
proto.write(ProcrankProto::Summary::Zram::RAW_TEXT, zram);
proto.end(token);
}
if (!ram.empty()) {
uint64_t token = proto.start(ProcrankProto::Summary::RAM);
proto.write(ProcrankProto::Summary::Ram::RAW_TEXT, ram);
proto.end(token);
}
proto.end(token);
if (!reader.ok(&line)) {
fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
return -1;
}
if (!proto.flush(out)) {
fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
return -1;
}
fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
return NO_ERROR;
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef PROCRANK_PARSER_H
#define PROCRANK_PARSER_H
#include "TextParserBase.h"
using namespace android;
/**
* Procrank parser, parses text produced by command procrank
*/
class ProcrankParser : public TextParserBase {
public:
ProcrankParser() : TextParserBase(String8("ProcrankParser")) {};
~ProcrankParser() {};
virtual status_t Parse(const int in, const int out) const;
};
#endif // PROCRANK_PARSER_H

View File

@@ -0,0 +1,95 @@
/*
* 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.
*/
#define LOG_TAG "incident_helper"
#include <android/util/ProtoOutputStream.h>
#include "frameworks/base/core/proto/android/os/ps.proto.h"
#include "ih_util.h"
#include "PsParser.h"
using namespace android::os;
status_t PsParser::Parse(const int in, const int out) const {
Reader reader(in);
string line;
header_t header; // the header of /d/wakeup_sources
vector<int> columnIndices; // task table can't be split by purely delimiter, needs column positions.
record_t record; // retain each record
int nline = 0;
int diff = 0;
ProtoOutputStream proto;
Table table(PsProto::Process::_FIELD_NAMES, PsProto::Process::_FIELD_IDS, PsProto::Process::_FIELD_COUNT);
const char* pcyNames[] = { "fg", "bg", "ta" };
const int pcyValues[] = {PsProto::Process::POLICY_FG, PsProto::Process::POLICY_BG, PsProto::Process::POLICY_TA};
table.addEnumTypeMap("pcy", pcyNames, pcyValues, 3);
const char* sNames[] = { "D", "R", "S", "T", "t", "X", "Z" };
const int sValues[] = {PsProto::Process::STATE_D, PsProto::Process::STATE_R, PsProto::Process::STATE_S, PsProto::Process::STATE_T, PsProto::Process::STATE_TRACING, PsProto::Process::STATE_X, PsProto::Process::STATE_Z};
table.addEnumTypeMap("s", sNames, sValues, 7);
// Parse line by line
while (reader.readLine(&line)) {
if (line.empty()) continue;
if (nline++ == 0) {
header = parseHeader(line, DEFAULT_WHITESPACE);
const char* headerNames[] = { "LABEL", "USER", "PID", "TID", "PPID", "VSZ", "RSS", "WCHAN", "ADDR", "S", "PRI", "NI", "RTPRIO", "SCH", "PCY", "TIME", "CMD", NULL };
if (!getColumnIndices(columnIndices, headerNames, line)) {
return -1;
}
continue;
}
record = parseRecordByColumns(line, columnIndices);
diff = record.size() - header.size();
if (diff < 0) {
// TODO: log this to incident report!
fprintf(stderr, "[%s]Line %d has %d missing fields\n%s\n", this->name.string(), nline, -diff, line.c_str());
printRecord(record);
continue;
} else if (diff > 0) {
// TODO: log this to incident report!
fprintf(stderr, "[%s]Line %d has %d extra fields\n%s\n", this->name.string(), nline, diff, line.c_str());
printRecord(record);
continue;
}
uint64_t token = proto.start(PsProto::PROCESSES);
for (int i=0; i<(int)record.size(); i++) {
if (!table.insertField(&proto, header[i], record[i])) {
fprintf(stderr, "[%s]Line %d has bad value %s of %s\n",
this->name.string(), nline, header[i].c_str(), record[i].c_str());
}
}
proto.end(token);
}
if (!reader.ok(&line)) {
fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
return -1;
}
if (!proto.flush(out)) {
fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
return -1;
}
fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
return NO_ERROR;
}

View File

@@ -0,0 +1,33 @@
/*
* 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.
*/
#ifndef PS_PARSER_H
#define PS_PARSER_H
#include "TextParserBase.h"
/**
* PS parser, parses output of 'ps' command to protobuf.
*/
class PsParser : public TextParserBase {
public:
PsParser() : TextParserBase(String8("Ps")) {};
~PsParser() {};
virtual status_t Parse(const int in, const int out) const;
};
#endif // PS_PARSER_H

View File

@@ -0,0 +1,227 @@
/*
* 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.
*/
#define LOG_TAG "incident_helper"
#include <android/util/ProtoOutputStream.h>
#include "frameworks/base/core/proto/android/os/system_properties.proto.h"
#include "ih_util.h"
#include "SystemPropertiesParser.h"
using namespace android::os;
const string LINE_DELIMITER = "]: [";
// system properties' names sometimes are not valid proto field names, make the names valid.
static string convertToFieldName(const string& name) {
int len = (int)name.length();
char cstr[len + 1];
strcpy(cstr, name.c_str());
for (int i = 0; i < len; i++) {
if (!isValidChar(cstr[i])) {
cstr[i] = '_';
}
}
return string(cstr);
}
status_t
SystemPropertiesParser::Parse(const int in, const int out) const
{
Reader reader(in);
string line;
string name; // the name of the property
string value; // the string value of the property
ProtoOutputStream proto;
vector<pair<string, string>> extras;
Table sysPropTable(SystemPropertiesProto::_FIELD_NAMES,
SystemPropertiesProto::_FIELD_IDS,
SystemPropertiesProto::_FIELD_COUNT);
Message sysProp(&sysPropTable);
Table aacDrcTable(SystemPropertiesProto::AacDrc::_FIELD_NAMES,
SystemPropertiesProto::AacDrc::_FIELD_IDS,
SystemPropertiesProto::AacDrc::_FIELD_COUNT);
Message aacDrc(&aacDrcTable);
sysProp.addSubMessage(SystemPropertiesProto::AAC_DRC, &aacDrc);
Table aaudioTable(SystemPropertiesProto::Aaudio::_FIELD_NAMES,
SystemPropertiesProto::Aaudio::_FIELD_IDS,
SystemPropertiesProto::Aaudio::_FIELD_COUNT);
Message aaudio(&aaudioTable);
sysProp.addSubMessage(SystemPropertiesProto::AAUDIO, &aaudio);
Table cameraTable(SystemPropertiesProto::Camera::_FIELD_NAMES,
SystemPropertiesProto::Camera::_FIELD_IDS,
SystemPropertiesProto::Camera::_FIELD_COUNT);
Message camera(&cameraTable);
sysProp.addSubMessage(SystemPropertiesProto::CAMERA, &camera);
Table dalvikVmTable(SystemPropertiesProto::DalvikVm::_FIELD_NAMES,
SystemPropertiesProto::DalvikVm::_FIELD_IDS,
SystemPropertiesProto::DalvikVm::_FIELD_COUNT);
Message dalvikVm(&dalvikVmTable);
sysProp.addSubMessage(SystemPropertiesProto::DALVIK_VM, &dalvikVm);
Table initSvcTable(SystemPropertiesProto::InitSvc::_FIELD_NAMES,
SystemPropertiesProto::InitSvc::_FIELD_IDS,
SystemPropertiesProto::InitSvc::_FIELD_COUNT);
initSvcTable.addEnumNameToValue("running", SystemPropertiesProto::InitSvc::STATUS_RUNNING);
initSvcTable.addEnumNameToValue("stopped", SystemPropertiesProto::InitSvc::STATUS_STOPPED);
Message initSvc(&initSvcTable);
sysProp.addSubMessage(SystemPropertiesProto::INIT_SVC, &initSvc);
Table logTable(SystemPropertiesProto::Log::_FIELD_NAMES,
SystemPropertiesProto::Log::_FIELD_IDS,
SystemPropertiesProto::Log::_FIELD_COUNT);
Message logMsg(&logTable);
sysProp.addSubMessage(SystemPropertiesProto::LOG, &logMsg);
Table persistTable(SystemPropertiesProto::Persist::_FIELD_NAMES,
SystemPropertiesProto::Persist::_FIELD_IDS,
SystemPropertiesProto::Persist::_FIELD_COUNT);
Message persist(&persistTable);
sysProp.addSubMessage(SystemPropertiesProto::PERSIST, &persist);
Table pmDexoptTable(SystemPropertiesProto::PmDexopt::_FIELD_NAMES,
SystemPropertiesProto::PmDexopt::_FIELD_IDS,
SystemPropertiesProto::PmDexopt::_FIELD_COUNT);
Message pmDexopt(&pmDexoptTable);
sysProp.addSubMessage(SystemPropertiesProto::PM_DEXOPT, &pmDexopt);
Table roTable(SystemPropertiesProto::Ro::_FIELD_NAMES,
SystemPropertiesProto::Ro::_FIELD_IDS,
SystemPropertiesProto::Ro::_FIELD_COUNT);
Message ro(&roTable);
Table bootTable(SystemPropertiesProto::Ro::Boot::_FIELD_NAMES,
SystemPropertiesProto::Ro::Boot::_FIELD_IDS,
SystemPropertiesProto::Ro::Boot::_FIELD_COUNT);
Message boot(&bootTable);
ro.addSubMessage(SystemPropertiesProto::Ro::BOOT, &boot);
Table bootimageTable(SystemPropertiesProto::Ro::BootImage::_FIELD_NAMES,
SystemPropertiesProto::Ro::BootImage::_FIELD_IDS,
SystemPropertiesProto::Ro::BootImage::_FIELD_COUNT);
Message bootimage(&bootimageTable);
ro.addSubMessage(SystemPropertiesProto::Ro::BOOTIMAGE, &bootimage);
Table buildTable(SystemPropertiesProto::Ro::Build::_FIELD_NAMES,
SystemPropertiesProto::Ro::Build::_FIELD_IDS,
SystemPropertiesProto::Ro::Build::_FIELD_COUNT);
Message build(&buildTable);
Table versionTable(SystemPropertiesProto::Ro::Build::Version::_FIELD_NAMES,
SystemPropertiesProto::Ro::Build::Version::_FIELD_IDS,
SystemPropertiesProto::Ro::Build::Version::_FIELD_COUNT);
Message version(&versionTable);
build.addSubMessage(SystemPropertiesProto::Ro::Build::VERSION, &version);
ro.addSubMessage(SystemPropertiesProto::Ro::BUILD, &build);
Table configTable(SystemPropertiesProto::Ro::Config::_FIELD_NAMES,
SystemPropertiesProto::Ro::Config::_FIELD_IDS,
SystemPropertiesProto::Ro::Config::_FIELD_COUNT);
Message config(&configTable);
ro.addSubMessage(SystemPropertiesProto::Ro::CONFIG, &config);
Table hardwareTable(SystemPropertiesProto::Ro::Hardware::_FIELD_NAMES,
SystemPropertiesProto::Ro::Hardware::_FIELD_IDS,
SystemPropertiesProto::Ro::Hardware::_FIELD_COUNT);
Message hardware(&hardwareTable);
ro.addSubMessage(SystemPropertiesProto::Ro::HARDWARE, &hardware);
Table productTable(SystemPropertiesProto::Ro::Product::_FIELD_NAMES,
SystemPropertiesProto::Ro::Product::_FIELD_IDS,
SystemPropertiesProto::Ro::Product::_FIELD_COUNT);
Message product(&productTable);
Table pVendorTable(SystemPropertiesProto::Ro::Product::Vendor::_FIELD_NAMES,
SystemPropertiesProto::Ro::Product::Vendor::_FIELD_IDS,
SystemPropertiesProto::Ro::Product::Vendor::_FIELD_COUNT);
Message pVendor(&pVendorTable);
product.addSubMessage(SystemPropertiesProto::Ro::Product::VENDOR, &pVendor);
ro.addSubMessage(SystemPropertiesProto::Ro::PRODUCT, &product);
Table telephonyTable(SystemPropertiesProto::Ro::Telephony::_FIELD_NAMES,
SystemPropertiesProto::Ro::Telephony::_FIELD_IDS,
SystemPropertiesProto::Ro::Telephony::_FIELD_COUNT);
Message telephony(&telephonyTable);
ro.addSubMessage(SystemPropertiesProto::Ro::TELEPHONY, &telephony);
Table vendorTable(SystemPropertiesProto::Ro::Vendor::_FIELD_NAMES,
SystemPropertiesProto::Ro::Vendor::_FIELD_IDS,
SystemPropertiesProto::Ro::Vendor::_FIELD_COUNT);
Message vendor(&vendorTable);
ro.addSubMessage(SystemPropertiesProto::Ro::VENDOR, &vendor);
sysProp.addSubMessage(SystemPropertiesProto::RO, &ro);
Table sysTable(SystemPropertiesProto::Sys::_FIELD_NAMES,
SystemPropertiesProto::Sys::_FIELD_IDS,
SystemPropertiesProto::Sys::_FIELD_COUNT);
Message sys(&sysTable);
Table usbTable(SystemPropertiesProto::Sys::Usb::_FIELD_NAMES,
SystemPropertiesProto::Sys::Usb::_FIELD_IDS,
SystemPropertiesProto::Sys::Usb::_FIELD_COUNT);
Message usb(&usbTable);
sys.addSubMessage(SystemPropertiesProto::Sys::USB, &usb);
sysProp.addSubMessage(SystemPropertiesProto::SYS, &sys);
// parse line by line
while (reader.readLine(&line)) {
if (line.empty()) continue;
line = line.substr(1, line.size() - 2); // trim []
size_t index = line.find(LINE_DELIMITER); // split by "]: ["
if (index == string::npos) {
fprintf(stderr, "Bad Line %s\n", line.c_str());
continue;
}
name = line.substr(0, index);
value = trim(line.substr(index + 4), DEFAULT_WHITESPACE);
if (value.empty()) continue;
// if the property name couldn't be found in proto definition or the value has mistype,
// add to extra properties with its name and value
if (!sysProp.insertField(&proto, convertToFieldName(name), value)) {
extras.push_back(make_pair(name, value));
}
}
// end session for the last write.
sysProp.endSession(&proto);
for (auto it = extras.begin(); it != extras.end(); it++) {
uint64_t token = proto.start(SystemPropertiesProto::EXTRA_PROPERTIES);
proto.write(SystemPropertiesProto::Property::NAME, it->first);
proto.write(SystemPropertiesProto::Property::VALUE, it->second);
proto.end(token);
}
if (!reader.ok(&line)) {
fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
return -1;
}
if (!proto.flush(out)) {
fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
return -1;
}
fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
return NO_ERROR;
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef SYSTEM_PROPERTIES_PARSER_H
#define SYSTEM_PROPERTIES_PARSER_H
#include "TextParserBase.h"
using namespace android;
/**
* SystemProperties parser, parses text produced by command getprop.
*/
class SystemPropertiesParser : public TextParserBase {
public:
SystemPropertiesParser() : TextParserBase(String8("SystemPropertiesParser")) {};
~SystemPropertiesParser() {};
virtual status_t Parse(const int in, const int out) const;
};
#endif // SYSTEM_PROPERTIES_PARSER_H

View File

@@ -0,0 +1 @@
random_battery_type_string

View File

@@ -0,0 +1,6 @@
freq cpu0 cpu1 cpu2 cpu3
307200 23860761 23860761 23890935 23890935
384000 83124 83124 29383 29383
748800 N/A N/A 10547 10547
768000 22652 22652 N/A N/A
825600 N/A N/A 13173 13173

Some files were not shown because too many files have changed in this diff Show More