summaryrefslogtreecommitdiff
path: root/cmds
diff options
context:
space:
mode:
Diffstat (limited to 'cmds')
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java3
-rw-r--r--cmds/am/src/com/android/commands/am/Instrument.java5
-rw-r--r--cmds/app_process/app_main.cpp24
-rw-r--r--cmds/appops/OWNERS1
-rw-r--r--cmds/backup/backup.cpp2
-rw-r--r--cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java4
-rw-r--r--cmds/bootanimation/Android.bp3
-rw-r--r--cmds/bootanimation/BootAnimation.cpp110
-rw-r--r--cmds/bootanimation/FORMAT.md4
-rw-r--r--cmds/bootanimation/audioplay.cpp26
-rw-r--r--cmds/gpu_counter_producer/Android.bp2
-rw-r--r--cmds/idmap2/Android.bp21
-rw-r--r--cmds/idmap2/idmap2/CreateMultiple.cpp8
-rw-r--r--cmds/idmap2/idmap2/Lookup.cpp6
-rw-r--r--cmds/idmap2/idmap2/Main.cpp8
-rw-r--r--cmds/idmap2/idmap2d/Idmap2Service.cpp49
-rw-r--r--cmds/idmap2/idmap2d/Idmap2Service.h15
-rw-r--r--cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl2
-rw-r--r--cmds/idmap2/include/idmap2/BinaryStreamVisitor.h2
-rw-r--r--cmds/idmap2/include/idmap2/FabricatedOverlay.h17
-rw-r--r--cmds/idmap2/include/idmap2/FileUtils.h4
-rw-r--r--cmds/idmap2/include/idmap2/Idmap.h7
-rw-r--r--cmds/idmap2/include/idmap2/LogInfo.h2
-rw-r--r--cmds/idmap2/include/idmap2/PrettyPrintVisitor.h2
-rw-r--r--cmds/idmap2/include/idmap2/RawPrintVisitor.h2
-rw-r--r--cmds/idmap2/include/idmap2/ResourceUtils.h2
-rw-r--r--cmds/idmap2/include/idmap2/XmlParser.h2
-rw-r--r--cmds/idmap2/libidmap2/CommandLineOptions.cpp9
-rw-r--r--cmds/idmap2/libidmap2/FabricatedOverlay.cpp34
-rw-r--r--cmds/idmap2/libidmap2/FileUtils.cpp24
-rw-r--r--cmds/idmap2/libidmap2/Idmap.cpp15
-rw-r--r--cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp18
-rw-r--r--cmds/idmap2/libidmap2/RawPrintVisitor.cpp12
-rw-r--r--cmds/idmap2/libidmap2/XmlParser.cpp15
-rw-r--r--cmds/idmap2/self_targeting/SelfTargeting.cpp1
-rw-r--r--cmds/idmap2/tests/FabricatedOverlayTests.cpp2
-rw-r--r--cmds/idmap2/tests/FileUtilsTests.cpp5
-rw-r--r--cmds/idmap2/tests/IdmapTests.cpp10
-rw-r--r--cmds/idmap2/tests/ResourceMappingTests.cpp2
-rw-r--r--cmds/incident/main.cpp10
-rw-r--r--cmds/incident_helper/src/TextParserBase.cpp8
-rw-r--r--cmds/incident_helper/src/main.cpp2
-rw-r--r--cmds/incident_helper/src/parsers/BatteryTypeParser.cpp4
-rw-r--r--cmds/incident_helper/src/parsers/CpuFreqParser.cpp4
-rw-r--r--cmds/incident_helper/src/parsers/CpuInfoParser.cpp10
-rw-r--r--cmds/incident_helper/src/parsers/EventLogTagsParser.cpp4
-rw-r--r--cmds/incident_helper/src/parsers/KernelWakesParser.cpp10
-rw-r--r--cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp4
-rw-r--r--cmds/incident_helper/src/parsers/ProcrankParser.cpp8
-rw-r--r--cmds/incident_helper/src/parsers/PsParser.cpp10
-rw-r--r--cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp4
-rw-r--r--cmds/incidentd/Android.bp64
-rw-r--r--cmds/incidentd/fuzzers/IncidentServiceFuzzer.cpp31
-rw-r--r--cmds/incidentd/src/IncidentService.cpp51
-rw-r--r--cmds/incidentd/src/Reporter.cpp4
-rw-r--r--cmds/incidentd/src/Section.cpp76
-rw-r--r--cmds/incidentd/src/report_directory.cpp6
-rw-r--r--cmds/locksettings/Android.bp5
-rwxr-xr-xcmds/locksettings/locksettings.sh6
-rw-r--r--cmds/locksettings/src/com/android/commands/locksettings/LockSettingsCmd.java47
-rw-r--r--cmds/screencap/screencap.cpp16
-rw-r--r--cmds/telecom/src/com/android/commands/telecom/Telecom.java19
-rw-r--r--cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java5
-rw-r--r--cmds/uinput/README.md272
-rw-r--r--cmds/uinput/jni/Android.bp1
-rw-r--r--cmds/uinput/jni/com_android_commands_uinput_Device.cpp48
-rw-r--r--cmds/uinput/src/com/android/commands/uinput/Device.java75
-rw-r--r--cmds/uinput/src/com/android/commands/uinput/Event.java235
-rw-r--r--cmds/uinput/src/com/android/commands/uinput/Uinput.java32
69 files changed, 1013 insertions, 538 deletions
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index b8d24e388d67..d79131ca5d7c 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -193,6 +193,9 @@ public class Am extends BaseCommand {
instrument.alwaysCheckSignature = true;
} else if (opt.equals("--instrument-sdk-sandbox")) {
instrument.instrumentSdkSandbox = true;
+ } else if (opt.equals("--instrument-sdk-in-sandbox")) {
+ instrument.instrumentSdkSandbox = true;
+ instrument.instrumentSdkInSandbox = true;
} else {
System.err.println("Error: Unknown option: " + opt);
return;
diff --git a/cmds/am/src/com/android/commands/am/Instrument.java b/cmds/am/src/com/android/commands/am/Instrument.java
index 2604497dcb63..e60593e8b633 100644
--- a/cmds/am/src/com/android/commands/am/Instrument.java
+++ b/cmds/am/src/com/android/commands/am/Instrument.java
@@ -20,6 +20,7 @@ import static android.app.ActivityManager.INSTR_FLAG_ALWAYS_CHECK_SIGNATURE;
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_HIDDEN_API_CHECKS;
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_ISOLATED_STORAGE;
import static android.app.ActivityManager.INSTR_FLAG_DISABLE_TEST_API_CHECKS;
+import static android.app.ActivityManager.INSTR_FLAG_INSTRUMENT_SDK_IN_SANDBOX;
import static android.app.ActivityManager.INSTR_FLAG_INSTRUMENT_SDK_SANDBOX;
import static android.app.ActivityManager.INSTR_FLAG_NO_RESTART;
@@ -99,6 +100,7 @@ public class Instrument {
public String componentNameArg;
public boolean alwaysCheckSignature = false;
public boolean instrumentSdkSandbox = false;
+ public boolean instrumentSdkInSandbox = false;
/**
* Construct the instrument command runner.
@@ -530,6 +532,9 @@ public class Instrument {
if (instrumentSdkSandbox) {
flags |= INSTR_FLAG_INSTRUMENT_SDK_SANDBOX;
}
+ if (instrumentSdkInSandbox) {
+ flags |= INSTR_FLAG_INSTRUMENT_SDK_IN_SANDBOX;
+ }
if (!mAm.startInstrumentation(cn, profileFile, flags, args, watcher, connection, userId,
abi)) {
throw new AndroidException("INSTRUMENTATION_FAILED: " + cn.flattenToString());
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 28db61f7d98a..4e41f2c1ac35 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -49,7 +49,7 @@ public:
virtual void onVmCreated(JNIEnv* env)
{
- if (mClassName.isEmpty()) {
+ if (mClassName.empty()) {
return; // Zygote. Nothing to do here.
}
@@ -66,10 +66,10 @@ public:
* executing boot class Java code and thereby deny ourselves access to
* non-boot classes.
*/
- char* slashClassName = toSlashClassName(mClassName.string());
+ char* slashClassName = toSlashClassName(mClassName.c_str());
mClass = env->FindClass(slashClassName);
if (mClass == NULL) {
- ALOGE("ERROR: could not find class '%s'\n", mClassName.string());
+ ALOGE("ERROR: could not find class '%s'\n", mClassName.c_str());
}
free(slashClassName);
@@ -98,7 +98,7 @@ public:
virtual void onExit(int code)
{
- if (mClassName.isEmpty()) {
+ if (mClassName.empty()) {
// if zygote
IPCThreadState::self()->stopProcess();
hardware::IPCThreadState::self()->stopProcess();
@@ -179,7 +179,7 @@ int main(int argc, char* const argv[])
argv_String.append(argv[i]);
argv_String.append("\" ");
}
- ALOGV("app_process main with argv: %s", argv_String.string());
+ ALOGV("app_process main with argv: %s", argv_String.c_str());
}
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
@@ -271,9 +271,9 @@ int main(int argc, char* const argv[])
} else if (strcmp(arg, "--application") == 0) {
application = true;
} else if (strncmp(arg, "--nice-name=", 12) == 0) {
- niceName.setTo(arg + 12);
+ niceName = (arg + 12);
} else if (strncmp(arg, "--", 2) != 0) {
- className.setTo(arg);
+ className = arg;
break;
} else {
--i;
@@ -282,7 +282,7 @@ int main(int argc, char* const argv[])
}
Vector<String8> args;
- if (!className.isEmpty()) {
+ if (!className.empty()) {
// We're not in zygote mode, the only argument we need to pass
// to RuntimeInit is the application argument.
//
@@ -300,7 +300,7 @@ int main(int argc, char* const argv[])
restOfArgs.append(argv_new[k]);
restOfArgs.append("\" ");
}
- ALOGV("Class name = %s, args = %s", className.string(), restOfArgs.string());
+ ALOGV("Class name = %s, args = %s", className.c_str(), restOfArgs.c_str());
}
} else {
// We're in zygote mode.
@@ -328,13 +328,13 @@ int main(int argc, char* const argv[])
}
}
- if (!niceName.isEmpty()) {
- runtime.setArgv0(niceName.string(), true /* setProcName */);
+ if (!niceName.empty()) {
+ runtime.setArgv0(niceName.c_str(), true /* setProcName */);
}
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
- } else if (!className.isEmpty()) {
+ } else if (!className.empty()) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
} else {
fprintf(stderr, "Error: no class name or --zygote supplied.\n");
diff --git a/cmds/appops/OWNERS b/cmds/appops/OWNERS
index 999ea0e62a0a..2fe78c5a7092 100644
--- a/cmds/appops/OWNERS
+++ b/cmds/appops/OWNERS
@@ -1 +1,2 @@
+#Bug component: 137825
include /core/java/android/permission/OWNERS
diff --git a/cmds/backup/backup.cpp b/cmds/backup/backup.cpp
index 8d9b528ae6a9..c2ce69011d92 100644
--- a/cmds/backup/backup.cpp
+++ b/cmds/backup/backup.cpp
@@ -75,7 +75,7 @@ static int perform_list(const char* filename)
size_t dataSize;
err = reader.ReadEntityHeader(&key, &dataSize);
if (err == 0) {
- printf(" entity: %s (%zu bytes)\n", key.string(), dataSize);
+ printf(" entity: %s (%zu bytes)\n", key.c_str(), dataSize);
} else {
printf(" Error reading entity header\n");
}
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index b6dc32a29f04..9dedf7025143 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -192,7 +192,7 @@ public class Bmgr {
}
if ("whitelist".equals(op)) {
- doPrintWhitelist();
+ doPrintAllowlist();
return;
}
@@ -911,7 +911,7 @@ public class Bmgr {
}
}
- private void doPrintWhitelist() {
+ private void doPrintAllowlist() {
try {
final String[] whitelist = mBmgr.getTransportWhitelist();
if (whitelist != null) {
diff --git a/cmds/bootanimation/Android.bp b/cmds/bootanimation/Android.bp
index 3534624a58a2..98767ee733ad 100644
--- a/cmds/bootanimation/Android.bp
+++ b/cmds/bootanimation/Android.bp
@@ -74,4 +74,7 @@ cc_library_shared {
"libGLESv2",
"libgui",
],
+ whole_static_libs: [
+ "libc++fs",
+ ],
}
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index a8b6c0b70804..89776dba7878 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -16,7 +16,9 @@
#define LOG_NDEBUG 0
#define LOG_TAG "BootAnimation"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <filesystem>
#include <vector>
#include <stdint.h>
@@ -28,6 +30,7 @@
#include <math.h>
#include <fcntl.h>
#include <utils/misc.h>
+#include <utils/Trace.h>
#include <signal.h>
#include <time.h>
@@ -79,18 +82,18 @@ static constexpr const char* PRODUCT_USERSPACE_REBOOT_ANIMATION_FILE = "/product
static constexpr const char* OEM_USERSPACE_REBOOT_ANIMATION_FILE = "/oem/media/userspace-reboot.zip";
static constexpr const char* SYSTEM_USERSPACE_REBOOT_ANIMATION_FILE = "/system/media/userspace-reboot.zip";
-static const char BOOTANIM_DATA_DIR_PATH[] = "/data/bootanim";
+static const char BOOTANIM_DATA_DIR_PATH[] = "/data/misc/bootanim";
static const char BOOTANIM_TIME_DIR_NAME[] = "time";
-static const char BOOTANIM_TIME_DIR_PATH[] = "/data/bootanim/time";
+static const char BOOTANIM_TIME_DIR_PATH[] = "/data/misc/bootanim/time";
static const char CLOCK_FONT_ASSET[] = "images/clock_font.png";
static const char CLOCK_FONT_ZIP_NAME[] = "clock_font.png";
static const char PROGRESS_FONT_ASSET[] = "images/progress_font.png";
static const char PROGRESS_FONT_ZIP_NAME[] = "progress_font.png";
static const char LAST_TIME_CHANGED_FILE_NAME[] = "last_time_change";
-static const char LAST_TIME_CHANGED_FILE_PATH[] = "/data/bootanim/time/last_time_change";
+static const char LAST_TIME_CHANGED_FILE_PATH[] = "/data/misc/bootanim/time/last_time_change";
static const char ACCURATE_TIME_FLAG_FILE_NAME[] = "time_is_accurate";
-static const char ACCURATE_TIME_FLAG_FILE_PATH[] = "/data/bootanim/time/time_is_accurate";
-static const char TIME_FORMAT_12_HOUR_FLAG_FILE_PATH[] = "/data/bootanim/time/time_format_12_hour";
+static const char ACCURATE_TIME_FLAG_FILE_PATH[] = "/data/misc/bootanim/time/time_is_accurate";
+static const char TIME_FORMAT_12_HOUR_FLAG_FILE_PATH[] = "/data/misc/bootanim/time/time_format_12_hour";
// Java timestamp format. Don't show the clock if the date is before 2000-01-01 00:00:00.
static const long long ACCURATE_TIME_EPOCH = 946684800000;
static constexpr char FONT_BEGIN_CHAR = ' ';
@@ -200,6 +203,7 @@ static GLfloat quadUVs[] = {
BootAnimation::BootAnimation(sp<Callbacks> callbacks)
: Thread(false), mLooper(new Looper(false)), mClockEnabled(true), mTimeIsAccurate(false),
mTimeFormat12Hour(false), mTimeCheckThread(nullptr), mCallbacks(callbacks) {
+ ATRACE_CALL();
mSession = new SurfaceComposerClient();
std::string powerCtl = android::base::GetProperty("sys.powerctl", "");
@@ -213,6 +217,7 @@ BootAnimation::BootAnimation(sp<Callbacks> callbacks)
}
BootAnimation::~BootAnimation() {
+ ATRACE_CALL();
if (mAnimation != nullptr) {
releaseAnimation(mAnimation);
mAnimation = nullptr;
@@ -222,6 +227,7 @@ BootAnimation::~BootAnimation() {
}
void BootAnimation::onFirstRef() {
+ ATRACE_CALL();
status_t err = mSession->linkToComposerDeath(this);
SLOGE_IF(err, "linkToComposerDeath failed (%s) ", strerror(-err));
if (err == NO_ERROR) {
@@ -240,6 +246,7 @@ sp<SurfaceComposerClient> BootAnimation::session() const {
}
void BootAnimation::binderDied(const wp<IBinder>&) {
+ ATRACE_CALL();
// woah, surfaceflinger died!
SLOGD("SurfaceFlinger died, exiting...");
@@ -251,6 +258,7 @@ void BootAnimation::binderDied(const wp<IBinder>&) {
static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitmapInfo* outInfo,
bool premultiplyAlpha) {
+ ATRACE_CALL();
AImageDecoder* decoder = nullptr;
AImageDecoder_createFromBuffer(encodedData, dataLength, &decoder);
if (!decoder) {
@@ -282,6 +290,7 @@ static void* decodeImage(const void* encodedData, size_t dataLength, AndroidBitm
status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
const char* name, bool premultiplyAlpha) {
+ ATRACE_CALL();
Asset* asset = assets.open(name, Asset::ACCESS_BUFFER);
if (asset == nullptr)
return NO_INIT;
@@ -338,6 +347,7 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets,
status_t BootAnimation::initTexture(FileMap* map, int* width, int* height,
bool premultiplyAlpha) {
+ ATRACE_CALL();
AndroidBitmapInfo bitmapInfo;
void* pixels = decodeImage(map->getDataPtr(), map->getDataLength(), &bitmapInfo,
premultiplyAlpha);
@@ -404,10 +414,12 @@ class BootAnimation::DisplayEventCallback : public LooperCallback {
public:
DisplayEventCallback(BootAnimation* bootAnimation) {
+ ATRACE_CALL();
mBootAnimation = bootAnimation;
}
int handleEvent(int /* fd */, int events, void* /* data */) {
+ ATRACE_CALL();
if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
ALOGE("Display event receiver pipe was closed or an error occurred. events=0x%x",
events);
@@ -492,6 +504,7 @@ ui::Size BootAnimation::limitSurfaceSize(int width, int height) const {
}
status_t BootAnimation::readyToRun() {
+ ATRACE_CALL();
mAssets.addDefaultAssets();
const std::vector<PhysicalDisplayId> ids = SurfaceComposerClient::getPhysicalDisplayIds();
@@ -628,6 +641,7 @@ status_t BootAnimation::readyToRun() {
}
void BootAnimation::rotateAwayFromNaturalOrientationIfNeeded() {
+ ATRACE_CALL();
const auto orientation = parseOrientationProperty();
if (orientation == ui::ROTATION_0) {
@@ -650,6 +664,7 @@ void BootAnimation::rotateAwayFromNaturalOrientationIfNeeded() {
}
ui::Rotation BootAnimation::parseOrientationProperty() {
+ ATRACE_CALL();
const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds();
if (displayIds.size() == 0) {
return ui::ROTATION_0;
@@ -672,11 +687,13 @@ ui::Rotation BootAnimation::parseOrientationProperty() {
}
void BootAnimation::projectSceneToWindow() {
+ ATRACE_CALL();
glViewport(0, 0, mWidth, mHeight);
glScissor(0, 0, mWidth, mHeight);
}
void BootAnimation::resizeSurface(int newWidth, int newHeight) {
+ ATRACE_CALL();
// We assume this function is called on the animation thread.
if (newWidth == mWidth && newHeight == mHeight) {
return;
@@ -704,8 +721,9 @@ void BootAnimation::resizeSurface(int newWidth, int newHeight) {
}
bool BootAnimation::preloadAnimation() {
+ ATRACE_CALL();
findBootAnimationFile();
- if (!mZipFileName.isEmpty()) {
+ if (!mZipFileName.empty()) {
mAnimation = loadAnimation(mZipFileName);
return (mAnimation != nullptr);
}
@@ -714,6 +732,7 @@ bool BootAnimation::preloadAnimation() {
}
bool BootAnimation::findBootAnimationFileInternal(const std::vector<std::string> &files) {
+ ATRACE_CALL();
for (const std::string& f : files) {
if (access(f.c_str(), R_OK) == 0) {
mZipFileName = f.c_str();
@@ -724,6 +743,7 @@ bool BootAnimation::findBootAnimationFileInternal(const std::vector<std::string>
}
void BootAnimation::findBootAnimationFile() {
+ ATRACE_CALL();
const bool playDarkAnim = android::base::GetIntProperty("ro.boot.theme", 0) == 1;
static const std::vector<std::string> bootFiles = {
APEX_BOOTANIMATION_FILE, playDarkAnim ? PRODUCT_BOOTANIMATION_DARK_FILE : PRODUCT_BOOTANIMATION_FILE,
@@ -747,6 +767,7 @@ void BootAnimation::findBootAnimationFile() {
}
GLuint compileShader(GLenum shaderType, const GLchar *source) {
+ ATRACE_CALL();
GLuint shader = glCreateShader(shaderType);
glShaderSource(shader, 1, &source, 0);
glCompileShader(shader);
@@ -765,6 +786,7 @@ GLuint compileShader(GLenum shaderType, const GLchar *source) {
}
GLuint linkShader(GLuint vertexShader, GLuint fragmentShader) {
+ ATRACE_CALL();
GLuint program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);
@@ -780,6 +802,7 @@ GLuint linkShader(GLuint vertexShader, GLuint fragmentShader) {
}
void BootAnimation::initShaders() {
+ ATRACE_CALL();
bool dynamicColoringEnabled = mAnimation != nullptr && mAnimation->dynamicColoringEnabled;
GLuint vertexShader = compileShader(GL_VERTEX_SHADER, (const GLchar *)VERTEX_SHADER_SOURCE);
GLuint imageFragmentShader =
@@ -813,12 +836,13 @@ void BootAnimation::initShaders() {
}
bool BootAnimation::threadLoop() {
+ ATRACE_CALL();
bool result;
initShaders();
// We have no bootanimation file, so we use the stock android logo
// animation.
- if (mZipFileName.isEmpty()) {
+ if (mZipFileName.empty()) {
ALOGD("No animation file");
result = android();
} else {
@@ -838,6 +862,7 @@ bool BootAnimation::threadLoop() {
}
bool BootAnimation::android() {
+ ATRACE_CALL();
glActiveTexture(GL_TEXTURE0);
SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot",
@@ -905,6 +930,7 @@ bool BootAnimation::android() {
}
void BootAnimation::checkExit() {
+ ATRACE_CALL();
// Allow surface flinger to gracefully request shutdown
char value[PROPERTY_VALUE_MAX];
property_get(EXIT_PROP_NAME, value, "0");
@@ -915,10 +941,12 @@ void BootAnimation::checkExit() {
}
bool BootAnimation::validClock(const Animation::Part& part) {
+ ATRACE_CALL();
return part.clockPosX != TEXT_MISSING_VALUE && part.clockPosY != TEXT_MISSING_VALUE;
}
bool parseTextCoord(const char* str, int* dest) {
+ ATRACE_CALL();
if (strcmp("c", str) == 0) {
*dest = TEXT_CENTER_VALUE;
return true;
@@ -935,6 +963,7 @@ bool parseTextCoord(const char* str, int* dest) {
// Parse two position coordinates. If only string is non-empty, treat it as the y value.
void parsePosition(const char* str1, const char* str2, int* x, int* y) {
+ ATRACE_CALL();
bool success = false;
if (strlen(str1) == 0) { // No values were specified
// success = false
@@ -963,6 +992,7 @@ void parsePosition(const char* str1, const char* str2, int* x, int* y) {
// If the input string isn't valid, parseColor returns false and color is
// left unchanged.
static bool parseColor(const char str[7], float color[3]) {
+ ATRACE_CALL();
float tmpColor[3];
for (int i = 0; i < 3; i++) {
int val = 0;
@@ -985,6 +1015,7 @@ static bool parseColor(const char str[7], float color[3]) {
// If the input color string is empty, set color with values in defaultColor.
static void parseColorDecimalString(const std::string& colorString,
float color[3], float defaultColor[3]) {
+ ATRACE_CALL();
if (colorString == "") {
memcpy(color, defaultColor, sizeof(float) * 3);
return;
@@ -996,6 +1027,7 @@ static void parseColorDecimalString(const std::string& colorString,
}
static bool readFile(ZipFileRO* zip, const char* name, String8& outString) {
+ ATRACE_CALL();
ZipEntryRO entry = zip->findEntryByName(name);
SLOGE_IF(!entry, "couldn't find %s", name);
if (!entry) {
@@ -1009,7 +1041,7 @@ static bool readFile(ZipFileRO* zip, const char* name, String8& outString) {
return false;
}
- outString.setTo((char const*)entryMap->getDataPtr(), entryMap->getDataLength());
+ outString = String8((char const*)entryMap->getDataPtr(), entryMap->getDataLength());
delete entryMap;
return true;
}
@@ -1018,6 +1050,7 @@ static bool readFile(ZipFileRO* zip, const char* name, String8& outString) {
// columns are the printable ASCII characters 0x20 - 0x7f. The
// top row is regular text; the bottom row is bold.
status_t BootAnimation::initFont(Font* font, const char* fallback) {
+ ATRACE_CALL();
status_t status = NO_ERROR;
if (font->map != nullptr) {
@@ -1045,6 +1078,7 @@ status_t BootAnimation::initFont(Font* font, const char* fallback) {
}
void BootAnimation::drawText(const char* str, const Font& font, bool bold, int* x, int* y) {
+ ATRACE_CALL();
glEnable(GL_BLEND); // Allow us to draw on top of the animation
glBindTexture(GL_TEXTURE_2D, font.texture.name);
glUseProgram(mTextShader);
@@ -1092,6 +1126,7 @@ void BootAnimation::drawText(const char* str, const Font& font, bool bold, int*
// We render 12 or 24 hour time.
void BootAnimation::drawClock(const Font& font, const int xPos, const int yPos) {
+ ATRACE_CALL();
static constexpr char TIME_FORMAT_12[] = "%l:%M";
static constexpr char TIME_FORMAT_24[] = "%H:%M";
static constexpr int TIME_LENGTH = 6;
@@ -1117,6 +1152,7 @@ void BootAnimation::drawClock(const Font& font, const int xPos, const int yPos)
}
void BootAnimation::drawProgress(int percent, const Font& font, const int xPos, const int yPos) {
+ ATRACE_CALL();
static constexpr int PERCENT_LENGTH = 5;
char percentBuff[PERCENT_LENGTH];
@@ -1129,12 +1165,13 @@ void BootAnimation::drawProgress(int percent, const Font& font, const int xPos,
}
bool BootAnimation::parseAnimationDesc(Animation& animation) {
+ ATRACE_CALL();
String8 desString;
if (!readFile(animation.zip, "desc.txt", desString)) {
return false;
}
- char const* s = desString.string();
+ char const* s = desString.c_str();
std::string dynamicColoringPartName = "";
bool postDynamicColoring = false;
@@ -1143,7 +1180,7 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) {
const char* endl = strstr(s, "\n");
if (endl == nullptr) break;
String8 line(s, endl - s);
- const char* l = line.string();
+ const char* l = line.c_str();
int fps = 0;
int width = 0;
int height = 0;
@@ -1252,6 +1289,7 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) {
}
bool BootAnimation::preloadZip(Animation& animation) {
+ ATRACE_CALL();
// read all the data structures
const size_t pcount = animation.parts.size();
void *cookie = nullptr;
@@ -1269,10 +1307,10 @@ bool BootAnimation::preloadZip(Animation& animation) {
continue;
}
- const String8 entryName(name);
- const String8 path(entryName.getPathDir());
- const String8 leaf(entryName.getPathLeaf());
- if (leaf.size() > 0) {
+ const std::filesystem::path entryName(name);
+ const std::filesystem::path path(entryName.parent_path());
+ const std::filesystem::path leaf(entryName.filename());
+ if (!leaf.empty()) {
if (entryName == CLOCK_FONT_ZIP_NAME) {
FileMap* map = zip->createEntryFileMap(entry);
if (map) {
@@ -1290,7 +1328,7 @@ bool BootAnimation::preloadZip(Animation& animation) {
}
for (size_t j = 0; j < pcount; j++) {
- if (path == animation.parts[j].path) {
+ if (path.string() == animation.parts[j].path.c_str()) {
uint16_t method;
// supports only stored png files
if (zip->getEntryInfo(entry, &method, nullptr, nullptr, nullptr, nullptr, nullptr)) {
@@ -1303,11 +1341,11 @@ bool BootAnimation::preloadZip(Animation& animation) {
part.audioData = (uint8_t *)map->getDataPtr();
part.audioLength = map->getDataLength();
} else if (leaf == "trim.txt") {
- part.trimData.setTo((char const*)map->getDataPtr(),
+ part.trimData = String8((char const*)map->getDataPtr(),
map->getDataLength());
} else {
Animation::Frame frame;
- frame.name = leaf;
+ frame.name = leaf.c_str();
frame.map = map;
frame.trimWidth = animation.width;
frame.trimHeight = animation.height;
@@ -1327,7 +1365,7 @@ bool BootAnimation::preloadZip(Animation& animation) {
// If there is trimData present, override the positioning defaults.
for (Animation::Part& part : animation.parts) {
- const char* trimDataStr = part.trimData.string();
+ const char* trimDataStr = part.trimData.c_str();
for (size_t frameIdx = 0; frameIdx < part.frames.size(); frameIdx++) {
const char* endl = strstr(trimDataStr, "\n");
// No more trimData for this part.
@@ -1335,7 +1373,7 @@ bool BootAnimation::preloadZip(Animation& animation) {
break;
}
String8 line(trimDataStr, endl - trimDataStr);
- const char* lineStr = line.string();
+ const char* lineStr = line.c_str();
trimDataStr = ++endl;
int width = 0, height = 0, x = 0, y = 0;
if (sscanf(lineStr, "%dx%d+%d+%d", &width, &height, &x, &y) == 4) {
@@ -1357,6 +1395,7 @@ bool BootAnimation::preloadZip(Animation& animation) {
}
bool BootAnimation::movie() {
+ ATRACE_CALL();
if (mAnimation == nullptr) {
mAnimation = loadAnimation(mZipFileName);
}
@@ -1393,7 +1432,7 @@ bool BootAnimation::movie() {
if (!exts) {
glGetError();
} else {
- gl_extensions.setTo(exts);
+ gl_extensions = exts;
if ((gl_extensions.find("GL_ARB_texture_non_power_of_two") != -1) ||
(gl_extensions.find("GL_OES_texture_npot") != -1)) {
mUseNpotTextures = true;
@@ -1450,6 +1489,7 @@ bool BootAnimation::movie() {
bool BootAnimation::shouldStopPlayingPart(const Animation::Part& part,
const int fadedFramesCount,
const int lastDisplayedProgress) {
+ ATRACE_CALL();
// stop playing only if it is time to exit and it's a partial part which has been faded out
return exitPending() && !part.playUntilComplete && fadedFramesCount >= part.framesToFadeCount &&
(lastDisplayedProgress == 0 || lastDisplayedProgress == 100);
@@ -1461,6 +1501,7 @@ float mapLinear(float x, float a1, float a2, float b1, float b2) {
}
void BootAnimation::drawTexturedQuad(float xStart, float yStart, float width, float height) {
+ ATRACE_CALL();
// Map coordinates from screen space to world space.
float x0 = mapLinear(xStart, 0, mWidth, -1, 1);
float y0 = mapLinear(yStart, 0, mHeight, -1, 1);
@@ -1484,6 +1525,7 @@ void BootAnimation::drawTexturedQuad(float xStart, float yStart, float width, fl
}
void BootAnimation::initDynamicColors() {
+ ATRACE_CALL();
for (int i = 0; i < DYNAMIC_COLOR_COUNT; i++) {
const auto syspropName = "persist.bootanim.color" + std::to_string(i + 1);
const auto syspropValue = android::base::GetProperty(syspropName, "");
@@ -1510,6 +1552,7 @@ void BootAnimation::initDynamicColors() {
}
bool BootAnimation::playAnimation(const Animation& animation) {
+ ATRACE_CALL();
const size_t pcount = animation.parts.size();
nsecs_t frameDuration = s2ns(1) / animation.fps;
@@ -1523,6 +1566,7 @@ bool BootAnimation::playAnimation(const Animation& animation) {
for (size_t i=0 ; i<pcount ; i++) {
const Animation::Part& part(animation.parts[i]);
const size_t fcount = part.frames.size();
+ glBindTexture(GL_TEXTURE_2D, 0);
// Handle animation package
if (part.animation != nullptr) {
@@ -1562,7 +1606,7 @@ bool BootAnimation::playAnimation(const Animation& animation) {
1.0f);
ALOGD("Playing files = %s/%s, Requested repeat = %d, playUntilComplete = %s",
- animation.fileName.string(), part.path.string(), part.count,
+ animation.fileName.c_str(), part.path.c_str(), part.count,
part.playUntilComplete ? "true" : "false");
// For the last animation, if we have progress indicator from
@@ -1599,8 +1643,10 @@ bool BootAnimation::playAnimation(const Animation& animation) {
if (r > 0) {
glBindTexture(GL_TEXTURE_2D, frame.tid);
} else {
- glGenTextures(1, &frame.tid);
- glBindTexture(GL_TEXTURE_2D, frame.tid);
+ if (part.count != 1) {
+ glGenTextures(1, &frame.tid);
+ glBindTexture(GL_TEXTURE_2D, frame.tid);
+ }
int w, h;
// Set decoding option to alpha unpremultiplied so that the R, G, B channels
// of transparent pixels are preserved.
@@ -1720,12 +1766,14 @@ bool BootAnimation::playAnimation(const Animation& animation) {
}
void BootAnimation::processDisplayEvents() {
+ ATRACE_CALL();
// This will poll mDisplayEventReceiver and if there are new events it'll call
// displayEventCallback synchronously.
mLooper->pollOnce(0);
}
void BootAnimation::handleViewport(nsecs_t timestep) {
+ ATRACE_CALL();
if (mShuttingDown || !mFlingerSurfaceControl || mTargetInset == 0) {
return;
}
@@ -1768,6 +1816,7 @@ void BootAnimation::handleViewport(nsecs_t timestep) {
}
void BootAnimation::releaseAnimation(Animation* animation) const {
+ ATRACE_CALL();
for (Vector<Animation::Part>::iterator it = animation->parts.begin(),
e = animation->parts.end(); it != e; ++it) {
if (it->animation)
@@ -1779,19 +1828,20 @@ void BootAnimation::releaseAnimation(Animation* animation) const {
}
BootAnimation::Animation* BootAnimation::loadAnimation(const String8& fn) {
+ ATRACE_CALL();
if (mLoadedFiles.indexOf(fn) >= 0) {
SLOGE("File \"%s\" is already loaded. Cyclic ref is not allowed",
- fn.string());
+ fn.c_str());
return nullptr;
}
- ZipFileRO *zip = ZipFileRO::open(fn);
+ ZipFileRO *zip = ZipFileRO::open(fn.c_str());
if (zip == nullptr) {
SLOGE("Failed to open animation zip \"%s\": %s",
- fn.string(), strerror(errno));
+ fn.c_str(), strerror(errno));
return nullptr;
}
- ALOGD("%s is loaded successfully", fn.string());
+ ALOGD("%s is loaded successfully", fn.c_str());
Animation *animation = new Animation;
animation->fileName = fn;
@@ -1810,6 +1860,7 @@ BootAnimation::Animation* BootAnimation::loadAnimation(const String8& fn) {
}
bool BootAnimation::updateIsTimeAccurate() {
+ ATRACE_CALL();
static constexpr long long MAX_TIME_IN_PAST = 60000LL * 60LL * 24LL * 30LL; // 30 days
static constexpr long long MAX_TIME_IN_FUTURE = 60000LL * 90LL; // 90 minutes
@@ -1853,11 +1904,13 @@ BootAnimation::TimeCheckThread::TimeCheckThread(BootAnimation* bootAnimation) :
mInotifyFd(-1), mBootAnimWd(-1), mTimeWd(-1), mBootAnimation(bootAnimation) {}
BootAnimation::TimeCheckThread::~TimeCheckThread() {
+ ATRACE_CALL();
// mInotifyFd may be -1 but that's ok since we're not at risk of attempting to close a valid FD.
close(mInotifyFd);
}
bool BootAnimation::TimeCheckThread::threadLoop() {
+ ATRACE_CALL();
bool shouldLoop = doThreadLoop() && !mBootAnimation->mTimeIsAccurate
&& mBootAnimation->mClockEnabled;
if (!shouldLoop) {
@@ -1868,6 +1921,7 @@ bool BootAnimation::TimeCheckThread::threadLoop() {
}
bool BootAnimation::TimeCheckThread::doThreadLoop() {
+ ATRACE_CALL();
static constexpr int BUFF_LEN (10 * (sizeof(struct inotify_event) + NAME_MAX + 1));
// Poll instead of doing a blocking read so the Thread can exit if requested.
@@ -1905,6 +1959,7 @@ bool BootAnimation::TimeCheckThread::doThreadLoop() {
}
void BootAnimation::TimeCheckThread::addTimeDirWatch() {
+ ATRACE_CALL();
mTimeWd = inotify_add_watch(mInotifyFd, BOOTANIM_TIME_DIR_PATH,
IN_CLOSE_WRITE | IN_MOVED_TO | IN_ATTRIB);
if (mTimeWd > 0) {
@@ -1915,6 +1970,7 @@ void BootAnimation::TimeCheckThread::addTimeDirWatch() {
}
status_t BootAnimation::TimeCheckThread::readyToRun() {
+ ATRACE_CALL();
mInotifyFd = inotify_init();
if (mInotifyFd < 0) {
SLOGE("Could not initialize inotify fd");
diff --git a/cmds/bootanimation/FORMAT.md b/cmds/bootanimation/FORMAT.md
index 988685e23443..01e8fe13fdf6 100644
--- a/cmds/bootanimation/FORMAT.md
+++ b/cmds/bootanimation/FORMAT.md
@@ -152,14 +152,14 @@ based on animation progression.
To enable it, add the following line as the second line of desc.txt:
- dynamic_colors PATH #RGBHEX0 #RGBHEX1 #RGBHEX2 #RGBHEX3
+ dynamic_colors PATH #RGBHEX1 #RGBHEX2 #RGBHEX3 #RGBHEX4
* **PATH:** file path of the part to apply dynamic color transition to.
Any part before this part will be rendered in the start colors.
Any part after will be rendered in the end colors.
* **RGBHEX1:** the first start color (masked by the R channel), specified as `#RRGGBB`.
* **RGBHEX2:** the second start color (masked by the G channel), specified as `#RRGGBB`.
- * **RGBHEX3:** the thrid start color (masked by the B channel), specified as `#RRGGBB`.
+ * **RGBHEX3:** the third start color (masked by the B channel), specified as `#RRGGBB`.
* **RGBHEX4:** the forth start color (masked by the A channel), specified as `#RRGGBB`.
The end colors will be read from the following system properties:
diff --git a/cmds/bootanimation/audioplay.cpp b/cmds/bootanimation/audioplay.cpp
index c5e16c6b7deb..9b95b04149bf 100644
--- a/cmds/bootanimation/audioplay.cpp
+++ b/cmds/bootanimation/audioplay.cpp
@@ -20,6 +20,8 @@
#define CHATTY ALOGD
#define LOG_TAG "audioplay"
+#include <binder/IServiceManager.h>
+
#include "audioplay.h"
#include <string.h>
@@ -316,8 +318,13 @@ public:
: Thread(false),
mExampleAudioData(exampleAudioData),
mExampleAudioLength(exampleAudioLength) {}
+
private:
virtual bool threadLoop() {
+ if (defaultServiceManager()->checkService(String16("audio")) == nullptr) {
+ ALOGW("Audio service is not ready yet, ignore creating playback engine");
+ return false;
+ }
audioplay::create(mExampleAudioData, mExampleAudioLength);
// Exit immediately
return false;
@@ -334,6 +341,11 @@ class AudioAnimationCallbacks : public android::BootAnimation::Callbacks {
public:
void init(const Vector<Animation::Part>& parts) override {
const Animation::Part* partWithAudio = nullptr;
+
+ if (!playSoundsAllowed()) {
+ return;
+ }
+
for (const Animation::Part& part : parts) {
if (part.audioData != nullptr) {
partWithAudio = &part;
@@ -401,14 +413,14 @@ bool create(const uint8_t* exampleClipBuf, int exampleClipBufSize) {
}
bool playClip(const uint8_t* buf, int size) {
- // Parse the WAV header
- const ChunkFormat* chunkFormat;
- if (!parseClipBuf(buf, size, &chunkFormat, &nextBuffer, &nextSize)) {
+ if (!hasPlayer()) {
+ ALOGE("cannot play clip %p without a player", buf);
return false;
}
- if (!hasPlayer()) {
- ALOGD("cannot play clip %p without a player", buf);
+ // Parse the WAV header
+ const ChunkFormat* chunkFormat;
+ if (!parseClipBuf(buf, size, &chunkFormat, &nextBuffer, &nextSize)) {
return false;
}
@@ -433,11 +445,9 @@ bool playClip(const uint8_t* buf, int size) {
void setPlaying(bool isPlaying) {
if (!hasPlayer()) return;
- SLresult result;
-
if (nullptr != bqPlayerPlay) {
// set the player's state
- result = (*bqPlayerPlay)->SetPlayState(bqPlayerPlay,
+ (*bqPlayerPlay)->SetPlayState(bqPlayerPlay,
isPlaying ? SL_PLAYSTATE_PLAYING : SL_PLAYSTATE_STOPPED);
}
diff --git a/cmds/gpu_counter_producer/Android.bp b/cmds/gpu_counter_producer/Android.bp
index 5b118ce62679..2232345ce4fa 100644
--- a/cmds/gpu_counter_producer/Android.bp
+++ b/cmds/gpu_counter_producer/Android.bp
@@ -18,8 +18,6 @@ cc_binary {
"-Werror",
"-Wunused",
"-Wunreachable-code",
- "-fPIE",
- "-pie",
],
soc_specific: true,
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index 5f06c971ba98..55ec7dae16b1 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -28,11 +28,14 @@ cc_defaults {
tidy_checks: [
"modernize-*",
"-modernize-avoid-c-arrays",
+ "-modernize-use-nodiscard",
"-modernize-use-trailing-return-type",
"android-*",
"misc-*",
+ "-misc-const-correctness",
"readability-*",
"-readability-identifier-length",
+ "-readability-implicit-bool-conversion",
],
tidy_checks_as_errors: [
"modernize-*",
@@ -56,6 +59,7 @@ cc_defaults {
"-readability-const-return-type",
"-readability-convert-member-functions-to-static",
"-readability-duplicate-include",
+ "-readability-implicit-bool-conversion",
"-readability-else-after-return",
"-readability-named-parameter",
"-readability-redundant-access-specifiers",
@@ -80,13 +84,13 @@ cc_library {
enabled: false,
},
static_libs: [
+ "libidmap2_policies",
"libidmap2_protos",
],
shared_libs: [
"libandroidfw",
"libbase",
"libcutils",
- "libidmap2_policies",
"libprotobuf-cpp-lite",
"libutils",
"libz",
@@ -125,7 +129,7 @@ cc_library {
},
}
-cc_library {
+cc_library_static {
name: "libidmap2_policies",
defaults: [
"idmap2_defaults",
@@ -142,9 +146,6 @@ cc_library {
],
},
host: {
- shared: {
- enabled: false,
- },
static_libs: [
"libandroidfw",
],
@@ -191,7 +192,6 @@ cc_test {
"libandroidfw",
"libbase",
"libidmap2",
- "libidmap2_policies",
"liblog",
"libprotobuf-cpp-lite",
"libutils",
@@ -199,6 +199,9 @@ cc_test {
"libz",
"libziparchive",
],
+ static_libs: [
+ "libidmap2_policies",
+ ],
},
host: {
static_libs: [
@@ -255,12 +258,14 @@ cc_binary {
"libbase",
"libcutils",
"libidmap2",
- "libidmap2_policies",
"libprotobuf-cpp-lite",
"libutils",
"libz",
"libziparchive",
],
+ static_libs: [
+ "libidmap2_policies",
+ ],
},
host: {
static_libs: [
@@ -298,13 +303,13 @@ cc_binary {
"libbinder",
"libcutils",
"libidmap2",
- "libidmap2_policies",
"libprotobuf-cpp-lite",
"libutils",
"libziparchive",
],
static_libs: [
"libc++fs",
+ "libidmap2_policies",
"libidmap2_protos",
"libidmap2daidl",
],
diff --git a/cmds/idmap2/idmap2/CreateMultiple.cpp b/cmds/idmap2/idmap2/CreateMultiple.cpp
index 953d99f8dcfb..68800cde6101 100644
--- a/cmds/idmap2/idmap2/CreateMultiple.cpp
+++ b/cmds/idmap2/idmap2/CreateMultiple.cpp
@@ -18,8 +18,8 @@
#include <sys/types.h> // umask
#include <fstream>
+#include <iostream>
#include <memory>
-#include <ostream>
#include <string>
#include <vector>
@@ -51,7 +51,7 @@ using android::idmap2::utils::UidHasWriteAccessToPath;
Result<Unit> CreateMultiple(const std::vector<std::string>& args) {
SYSTRACE << "CreateMultiple " << args;
std::string target_apk_path;
- std::string idmap_dir = kIdmapCacheDir;
+ std::string idmap_dir{kIdmapCacheDir};
std::vector<std::string> overlay_apk_paths;
std::vector<std::string> policies;
bool ignore_overlayable = false;
@@ -67,7 +67,7 @@ Result<Unit> CreateMultiple(const std::vector<std::string>& args) {
.OptionalOption("--idmap-dir",
StringPrintf("output: path to the directory in which to write idmap file"
" (defaults to %s)",
- kIdmapCacheDir),
+ kIdmapCacheDir.data()),
&idmap_dir)
.OptionalOption("--policy",
"input: an overlayable policy this overlay fulfills"
@@ -142,7 +142,7 @@ Result<Unit> CreateMultiple(const std::vector<std::string>& args) {
}
for (const std::string& idmap_path : idmap_paths) {
- std::cout << idmap_path << std::endl;
+ std::cout << idmap_path << '\n';
}
return Unit{};
diff --git a/cmds/idmap2/idmap2/Lookup.cpp b/cmds/idmap2/idmap2/Lookup.cpp
index add0d8d48108..34d91795fc29 100644
--- a/cmds/idmap2/idmap2/Lookup.cpp
+++ b/cmds/idmap2/idmap2/Lookup.cpp
@@ -16,9 +16,9 @@
#include <algorithm>
#include <fstream>
+#include <iostream>
#include <iterator>
#include <memory>
-#include <ostream>
#include <string>
#include <utility>
#include <vector>
@@ -94,7 +94,7 @@ void PrintValue(AssetManager2* const am, const AssetManager2::SelectedValue& val
const ResStringPool* pool = am->GetStringPoolForCookie(value.cookie);
out->append("\"");
if (auto str = pool->string8ObjectAt(value.data); str.ok()) {
- out->append(*str);
+ out->append(str->c_str());
}
} break;
default:
@@ -230,7 +230,7 @@ Result<Unit> Lookup(const std::vector<std::string>& args) {
if (!value) {
return Error(value.GetError(), "resource 0x%08x not found", *resid);
}
- std::cout << *value << std::endl;
+ std::cout << *value << '\n';
}
return Unit{};
diff --git a/cmds/idmap2/idmap2/Main.cpp b/cmds/idmap2/idmap2/Main.cpp
index aa6d0e76698f..5ef15a684853 100644
--- a/cmds/idmap2/idmap2/Main.cpp
+++ b/cmds/idmap2/idmap2/Main.cpp
@@ -45,7 +45,7 @@ void PrintUsage(const NameToFunctionMap& commands, std::ostream& out) {
}
out << iter->first;
}
- out << "]" << std::endl;
+ out << "]" << '\n';
}
} // namespace
@@ -65,18 +65,18 @@ int main(int argc, char** argv) {
const std::unique_ptr<std::vector<std::string>> args =
CommandLineOptions::ConvertArgvToVector(argc - 1, const_cast<const char**>(argv + 1));
if (!args) {
- std::cerr << "error: failed to parse command line options" << std::endl;
+ std::cerr << "error: failed to parse command line options" << '\n';
return EXIT_FAILURE;
}
const auto iter = commands.find(argv[1]);
if (iter == commands.end()) {
- std::cerr << argv[1] << ": command not found" << std::endl;
+ std::cerr << argv[1] << ": command not found" << '\n';
PrintUsage(commands, std::cerr);
return EXIT_FAILURE;
}
const auto result = iter->second(*args);
if (!result) {
- std::cerr << "error: " << result.GetErrorMessage() << std::endl;
+ std::cerr << "error: " << result.GetErrorMessage() << '\n';
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index 10947dc90a76..d76ca5bdce42 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -59,7 +59,7 @@ using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask
namespace {
-constexpr const char* kFrameworkPath = "/system/framework/framework-res.apk";
+constexpr std::string_view kFrameworkPath = "/system/framework/framework-res.apk";
Status ok() {
return Status::ok();
@@ -207,23 +207,47 @@ Status Idmap2Service::createIdmap(const std::string& target_path, const std::str
idmap2::Result<Idmap2Service::TargetResourceContainerPtr> Idmap2Service::GetTargetContainer(
const std::string& target_path) {
- if (target_path == kFrameworkPath) {
- if (framework_apk_cache_ == nullptr) {
- // Initialize the framework APK cache.
- auto target = TargetResourceContainer::FromPath(target_path);
- if (!target) {
- return target.GetError();
+ const bool is_framework = target_path == kFrameworkPath;
+ bool use_cache;
+ struct stat st = {};
+ if (is_framework || !::stat(target_path.c_str(), &st)) {
+ use_cache = true;
+ } else {
+ LOG(WARNING) << "failed to stat target path '" << target_path << "' for the cache";
+ use_cache = false;
+ }
+
+ if (use_cache) {
+ std::lock_guard lock(container_cache_mutex_);
+ if (auto cache_it = container_cache_.find(target_path); cache_it != container_cache_.end()) {
+ const auto& item = cache_it->second;
+ if (is_framework ||
+ (item.dev == st.st_dev && item.inode == st.st_ino && item.size == st.st_size
+ && item.mtime.tv_sec == st.st_mtim.tv_sec && item.mtime.tv_nsec == st.st_mtim.tv_nsec)) {
+ return {item.apk.get()};
}
- framework_apk_cache_ = std::move(*target);
+ container_cache_.erase(cache_it);
}
- return {framework_apk_cache_.get()};
}
auto target = TargetResourceContainer::FromPath(target_path);
if (!target) {
return target.GetError();
}
- return {std::move(*target)};
+ if (!use_cache) {
+ return {std::move(*target)};
+ }
+
+ const auto res = target->get();
+ std::lock_guard lock(container_cache_mutex_);
+ container_cache_.emplace(target_path, CachedContainer {
+ .dev = dev_t(st.st_dev),
+ .inode = ino_t(st.st_ino),
+ .size = st.st_size,
+ .mtime = st.st_mtim,
+ .apk = std::move(*target)
+ });
+ return {res};
}
Status Idmap2Service::createFabricatedOverlay(
@@ -241,7 +265,8 @@ Status Idmap2Service::createFabricatedOverlay(
res.configuration.value_or(std::string()));
} else if (res.binaryData.has_value()) {
builder.SetResourceValue(res.resourceName, res.binaryData->get(),
- res.configuration.value_or(std::string()));
+ res.binaryDataOffset, res.binaryDataSize,
+ res.configuration.value_or(std::string()));
} else {
builder.SetResourceValue(res.resourceName, res.dataType, res.data,
res.configuration.value_or(std::string()));
@@ -257,7 +282,7 @@ Status Idmap2Service::createFabricatedOverlay(
const std::string random_suffix = RandomStringForPath(kSuffixLength);
file_name = StringPrintf("%s-%s-%s.frro", overlay.packageName.c_str(),
overlay.overlayName.c_str(), random_suffix.c_str());
- path = StringPrintf("%s/%s", kIdmapCacheDir, file_name.c_str());
+ path = StringPrintf("%s/%s", kIdmapCacheDir.data(), file_name.c_str());
// Invoking std::filesystem::exists with a file name greater than 255 characters will cause this
// process to abort since the name exceeds the maximum file name size.
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.h b/cmds/idmap2/idmap2d/Idmap2Service.h
index cc8cc5f218d2..a69fa6119974 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.h
+++ b/cmds/idmap2/idmap2d/Idmap2Service.h
@@ -75,7 +75,20 @@ class Idmap2Service : public BinderService<Idmap2Service>, public BnIdmap2 {
private:
// idmap2d is killed after a period of inactivity, so any information stored on this class should
// be able to be recalculated if idmap2 dies and restarts.
- std::unique_ptr<idmap2::TargetResourceContainer> framework_apk_cache_;
+
+ // A cache item for the resource containers (apks or frros), with all information needed to
+ // detect if it has changed since it was parsed:
+ // - (dev, inode) pair uniquely identifies a file on a particular device partition (see stat(2)).
+ // - (mtime, size) ensure the file data hasn't changed inside that file.
+ struct CachedContainer {
+ dev_t dev;
+ ino_t inode;
+ int64_t size;
+ struct timespec mtime;
+ std::unique_ptr<idmap2::TargetResourceContainer> apk;
+ };
+ std::unordered_map<std::string, CachedContainer> container_cache_;
+ std::mutex container_cache_mutex_;
int32_t frro_iter_id_ = 0;
std::optional<std::filesystem::directory_iterator> frro_iter_;
diff --git a/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl b/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl
index 3ad6d58e8253..8ebd454705f0 100644
--- a/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl
+++ b/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl
@@ -26,4 +26,6 @@ parcelable FabricatedOverlayInternalEntry {
@nullable @utf8InCpp String stringData;
@nullable ParcelFileDescriptor binaryData;
@nullable @utf8InCpp String configuration;
+ long binaryDataOffset;
+ long binaryDataSize;
} \ No newline at end of file
diff --git a/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h b/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h
index 7b38bd11d847..57af1b61c300 100644
--- a/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h
+++ b/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h
@@ -18,7 +18,7 @@
#define IDMAP2_INCLUDE_IDMAP2_BINARYSTREAMVISITOR_H_
#include <cstdint>
-#include <iostream>
+#include <ostream>
#include <string>
#include "idmap2/Idmap.h"
diff --git a/cmds/idmap2/include/idmap2/FabricatedOverlay.h b/cmds/idmap2/include/idmap2/FabricatedOverlay.h
index 9f57710edb0b..1e7d4c28f45c 100644
--- a/cmds/idmap2/include/idmap2/FabricatedOverlay.h
+++ b/cmds/idmap2/include/idmap2/FabricatedOverlay.h
@@ -19,9 +19,10 @@
#include <libidmap2/proto/fabricated_v1.pb.h>
-#include <iostream>
+#include <istream>
#include <map>
#include <memory>
+#include <ostream>
#include <string>
#include <unordered_map>
#include <vector>
@@ -48,6 +49,8 @@ struct FabricatedOverlay {
Builder& SetResourceValue(const std::string& resource_name,
std::optional<android::base::borrowed_fd>&& binary_value,
+ off64_t data_binary_offset,
+ size_t data_binary_size,
const std::string& configuration);
inline Builder& setFrroPath(std::string frro_path) {
@@ -64,6 +67,8 @@ struct FabricatedOverlay {
DataValue data_value;
std::string data_string_value;
std::optional<android::base::borrowed_fd> data_binary_value;
+ off64_t data_binary_offset;
+ size_t data_binary_size;
std::string configuration;
};
@@ -75,6 +80,12 @@ struct FabricatedOverlay {
std::vector<Entry> entries_;
};
+ struct BinaryData {
+ android::base::borrowed_fd file_descriptor;
+ off64_t offset;
+ size_t size;
+ };
+
Result<Unit> ToBinaryStream(std::ostream& stream) const;
static Result<FabricatedOverlay> FromBinaryStream(std::istream& stream);
@@ -91,13 +102,13 @@ struct FabricatedOverlay {
explicit FabricatedOverlay(pb::FabricatedOverlay&& overlay,
std::string&& string_pool_data_,
- std::vector<android::base::borrowed_fd> binary_files_,
+ std::vector<FabricatedOverlay::BinaryData> binary_files_,
off_t total_binary_bytes_,
std::optional<uint32_t> crc_from_disk = {});
pb::FabricatedOverlay overlay_pb_;
std::string string_pool_data_;
- std::vector<android::base::borrowed_fd> binary_files_;
+ std::vector<FabricatedOverlay::BinaryData> binary_files_;
uint32_t total_binary_bytes_;
std::optional<uint32_t> crc_from_disk_;
mutable std::optional<SerializedData> data_;
diff --git a/cmds/idmap2/include/idmap2/FileUtils.h b/cmds/idmap2/include/idmap2/FileUtils.h
index bc0bb47fc2b7..3e99981b4e0d 100644
--- a/cmds/idmap2/include/idmap2/FileUtils.h
+++ b/cmds/idmap2/include/idmap2/FileUtils.h
@@ -19,12 +19,12 @@
#include <sys/types.h>
-#include <random>
#include <string>
+#include <string_view>
namespace android::idmap2::utils {
-constexpr const char* kIdmapCacheDir = "/data/resource-cache";
+constexpr std::string_view kIdmapCacheDir = "/data/resource-cache";
constexpr const mode_t kIdmapFilePermissionMask = 0133; // u=rw,g=r,o=r
bool UidHasWriteAccessToPath(uid_t uid, const std::string& path);
diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h
index 03e714a3847e..e86f81485a41 100644
--- a/cmds/idmap2/include/idmap2/Idmap.h
+++ b/cmds/idmap2/include/idmap2/Idmap.h
@@ -71,9 +71,10 @@
#ifndef IDMAP2_INCLUDE_IDMAP2_IDMAP_H_
#define IDMAP2_INCLUDE_IDMAP2_IDMAP_H_
-#include <iostream>
+#include <istream>
#include <memory>
#include <string>
+#include <string_view>
#include <vector>
#include "android-base/macros.h"
@@ -272,8 +273,8 @@ class IdmapData {
class Idmap {
public:
- static std::string CanonicalIdmapPathFor(const std::string& absolute_dir,
- const std::string& absolute_apk_path);
+ static std::string CanonicalIdmapPathFor(std::string_view absolute_dir,
+ std::string_view absolute_apk_path);
static Result<std::unique_ptr<const Idmap>> FromBinaryStream(std::istream& stream);
diff --git a/cmds/idmap2/include/idmap2/LogInfo.h b/cmds/idmap2/include/idmap2/LogInfo.h
index a6237e6f6ba9..b57615270d50 100644
--- a/cmds/idmap2/include/idmap2/LogInfo.h
+++ b/cmds/idmap2/include/idmap2/LogInfo.h
@@ -61,7 +61,7 @@ class LogInfo {
#ifdef __ANDROID__
LOG(WARNING) << msg.GetString();
#else
- std::cerr << "W " << msg.GetString() << std::endl;
+ std::cerr << "W " << msg.GetString() << '\n';
#endif
lines_.push_back("W " + msg.GetString());
}
diff --git a/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h b/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h
index 4464201a1f2e..ed18d9cbf20f 100644
--- a/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h
+++ b/cmds/idmap2/include/idmap2/PrettyPrintVisitor.h
@@ -17,7 +17,7 @@
#ifndef IDMAP2_INCLUDE_IDMAP2_PRETTYPRINTVISITOR_H_
#define IDMAP2_INCLUDE_IDMAP2_PRETTYPRINTVISITOR_H_
-#include <iostream>
+#include <ostream>
#include <memory>
#include "androidfw/AssetManager2.h"
diff --git a/cmds/idmap2/include/idmap2/RawPrintVisitor.h b/cmds/idmap2/include/idmap2/RawPrintVisitor.h
index ebd0d1eb2fbc..849ba11aacff 100644
--- a/cmds/idmap2/include/idmap2/RawPrintVisitor.h
+++ b/cmds/idmap2/include/idmap2/RawPrintVisitor.h
@@ -17,7 +17,7 @@
#ifndef IDMAP2_INCLUDE_IDMAP2_RAWPRINTVISITOR_H_
#define IDMAP2_INCLUDE_IDMAP2_RAWPRINTVISITOR_H_
-#include <iostream>
+#include <ostream>
#include <memory>
#include <string>
diff --git a/cmds/idmap2/include/idmap2/ResourceUtils.h b/cmds/idmap2/include/idmap2/ResourceUtils.h
index c2b0abed442c..d4490ef47b25 100644
--- a/cmds/idmap2/include/idmap2/ResourceUtils.h
+++ b/cmds/idmap2/include/idmap2/ResourceUtils.h
@@ -43,6 +43,8 @@ struct TargetValue {
DataValue data_value;
std::string data_string_value;
std::optional<android::base::borrowed_fd> data_binary_value;
+ off64_t data_binary_offset;
+ size_t data_binary_size;
};
struct TargetValueWithConfig {
diff --git a/cmds/idmap2/include/idmap2/XmlParser.h b/cmds/idmap2/include/idmap2/XmlParser.h
index c968a5e6c04f..c93b06738fcb 100644
--- a/cmds/idmap2/include/idmap2/XmlParser.h
+++ b/cmds/idmap2/include/idmap2/XmlParser.h
@@ -17,8 +17,6 @@
#ifndef IDMAP2_INCLUDE_IDMAP2_XMLPARSER_H_
#define IDMAP2_INCLUDE_IDMAP2_XMLPARSER_H_
-#include <iostream>
-#include <map>
#include <memory>
#include <string>
diff --git a/cmds/idmap2/libidmap2/CommandLineOptions.cpp b/cmds/idmap2/libidmap2/CommandLineOptions.cpp
index 8129d99650f7..2da05b36b775 100644
--- a/cmds/idmap2/libidmap2/CommandLineOptions.cpp
+++ b/cmds/idmap2/libidmap2/CommandLineOptions.cpp
@@ -19,8 +19,9 @@
#include <algorithm>
#include <cassert>
#include <iomanip>
-#include <iostream>
+#include <iterator>
#include <memory>
+#include <ostream>
#include <set>
#include <sstream>
#include <string>
@@ -131,7 +132,7 @@ Result<Unit> CommandLineOptions::Parse(const std::vector<std::string>& argv) con
separator = true;
stream << opt << ": missing mandatory option";
}
- stream << std::endl;
+ stream << '\n';
Usage(stream);
return Error("%s", stream.str().c_str());
}
@@ -168,7 +169,7 @@ void CommandLineOptions::Usage(std::ostream& out) const {
out << " [" << opt.name << " arg [..]]";
}
}
- out << std::endl << std::endl;
+ out << "\n\n";
for (const Option& opt : options_) {
out << std::left << std::setw(maxLength);
if (opt.argument) {
@@ -181,7 +182,7 @@ void CommandLineOptions::Usage(std::ostream& out) const {
opt.count == Option::COUNT_OPTIONAL_ONCE_OR_MORE) {
out << " (can be provided multiple times)";
}
- out << std::endl;
+ out << '\n';
}
}
diff --git a/cmds/idmap2/libidmap2/FabricatedOverlay.cpp b/cmds/idmap2/libidmap2/FabricatedOverlay.cpp
index dd5be21cd164..47daf23c6381 100644
--- a/cmds/idmap2/libidmap2/FabricatedOverlay.cpp
+++ b/cmds/idmap2/libidmap2/FabricatedOverlay.cpp
@@ -55,7 +55,7 @@ void Write32(std::ostream& stream, uint32_t value) {
FabricatedOverlay::FabricatedOverlay(pb::FabricatedOverlay&& overlay,
std::string&& string_pool_data,
- std::vector<android::base::borrowed_fd> binary_files,
+ std::vector<FabricatedOverlay::BinaryData> binary_files,
off_t total_binary_bytes,
std::optional<uint32_t> crc_from_disk)
: overlay_pb_(std::forward<pb::FabricatedOverlay>(overlay)),
@@ -81,7 +81,7 @@ FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetResourceValue(
const std::string& resource_name, uint8_t data_type, uint32_t data_value,
const std::string& configuration) {
entries_.emplace_back(
- Entry{resource_name, data_type, data_value, "", std::nullopt, configuration});
+ Entry{resource_name, data_type, data_value, "", std::nullopt, 0, 0, configuration});
return *this;
}
@@ -89,14 +89,15 @@ FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetResourceValue(
const std::string& resource_name, uint8_t data_type, const std::string& data_string_value,
const std::string& configuration) {
entries_.emplace_back(
- Entry{resource_name, data_type, 0, data_string_value, std::nullopt, configuration});
+ Entry{resource_name, data_type, 0, data_string_value, std::nullopt, 0, 0, configuration});
return *this;
}
FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetResourceValue(
const std::string& resource_name, std::optional<android::base::borrowed_fd>&& binary_value,
- const std::string& configuration) {
- entries_.emplace_back(Entry{resource_name, 0, 0, "", binary_value, configuration});
+ off64_t data_binary_offset, size_t data_binary_size, const std::string& configuration) {
+ entries_.emplace_back(Entry{resource_name, 0, 0, "", binary_value,
+ data_binary_offset, data_binary_size, configuration});
return *this;
}
@@ -148,7 +149,8 @@ Result<FabricatedOverlay> FabricatedOverlay::Builder::Build() {
}
value->second = TargetValue{res_entry.data_type, res_entry.data_value,
- res_entry.data_string_value, res_entry.data_binary_value};
+ res_entry.data_string_value, res_entry.data_binary_value,
+ res_entry.data_binary_offset, res_entry.data_binary_size};
}
pb::FabricatedOverlay overlay_pb;
@@ -157,7 +159,7 @@ Result<FabricatedOverlay> FabricatedOverlay::Builder::Build() {
overlay_pb.set_target_package_name(target_package_name_);
overlay_pb.set_target_overlayable(target_overlayable_);
- std::vector<android::base::borrowed_fd> binary_files;
+ std::vector<FabricatedOverlay::BinaryData> binary_files;
size_t total_binary_bytes = 0;
// 16 for the number of bytes in the frro file before the binary data
const size_t FRRO_HEADER_SIZE = 16;
@@ -182,16 +184,15 @@ Result<FabricatedOverlay> FabricatedOverlay::Builder::Build() {
pb_value->set_data_value(ref.index());
} else if (value.second.data_binary_value.has_value()) {
pb_value->set_data_type(Res_value::TYPE_STRING);
- struct stat s;
- if (fstat(value.second.data_binary_value->get(), &s) == -1) {
- return Error("unable to get size of binary file: %d", errno);
- }
std::string uri
= StringPrintf("frro:/%s?offset=%d&size=%d", frro_path_.c_str(),
static_cast<int> (FRRO_HEADER_SIZE + total_binary_bytes),
- static_cast<int> (s.st_size));
- total_binary_bytes += s.st_size;
- binary_files.emplace_back(value.second.data_binary_value->get());
+ static_cast<int> (value.second.data_binary_size));
+ total_binary_bytes += value.second.data_binary_size;
+ binary_files.emplace_back(FabricatedOverlay::BinaryData{
+ value.second.data_binary_value->get(),
+ value.second.data_binary_offset,
+ value.second.data_binary_size});
auto ref = string_pool.MakeRef(std::move(uri));
pb_value->set_data_value(ref.index());
} else {
@@ -310,8 +311,9 @@ Result<Unit> FabricatedOverlay::ToBinaryStream(std::ostream& stream) const {
Write32(stream, (*data)->pb_crc);
Write32(stream, total_binary_bytes_);
std::string file_contents;
- for (const android::base::borrowed_fd fd : binary_files_) {
- if (!ReadFdToString(fd, &file_contents)) {
+ for (const FabricatedOverlay::BinaryData fd : binary_files_) {
+ file_contents.resize(fd.size);
+ if (!ReadFullyAtOffset(fd.file_descriptor, file_contents.data(), fd.size, fd.offset)) {
return Error("Failed to read binary file data.");
}
stream.write(file_contents.data(), file_contents.length());
diff --git a/cmds/idmap2/libidmap2/FileUtils.cpp b/cmds/idmap2/libidmap2/FileUtils.cpp
index 98a4ceabdb94..bc5654aad7b8 100644
--- a/cmds/idmap2/libidmap2/FileUtils.cpp
+++ b/cmds/idmap2/libidmap2/FileUtils.cpp
@@ -16,11 +16,13 @@
#include "idmap2/FileUtils.h"
+#include <random>
#include <string>
+#include <string_view>
#include "android-base/file.h"
#include "android-base/macros.h"
-#include "android-base/stringprintf.h"
+#include "android-base/strings.h"
#include "private/android_filesystem_config.h"
namespace android::idmap2::utils {
@@ -33,9 +35,9 @@ bool UidHasWriteAccessToPath(uid_t uid, const std::string& path) {
return false;
}
- const std::string cache_subdir = base::StringPrintf("%s/", kIdmapCacheDir);
- if (canonical_path == kIdmapCacheDir ||
- canonical_path.compare(0, cache_subdir.size(), cache_subdir) == 0) {
+ if (base::StartsWith(canonical_path, kIdmapCacheDir) &&
+ (canonical_path.size() == kIdmapCacheDir.size() ||
+ canonical_path[kIdmapCacheDir.size()] == '/')) {
// limit access to /data/resource-cache to root and system
return uid == AID_ROOT || uid == AID_SYSTEM;
}
@@ -47,17 +49,17 @@ bool UidHasWriteAccessToPath(uid_t uid ATTRIBUTE_UNUSED, const std::string& path
}
#endif
-std::string RandomStringForPath(const size_t length) {
- constexpr char kChars[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
- constexpr size_t kCharLastIndex = sizeof(kChars) - 1;
+std::string RandomStringForPath(size_t length) {
+ constexpr std::string_view kChars =
+ "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
std::string out_rand;
- out_rand.reserve(length);
+ out_rand.resize(length);
- std::random_device rd;
- std::uniform_int_distribution<int> dist(0, kCharLastIndex);
+ static thread_local std::random_device rd;
+ std::uniform_int_distribution<int> dist(0, kChars.size() - 1);
for (size_t i = 0; i < length; i++) {
- out_rand[i] = kChars[dist(rd) % (kCharLastIndex)];
+ out_rand[i] = kChars[dist(rd)];
}
return out_rand;
}
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index 7c0b937122c7..12d9dd9bd1ad 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -18,13 +18,14 @@
#include <algorithm>
#include <cassert>
-#include <iostream>
+#include <istream>
#include <iterator>
#include <limits>
#include <memory>
#include <string>
#include <utility>
+#include "android-base/format.h"
#include "android-base/macros.h"
#include "androidfw/AssetManager2.h"
#include "idmap2/ResourceMapping.h"
@@ -80,7 +81,7 @@ bool WARN_UNUSED ReadString(std::istream& stream, std::string* out) {
if (padding_size != 0 && !stream.seekg(padding_size, std::ios_base::cur)) {
return false;
}
- *out = buf;
+ *out = std::move(buf);
return true;
}
@@ -279,13 +280,13 @@ std::unique_ptr<const IdmapData> IdmapData::FromBinaryStream(std::istream& strea
return std::move(data);
}
-std::string Idmap::CanonicalIdmapPathFor(const std::string& absolute_dir,
- const std::string& absolute_apk_path) {
+std::string Idmap::CanonicalIdmapPathFor(std::string_view absolute_dir,
+ std::string_view absolute_apk_path) {
assert(absolute_dir.size() > 0 && absolute_dir[0] == "/");
assert(absolute_apk_path.size() > 0 && absolute_apk_path[0] == "/");
- std::string copy(++absolute_apk_path.cbegin(), absolute_apk_path.cend());
+ std::string copy(absolute_apk_path.begin() + 1, absolute_apk_path.end());
replace(copy.begin(), copy.end(), '/', '@');
- return absolute_dir + "/" + copy + "@idmap";
+ return fmt::format("{}/{}@idmap", absolute_dir, copy);
}
Result<std::unique_ptr<const Idmap>> Idmap::FromBinaryStream(std::istream& stream) {
@@ -332,7 +333,7 @@ Result<std::unique_ptr<const IdmapData>> IdmapData::FromResourceMapping(
values[cd] = value;
inline_value_count++;
}
- data->target_inline_entries_.push_back({mapping.first, values});
+ data->target_inline_entries_.push_back({mapping.first, std::move(values)});
}
}
diff --git a/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp b/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp
index a44fa756aa1c..eb9458268dad 100644
--- a/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp
+++ b/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp
@@ -34,21 +34,21 @@ void PrettyPrintVisitor::visit(const Idmap& idmap ATTRIBUTE_UNUSED) {
}
void PrettyPrintVisitor::visit(const IdmapHeader& header) {
- stream_ << "Paths:" << std::endl
- << TAB "target path : " << header.GetTargetPath() << std::endl
- << TAB "overlay path : " << header.GetOverlayPath() << std::endl;
+ stream_ << "Paths:" << '\n'
+ << TAB "target path : " << header.GetTargetPath() << '\n'
+ << TAB "overlay path : " << header.GetOverlayPath() << '\n';
if (!header.GetOverlayName().empty()) {
- stream_ << "Overlay name: " << header.GetOverlayName() << std::endl;
+ stream_ << "Overlay name: " << header.GetOverlayName() << '\n';
}
const std::string& debug = header.GetDebugInfo();
if (!debug.empty()) {
std::istringstream debug_stream(debug);
std::string line;
- stream_ << "Debug info:" << std::endl;
+ stream_ << "Debug info:" << '\n';
while (std::getline(debug_stream, line)) {
- stream_ << TAB << line << std::endl;
+ stream_ << TAB << line << '\n';
}
}
@@ -59,7 +59,7 @@ void PrettyPrintVisitor::visit(const IdmapHeader& header) {
overlay_ = std::move(*overlay);
}
- stream_ << "Mapping:" << std::endl;
+ stream_ << "Mapping:" << '\n';
}
void PrettyPrintVisitor::visit(const IdmapData::Header& header ATTRIBUTE_UNUSED) {
@@ -90,7 +90,7 @@ void PrettyPrintVisitor::visit(const IdmapData& data) {
<< base::StringPrintf("0x%08x -> 0x%08x (%s -> %s)", target_entry.target_id,
target_entry.overlay_id, target_name.c_str(),
overlay_name.c_str())
- << std::endl;
+ << '\n';
}
for (auto& target_entry : data.GetTargetInlineEntries()) {
@@ -114,7 +114,7 @@ void PrettyPrintVisitor::visit(const IdmapData& data) {
}
}
- stream_ << " (" << target_name << ")" << std::endl;
+ stream_ << " (" << target_name << ")" << '\n';
}
}
diff --git a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
index 3531cd7c2f36..9d04a7f87400 100644
--- a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
+++ b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
@@ -96,7 +96,7 @@ void RawPrintVisitor::visit(const IdmapData& data ATTRIBUTE_UNUSED) {
auto value = target_entry_value.second;
print(target_entry_value.first.to_string(), false, "config: %s",
- target_entry_value.first.toString().string());
+ target_entry_value.first.toString().c_str());
print(value.data_type, "type: %s",
utils::DataTypeToString(value.data_type).data());
@@ -161,7 +161,7 @@ void RawPrintVisitor::print(uint8_t value, const char* fmt, ...) {
va_end(ap);
stream_ << base::StringPrintf("%08zx: %02x", offset_, value) << " " << comment
- << std::endl;
+ << '\n';
offset_ += sizeof(uint8_t);
}
@@ -173,7 +173,7 @@ void RawPrintVisitor::print(uint16_t value, const char* fmt, ...) {
base::StringAppendV(&comment, fmt, ap);
va_end(ap);
- stream_ << base::StringPrintf("%08zx: %04x", offset_, value) << " " << comment << std::endl;
+ stream_ << base::StringPrintf("%08zx: %04x", offset_, value) << " " << comment << '\n';
offset_ += sizeof(uint16_t);
}
@@ -185,7 +185,7 @@ void RawPrintVisitor::print(uint32_t value, const char* fmt, ...) {
base::StringAppendV(&comment, fmt, ap);
va_end(ap);
- stream_ << base::StringPrintf("%08zx: %08x", offset_, value) << " " << comment << std::endl;
+ stream_ << base::StringPrintf("%08zx: %08x", offset_, value) << " " << comment << '\n';
offset_ += sizeof(uint32_t);
}
@@ -198,7 +198,7 @@ void RawPrintVisitor::print(const std::string& value, bool print_value, const ch
va_end(ap);
stream_ << base::StringPrintf("%08zx: %08x", offset_, (uint32_t)value.size()) << " " << comment
- << " size" << std::endl;
+ << " size" << '\n';
offset_ += sizeof(uint32_t);
stream_ << base::StringPrintf("%08zx: ", offset_) << "........ " << comment;
@@ -207,7 +207,7 @@ void RawPrintVisitor::print(const std::string& value, bool print_value, const ch
if (print_value) {
stream_ << ": " << value;
}
- stream_ << std::endl;
+ stream_ << '\n';
}
void RawPrintVisitor::align() {
diff --git a/cmds/idmap2/libidmap2/XmlParser.cpp b/cmds/idmap2/libidmap2/XmlParser.cpp
index 70822c890288..780715561006 100644
--- a/cmds/idmap2/libidmap2/XmlParser.cpp
+++ b/cmds/idmap2/libidmap2/XmlParser.cpp
@@ -16,8 +16,6 @@
#include "idmap2/XmlParser.h"
-#include <iostream>
-#include <map>
#include <memory>
#include <string>
#include <utility>
@@ -111,7 +109,7 @@ Result<std::string> GetStringValue(const ResXMLParser& parser, const Res_value&
switch (value.dataType) {
case Res_value::TYPE_STRING: {
if (auto str = parser.getStrings().string8ObjectAt(value.data); str.ok()) {
- return std::string(str->string());
+ return std::string(str->c_str());
}
break;
}
@@ -132,11 +130,14 @@ Result<Res_value> XmlParser::Node::GetAttributeValue(ResourceId attr,
}
Result<Res_value> XmlParser::Node::GetAttributeValue(const std::string& name) const {
+ String16 name16;
return FindAttribute(parser_, name, [&](size_t index) -> bool {
- size_t len;
- const String16 key16(parser_.getAttributeName(index, &len));
- std::string key = String8(key16).c_str();
- return key == name;
+ if (name16.empty()) {
+ name16 = String16(name.c_str(), name.size());
+ }
+ size_t key_len;
+ const auto key16 = parser_.getAttributeName(index, &key_len);
+ return key16 && name16.size() == key_len && name16 == key16;
});
}
diff --git a/cmds/idmap2/self_targeting/SelfTargeting.cpp b/cmds/idmap2/self_targeting/SelfTargeting.cpp
index a8aa03309b16..c7f5cf3632c5 100644
--- a/cmds/idmap2/self_targeting/SelfTargeting.cpp
+++ b/cmds/idmap2/self_targeting/SelfTargeting.cpp
@@ -52,6 +52,7 @@ CreateFrroFile(std::string& out_err_result, const std::string& packageName,
const auto dataType = entry_params.data_type;
if (entry_params.data_binary_value.has_value()) {
builder.SetResourceValue(entry_params.resource_name, *entry_params.data_binary_value,
+ entry_params.binary_data_offset, entry_params.binary_data_size,
entry_params.configuration);
} else if (dataType >= Res_value::TYPE_FIRST_INT && dataType <= Res_value::TYPE_LAST_INT) {
builder.SetResourceValue(entry_params.resource_name, dataType,
diff --git a/cmds/idmap2/tests/FabricatedOverlayTests.cpp b/cmds/idmap2/tests/FabricatedOverlayTests.cpp
index e13a0eb5d488..b460bb33f559 100644
--- a/cmds/idmap2/tests/FabricatedOverlayTests.cpp
+++ b/cmds/idmap2/tests/FabricatedOverlayTests.cpp
@@ -59,7 +59,7 @@ TEST(FabricatedOverlayTests, SetResourceValue) {
Res_value::TYPE_STRING,
"foobar",
"en-rUS-normal-xxhdpi-v21")
- .SetResourceValue("com.example.target:drawable/dr1", fd, "port-xxhdpi-v7")
+ .SetResourceValue("com.example.target:drawable/dr1", fd, 0, 8341, "port-xxhdpi-v7")
.setFrroPath("/foo/bar/biz.frro")
.Build();
ASSERT_TRUE(overlay);
diff --git a/cmds/idmap2/tests/FileUtilsTests.cpp b/cmds/idmap2/tests/FileUtilsTests.cpp
index 5750ca1f49c5..b160e8e08618 100644
--- a/cmds/idmap2/tests/FileUtilsTests.cpp
+++ b/cmds/idmap2/tests/FileUtilsTests.cpp
@@ -27,8 +27,9 @@ namespace android::idmap2::utils {
#ifdef __ANDROID__
TEST(FileUtilsTests, UidHasWriteAccessToPath) {
constexpr const char* tmp_path = "/data/local/tmp/test@idmap";
- const std::string cache_path(base::StringPrintf("%s/test@idmap", kIdmapCacheDir));
- const std::string sneaky_cache_path(base::StringPrintf("/data/../%s/test@idmap", kIdmapCacheDir));
+ const std::string cache_path(base::StringPrintf("%s/test@idmap", kIdmapCacheDir.data()));
+ const std::string sneaky_cache_path(
+ base::StringPrintf("/data/../%s/test@idmap", kIdmapCacheDir.data()));
ASSERT_TRUE(UidHasWriteAccessToPath(AID_ROOT, tmp_path));
ASSERT_TRUE(UidHasWriteAccessToPath(AID_ROOT, cache_path));
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index b473f26b2230..a3448fda60d9 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -269,7 +269,7 @@ TEST(IdmapTests, FabricatedOverlay) {
.SetResourceValue("integer/int1", Res_value::TYPE_INT_DEC, 2U, "land-xxhdpi-v7")
.SetResourceValue("string/str1", Res_value::TYPE_REFERENCE, 0x7f010000, "land")
.SetResourceValue("string/str2", Res_value::TYPE_STRING, "foobar", "xxhdpi-v7")
- .SetResourceValue("drawable/dr1", fd, "port-xxhdpi-v7")
+ .SetResourceValue("drawable/dr1", fd, 0, 8341, "port-xxhdpi-v7")
.setFrroPath("/foo/bar/biz.frro")
.Build();
@@ -613,19 +613,19 @@ class TestVisitor : public Visitor {
}
void visit(const Idmap& idmap ATTRIBUTE_UNUSED) override {
- stream_ << "TestVisitor::visit(Idmap)" << std::endl;
+ stream_ << "TestVisitor::visit(Idmap)" << '\n';
}
void visit(const IdmapHeader& idmap ATTRIBUTE_UNUSED) override {
- stream_ << "TestVisitor::visit(IdmapHeader)" << std::endl;
+ stream_ << "TestVisitor::visit(IdmapHeader)" << '\n';
}
void visit(const IdmapData& idmap ATTRIBUTE_UNUSED) override {
- stream_ << "TestVisitor::visit(IdmapData)" << std::endl;
+ stream_ << "TestVisitor::visit(IdmapData)" << '\n';
}
void visit(const IdmapData::Header& idmap ATTRIBUTE_UNUSED) override {
- stream_ << "TestVisitor::visit(IdmapData::Header)" << std::endl;
+ stream_ << "TestVisitor::visit(IdmapData::Header)" << '\n';
}
private:
diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp
index 380e462a3aba..40f98c2f351b 100644
--- a/cmds/idmap2/tests/ResourceMappingTests.cpp
+++ b/cmds/idmap2/tests/ResourceMappingTests.cpp
@@ -212,7 +212,7 @@ TEST(ResourceMappingTests, FabricatedOverlay) {
.SetResourceValue("integer/int1", Res_value::TYPE_INT_DEC, 2U, "")
.SetResourceValue("string/str1", Res_value::TYPE_REFERENCE, 0x7f010000, "")
.SetResourceValue("string/str2", Res_value::TYPE_STRING, "foobar", "")
- .SetResourceValue("drawable/dr1", fd, "")
+ .SetResourceValue("drawable/dr1", fd, 0, 8341, "")
.setFrroPath("/foo/bar/biz.frro")
.Build();
diff --git a/cmds/incident/main.cpp b/cmds/incident/main.cpp
index 6e0bd0629274..0d9f4e92662b 100644
--- a/cmds/incident/main.cpp
+++ b/cmds/incident/main.cpp
@@ -83,8 +83,8 @@ StatusListener::onReportSectionStatus(int32_t section, int32_t status)
Status
StatusListener::onReportServiceStatus(const String16& service, int32_t status)
{
- fprintf(stderr, "service '%s' status %d\n", String8(service).string(), status);
- ALOGD("service '%s' status %d\n", String8(service).string(), status);
+ fprintf(stderr, "service '%s' status %d\n", String8(service).c_str(), status);
+ ALOGD("service '%s' status %d\n", String8(service).c_str(), status);
return Status::ok();
}
@@ -384,7 +384,7 @@ main(int argc, char** argv)
status = service->reportIncidentToStream(args, listener, std::move(writeEnd));
if (!status.isOk()) {
- fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
+ fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().c_str());
return 1;
}
@@ -396,14 +396,14 @@ main(int argc, char** argv)
sp<StatusListener> listener(new StatusListener());
status = service->reportIncidentToDumpstate(std::move(writeEnd), listener);
if (!status.isOk()) {
- fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
+ fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().c_str());
return 1;
}
return listener->getExitCodeOrElse(stream_output(fds[0], STDOUT_FILENO));
} else {
status = service->reportIncident(args);
if (!status.isOk()) {
- fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().string());
+ fprintf(stderr, "reportIncident returned \"%s\"\n", status.toString8().c_str());
return 1;
} else {
return 0;
diff --git a/cmds/incident_helper/src/TextParserBase.cpp b/cmds/incident_helper/src/TextParserBase.cpp
index e9bc70f37026..e625afa626ec 100644
--- a/cmds/incident_helper/src/TextParserBase.cpp
+++ b/cmds/incident_helper/src/TextParserBase.cpp
@@ -27,11 +27,11 @@ 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());
+ fprintf(stderr, "[%s]Failed to read data from incidentd\n", this->name.c_str());
return -1;
}
if (!WriteStringToFd(content, out)) {
- fprintf(stderr, "[%s]Failed to write data to incidentd\n", this->name.string());
+ fprintf(stderr, "[%s]Failed to write data to incidentd\n", this->name.c_str());
return -1;
}
return NO_ERROR;
@@ -42,13 +42,13 @@ 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());
+ fprintf(stderr, "[%s]Failed to read data from incidentd\n", this->name.c_str());
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());
+ fprintf(stderr, "[%s]Failed to write data to incidentd\n", this->name.c_str());
return -1;
}
return NO_ERROR;
diff --git a/cmds/incident_helper/src/main.cpp b/cmds/incident_helper/src/main.cpp
index ff5fd86cf11e..cc03d4a65f17 100644
--- a/cmds/incident_helper/src/main.cpp
+++ b/cmds/incident_helper/src/main.cpp
@@ -101,7 +101,7 @@ int main(int argc, char** argv) {
fprintf(stderr, "Pasring section %d...\n", sectionID);
TextParserBase* parser = selectParser(sectionID);
if (parser != nullptr) {
- fprintf(stderr, "Running parser: %s\n", parser->name.string());
+ fprintf(stderr, "Running parser: %s\n", parser->name.c_str());
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));
diff --git a/cmds/incident_helper/src/parsers/BatteryTypeParser.cpp b/cmds/incident_helper/src/parsers/BatteryTypeParser.cpp
index ced6cf807e0d..2a032fbf3aa6 100644
--- a/cmds/incident_helper/src/parsers/BatteryTypeParser.cpp
+++ b/cmds/incident_helper/src/parsers/BatteryTypeParser.cpp
@@ -52,9 +52,9 @@ BatteryTypeParser::Parse(const int in, const int out) const
}
if (!proto.flush(out)) {
- fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+ fprintf(stderr, "[%s]Error writing proto back\n", this->name.c_str());
return -1;
}
- fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+ fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.c_str(), proto.size());
return NO_ERROR;
}
diff --git a/cmds/incident_helper/src/parsers/CpuFreqParser.cpp b/cmds/incident_helper/src/parsers/CpuFreqParser.cpp
index 43a12f603ba3..c9bf4c528109 100644
--- a/cmds/incident_helper/src/parsers/CpuFreqParser.cpp
+++ b/cmds/incident_helper/src/parsers/CpuFreqParser.cpp
@@ -82,9 +82,9 @@ CpuFreqParser::Parse(const int in, const int out) const
}
if (!proto.flush(out)) {
- fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+ fprintf(stderr, "[%s]Error writing proto back\n", this->name.c_str());
return -1;
}
- fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+ fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.c_str(), proto.size());
return NO_ERROR;
}
diff --git a/cmds/incident_helper/src/parsers/CpuInfoParser.cpp b/cmds/incident_helper/src/parsers/CpuInfoParser.cpp
index 5d525e6c7f3e..77751a2fdfc0 100644
--- a/cmds/incident_helper/src/parsers/CpuInfoParser.cpp
+++ b/cmds/incident_helper/src/parsers/CpuInfoParser.cpp
@@ -130,11 +130,11 @@ CpuInfoParser::Parse(const int in, const int out) const
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());
+ fprintf(stderr, "[%s]Line %d has %d missing fields\n%s\n", this->name.c_str(), 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());
+ fprintf(stderr, "[%s]Line %d has %d extra fields\n%s\n", this->name.c_str(), nline, diff, line.c_str());
printRecord(record);
continue;
}
@@ -143,7 +143,7 @@ CpuInfoParser::Parse(const int in, const int out) const
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());
+ this->name.c_str(), nline, header[i].c_str(), record[i].c_str());
}
}
proto.end(token);
@@ -155,9 +155,9 @@ CpuInfoParser::Parse(const int in, const int out) const
}
if (!proto.flush(out)) {
- fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+ fprintf(stderr, "[%s]Error writing proto back\n", this->name.c_str());
return -1;
}
- fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+ fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.c_str(), proto.size());
return NO_ERROR;
}
diff --git a/cmds/incident_helper/src/parsers/EventLogTagsParser.cpp b/cmds/incident_helper/src/parsers/EventLogTagsParser.cpp
index 4fd6b068cf1e..0474a5055bf2 100644
--- a/cmds/incident_helper/src/parsers/EventLogTagsParser.cpp
+++ b/cmds/incident_helper/src/parsers/EventLogTagsParser.cpp
@@ -76,9 +76,9 @@ EventLogTagsParser::Parse(const int in, const int out) const
}
if (!proto.flush(out)) {
- fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+ fprintf(stderr, "[%s]Error writing proto back\n", this->name.c_str());
return -1;
}
- fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+ fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.c_str(), proto.size());
return NO_ERROR;
}
diff --git a/cmds/incident_helper/src/parsers/KernelWakesParser.cpp b/cmds/incident_helper/src/parsers/KernelWakesParser.cpp
index 85beaf06eeb8..d16c23cce29b 100644
--- a/cmds/incident_helper/src/parsers/KernelWakesParser.cpp
+++ b/cmds/incident_helper/src/parsers/KernelWakesParser.cpp
@@ -51,11 +51,11 @@ KernelWakesParser::Parse(const int in, const int out) const
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());
+ fprintf(stderr, "[%s]Line %d has missing fields\n%s\n", this->name.c_str(), 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());
+ fprintf(stderr, "[%s]Line %d has extra fields\n%s\n", this->name.c_str(), nline, line.c_str());
continue;
}
@@ -63,7 +63,7 @@ KernelWakesParser::Parse(const int in, const int out) const
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());
+ this->name.c_str(), nline, header[i].c_str(), record[i].c_str());
}
}
proto.end(token);
@@ -75,9 +75,9 @@ KernelWakesParser::Parse(const int in, const int out) const
}
if (!proto.flush(out)) {
- fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+ fprintf(stderr, "[%s]Error writing proto back\n", this->name.c_str());
return -1;
}
- fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+ fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.c_str(), proto.size());
return NO_ERROR;
}
diff --git a/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp b/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp
index 2a89c920c119..36710dfea8f1 100644
--- a/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp
+++ b/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp
@@ -114,10 +114,10 @@ PageTypeInfoParser::Parse(const int in, const int out) const
}
if (!proto.flush(out)) {
- fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+ fprintf(stderr, "[%s]Error writing proto back\n", this->name.c_str());
return -1;
}
- fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+ fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.c_str(), proto.size());
return NO_ERROR;
}
diff --git a/cmds/incident_helper/src/parsers/ProcrankParser.cpp b/cmds/incident_helper/src/parsers/ProcrankParser.cpp
index 4763b482e368..997d2e50a14b 100644
--- a/cmds/incident_helper/src/parsers/ProcrankParser.cpp
+++ b/cmds/incident_helper/src/parsers/ProcrankParser.cpp
@@ -60,7 +60,7 @@ ProcrankParser::Parse(const int in, const int out) const
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,
+ fprintf(stderr, "[%s]Line %d has missing fields\n%s\n", this->name.c_str(), nline,
line.c_str());
}
continue;
@@ -70,7 +70,7 @@ ProcrankParser::Parse(const int in, const int out) const
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());
+ this->name.c_str(), nline, header[i].c_str(), record[i].c_str());
}
}
proto.end(token);
@@ -104,9 +104,9 @@ ProcrankParser::Parse(const int in, const int out) const
}
if (!proto.flush(out)) {
- fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+ fprintf(stderr, "[%s]Error writing proto back\n", this->name.c_str());
return -1;
}
- fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+ fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.c_str(), proto.size());
return NO_ERROR;
}
diff --git a/cmds/incident_helper/src/parsers/PsParser.cpp b/cmds/incident_helper/src/parsers/PsParser.cpp
index d3cb4be59f66..55aa555794c0 100644
--- a/cmds/incident_helper/src/parsers/PsParser.cpp
+++ b/cmds/incident_helper/src/parsers/PsParser.cpp
@@ -61,12 +61,12 @@ status_t PsParser::Parse(const int in, const int out) const {
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());
+ fprintf(stderr, "[%s]Line %d has %d missing fields\n%s\n", this->name.c_str(), 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());
+ fprintf(stderr, "[%s]Line %d has %d extra fields\n%s\n", this->name.c_str(), nline, diff, line.c_str());
printRecord(record);
continue;
}
@@ -75,7 +75,7 @@ status_t PsParser::Parse(const int in, const int out) const {
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());
+ this->name.c_str(), nline, header[i].c_str(), record[i].c_str());
}
}
proto.end(token);
@@ -87,9 +87,9 @@ status_t PsParser::Parse(const int in, const int out) const {
}
if (!proto.flush(out)) {
- fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+ fprintf(stderr, "[%s]Error writing proto back\n", this->name.c_str());
return -1;
}
- fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+ fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.c_str(), proto.size());
return NO_ERROR;
}
diff --git a/cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp b/cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp
index eba536bd9e9c..86c34bc25bd8 100644
--- a/cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp
+++ b/cmds/incident_helper/src/parsers/SystemPropertiesParser.cpp
@@ -219,9 +219,9 @@ SystemPropertiesParser::Parse(const int in, const int out) const
}
if (!proto.flush(out)) {
- fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+ fprintf(stderr, "[%s]Error writing proto back\n", this->name.c_str());
return -1;
}
- fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+ fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.c_str(), proto.size());
return NO_ERROR;
}
diff --git a/cmds/incidentd/Android.bp b/cmds/incidentd/Android.bp
index b0b23f569664..bd30404848a3 100644
--- a/cmds/incidentd/Android.bp
+++ b/cmds/incidentd/Android.bp
@@ -82,17 +82,11 @@ cc_binary {
},
},
-
init_rc: ["incidentd.rc"],
}
-// ==============
-// incidentd_test
-// ==============
-
-cc_test {
- name: "incidentd_test",
- test_suites: ["device-tests"],
+cc_defaults {
+ name: "incidentd_test_defaults",
cflags: [
"-Werror",
@@ -110,8 +104,6 @@ cc_test {
generated_headers: ["framework-cppstream-protos"],
srcs: [
- "tests/**/*.cpp",
- "tests/**/*.proto",
"src/FdBuffer.cpp",
"src/Privacy.cpp",
"src/PrivacyFilter.cpp",
@@ -125,13 +117,11 @@ cc_test {
"src/**/*.proto",
],
- data: ["testdata/**/*"],
-
static_libs: [
- "libgmock",
"libincidentcompanion",
"libplatformprotos-test",
],
+
shared_libs: [
"libbase",
"libbinder",
@@ -144,6 +134,30 @@ cc_test {
"libservices",
"libutils",
],
+}
+
+// ==============
+// incidentd_test
+// ==============
+cc_test {
+ name: "incidentd_test",
+
+ defaults: [
+ "incidentd_test_defaults",
+ ],
+
+ test_suites: ["device-tests"],
+
+ srcs: [
+ "tests/**/*.cpp",
+ "tests/**/*.proto",
+ ],
+
+ data: ["testdata/**/*"],
+
+ static_libs: [
+ "libgmock",
+ ],
target: {
android: {
@@ -160,3 +174,27 @@ genrule {
out: ["section_list.cpp"],
cmd: "$(location incident-section-gen) incidentd > $(out)",
}
+
+cc_fuzz {
+ name: "incidentd_service_fuzzer",
+ defaults: [
+ "service_fuzzer_defaults",
+ "fuzzer_disable_leaks",
+ "incidentd_test_defaults",
+ ],
+
+ fuzz_config: {
+ cc: [
+ "yaochen@google.com",
+ "yanmin@google.com",
+ ],
+ triage_assignee: "waghpawan@google.com",
+ },
+
+ srcs: [
+ "fuzzers/IncidentServiceFuzzer.cpp",
+ "src/IncidentService.cpp",
+ "src/Broadcaster.cpp",
+ ":incidentd_section_list",
+ ],
+}
diff --git a/cmds/incidentd/fuzzers/IncidentServiceFuzzer.cpp b/cmds/incidentd/fuzzers/IncidentServiceFuzzer.cpp
new file mode 100644
index 000000000000..14c969b30ee6
--- /dev/null
+++ b/cmds/incidentd/fuzzers/IncidentServiceFuzzer.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2023 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 <fuzzbinder/libbinder_driver.h>
+#include <utils/Looper.h>
+
+#include "IncidentService.h"
+
+using ::android::fuzzService;
+using ::android::os::incidentd::IncidentService;
+using ::android::Looper;
+using ::android::sp;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ sp<Looper> looper(Looper::prepare(0));
+ sp<IncidentService> service = sp<IncidentService>::make(looper);
+ fuzzService(service, FuzzedDataProvider(data, size));
+ return 0;
+}
diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp
index 5af02f405ed9..5ebf3e2c3047 100644
--- a/cmds/incidentd/src/IncidentService.cpp
+++ b/cmds/incidentd/src/IncidentService.cpp
@@ -407,8 +407,8 @@ Status IncidentService::systemRunning() {
Status IncidentService::getIncidentReportList(const String16& pkg16, const String16& cls16,
vector<String16>* result) {
status_t err;
- const string pkg(String8(pkg16).string());
- const string cls(String8(cls16).string());
+ const string pkg(String8(pkg16).c_str());
+ const string cls(String8(cls16).c_str());
// List the reports
vector<sp<ReportFile>> all;
@@ -441,9 +441,9 @@ Status IncidentService::getIncidentReport(const String16& pkg16, const String16&
const String16& id16, IncidentManager::IncidentReport* result) {
status_t err;
- const string pkg(String8(pkg16).string());
- const string cls(String8(cls16).string());
- const string id(String8(id16).string());
+ const string pkg(String8(pkg16).c_str());
+ const string cls(String8(cls16).c_str());
+ const string id(String8(id16).c_str());
IncidentReportArgs args;
sp<ReportFile> file = mWorkDirectory->getReport(pkg, cls, id, &args);
@@ -470,9 +470,9 @@ Status IncidentService::getIncidentReport(const String16& pkg16, const String16&
Status IncidentService::deleteIncidentReports(const String16& pkg16, const String16& cls16,
const String16& id16) {
- const string pkg(String8(pkg16).string());
- const string cls(String8(cls16).string());
- const string id(String8(id16).string());
+ const string pkg(String8(pkg16).c_str());
+ const string cls(String8(cls16).c_str());
+ const string id(String8(id16).c_str());
sp<ReportFile> file = mWorkDirectory->getReport(pkg, cls, id, nullptr);
if (file != nullptr) {
@@ -484,7 +484,7 @@ Status IncidentService::deleteIncidentReports(const String16& pkg16, const Strin
}
Status IncidentService::deleteAllIncidentReports(const String16& pkg16) {
- const string pkg(String8(pkg16).string());
+ const string pkg(String8(pkg16).c_str());
mWorkDirectory->commitAll(pkg);
mBroadcaster->clearPackageBroadcasts(pkg);
@@ -502,9 +502,13 @@ status_t IncidentService::onTransact(uint32_t code, const Parcel& data, Parcel*
switch (code) {
case SHELL_COMMAND_TRANSACTION: {
- int in = data.readFileDescriptor();
- int out = data.readFileDescriptor();
- int err = data.readFileDescriptor();
+ unique_fd in, out, err;
+ if (status_t status = data.readUniqueFileDescriptor(&in); status != OK) return status;
+
+ if (status_t status = data.readUniqueFileDescriptor(&out); status != OK) return status;
+
+ if (status_t status = data.readUniqueFileDescriptor(&err); status != OK) return status;
+
int argc = data.readInt32();
Vector<String8> args;
for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
@@ -513,16 +517,19 @@ status_t IncidentService::onTransact(uint32_t code, const Parcel& data, Parcel*
sp<IShellCallback> shellCallback = IShellCallback::asInterface(data.readStrongBinder());
sp<IResultReceiver> resultReceiver =
IResultReceiver::asInterface(data.readStrongBinder());
+ if (resultReceiver == nullptr) {
+ return BAD_VALUE;
+ }
- FILE* fin = fdopen(in, "r");
- FILE* fout = fdopen(out, "w");
- FILE* ferr = fdopen(err, "w");
+ FILE* fin = fdopen(in.release(), "r");
+ FILE* fout = fdopen(out.release(), "w");
+ FILE* ferr = fdopen(err.release(), "w");
if (fin == NULL || fout == NULL || ferr == NULL) {
resultReceiver->send(NO_MEMORY);
} else {
- err = command(fin, fout, ferr, args);
- resultReceiver->send(err);
+ status_t result = command(fin, fout, ferr, args);
+ resultReceiver->send(result);
}
if (fin != NULL) {
@@ -533,7 +540,7 @@ status_t IncidentService::onTransact(uint32_t code, const Parcel& data, Parcel*
fflush(fout);
fclose(fout);
}
- if (fout != NULL) {
+ if (ferr != NULL) {
fflush(ferr);
fclose(ferr);
}
@@ -560,12 +567,12 @@ status_t IncidentService::command(FILE* in, FILE* out, FILE* err, Vector<String8
fprintf(out, "Not enough arguments for section\n");
return NO_ERROR;
}
- int id = atoi(args[1]);
+ int id = atoi(args[1].c_str());
int idx = 0;
while (SECTION_LIST[idx] != NULL) {
const Section* section = SECTION_LIST[idx];
if (section->id == id) {
- fprintf(out, "Section[%d] %s\n", id, section->name.string());
+ fprintf(out, "Section[%d] %s\n", id, section->name.c_str());
break;
}
idx++;
@@ -589,7 +596,7 @@ status_t IncidentService::cmd_help(FILE* out) {
static void printPrivacy(const Privacy* p, FILE* out, String8 indent) {
if (p == NULL) return;
- fprintf(out, "%sid:%d, type:%d, dest:%d\n", indent.string(), p->field_id, p->type, p->policy);
+ fprintf(out, "%sid:%d, type:%d, dest:%d\n", indent.c_str(), p->field_id, p->type, p->policy);
if (p->children == NULL) return;
for (int i = 0; p->children[i] != NULL; i++) { // NULL-terminated.
printPrivacy(p->children[i], out, indent + " ");
@@ -602,7 +609,7 @@ status_t IncidentService::cmd_privacy(FILE* in, FILE* out, FILE* err, Vector<Str
const int argCount = args.size();
if (argCount >= 3) {
String8 opt = args[1];
- int sectionId = atoi(args[2].string());
+ int sectionId = atoi(args[2].c_str());
const Privacy* p = get_privacy_of_section(sectionId);
if (p == NULL) {
diff --git a/cmds/incidentd/src/Reporter.cpp b/cmds/incidentd/src/Reporter.cpp
index 86a78f095f52..c9cf7275a821 100644
--- a/cmds/incidentd/src/Reporter.cpp
+++ b/cmds/incidentd/src/Reporter.cpp
@@ -711,7 +711,7 @@ status_t Reporter::execute_section(const Section* section, IncidentMetadata* met
return NO_ERROR;
}
- ALOGD("Start incident report section %d '%s'", sectionId, section->name.string());
+ ALOGD("Start incident report section %d '%s'", sectionId, section->name.c_str());
IncidentMetadata::SectionStats* sectionMetadata = metadata->add_sections();
// Notify listener of starting
@@ -747,7 +747,7 @@ status_t Reporter::execute_section(const Section* section, IncidentMetadata* met
sectionId, IIncidentReportStatusListener::STATUS_FINISHED);
});
- ALOGD("Finish incident report section %d '%s'", sectionId, section->name.string());
+ ALOGD("Finish incident report section %d '%s'", sectionId, section->name.c_str());
return NO_ERROR;
}
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 581367a75804..c2aa26948146 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -60,7 +60,7 @@ const char INCIDENT_HELPER[] = "/system/bin/incident_helper";
const char* GZIP[] = {"/system/bin/gzip", NULL};
static pid_t fork_execute_incident_helper(const int id, Fpipe* p2cPipe, Fpipe* c2pPipe) {
- const char* ihArgs[]{INCIDENT_HELPER, "-s", String8::format("%d", id).string(), NULL};
+ const char* ihArgs[]{INCIDENT_HELPER, "-s", String8::format("%d", id).c_str(), NULL};
return fork_execute_cmd(const_cast<char**>(ihArgs), p2cPipe, c2pPipe);
}
@@ -100,7 +100,7 @@ status_t FileSection::Execute(ReportWriter* writer) const {
// add O_CLOEXEC to make sure it is closed when exec incident helper
unique_fd fd(open(mFilename, O_RDONLY | O_CLOEXEC));
if (fd.get() == -1) {
- ALOGW("[%s] failed to open file", this->name.string());
+ ALOGW("[%s] failed to open file", this->name.c_str());
// There may be some devices/architectures that won't have the file.
// Just return here without an error.
return NO_ERROR;
@@ -110,13 +110,13 @@ status_t FileSection::Execute(ReportWriter* writer) const {
Fpipe c2pPipe;
// initiate pipes to pass data to/from incident_helper
if (!p2cPipe.init() || !c2pPipe.init()) {
- ALOGW("[%s] failed to setup pipes", this->name.string());
+ ALOGW("[%s] failed to setup pipes", this->name.c_str());
return -errno;
}
pid_t pid = fork_execute_incident_helper(this->id, &p2cPipe, &c2pPipe);
if (pid == -1) {
- ALOGW("[%s] failed to fork", this->name.string());
+ ALOGW("[%s] failed to fork", this->name.c_str());
return -errno;
}
@@ -128,14 +128,14 @@ status_t FileSection::Execute(ReportWriter* writer) const {
writer->setSectionStats(buffer);
if (readStatus != NO_ERROR || buffer.timedOut()) {
ALOGW("[%s] failed to read data from incident helper: %s, timedout: %s",
- this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
+ this->name.c_str(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
kill_child(pid);
return readStatus;
}
status_t ihStatus = wait_child(pid);
if (ihStatus != NO_ERROR) {
- ALOGW("[%s] abnormal child process: %s", this->name.string(), strerror(-ihStatus));
+ ALOGW("[%s] abnormal child process: %s", this->name.c_str(), strerror(-ihStatus));
return OK; // Not a fatal error.
}
@@ -169,7 +169,7 @@ status_t GZipSection::Execute(ReportWriter* writer) const {
index++; // look at the next file.
}
if (fd.get() == -1) {
- ALOGW("[%s] can't open all the files", this->name.string());
+ ALOGW("[%s] can't open all the files", this->name.c_str());
return NO_ERROR; // e.g. LAST_KMSG will reach here in user build.
}
FdBuffer buffer;
@@ -177,13 +177,13 @@ status_t GZipSection::Execute(ReportWriter* writer) const {
Fpipe c2pPipe;
// initiate pipes to pass data to/from gzip
if (!p2cPipe.init() || !c2pPipe.init()) {
- ALOGW("[%s] failed to setup pipes", this->name.string());
+ ALOGW("[%s] failed to setup pipes", this->name.c_str());
return -errno;
}
pid_t pid = fork_execute_cmd((char* const*)GZIP, &p2cPipe, &c2pPipe);
if (pid == -1) {
- ALOGW("[%s] failed to fork", this->name.string());
+ ALOGW("[%s] failed to fork", this->name.c_str());
return -errno;
}
// parent process
@@ -202,14 +202,14 @@ status_t GZipSection::Execute(ReportWriter* writer) const {
size_t editPos = internalBuffer->wp()->pos();
internalBuffer->wp()->move(8); // reserve 8 bytes for the varint of the data size.
size_t dataBeginAt = internalBuffer->wp()->pos();
- VLOG("[%s] editPos=%zu, dataBeginAt=%zu", this->name.string(), editPos, dataBeginAt);
+ VLOG("[%s] editPos=%zu, dataBeginAt=%zu", this->name.c_str(), editPos, dataBeginAt);
status_t readStatus = buffer.readProcessedDataInStream(
fd.get(), std::move(p2cPipe.writeFd()), std::move(c2pPipe.readFd()), this->timeoutMs,
isSysfs(mFilenames[index]));
writer->setSectionStats(buffer);
if (readStatus != NO_ERROR || buffer.timedOut()) {
- ALOGW("[%s] failed to read data from gzip: %s, timedout: %s", this->name.string(),
+ ALOGW("[%s] failed to read data from gzip: %s, timedout: %s", this->name.c_str(),
strerror(-readStatus), buffer.timedOut() ? "true" : "false");
kill_child(pid);
return readStatus;
@@ -217,7 +217,7 @@ status_t GZipSection::Execute(ReportWriter* writer) const {
status_t gzipStatus = wait_child(pid);
if (gzipStatus != NO_ERROR) {
- ALOGW("[%s] abnormal child process: %s", this->name.string(), strerror(-gzipStatus));
+ ALOGW("[%s] abnormal child process: %s", this->name.c_str(), strerror(-gzipStatus));
return gzipStatus;
}
// Revisit the actual size from gzip result and edit the internal buffer accordingly.
@@ -290,7 +290,7 @@ status_t WorkerThreadSection::Execute(ReportWriter* writer) const {
FdBuffer buffer;
err = buffer.read(data->pipe.readFd().get(), this->timeoutMs);
if (err != NO_ERROR) {
- ALOGE("[%s] reader failed with error '%s'", this->name.string(), strerror(-err));
+ ALOGE("[%s] reader failed with error '%s'", this->name.c_str(), strerror(-err));
}
// If the worker side is finished, then return its error (which may overwrite
@@ -300,7 +300,7 @@ status_t WorkerThreadSection::Execute(ReportWriter* writer) const {
data->pipe.close();
if (data->workerError != NO_ERROR) {
err = data->workerError;
- ALOGE("[%s] worker failed with error '%s'", this->name.string(), strerror(-err));
+ ALOGE("[%s] worker failed with error '%s'", this->name.c_str(), strerror(-err));
}
workerDone = data->workerDone;
}
@@ -309,17 +309,17 @@ status_t WorkerThreadSection::Execute(ReportWriter* writer) const {
if (err != NO_ERROR) {
char errMsg[128];
snprintf(errMsg, 128, "[%s] failed with error '%s'",
- this->name.string(), strerror(-err));
+ this->name.c_str(), strerror(-err));
writer->error(this, err, "WorkerThreadSection failed.");
return NO_ERROR;
}
if (buffer.truncated()) {
- ALOGW("[%s] too large, truncating", this->name.string());
+ ALOGW("[%s] too large, truncating", this->name.c_str());
// Do not write a truncated section. It won't pass through the PrivacyFilter.
return NO_ERROR;
}
if (!workerDone || buffer.timedOut()) {
- ALOGW("[%s] timed out", this->name.string());
+ ALOGW("[%s] timed out", this->name.c_str());
return NO_ERROR;
}
@@ -360,18 +360,18 @@ status_t CommandSection::Execute(ReportWriter* writer) const {
Fpipe ihPipe;
if (!cmdPipe.init() || !ihPipe.init()) {
- ALOGW("[%s] failed to setup pipes", this->name.string());
+ ALOGW("[%s] failed to setup pipes", this->name.c_str());
return -errno;
}
pid_t cmdPid = fork_execute_cmd((char* const*)mCommand, NULL, &cmdPipe);
if (cmdPid == -1) {
- ALOGW("[%s] failed to fork", this->name.string());
+ ALOGW("[%s] failed to fork", this->name.c_str());
return -errno;
}
pid_t ihPid = fork_execute_incident_helper(this->id, &cmdPipe, &ihPipe);
if (ihPid == -1) {
- ALOGW("[%s] failed to fork", this->name.string());
+ ALOGW("[%s] failed to fork", this->name.c_str());
return -errno;
}
@@ -381,7 +381,7 @@ status_t CommandSection::Execute(ReportWriter* writer) const {
writer->setSectionStats(buffer);
if (readStatus != NO_ERROR || buffer.timedOut()) {
ALOGW("[%s] failed to read data from incident helper: %s, timedout: %s",
- this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
+ this->name.c_str(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
kill_child(cmdPid);
kill_child(ihPid);
return readStatus;
@@ -393,7 +393,7 @@ status_t CommandSection::Execute(ReportWriter* writer) const {
status_t ihStatus = wait_child(ihPid);
if (cmdStatus != NO_ERROR || ihStatus != NO_ERROR) {
ALOGW("[%s] abnormal child processes, return status: command: %s, incident helper: %s",
- this->name.string(), strerror(-cmdStatus), strerror(-ihStatus));
+ this->name.c_str(), strerror(-cmdStatus), strerror(-ihStatus));
// Not a fatal error.
return NO_ERROR;
}
@@ -428,7 +428,7 @@ status_t DumpsysSection::BlockingCall(unique_fd& pipeWriteFd) const {
sp<IBinder> service = defaultServiceManager()->checkService(mService);
if (service == NULL) {
- ALOGW("DumpsysSection: Can't lookup service: %s", String8(mService).string());
+ ALOGW("DumpsysSection: Can't lookup service: %s", String8(mService).c_str());
return NAME_NOT_FOUND;
}
@@ -463,14 +463,14 @@ status_t TextDumpsysSection::Execute(ReportWriter* writer) const {
// checkService won't wait for the service to show up like getService will.
sp<IBinder> service = defaultServiceManager()->checkService(mService);
if (service == NULL) {
- ALOGW("TextDumpsysSection: Can't lookup service: %s", String8(mService).string());
+ ALOGW("TextDumpsysSection: Can't lookup service: %s", String8(mService).c_str());
return NAME_NOT_FOUND;
}
// Create pipe
Fpipe dumpPipe;
if (!dumpPipe.init()) {
- ALOGW("[%s] failed to setup pipe", this->name.string());
+ ALOGW("[%s] failed to setup pipe", this->name.c_str());
return -errno;
}
@@ -482,7 +482,7 @@ status_t TextDumpsysSection::Execute(ReportWriter* writer) const {
signal(SIGPIPE, sigpipe_handler);
status_t err = service->dump(write_fd.get(), this->mArgs);
if (err != OK) {
- ALOGW("[%s] dump thread failed. Error: %s", this->name.string(), strerror(-err));
+ ALOGW("[%s] dump thread failed. Error: %s", this->name.c_str(), strerror(-err));
}
write_fd.reset();
});
@@ -490,7 +490,7 @@ status_t TextDumpsysSection::Execute(ReportWriter* writer) const {
// Collect dump content
FdBuffer buffer;
ProtoOutputStream proto;
- proto.write(TextDumpProto::COMMAND, std::string(name.string()));
+ proto.write(TextDumpProto::COMMAND, std::string(name.c_str()));
proto.write(TextDumpProto::DUMP_DURATION_NS, int64_t(Nanotime() - start));
buffer.write(proto.data());
@@ -504,7 +504,7 @@ status_t TextDumpsysSection::Execute(ReportWriter* writer) const {
dumpPipe.readFd().reset();
writer->setSectionStats(buffer);
if (readStatus != OK || buffer.timedOut()) {
- ALOGW("[%s] failed to read from dumpsys: %s, timedout: %s", this->name.string(),
+ ALOGW("[%s] failed to read from dumpsys: %s, timedout: %s", this->name.c_str(),
strerror(-readStatus), buffer.timedOut() ? "true" : "false");
worker.detach();
return readStatus;
@@ -579,7 +579,7 @@ status_t LogSection::BlockingCall(unique_fd& pipeWriteFd) const {
// Hence forking a new process to prevent memory fragmentation.
pid_t pid = fork();
if (pid < 0) {
- ALOGW("[%s] failed to fork", this->name.string());
+ ALOGW("[%s] failed to fork", this->name.c_str());
return errno;
}
if (pid > 0) {
@@ -593,7 +593,7 @@ status_t LogSection::BlockingCall(unique_fd& pipeWriteFd) const {
android_logger_list_free);
if (android_logger_open(loggers.get(), mLogID) == NULL) {
- ALOGE("[%s] Can't get logger.", this->name.string());
+ ALOGE("[%s] Can't get logger.", this->name.c_str());
_exit(EXIT_FAILURE);
}
@@ -610,7 +610,7 @@ status_t LogSection::BlockingCall(unique_fd& pipeWriteFd) const {
// status = -EAGAIN, graceful indication for ANDRODI_LOG_NONBLOCK that this is the end.
if (status <= 0) {
if (status != -EAGAIN) {
- ALOGW("[%s] fails to read a log_msg.\n", this->name.string());
+ ALOGW("[%s] fails to read a log_msg.\n", this->name.c_str());
err = -status;
}
break;
@@ -680,7 +680,7 @@ status_t LogSection::BlockingCall(unique_fd& pipeWriteFd) const {
AndroidLogEntry entry;
status = android_log_processLogBuffer(&msg.entry, &entry);
if (status != OK) {
- ALOGW("[%s] fails to process to an entry.\n", this->name.string());
+ ALOGW("[%s] fails to process to an entry.\n", this->name.c_str());
err = status;
break;
}
@@ -702,7 +702,7 @@ status_t LogSection::BlockingCall(unique_fd& pipeWriteFd) const {
}
if (!proto.flush(pipeWriteFd.get())) {
if (errno == EPIPE) {
- ALOGW("[%s] wrote to a broken pipe\n", this->name.string());
+ ALOGW("[%s] wrote to a broken pipe\n", this->name.c_str());
}
err = errno;
break;
@@ -757,7 +757,7 @@ status_t TombstoneSection::BlockingCall(unique_fd& pipeWriteFd) const {
}
ssize_t exe_name_len = readlink(link_name, exe_name, EXE_NAME_LEN);
if (exe_name_len < 0 || exe_name_len >= EXE_NAME_LEN) {
- ALOGE("[%s] Can't read '%s': %s", name.string(), link_name, strerror(errno));
+ ALOGE("[%s] Can't read '%s': %s", name.c_str(), link_name, strerror(errno));
continue;
}
// readlink(2) does not put a null terminator at the end
@@ -788,7 +788,7 @@ status_t TombstoneSection::BlockingCall(unique_fd& pipeWriteFd) const {
Fpipe dumpPipe;
if (!dumpPipe.init()) {
- ALOGW("[%s] failed to setup dump pipe", this->name.string());
+ ALOGW("[%s] failed to setup dump pipe", this->name.c_str());
err = -errno;
break;
}
@@ -822,12 +822,12 @@ status_t TombstoneSection::BlockingCall(unique_fd& pipeWriteFd) const {
// Wait on the child to avoid it becoming a zombie process.
status_t cStatus = wait_child(child);
if (err != NO_ERROR) {
- ALOGW("[%s] failed to read stack dump: %d", this->name.string(), err);
+ ALOGW("[%s] failed to read stack dump: %d", this->name.c_str(), err);
dumpPipe.readFd().reset();
break;
}
if (cStatus != NO_ERROR) {
- ALOGE("[%s] child had an issue: %s\n", this->name.string(), strerror(-cStatus));
+ ALOGE("[%s] child had an issue: %s\n", this->name.c_str(), strerror(-cStatus));
}
// Resize dump buffer
@@ -852,7 +852,7 @@ status_t TombstoneSection::BlockingCall(unique_fd& pipeWriteFd) const {
dumpPipe.readFd().reset();
if (!proto.flush(pipeWriteFd.get())) {
if (errno == EPIPE) {
- ALOGE("[%s] wrote to a broken pipe\n", this->name.string());
+ ALOGE("[%s] wrote to a broken pipe\n", this->name.c_str());
}
err = errno;
break;
diff --git a/cmds/incidentd/src/report_directory.cpp b/cmds/incidentd/src/report_directory.cpp
index 7d20a74437ce..6b2fb8ec308a 100644
--- a/cmds/incidentd/src/report_directory.cpp
+++ b/cmds/incidentd/src/report_directory.cpp
@@ -62,8 +62,8 @@ void clean_directory(const char* directory, off_t maxSize, size_t maxCount) {
continue;
}
String8 filename = dirbase + entry->d_name;
- if (stat(filename.string(), &st) != 0) {
- ALOGE("Unable to stat file %s", filename.string());
+ if (stat(filename.c_str(), &st) != 0) {
+ ALOGE("Unable to stat file %s", filename.c_str());
continue;
}
if (!S_ISREG(st.st_mode)) {
@@ -88,7 +88,7 @@ void clean_directory(const char* directory, off_t maxSize, size_t maxCount) {
// Remove files until we're under our limits.
for (std::vector<std::pair<String8, struct stat>>::iterator it = files.begin();
it != files.end() && totalSize >= maxSize && totalCount >= maxCount; it++) {
- remove(it->first.string());
+ remove(it->first.c_str());
totalSize -= it->second.st_size;
totalCount--;
}
diff --git a/cmds/locksettings/Android.bp b/cmds/locksettings/Android.bp
index 5ee582450361..ee31aed14385 100644
--- a/cmds/locksettings/Android.bp
+++ b/cmds/locksettings/Android.bp
@@ -21,8 +21,7 @@ package {
default_applicable_licenses: ["frameworks_base_license"],
}
-java_binary {
+sh_binary {
name: "locksettings",
- wrapper: "locksettings.sh",
- srcs: ["**/*.java"],
+ src: "locksettings.sh",
}
diff --git a/cmds/locksettings/locksettings.sh b/cmds/locksettings/locksettings.sh
index 0ef4fa9f6771..2f8d86844eb1 100755
--- a/cmds/locksettings/locksettings.sh
+++ b/cmds/locksettings/locksettings.sh
@@ -1,6 +1,2 @@
#!/system/bin/sh
-# Script to start "locksettings" on the device
-#
-base=/system
-export CLASSPATH=$base/framework/locksettings.jar
-exec app_process $base/bin com.android.commands.locksettings.LockSettingsCmd "$@"
+cmd lock_settings "$@"
diff --git a/cmds/locksettings/src/com/android/commands/locksettings/LockSettingsCmd.java b/cmds/locksettings/src/com/android/commands/locksettings/LockSettingsCmd.java
deleted file mode 100644
index 7d9260a77158..000000000000
--- a/cmds/locksettings/src/com/android/commands/locksettings/LockSettingsCmd.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.commands.locksettings;
-
-import android.os.ResultReceiver;
-import android.os.ServiceManager;
-import android.os.ShellCallback;
-
-import com.android.internal.os.BaseCommand;
-import com.android.internal.widget.ILockSettings;
-
-import java.io.FileDescriptor;
-import java.io.PrintStream;
-
-public final class LockSettingsCmd extends BaseCommand {
-
- public static void main(String[] args) {
- (new LockSettingsCmd()).run(args);
- }
-
- @Override
- public void onShowUsage(PrintStream out) {
- main(new String[] { "help" });
- }
-
- @Override
- public void onRun() throws Exception {
- ILockSettings lockSettings = ILockSettings.Stub.asInterface(
- ServiceManager.getService("lock_settings"));
- lockSettings.asBinder().shellCommand(FileDescriptor.in, FileDescriptor.out,
- FileDescriptor.err, getRawArgs(), new ShellCallback(), new ResultReceiver(null) {});
- }
-}
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index 863efffe3807..ee9c464219d9 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -196,9 +196,6 @@ int main(int argc, char** argv)
return 1;
}
- void const* mapbase = MAP_FAILED;
- ssize_t mapsize = -1;
-
void* base = NULL;
// setThreadPoolMaxThreadCount(0) actually tells the kernel it's
@@ -209,21 +206,19 @@ int main(int argc, char** argv)
ProcessState::self()->startThreadPool();
sp<SyncScreenCaptureListener> captureListener = new SyncScreenCaptureListener();
- status_t result = ScreenshotClient::captureDisplay(*displayIdOpt, captureListener);
- if (result != NO_ERROR) {
- close(fd);
- return 1;
- }
+ ScreenshotClient::captureDisplay(*displayIdOpt, captureListener);
ScreenCaptureResults captureResults = captureListener->waitForResults();
if (!captureResults.fenceResult.ok()) {
close(fd);
+ fprintf(stderr, "Failed to take screenshot. Status: %d\n",
+ fenceStatus(captureResults.fenceResult));
return 1;
}
ui::Dataspace dataspace = captureResults.capturedDataspace;
sp<GraphicBuffer> buffer = captureResults.buffer;
- result = buffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &base);
+ status_t result = buffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &base);
if (base == nullptr || result != NO_ERROR) {
String8 reason;
@@ -278,9 +273,6 @@ int main(int argc, char** argv)
}
}
close(fd);
- if (mapbase != MAP_FAILED) {
- munmap((void *)mapbase, mapsize);
- }
return 0;
}
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index 13c7946a033f..1488e14cfb8f 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -76,6 +76,8 @@ public final class Telecom extends BaseCommand {
private static final String COMMAND_CLEANUP_ORPHAN_PHONE_ACCOUNTS =
"cleanup-orphan-phone-accounts";
private static final String COMMAND_RESET_CAR_MODE = "reset-car-mode";
+ private static final String COMMAND_IS_NON_IN_CALL_SERVICE_BOUND =
+ "is-non-ui-in-call-service-bound";
/**
* Change the system dialer package name if a package name was specified,
@@ -169,6 +171,8 @@ public final class Telecom extends BaseCommand {
+ " over Telephony.\n"
+ "telecom log-mark <MESSAGE>: emits a message into the telecom logs. Useful for "
+ "testers to indicate where in the logs various test steps take place.\n"
+ + "telecom is-non-ui-in-call-service-bound <PACKAGE>: queries a particular "
+ + "non-ui-InCallService in InCallController to determine if it is bound \n"
);
}
@@ -270,6 +274,9 @@ public final class Telecom extends BaseCommand {
case COMMAND_GET_MAX_PHONES:
runGetMaxPhones();
break;
+ case COMMAND_IS_NON_IN_CALL_SERVICE_BOUND:
+ runIsNonUiInCallServiceBound();
+ break;
case COMMAND_SET_TEST_EMERGENCY_PHONE_ACCOUNT_PACKAGE_FILTER:
runSetEmergencyPhoneAccountPackageFilter();
break;
@@ -428,6 +435,18 @@ public final class Telecom extends BaseCommand {
}
/**
+ * prints out whether a particular non-ui InCallServices is bound in a call
+ */
+ public void runIsNonUiInCallServiceBound() throws RemoteException {
+ if (TextUtils.isEmpty(mArgs.peekNextArg())) {
+ System.out.println("No Argument passed. Please pass a <PACKAGE_NAME> to lookup.");
+ } else {
+ System.out.println(
+ String.valueOf(mTelecomService.isNonUiInCallServiceBound(nextArg())));
+ }
+ }
+
+ /**
* Prints the mSIM config to the console.
* "DSDS" for a phone in DSDS mode
* "" (empty string) for a phone in SS mode
diff --git a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
index 39248730802f..7489ce3eceea 100644
--- a/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
+++ b/cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
@@ -8,6 +8,7 @@ import android.app.UiAutomation;
import android.app.UiAutomationConnection;
import android.content.Intent;
import android.os.HandlerThread;
+import android.os.Looper;
import android.os.RemoteException;
/**
@@ -26,6 +27,10 @@ public class UiAutomationShellWrapper {
throw new IllegalStateException("Already connected!");
}
mHandlerThread.start();
+ // The AccessibilityInteractionClient used by UiAutomation expects the main looper to
+ // be prepared. In most contexts this is normally done automatically, but must be called
+ // explicitly here because this is a shell tool.
+ Looper.prepareMainLooper();
mUiAutomation = new UiAutomation(mHandlerThread.getLooper(),
new UiAutomationConnection());
mUiAutomation.connect();
diff --git a/cmds/uinput/README.md b/cmds/uinput/README.md
index 47e1dad9ccd6..82df55509a7a 100644
--- a/cmds/uinput/README.md
+++ b/cmds/uinput/README.md
@@ -1,87 +1,99 @@
# Usage
-## Two options to use the uinput command:
-### 1. Interactive through stdin:
-type `uinput -` into the terminal, then type/paste commands to send to the binary.
-Use Ctrl+D to signal end of stream to the binary (EOF).
-This mode can be also used from an app to send uinput events.
-For an example, see the cts test case at: [InputTestCase.java][2]
+There are two ways to use the `uinput` command:
-When using another program to control uinput in interactive mode, registering a
-new input device (for example, a bluetooth joystick) should be the first step.
-After the device is added, you need to wait for the _onInputDeviceAdded_
-(see [InputDeviceListener][1]) notification before issuing commands
-to the device.
-Failure to do so will cause missed events and inconsistent behavior.
+* **Recommended:** `uinput -` reads commands from standard input until End-of-File (Ctrl+D) is sent.
+ This mode can be used interactively from a terminal or used to control uinput from another program
+ or app (such as the CTS tests via [`UinputDevice`][UinputDevice]).
+* `uinput <filename>` reads commands from a file instead of standard input.
-### 2. Using a file as an input:
-type `uinput <filename>`, and the file will be used an an input to the binary.
-You must add a sufficient delay after a "register" command to ensure device
-is ready. The interactive mode is the recommended method of communicating
-with the uinput binary.
+[UinputDevice]: https://cs.android.com/android/platform/superproject/main/+/main:cts/libs/input/src/com/android/cts/input/UinputDevice.java
-All of the input commands should be in pseudo-JSON format as documented below.
-See examples [here][3].
+## Command format
-The file can have multiple commands one after the other (which is not strictly
-legal JSON format, as this would imply multiple root elements).
+Input commands should be in JSON format, though the parser is in [lenient mode] to allow comments,
+and integers can be specified in hexadecimal (e.g. `0xABCD`). The input file (or standard input) can
+contain multiple commands, which will be executed in sequence. Simply add multiple JSON objects to
+the file, one after the other without separators:
-## Command description
+```json5
+{
+ "id": 1,
+ "command": "register",
+ // ...
+}
+{
+ "id": 1,
+ "command": "delay",
+ // ...
+}
+```
+
+Many examples of command files can be found [in the CTS tests][cts-example-jsons].
+
+[lenient mode]: https://developer.android.com/reference/android/util/JsonReader#setLenient(boolean)
+[cts-example-jsons]: https://cs.android.com/android/platform/superproject/main/+/main:cts/tests/tests/hardware/res/raw/
+
+## Command reference
+
+### `register`
-1. `register`
Register a new uinput device
-| Field | Type | Description |
-|:-------------:|:-------------:|:-------------------------- |
-| id | integer | Device id |
-| command | string | Must be set to "register" |
-| name | string | Device name |
-| vid | 16-bit integer| Vendor id |
-| pid | 16-bit integer| Product id |
-| bus | string | Bus that device should use |
-| configuration | int array | uinput device configuration|
-| ff_effects_max| integer | ff_effects_max value |
-| abs_info | array | ABS axes information |
-
-Device ID is used for matching the subsequent commands to a specific device
-to avoid ambiguity when multiple devices are registered.
-
-Device bus is used to determine how the uinput device is connected to the host.
-The options are "usb" and "bluetooth".
-
-Device configuration is used to configure uinput device. "type" field provides the UI_SET_*
-control code, and data is a vector of control values to be sent to uinput device, depends on
-the control code.
+| Field | Type | Description |
+|:----------------:|:--------------:|:-------------------------- |
+| `id` | integer | Device ID |
+| `command` | string | Must be set to "register" |
+| `name` | string | Device name |
+| `vid` | 16-bit integer | Vendor ID |
+| `pid` | 16-bit integer | Product ID |
+| `bus` | string | Bus that device should use |
+| `configuration` | object array | uinput device configuration|
+| `ff_effects_max` | integer | `ff_effects_max` value |
+| `abs_info` | array | Absolute axes information |
-| Field | Type | Description |
-|:-------------:|:-------------:|:-------------------------- |
-| type | integer | UI_SET_ control type |
-| data | int array | control values |
+`id` is used for matching the subsequent commands to a specific device to avoid ambiguity when
+multiple devices are registered.
-Device ff_effects_max must be provided if FFBIT is set.
+`bus` is used to determine how the uinput device is connected to the host. The options are `"usb"`
+and `"bluetooth"`.
-Device abs_info fields are provided to set the device axes information. It is an array of below
-objects:
-| Field | Type | Description |
-|:-------------:|:-------------:|:-------------------------- |
-| code | integer | Axis code |
-| info | object | ABS information object |
+Device configuration is used to configure the uinput device. The `type` field provides a `UI_SET_*`
+control code as an integer value or a string label (e.g. `"UI_SET_EVBIT"`), and data is a vector of
+control values to be sent to the uinput device, which depends on the control code.
+
+| Field | Type | Description |
+|:-------------:|:---------------------:|:-----------------------|
+| `type` | integer\|string | `UI_SET_` control type |
+| `data` | integer\|string array | control values |
+
+Due to the sequential nature in which this is parsed, the `type` field must be specified before
+the `data` field in this JSON Object.
+
+`ff_effects_max` must be provided if `UI_SET_FFBIT` is used in `configuration`.
+
+`abs_info` fields are provided to set the device axes information. It is an array of below objects:
+
+| Field | Type | Description |
+|:-------------:|:---------------:|:------------------------|
+| `code` | integer\|string | Axis code or label |
+| `info` | object | Axis information object |
+
+The axis information object is defined as below, with the fields having the same meaning as those
+Linux's [`struct input_absinfo`][struct input_absinfo]:
-ABS information object is defined as below:
| Field | Type | Description |
|:-------------:|:-------------:|:-------------------------- |
-| value | integer | Latest reported value |
-| minimum | integer | Minimum value for the axis |
-| maximum | integer | Maximum value for the axis |
-| fuzz | integer | fuzz value for noise filter|
-| flat | integer | values to be discarded |
-| resolution | integer | resolution of axis |
-
-See [struct input_absinfo][4]) definitions.
+| `value` | integer | Latest reported value |
+| `minimum` | integer | Minimum value for the axis |
+| `maximum` | integer | Maximum value for the axis |
+| `fuzz` | integer | fuzz value for noise filter|
+| `flat` | integer | values to be discarded |
+| `resolution` | integer | resolution of axis |
Example:
-```json
+```json5
{
"id": 1,
"command": "register",
@@ -90,33 +102,56 @@ Example:
"pid": 0x2c42,
"bus": "usb",
"configuration":[
- {"type":100, "data":[1, 21]}, // UI_SET_EVBIT : EV_KEY and EV_FF
- {"type":101, "data":[11, 2, 3, 4]}, // UI_SET_KEYBIT : KEY_0 KEY_1 KEY_2 KEY_3
- {"type":107, "data":[80]} // UI_SET_FFBIT : FF_RUMBLE
+ {"type":"UI_SET_EVBIT", "data":["EV_KEY", "EV_FF"]},
+ {"type":"UI_SET_KEYBIT", "data":["KEY_0", "KEY_1", "KEY_2", "KEY_3"]},
+ {"type":"UI_SET_ABSBIT", "data":["ABS_Y", "ABS_WHEEL"]},
+ {"type":"UI_SET_FFBIT", "data":["FF_RUMBLE"]}
],
"ff_effects_max" : 1,
"abs_info": [
- {"code":1, "info": {"value":20, "minimum":-255,
+ {"code":"ABS_Y", "info": {"value":20, "minimum":-255,
"maximum":255, "fuzz":0, "flat":0, "resolution":1}
},
- {"code":8, "info": {"value":-50, "minimum":-255,
+ {"code":"ABS_WHEEL", "info": {"value":-50, "minimum":-255,
"maximum":255, "fuzz":0, "flat":0, "resolution":1}
}
]
}
-
```
-2. `delay`
+
+[struct input_absinfo]: https://cs.android.com/android/platform/superproject/main/+/main:bionic/libc/kernel/uapi/linux/input.h?q=%22struct%20input_absinfo%22
+
+#### Waiting for registration
+
+After the command is sent, there will be a delay before the device is set up by the Android input
+stack, and `uinput` does not wait for that process to finish. Any commands sent to the device during
+that time will be dropped. If you are controlling `uinput` by sending commands through standard
+input from an app, you need to wait for [`onInputDeviceAdded`][onInputDeviceAdded] to be called on
+an `InputDeviceListener` before issuing commands to the device. If you are passing a file to
+`uinput`, add a `delay` after the `register` command to let registration complete. You can add a
+`sync` in certain positions, like at the end of the file to get a response when all commands have
+finished processing.
+
+[onInputDeviceAdded]: https://developer.android.com/reference/android/hardware/input/InputManager.InputDeviceListener.html
+
+#### Unregistering the device
+
+As soon as EOF is reached (either in interactive mode, or in file mode), the device that was created
+will be unregistered. There is no explicit command for unregistering a device.
+
+### `delay`
+
Add a delay to command processing
| Field | Type | Description |
|:-------------:|:-------------:|:-------------------------- |
-| id | integer | Device id |
-| command | string | Must be set to "delay" |
-| duration | integer | Delay in milliseconds |
+| `id` | integer | Device ID |
+| `command` | string | Must be set to "delay" |
+| `duration` | integer | Delay in milliseconds |
Example:
-```json
+
+```json5
{
"id": 1,
"command": "delay",
@@ -124,43 +159,68 @@ Example:
}
```
-3. `inject`
-Send an array of uinput event packets [type, code, value] to the uinput device
+### `inject`
-| Field | Type | Description |
-|:-------------:|:-------------:|:-------------------------- |
-| id | integer | Device id |
-| command | string | Must be set to "inject" |
-| events | integer array | events to inject |
+Send an array of uinput event packets to the uinput device
-The "events" parameter is an array of integers, encapsulates evdev input_event type, code and value,
-see the example below.
+| Field | Type | Description |
+|:-------------:|:---------------------:|:-------------------------- |
+| `id` | integer | Device ID |
+| `command` | string | Must be set to "inject" |
+| `events` | integer\|string array | events to inject |
-Example:
-```json
+The `events` parameter is an array of integers in sets of three: a type, an axis code, and an axis
+value, like you'd find in Linux's `struct input_event`. For example, sending presses of the 0 and 1
+keys would look like this:
+
+```json5
{
"id": 1,
"command": "inject",
- "events": [0x01, 0xb, 0x1, // EV_KEY, KEY_0, DOWN
- 0x00, 0x00, 0x00, // EV_SYN, SYN_REPORT, 0
- 0x01, 0x0b, 0x00, // EV_KEY, KEY_0, UP
- 0x00, 0x00, 0x00, // EV_SYN, SYN_REPORT, 0
- 0x01, 0x2, 0x1, // EV_KEY, KEY_1, DOWN
- 0x00, 0x00, 0x01, // EV_SYN, SYN_REPORT, 0
- 0x01, 0x02, 0x00, // EV_KEY, KEY_1, UP
- 0x00, 0x00, 0x01 // EV_SYN, SYN_REPORT, 0
+ "events": ["EV_KEY", "KEY_0", 1,
+ "EV_SYN", "SYN_REPORT", 0,
+ "EV_KEY", "KEY_0", 0,
+ "EV_SYN", "SYN_REPORT", 0,
+ "EV_KEY", "KEY_1", 1,
+ "EV_SYN", "SYN_REPORT", 0,
+ "EV_KEY", "KEY_1", 0,
+ "EV_SYN", "SYN_REPORT", 0
]
}
```
-### Notes
-1. As soon as EOF is reached (either in interactive mode, or in file mode),
-the device that was created will be unregistered. There is no
-explicit command for unregistering a device.
-2. The `getevent` utility can used to print out the key events
-for debugging purposes.
-
-[1]: https://developer.android.com/reference/android/hardware/input/InputManager.InputDeviceListener.html
-[2]: ../../../../cts/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java
-[3]: ../../../../cts/tests/tests/hardware/res/raw/
-[4]: ../../../../bionic/libc/kernel/uapi/linux/input.h
+### `sync`
+
+A command used to get a response once the command is processed. When several `inject` and `delay`
+commands are used in a row, the `sync` command can be used to track the progress of the command
+queue.
+
+| Field | Type | Description |
+|:-----------:|:-------:|:---------------------------------------------|
+| `id` | integer | Device ID |
+| `command` | string | Must be set to "sync" |
+| `syncToken` | string | The token used to identify this sync command |
+
+Example:
+
+```json5
+{
+ "id": 1,
+ "command": "syncToken",
+ "syncToken": "finished_injecting_events"
+}
+```
+
+This command will result in the following response when it is processed:
+
+```json5
+{
+ "id": 1,
+ "result": "sync",
+ "syncToken": "finished_injecting_events"
+}
+```
+
+## Notes
+
+The `getevent` utility can used to print out the key events for debugging purposes.
diff --git a/cmds/uinput/jni/Android.bp b/cmds/uinput/jni/Android.bp
index c56adc35b580..558bcc54c7ef 100644
--- a/cmds/uinput/jni/Android.bp
+++ b/cmds/uinput/jni/Android.bp
@@ -21,6 +21,7 @@ cc_library_shared {
"libbase",
"libbinder",
"liblog",
+ "libinput",
"libnativehelper",
],
diff --git a/cmds/uinput/jni/com_android_commands_uinput_Device.cpp b/cmds/uinput/jni/com_android_commands_uinput_Device.cpp
index 3f4163dc54ec..7659054119c8 100644
--- a/cmds/uinput/jni/com_android_commands_uinput_Device.cpp
+++ b/cmds/uinput/jni/com_android_commands_uinput_Device.cpp
@@ -16,12 +16,24 @@
#define LOG_TAG "UinputCommandDevice"
-#include <linux/uinput.h>
+#include "com_android_commands_uinput_Device.h"
+#include <android-base/stringprintf.h>
+#include <android/looper.h>
+#include <android_os_Parcel.h>
#include <fcntl.h>
+#include <input/InputEventLabels.h>
#include <inttypes.h>
+#include <jni.h>
+#include <linux/uinput.h>
+#include <log/log.h>
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <nativehelper/ScopedUtfChars.h>
#include <time.h>
#include <unistd.h>
+
#include <algorithm>
#include <array>
#include <cstdio>
@@ -30,19 +42,6 @@
#include <memory>
#include <vector>
-#include <android/looper.h>
-#include <android_os_Parcel.h>
-#include <jni.h>
-#include <log/log.h>
-#include <nativehelper/JNIHelp.h>
-#include <nativehelper/ScopedLocalRef.h>
-#include <nativehelper/ScopedPrimitiveArray.h>
-#include <nativehelper/ScopedUtfChars.h>
-
-#include <android-base/stringprintf.h>
-
-#include "com_android_commands_uinput_Device.h"
-
namespace android {
namespace uinput {
@@ -307,6 +306,21 @@ static void setAbsInfo(JNIEnv* env, jclass /* clazz */, jint handle, jint axisCo
::ioctl(static_cast<int>(handle), UI_ABS_SETUP, &absSetup);
}
+static jint getEvdevEventTypeByLabel(JNIEnv* env, jclass /* clazz */, jstring rawLabel) {
+ ScopedUtfChars label(env, rawLabel);
+ return InputEventLookup::getLinuxEvdevEventTypeByLabel(label.c_str()).value_or(-1);
+}
+
+static jint getEvdevEventCodeByLabel(JNIEnv* env, jclass /* clazz */, jint type, jstring rawLabel) {
+ ScopedUtfChars label(env, rawLabel);
+ return InputEventLookup::getLinuxEvdevEventCodeByLabel(type, label.c_str()).value_or(-1);
+}
+
+static jint getEvdevInputPropByLabel(JNIEnv* env, jclass /* clazz */, jstring rawLabel) {
+ ScopedUtfChars label(env, rawLabel);
+ return InputEventLookup::getLinuxEvdevInputPropByLabel(label.c_str()).value_or(-1);
+}
+
static JNINativeMethod sMethods[] = {
{"nativeOpenUinputDevice",
"(Ljava/lang/String;IIIIILjava/lang/String;"
@@ -316,6 +330,12 @@ static JNINativeMethod sMethods[] = {
{"nativeConfigure", "(II[I)V", reinterpret_cast<void*>(configure)},
{"nativeSetAbsInfo", "(IILandroid/os/Parcel;)V", reinterpret_cast<void*>(setAbsInfo)},
{"nativeCloseUinputDevice", "(J)V", reinterpret_cast<void*>(closeUinputDevice)},
+ {"nativeGetEvdevEventTypeByLabel", "(Ljava/lang/String;)I",
+ reinterpret_cast<void*>(getEvdevEventTypeByLabel)},
+ {"nativeGetEvdevEventCodeByLabel", "(ILjava/lang/String;)I",
+ reinterpret_cast<void*>(getEvdevEventCodeByLabel)},
+ {"nativeGetEvdevInputPropByLabel", "(Ljava/lang/String;)I",
+ reinterpret_cast<void*>(getEvdevInputPropByLabel)},
};
int register_com_android_commands_uinput_Device(JNIEnv* env) {
diff --git a/cmds/uinput/src/com/android/commands/uinput/Device.java b/cmds/uinput/src/com/android/commands/uinput/Device.java
index 732b33d60c15..ad5e70f4ff0c 100644
--- a/cmds/uinput/src/com/android/commands/uinput/Device.java
+++ b/cmds/uinput/src/com/android/commands/uinput/Device.java
@@ -45,6 +45,7 @@ public class Device {
private static final int MSG_OPEN_UINPUT_DEVICE = 1;
private static final int MSG_CLOSE_UINPUT_DEVICE = 2;
private static final int MSG_INJECT_EVENT = 3;
+ private static final int MSG_SYNC_EVENT = 4;
private final int mId;
private final HandlerThread mThread;
@@ -66,6 +67,9 @@ public class Device {
private static native void nativeInjectEvent(long ptr, int type, int code, int value);
private static native void nativeConfigure(int handle, int code, int[] configs);
private static native void nativeSetAbsInfo(int handle, int axisCode, Parcel axisParcel);
+ private static native int nativeGetEvdevEventTypeByLabel(String label);
+ private static native int nativeGetEvdevEventCodeByLabel(int type, String label);
+ private static native int nativeGetEvdevInputPropByLabel(String label);
public Device(int id, String name, int vid, int pid, int bus,
SparseArray<int[]> configuration, int ffEffectsMax,
@@ -119,6 +123,16 @@ public class Device {
}
/**
+ * Synchronize the uinput command queue by writing a sync response with the provided syncToken
+ * to the output stream when this event is processed.
+ *
+ * @param syncToken The token for this sync command.
+ */
+ public void syncEvent(String syncToken) {
+ mHandler.sendMessageAtTime(mHandler.obtainMessage(MSG_SYNC_EVENT, syncToken), mTimeToSend);
+ }
+
+ /**
* Close an uinput device.
*
*/
@@ -171,6 +185,9 @@ public class Device {
mCond.notify();
}
break;
+ case MSG_SYNC_EVENT:
+ handleSyncEvent((String) msg.obj);
+ break;
default:
throw new IllegalArgumentException("Unknown device message");
}
@@ -184,6 +201,18 @@ public class Device {
getLooper().myQueue().removeSyncBarrier(mBarrierToken);
mBarrierToken = 0;
}
+
+ private void handleSyncEvent(String syncToken) {
+ final JSONObject json = new JSONObject();
+ try {
+ json.put("reason", "sync");
+ json.put("id", mId);
+ json.put("syncToken", syncToken);
+ } catch (JSONException e) {
+ throw new RuntimeException("Could not create JSON object ", e);
+ }
+ writeOutputObject(json);
+ }
}
private class DeviceCallback {
@@ -211,7 +240,7 @@ public class Device {
}
public void onDeviceVibrating(int value) {
- JSONObject json = new JSONObject();
+ final JSONObject json = new JSONObject();
try {
json.put("reason", "vibrating");
json.put("id", mId);
@@ -219,12 +248,7 @@ public class Device {
} catch (JSONException e) {
throw new RuntimeException("Could not create JSON object ", e);
}
- try {
- mOutputStream.write(json.toString().getBytes());
- mOutputStream.flush();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
+ writeOutputObject(json);
}
public void onDeviceError() {
@@ -234,4 +258,41 @@ public class Device {
msg.sendToTarget();
}
}
+
+ private void writeOutputObject(JSONObject json) {
+ try {
+ mOutputStream.write(json.toString().getBytes());
+ mOutputStream.flush();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ static int getEvdevEventTypeByLabel(String label) {
+ final var type = nativeGetEvdevEventTypeByLabel(label);
+ if (type < 0) {
+ throw new IllegalArgumentException(
+ "Failed to get evdev event type from label: " + label);
+ }
+ return type;
+ }
+
+ static int getEvdevEventCodeByLabel(int type, String label) {
+ final var code = nativeGetEvdevEventCodeByLabel(type, label);
+ if (code < 0) {
+ throw new IllegalArgumentException(
+ "Failed to get evdev event code for type " + type + " from label: " + label);
+ }
+ return code;
+
+ }
+
+ static int getEvdevInputPropByLabel(String label) {
+ final var prop = nativeGetEvdevInputPropByLabel(label);
+ if (prop < 0) {
+ throw new IllegalArgumentException(
+ "Failed to get evdev input prop from label: " + label);
+ }
+ return prop;
+ }
}
diff --git a/cmds/uinput/src/com/android/commands/uinput/Event.java b/cmds/uinput/src/com/android/commands/uinput/Event.java
index 4b090f5a713c..9d8f1f400950 100644
--- a/cmds/uinput/src/com/android/commands/uinput/Event.java
+++ b/cmds/uinput/src/com/android/commands/uinput/Event.java
@@ -25,6 +25,9 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Function;
import java.util.stream.IntStream;
import src.com.android.commands.uinput.InputAbsInfo;
@@ -36,10 +39,48 @@ import src.com.android.commands.uinput.InputAbsInfo;
public class Event {
private static final String TAG = "UinputEvent";
- public static final String COMMAND_REGISTER = "register";
- public static final String COMMAND_DELAY = "delay";
- public static final String COMMAND_INJECT = "inject";
- private static final int ABS_CNT = 64;
+ enum Command {
+ REGISTER("register"),
+ DELAY("delay"),
+ INJECT("inject"),
+ SYNC("sync");
+
+ final String mCommandName;
+
+ Command(String command) {
+ mCommandName = command;
+ }
+ }
+
+ private static final int EV_KEY = 0x01;
+ private static final int EV_REL = 0x02;
+ private static final int EV_ABS = 0x03;
+ private static final int EV_MSC = 0x04;
+ private static final int EV_SW = 0x05;
+ private static final int EV_LED = 0x11;
+ private static final int EV_SND = 0x12;
+ private static final int EV_FF = 0x15;
+
+ private enum UinputControlCode {
+ UI_SET_EVBIT("UI_SET_EVBIT", 100),
+ UI_SET_KEYBIT("UI_SET_KEYBIT", 101),
+ UI_SET_RELBIT("UI_SET_RELBIT", 102),
+ UI_SET_ABSBIT("UI_SET_ABSBIT", 103),
+ UI_SET_MSCBIT("UI_SET_MSCBIT", 104),
+ UI_SET_LEDBIT("UI_SET_LEDBIT", 105),
+ UI_SET_SNDBIT("UI_SET_SNDBIT", 106),
+ UI_SET_FFBIT("UI_SET_FFBIT", 107),
+ UI_SET_SWBIT("UI_SET_SWBIT", 109),
+ UI_SET_PROPBIT("UI_SET_PROPBIT", 110);
+
+ final String mName;
+ final int mValue;
+
+ UinputControlCode(String name, int value) {
+ this.mName = name;
+ this.mValue = value;
+ }
+ }
// These constants come from "include/uapi/linux/input.h" in the kernel
enum Bus {
@@ -56,7 +97,7 @@ public class Event {
}
private int mId;
- private String mCommand;
+ private Command mCommand;
private String mName;
private int mVid;
private int mPid;
@@ -67,12 +108,13 @@ public class Event {
private int mFfEffectsMax = 0;
private String mInputport;
private SparseArray<InputAbsInfo> mAbsInfo;
+ private String mSyncToken;
public int getId() {
return mId;
}
- public String getCommand() {
+ public Command getCommand() {
return mCommand;
}
@@ -116,6 +158,10 @@ public class Event {
return mInputport;
}
+ public String getSyncToken() {
+ return mSyncToken;
+ }
+
/**
* Convert an event to String.
*/
@@ -146,7 +192,14 @@ public class Event {
}
private void setCommand(String command) {
- mEvent.mCommand = command;
+ Objects.requireNonNull(command, "Command must not be null");
+ for (Command cmd : Command.values()) {
+ if (cmd.mCommandName.equals(command)) {
+ mEvent.mCommand = cmd;
+ return;
+ }
+ }
+ throw new IllegalStateException("Unrecognized command: " + command);
}
public void setName(String name) {
@@ -189,27 +242,38 @@ public class Event {
mEvent.mInputport = port;
}
+ public void setSyncToken(String syncToken) {
+ mEvent.mSyncToken = Objects.requireNonNull(syncToken, "Sync token must not be null");
+ }
+
public Event build() {
if (mEvent.mId == -1) {
throw new IllegalStateException("No event id");
} else if (mEvent.mCommand == null) {
throw new IllegalStateException("Event does not contain a command");
}
- if (COMMAND_REGISTER.equals(mEvent.mCommand)) {
- if (mEvent.mConfiguration == null) {
- throw new IllegalStateException(
- "Device registration is missing configuration");
+ switch (mEvent.mCommand) {
+ case REGISTER -> {
+ if (mEvent.mConfiguration == null) {
+ throw new IllegalStateException(
+ "Device registration is missing configuration");
+ }
}
- } else if (COMMAND_DELAY.equals(mEvent.mCommand)) {
- if (mEvent.mDuration <= 0) {
- throw new IllegalStateException("Delay has missing or invalid duration");
+ case DELAY -> {
+ if (mEvent.mDuration <= 0) {
+ throw new IllegalStateException("Delay has missing or invalid duration");
+ }
}
- } else if (COMMAND_INJECT.equals(mEvent.mCommand)) {
- if (mEvent.mInjections == null) {
- throw new IllegalStateException("Inject command is missing injection data");
+ case INJECT -> {
+ if (mEvent.mInjections == null) {
+ throw new IllegalStateException("Inject command is missing injection data");
+ }
+ }
+ case SYNC -> {
+ if (mEvent.mSyncToken == null) {
+ throw new IllegalStateException("Sync command is missing sync token");
+ }
}
- } else {
- throw new IllegalStateException("Unknown command " + mEvent.mCommand);
}
return mEvent;
}
@@ -257,8 +321,8 @@ public class Event {
eb.setBus(readBus());
break;
case "events":
- int[] injections = readIntList().stream()
- .mapToInt(Integer::intValue).toArray();
+ int[] injections = readInjectedEvents().stream()
+ .mapToInt(Integer::intValue).toArray();
eb.setInjections(injections);
break;
case "configuration":
@@ -276,6 +340,9 @@ public class Event {
case "port":
eb.setInputport(mReader.nextString());
break;
+ case "syncToken":
+ eb.setSyncToken(mReader.nextString());
+ break;
default:
mReader.skipValue();
}
@@ -293,12 +360,17 @@ public class Event {
return e;
}
- private ArrayList<Integer> readIntList() throws IOException {
- ArrayList<Integer> data = new ArrayList<Integer>();
+ private ArrayList<Integer> readInjectedEvents() throws IOException {
+ ArrayList<Integer> data = new ArrayList<>();
try {
mReader.beginArray();
while (mReader.hasNext()) {
- data.add(Integer.decode(mReader.nextString()));
+ // Read events in groups of three, because we expect an event type, event code,
+ // and event value.
+ final int type = readEvdevEventType();
+ data.add(type);
+ data.add(readEvdevEventCode(type));
+ data.add(readInt());
}
mReader.endArray();
} catch (IllegalStateException | NumberFormatException e) {
@@ -309,22 +381,32 @@ public class Event {
return data;
}
- private byte[] readData() throws IOException {
- ArrayList<Integer> data = readIntList();
- byte[] rawData = new byte[data.size()];
- for (int i = 0; i < data.size(); i++) {
- int d = data.get(i);
- if ((d & 0xFF) != d) {
- throw new IllegalStateException("Invalid data, all values must be byte-sized");
+ private int readValueAsInt(Function<String, Integer> stringToInt) throws IOException {
+ switch (mReader.peek()) {
+ case NUMBER: {
+ return mReader.nextInt();
+ }
+ case STRING: {
+ final var str = mReader.nextString();
+ try {
+ // Attempt to first parse the value as an int.
+ return Integer.decode(str);
+ } catch (NumberFormatException e) {
+ // Then fall back to the supplied function.
+ return stringToInt.apply(str);
+ }
+ }
+ default: {
+ throw new IllegalStateException(
+ "Encountered malformed data. Expected int or string.");
}
- rawData[i] = (byte) d;
}
- return rawData;
}
private int readInt() throws IOException {
- String val = mReader.nextString();
- return Integer.decode(val);
+ return readValueAsInt((str) -> {
+ throw new IllegalStateException("Encountered malformed data. Expected int.");
+ });
}
private Bus readBus() throws IOException {
@@ -338,17 +420,20 @@ public class Event {
try {
mReader.beginArray();
while (mReader.hasNext()) {
- int type = 0;
+ UinputControlCode controlCode = null;
IntStream data = null;
mReader.beginObject();
while (mReader.hasNext()) {
String name = mReader.nextName();
switch (name) {
case "type":
- type = readInt();
+ controlCode = readUinputControlCode();
break;
case "data":
- data = readIntList().stream().mapToInt(Integer::intValue);
+ Objects.requireNonNull(controlCode,
+ "Configuration 'type' must be specified before 'data'.");
+ data = readDataForControlCode(controlCode)
+ .stream().mapToInt(Integer::intValue);
break;
default:
consumeRemainingElements();
@@ -358,9 +443,9 @@ public class Event {
}
}
mReader.endObject();
- if (data != null) {
- final int[] existing = configuration.get(type);
- configuration.put(type, existing == null ? data.toArray()
+ if (controlCode != null && data != null) {
+ final int[] existing = configuration.get(controlCode.mValue);
+ configuration.put(controlCode.mValue, existing == null ? data.toArray()
: IntStream.concat(IntStream.of(existing), data).toArray());
}
}
@@ -373,6 +458,60 @@ public class Event {
return configuration;
}
+ private UinputControlCode readUinputControlCode() throws IOException {
+ var code = readValueAsInt((controlTypeStr) -> {
+ for (UinputControlCode controlCode : UinputControlCode.values()) {
+ if (controlCode.mName.equals(controlTypeStr)) {
+ return controlCode.mValue;
+ }
+ }
+ return -1;
+ });
+ for (UinputControlCode controlCode : UinputControlCode.values()) {
+ if (controlCode.mValue == code) {
+ return controlCode;
+ }
+ }
+ return null;
+ }
+
+ private List<Integer> readDataForControlCode(
+ UinputControlCode controlCode) throws IOException {
+ return switch (controlCode) {
+ case UI_SET_EVBIT -> readArrayAsInts(this::readEvdevEventType);
+ case UI_SET_KEYBIT -> readArrayAsInts(() -> readEvdevEventCode(EV_KEY));
+ case UI_SET_RELBIT -> readArrayAsInts(() -> readEvdevEventCode(EV_REL));
+ case UI_SET_ABSBIT -> readArrayAsInts(() -> readEvdevEventCode(EV_ABS));
+ case UI_SET_MSCBIT -> readArrayAsInts(() -> readEvdevEventCode(EV_MSC));
+ case UI_SET_LEDBIT -> readArrayAsInts(() -> readEvdevEventCode(EV_LED));
+ case UI_SET_SNDBIT -> readArrayAsInts(() -> readEvdevEventCode(EV_SND));
+ case UI_SET_FFBIT -> readArrayAsInts(() -> readEvdevEventCode(EV_FF));
+ case UI_SET_SWBIT -> readArrayAsInts(() -> readEvdevEventCode(EV_SW));
+ case UI_SET_PROPBIT -> readArrayAsInts(this::readEvdevInputProp);
+ };
+ }
+
+ interface IntValueReader {
+ int readNextValue() throws IOException;
+ }
+
+ private ArrayList<Integer> readArrayAsInts(
+ IntValueReader nextValueReader) throws IOException {
+ ArrayList<Integer> data = new ArrayList<>();
+ try {
+ mReader.beginArray();
+ while (mReader.hasNext()) {
+ data.add(nextValueReader.readNextValue());
+ }
+ mReader.endArray();
+ } catch (IllegalStateException | NumberFormatException e) {
+ consumeRemainingElements();
+ mReader.endArray();
+ throw new IllegalStateException("Encountered malformed data.", e);
+ }
+ return data;
+ }
+
private InputAbsInfo readAbsInfo() throws IllegalStateException, IOException {
InputAbsInfo absInfo = new InputAbsInfo();
try {
@@ -426,7 +565,7 @@ public class Event {
String name = mReader.nextName();
switch (name) {
case "code":
- type = readInt();
+ type = readEvdevEventCode(EV_ABS);
break;
case "info":
absInfo = readAbsInfo();
@@ -452,6 +591,18 @@ public class Event {
return infoArray;
}
+ private int readEvdevEventType() throws IOException {
+ return readValueAsInt(Device::getEvdevEventTypeByLabel);
+ }
+
+ private int readEvdevEventCode(int type) throws IOException {
+ return readValueAsInt((str) -> Device.getEvdevEventCodeByLabel(type, str));
+ }
+
+ private int readEvdevInputProp() throws IOException {
+ return readValueAsInt(Device::getEvdevInputPropByLabel);
+ }
+
private void consumeRemainingElements() throws IOException {
while (mReader.hasNext()) {
mReader.skipValue();
diff --git a/cmds/uinput/src/com/android/commands/uinput/Uinput.java b/cmds/uinput/src/com/android/commands/uinput/Uinput.java
index 740578e878ac..47b7a354f330 100644
--- a/cmds/uinput/src/com/android/commands/uinput/Uinput.java
+++ b/cmds/uinput/src/com/android/commands/uinput/Uinput.java
@@ -25,6 +25,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
+import java.util.Objects;
/**
* Uinput class encapsulates execution of "uinput" command. It parses the provided input stream
@@ -96,28 +97,27 @@ public class Uinput {
private void process(Event e) {
final int index = mDevices.indexOfKey(e.getId());
- if (index >= 0) {
- Device d = mDevices.valueAt(index);
- if (Event.COMMAND_DELAY.equals(e.getCommand())) {
- d.addDelay(e.getDuration());
- } else if (Event.COMMAND_INJECT.equals(e.getCommand())) {
- d.injectEvent(e.getInjections());
- } else {
- if (Event.COMMAND_REGISTER.equals(e.getCommand())) {
- error("Device id=" + e.getId() + " is already registered. Ignoring event.");
- } else {
- error("Unknown command \"" + e.getCommand() + "\". Ignoring event.");
- }
+ if (index < 0) {
+ if (e.getCommand() != Event.Command.REGISTER) {
+ Log.e(TAG, "Unknown device id specified. Ignoring event.");
+ return;
}
- } else if (Event.COMMAND_REGISTER.equals(e.getCommand())) {
registerDevice(e);
- } else {
- Log.e(TAG, "Unknown device id specified. Ignoring event.");
+ return;
+ }
+
+ final Device d = mDevices.valueAt(index);
+ switch (Objects.requireNonNull(e.getCommand())) {
+ case REGISTER ->
+ error("Device id=" + e.getId() + " is already registered. Ignoring event.");
+ case INJECT -> d.injectEvent(e.getInjections());
+ case DELAY -> d.addDelay(e.getDuration());
+ case SYNC -> d.syncEvent(e.getSyncToken());
}
}
private void registerDevice(Event e) {
- if (!Event.COMMAND_REGISTER.equals(e.getCommand())) {
+ if (!Event.Command.REGISTER.equals(e.getCommand())) {
throw new IllegalStateException(
"Tried to send command \"" + e.getCommand() + "\" to an unregistered device!");
}