summaryrefslogtreecommitdiff
path: root/cmds
diff options
context:
space:
mode:
Diffstat (limited to 'cmds')
-rw-r--r--cmds/am/src/com/android/commands/am/Instrument.java3
-rw-r--r--cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java29
-rw-r--r--cmds/bootanimation/BootAnimation.cpp90
-rw-r--r--cmds/bootanimation/FORMAT.md1
-rw-r--r--cmds/idmap2/Android.bp6
-rw-r--r--cmds/idmap2/idmap2d/Idmap2Service.cpp13
-rw-r--r--cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl3
-rw-r--r--cmds/idmap2/include/idmap2/BinaryStreamVisitor.h2
-rw-r--r--cmds/idmap2/include/idmap2/FabricatedOverlay.h35
-rw-r--r--cmds/idmap2/include/idmap2/Idmap.h96
-rw-r--r--cmds/idmap2/include/idmap2/ResourceContainer.h10
-rw-r--r--cmds/idmap2/include/idmap2/ResourceMapping.h6
-rw-r--r--cmds/idmap2/include/idmap2/ResourceUtils.h18
-rw-r--r--cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp31
-rw-r--r--cmds/idmap2/libidmap2/FabricatedOverlay.cpp201
-rw-r--r--cmds/idmap2/libidmap2/Idmap.cpp75
-rw-r--r--cmds/idmap2/libidmap2/PolicyUtils.cpp2
-rw-r--r--cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp19
-rw-r--r--cmds/idmap2/libidmap2/RawPrintVisitor.cpp34
-rw-r--r--cmds/idmap2/libidmap2/ResourceContainer.cpp6
-rw-r--r--cmds/idmap2/libidmap2/ResourceMapping.cpp25
-rw-r--r--cmds/idmap2/libidmap2/proto/fabricated_v1.proto1
-rw-r--r--cmds/idmap2/self_targeting/SelfTargeting.cpp205
-rw-r--r--cmds/idmap2/tests/BinaryStreamVisitorTests.cpp6
-rw-r--r--cmds/idmap2/tests/FabricatedOverlayTests.cpp93
-rw-r--r--cmds/idmap2/tests/Idmap2BinaryTests.cpp81
-rw-r--r--cmds/idmap2/tests/IdmapTests.cpp56
-rw-r--r--cmds/idmap2/tests/R.h34
-rw-r--r--cmds/idmap2/tests/RawPrintVisitorTests.cpp34
-rw-r--r--cmds/idmap2/tests/ResourceMappingTests.cpp50
-rw-r--r--cmds/idmap2/tests/ResultTests.cpp5
-rw-r--r--cmds/idmap2/tests/TestConstants.h4
-rw-r--r--cmds/idmap2/tests/TestHelpers.h97
-rw-r--r--cmds/idmap2/tests/data/overlay/res/drawable/android.pngbin0 -> 8341 bytes
-rwxr-xr-xcmds/idmap2/tests/data/target/build6
-rw-r--r--cmds/idmap2/tests/data/target/res/drawable/dr1.pngbin0 -> 546 bytes
-rw-r--r--cmds/idmap2/tests/data/target/res/values/overlayable.xml1
-rw-r--r--cmds/idmap2/tests/data/target/target-no-overlayable.apkbin2391 -> 2761 bytes
-rw-r--r--cmds/idmap2/tests/data/target/target.apkbin5201 -> 5571 bytes
-rw-r--r--cmds/screencap/screencap.cpp46
-rw-r--r--cmds/telecom/src/com/android/commands/telecom/Telecom.java12
-rw-r--r--cmds/uinput/jni/com_android_commands_uinput_Device.cpp12
-rw-r--r--cmds/uinput/jni/com_android_commands_uinput_Device.h1
-rw-r--r--cmds/uinput/src/com/android/commands/uinput/Device.java11
-rw-r--r--cmds/uinput/src/com/android/commands/uinput/Event.java23
-rw-r--r--cmds/uinput/src/com/android/commands/uinput/Uinput.java2
46 files changed, 1108 insertions, 377 deletions
diff --git a/cmds/am/src/com/android/commands/am/Instrument.java b/cmds/am/src/com/android/commands/am/Instrument.java
index 7ff4bc4bcf76..2604497dcb63 100644
--- a/cmds/am/src/com/android/commands/am/Instrument.java
+++ b/cmds/am/src/com/android/commands/am/Instrument.java
@@ -425,7 +425,8 @@ public class Instrument {
if (cn == null) throw new IllegalArgumentException("Bad component name: " + cnArg);
return cn;
} else {
- List<InstrumentationInfo> infos = mPm.queryInstrumentation(null, 0).getList();
+ List<InstrumentationInfo> infos = mPm.queryInstrumentationAsUser(
+ null, 0, userId).getList();
final int numInfos = infos == null ? 0: infos.size();
ArrayList<ComponentName> cns = new ArrayList<>();
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index ed717c491467..699808156033 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -195,10 +195,35 @@ public class Bmgr {
return;
}
+ if ("scheduling".equals(op)) {
+ setSchedulingEnabled(userId);
+ return;
+ }
+
System.err.println("Unknown command");
showUsage();
}
+ private void setSchedulingEnabled(int userId) {
+ String arg = nextArg();
+ if (arg == null) {
+ showUsage();
+ return;
+ }
+
+ try {
+ boolean enable = Boolean.parseBoolean(arg);
+ mBmgr.setFrameworkSchedulingEnabledForUser(userId, enable);
+ System.out.println(
+ "Backup scheduling is now "
+ + (enable ? "enabled" : "disabled")
+ + " for user "
+ + userId);
+ } catch (RemoteException e) {
+ handleRemoteException(e);
+ }
+ }
+
private void handleRemoteException(RemoteException e) {
System.err.println(e.toString());
System.err.println(BMGR_NOT_RUNNING_ERR);
@@ -944,6 +969,7 @@ public class Bmgr {
System.err.println(" bmgr activate BOOL");
System.err.println(" bmgr activated");
System.err.println(" bmgr autorestore BOOL");
+ System.err.println(" bmgr scheduling BOOL");
System.err.println("");
System.err.println("The '--user' option specifies the user on which the operation is run.");
System.err.println("It must be the first argument before the operation.");
@@ -1021,6 +1047,9 @@ public class Bmgr {
System.err.println("");
System.err.println("The 'autorestore' command enables or disables automatic restore when");
System.err.println("a new package is installed.");
+ System.err.println("");
+ System.err.println("The 'scheduling' command enables or disables backup scheduling in the");
+ System.err.println("framework.");
}
private static class BackupMonitor extends IBackupManagerMonitor.Stub {
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 1efdf7759f32..00d9a4bf05f0 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -71,8 +71,6 @@ static const char PRODUCT_BOOTANIMATION_DARK_FILE[] = "/product/media/bootanimat
static const char PRODUCT_BOOTANIMATION_FILE[] = "/product/media/bootanimation.zip";
static const char SYSTEM_BOOTANIMATION_FILE[] = "/system/media/bootanimation.zip";
static const char APEX_BOOTANIMATION_FILE[] = "/apex/com.android.bootanimation/etc/bootanimation.zip";
-static const char PRODUCT_ENCRYPTED_BOOTANIMATION_FILE[] = "/product/media/bootanimation-encrypted.zip";
-static const char SYSTEM_ENCRYPTED_BOOTANIMATION_FILE[] = "/system/media/bootanimation-encrypted.zip";
static const char OEM_SHUTDOWNANIMATION_FILE[] = "/oem/media/shutdownanimation.zip";
static const char PRODUCT_SHUTDOWNANIMATION_FILE[] = "/product/media/shutdownanimation.zip";
static const char SYSTEM_SHUTDOWNANIMATION_FILE[] = "/system/media/shutdownanimation.zip";
@@ -494,28 +492,13 @@ ui::Size BootAnimation::limitSurfaceSize(int width, int height) const {
status_t BootAnimation::readyToRun() {
mAssets.addDefaultAssets();
- mDisplayToken = SurfaceComposerClient::getInternalDisplayToken();
- if (mDisplayToken == nullptr)
+ const std::vector<PhysicalDisplayId> ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ if (ids.empty()) {
+ SLOGE("Failed to get ID for any displays\n");
return NAME_NOT_FOUND;
+ }
- DisplayMode displayMode;
- const status_t error =
- SurfaceComposerClient::getActiveDisplayMode(mDisplayToken, &displayMode);
- if (error != NO_ERROR)
- return error;
-
- mMaxWidth = android::base::GetIntProperty("ro.surface_flinger.max_graphics_width", 0);
- mMaxHeight = android::base::GetIntProperty("ro.surface_flinger.max_graphics_height", 0);
- ui::Size resolution = displayMode.resolution;
- resolution = limitSurfaceSize(resolution.width, resolution.height);
- // create the native surface
- sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
- resolution.getWidth(), resolution.getHeight(), PIXEL_FORMAT_RGB_565,
- ISurfaceComposerClient::eOpaque);
-
- SurfaceComposerClient::Transaction t;
-
- // this guest property specifies multi-display IDs to show the boot animation
+ // this system property specifies multi-display IDs to show the boot animation
// multiple ids can be set with comma (,) as separator, for example:
// setprop persist.boot.animation.displays 19260422155234049,19261083906282754
Vector<PhysicalDisplayId> physicalDisplayIds;
@@ -542,9 +525,44 @@ status_t BootAnimation::readyToRun() {
stream.ignore();
}
+ // the first specified display id is used to retrieve mDisplayToken
+ for (const auto id : physicalDisplayIds) {
+ if (std::find(ids.begin(), ids.end(), id) != ids.end()) {
+ if (const auto token = SurfaceComposerClient::getPhysicalDisplayToken(id)) {
+ mDisplayToken = token;
+ break;
+ }
+ }
+ }
+ }
+
+ // If the system property is not present or invalid, display 0 is used
+ if (mDisplayToken == nullptr) {
+ mDisplayToken = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
+ if (mDisplayToken == nullptr) {
+ return NAME_NOT_FOUND;
+ }
+ }
+
+ DisplayMode displayMode;
+ const status_t error =
+ SurfaceComposerClient::getActiveDisplayMode(mDisplayToken, &displayMode);
+ if (error != NO_ERROR) {
+ return error;
+ }
+
+ mMaxWidth = android::base::GetIntProperty("ro.surface_flinger.max_graphics_width", 0);
+ mMaxHeight = android::base::GetIntProperty("ro.surface_flinger.max_graphics_height", 0);
+ ui::Size resolution = displayMode.resolution;
+ resolution = limitSurfaceSize(resolution.width, resolution.height);
+ // create the native surface
+ sp<SurfaceControl> control = session()->createSurface(String8("BootAnimation"),
+ resolution.getWidth(), resolution.getHeight(), PIXEL_FORMAT_RGB_565,
+ ISurfaceComposerClient::eOpaque);
+
+ SurfaceComposerClient::Transaction t;
+ if (isValid) {
// In the case of multi-display, boot animation shows on the specified displays
- // in addition to the primary display
- const auto ids = SurfaceComposerClient::getPhysicalDisplayIds();
for (const auto id : physicalDisplayIds) {
if (std::find(ids.begin(), ids.end(), id) != ids.end()) {
if (const auto token = SurfaceComposerClient::getPhysicalDisplayToken(id)) {
@@ -572,8 +590,9 @@ status_t BootAnimation::readyToRun() {
eglQuerySurface(display, surface, EGL_WIDTH, &w);
eglQuerySurface(display, surface, EGL_HEIGHT, &h);
- if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE)
+ if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
return NO_INIT;
+ }
mDisplay = display;
mContext = context;
@@ -670,10 +689,6 @@ void BootAnimation::resizeSurface(int newWidth, int newHeight) {
mWidth = limitedSize.width;
mHeight = limitedSize.height;
- SurfaceComposerClient::Transaction t;
- t.setSize(mFlingerSurfaceControl, mWidth, mHeight);
- t.apply();
-
EGLConfig config = getEglConfig(mDisplay);
EGLSurface surface = eglCreateWindowSurface(mDisplay, config, mFlingerSurface.get(), nullptr);
if (eglMakeCurrent(mDisplay, surface, surface, mContext) == EGL_FALSE) {
@@ -707,23 +722,6 @@ bool BootAnimation::findBootAnimationFileInternal(const std::vector<std::string>
}
void BootAnimation::findBootAnimationFile() {
- // If the device has encryption turned on or is in process
- // of being encrypted we show the encrypted boot animation.
- char decrypt[PROPERTY_VALUE_MAX];
- property_get("vold.decrypt", decrypt, "");
-
- bool encryptedAnimation = atoi(decrypt) != 0 ||
- !strcmp("trigger_restart_min_framework", decrypt);
-
- if (!mShuttingDown && encryptedAnimation) {
- static const std::vector<std::string> encryptedBootFiles = {
- PRODUCT_ENCRYPTED_BOOTANIMATION_FILE, SYSTEM_ENCRYPTED_BOOTANIMATION_FILE,
- };
- if (findBootAnimationFileInternal(encryptedBootFiles)) {
- return;
- }
- }
-
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,
diff --git a/cmds/bootanimation/FORMAT.md b/cmds/bootanimation/FORMAT.md
index 64814c8a25e2..988685e23443 100644
--- a/cmds/bootanimation/FORMAT.md
+++ b/cmds/bootanimation/FORMAT.md
@@ -4,7 +4,6 @@
The system selects a boot animation zipfile from the following locations, in order:
- /system/media/bootanimation-encrypted.zip (if getprop("vold.decrypt") = '1')
/system/media/bootanimation.zip
/oem/media/bootanimation.zip
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index aa2113f931c3..5f06c971ba98 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -23,6 +23,7 @@ package {
cc_defaults {
name: "idmap2_defaults",
+ cpp_std: "gnu++2b",
tidy: true,
tidy_checks: [
"modernize-*",
@@ -31,6 +32,7 @@ cc_defaults {
"android-*",
"misc-*",
"readability-*",
+ "-readability-identifier-length",
],
tidy_checks_as_errors: [
"modernize-*",
@@ -55,7 +57,6 @@ cc_defaults {
"-readability-convert-member-functions-to-static",
"-readability-duplicate-include",
"-readability-else-after-return",
- "-readability-identifier-length",
"-readability-named-parameter",
"-readability-redundant-access-specifiers",
"-readability-uppercase-literal-suffix",
@@ -70,6 +71,7 @@ cc_library {
host_supported: true,
srcs: [
"libidmap2/**/*.cpp",
+ "self_targeting/*.cpp",
],
export_include_dirs: ["include"],
target: {
@@ -116,6 +118,7 @@ cc_library {
"libidmap2/proto/*.proto",
],
host_supported: true,
+ tidy: false,
proto: {
type: "lite",
export_proto_headers: true,
@@ -220,6 +223,7 @@ cc_test {
},
data: [
"tests/data/**/*.apk",
+ "tests/data/**/*.png",
],
compile_multilib: "first",
test_options: {
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index e2638106994c..10947dc90a76 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -39,6 +39,7 @@
#include "idmap2/PrettyPrintVisitor.h"
#include "idmap2/Result.h"
#include "idmap2/SysTrace.h"
+#include <fcntl.h>
using android::base::StringPrintf;
using android::binder::Status;
@@ -235,7 +236,16 @@ Status Idmap2Service::createFabricatedOverlay(
}
for (const auto& res : overlay.entries) {
- builder.SetResourceValue(res.resourceName, res.dataType, res.data);
+ if (res.dataType == Res_value::TYPE_STRING) {
+ builder.SetResourceValue(res.resourceName, res.dataType, res.stringData.value(),
+ 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()));
+ } else {
+ builder.SetResourceValue(res.resourceName, res.dataType, res.data,
+ res.configuration.value_or(std::string()));
+ }
}
// Generate the file path of the fabricated overlay and ensure it does not collide with an
@@ -258,6 +268,7 @@ Status Idmap2Service::createFabricatedOverlay(
file_name.c_str(), kMaxFileNameLength));
}
} while (std::filesystem::exists(path));
+ builder.setFrroPath(path);
const uid_t uid = IPCThreadState::self()->getCallingUid();
if (!UidHasWriteAccessToPath(uid, path)) {
diff --git a/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl b/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl
index 6c2af274ae32..3ad6d58e8253 100644
--- a/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl
+++ b/cmds/idmap2/idmap2d/aidl/core/android/os/FabricatedOverlayInternalEntry.aidl
@@ -23,4 +23,7 @@ parcelable FabricatedOverlayInternalEntry {
@utf8InCpp String resourceName;
int dataType;
int data;
+ @nullable @utf8InCpp String stringData;
+ @nullable ParcelFileDescriptor binaryData;
+ @nullable @utf8InCpp String configuration;
} \ No newline at end of file
diff --git a/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h b/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h
index 5e189f2c1340..7b38bd11d847 100644
--- a/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h
+++ b/cmds/idmap2/include/idmap2/BinaryStreamVisitor.h
@@ -39,7 +39,7 @@ class BinaryStreamVisitor : public Visitor {
void Write8(uint8_t value);
void Write16(uint16_t value);
void Write32(uint32_t value);
- void WriteString(const StringPiece& value);
+ void WriteString(StringPiece value);
std::ostream& stream_;
};
diff --git a/cmds/idmap2/include/idmap2/FabricatedOverlay.h b/cmds/idmap2/include/idmap2/FabricatedOverlay.h
index 375671881e5f..9f57710edb0b 100644
--- a/cmds/idmap2/include/idmap2/FabricatedOverlay.h
+++ b/cmds/idmap2/include/idmap2/FabricatedOverlay.h
@@ -28,6 +28,7 @@
#include "idmap2/ResourceContainer.h"
#include "idmap2/Result.h"
+#include <binder/ParcelFileDescriptor.h>
namespace android::idmap2 {
@@ -39,7 +40,20 @@ struct FabricatedOverlay {
Builder& SetOverlayable(const std::string& name);
Builder& SetResourceValue(const std::string& resource_name, uint8_t data_type,
- uint32_t data_value);
+ uint32_t data_value, const std::string& configuration);
+
+ Builder& SetResourceValue(const std::string& resource_name, uint8_t data_type,
+ const std::string& data_string_value,
+ const std::string& configuration);
+
+ Builder& SetResourceValue(const std::string& resource_name,
+ std::optional<android::base::borrowed_fd>&& binary_value,
+ const std::string& configuration);
+
+ inline Builder& setFrroPath(std::string frro_path) {
+ frro_path_ = std::move(frro_path);
+ return *this;
+ }
WARN_UNUSED Result<FabricatedOverlay> Build();
@@ -48,12 +62,16 @@ struct FabricatedOverlay {
std::string resource_name;
DataType data_type;
DataValue data_value;
+ std::string data_string_value;
+ std::optional<android::base::borrowed_fd> data_binary_value;
+ std::string configuration;
};
std::string package_name_;
std::string name_;
std::string target_package_name_;
std::string target_overlayable_;
+ std::string frro_path_;
std::vector<Entry> entries_;
};
@@ -62,18 +80,25 @@ struct FabricatedOverlay {
private:
struct SerializedData {
- std::unique_ptr<uint8_t[]> data;
- size_t data_size;
- uint32_t crc;
- };
+ std::unique_ptr<uint8_t[]> pb_data;
+ size_t pb_data_size;
+ uint32_t pb_crc;
+ std::string sp_data;
+ };
Result<SerializedData*> InitializeData() const;
Result<uint32_t> GetCrc() const;
explicit FabricatedOverlay(pb::FabricatedOverlay&& overlay,
+ std::string&& string_pool_data_,
+ std::vector<android::base::borrowed_fd> 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_;
+ uint32_t total_binary_bytes_;
std::optional<uint32_t> crc_from_disk_;
mutable std::optional<SerializedData> data_;
diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h
index 58aff42b1e98..03e714a3847e 100644
--- a/cmds/idmap2/include/idmap2/Idmap.h
+++ b/cmds/idmap2/include/idmap2/Idmap.h
@@ -21,42 +21,51 @@
* header := magic version target_crc overlay_crc fulfilled_policies
* enforce_overlayable target_path overlay_path overlay_name
* debug_info
- * data := data_header target_entry* target_inline_entry* overlay_entry*
- * string_pool
- * data_header := target_entry_count target_inline_entry_count overlay_entry_count
+ * data := data_header target_entry* target_inline_entry*
+ target_inline_entry_value* config* overlay_entry* string_pool
+ * data_header := target_entry_count target_inline_entry_count
+ target_inline_entry_value_count config_count overlay_entry_count
* string_pool_index
* target_entry := target_id overlay_id
- * target_inline_entry := target_id Res_value::size padding(1) Res_value::type
+ * target_inline_entry := target_id start_value_index value_count
+ * target_inline_entry_value := config_index Res_value::size padding(1) Res_value::type
+ * Res_value::value
+ * config := target_id Res_value::size padding(1) Res_value::type
* Res_value::value
* overlay_entry := overlay_id target_id
*
- * debug_info := string
- * enforce_overlayable := <uint32_t>
- * fulfilled_policies := <uint32_t>
- * magic := <uint32_t>
- * overlay_crc := <uint32_t>
- * overlay_entry_count := <uint32_t>
- * overlay_id := <uint32_t>
- * overlay_package_id := <uint8_t>
- * overlay_name := string
- * overlay_path := string
- * padding(n) := <uint8_t>[n]
- * Res_value::size := <uint16_t>
- * Res_value::type := <uint8_t>
- * Res_value::value := <uint32_t>
- * string := <uint32_t> <uint8_t>+ padding(n)
- * string_pool := string
- * string_pool_index := <uint32_t>
- * string_pool_length := <uint32_t>
- * target_crc := <uint32_t>
- * target_entry_count := <uint32_t>
- * target_inline_entry_count := <uint32_t>
- * target_id := <uint32_t>
- * target_package_id := <uint8_t>
- * target_path := string
- * value_type := <uint8_t>
- * value_data := <uint32_t>
- * version := <uint32_t>
+ * debug_info := string
+ * enforce_overlayable := <uint32_t>
+ * fulfilled_policies := <uint32_t>
+ * magic := <uint32_t>
+ * overlay_crc := <uint32_t>
+ * overlay_entry_count := <uint32_t>
+ * overlay_id := <uint32_t>
+ * overlay_package_id := <uint8_t>
+ * overlay_name := string
+ * overlay_path := string
+ * padding(n) := <uint8_t>[n]
+ * Res_value::size := <uint16_t>
+ * Res_value::type := <uint8_t>
+ * Res_value::value := <uint32_t>
+ * string := <uint32_t> <uint8_t>+ padding(n)
+ * string_pool := string
+ * string_pool_index := <uint32_t>
+ * string_pool_length := <uint32_t>
+ * target_crc := <uint32_t>
+ * target_entry_count := <uint32_t>
+ * target_inline_entry_count := <uint32_t>
+ * target_inline_entry_value_count := <uint32_t>
+ * config_count := <uint32_t>
+ * config_index := <uint32_t>
+ * start_value_index := <uint32_t>
+ * value_count := <uint32_t>
+ * target_id := <uint32_t>
+ * target_package_id := <uint8_t>
+ * target_path := string
+ * value_type := <uint8_t>
+ * value_data := <uint32_t>
+ * version := <uint32_t>
*/
#ifndef IDMAP2_INCLUDE_IDMAP2_IDMAP_H_
@@ -70,6 +79,7 @@
#include "android-base/macros.h"
#include "androidfw/ResourceTypes.h"
#include "androidfw/StringPiece.h"
+#include "androidfw/ConfigDescription.h"
#include "idmap2/ResourceContainer.h"
#include "idmap2/ResourceMapping.h"
@@ -165,19 +175,27 @@ class IdmapData {
public:
static std::unique_ptr<const Header> FromBinaryStream(std::istream& stream);
- inline uint32_t GetTargetEntryCount() const {
+ [[nodiscard]] inline uint32_t GetTargetEntryCount() const {
return target_entry_count;
}
- inline uint32_t GetTargetInlineEntryCount() const {
+ [[nodiscard]] inline uint32_t GetTargetInlineEntryCount() const {
return target_entry_inline_count;
}
- inline uint32_t GetOverlayEntryCount() const {
+ [[nodiscard]] inline uint32_t GetTargetInlineEntryValueCount() const {
+ return target_entry_inline_value_count;
+ }
+
+ [[nodiscard]] inline uint32_t GetConfigCount() const {
+ return config_count;
+ }
+
+ [[nodiscard]] inline uint32_t GetOverlayEntryCount() const {
return overlay_entry_count;
}
- inline uint32_t GetStringPoolIndexOffset() const {
+ [[nodiscard]] inline uint32_t GetStringPoolIndexOffset() const {
return string_pool_index_offset;
}
@@ -186,6 +204,8 @@ class IdmapData {
private:
uint32_t target_entry_count;
uint32_t target_entry_inline_count;
+ uint32_t target_entry_inline_value_count;
+ uint32_t config_count;
uint32_t overlay_entry_count;
uint32_t string_pool_index_offset;
Header() = default;
@@ -202,7 +222,7 @@ class IdmapData {
struct TargetInlineEntry {
ResourceId target_id;
- TargetValue value;
+ std::map<ConfigDescription, TargetValue> values;
};
struct OverlayEntry {
@@ -227,11 +247,11 @@ class IdmapData {
return target_inline_entries_;
}
- const std::vector<OverlayEntry>& GetOverlayEntries() const {
+ [[nodiscard]] const std::vector<OverlayEntry>& GetOverlayEntries() const {
return overlay_entries_;
}
- const std::string& GetStringPoolData() const {
+ [[nodiscard]] const std::string& GetStringPoolData() const {
return string_pool_data_;
}
diff --git a/cmds/idmap2/include/idmap2/ResourceContainer.h b/cmds/idmap2/include/idmap2/ResourceContainer.h
index c3ba4640bd77..4d2832113f71 100644
--- a/cmds/idmap2/include/idmap2/ResourceContainer.h
+++ b/cmds/idmap2/include/idmap2/ResourceContainer.h
@@ -46,14 +46,6 @@ struct TargetResourceContainer : public ResourceContainer {
~TargetResourceContainer() override = default;
};
-struct OverlayManifestInfo {
- std::string package_name; // NOLINT(misc-non-private-member-variables-in-classes)
- std::string name; // NOLINT(misc-non-private-member-variables-in-classes)
- std::string target_package; // NOLINT(misc-non-private-member-variables-in-classes)
- std::string target_name; // NOLINT(misc-non-private-member-variables-in-classes)
- ResourceId resource_mapping; // NOLINT(misc-non-private-member-variables-in-classes)
-};
-
struct OverlayData {
struct ResourceIdValue {
// The overlay resource id.
@@ -66,7 +58,7 @@ struct OverlayData {
struct Value {
std::string resource_name;
- std::variant<ResourceIdValue, TargetValue> value;
+ std::variant<ResourceIdValue, TargetValueWithConfig> value;
};
struct InlineStringPoolData {
diff --git a/cmds/idmap2/include/idmap2/ResourceMapping.h b/cmds/idmap2/include/idmap2/ResourceMapping.h
index 5a0a384f75a3..4bad2fa392a2 100644
--- a/cmds/idmap2/include/idmap2/ResourceMapping.h
+++ b/cmds/idmap2/include/idmap2/ResourceMapping.h
@@ -33,7 +33,8 @@
using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
namespace android::idmap2 {
-using TargetResourceMap = std::map<ResourceId, std::variant<ResourceId, TargetValue>>;
+using ConfigMap = std::unordered_map<std::string, TargetValue>;
+using TargetResourceMap = std::map<ResourceId, std::variant<ResourceId, ConfigMap>>;
using OverlayResourceMap = std::map<ResourceId, ResourceId>;
class ResourceMapping {
@@ -69,7 +70,8 @@ class ResourceMapping {
// If `allow_rewriting_` is true, then the overlay-to-target map will be populated if the target
// resource id is mapped to an overlay resource id.
Result<Unit> AddMapping(ResourceId target_resource,
- const std::variant<OverlayData::ResourceIdValue, TargetValue>& value);
+ const std::variant<OverlayData::ResourceIdValue,
+ TargetValueWithConfig>& value);
TargetResourceMap target_map_;
OverlayResourceMap overlay_map_;
diff --git a/cmds/idmap2/include/idmap2/ResourceUtils.h b/cmds/idmap2/include/idmap2/ResourceUtils.h
index a0202dfee473..c2b0abed442c 100644
--- a/cmds/idmap2/include/idmap2/ResourceUtils.h
+++ b/cmds/idmap2/include/idmap2/ResourceUtils.h
@@ -19,6 +19,7 @@
#include <optional>
#include <string>
+#include <android-base/unique_fd.h>
#include "androidfw/AssetManager2.h"
#include "idmap2/Result.h"
@@ -29,17 +30,28 @@ namespace android::idmap2 {
#define EXTRACT_ENTRY(resid) (0x0000ffff & (resid))
// use typedefs to let the compiler warn us about implicit casts
-using ResourceId = uint32_t; // 0xpptteeee
+using ResourceId = android::ResourceId; // 0xpptteeee
using PackageId = uint8_t; // pp in 0xpptteeee
using TypeId = uint8_t; // tt in 0xpptteeee
using EntryId = uint16_t; // eeee in 0xpptteeee
-using DataType = uint8_t; // Res_value::dataType
-using DataValue = uint32_t; // Res_value::data
+using DataType = android::DataType; // Res_value::dataType
+using DataValue = android::DataValue; // Res_value::data
struct TargetValue {
DataType data_type;
DataValue data_value;
+ std::string data_string_value;
+ std::optional<android::base::borrowed_fd> data_binary_value;
+};
+
+struct TargetValueWithConfig {
+ TargetValue value;
+ std::string config;
+
+ [[nodiscard]] std::pair<std::string, TargetValue> to_pair() const {
+ return std::make_pair(config, value);
+ }
};
namespace utils {
diff --git a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
index 3bbe9d91deb6..89769246434a 100644
--- a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
+++ b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
@@ -38,7 +38,7 @@ void BinaryStreamVisitor::Write32(uint32_t value) {
stream_.write(reinterpret_cast<char*>(&x), sizeof(uint32_t));
}
-void BinaryStreamVisitor::WriteString(const StringPiece& value) {
+void BinaryStreamVisitor::WriteString(StringPiece value) {
// pad with null to nearest word boundary;
size_t padding_size = CalculatePadding(value.size());
Write32(value.size());
@@ -70,12 +70,35 @@ void BinaryStreamVisitor::visit(const IdmapData& data) {
}
static constexpr uint16_t kValueSize = 8U;
+ std::vector<std::pair<ConfigDescription, TargetValue>> target_values;
+ target_values.reserve(data.GetHeader()->GetTargetInlineEntryValueCount());
for (const auto& target_entry : data.GetTargetInlineEntries()) {
Write32(target_entry.target_id);
+ Write32(target_values.size());
+ Write32(target_entry.values.size());
+ target_values.insert(
+ target_values.end(), target_entry.values.begin(), target_entry.values.end());
+ }
+
+ std::vector<ConfigDescription> configs;
+ configs.reserve(data.GetHeader()->GetConfigCount());
+ for (const auto& target_entry_value : target_values) {
+ auto config_it = find(configs.begin(), configs.end(), target_entry_value.first);
+ if (config_it != configs.end()) {
+ Write32(config_it - configs.begin());
+ } else {
+ Write32(configs.size());
+ configs.push_back(target_entry_value.first);
+ }
Write16(kValueSize);
Write8(0U); // padding
- Write8(target_entry.value.data_type);
- Write32(target_entry.value.data_value);
+ Write8(target_entry_value.second.data_type);
+ Write32(target_entry_value.second.data_value);
+ }
+
+ for( auto& cd : configs) {
+ cd.swapHtoD();
+ stream_.write(reinterpret_cast<char*>(&cd), sizeof(cd));
}
for (const auto& overlay_entry : data.GetOverlayEntries()) {
@@ -89,6 +112,8 @@ void BinaryStreamVisitor::visit(const IdmapData& data) {
void BinaryStreamVisitor::visit(const IdmapData::Header& header) {
Write32(header.GetTargetEntryCount());
Write32(header.GetTargetInlineEntryCount());
+ Write32(header.GetTargetInlineEntryValueCount());
+ Write32(header.GetConfigCount());
Write32(header.GetOverlayEntryCount());
Write32(header.GetStringPoolIndexOffset());
}
diff --git a/cmds/idmap2/libidmap2/FabricatedOverlay.cpp b/cmds/idmap2/libidmap2/FabricatedOverlay.cpp
index 8352dbb7b619..dd5be21cd164 100644
--- a/cmds/idmap2/libidmap2/FabricatedOverlay.cpp
+++ b/cmds/idmap2/libidmap2/FabricatedOverlay.cpp
@@ -16,9 +16,14 @@
#include "idmap2/FabricatedOverlay.h"
+#include <sys/stat.h> // umask
+#include <sys/types.h> // umask
+
+#include <android-base/file.h>
#include <androidfw/ResourceUtils.h>
+#include <androidfw/StringPool.h>
#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/io/zero_copy_stream_impl_lite.h>
+#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <utils/ByteOrder.h>
#include <zlib.h>
@@ -30,6 +35,8 @@
namespace android::idmap2 {
+constexpr auto kBufferSize = 1024;
+
namespace {
bool Read32(std::istream& stream, uint32_t* out) {
uint32_t value;
@@ -47,8 +54,15 @@ void Write32(std::ostream& stream, uint32_t value) {
} // namespace
FabricatedOverlay::FabricatedOverlay(pb::FabricatedOverlay&& overlay,
+ std::string&& string_pool_data,
+ std::vector<android::base::borrowed_fd> binary_files,
+ off_t total_binary_bytes,
std::optional<uint32_t> crc_from_disk)
- : overlay_pb_(std::forward<pb::FabricatedOverlay>(overlay)), crc_from_disk_(crc_from_disk) {
+ : overlay_pb_(std::forward<pb::FabricatedOverlay>(overlay)),
+ string_pool_data_(std::move(string_pool_data)),
+ binary_files_(std::move(binary_files)),
+ total_binary_bytes_(total_binary_bytes),
+ crc_from_disk_(crc_from_disk) {
}
FabricatedOverlay::Builder::Builder(const std::string& package_name, const std::string& name,
@@ -64,13 +78,35 @@ FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetOverlayable(const std
}
FabricatedOverlay::Builder& FabricatedOverlay::Builder::SetResourceValue(
- const std::string& resource_name, uint8_t data_type, uint32_t data_value) {
- entries_.emplace_back(Entry{resource_name, data_type, data_value});
+ 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});
+ return *this;
+}
+
+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});
+ 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});
return *this;
}
Result<FabricatedOverlay> FabricatedOverlay::Builder::Build() {
- std::map<std::string, std::map<std::string, std::map<std::string, TargetValue>>> entries;
+ using ConfigMap = std::map<std::string, TargetValue, std::less<>>;
+ using EntryMap = std::map<std::string, ConfigMap, std::less<>>;
+ using TypeMap = std::map<std::string, EntryMap, std::less<>>;
+ using PackageMap = std::map<std::string, TypeMap, std::less<>>;
+ PackageMap package_map;
+ android::StringPool string_pool;
for (const auto& res_entry : entries_) {
StringPiece package_substr;
StringPiece type_name;
@@ -80,8 +116,7 @@ Result<FabricatedOverlay> FabricatedOverlay::Builder::Build() {
return Error("failed to parse resource name '%s'", res_entry.resource_name.c_str());
}
- std::string package_name =
- package_substr.empty() ? target_package_name_ : package_substr.to_string();
+ std::string_view package_name = package_substr.empty() ? target_package_name_ : package_substr;
if (type_name.empty()) {
return Error("resource name '%s' missing type name", res_entry.resource_name.c_str());
}
@@ -90,28 +125,30 @@ Result<FabricatedOverlay> FabricatedOverlay::Builder::Build() {
return Error("resource name '%s' missing entry name", res_entry.resource_name.c_str());
}
- auto package = entries.find(package_name);
- if (package == entries.end()) {
- package = entries
- .insert(std::make_pair(
- package_name, std::map<std::string, std::map<std::string, TargetValue>>()))
+ auto package = package_map.find(package_name);
+ if (package == package_map.end()) {
+ package = package_map
+ .insert(std::make_pair(package_name, TypeMap()))
.first;
}
- auto type = package->second.find(type_name.to_string());
+ auto type = package->second.find(type_name);
if (type == package->second.end()) {
- type =
- package->second
- .insert(std::make_pair(type_name.to_string(), std::map<std::string, TargetValue>()))
- .first;
+ type = package->second.insert(std::make_pair(type_name, EntryMap())).first;
}
- auto entry = type->second.find(entry_name.to_string());
+ auto entry = type->second.find(entry_name);
if (entry == type->second.end()) {
- entry = type->second.insert(std::make_pair(entry_name.to_string(), TargetValue())).first;
+ entry = type->second.insert(std::make_pair(entry_name, ConfigMap())).first;
}
- entry->second = TargetValue{res_entry.data_type, res_entry.data_value};
+ auto value = entry->second.find(res_entry.configuration);
+ if (value == entry->second.end()) {
+ value = entry->second.insert(std::make_pair(res_entry.configuration, TargetValue())).first;
+ }
+
+ value->second = TargetValue{res_entry.data_type, res_entry.data_value,
+ res_entry.data_string_value, res_entry.data_binary_value};
}
pb::FabricatedOverlay overlay_pb;
@@ -120,25 +157,54 @@ Result<FabricatedOverlay> FabricatedOverlay::Builder::Build() {
overlay_pb.set_target_package_name(target_package_name_);
overlay_pb.set_target_overlayable(target_overlayable_);
- for (const auto& package : entries) {
+ std::vector<android::base::borrowed_fd> 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;
+
+ for (auto& package : package_map) {
auto package_pb = overlay_pb.add_packages();
package_pb->set_name(package.first);
- for (const auto& type : package.second) {
+ for (auto& type : package.second) {
auto type_pb = package_pb->add_types();
type_pb->set_name(type.first);
- for (const auto& entry : type.second) {
- auto entry_pb = type_pb->add_entries();
- entry_pb->set_name(entry.first);
- pb::ResourceValue* value = entry_pb->mutable_res_value();
- value->set_data_type(entry.second.data_type);
- value->set_data_value(entry.second.data_value);
+ for (auto& entry : type.second) {
+ for (const auto& value: entry.second) {
+ auto entry_pb = type_pb->add_entries();
+ entry_pb->set_name(entry.first);
+ entry_pb->set_configuration(value.first);
+ pb::ResourceValue* pb_value = entry_pb->mutable_res_value();
+ pb_value->set_data_type(value.second.data_type);
+ if (value.second.data_type == Res_value::TYPE_STRING) {
+ auto ref = string_pool.MakeRef(value.second.data_string_value);
+ 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());
+ auto ref = string_pool.MakeRef(std::move(uri));
+ pb_value->set_data_value(ref.index());
+ } else {
+ pb_value->set_data_value(value.second.data_value);
+ }
+ }
}
}
}
-
- return FabricatedOverlay(std::move(overlay_pb));
+ android::BigBuffer string_buffer(kBufferSize);
+ android::StringPool::FlattenUtf8(&string_buffer, string_pool, nullptr);
+ return FabricatedOverlay(std::move(overlay_pb), string_buffer.to_string(),
+ std::move(binary_files), total_binary_bytes);
}
Result<FabricatedOverlay> FabricatedOverlay::FromBinaryStream(std::istream& stream) {
@@ -156,16 +222,35 @@ Result<FabricatedOverlay> FabricatedOverlay::FromBinaryStream(std::istream& stre
return Error("Failed to read fabricated overlay version.");
}
- if (version != 1) {
+ if (version < 1 || version > 3) {
return Error("Invalid fabricated overlay version '%u'.", version);
}
uint32_t crc;
if (!Read32(stream, &crc)) {
- return Error("Failed to read fabricated overlay version.");
+ return Error("Failed to read fabricated overlay crc.");
}
pb::FabricatedOverlay overlay{};
+ std::string sp_data;
+ uint32_t total_binary_bytes;
+ if (version == 3) {
+ if (!Read32(stream, &total_binary_bytes)) {
+ return Error("Failed read total binary bytes.");
+ }
+ stream.seekg(total_binary_bytes, std::istream::cur);
+ }
+ if (version >= 2) {
+ uint32_t sp_size;
+ if (!Read32(stream, &sp_size)) {
+ return Error("Failed read string pool size.");
+ }
+ std::string buf(sp_size, '\0');
+ if (!stream.read(buf.data(), sp_size)) {
+ return Error("Failed to read string pool.");
+ }
+ sp_data = buf;
+ }
if (!overlay.ParseFromIstream(&stream)) {
return Error("Failed read fabricated overlay proto.");
}
@@ -173,31 +258,33 @@ Result<FabricatedOverlay> FabricatedOverlay::FromBinaryStream(std::istream& stre
// If the proto version is the latest version, then the contents of the proto must be the same
// when the proto is re-serialized; otherwise, the crc must be calculated because migrating the
// proto to the latest version will likely change the contents of the fabricated overlay.
- return FabricatedOverlay(std::move(overlay), version == kFabricatedOverlayCurrentVersion
+ return FabricatedOverlay(std::move(overlay), std::move(sp_data), {}, total_binary_bytes,
+ version == kFabricatedOverlayCurrentVersion
? std::optional<uint32_t>(crc)
: std::nullopt);
}
Result<FabricatedOverlay::SerializedData*> FabricatedOverlay::InitializeData() const {
if (!data_.has_value()) {
- auto size = overlay_pb_.ByteSizeLong();
- auto data = std::unique_ptr<uint8_t[]>(new uint8_t[size]);
+ auto pb_size = overlay_pb_.ByteSizeLong();
+ auto pb_data = std::unique_ptr<uint8_t[]>(new uint8_t[pb_size]);
// Ensure serialization is deterministic
- google::protobuf::io::ArrayOutputStream array_stream(data.get(), size);
+ google::protobuf::io::ArrayOutputStream array_stream(pb_data.get(), pb_size);
google::protobuf::io::CodedOutputStream output_stream(&array_stream);
output_stream.SetSerializationDeterministic(true);
overlay_pb_.SerializeWithCachedSizes(&output_stream);
- if (output_stream.HadError() || size != output_stream.ByteCount()) {
+ if (output_stream.HadError() || pb_size != output_stream.ByteCount()) {
return Error("Failed to serialize fabricated overlay.");
}
// Calculate the crc using the proto data and the version.
- uint32_t crc = crc32(0L, Z_NULL, 0);
- crc = crc32(crc, reinterpret_cast<const uint8_t*>(&kFabricatedOverlayCurrentVersion),
+ uint32_t pb_crc = crc32(0L, Z_NULL, 0);
+ pb_crc = crc32(pb_crc, reinterpret_cast<const uint8_t*>(&kFabricatedOverlayCurrentVersion),
sizeof(uint32_t));
- crc = crc32(crc, data.get(), size);
- data_ = SerializedData{std::move(data), size, crc};
+ pb_crc = crc32(pb_crc, pb_data.get(), pb_size);
+
+ data_ = SerializedData{std::move(pb_data), pb_size, pb_crc, string_pool_data_};
}
return &(*data_);
}
@@ -209,7 +296,7 @@ Result<uint32_t> FabricatedOverlay::GetCrc() const {
if (!data) {
return data.GetError();
}
- return (*data)->crc;
+ return (*data)->pb_crc;
}
Result<Unit> FabricatedOverlay::ToBinaryStream(std::ostream& stream) const {
@@ -220,8 +307,21 @@ Result<Unit> FabricatedOverlay::ToBinaryStream(std::ostream& stream) const {
Write32(stream, kFabricatedOverlayMagic);
Write32(stream, kFabricatedOverlayCurrentVersion);
- Write32(stream, (*data)->crc);
- stream.write(reinterpret_cast<const char*>((*data)->data.get()), (*data)->data_size);
+ 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)) {
+ return Error("Failed to read binary file data.");
+ }
+ stream.write(file_contents.data(), file_contents.length());
+ }
+ Write32(stream, (*data)->sp_data.length());
+ stream.write((*data)->sp_data.data(), (*data)->sp_data.length());
+ if (stream.bad()) {
+ return Error("Failed to write string pool data.");
+ }
+ stream.write(reinterpret_cast<const char*>((*data)->pb_data.get()), (*data)->pb_data_size);
if (stream.bad()) {
return Error("Failed to write serialized fabricated overlay.");
}
@@ -283,11 +383,20 @@ Result<OverlayData> FabContainer::GetOverlayData(const OverlayManifestInfo& info
entry.name().c_str());
const auto& res_value = entry.res_value();
result.pairs.emplace_back(OverlayData::Value{
- name, TargetValue{.data_type = static_cast<uint8_t>(res_value.data_type()),
- .data_value = res_value.data_value()}});
+ name, TargetValueWithConfig{.config = entry.configuration(), .value = TargetValue{
+ .data_type = static_cast<uint8_t>(res_value.data_type()),
+ .data_value = res_value.data_value()}}});
}
}
}
+ const uint32_t string_pool_data_length = overlay_.string_pool_data_.length();
+ result.string_pool_data = OverlayData::InlineStringPoolData{
+ .data = std::unique_ptr<uint8_t[]>(new uint8_t[string_pool_data_length]),
+ .data_length = string_pool_data_length,
+ .string_pool_offset = 0,
+ };
+ memcpy(result.string_pool_data->data.get(), overlay_.string_pool_data_.data(),
+ string_pool_data_length);
return result;
}
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index 06650f681b24..7c0b937122c7 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -77,8 +77,7 @@ bool WARN_UNUSED ReadString(std::istream& stream, std::string* out) {
return false;
}
uint32_t padding_size = CalculatePadding(size);
- std::string padding(padding_size, '\0');
- if (!stream.read(padding.data(), padding_size)) {
+ if (padding_size != 0 && !stream.seekg(padding_size, std::ios_base::cur)) {
return false;
}
*out = buf;
@@ -186,6 +185,8 @@ std::unique_ptr<const IdmapData::Header> IdmapData::Header::FromBinaryStream(std
std::unique_ptr<IdmapData::Header> idmap_data_header(new IdmapData::Header());
if (!Read32(stream, &idmap_data_header->target_entry_count) ||
!Read32(stream, &idmap_data_header->target_entry_inline_count) ||
+ !Read32(stream, &idmap_data_header->target_entry_inline_value_count) ||
+ !Read32(stream, &idmap_data_header->config_count) ||
!Read32(stream, &idmap_data_header->overlay_entry_count) ||
!Read32(stream, &idmap_data_header->string_pool_index_offset)) {
return nullptr;
@@ -207,20 +208,59 @@ std::unique_ptr<const IdmapData> IdmapData::FromBinaryStream(std::istream& strea
if (!Read32(stream, &target_entry.target_id) || !Read32(stream, &target_entry.overlay_id)) {
return nullptr;
}
- data->target_entries_.push_back(target_entry);
+ data->target_entries_.emplace_back(target_entry);
}
// Read the mapping of target resource id to inline overlay values.
- uint8_t unused1;
- uint16_t unused2;
+ std::vector<std::tuple<TargetInlineEntry, uint32_t, uint32_t>> target_inline_entries;
for (size_t i = 0; i < data->header_->GetTargetInlineEntryCount(); i++) {
TargetInlineEntry target_entry{};
- if (!Read32(stream, &target_entry.target_id) || !Read16(stream, &unused2) ||
- !Read8(stream, &unused1) || !Read8(stream, &target_entry.value.data_type) ||
- !Read32(stream, &target_entry.value.data_value)) {
+ uint32_t entry_offset;
+ uint32_t entry_count;
+ if (!Read32(stream, &target_entry.target_id) || !Read32(stream, &entry_offset)
+ || !Read32(stream, &entry_count)) {
return nullptr;
}
- data->target_inline_entries_.push_back(target_entry);
+ target_inline_entries.emplace_back(target_entry, entry_offset, entry_count);
+ }
+
+ // Read the inline overlay resource values
+ std::vector<std::pair<uint32_t, TargetValue>> target_values;
+ uint8_t unused1;
+ uint16_t unused2;
+ for (size_t i = 0; i < data->header_->GetTargetInlineEntryValueCount(); i++) {
+ uint32_t config_index;
+ if (!Read32(stream, &config_index)) {
+ return nullptr;
+ }
+ TargetValue value;
+ if (!Read16(stream, &unused2)
+ || !Read8(stream, &unused1)
+ || !Read8(stream, &value.data_type)
+ || !Read32(stream, &value.data_value)) {
+ return nullptr;
+ }
+ target_values.emplace_back(config_index, value);
+ }
+
+ // Read the configurations
+ std::vector<ConfigDescription> configurations;
+ for (size_t i = 0; i < data->header_->GetConfigCount(); i++) {
+ ConfigDescription cd;
+ if (!stream.read(reinterpret_cast<char*>(&cd), sizeof(ConfigDescription))) {
+ return nullptr;
+ }
+ configurations.emplace_back(cd);
+ }
+
+ // Construct complete target inline entries
+ for (auto [target_entry, entry_offset, entry_count] : target_inline_entries) {
+ for(size_t i = 0; i < entry_count; i++) {
+ const auto& target_value = target_values[entry_offset + i];
+ const auto& config = configurations[target_value.first];
+ target_entry.values[config] = target_value.second;
+ }
+ data->target_inline_entries_.emplace_back(target_entry);
}
// Read the mapping of overlay resource id to target resource id.
@@ -277,13 +317,22 @@ Result<std::unique_ptr<const IdmapData>> IdmapData::FromResourceMapping(
}
std::unique_ptr<IdmapData> data(new IdmapData());
- data->string_pool_data_ = resource_mapping.GetStringPoolData().to_string();
+ data->string_pool_data_ = std::string(resource_mapping.GetStringPoolData());
+ uint32_t inline_value_count = 0;
+ std::set<std::string> config_set;
for (const auto& mapping : resource_mapping.GetTargetToOverlayMap()) {
if (auto overlay_resource = std::get_if<ResourceId>(&mapping.second)) {
data->target_entries_.push_back({mapping.first, *overlay_resource});
} else {
- data->target_inline_entries_.push_back(
- {mapping.first, std::get<TargetValue>(mapping.second)});
+ std::map<ConfigDescription, TargetValue> values;
+ for (const auto& [config, value] : std::get<ConfigMap>(mapping.second)) {
+ config_set.insert(config);
+ ConfigDescription cd;
+ ConfigDescription::Parse(config, &cd);
+ values[cd] = value;
+ inline_value_count++;
+ }
+ data->target_inline_entries_.push_back({mapping.first, values});
}
}
@@ -295,6 +344,8 @@ Result<std::unique_ptr<const IdmapData>> IdmapData::FromResourceMapping(
data_header->target_entry_count = static_cast<uint32_t>(data->target_entries_.size());
data_header->target_entry_inline_count =
static_cast<uint32_t>(data->target_inline_entries_.size());
+ data_header->target_entry_inline_value_count = inline_value_count;
+ data_header->config_count = config_set.size();
data_header->overlay_entry_count = static_cast<uint32_t>(data->overlay_entries_.size());
data_header->string_pool_index_offset = resource_mapping.GetStringPoolOffset();
data->header_ = std::move(data_header);
diff --git a/cmds/idmap2/libidmap2/PolicyUtils.cpp b/cmds/idmap2/libidmap2/PolicyUtils.cpp
index 4e3f54d2583e..76c70cab6296 100644
--- a/cmds/idmap2/libidmap2/PolicyUtils.cpp
+++ b/cmds/idmap2/libidmap2/PolicyUtils.cpp
@@ -53,7 +53,7 @@ std::vector<std::string> BitmaskToPolicies(const PolicyBitmask& bitmask) {
for (const auto& policy : kPolicyStringToFlag) {
if ((bitmask & policy.second) != 0) {
- policies.emplace_back(policy.first.to_string());
+ policies.emplace_back(policy.first);
}
}
diff --git a/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp b/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp
index d10a2785aaba..a44fa756aa1c 100644
--- a/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp
+++ b/cmds/idmap2/libidmap2/PrettyPrintVisitor.cpp
@@ -94,14 +94,17 @@ void PrettyPrintVisitor::visit(const IdmapData& data) {
}
for (auto& target_entry : data.GetTargetInlineEntries()) {
- stream_ << TAB << base::StringPrintf("0x%08x -> ", target_entry.target_id)
- << utils::DataTypeToString(target_entry.value.data_type);
-
- if (target_entry.value.data_type == Res_value::TYPE_STRING) {
- auto str = string_pool.stringAt(target_entry.value.data_value - string_pool_offset);
- stream_ << " \"" << str.value_or(StringPiece16(u"")) << "\"";
- } else {
- stream_ << " " << base::StringPrintf("0x%08x", target_entry.value.data_value);
+ for(auto iter = target_entry.values.begin(); iter != target_entry.values.end(); ++iter) {
+ auto value = iter->second;
+ stream_ << TAB << base::StringPrintf("0x%08x -> ", target_entry.target_id)
+ << utils::DataTypeToString(value.data_type);
+
+ if (value.data_type == Res_value::TYPE_STRING) {
+ auto str = string_pool.stringAt(value.data_value - string_pool_offset);
+ stream_ << " \"" << str.value_or(StringPiece16(u"")) << "\"";
+ } else {
+ stream_ << " " << base::StringPrintf("0x%08x", value.data_value);
+ }
}
std::string target_name = kUnknownResourceName;
diff --git a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
index 779538c617f4..3531cd7c2f36 100644
--- a/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
+++ b/cmds/idmap2/libidmap2/RawPrintVisitor.cpp
@@ -89,22 +89,30 @@ void RawPrintVisitor::visit(const IdmapData& data ATTRIBUTE_UNUSED) {
print(target_entry.target_id, "target id");
}
+
pad(sizeof(Res_value::size) + sizeof(Res_value::res0));
- print(target_entry.value.data_type, "type: %s",
- utils::DataTypeToString(target_entry.value.data_type).data());
+ for (auto& target_entry_value : target_entry.values) {
+ auto value = target_entry_value.second;
- Result<std::string> overlay_name(Error(""));
- if (overlay_ != nullptr &&
- (target_entry.value.data_value == Res_value::TYPE_REFERENCE ||
- target_entry.value.data_value == Res_value::TYPE_DYNAMIC_REFERENCE)) {
- overlay_name = overlay_->GetResourceName(target_entry.value.data_value);
- }
+ print(target_entry_value.first.to_string(), false, "config: %s",
+ target_entry_value.first.toString().string());
- if (overlay_name) {
- print(target_entry.value.data_value, "data: %s", overlay_name->c_str());
- } else {
- print(target_entry.value.data_value, "data");
+ print(value.data_type, "type: %s",
+ utils::DataTypeToString(value.data_type).data());
+
+ Result<std::string> overlay_name(Error(""));
+ if (overlay_ != nullptr &&
+ (value.data_value == Res_value::TYPE_REFERENCE ||
+ value.data_value == Res_value::TYPE_DYNAMIC_REFERENCE)) {
+ overlay_name = overlay_->GetResourceName(value.data_value);
+ }
+
+ if (overlay_name) {
+ print(value.data_value, "data: %s", overlay_name->c_str());
+ } else {
+ print(value.data_value, "data");
+ }
}
}
@@ -138,6 +146,8 @@ void RawPrintVisitor::visit(const IdmapData& data ATTRIBUTE_UNUSED) {
void RawPrintVisitor::visit(const IdmapData::Header& header) {
print(header.GetTargetEntryCount(), "target entry count");
print(header.GetTargetInlineEntryCount(), "target inline entry count");
+ print(header.GetTargetInlineEntryValueCount(), "target inline entry value count");
+ print(header.GetConfigCount(), "config count");
print(header.GetOverlayEntryCount(), "overlay entry count");
print(header.GetStringPoolIndexOffset(), "string pool index offset");
}
diff --git a/cmds/idmap2/libidmap2/ResourceContainer.cpp b/cmds/idmap2/libidmap2/ResourceContainer.cpp
index a62472c8f11e..0e3590486c6f 100644
--- a/cmds/idmap2/libidmap2/ResourceContainer.cpp
+++ b/cmds/idmap2/libidmap2/ResourceContainer.cpp
@@ -226,8 +226,10 @@ Result<OverlayData> CreateResourceMapping(ResourceId id, const ZipAssetsProvider
*target_resource, OverlayData::ResourceIdValue{overlay_resource->data, rewrite_id}});
} else {
overlay_data.pairs.emplace_back(
- OverlayData::Value{*target_resource, TargetValue{.data_type = overlay_resource->dataType,
- .data_value = overlay_resource->data}});
+ OverlayData::Value{*target_resource, TargetValueWithConfig{
+ .config = std::string(),
+ .value = TargetValue{.data_type = overlay_resource->dataType,
+ .data_value = overlay_resource->data}}});
}
}
diff --git a/cmds/idmap2/libidmap2/ResourceMapping.cpp b/cmds/idmap2/libidmap2/ResourceMapping.cpp
index 3bbbf248c87d..b2300cea3a68 100644
--- a/cmds/idmap2/libidmap2/ResourceMapping.cpp
+++ b/cmds/idmap2/libidmap2/ResourceMapping.cpp
@@ -89,7 +89,7 @@ Result<Unit> CheckOverlayable(const TargetResourceContainer& target,
// If the overlay supplies a target overlayable name, the resource must belong to the
// overlayable defined with the specified name to be overlaid.
return Error(R"(<overlay> android:targetName "%s" does not match overlayable name "%s")",
- overlay_info.target_name.c_str(), (*overlayable_info)->name.c_str());
+ overlay_info.target_name.c_str(), (*overlayable_info)->name.data());
}
// Enforce policy restrictions if the resource is declared as overlayable.
@@ -160,15 +160,14 @@ Result<ResourceMapping> ResourceMapping::FromContainers(const TargetResourceCont
Result<Unit> ResourceMapping::AddMapping(
ResourceId target_resource,
- const std::variant<OverlayData::ResourceIdValue, TargetValue>& value) {
- if (target_map_.find(target_resource) != target_map_.end()) {
- return Error(R"(target resource id "0x%08x" mapped to multiple values)", target_resource);
- }
-
+ const std::variant<OverlayData::ResourceIdValue, TargetValueWithConfig>& value) {
// TODO(141485591): Ensure that the overlay type is compatible with the target type. If the
// runtime types are not compatible, it could cause runtime crashes when the resource is resolved.
if (auto overlay_resource = std::get_if<OverlayData::ResourceIdValue>(&value)) {
+ if (target_map_.find(target_resource) != target_map_.end()) {
+ return Error(R"(target resource id "0x%08x" mapped to multiple values)", target_resource);
+ }
target_map_.insert(std::make_pair(target_resource, overlay_resource->overlay_id));
if (overlay_resource->rewrite_id) {
// An overlay resource can override multiple target resources at once. Rewrite the overlay
@@ -176,8 +175,18 @@ Result<Unit> ResourceMapping::AddMapping(
overlay_map_.insert(std::make_pair(overlay_resource->overlay_id, target_resource));
}
} else {
- auto overlay_value = std::get<TargetValue>(value);
- target_map_.insert(std::make_pair(target_resource, overlay_value));
+ auto[iter, inserted] = target_map_.try_emplace(target_resource, ConfigMap());
+ auto& resource_value = iter->second;
+ if (!inserted && std::holds_alternative<ResourceId>(resource_value)) {
+ return Error(R"(target resource id "0x%08x" mapped to multiple values)", target_resource);
+ }
+ auto& config_map = std::get<ConfigMap>(resource_value);
+ const auto& config_value = std::get<TargetValueWithConfig>(value);
+ if (config_map.find(config_value.config) != config_map.end()) {
+ return Error(R"(target resource id "0x%08x" mapped to multiple values with the same config)",
+ target_resource);
+ }
+ config_map.insert(config_value.to_pair());
}
return Unit{};
diff --git a/cmds/idmap2/libidmap2/proto/fabricated_v1.proto b/cmds/idmap2/libidmap2/proto/fabricated_v1.proto
index a392b2b6d856..c7a79b31e151 100644
--- a/cmds/idmap2/libidmap2/proto/fabricated_v1.proto
+++ b/cmds/idmap2/libidmap2/proto/fabricated_v1.proto
@@ -46,6 +46,7 @@ message ResourceEntry {
oneof value {
ResourceValue res_value = 2;
}
+ string configuration = 3;
}
message ResourceValue {
diff --git a/cmds/idmap2/self_targeting/SelfTargeting.cpp b/cmds/idmap2/self_targeting/SelfTargeting.cpp
new file mode 100644
index 000000000000..a8aa03309b16
--- /dev/null
+++ b/cmds/idmap2/self_targeting/SelfTargeting.cpp
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2022 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 <sys/stat.h>
+
+#include <fstream>
+#include <optional>
+
+#define LOG_TAG "SelfTargeting"
+
+#include "androidfw/ResourceTypes.h"
+#include "idmap2/BinaryStreamVisitor.h"
+#include "idmap2/FabricatedOverlay.h"
+#include "idmap2/Idmap.h"
+#include "idmap2/Result.h"
+
+using PolicyBitmask = android::ResTable_overlayable_policy_header::PolicyBitmask;
+using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags;
+using android::idmap2::BinaryStreamVisitor;
+using android::idmap2::Idmap;
+using android::idmap2::OverlayResourceContainer;
+
+namespace android::self_targeting {
+
+constexpr const mode_t kIdmapFilePermission = S_IRUSR | S_IWUSR; // u=rw-, g=---, o=---
+
+extern "C" bool
+CreateFrroFile(std::string& out_err_result, const std::string& packageName,
+ const std::string& overlayName, const std::string& targetPackageName,
+ const std::optional<std::string>& targetOverlayable,
+ const std::vector<FabricatedOverlayEntryParameters>& entries_params,
+ const std::string& frro_file_path) {
+ android::idmap2::FabricatedOverlay::Builder builder(packageName, overlayName,
+ targetPackageName);
+ if (targetOverlayable.has_value()) {
+ builder.SetOverlayable(targetOverlayable.value_or(std::string()));
+ }
+ for (const auto& entry_params : entries_params) {
+ 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.configuration);
+ } else if (dataType >= Res_value::TYPE_FIRST_INT && dataType <= Res_value::TYPE_LAST_INT) {
+ builder.SetResourceValue(entry_params.resource_name, dataType,
+ entry_params.data_value, entry_params.configuration);
+ } else if (dataType == Res_value::TYPE_STRING) {
+ builder.SetResourceValue(entry_params.resource_name, dataType,
+ entry_params.data_string_value , entry_params.configuration);
+ } else {
+ out_err_result = base::StringPrintf("Unsupported data type %d", dataType);
+ return false;
+ }
+ }
+
+ const auto frro = builder.Build();
+ std::ofstream fout(frro_file_path);
+ if (fout.fail()) {
+ out_err_result = base::StringPrintf("open output stream fail %s", std::strerror(errno));
+ return false;
+ }
+ auto result = frro->ToBinaryStream(fout);
+ if (!result) {
+ unlink(frro_file_path.c_str());
+ out_err_result = base::StringPrintf("to stream fail %s", result.GetErrorMessage().c_str());
+ return false;
+ }
+ fout.close();
+ if (fout.fail()) {
+ unlink(frro_file_path.c_str());
+ out_err_result = base::StringPrintf("output stream fail %s", std::strerror(errno));
+ return false;
+ }
+ if (chmod(frro_file_path.c_str(), kIdmapFilePermission) == -1) {
+ out_err_result = base::StringPrintf("Failed to change the file permission %s",
+ frro_file_path.c_str());
+ return false;
+ }
+ return true;
+}
+
+static PolicyBitmask GetFulfilledPolicy(const bool isSystem, const bool isVendor,
+ const bool isProduct, const bool isTargetSignature,
+ const bool isOdm, const bool isOem) {
+ auto fulfilled_policy = static_cast<PolicyBitmask>(PolicyFlags::PUBLIC);
+
+ if (isSystem) {
+ fulfilled_policy |= PolicyFlags::SYSTEM_PARTITION;
+ }
+ if (isVendor) {
+ fulfilled_policy |= PolicyFlags::VENDOR_PARTITION;
+ }
+ if (isProduct) {
+ fulfilled_policy |= PolicyFlags::PRODUCT_PARTITION;
+ }
+ if (isOdm) {
+ fulfilled_policy |= PolicyFlags::ODM_PARTITION;
+ }
+ if (isOem) {
+ fulfilled_policy |= PolicyFlags::OEM_PARTITION;
+ }
+ if (isTargetSignature) {
+ fulfilled_policy |= PolicyFlags::SIGNATURE;
+ }
+
+ // Not support actor_signature and config_overlay_signature
+ fulfilled_policy &=
+ ~(PolicyFlags::ACTOR_SIGNATURE | PolicyFlags::CONFIG_SIGNATURE);
+
+ ALOGV(
+ "fulfilled_policy = 0x%08x, isSystem = %d, isVendor = %d, isProduct = %d,"
+ " isTargetSignature = %d, isOdm = %d, isOem = %d,",
+ fulfilled_policy, isSystem, isVendor, isProduct, isTargetSignature, isOdm, isOem);
+ return fulfilled_policy;
+}
+
+extern "C" bool
+CreateIdmapFile(std::string& out_err, const std::string& targetPath, const std::string& overlayPath,
+ const std::string& idmapPath, const std::string& overlayName,
+ const bool isSystem, const bool isVendor, const bool isProduct,
+ const bool isTargetSignature, const bool isOdm, const bool isOem) {
+ // idmap files are mapped with mmap in libandroidfw. Deleting and recreating the idmap
+ // guarantees that existing memory maps will continue to be valid and unaffected. The file must
+ // be deleted before attempting to create the idmap, so that if idmap creation fails, the
+ // overlay will no longer be usable.
+ unlink(idmapPath.c_str());
+
+ const auto target = idmap2::TargetResourceContainer::FromPath(targetPath);
+ if (!target) {
+ out_err = base::StringPrintf("Failed to load target %s because of %s", targetPath.c_str(),
+ target.GetErrorMessage().c_str());
+ return false;
+ }
+
+ const auto overlay = OverlayResourceContainer::FromPath(overlayPath);
+ if (!overlay) {
+ out_err = base::StringPrintf("Failed to load overlay %s because of %s", overlayPath.c_str(),
+ overlay.GetErrorMessage().c_str());
+ return false;
+ }
+
+ // Overlay self target process. Only allow self-targeting types.
+ const auto fulfilled_policies = GetFulfilledPolicy(isSystem, isVendor, isProduct,
+ isTargetSignature, isOdm, isOem);
+
+ const auto idmap = Idmap::FromContainers(**target, **overlay, overlayName,
+ fulfilled_policies, true /* enforce_overlayable */);
+ if (!idmap) {
+ out_err = base::StringPrintf("Failed to create idmap because of %s",
+ idmap.GetErrorMessage().c_str());
+ return false;
+ }
+
+ std::ofstream fout(idmapPath.c_str());
+ if (fout.fail()) {
+ out_err = base::StringPrintf("Failed to create idmap %s because of %s", idmapPath.c_str(),
+ strerror(errno));
+ return false;
+ }
+
+ BinaryStreamVisitor visitor(fout);
+ (*idmap)->accept(&visitor);
+ fout.close();
+ if (fout.fail()) {
+ unlink(idmapPath.c_str());
+ out_err = base::StringPrintf("Failed to write idmap %s because of %s", idmapPath.c_str(),
+ strerror(errno));
+ return false;
+ }
+ if (chmod(idmapPath.c_str(), kIdmapFilePermission) == -1) {
+ out_err = base::StringPrintf("Failed to change the file permission %s", idmapPath.c_str());
+ return false;
+ }
+ return true;
+}
+
+extern "C" bool
+GetFabricatedOverlayInfo(std::string& out_err, const std::string& overlay_path,
+ OverlayManifestInfo& out_info) {
+ const auto overlay = idmap2::FabricatedOverlayContainer::FromPath(overlay_path);
+ if (!overlay) {
+ out_err = base::StringPrintf("Failed to write idmap %s because of %s",
+ overlay_path.c_str(), strerror(errno));
+ return false;
+ }
+
+ out_info = (*overlay)->GetManifestInfo();
+
+ return true;
+}
+
+} // namespace android::self_targeting
+
diff --git a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
index bf6332742787..f1eeab9c803b 100644
--- a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
+++ b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
@@ -84,8 +84,10 @@ TEST(BinaryStreamVisitorTests, CreateBinaryStreamViaBinaryStreamVisitor) {
const auto& target_inline_entries2 = data2->GetTargetInlineEntries();
ASSERT_EQ(target_inline_entries1.size(), target_inline_entries2.size());
ASSERT_EQ(target_inline_entries1[0].target_id, target_inline_entries2[0].target_id);
- ASSERT_EQ(target_inline_entries1[0].value.data_type, target_inline_entries2[0].value.data_type);
- ASSERT_EQ(target_inline_entries1[0].value.data_value, target_inline_entries2[0].value.data_value);
+ ASSERT_EQ(target_inline_entries1[0].values.begin()->second.data_type,
+ target_inline_entries2[0].values.begin()->second.data_type);
+ ASSERT_EQ(target_inline_entries1[0].values.begin()->second.data_value,
+ target_inline_entries2[0].values.begin()->second.data_value);
const auto& overlay_entries1 = data1->GetOverlayEntries();
const auto& overlay_entries2 = data2->GetOverlayEntries();
diff --git a/cmds/idmap2/tests/FabricatedOverlayTests.cpp b/cmds/idmap2/tests/FabricatedOverlayTests.cpp
index 468ea0c634c1..e13a0eb5d488 100644
--- a/cmds/idmap2/tests/FabricatedOverlayTests.cpp
+++ b/cmds/idmap2/tests/FabricatedOverlayTests.cpp
@@ -17,6 +17,7 @@
#include <android-base/file.h>
#include <gtest/gtest.h>
#include <idmap2/FabricatedOverlay.h>
+#include "TestHelpers.h"
#include <fstream>
#include <utility>
@@ -41,11 +42,25 @@ TEST(FabricatedOverlayTests, OverlayInfo) {
}
TEST(FabricatedOverlayTests, SetResourceValue) {
+ auto path = GetTestDataPath() + "/overlay/res/drawable/android.png";
+ auto fd = android::base::unique_fd(::open(path.c_str(), O_RDONLY | O_CLOEXEC));
+ ASSERT_TRUE(fd > 0) << "errno " << errno << " for path " << path;
+
auto overlay =
FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "com.example.target")
- .SetResourceValue("com.example.target:integer/int1", Res_value::TYPE_INT_DEC, 1U)
- .SetResourceValue("com.example.target.split:integer/int2", Res_value::TYPE_INT_DEC, 2U)
- .SetResourceValue("string/int3", Res_value::TYPE_REFERENCE, 0x7f010000)
+ .SetResourceValue(
+ "com.example.target:integer/int1", Res_value::TYPE_INT_DEC, 1U, "port")
+ .SetResourceValue(
+ "com.example.target.split:integer/int2", Res_value::TYPE_INT_DEC, 2U, "land")
+ .SetResourceValue(
+ "string/int3", Res_value::TYPE_REFERENCE, 0x7f010000, "xxhdpi-v7")
+ .SetResourceValue(
+ "com.example.target:string/string1",
+ Res_value::TYPE_STRING,
+ "foobar",
+ "en-rUS-normal-xxhdpi-v21")
+ .SetResourceValue("com.example.target:drawable/dr1", fd, "port-xxhdpi-v7")
+ .setFrroPath("/foo/bar/biz.frro")
.Build();
ASSERT_TRUE(overlay);
auto container = FabricatedOverlayContainer::FromOverlay(std::move(*overlay));
@@ -59,42 +74,63 @@ TEST(FabricatedOverlayTests, SetResourceValue) {
auto pairs = container->GetOverlayData(*info);
ASSERT_TRUE(pairs);
- EXPECT_FALSE(pairs->string_pool_data.has_value());
- ASSERT_EQ(3U, pairs->pairs.size());
+ ASSERT_EQ(5U, pairs->pairs.size());
+ auto string_pool = ResStringPool(pairs->string_pool_data->data.get(),
+ pairs->string_pool_data->data_length, false);
auto& it = pairs->pairs[0];
- ASSERT_EQ("com.example.target:integer/int1", it.resource_name);
- auto entry = std::get_if<TargetValue>(&it.value);
+ ASSERT_EQ("com.example.target:drawable/dr1", it.resource_name);
+ auto entry = std::get_if<TargetValueWithConfig>(&it.value);
ASSERT_NE(nullptr, entry);
- ASSERT_EQ(1U, entry->data_value);
- ASSERT_EQ(Res_value::TYPE_INT_DEC, entry->data_type);
+ ASSERT_EQ(std::string("frro://foo/bar/biz.frro?offset=16&size=8341"),
+ string_pool.string8At(entry->value.data_value).value_or(""));
+ ASSERT_EQ(Res_value::TYPE_STRING, entry->value.data_type);
+ ASSERT_EQ("port-xxhdpi-v7", entry->config);
it = pairs->pairs[1];
- ASSERT_EQ("com.example.target:string/int3", it.resource_name);
- entry = std::get_if<TargetValue>(&it.value);
+ ASSERT_EQ("com.example.target:integer/int1", it.resource_name);
+ entry = std::get_if<TargetValueWithConfig>(&it.value);
ASSERT_NE(nullptr, entry);
- ASSERT_EQ(0x7f010000, entry->data_value);
- ASSERT_EQ(Res_value::TYPE_REFERENCE, entry->data_type);
+ ASSERT_EQ(1U, entry->value.data_value);
+ ASSERT_EQ(Res_value::TYPE_INT_DEC, entry->value.data_type);
+ ASSERT_EQ("port", entry->config);
it = pairs->pairs[2];
+ ASSERT_EQ("com.example.target:string/int3", it.resource_name);
+ entry = std::get_if<TargetValueWithConfig>(&it.value);
+ ASSERT_NE(nullptr, entry);
+ ASSERT_EQ(0x7f010000, entry->value.data_value);
+ ASSERT_EQ(Res_value::TYPE_REFERENCE, entry->value.data_type);
+ ASSERT_EQ("xxhdpi-v7", entry->config);
+
+ it = pairs->pairs[3];
+ ASSERT_EQ("com.example.target:string/string1", it.resource_name);
+ entry = std::get_if<TargetValueWithConfig>(&it.value);
+ ASSERT_NE(nullptr, entry);
+ ASSERT_EQ(Res_value::TYPE_STRING, entry->value.data_type);
+ ASSERT_EQ(std::string("foobar"), string_pool.string8At(entry->value.data_value).value_or(""));
+ ASSERT_EQ("en-rUS-normal-xxhdpi-v21", entry->config);
+
+ it = pairs->pairs[4];
ASSERT_EQ("com.example.target.split:integer/int2", it.resource_name);
- entry = std::get_if<TargetValue>(&it.value);
+ entry = std::get_if<TargetValueWithConfig>(&it.value);
ASSERT_NE(nullptr, entry);
- ASSERT_EQ(2U, entry->data_value);
- ASSERT_EQ(Res_value::TYPE_INT_DEC, entry->data_type);
+ ASSERT_EQ(2U, entry->value.data_value);
+ ASSERT_EQ(Res_value::TYPE_INT_DEC, entry->value.data_type);
+ ASSERT_EQ("land", entry->config);
}
TEST(FabricatedOverlayTests, SetResourceValueBadArgs) {
{
auto builder =
FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "com.example.target")
- .SetResourceValue("int1", Res_value::TYPE_INT_DEC, 1U);
+ .SetResourceValue("int1", Res_value::TYPE_INT_DEC, 1U, "");
ASSERT_FALSE(builder.Build());
}
{
auto builder =
FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "com.example.target")
- .SetResourceValue("com.example.target:int2", Res_value::TYPE_INT_DEC, 1U);
+ .SetResourceValue("com.example.target:int2", Res_value::TYPE_INT_DEC, 1U, "");
ASSERT_FALSE(builder.Build());
}
}
@@ -103,7 +139,9 @@ TEST(FabricatedOverlayTests, SerializeAndDeserialize) {
auto overlay =
FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "com.example.target")
.SetOverlayable("TestResources")
- .SetResourceValue("com.example.target:integer/int1", Res_value::TYPE_INT_DEC, 1U)
+ .SetResourceValue("com.example.target:integer/int1", Res_value::TYPE_INT_DEC, 1U, "")
+ .SetResourceValue(
+ "com.example.target:string/string1", Res_value::TYPE_STRING, "foobar", "")
.Build();
ASSERT_TRUE(overlay);
TemporaryFile tf;
@@ -126,14 +164,23 @@ TEST(FabricatedOverlayTests, SerializeAndDeserialize) {
auto pairs = (*container)->GetOverlayData(*info);
ASSERT_TRUE(pairs) << pairs.GetErrorMessage();
- EXPECT_EQ(1U, pairs->pairs.size());
+ EXPECT_EQ(2U, pairs->pairs.size());
+ auto string_pool = ResStringPool(pairs->string_pool_data->data.get(),
+ pairs->string_pool_data->data_length, false);
auto& it = pairs->pairs[0];
ASSERT_EQ("com.example.target:integer/int1", it.resource_name);
- auto entry = std::get_if<TargetValue>(&it.value);
+ auto entry = std::get_if<TargetValueWithConfig>(&it.value);
+ ASSERT_NE(nullptr, entry);
+ EXPECT_EQ(1U, entry->value.data_value);
+ EXPECT_EQ(Res_value::TYPE_INT_DEC, entry->value.data_type);
+
+ it = pairs->pairs[1];
+ ASSERT_EQ("com.example.target:string/string1", it.resource_name);
+ entry = std::get_if<TargetValueWithConfig>(&it.value);
ASSERT_NE(nullptr, entry);
- EXPECT_EQ(1U, entry->data_value);
- EXPECT_EQ(Res_value::TYPE_INT_DEC, entry->data_type);
+ ASSERT_EQ(Res_value::TYPE_STRING, entry->value.data_type);
+ ASSERT_EQ(std::string("foobar"), string_pool.string8At(entry->value.data_value).value_or(""));
}
} // namespace android::idmap2
diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
index e1b782972d3c..5a7fcd519cfd 100644
--- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp
+++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
@@ -46,7 +46,6 @@
using ::android::base::StringPrintf;
using ::android::util::ExecuteBinary;
-using ::testing::NotNull;
namespace android::idmap2 {
@@ -95,8 +94,8 @@ TEST_F(Idmap2BinaryTests, Create) {
"--overlay-name", TestConstants::OVERLAY_NAME_DEFAULT,
"--idmap-path", GetIdmapPath()});
// clang-format on
- ASSERT_THAT(result, NotNull());
- ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
+ ASSERT_TRUE((bool)result);
+ ASSERT_EQ(result.status, EXIT_SUCCESS) << result.stderr_str;
struct stat st;
ASSERT_EQ(stat(GetIdmapPath().c_str(), &st), 0);
@@ -122,33 +121,33 @@ TEST_F(Idmap2BinaryTests, Dump) {
"--overlay-name", TestConstants::OVERLAY_NAME_DEFAULT,
"--idmap-path", GetIdmapPath()});
// clang-format on
- ASSERT_THAT(result, NotNull());
- ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
+ ASSERT_TRUE((bool)result);
+ ASSERT_EQ(result.status, EXIT_SUCCESS) << result.stderr_str;
// clang-format off
result = ExecuteBinary({"idmap2",
"dump",
"--idmap-path", GetIdmapPath()});
// clang-format on
- ASSERT_THAT(result, NotNull());
- ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
+ ASSERT_TRUE((bool)result);
+ ASSERT_EQ(result.status, EXIT_SUCCESS) << result.stderr_str;
- ASSERT_NE(result->stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::integer::int1,
+ ASSERT_NE(result.stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::integer::int1,
R::overlay::integer::int1)),
std::string::npos)
- << result->stdout_str;
- ASSERT_NE(result->stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str1,
+ << result.stdout_str;
+ ASSERT_NE(result.stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str1,
R::overlay::string::str1)),
std::string::npos)
- << result->stdout_str;
- ASSERT_NE(result->stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str3,
+ << result.stdout_str;
+ ASSERT_NE(result.stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str3,
R::overlay::string::str3)),
std::string::npos)
- << result->stdout_str;
- ASSERT_NE(result->stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str4,
+ << result.stdout_str;
+ ASSERT_NE(result.stdout_str.find(StringPrintf("0x%08x -> 0x%08x", R::target::string::str4,
R::overlay::string::str4)),
std::string::npos)
- << result->stdout_str;
+ << result.stdout_str;
// clang-format off
result = ExecuteBinary({"idmap2",
@@ -156,9 +155,9 @@ TEST_F(Idmap2BinaryTests, Dump) {
"--verbose",
"--idmap-path", GetIdmapPath()});
// clang-format on
- ASSERT_THAT(result, NotNull());
- ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
- ASSERT_NE(result->stdout_str.find("00000000: 504d4449 magic"), std::string::npos);
+ ASSERT_TRUE((bool)result);
+ ASSERT_EQ(result.status, EXIT_SUCCESS) << result.stderr_str;
+ ASSERT_NE(result.stdout_str.find("00000000: 504d4449 magic"), std::string::npos);
// clang-format off
result = ExecuteBinary({"idmap2",
@@ -166,8 +165,8 @@ TEST_F(Idmap2BinaryTests, Dump) {
"--verbose",
"--idmap-path", GetTestDataPath() + "/DOES-NOT-EXIST"});
// clang-format on
- ASSERT_THAT(result, NotNull());
- ASSERT_NE(result->status, EXIT_SUCCESS);
+ ASSERT_TRUE((bool)result);
+ ASSERT_NE(result.status, EXIT_SUCCESS);
unlink(GetIdmapPath().c_str());
}
@@ -183,8 +182,8 @@ TEST_F(Idmap2BinaryTests, Lookup) {
"--overlay-name", TestConstants::OVERLAY_NAME_DEFAULT,
"--idmap-path", GetIdmapPath()});
// clang-format on
- ASSERT_THAT(result, NotNull());
- ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
+ ASSERT_TRUE((bool)result);
+ ASSERT_EQ(result.status, EXIT_SUCCESS) << result.stderr_str;
// clang-format off
result = ExecuteBinary({"idmap2",
@@ -193,10 +192,10 @@ TEST_F(Idmap2BinaryTests, Lookup) {
"--config", "",
"--resid", StringPrintf("0x%08x", R::target::string::str1)});
// clang-format on
- ASSERT_THAT(result, NotNull());
- ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
- ASSERT_NE(result->stdout_str.find("overlay-1"), std::string::npos);
- ASSERT_EQ(result->stdout_str.find("overlay-1-sv"), std::string::npos);
+ ASSERT_TRUE((bool)result);
+ ASSERT_EQ(result.status, EXIT_SUCCESS) << result.stderr_str;
+ ASSERT_NE(result.stdout_str.find("overlay-1"), std::string::npos);
+ ASSERT_EQ(result.stdout_str.find("overlay-1-sv"), std::string::npos);
// clang-format off
result = ExecuteBinary({"idmap2",
@@ -205,10 +204,10 @@ TEST_F(Idmap2BinaryTests, Lookup) {
"--config", "",
"--resid", "test.target:string/str1"});
// clang-format on
- ASSERT_THAT(result, NotNull());
- ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
- ASSERT_NE(result->stdout_str.find("overlay-1"), std::string::npos);
- ASSERT_EQ(result->stdout_str.find("overlay-1-sv"), std::string::npos);
+ ASSERT_TRUE((bool)result);
+ ASSERT_EQ(result.status, EXIT_SUCCESS) << result.stderr_str;
+ ASSERT_NE(result.stdout_str.find("overlay-1"), std::string::npos);
+ ASSERT_EQ(result.stdout_str.find("overlay-1-sv"), std::string::npos);
// clang-format off
result = ExecuteBinary({"idmap2",
@@ -217,9 +216,9 @@ TEST_F(Idmap2BinaryTests, Lookup) {
"--config", "sv",
"--resid", "test.target:string/str1"});
// clang-format on
- ASSERT_THAT(result, NotNull());
- ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr_str;
- ASSERT_NE(result->stdout_str.find("overlay-1-sv"), std::string::npos);
+ ASSERT_TRUE((bool)result);
+ ASSERT_EQ(result.status, EXIT_SUCCESS) << result.stderr_str;
+ ASSERT_NE(result.stdout_str.find("overlay-1-sv"), std::string::npos);
unlink(GetIdmapPath().c_str());
}
@@ -234,8 +233,8 @@ TEST_F(Idmap2BinaryTests, InvalidCommandLineOptions) {
auto result = ExecuteBinary({"idmap2",
"create"});
// clang-format on
- ASSERT_THAT(result, NotNull());
- ASSERT_NE(result->status, EXIT_SUCCESS);
+ ASSERT_TRUE((bool)result);
+ ASSERT_NE(result.status, EXIT_SUCCESS);
// missing argument to option
// clang-format off
@@ -246,8 +245,8 @@ TEST_F(Idmap2BinaryTests, InvalidCommandLineOptions) {
"--overlay-name", TestConstants::OVERLAY_NAME_DEFAULT,
"--idmap-path"});
// clang-format on
- ASSERT_THAT(result, NotNull());
- ASSERT_NE(result->status, EXIT_SUCCESS);
+ ASSERT_TRUE((bool)result);
+ ASSERT_NE(result.status, EXIT_SUCCESS);
// invalid target apk path
// clang-format off
@@ -258,8 +257,8 @@ TEST_F(Idmap2BinaryTests, InvalidCommandLineOptions) {
"--overlay-name", TestConstants::OVERLAY_NAME_DEFAULT,
"--idmap-path", GetIdmapPath()});
// clang-format on
- ASSERT_THAT(result, NotNull());
- ASSERT_NE(result->status, EXIT_SUCCESS);
+ ASSERT_TRUE((bool)result);
+ ASSERT_NE(result.status, EXIT_SUCCESS);
// unknown policy
// clang-format off
@@ -271,8 +270,8 @@ TEST_F(Idmap2BinaryTests, InvalidCommandLineOptions) {
"--idmap-path", GetIdmapPath(),
"--policy", "this-does-not-exist"});
// clang-format on
- ASSERT_THAT(result, NotNull());
- ASSERT_NE(result->status, EXIT_SUCCESS);
+ ASSERT_TRUE((bool)result);
+ ASSERT_NE(result.status, EXIT_SUCCESS);
}
} // namespace android::idmap2
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index 738b9cf237c9..b473f26b2230 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -47,10 +47,11 @@ namespace android::idmap2 {
ASSERT_EQ((entry).target_id, (target_resid)); \
ASSERT_EQ((entry).overlay_id, (overlay_resid))
-#define ASSERT_TARGET_INLINE_ENTRY(entry, target_resid, expected_type, expected_value) \
- ASSERT_EQ((entry).target_id, target_resid); \
- ASSERT_EQ((entry).value.data_type, (expected_type)); \
- ASSERT_EQ((entry).value.data_value, (expected_value))
+#define ASSERT_TARGET_INLINE_ENTRY(entry, target_resid, ex_config, expected_type, expected_value) \
+ ASSERT_EQ((entry).target_id, target_resid); \
+ ASSERT_EQ((entry).values.begin()->first.to_string(), (ex_config)); \
+ ASSERT_EQ((entry).values.begin()->second.data_type, (expected_type)); \
+ ASSERT_EQ((entry).values.begin()->second.data_value, (expected_value))
#define ASSERT_OVERLAY_ENTRY(entry, overlay_resid, target_resid) \
ASSERT_EQ((entry).overlay_id, (overlay_resid)); \
@@ -67,7 +68,7 @@ TEST(IdmapTests, CreateIdmapHeaderFromBinaryStream) {
std::unique_ptr<const IdmapHeader> header = IdmapHeader::FromBinaryStream(stream);
ASSERT_THAT(header, NotNull());
ASSERT_EQ(header->GetMagic(), 0x504d4449U);
- ASSERT_EQ(header->GetVersion(), 0x08U);
+ ASSERT_EQ(header->GetVersion(), 0x09U);
ASSERT_EQ(header->GetTargetCrc(), 0x1234U);
ASSERT_EQ(header->GetOverlayCrc(), 0x5678U);
ASSERT_EQ(header->GetFulfilledPolicies(), 0x11);
@@ -122,8 +123,8 @@ TEST(IdmapTests, CreateIdmapDataFromBinaryStream) {
const auto& target_inline_entries = data->GetTargetInlineEntries();
ASSERT_EQ(target_inline_entries.size(), 1U);
- ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], 0x7f040000, Res_value::TYPE_INT_HEX,
- 0x12345678);
+ ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], 0x7f040000, "land-xxhdpi-v7",
+ Res_value::TYPE_INT_HEX, 0x12345678);
const auto& overlay_entries = data->GetOverlayEntries();
ASSERT_EQ(target_entries.size(), 3U);
@@ -142,7 +143,7 @@ TEST(IdmapTests, CreateIdmapFromBinaryStream) {
ASSERT_THAT(idmap->GetHeader(), NotNull());
ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
- ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x08U);
+ ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x09U);
ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0x1234U);
ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0x5678U);
ASSERT_EQ(idmap->GetHeader()->GetFulfilledPolicies(), kIdmapRawDataPolicies);
@@ -165,8 +166,8 @@ TEST(IdmapTests, CreateIdmapFromBinaryStream) {
const auto& target_inline_entries = data->GetTargetInlineEntries();
ASSERT_EQ(target_inline_entries.size(), 1U);
- ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], 0x7f040000, Res_value::TYPE_INT_HEX,
- 0x12345678);
+ ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], 0x7f040000, "land-xxhdpi-v7",
+ Res_value::TYPE_INT_HEX, 0x12345678);
const auto& overlay_entries = data->GetOverlayEntries();
ASSERT_EQ(target_entries.size(), 3U);
@@ -203,7 +204,7 @@ TEST(IdmapTests, CreateIdmapHeaderFromApkAssets) {
ASSERT_THAT(idmap->GetHeader(), NotNull());
ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
- ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x08U);
+ ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x09U);
ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), android::idmap2::TestConstants::TARGET_CRC);
ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), android::idmap2::TestConstants::OVERLAY_CRC);
ASSERT_EQ(idmap->GetHeader()->GetFulfilledPolicies(), PolicyFlags::PUBLIC);
@@ -259,10 +260,17 @@ TEST(IdmapTests, FabricatedOverlay) {
auto target = TargetResourceContainer::FromPath(target_apk_path);
ASSERT_TRUE(target);
+ auto path = GetTestDataPath() + "/overlay/res/drawable/android.png";
+ auto fd = android::base::unique_fd(::open(path.c_str(), O_RDONLY | O_CLOEXEC));
+ ASSERT_TRUE(fd > 0) << "errno " << errno << " for path " << path;
+
auto frro = FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "test.target")
.SetOverlayable("TestResources")
- .SetResourceValue("integer/int1", Res_value::TYPE_INT_DEC, 2U)
- .SetResourceValue("string/str1", Res_value::TYPE_REFERENCE, 0x7f010000)
+ .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")
+ .setFrroPath("/foo/bar/biz.frro")
.Build();
ASSERT_TRUE(frro);
@@ -288,12 +296,24 @@ TEST(IdmapTests, FabricatedOverlay) {
ASSERT_EQ(data->GetTargetEntries().size(), 0U);
ASSERT_EQ(data->GetOverlayEntries().size(), 0U);
+ auto string_pool_data = data->GetStringPoolData();
+ auto string_pool = ResStringPool(string_pool_data.data(), string_pool_data.size(), false);
+
+ std::u16string expected_uri = u"frro://foo/bar/biz.frro?offset=16&size=8341";
+ uint32_t uri_index
+ = string_pool.indexOfString(expected_uri.data(), expected_uri.length()).value_or(-1);
+
const auto& target_inline_entries = data->GetTargetInlineEntries();
- ASSERT_EQ(target_inline_entries.size(), 2U);
- ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], R::target::integer::int1,
+ ASSERT_EQ(target_inline_entries.size(), 4U);
+ ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], R::target::drawable::dr1, "port-xxhdpi-v7",
+ Res_value::TYPE_STRING, uri_index);
+ ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[1], R::target::integer::int1, "land-xxhdpi-v7",
Res_value::TYPE_INT_DEC, 2U);
- ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[1], R::target::string::str1,
+ ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[2], R::target::string::str1, "land",
Res_value::TYPE_REFERENCE, 0x7f010000);
+ ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[3], R::target::string::str2, "xxhdpi-v7",
+ Res_value::TYPE_STRING,
+ (uint32_t) (string_pool.indexOfString(u"foobar", 6)).value_or(-1));
}
TEST(IdmapTests, FailCreateIdmapInvalidName) {
@@ -434,9 +454,9 @@ TEST(IdmapTests, CreateIdmapDataInlineResources) {
constexpr size_t overlay_string_pool_size = 10U;
const auto& target_inline_entries = data->GetTargetInlineEntries();
ASSERT_EQ(target_inline_entries.size(), 2U);
- ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], R::target::integer::int1,
+ ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[0], R::target::integer::int1, std::string(),
Res_value::TYPE_INT_DEC, 73U); // -> 73
- ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[1], R::target::string::str1,
+ ASSERT_TARGET_INLINE_ENTRY(target_inline_entries[1], R::target::string::str1, std::string(),
Res_value::TYPE_STRING,
overlay_string_pool_size + 0U); // -> "Hello World"
diff --git a/cmds/idmap2/tests/R.h b/cmds/idmap2/tests/R.h
index 89219c9c8213..80c062d92640 100644
--- a/cmds/idmap2/tests/R.h
+++ b/cmds/idmap2/tests/R.h
@@ -26,23 +26,27 @@ namespace android::idmap2 {
// clang-format off
namespace R::target {
namespace integer { // NOLINT(runtime/indentation_namespace)
- constexpr ResourceId int1 = 0x7f010000;
+ constexpr ResourceId int1 = 0x7f020000;
+ }
+ namespace drawable {
+ constexpr ResourceId dr1 = 0x7f010000;
}
namespace string { // NOLINT(runtime/indentation_namespace)
- constexpr ResourceId not_overlayable = 0x7f020003;
- constexpr ResourceId other = 0x7f020004;
- constexpr ResourceId policy_actor = 0x7f020005;
- constexpr ResourceId policy_config_signature = 0x7f020006;
- constexpr ResourceId policy_odm = 0x7f020007;
- constexpr ResourceId policy_oem = 0x7f020008;
- constexpr ResourceId policy_product = 0x7f020009;
- constexpr ResourceId policy_public = 0x7f02000a;
- constexpr ResourceId policy_signature = 0x7f02000b;
- constexpr ResourceId policy_system = 0x7f02000c;
- constexpr ResourceId policy_system_vendor = 0x7f02000d;
- constexpr ResourceId str1 = 0x7f02000e;
- constexpr ResourceId str3 = 0x7f020010;
- constexpr ResourceId str4 = 0x7f020011;
+ constexpr ResourceId not_overlayable = 0x7f030003;
+ constexpr ResourceId other = 0x7f030004;
+ constexpr ResourceId policy_actor = 0x7f030005;
+ constexpr ResourceId policy_config_signature = 0x7f030006;
+ constexpr ResourceId policy_odm = 0x7f030007;
+ constexpr ResourceId policy_oem = 0x7f030008;
+ constexpr ResourceId policy_product = 0x7f030009;
+ constexpr ResourceId policy_public = 0x7f03000a;
+ constexpr ResourceId policy_signature = 0x7f03000b;
+ constexpr ResourceId policy_system = 0x7f03000c;
+ constexpr ResourceId policy_system_vendor = 0x7f03000d;
+ constexpr ResourceId str1 = 0x7f03000e;
+ constexpr ResourceId str2 = 0x7f03000f;
+ constexpr ResourceId str3 = 0x7f030010;
+ constexpr ResourceId str4 = 0x7f030011;
} // namespace string
} // namespace R::target
diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
index a6371cb74f2e..68164e26f352 100644
--- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
@@ -64,7 +64,7 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) {
(*idmap)->accept(&visitor);
ASSERT_CONTAINS_REGEX(ADDRESS "504d4449 magic\n", stream.str());
- ASSERT_CONTAINS_REGEX(ADDRESS "00000008 version\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00000009 version\n", stream.str());
ASSERT_CONTAINS_REGEX(
StringPrintf(ADDRESS "%s target crc\n", android::idmap2::TestConstants::TARGET_CRC_STRING),
stream.str());
@@ -75,24 +75,26 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitor) {
ASSERT_CONTAINS_REGEX(ADDRESS "00000001 enforce overlayable\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00000004 target entry count", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00000000 target inline entry count", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00000000 target inline entry value count", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00000000 config count", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00000004 overlay entry count", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "0000000a string pool index offset", stream.str());
- ASSERT_CONTAINS_REGEX(ADDRESS "7f010000 target id: integer/int1", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 target id: integer/int1", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "7f010000 overlay id: integer/int1", stream.str());
- ASSERT_CONTAINS_REGEX(ADDRESS "7f02000e target id: string/str1", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "7f03000e target id: string/str1", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "7f02000b overlay id: string/str1", stream.str());
- ASSERT_CONTAINS_REGEX(ADDRESS "7f020010 target id: string/str3", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "7f030010 target id: string/str3", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "7f02000c overlay id: string/str3", stream.str());
- ASSERT_CONTAINS_REGEX(ADDRESS "7f020011 target id: string/str4", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "7f030011 target id: string/str4", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "7f02000d overlay id: string/str4", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "7f010000 overlay id: integer/int1", stream.str());
- ASSERT_CONTAINS_REGEX(ADDRESS "7f010000 target id: integer/int1", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 target id: integer/int1", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "7f02000b overlay id: string/str1", stream.str());
- ASSERT_CONTAINS_REGEX(ADDRESS "7f02000e target id: string/str1", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "7f03000e target id: string/str1", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "7f02000c overlay id: string/str3", stream.str());
- ASSERT_CONTAINS_REGEX(ADDRESS "7f020010 target id: string/str3", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "7f030010 target id: string/str3", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "7f02000d overlay id: string/str4", stream.str());
- ASSERT_CONTAINS_REGEX(ADDRESS "7f020011 target id: string/str4", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "7f030011 target id: string/str4", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "000000b4 string pool size", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "........ string pool", stream.str());
}
@@ -111,7 +113,7 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitorWithoutAccessToApks) {
(*idmap)->accept(&visitor);
ASSERT_CONTAINS_REGEX(ADDRESS "504d4449 magic\n", stream.str());
- ASSERT_CONTAINS_REGEX(ADDRESS "00000008 version\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00000009 version\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00001234 target crc\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00005678 overlay crc\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00000011 fulfilled policies: public|signature\n", stream.str());
@@ -124,17 +126,25 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitorWithoutAccessToApks) {
ASSERT_CONTAINS_REGEX(ADDRESS "........ overlay name: OverlayName\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00000003 target entry count\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00000001 target inline entry count\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00000001 target inline entry value count", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "00000001 config count", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00000003 overlay entry count\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00000000 string pool index offset\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 target id\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 overlay id\n", stream.str());
- ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 target id\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "7f030000 target id\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "7f030000 overlay id\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "7f030002 target id\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "7f030001 overlay id\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "7f040000 target id\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "0000000e config: land-xxhdpi-v7 size\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "........ config: land-xxhdpi-v7\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS " 11 type: integer\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "12345678 data\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "7f020000 overlay id\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "7f030002 target id\n", stream.str());
ASSERT_CONTAINS_REGEX(ADDRESS "00000004 string pool size\n", stream.str());
- ASSERT_CONTAINS_REGEX("000000a4: ........ string pool\n", stream.str());
+ ASSERT_CONTAINS_REGEX(ADDRESS "........ string pool\n", stream.str());
}
} // namespace android::idmap2
diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp
index 32b3d1326d92..380e462a3aba 100644
--- a/cmds/idmap2/tests/ResourceMappingTests.cpp
+++ b/cmds/idmap2/tests/ResourceMappingTests.cpp
@@ -23,6 +23,7 @@
#include <memory>
#include <string>
+#include <fcntl.h>
#include "R.h"
#include "TestConstants.h"
#include "TestHelpers.h"
@@ -76,7 +77,12 @@ Result<Unit> MappingExists(const ResourceMapping& mapping, ResourceId target_res
auto target_map = mapping.GetTargetToOverlayMap();
auto entry_map = target_map.find(target_resource);
if (entry_map == target_map.end()) {
- return Error("Failed to find mapping for target resource");
+ std::string keys;
+ for (const auto &pair : target_map) {
+ keys.append(fmt::format("0x{:x}", pair.first)).append(" ");
+ }
+ return Error(R"(Failed to find mapping for target resource "0x%02x": "%s")",
+ target_resource, keys.c_str());
}
auto actual_overlay_resource = std::get_if<ResourceId>(&entry_map->second);
@@ -108,22 +114,28 @@ Result<Unit> MappingExists(const ResourceMapping& mapping, const ResourceId& tar
auto target_map = mapping.GetTargetToOverlayMap();
auto entry_map = target_map.find(target_resource);
if (entry_map == target_map.end()) {
- return Error("Failed to find mapping for target resource");
+ std::string keys;
+ for (const auto &pair : target_map) {
+ keys.append(fmt::format("{:x}", pair.first)).append(" ");
+ }
+ return Error(R"(Failed to find mapping for target resource "0x%02x": "%s")",
+ target_resource, keys.c_str());
}
- auto actual_overlay_value = std::get_if<TargetValue>(&entry_map->second);
- if (actual_overlay_value == nullptr) {
+ auto config_map = std::get_if<ConfigMap>(&entry_map->second);
+ if (config_map == nullptr || config_map->empty()) {
return Error("Target resource is not mapped to an inline value");
}
+ auto actual_overlay_value = config_map->begin()->second;
- if (actual_overlay_value->data_type != type) {
+ if (actual_overlay_value.data_type != type) {
return Error(R"(Expected type: "0x%02x" Actual type: "0x%02x")", type,
- actual_overlay_value->data_type);
+ actual_overlay_value.data_type);
}
- if (actual_overlay_value->data_value != value) {
+ if (actual_overlay_value.data_value != value) {
return Error(R"(Expected value: "0x%08x" Actual value: "0x%08x")", type,
- actual_overlay_value->data_value);
+ actual_overlay_value.data_value);
}
return Result<Unit>({});
@@ -192,10 +204,16 @@ TEST(ResourceMappingTests, InlineResources) {
}
TEST(ResourceMappingTests, FabricatedOverlay) {
+ auto path = GetTestDataPath() + "/overlay/res/drawable/android.png";
+ auto fd = android::base::unique_fd(::open(path.c_str(), O_RDONLY | O_CLOEXEC));
+ ASSERT_TRUE(fd > 0) << "errno " << errno << " for path " << path;
auto frro = FabricatedOverlay::Builder("com.example.overlay", "SandTheme", "test.target")
.SetOverlayable("TestResources")
- .SetResourceValue("integer/int1", Res_value::TYPE_INT_DEC, 2U)
- .SetResourceValue("string/str1", Res_value::TYPE_REFERENCE, 0x7f010000)
+ .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, "")
+ .setFrroPath("/foo/bar/biz.frro")
.Build();
ASSERT_TRUE(frro);
@@ -209,9 +227,19 @@ TEST(ResourceMappingTests, FabricatedOverlay) {
ASSERT_TRUE(resources) << resources.GetErrorMessage();
auto& res = *resources;
- ASSERT_EQ(res.GetTargetToOverlayMap().size(), 2U);
+ auto string_pool_data = res.GetStringPoolData();
+ auto string_pool = ResStringPool(string_pool_data.data(), string_pool_data.size(), false);
+
+ std::u16string expected_uri = u"frro://foo/bar/biz.frro?offset=16&size=8341";
+ uint32_t uri_index
+ = string_pool.indexOfString(expected_uri.data(), expected_uri.length()).value_or(-1);
+
+ ASSERT_EQ(res.GetTargetToOverlayMap().size(), 4U);
ASSERT_EQ(res.GetOverlayToTargetMap().size(), 0U);
ASSERT_RESULT(MappingExists(res, R::target::string::str1, Res_value::TYPE_REFERENCE, 0x7f010000));
+ ASSERT_RESULT(MappingExists(res, R::target::string::str2, Res_value::TYPE_STRING,
+ (uint32_t) (string_pool.indexOfString(u"foobar", 6)).value_or(-1)));
+ ASSERT_RESULT(MappingExists(res, R::target::drawable::dr1, Res_value::TYPE_STRING, uri_index));
ASSERT_RESULT(MappingExists(res, R::target::integer::int1, Res_value::TYPE_INT_DEC, 2U));
}
diff --git a/cmds/idmap2/tests/ResultTests.cpp b/cmds/idmap2/tests/ResultTests.cpp
index f2f8854cec3a..f9c4fa3c798b 100644
--- a/cmds/idmap2/tests/ResultTests.cpp
+++ b/cmds/idmap2/tests/ResultTests.cpp
@@ -259,7 +259,8 @@ TEST(ResultTests, CascadeError) {
}
struct NoCopyContainer {
- uint32_t value; // NOLINT(misc-non-private-member-variables-in-classes)
+ uint32_t value = 0; // NOLINT(misc-non-private-member-variables-in-classes)
+ NoCopyContainer() = default;
NoCopyContainer(const NoCopyContainer&) = delete;
NoCopyContainer& operator=(const NoCopyContainer&) = delete;
};
@@ -268,7 +269,7 @@ Result<std::unique_ptr<NoCopyContainer>> CreateNoCopyContainer(bool succeed) {
if (!succeed) {
return Error("foo");
}
- std::unique_ptr<NoCopyContainer> p(new NoCopyContainer{0U});
+ std::unique_ptr<NoCopyContainer> p(new NoCopyContainer{});
p->value = 42U;
return std::move(p);
}
diff --git a/cmds/idmap2/tests/TestConstants.h b/cmds/idmap2/tests/TestConstants.h
index d5799adf0ec3..794d6221c2c0 100644
--- a/cmds/idmap2/tests/TestConstants.h
+++ b/cmds/idmap2/tests/TestConstants.h
@@ -19,8 +19,8 @@
namespace android::idmap2::TestConstants {
-constexpr const auto TARGET_CRC = 0x7c2d4719;
-constexpr const auto TARGET_CRC_STRING = "7c2d4719";
+constexpr const auto TARGET_CRC = 0xa960a69;
+constexpr const auto TARGET_CRC_STRING = "0a960a69";
constexpr const auto OVERLAY_CRC = 0xb71095cf;
constexpr const auto OVERLAY_CRC_STRING = "b71095cf";
diff --git a/cmds/idmap2/tests/TestHelpers.h b/cmds/idmap2/tests/TestHelpers.h
index 6b5f3a8a98eb..cdc0b8fbb87e 100644
--- a/cmds/idmap2/tests/TestHelpers.h
+++ b/cmds/idmap2/tests/TestHelpers.h
@@ -30,7 +30,7 @@ const unsigned char kIdmapRawData[] = {
0x49, 0x44, 0x4d, 0x50,
// 0x4: version
- 0x08, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00,
// 0x8: target crc
0x34, 0x12, 0x00, 0x00,
@@ -76,66 +76,123 @@ const unsigned char kIdmapRawData[] = {
// 0x58: target_inline_entry_count
0x01, 0x00, 0x00, 0x00,
- // 0x5c: overlay_entry_count
+ // 0x5c: target_inline_entry_value_count
+ 0x01, 0x00, 0x00, 0x00,
+
+ // 0x60: config_count
+ 0x01, 0x00, 0x00, 0x00,
+
+ // 0x64: overlay_entry_count
0x03, 0x00, 0x00, 0x00,
- // 0x60: string_pool_offset
+ // 0x68: string_pool_offset
0x00, 0x00, 0x00, 0x00,
// TARGET ENTRIES
- // 0x64: target id (0x7f020000)
+ // 0x6c: target id (0x7f020000)
0x00, 0x00, 0x02, 0x7f,
- // 0x68: overlay_id (0x7f020000)
+ // 0x70: overlay_id (0x7f020000)
0x00, 0x00, 0x02, 0x7f,
- // 0x6c: target id (0x7f030000)
+ // 0x74: target id (0x7f030000)
0x00, 0x00, 0x03, 0x7f,
- // 0x70: overlay_id (0x7f030000)
+ // 0x78: overlay_id (0x7f030000)
0x00, 0x00, 0x03, 0x7f,
- // 0x74: target id (0x7f030002)
+ // 0x7c: target id (0x7f030002)
0x02, 0x00, 0x03, 0x7f,
- // 0x78: overlay_id (0x7f030001)
+ // 0x80: overlay_id (0x7f030001)
0x01, 0x00, 0x03, 0x7f,
// INLINE TARGET ENTRIES
- // 0x7c: target_id
+ // 0x84: target_id
0x00, 0x00, 0x04, 0x7f,
- // 0x80: Res_value::size (value ignored by idmap)
+ // 0x88: start value index
+ 0x00, 0x00, 0x00, 0x00,
+
+ // 0x8c: value count
+ 0x01, 0x00, 0x00, 0x00,
+
+ // INLINE TARGET ENTRY VALUES
+
+ // 0x90: config index
+ 0x00, 0x00, 0x00, 0x00,
+
+ // 0x94: Res_value::size (value ignored by idmap)
0x08, 0x00,
- // 0x82: Res_value::res0 (value ignored by idmap)
+ // 0x98: Res_value::res0 (value ignored by idmap)
0x00,
- // 0x83: Res_value::dataType (TYPE_INT_HEX)
+ // 0x9c: Res_value::dataType (TYPE_INT_HEX)
0x11,
- // 0x84: Res_value::data
+ // 0xa0: Res_value::data
0x78, 0x56, 0x34, 0x12,
+ // CONFIGURATIONS
+
+ // 0xa4: ConfigDescription
+ // size
+ 0x40, 0x00, 0x00, 0x00,
+ // 0xa8: imsi
+ 0x00, 0x00, 0x00, 0x00,
+ // 0xac: locale
+ 0x00, 0x00, 0x00, 0x00,
+ // 0xb0: screenType
+ 0x02, 0x00, 0xe0, 0x01,
+ // 0xb4: input
+ 0x00, 0x00, 0x00, 0x00,
+ // 0xb8: screenSize
+ 0x00, 0x00, 0x00, 0x00,
+ // 0xbc: version
+ 0x07, 0x00, 0x00, 0x00,
+ // 0xc0: screenConfig
+ 0x00, 0x00, 0x00, 0x00,
+ // 0xc4: screenSizeDp
+ 0x00, 0x00, 0x00, 0x00,
+ // 0xc8: localeScript
+ 0x00, 0x00, 0x00, 0x00,
+ // 0xcc: localVariant(1)
+ 0x00, 0x00, 0x00, 0x00,
+ // 0xd0: localVariant(2)
+ 0x00, 0x00, 0x00, 0x00,
+ // 0xd4: screenConfig2
+ 0x00, 0x00, 0x00, 0x00,
+ // 0xd8: localeScriptWasComputed
+ 0x00,
+ // 0xd9: localeNumberingSystem(1)
+ 0x00, 0x00, 0x00, 0x00,
+ // 0xdd: localeNumberingSystem(2)
+ 0x00, 0x00, 0x00, 0x00,
+
+ // 0xe1: padding
+ 0x00, 0x00, 0x00,
+
+
// OVERLAY ENTRIES
- // 0x88: 0x7f020000 -> 0x7f020000
+ // 0xe4: 0x7f020000 -> 0x7f020000
0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x02, 0x7f,
- // 0x90: 0x7f030000 -> 0x7f030000
+ // 0xec: 0x7f030000 -> 0x7f030000
0x00, 0x00, 0x03, 0x7f, 0x00, 0x00, 0x03, 0x7f,
- // 0x98: 0x7f030001 -> 0x7f030002
+ // 0xf4: 0x7f030001 -> 0x7f030002
0x01, 0x00, 0x03, 0x7f, 0x02, 0x00, 0x03, 0x7f,
- // 0xa0: string pool
+ // 0xfc: string pool
// string length,
0x04, 0x00, 0x00, 0x00,
- // 0xa4 string contents "test"
+ // 0x100 string contents "test"
0x74, 0x65, 0x73, 0x74};
-const unsigned int kIdmapRawDataLen = 0xa8;
+constexpr unsigned int kIdmapRawDataLen = std::size(kIdmapRawData);
const unsigned int kIdmapRawDataOffset = 0x54;
const unsigned int kIdmapRawDataTargetCrc = 0x1234;
const unsigned int kIdmapRawOverlayCrc = 0x5678;
diff --git a/cmds/idmap2/tests/data/overlay/res/drawable/android.png b/cmds/idmap2/tests/data/overlay/res/drawable/android.png
new file mode 100644
index 000000000000..b7317b0933fb
--- /dev/null
+++ b/cmds/idmap2/tests/data/overlay/res/drawable/android.png
Binary files differ
diff --git a/cmds/idmap2/tests/data/target/build b/cmds/idmap2/tests/data/target/build
index e6df742cc9da..cd13a7ec1bd8 100755
--- a/cmds/idmap2/tests/data/target/build
+++ b/cmds/idmap2/tests/data/target/build
@@ -17,5 +17,7 @@ aapt2 link --manifest AndroidManifest.xml -A assets -o target.apk compiled.flata
rm compiled.flata
aapt2 compile res/values/values.xml -o .
-aapt2 link --manifest AndroidManifest.xml -A assets -o target-no-overlayable.apk values_values.arsc.flat
-rm values_values.arsc.flat \ No newline at end of file
+aapt2 compile res/drawable/dr1.png -o .
+aapt2 link --manifest AndroidManifest.xml -A assets -o target-no-overlayable.apk values_values.arsc.flat drawable_dr1.png.flat
+rm values_values.arsc.flat
+rm drawable_dr1.png.flat
diff --git a/cmds/idmap2/tests/data/target/res/drawable/dr1.png b/cmds/idmap2/tests/data/target/res/drawable/dr1.png
new file mode 100644
index 000000000000..1a56e68fd6d2
--- /dev/null
+++ b/cmds/idmap2/tests/data/target/res/drawable/dr1.png
Binary files differ
diff --git a/cmds/idmap2/tests/data/target/res/values/overlayable.xml b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
index 57e6c439c23c..aac9081b9513 100644
--- a/cmds/idmap2/tests/data/target/res/values/overlayable.xml
+++ b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
@@ -63,6 +63,7 @@
<item type="string" name="y" />
<item type="string" name="z" />
<item type="integer" name="int1" />
+ <item type="drawable" name="dr1" />
</policy>
</overlayable>
diff --git a/cmds/idmap2/tests/data/target/target-no-overlayable.apk b/cmds/idmap2/tests/data/target/target-no-overlayable.apk
index cc3491de894d..680eeb609f8e 100644
--- a/cmds/idmap2/tests/data/target/target-no-overlayable.apk
+++ b/cmds/idmap2/tests/data/target/target-no-overlayable.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/target/target.apk b/cmds/idmap2/tests/data/target/target.apk
index 4a58c5e28f49..145e737ca138 100644
--- a/cmds/idmap2/tests/data/target/target.apk
+++ b/cmds/idmap2/tests/data/target/target.apk
Binary files differ
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index 7e6a521ca46c..d7222d248911 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -45,17 +45,23 @@ using namespace android;
#define COLORSPACE_SRGB 1
#define COLORSPACE_DISPLAY_P3 2
-static void usage(const char* pname, DisplayId displayId)
+static void usage(const char* pname, std::optional<PhysicalDisplayId> displayId)
{
+ std::string defaultDisplayStr = "";
+ if (!displayId) {
+ defaultDisplayStr = "";
+ } else {
+ defaultDisplayStr = " (default: " + to_string(*displayId) + ")";
+ }
fprintf(stderr,
"usage: %s [-hp] [-d display-id] [FILENAME]\n"
" -h: this message\n"
" -p: save the file as a png.\n"
- " -d: specify the display ID to capture (default: %s)\n"
+ " -d: specify the display ID to capture%s\n"
" see \"dumpsys SurfaceFlinger --display-id\" for valid display IDs.\n"
"If FILENAME ends with .png it will be saved as a png.\n"
"If FILENAME is not given, the results will be printed to stdout.\n",
- pname, to_string(displayId).c_str());
+ pname, defaultDisplayStr.c_str());
}
static int32_t flinger2bitmapFormat(PixelFormat f)
@@ -121,12 +127,12 @@ static status_t notifyMediaScanner(const char* fileName) {
int main(int argc, char** argv)
{
- std::optional<DisplayId> displayId = SurfaceComposerClient::getInternalDisplayId();
- if (!displayId) {
- fprintf(stderr, "Failed to get ID for internal display\n");
+ const std::vector<PhysicalDisplayId> ids = SurfaceComposerClient::getPhysicalDisplayIds();
+ if (ids.empty()) {
+ fprintf(stderr, "Failed to get ID for any displays.\n");
return 1;
}
-
+ std::optional<PhysicalDisplayId> displayId;
const char* pname = argv[0];
bool png = false;
int c;
@@ -136,18 +142,34 @@ int main(int argc, char** argv)
png = true;
break;
case 'd':
- displayId = DisplayId::fromValue(atoll(optarg));
+ displayId = DisplayId::fromValue<PhysicalDisplayId>(atoll(optarg));
if (!displayId) {
- fprintf(stderr, "Invalid display ID\n");
+ fprintf(stderr, "Invalid display ID: %s\n", optarg);
return 1;
}
break;
case '?':
case 'h':
- usage(pname, *displayId);
+ if (ids.size() == 1) {
+ displayId = ids.front();
+ }
+ usage(pname, displayId);
return 1;
}
}
+
+ if (!displayId) { // no diplsay id is specified
+ displayId = ids.front();
+ if (ids.size() > 1) {
+ fprintf(stderr,
+ "[Warning] Multiple displays were found, but no display id was specified! "
+ "Defaulting to the first display found, however this default is not guaranteed "
+ "to be consistent across captures. A display id should be specified.\n");
+ fprintf(stderr, "A display ID can be specified with the [-d display-id] option.\n");
+ fprintf(stderr, "See \"dumpsys SurfaceFlinger --display-id\" for valid display IDs.\n");
+ }
+ }
+
argc -= optind;
argv += optind;
@@ -169,7 +191,7 @@ int main(int argc, char** argv)
}
if (fd == -1) {
- usage(pname, *displayId);
+ usage(pname, displayId);
return 1;
}
@@ -193,7 +215,7 @@ int main(int argc, char** argv)
}
ScreenCaptureResults captureResults = captureListener->waitForResults();
- if (captureResults.result != NO_ERROR) {
+ if (!captureResults.fenceResult.ok()) {
close(fd);
return 1;
}
diff --git a/cmds/telecom/src/com/android/commands/telecom/Telecom.java b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
index d464e266ac36..13c7946a033f 100644
--- a/cmds/telecom/src/com/android/commands/telecom/Telecom.java
+++ b/cmds/telecom/src/com/android/commands/telecom/Telecom.java
@@ -54,7 +54,7 @@ public final class Telecom extends BaseCommand {
(new Telecom()).run(args);
}
-
+ private static final String CALLING_PACKAGE = Telecom.class.getPackageName();
private static final String COMMAND_SET_PHONE_ACCOUNT_ENABLED = "set-phone-account-enabled";
private static final String COMMAND_SET_PHONE_ACCOUNT_DISABLED = "set-phone-account-disabled";
private static final String COMMAND_REGISTER_PHONE_ACCOUNT = "register-phone-account";
@@ -297,7 +297,7 @@ public final class Telecom extends BaseCommand {
final String label = nextArgRequired();
PhoneAccount account = PhoneAccount.builder(handle, label)
.setCapabilities(PhoneAccount.CAPABILITY_CALL_PROVIDER).build();
- mTelecomService.registerPhoneAccount(account);
+ mTelecomService.registerPhoneAccount(account, CALLING_PACKAGE);
System.out.println("Success - " + handle + " registered.");
}
@@ -327,7 +327,7 @@ public final class Telecom extends BaseCommand {
.addSupportedUriScheme(PhoneAccount.SCHEME_TEL)
.addSupportedUriScheme(PhoneAccount.SCHEME_VOICEMAIL)
.build();
- mTelecomService.registerPhoneAccount(account);
+ mTelecomService.registerPhoneAccount(account, CALLING_PACKAGE);
System.out.println("Success - " + handle + " registered.");
}
@@ -369,7 +369,7 @@ public final class Telecom extends BaseCommand {
private void runUnregisterPhoneAccount() throws RemoteException {
final PhoneAccountHandle handle = getPhoneAccountHandleFromArgs();
- mTelecomService.unregisterPhoneAccount(handle);
+ mTelecomService.unregisterPhoneAccount(handle, CALLING_PACKAGE);
System.out.println("Success - " + handle + " unregistered.");
}
@@ -406,11 +406,11 @@ public final class Telecom extends BaseCommand {
}
private void runGetDefaultDialer() throws RemoteException {
- System.out.println(mTelecomService.getDefaultDialerPackage());
+ System.out.println(mTelecomService.getDefaultDialerPackage(CALLING_PACKAGE));
}
private void runGetSystemDialer() throws RemoteException {
- System.out.println(mTelecomService.getSystemDialerPackage());
+ System.out.println(mTelecomService.getSystemDialerPackage(CALLING_PACKAGE));
}
private void runWaitOnHandler() throws RemoteException {
diff --git a/cmds/uinput/jni/com_android_commands_uinput_Device.cpp b/cmds/uinput/jni/com_android_commands_uinput_Device.cpp
index 06fa2aac2c7e..3f4163dc54ec 100644
--- a/cmds/uinput/jni/com_android_commands_uinput_Device.cpp
+++ b/cmds/uinput/jni/com_android_commands_uinput_Device.cpp
@@ -99,6 +99,7 @@ JNIEnv* DeviceCallback::getJNIEnv() {
std::unique_ptr<UinputDevice> UinputDevice::open(int32_t id, const char* name, int32_t vid,
int32_t pid, uint16_t bus, uint32_t ffEffectsMax,
+ const char* port,
std::unique_ptr<DeviceCallback> callback) {
android::base::unique_fd fd(::open(UINPUT_PATH, O_RDWR | O_NONBLOCK | O_CLOEXEC));
if (!fd.ok()) {
@@ -131,6 +132,9 @@ std::unique_ptr<UinputDevice> UinputDevice::open(int32_t id, const char* name, i
return nullptr;
}
+ // set the physical port.
+ ::ioctl(fd, UI_SET_PHYS, port);
+
if (::ioctl(fd, UI_DEV_CREATE) != 0) {
ALOGE("Unable to create uinput device: %s.", strerror(errno));
return nullptr;
@@ -240,17 +244,19 @@ std::vector<int32_t> toVector(JNIEnv* env, jintArray javaArray) {
}
static jlong openUinputDevice(JNIEnv* env, jclass /* clazz */, jstring rawName, jint id, jint vid,
- jint pid, jint bus, jint ffEffectsMax, jobject callback) {
+ jint pid, jint bus, jint ffEffectsMax, jstring rawPort,
+ jobject callback) {
ScopedUtfChars name(env, rawName);
if (name.c_str() == nullptr) {
return 0;
}
+ ScopedUtfChars port(env, rawPort);
std::unique_ptr<uinput::DeviceCallback> cb =
std::make_unique<uinput::DeviceCallback>(env, callback);
std::unique_ptr<uinput::UinputDevice> d =
- uinput::UinputDevice::open(id, name.c_str(), vid, pid, bus, ffEffectsMax,
+ uinput::UinputDevice::open(id, name.c_str(), vid, pid, bus, ffEffectsMax, port.c_str(),
std::move(cb));
return reinterpret_cast<jlong>(d.release());
}
@@ -303,7 +309,7 @@ static void setAbsInfo(JNIEnv* env, jclass /* clazz */, jint handle, jint axisCo
static JNINativeMethod sMethods[] = {
{"nativeOpenUinputDevice",
- "(Ljava/lang/String;IIIII"
+ "(Ljava/lang/String;IIIIILjava/lang/String;"
"Lcom/android/commands/uinput/Device$DeviceCallback;)J",
reinterpret_cast<void*>(openUinputDevice)},
{"nativeInjectEvent", "(JIII)V", reinterpret_cast<void*>(injectEvent)},
diff --git a/cmds/uinput/jni/com_android_commands_uinput_Device.h b/cmds/uinput/jni/com_android_commands_uinput_Device.h
index 5a9a06cfb32e..6da3d7968ed0 100644
--- a/cmds/uinput/jni/com_android_commands_uinput_Device.h
+++ b/cmds/uinput/jni/com_android_commands_uinput_Device.h
@@ -48,6 +48,7 @@ class UinputDevice {
public:
static std::unique_ptr<UinputDevice> open(int32_t id, const char* name, int32_t vid,
int32_t pid, uint16_t bus, uint32_t ff_effects_max,
+ const char* port,
std::unique_ptr<DeviceCallback> callback);
virtual ~UinputDevice();
diff --git a/cmds/uinput/src/com/android/commands/uinput/Device.java b/cmds/uinput/src/com/android/commands/uinput/Device.java
index 62bee7b964bd..732b33d60c15 100644
--- a/cmds/uinput/src/com/android/commands/uinput/Device.java
+++ b/cmds/uinput/src/com/android/commands/uinput/Device.java
@@ -61,7 +61,7 @@ public class Device {
}
private static native long nativeOpenUinputDevice(String name, int id, int vid, int pid,
- int bus, int ffEffectsMax, DeviceCallback callback);
+ int bus, int ffEffectsMax, String port, DeviceCallback callback);
private static native void nativeCloseUinputDevice(long ptr);
private static native void nativeInjectEvent(long ptr, int type, int code, int value);
private static native void nativeConfigure(int handle, int code, int[] configs);
@@ -69,7 +69,7 @@ public class Device {
public Device(int id, String name, int vid, int pid, int bus,
SparseArray<int[]> configuration, int ffEffectsMax,
- SparseArray<InputAbsInfo> absInfo) {
+ SparseArray<InputAbsInfo> absInfo, String port) {
mId = id;
mThread = new HandlerThread("UinputDeviceHandler");
mThread.start();
@@ -88,6 +88,11 @@ public class Device {
} else {
args.arg1 = id + ":" + vid + ":" + pid;
}
+ if (port != null) {
+ args.arg2 = port;
+ } else {
+ args.arg2 = "uinput:" + id + ":" + vid + ":" + pid;
+ }
mHandler.obtainMessage(MSG_OPEN_UINPUT_DEVICE, args).sendToTarget();
mTimeToSend = SystemClock.uptimeMillis();
@@ -142,7 +147,7 @@ public class Device {
case MSG_OPEN_UINPUT_DEVICE:
SomeArgs args = (SomeArgs) msg.obj;
mPtr = nativeOpenUinputDevice((String) args.arg1, args.argi1, args.argi2,
- args.argi3, args.argi4, args.argi5,
+ args.argi3, args.argi4, args.argi5, (String) args.arg2,
new DeviceCallback());
break;
case MSG_INJECT_EVENT:
diff --git a/cmds/uinput/src/com/android/commands/uinput/Event.java b/cmds/uinput/src/com/android/commands/uinput/Event.java
index c4ba05054eda..4b090f5a713c 100644
--- a/cmds/uinput/src/com/android/commands/uinput/Event.java
+++ b/cmds/uinput/src/com/android/commands/uinput/Event.java
@@ -25,6 +25,7 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.stream.IntStream;
import src.com.android.commands.uinput.InputAbsInfo;
@@ -64,6 +65,7 @@ public class Event {
private SparseArray<int[]> mConfiguration;
private int mDuration;
private int mFfEffectsMax = 0;
+ private String mInputport;
private SparseArray<InputAbsInfo> mAbsInfo;
public int getId() {
@@ -110,6 +112,10 @@ public class Event {
return mAbsInfo;
}
+ public String getPort() {
+ return mInputport;
+ }
+
/**
* Convert an event to String.
*/
@@ -124,6 +130,7 @@ public class Event {
+ ", configuration=" + mConfiguration
+ ", duration=" + mDuration
+ ", ff_effects_max=" + mFfEffectsMax
+ + ", port=" + mInputport
+ "}";
}
@@ -178,6 +185,10 @@ public class Event {
mEvent.mAbsInfo = absInfo;
}
+ public void setInputport(String port) {
+ mEvent.mInputport = port;
+ }
+
public Event build() {
if (mEvent.mId == -1) {
throw new IllegalStateException("No event id");
@@ -262,6 +273,9 @@ public class Event {
case "duration":
eb.setDuration(readInt());
break;
+ case "port":
+ eb.setInputport(mReader.nextString());
+ break;
default:
mReader.skipValue();
}
@@ -325,7 +339,7 @@ public class Event {
mReader.beginArray();
while (mReader.hasNext()) {
int type = 0;
- int[] data = null;
+ IntStream data = null;
mReader.beginObject();
while (mReader.hasNext()) {
String name = mReader.nextName();
@@ -334,8 +348,7 @@ public class Event {
type = readInt();
break;
case "data":
- data = readIntList().stream()
- .mapToInt(Integer::intValue).toArray();
+ data = readIntList().stream().mapToInt(Integer::intValue);
break;
default:
consumeRemainingElements();
@@ -346,7 +359,9 @@ public class Event {
}
mReader.endObject();
if (data != null) {
- configuration.put(type, data);
+ final int[] existing = configuration.get(type);
+ configuration.put(type, existing == null ? data.toArray()
+ : IntStream.concat(IntStream.of(existing), data).toArray());
}
}
mReader.endArray();
diff --git a/cmds/uinput/src/com/android/commands/uinput/Uinput.java b/cmds/uinput/src/com/android/commands/uinput/Uinput.java
index f7601a2f7c07..740578e878ac 100644
--- a/cmds/uinput/src/com/android/commands/uinput/Uinput.java
+++ b/cmds/uinput/src/com/android/commands/uinput/Uinput.java
@@ -123,7 +123,7 @@ public class Uinput {
}
int id = e.getId();
Device d = new Device(id, e.getName(), e.getVendorId(), e.getProductId(), e.getBus(),
- e.getConfiguration(), e.getFfEffectsMax(), e.getAbsInfo());
+ e.getConfiguration(), e.getFfEffectsMax(), e.getAbsInfo(), e.getPort());
mDevices.append(id, d);
}