diff options
Diffstat (limited to 'cmds')
-rw-r--r-- | cmds/bootanimation/Android.bp | 16 | ||||
-rw-r--r-- | cmds/bootanimation/BootAnimation.cpp | 496 | ||||
-rw-r--r-- | cmds/bootanimation/BootAnimation.h | 50 | ||||
-rw-r--r-- | cmds/bootanimation/bootanimation_flags.aconfig | 12 | ||||
-rw-r--r-- | cmds/idmap2/include/idmap2/Idmap.h | 11 | ||||
-rw-r--r-- | cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp | 60 | ||||
-rw-r--r-- | cmds/idmap2/libidmap2/Idmap.cpp | 94 | ||||
-rw-r--r-- | cmds/idmap2/libidmap2/ResourceContainer.cpp | 16 | ||||
-rw-r--r-- | cmds/idmap2/tests/IdmapTests.cpp | 6 | ||||
-rw-r--r-- | cmds/idmap2/tests/RawPrintVisitorTests.cpp | 4 | ||||
-rw-r--r-- | cmds/idmap2/tests/TestHelpers.h | 38 | ||||
-rw-r--r-- | cmds/uinput/README.md | 5 |
12 files changed, 442 insertions, 366 deletions
diff --git a/cmds/bootanimation/Android.bp b/cmds/bootanimation/Android.bp index 3534624a58a2..f80ccf7a56fb 100644 --- a/cmds/bootanimation/Android.bp +++ b/cmds/bootanimation/Android.bp @@ -7,6 +7,18 @@ package { default_applicable_licenses: ["frameworks_base_license"], } +aconfig_declarations { + name: "bootanimation_flags", + package: "com.android.graphics.bootanimation.flags", + container: "system", + srcs: ["bootanimation_flags.aconfig"], +} + +cc_aconfig_library { + name: "libbootanimationflags", + aconfig_declarations: "bootanimation_flags", +} + cc_defaults { name: "bootanimation_defaults", @@ -28,6 +40,10 @@ cc_defaults { "liblog", "libutils", ], + + static_libs: [ + "libbootanimationflags", + ], } // bootanimation executable diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index c2f6e3072507..b43905b19239 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -15,6 +15,7 @@ */ #define LOG_NDEBUG 0 + #define LOG_TAG "BootAnimation" #define ATRACE_TAG ATRACE_TAG_GRAPHICS @@ -61,6 +62,8 @@ #include "BootAnimation.h" +#include <com_android_graphics_bootanimation_flags.h> + #define ANIM_PATH_MAX 255 #define STR(x) #x #define STRTO(x) STR(x) @@ -106,7 +109,6 @@ static const int TEXT_CENTER_VALUE = INT_MAX; static const int TEXT_MISSING_VALUE = INT_MIN; static const char EXIT_PROP_NAME[] = "service.bootanim.exit"; static const char PROGRESS_PROP_NAME[] = "service.bootanim.progress"; -static const char DISPLAYS_PROP_NAME[] = "persist.service.bootanim.displays"; static const char CLOCK_ENABLED_PROP_NAME[] = "persist.sys.bootanim.clock.enabled"; static const int ANIM_ENTRY_NAME_MAX = ANIM_PATH_MAX + 1; static const int MAX_CHECK_EXIT_INTERVAL_US = 50000; @@ -449,19 +451,21 @@ public: auto token = SurfaceComposerClient::getPhysicalDisplayToken( event.header.displayId); - if (token != mBootAnimation->mDisplayToken) { + auto& firstDisplay = mBootAnimation->mDisplays.front(); + if (token != firstDisplay.displayToken) { // ignore hotplug of a secondary display continue; } DisplayMode displayMode; const status_t error = SurfaceComposerClient::getActiveDisplayMode( - mBootAnimation->mDisplayToken, &displayMode); + firstDisplay.displayToken, &displayMode); if (error != NO_ERROR) { SLOGE("Can't get active display mode."); } mBootAnimation->resizeSurface(displayMode.resolution.getWidth(), - displayMode.resolution.getHeight()); + displayMode.resolution.getHeight(), + firstDisplay); } } } while (numEvents > 0); @@ -507,141 +511,106 @@ ui::Size BootAnimation::limitSurfaceSize(int width, int height) const { status_t BootAnimation::readyToRun() { ATRACE_CALL(); mAssets.addDefaultAssets(); + return initDisplaysAndSurfaces(); +} - const std::vector<PhysicalDisplayId> ids = SurfaceComposerClient::getPhysicalDisplayIds(); - if (ids.empty()) { - SLOGE("Failed to get ID for any displays\n"); +status_t BootAnimation::initDisplaysAndSurfaces() { + std::vector<PhysicalDisplayId> displayIds = SurfaceComposerClient::getPhysicalDisplayIds(); + if (displayIds.empty()) { + SLOGE("Failed to get ID for any displays"); return NAME_NOT_FOUND; } - // 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; - char displayValue[PROPERTY_VALUE_MAX] = ""; - property_get(DISPLAYS_PROP_NAME, displayValue, ""); - bool isValid = displayValue[0] != '\0'; - if (isValid) { - char *p = displayValue; - while (*p) { - if (!isdigit(*p) && *p != ',') { - isValid = false; - break; - } - p ++; - } - if (!isValid) - SLOGE("Invalid syntax for the value of system prop: %s", DISPLAYS_PROP_NAME); - } - if (isValid) { - std::istringstream stream(displayValue); - for (PhysicalDisplayId id; stream >> id.value; ) { - physicalDisplayIds.add(id); - if (stream.peek() == ',') - 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 Multi-Display isn't explicitly enabled, ignore all displays after the first one + if (!com::android::graphics::bootanimation::flags::multidisplay()) { + displayIds.erase(displayIds.begin() + 1, displayIds.end()); } - // If the system property is not present or invalid, display 0 is used - if (mDisplayToken == nullptr) { - mDisplayToken = SurfaceComposerClient::getPhysicalDisplayToken(ids.front()); - if (mDisplayToken == nullptr) { + for (const auto id : displayIds) { + if (const auto token = SurfaceComposerClient::getPhysicalDisplayToken(id)) { + mDisplays.push_back({.displayToken = token}); + } else { + SLOGE("Failed to get display token for a display"); + SLOGE("Failed to get display token for display %" PRIu64, id.value); return NAME_NOT_FOUND; } } - DisplayMode displayMode; - const status_t error = - SurfaceComposerClient::getActiveDisplayMode(mDisplayToken, &displayMode); - if (error != NO_ERROR) { - return error; - } + // Initialize EGL + mEgl = eglGetDisplay(EGL_DEFAULT_DISPLAY); + eglInitialize(mEgl, nullptr, nullptr); + EGLConfig config = getEglConfig(mEgl); + EGLint contextAttributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; + mEglContext = eglCreateContext(mEgl, config, nullptr, contextAttributes); 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 - for (const auto id : physicalDisplayIds) { - if (std::find(ids.begin(), ids.end(), id) != ids.end()) { - if (const auto token = SurfaceComposerClient::getPhysicalDisplayToken(id)) { - t.setDisplayLayerStack(token, ui::DEFAULT_LAYER_STACK); - } - } + for (size_t displayIdx = 0; displayIdx < mDisplays.size(); displayIdx++) { + auto& display = mDisplays[displayIdx]; + DisplayMode displayMode; + const status_t error = + SurfaceComposerClient::getActiveDisplayMode(display.displayToken, &displayMode); + if (error != NO_ERROR) { + return error; } - t.setLayerStack(control, ui::DEFAULT_LAYER_STACK); - } - - t.setLayer(control, 0x40000000) - .apply(); - - sp<Surface> s = control->getSurface(); - - // initialize opengl and egl - EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - eglInitialize(display, nullptr, nullptr); - EGLConfig config = getEglConfig(display); - EGLSurface surface = eglCreateWindowSurface(display, config, s.get(), nullptr); - // Initialize egl context with client version number 2.0. - EGLint contextAttributes[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}; - EGLContext context = eglCreateContext(display, config, nullptr, contextAttributes); - EGLint w, h; - eglQuerySurface(display, surface, EGL_WIDTH, &w); - eglQuerySurface(display, surface, EGL_HEIGHT, &h); - - if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) { - return NO_INIT; - } - - mDisplay = display; - mContext = context; - mSurface = surface; - mInitWidth = mWidth = w; - mInitHeight = mHeight = h; - mFlingerSurfaceControl = control; - mFlingerSurface = s; - mTargetInset = -1; - - // Rotate the boot animation according to the value specified in the sysprop - // ro.bootanim.set_orientation_<display_id>. Four values are supported: ORIENTATION_0, - // ORIENTATION_90, ORIENTATION_180 and ORIENTATION_270. - // If the value isn't specified or is ORIENTATION_0, nothing will be changed. - // This is needed to support having boot animation in orientations different from the natural - // device orientation. For example, on tablets that may want to keep natural orientation - // portrait for applications compatibility and to have the boot animation in landscape. - rotateAwayFromNaturalOrientationIfNeeded(); - - projectSceneToWindow(); + ui::Size resolution = displayMode.resolution; + // Clamp each surface to max size + resolution = limitSurfaceSize(resolution.width, resolution.height); + // Create the native surface + display.surfaceControl = + session()->createSurface(String8("BootAnimation"), resolution.width, + resolution.height, PIXEL_FORMAT_RGB_565, + ISurfaceComposerClient::eOpaque); + // Attach surface to layerstack, and associate layerstack with physical display + configureDisplayAndLayerStack(display, ui::LayerStack::fromValue(displayIdx)); + display.surface = display.surfaceControl->getSurface(); + display.eglSurface = eglCreateWindowSurface(mEgl, config, display.surface.get(), nullptr); + + EGLint w, h; + eglQuerySurface(mEgl, display.eglSurface, EGL_WIDTH, &w); + eglQuerySurface(mEgl, display.eglSurface, EGL_HEIGHT, &h); + if (eglMakeCurrent(mEgl, display.eglSurface, display.eglSurface, + mEglContext) == EGL_FALSE) { + return NO_INIT; + } + display.initWidth = display.width = w; + display.initHeight = display.height = h; + mTargetInset = -1; + + // Rotate the boot animation according to the value specified in the sysprop + // ro.bootanim.set_orientation_<display_id>. Four values are supported: ORIENTATION_0, + // ORIENTATION_90, ORIENTATION_180 and ORIENTATION_270. + // If the value isn't specified or is ORIENTATION_0, nothing will be changed. + // This is needed to support boot animation in orientations different from the natural + // device orientation. For example, on tablets that may want to keep natural orientation + // portrait for applications compatibility and to have the boot animation in landscape. + rotateAwayFromNaturalOrientationIfNeeded(display); + + projectSceneToWindow(display); + } // end iteration over all display tokens // Register a display event receiver mDisplayEventReceiver = std::make_unique<DisplayEventReceiver>(); status_t status = mDisplayEventReceiver->initCheck(); SLOGE_IF(status != NO_ERROR, "Initialization of DisplayEventReceiver failed with status: %d", - status); + status); mLooper->addFd(mDisplayEventReceiver->getFd(), 0, Looper::EVENT_INPUT, - new DisplayEventCallback(this), nullptr); + new DisplayEventCallback(this), nullptr); return NO_ERROR; } -void BootAnimation::rotateAwayFromNaturalOrientationIfNeeded() { +void BootAnimation::configureDisplayAndLayerStack(const Display& display, + ui::LayerStack layerStack) { + SurfaceComposerClient::Transaction t; + t.setDisplayLayerStack(display.displayToken, layerStack); + t.setLayerStack(display.surfaceControl, layerStack) + .setLayer(display.surfaceControl, 0x40000000) + .apply(); +} + +void BootAnimation::rotateAwayFromNaturalOrientationIfNeeded(Display& display) { ATRACE_CALL(); const auto orientation = parseOrientationProperty(); @@ -651,16 +620,16 @@ void BootAnimation::rotateAwayFromNaturalOrientationIfNeeded() { } if (orientation == ui::ROTATION_90 || orientation == ui::ROTATION_270) { - std::swap(mWidth, mHeight); - std::swap(mInitWidth, mInitHeight); - mFlingerSurfaceControl->updateDefaultBufferSize(mWidth, mHeight); + std::swap(display.width, display.height); + std::swap(display.initWidth, display.initHeight); + display.surfaceControl->updateDefaultBufferSize(display.width, display.height); } - Rect displayRect(0, 0, mWidth, mHeight); - Rect layerStackRect(0, 0, mWidth, mHeight); + Rect displayRect(0, 0, display.width, display.height); + Rect layerStackRect(0, 0, display.width, display.height); SurfaceComposerClient::Transaction t; - t.setDisplayProjection(mDisplayToken, orientation, layerStackRect, displayRect); + t.setDisplayProjection(display.displayToken, orientation, layerStackRect, displayRect); t.apply(); } @@ -691,38 +660,37 @@ ui::Rotation BootAnimation::parseOrientationProperty() { return ui::ROTATION_0; } -void BootAnimation::projectSceneToWindow() { +void BootAnimation::projectSceneToWindow(const Display& display) { ATRACE_CALL(); - glViewport(0, 0, mWidth, mHeight); - glScissor(0, 0, mWidth, mHeight); + glViewport(0, 0, display.width, display.height); + glScissor(0, 0, display.width, display.height); } -void BootAnimation::resizeSurface(int newWidth, int newHeight) { +void BootAnimation::resizeSurface(int newWidth, int newHeight, Display& display) { ATRACE_CALL(); // We assume this function is called on the animation thread. - if (newWidth == mWidth && newHeight == mHeight) { + if (newWidth == display.width && newHeight == display.height) { return; } - SLOGV("Resizing the boot animation surface to %d %d", newWidth, newHeight); - eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglDestroySurface(mDisplay, mSurface); + eglMakeCurrent(mEgl, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(mEgl, display.eglSurface); const auto limitedSize = limitSurfaceSize(newWidth, newHeight); - mWidth = limitedSize.width; - mHeight = limitedSize.height; - - mFlingerSurfaceControl->updateDefaultBufferSize(mWidth, mHeight); - EGLConfig config = getEglConfig(mDisplay); - EGLSurface surface = eglCreateWindowSurface(mDisplay, config, mFlingerSurface.get(), nullptr); - if (eglMakeCurrent(mDisplay, surface, surface, mContext) == EGL_FALSE) { - SLOGE("Can't make the new surface current. Error %d", eglGetError()); + display.width = limitedSize.width; + display.height = limitedSize.height; + + display.surfaceControl->updateDefaultBufferSize(display.width, display.height); + EGLConfig config = getEglConfig(mEgl); + EGLSurface eglSurface = eglCreateWindowSurface(mEgl, config, display.surface.get(), nullptr); + if (eglMakeCurrent(mEgl, eglSurface, eglSurface, mEglContext) == EGL_FALSE) { + SLOGE("Can't make the new eglSurface current. Error %d", eglGetError()); return; } - projectSceneToWindow(); + projectSceneToWindow(display); - mSurface = surface; + display.eglSurface = eglSurface; } bool BootAnimation::preloadAnimation() { @@ -852,24 +820,26 @@ bool BootAnimation::threadLoop() { // animation. if (mZipFileName.empty()) { ALOGD("No animation file"); - result = android(); + result = android(mDisplays.front()); } else { result = movie(); } mCallbacks->shutdown(); - eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - eglDestroyContext(mDisplay, mContext); - eglDestroySurface(mDisplay, mSurface); - mFlingerSurface.clear(); - mFlingerSurfaceControl.clear(); - eglTerminate(mDisplay); + eglMakeCurrent(mEgl, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroyContext(mEgl, mEglContext); + for (auto& display : mDisplays) { + eglDestroySurface(mEgl, display.eglSurface); + display.surface.clear(); + display.surfaceControl.clear(); + } + eglTerminate(mEgl); eglReleaseThread(); IPCThreadState::self()->stopProcess(); return result; } -bool BootAnimation::android() { +bool BootAnimation::android(const Display& display) { ATRACE_CALL(); glActiveTexture(GL_TEXTURE0); @@ -887,7 +857,7 @@ bool BootAnimation::android() { glClearColor(0,0,0,1); glClear(GL_COLOR_BUFFER_BIT); - eglSwapBuffers(mDisplay, mSurface); + eglSwapBuffers(mEgl, display.eglSurface); // Blend state glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -895,11 +865,11 @@ bool BootAnimation::android() { const nsecs_t startTime = systemTime(); do { processDisplayEvents(); - const GLint xc = (mWidth - mAndroid[0].w) / 2; - const GLint yc = (mHeight - mAndroid[0].h) / 2; + const GLint xc = (display.width - mAndroid[0].w) / 2; + const GLint yc = (display.height - mAndroid[0].h) / 2; const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h); - glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(), - updateRect.height()); + glScissor(updateRect.left, display.height - updateRect.bottom, updateRect.width(), + updateRect.height()); nsecs_t now = systemTime(); double time = now - startTime; @@ -913,14 +883,14 @@ bool BootAnimation::android() { glEnable(GL_SCISSOR_TEST); glDisable(GL_BLEND); glBindTexture(GL_TEXTURE_2D, mAndroid[1].name); - drawTexturedQuad(x, yc, mAndroid[1].w, mAndroid[1].h); - drawTexturedQuad(x + mAndroid[1].w, yc, mAndroid[1].w, mAndroid[1].h); + drawTexturedQuad(x, yc, mAndroid[1].w, mAndroid[1].h, display); + drawTexturedQuad(x + mAndroid[1].w, yc, mAndroid[1].w, mAndroid[1].h, display); glEnable(GL_BLEND); glBindTexture(GL_TEXTURE_2D, mAndroid[0].name); - drawTexturedQuad(xc, yc, mAndroid[0].w, mAndroid[0].h); + drawTexturedQuad(xc, yc, mAndroid[0].w, mAndroid[0].h, display); - EGLBoolean res = eglSwapBuffers(mDisplay, mSurface); + EGLBoolean res = eglSwapBuffers(mEgl, display.eglSurface); if (res == EGL_FALSE) break; @@ -939,7 +909,7 @@ bool BootAnimation::android() { void BootAnimation::checkExit() { ATRACE_CALL(); - // Allow surface flinger to gracefully request shutdown + // Allow SurfaceFlinger to gracefully request shutdown char value[PROPERTY_VALUE_MAX]; property_get(EXIT_PROP_NAME, value, "0"); int exitnow = atoi(value); @@ -1085,7 +1055,8 @@ status_t BootAnimation::initFont(Font* font, const char* fallback) { return status; } -void BootAnimation::drawText(const char* str, const Font& font, bool bold, int* x, int* y) { +void BootAnimation::drawText(const char* str, const Font& font, bool bold, + int* x, int* y, const Display& display) { ATRACE_CALL(); glEnable(GL_BLEND); // Allow us to draw on top of the animation glBindTexture(GL_TEXTURE_2D, font.texture.name); @@ -1096,14 +1067,14 @@ void BootAnimation::drawText(const char* str, const Font& font, bool bold, int* const int strWidth = font.char_width * len; if (*x == TEXT_CENTER_VALUE) { - *x = (mWidth - strWidth) / 2; + *x = (display.width - strWidth) / 2; } else if (*x < 0) { - *x = mWidth + *x - strWidth; + *x = display.width + *x - strWidth; } if (*y == TEXT_CENTER_VALUE) { - *y = (mHeight - font.char_height) / 2; + *y = (display.height - font.char_height) / 2; } else if (*y < 0) { - *y = mHeight + *y - font.char_height; + *y = display.height + *y - font.char_height; } for (int i = 0; i < len; i++) { @@ -1123,7 +1094,7 @@ void BootAnimation::drawText(const char* str, const Font& font, bool bold, int* float v1 = v0 + 1.0f / FONT_NUM_ROWS / 2; float u1 = u0 + 1.0f / FONT_NUM_COLS; glUniform4f(mTextCropAreaLocation, u0, v0, u1, v1); - drawTexturedQuad(*x, *y, font.char_width, font.char_height); + drawTexturedQuad(*x, *y, font.char_width, font.char_height, display); *x += font.char_width; } @@ -1133,7 +1104,8 @@ void BootAnimation::drawText(const char* str, const Font& font, bool bold, int* } // We render 12 or 24 hour time. -void BootAnimation::drawClock(const Font& font, const int xPos, const int yPos) { +void BootAnimation::drawClock(const Font& font, const int xPos, const int yPos, + const Display& display) { ATRACE_CALL(); static constexpr char TIME_FORMAT_12[] = "%l:%M"; static constexpr char TIME_FORMAT_24[] = "%H:%M"; @@ -1156,10 +1128,11 @@ void BootAnimation::drawClock(const Font& font, const int xPos, const int yPos) char* out = timeBuff[0] == ' ' ? &timeBuff[1] : &timeBuff[0]; int x = xPos; int y = yPos; - drawText(out, font, false, &x, &y); + drawText(out, font, false, &x, &y, display); } -void BootAnimation::drawProgress(int percent, const Font& font, const int xPos, const int yPos) { +void BootAnimation::drawProgress(int percent, const Font& font, const int xPos, const int yPos, + const Display& display) { ATRACE_CALL(); static constexpr int PERCENT_LENGTH = 5; @@ -1169,7 +1142,7 @@ void BootAnimation::drawProgress(int percent, const Font& font, const int xPos, sprintf(percentBuff, "%d;", percent); int x = xPos; int y = yPos; - drawText(percentBuff, font, false, &x, &y); + drawText(percentBuff, font, false, &x, &y, display); } bool BootAnimation::parseAnimationDesc(Animation& animation) { @@ -1298,8 +1271,7 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) { bool BootAnimation::preloadZip(Animation& animation) { ATRACE_CALL(); - // read all the data structures - const size_t pcount = animation.parts.size(); + const size_t numParts = animation.parts.size(); void *cookie = nullptr; ZipFileRO* zip = animation.zip; if (!zip->startIteration(&cookie)) { @@ -1335,8 +1307,8 @@ bool BootAnimation::preloadZip(Animation& animation) { continue; } - for (size_t j = 0; j < pcount; j++) { - if (path.string() == animation.parts[j].path.c_str()) { + for (size_t partIdx = 0; partIdx < numParts; partIdx++) { + if (path.string() == animation.parts[partIdx].path.c_str()) { uint16_t method; // supports only stored png files if (zip->getEntryInfo(entry, &method, nullptr, nullptr, nullptr, nullptr, @@ -1344,7 +1316,7 @@ bool BootAnimation::preloadZip(Animation& animation) { if (method == ZipFileRO::kCompressStored) { FileMap* map = zip->createEntryFileMap(entry); if (map) { - Animation::Part& part(animation.parts.editItemAt(j)); + Animation::Part& part(animation.parts.editItemAt(partIdx)); if (leaf == "audio.wav") { // a part may have at most one audio file part.audioData = (uint8_t *)map->getDataPtr(); @@ -1375,7 +1347,8 @@ bool BootAnimation::preloadZip(Animation& animation) { // If there is trimData present, override the positioning defaults. for (Animation::Part& part : animation.parts) { const char* trimDataStr = part.trimData.c_str(); - for (size_t frameIdx = 0; frameIdx < part.frames.size(); frameIdx++) { + const size_t numFramesInPart = part.frames.size(); + for (size_t frameIdxInPart = 0; frameIdxInPart < numFramesInPart; frameIdxInPart++) { const char* endl = strstr(trimDataStr, "\n"); // No more trimData for this part. if (endl == nullptr) { @@ -1386,7 +1359,7 @@ bool BootAnimation::preloadZip(Animation& animation) { trimDataStr = ++endl; int width = 0, height = 0, x = 0, y = 0; if (sscanf(lineStr, "%dx%d+%d+%d", &width, &height, &x, &y) == 4) { - Animation::Frame& frame(part.frames.editItemAt(frameIdx)); + Animation::Frame& frame(part.frames.editItemAt(frameIdxInPart)); frame.trimWidth = width; frame.trimHeight = height; frame.trimX = x; @@ -1509,13 +1482,15 @@ float mapLinear(float x, float a1, float a2, float b1, float b2) { return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); } -void BootAnimation::drawTexturedQuad(float xStart, float yStart, float width, float height) { +void BootAnimation::drawTexturedQuad(float xStart, float yStart, + float width, float height, + const Display& display) { ATRACE_CALL(); // Map coordinates from screen space to world space. - float x0 = mapLinear(xStart, 0, mWidth, -1, 1); - float y0 = mapLinear(yStart, 0, mHeight, -1, 1); - float x1 = mapLinear(xStart + width, 0, mWidth, -1, 1); - float y1 = mapLinear(yStart + height, 0, mHeight, -1, 1); + float x0 = mapLinear(xStart, 0, display.width, -1, 1); + float y0 = mapLinear(yStart, 0, display.height, -1, 1); + float x1 = mapLinear(xStart + width, 0, display.width, -1, 1); + float y1 = mapLinear(yStart + height, 0, display.height, -1, 1); // Update quad vertex positions. quadPositions[0] = x0; quadPositions[1] = y0; @@ -1562,7 +1537,7 @@ void BootAnimation::initDynamicColors() { bool BootAnimation::playAnimation(const Animation& animation) { ATRACE_CALL(); - const size_t pcount = animation.parts.size(); + const size_t numParts = animation.parts.size(); nsecs_t frameDuration = s2ns(1) / animation.fps; SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot", @@ -1572,9 +1547,9 @@ bool BootAnimation::playAnimation(const Animation& animation) { int lastDisplayedProgress = 0; int colorTransitionStart = animation.colorTransitionStart; int colorTransitionEnd = animation.colorTransitionEnd; - for (size_t i=0 ; i<pcount ; i++) { - const Animation::Part& part(animation.parts[i]); - const size_t fcount = part.frames.size(); + for (size_t partIdx = 0; partIdx < numParts; partIdx++) { + const Animation::Part& part(animation.parts[partIdx]); + const size_t numFramesInPart = part.frames.size(); glBindTexture(GL_TEXTURE_2D, 0); // Handle animation package @@ -1586,7 +1561,9 @@ bool BootAnimation::playAnimation(const Animation& animation) { } // process the part not only while the count allows but also if already fading - for (int r=0 ; !part.count || r<part.count || fadedFramesCount > 0 ; r++) { + for (int frameIdx = 0; + !part.count || frameIdx < part.count || fadedFramesCount > 0; + frameIdx++) { if (shouldStopPlayingPart(part, fadedFramesCount, lastDisplayedProgress)) break; // It's possible that the sysprops were not loaded yet at this boot phase. @@ -1601,12 +1578,12 @@ bool BootAnimation::playAnimation(const Animation& animation) { const int transitionLength = colorTransitionEnd - colorTransitionStart; if (part.postDynamicColoring) { colorTransitionStart = 0; - colorTransitionEnd = fmin(transitionLength, fcount - 1); + colorTransitionEnd = fmin(transitionLength, numFramesInPart - 1); } } } - mCallbacks->playPart(i, part, r); + mCallbacks->playPart(partIdx, part, frameIdx); glClearColor( part.backgroundColor[0], @@ -1620,11 +1597,10 @@ bool BootAnimation::playAnimation(const Animation& animation) { // For the last animation, if we have progress indicator from // the system, display it. - int currentProgress = android::base::GetIntProperty(PROGRESS_PROP_NAME, 0); - bool displayProgress = animation.progressEnabled && - (i == (pcount -1)) && currentProgress != 0; + const bool displayProgress = animation.progressEnabled && (partIdx == (numParts - 1)) && + android::base::GetIntProperty(PROGRESS_PROP_NAME, 0) != 0; - for (size_t j=0 ; j<fcount ; j++) { + for (size_t frameIdxInPart = 0; frameIdxInPart < numFramesInPart; frameIdxInPart++) { if (shouldStopPlayingPart(part, fadedFramesCount, lastDisplayedProgress)) break; // Color progress is @@ -1635,21 +1611,15 @@ bool BootAnimation::playAnimation(const Animation& animation) { // - 1 for parts that come after. float colorProgress = part.useDynamicColoring ? fmin(fmax( - ((float)j - colorTransitionStart) / + (static_cast<float>(frameIdxInPart) - colorTransitionStart) / fmax(colorTransitionEnd - colorTransitionStart, 1.0f), 0.0f), 1.0f) : (part.postDynamicColoring ? 1 : 0); - processDisplayEvents(); - const double ratio_w = static_cast<double>(mWidth) / mInitWidth; - const double ratio_h = static_cast<double>(mHeight) / mInitHeight; - const int animationX = (mWidth - animation.width * ratio_w) / 2; - const int animationY = (mHeight - animation.height * ratio_h) / 2; - - const Animation::Frame& frame(part.frames[j]); + const Animation::Frame& frame(part.frames[frameIdxInPart]); nsecs_t lastFrame = systemTime(); - if (r > 0) { + if (frameIdx > 0) { glBindTexture(GL_TEXTURE_2D, frame.tid); } else { if (part.count != 1) { @@ -1662,17 +1632,6 @@ bool BootAnimation::playAnimation(const Animation& animation) { initTexture(frame.map, &w, &h, false /* don't premultiply alpha */); } - const int trimWidth = frame.trimWidth * ratio_w; - const int trimHeight = frame.trimHeight * ratio_h; - const int trimX = frame.trimX * ratio_w; - const int trimY = frame.trimY * ratio_h; - const int xc = animationX + trimX; - const int yc = animationY + trimY; - glClear(GL_COLOR_BUFFER_BIT); - // specify the y center as ceiling((mHeight - frame.trimHeight) / 2) - // which is equivalent to mHeight - (yc + frame.trimHeight) - const int frameDrawY = mHeight - (yc + trimHeight); - float fade = 0; // if the part hasn't been stopped yet then continue fading if necessary if (exitPending() && part.hasFadingPhase()) { @@ -1681,40 +1640,66 @@ bool BootAnimation::playAnimation(const Animation& animation) { fadedFramesCount = MAX_FADED_FRAMES_COUNT; // no more fading } } - glUseProgram(mImageShader); - glUniform1i(mImageTextureLocation, 0); - glUniform1f(mImageFadeLocation, fade); - if (animation.dynamicColoringEnabled) { - glUniform1f(mImageColorProgressLocation, colorProgress); - } - glEnable(GL_BLEND); - drawTexturedQuad(xc, frameDrawY, trimWidth, trimHeight); - glDisable(GL_BLEND); - if (mClockEnabled && mTimeIsAccurate && validClock(part)) { - drawClock(animation.clockFont, part.clockPosX, part.clockPosY); - } + // Draw the current frame's texture on every physical display that is enabled. + for (const auto& display : mDisplays) { + eglMakeCurrent(mEgl, display.eglSurface, display.eglSurface, mEglContext); + + const double ratioW = + static_cast<double>(display.width) / display.initWidth; + const double ratioH = + static_cast<double>(display.height) / display.initHeight; + const int animationX = (display.width - animation.width * ratioW) / 2; + const int animationY = (display.height - animation.height * ratioH) / 2; + + const int trimWidth = frame.trimWidth * ratioW; + const int trimHeight = frame.trimHeight * ratioH; + const int trimX = frame.trimX * ratioW; + const int trimY = frame.trimY * ratioH; + const int xc = animationX + trimX; + const int yc = animationY + trimY; + projectSceneToWindow(display); + handleViewport(frameDuration, display); + glClear(GL_COLOR_BUFFER_BIT); + // specify the y center as ceiling((height - frame.trimHeight) / 2) + // which is equivalent to height - (yc + frame.trimHeight) + const int frameDrawY = display.height - (yc + trimHeight); + + glUseProgram(mImageShader); + glUniform1i(mImageTextureLocation, 0); + glUniform1f(mImageFadeLocation, fade); + if (animation.dynamicColoringEnabled) { + glUniform1f(mImageColorProgressLocation, colorProgress); + } + glEnable(GL_BLEND); + drawTexturedQuad(xc, frameDrawY, trimWidth, trimHeight, display); + glDisable(GL_BLEND); - if (displayProgress) { - int newProgress = android::base::GetIntProperty(PROGRESS_PROP_NAME, 0); - // In case the new progress jumped suddenly, still show an - // increment of 1. - if (lastDisplayedProgress != 100) { - // Artificially sleep 1/10th a second to slow down the animation. - usleep(100000); - if (lastDisplayedProgress < newProgress) { - lastDisplayedProgress++; - } + if (mClockEnabled && mTimeIsAccurate && validClock(part)) { + drawClock(animation.clockFont, part.clockPosX, part.clockPosY, display); } - // Put the progress percentage right below the animation. - int posY = animation.height / 3; - int posX = TEXT_CENTER_VALUE; - drawProgress(lastDisplayedProgress, animation.progressFont, posX, posY); - } - handleViewport(frameDuration); + if (displayProgress) { + int newProgress = android::base::GetIntProperty(PROGRESS_PROP_NAME, 0); + // In case the new progress jumped suddenly, still show an + // increment of 1. + if (lastDisplayedProgress != 100) { + // Artificially sleep 1/10th a second to slow down the animation. + usleep(100000); + if (lastDisplayedProgress < newProgress) { + lastDisplayedProgress++; + } + } + // Put the progress percentage right below the animation. + int posY = animation.height / 3; + int posX = TEXT_CENTER_VALUE; + drawProgress(lastDisplayedProgress, + animation.progressFont, posX, posY, display); + } + + eglSwapBuffers(mEgl, display.eglSurface); + } - eglSwapBuffers(mDisplay, mSurface); nsecs_t now = systemTime(); nsecs_t delay = frameDuration - (now - lastFrame); @@ -1760,9 +1745,7 @@ bool BootAnimation::playAnimation(const Animation& animation) { // Free textures created for looping parts now that the animation is done. for (const Animation::Part& part : animation.parts) { if (part.count != 1) { - const size_t fcount = part.frames.size(); - for (size_t j = 0; j < fcount; j++) { - const Animation::Frame& frame(part.frames[j]); + for (const auto& frame : part.frames) { glDeleteTextures(1, &frame.tid); } } @@ -1781,16 +1764,17 @@ void BootAnimation::processDisplayEvents() { mLooper->pollOnce(0); } -void BootAnimation::handleViewport(nsecs_t timestep) { +void BootAnimation::handleViewport(nsecs_t timestep, const Display& display) { ATRACE_CALL(); - if (mShuttingDown || !mFlingerSurfaceControl || mTargetInset == 0) { + if (mShuttingDown || !display.surfaceControl || mTargetInset == 0) { return; } if (mTargetInset < 0) { // Poll the amount for the top display inset. This will return -1 until persistent properties // have been loaded. - mTargetInset = android::base::GetIntProperty("persist.sys.displayinset.top", - -1 /* default */, -1 /* min */, mHeight / 2 /* max */); + mTargetInset = + android::base::GetIntProperty("persist.sys.displayinset.top", -1 /* default */, + -1 /* min */, display.height / 2 /* max */); } if (mTargetInset <= 0) { return; @@ -1802,19 +1786,27 @@ void BootAnimation::handleViewport(nsecs_t timestep) { int interpolatedInset = (cosf((fraction + 1) * M_PI) / 2.0f + 0.5f) * mTargetInset; SurfaceComposerClient::Transaction() - .setCrop(mFlingerSurfaceControl, Rect(0, interpolatedInset, mWidth, mHeight)) + .setCrop(display.surfaceControl, + Rect(0, interpolatedInset, display.width, display.height)) .apply(); } else { // At the end of the animation, we switch to the viewport that DisplayManager will apply // later. This changes the coordinate system, and means we must move the surface up by // the inset amount. - Rect layerStackRect(0, 0, mWidth, mHeight - mTargetInset); - Rect displayRect(0, mTargetInset, mWidth, mHeight); - + Rect layerStackRect(0, 0, + display.width, + display.height - mTargetInset); + Rect displayRect(0, mTargetInset, + display.width, + display.height); SurfaceComposerClient::Transaction t; - t.setPosition(mFlingerSurfaceControl, 0, -mTargetInset) - .setCrop(mFlingerSurfaceControl, Rect(0, mTargetInset, mWidth, mHeight)); - t.setDisplayProjection(mDisplayToken, ui::ROTATION_0, layerStackRect, displayRect); + t.setPosition(display.surfaceControl, 0, -mTargetInset) + .setCrop(display.surfaceControl, + Rect(0, mTargetInset, + display.width, + display.height)); + t.setDisplayProjection(display.displayToken, + ui::ROTATION_0, layerStackRect, displayRect); t.apply(); mTargetInset = mCurrentInset = 0; diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h index 8683b71a3762..0a057461228c 100644 --- a/cmds/bootanimation/BootAnimation.h +++ b/cmds/bootanimation/BootAnimation.h @@ -31,6 +31,7 @@ #include <binder/IBinder.h> #include <ui/Rotation.h> +#include <ui/LayerStack.h> #include <EGL/egl.h> #include <GLES2/gl2.h> @@ -119,6 +120,18 @@ public: float endColors[4][3]; // End colors of dynamic color transition. }; + // Collects all attributes that must be tracked per physical display. + struct Display { + int width; + int height; + int initWidth; + int initHeight; + EGLDisplay eglSurface; + sp<IBinder> displayToken; + sp<SurfaceControl> surfaceControl; + sp<Surface> surface; + }; + // All callbacks will be called from this class's internal thread. class Callbacks : public RefBase { public: @@ -181,14 +194,18 @@ private: bool premultiplyAlpha = true); status_t initFont(Font* font, const char* fallback); void initShaders(); - bool android(); + bool android(const Display& display); + status_t initDisplaysAndSurfaces(); bool movie(); - void drawText(const char* str, const Font& font, bool bold, int* x, int* y); - void drawClock(const Font& font, const int xPos, const int yPos); - void drawProgress(int percent, const Font& font, const int xPos, const int yPos); + void drawText(const char* str, const Font& font, bool bold, + int* x, int* y, const Display& display); + void drawClock(const Font& font, const int xPos, const int yPos, const Display& display); + void drawProgress(int percent, const Font& font, + const int xPos, const int yPos, const Display& display); void fadeFrame(int frameLeft, int frameBottom, int frameWidth, int frameHeight, const Animation::Part& part, int fadedFramesCount); - void drawTexturedQuad(float xStart, float yStart, float width, float height); + void drawTexturedQuad(float xStart, float yStart, + float width, float height, const Display& display); bool validClock(const Animation::Part& part); Animation* loadAnimation(const String8&); bool playAnimation(const Animation&); @@ -200,36 +217,31 @@ private: bool preloadAnimation(); EGLConfig getEglConfig(const EGLDisplay&); ui::Size limitSurfaceSize(int width, int height) const; - void resizeSurface(int newWidth, int newHeight); - void projectSceneToWindow(); - void rotateAwayFromNaturalOrientationIfNeeded(); + void resizeSurface(int newWidth, int newHeight, Display& display); + void projectSceneToWindow(const Display& display); + void rotateAwayFromNaturalOrientationIfNeeded(Display& display); ui::Rotation parseOrientationProperty(); + void configureDisplayAndLayerStack(const Display& display, ui::LayerStack layerStack); bool shouldStopPlayingPart(const Animation::Part& part, int fadedFramesCount, int lastDisplayedProgress); void checkExit(); - void handleViewport(nsecs_t timestep); + void handleViewport(nsecs_t timestep, const Display& display); void initDynamicColors(); sp<SurfaceComposerClient> mSession; AssetManager mAssets; Texture mAndroid[2]; - int mWidth; - int mHeight; - int mInitWidth; - int mInitHeight; int mMaxWidth = 0; int mMaxHeight = 0; int mCurrentInset; int mTargetInset; bool mUseNpotTextures = false; - EGLDisplay mDisplay; - EGLDisplay mContext; - EGLDisplay mSurface; - sp<IBinder> mDisplayToken; - sp<SurfaceControl> mFlingerSurfaceControl; - sp<Surface> mFlingerSurface; + EGLDisplay mEgl; + EGLDisplay mEglContext; + // Per-Display Attributes (to support multi-display) + std::vector<Display> mDisplays; bool mClockEnabled; bool mTimeIsAccurate; bool mTimeFormat12Hour; diff --git a/cmds/bootanimation/bootanimation_flags.aconfig b/cmds/bootanimation/bootanimation_flags.aconfig new file mode 100644 index 000000000000..04837b98e414 --- /dev/null +++ b/cmds/bootanimation/bootanimation_flags.aconfig @@ -0,0 +1,12 @@ +package: "com.android.graphics.bootanimation.flags" +container: "system" + +flag { + name: "multidisplay" + namespace: "bootanimation" + description: "Enable boot animation on multiple displays (e.g. foldables)" + bug: "335406617" + is_fixed_read_only: true +} + + diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h index e86f81485a41..b0ba01957ab6 100644 --- a/cmds/idmap2/include/idmap2/Idmap.h +++ b/cmds/idmap2/include/idmap2/Idmap.h @@ -21,18 +21,19 @@ * 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* - target_inline_entry_value* config* overlay_entry* string_pool + * data := data_header target_entries target_inline_entries + target_inline_entry_value* config* overlay_entries 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 start_value_index value_count + * target_entries := target_id* overlay_id* + * target_inline_entries := target_id* target_inline_value_header* + * target_inline_value_header := 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 + * overlay_entries := overlay_id* target_id* * * debug_info := string * enforce_overlayable := <uint32_t> diff --git a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp index 89769246434a..00ef0c7f8cf0 100644 --- a/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp +++ b/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp @@ -66,43 +66,57 @@ void BinaryStreamVisitor::visit(const IdmapHeader& header) { void BinaryStreamVisitor::visit(const IdmapData& data) { for (const auto& target_entry : data.GetTargetEntries()) { Write32(target_entry.target_id); + } + for (const auto& target_entry : data.GetTargetEntries()) { Write32(target_entry.overlay_id); } - 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()); + uint32_t current_inline_entry_values_count = 0; + for (const auto& target_inline_entry : data.GetTargetInlineEntries()) { + Write32(target_inline_entry.target_id); + } + for (const auto& target_inline_entry : data.GetTargetInlineEntries()) { + Write32(current_inline_entry_values_count); + Write32(target_inline_entry.values.size()); + current_inline_entry_values_count += target_inline_entry.values.size(); } 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); + for (const auto& target_entry : data.GetTargetInlineEntries()) { + for (const auto& target_entry_value : target_entry.values) { + auto config_it = std::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); + } + // We're writing a Res_value entry here, and the first 3 bytes of that are + // sizeof() + a padding 0 byte + static constexpr decltype(android::Res_value::size) kSize = sizeof(android::Res_value); + Write16(kSize); + Write8(0U); + Write8(target_entry_value.second.data_type); + Write32(target_entry_value.second.data_value); } - Write16(kValueSize); - Write8(0U); // padding - 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)); + if (!configs.empty()) { + stream_.write(reinterpret_cast<const char*>(&configs.front()), + sizeof(configs.front()) * configs.size()); + if (configs.size() >= 100) { + // Let's write a message to future us so that they know when to replace the linear search + // in `configs` vector with something more efficient. + LOG(WARNING) << "Idmap got " << configs.size() + << " configurations, time to fix the bruteforce search"; + } } for (const auto& overlay_entry : data.GetOverlayEntries()) { Write32(overlay_entry.overlay_id); + } + for (const auto& overlay_entry : data.GetOverlayEntries()) { Write32(overlay_entry.target_id); } diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp index 12d9dd9bd1ad..7680109f1d54 100644 --- a/cmds/idmap2/libidmap2/Idmap.cpp +++ b/cmds/idmap2/libidmap2/Idmap.cpp @@ -204,73 +204,91 @@ std::unique_ptr<const IdmapData> IdmapData::FromBinaryStream(std::istream& strea } // Read the mapping of target resource id to overlay resource value. + data->target_entries_.resize(data->header_->GetTargetEntryCount()); for (size_t i = 0; i < data->header_->GetTargetEntryCount(); i++) { - TargetEntry target_entry{}; - if (!Read32(stream, &target_entry.target_id) || !Read32(stream, &target_entry.overlay_id)) { + if (!Read32(stream, &data->target_entries_[i].target_id)) { + return nullptr; + } + } + for (size_t i = 0; i < data->header_->GetTargetEntryCount(); i++) { + if (!Read32(stream, &data->target_entries_[i].overlay_id)) { return nullptr; } - data->target_entries_.emplace_back(target_entry); } // Read the mapping of target resource id to inline overlay values. - std::vector<std::tuple<TargetInlineEntry, uint32_t, uint32_t>> target_inline_entries; + struct TargetInlineEntryHeader { + ResourceId target_id; + uint32_t values_offset; + uint32_t values_count; + }; + std::vector<TargetInlineEntryHeader> target_inline_entries( + data->header_->GetTargetInlineEntryCount()); + for (size_t i = 0; i < data->header_->GetTargetInlineEntryCount(); i++) { + if (!Read32(stream, &target_inline_entries[i].target_id)) { + return nullptr; + } + } for (size_t i = 0; i < data->header_->GetTargetInlineEntryCount(); i++) { - TargetInlineEntry target_entry{}; - uint32_t entry_offset; - uint32_t entry_count; - if (!Read32(stream, &target_entry.target_id) || !Read32(stream, &entry_offset) - || !Read32(stream, &entry_count)) { + if (!Read32(stream, &target_inline_entries[i].values_offset) || + !Read32(stream, &target_inline_entries[i].values_count)) { return nullptr; } - 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++) { + struct TargetValueHeader { uint32_t config_index; - if (!Read32(stream, &config_index)) { + DataType data_type; + DataValue data_value; + }; + std::vector<TargetValueHeader> target_values(data->header_->GetTargetInlineEntryValueCount()); + for (size_t i = 0; i < data->header_->GetTargetInlineEntryValueCount(); i++) { + auto& value = target_values[i]; + if (!Read32(stream, &value.config_index)) { return nullptr; } - TargetValue value; - if (!Read16(stream, &unused2) - || !Read8(stream, &unused1) - || !Read8(stream, &value.data_type) - || !Read32(stream, &value.data_value)) { + // skip the padding + stream.seekg(3, std::ios::cur); + if (!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))) { + std::vector<ConfigDescription> configurations(data->header_->GetConfigCount()); + if (!configurations.empty()) { + if (!stream.read(reinterpret_cast<char*>(&configurations.front()), + sizeof(configurations.front()) * configurations.size())) { 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_.reserve(target_inline_entries.size()); + for (auto&& entry_header : target_inline_entries) { + TargetInlineEntry& entry = data->target_inline_entries_.emplace_back(); + entry.target_id = entry_header.target_id; + for (size_t i = 0; i < entry_header.values_count; i++) { + const auto& value_header = target_values[entry_header.values_offset + i]; + const auto& config = configurations[value_header.config_index]; + auto& value = entry.values[config]; + value.data_type = value_header.data_type; + value.data_value = value_header.data_value; } - data->target_inline_entries_.emplace_back(target_entry); } // Read the mapping of overlay resource id to target resource id. + data->overlay_entries_.resize(data->header_->GetOverlayEntryCount()); + for (size_t i = 0; i < data->header_->GetOverlayEntryCount(); i++) { + if (!Read32(stream, &data->overlay_entries_[i].overlay_id)) { + return nullptr; + } + } for (size_t i = 0; i < data->header_->GetOverlayEntryCount(); i++) { - OverlayEntry overlay_entry{}; - if (!Read32(stream, &overlay_entry.overlay_id) || !Read32(stream, &overlay_entry.target_id)) { + if (!Read32(stream, &data->overlay_entries_[i].target_id)) { return nullptr; } - data->overlay_entries_.emplace_back(overlay_entry); } // Read raw string pool bytes. @@ -320,7 +338,7 @@ Result<std::unique_ptr<const IdmapData>> IdmapData::FromResourceMapping( std::unique_ptr<IdmapData> data(new IdmapData()); data->string_pool_data_ = std::string(resource_mapping.GetStringPoolData()); uint32_t inline_value_count = 0; - std::set<std::string> config_set; + std::set<std::string_view> 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}); @@ -329,7 +347,9 @@ Result<std::unique_ptr<const IdmapData>> IdmapData::FromResourceMapping( for (const auto& [config, value] : std::get<ConfigMap>(mapping.second)) { config_set.insert(config); ConfigDescription cd; - ConfigDescription::Parse(config, &cd); + if (!ConfigDescription::Parse(config, &cd)) { + return Error("failed to parse configuration string '%s'", config.c_str()); + } values[cd] = value; inline_value_count++; } diff --git a/cmds/idmap2/libidmap2/ResourceContainer.cpp b/cmds/idmap2/libidmap2/ResourceContainer.cpp index 3c0e118bbfe7..57ae3548123b 100644 --- a/cmds/idmap2/libidmap2/ResourceContainer.cpp +++ b/cmds/idmap2/libidmap2/ResourceContainer.cpp @@ -17,6 +17,7 @@ #include "idmap2/ResourceContainer.h" #include <memory> +#include <mutex> #include <string> #include <utility> #include <vector> @@ -296,7 +297,7 @@ struct ResState { } // namespace struct ApkResourceContainer : public TargetResourceContainer, public OverlayResourceContainer { - static Result<std::unique_ptr<ApkResourceContainer>> FromPath(const std::string& path); + static Result<std::unique_ptr<ApkResourceContainer>> FromPath(std::string path); // inherited from TargetResourceContainer Result<bool> DefinesOverlayable() const override; @@ -320,6 +321,7 @@ struct ApkResourceContainer : public TargetResourceContainer, public OverlayReso Result<const ResState*> GetState() const; ZipAssetsProvider* GetZipAssets() const; + mutable std::mutex state_lock_; mutable std::variant<std::unique_ptr<ZipAssetsProvider>, ResState> state_; std::string path_; }; @@ -330,16 +332,17 @@ ApkResourceContainer::ApkResourceContainer(std::unique_ptr<ZipAssetsProvider> zi } Result<std::unique_ptr<ApkResourceContainer>> ApkResourceContainer::FromPath( - const std::string& path) { + std::string path) { auto zip_assets = ZipAssetsProvider::Create(path, 0 /* flags */); if (zip_assets == nullptr) { return Error("failed to load zip assets"); } return std::unique_ptr<ApkResourceContainer>( - new ApkResourceContainer(std::move(zip_assets), path)); + new ApkResourceContainer(std::move(zip_assets), std::move(path))); } Result<const ResState*> ApkResourceContainer::GetState() const { + std::lock_guard lock(state_lock_); if (auto state = std::get_if<ResState>(&state_); state != nullptr) { return state; } @@ -355,6 +358,7 @@ Result<const ResState*> ApkResourceContainer::GetState() const { } ZipAssetsProvider* ApkResourceContainer::GetZipAssets() const { + std::lock_guard lock(state_lock_); if (auto zip = std::get_if<std::unique_ptr<ZipAssetsProvider>>(&state_); zip != nullptr) { return zip->get(); } @@ -427,7 +431,7 @@ Result<std::string> ApkResourceContainer::GetResourceName(ResourceId id) const { Result<std::unique_ptr<TargetResourceContainer>> TargetResourceContainer::FromPath( std::string path) { - auto result = ApkResourceContainer::FromPath(path); + auto result = ApkResourceContainer::FromPath(std::move(path)); if (!result) { return result.GetError(); } @@ -438,7 +442,7 @@ Result<std::unique_ptr<OverlayResourceContainer>> OverlayResourceContainer::From std::string path) { // Load the path as a fabricated overlay if the file magic indicates this is a fabricated overlay. if (android::IsFabricatedOverlay(path)) { - auto result = FabricatedOverlayContainer::FromPath(path); + auto result = FabricatedOverlayContainer::FromPath(std::move(path)); if (!result) { return result.GetError(); } @@ -446,7 +450,7 @@ Result<std::unique_ptr<OverlayResourceContainer>> OverlayResourceContainer::From } // Fallback to loading the container as an APK. - auto result = ApkResourceContainer::FromPath(path); + auto result = ApkResourceContainer::FromPath(std::move(path)); if (!result) { return result.GetError(); } diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp index c85619c1e4bf..1b656e8c2088 100644 --- a/cmds/idmap2/tests/IdmapTests.cpp +++ b/cmds/idmap2/tests/IdmapTests.cpp @@ -68,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(), 0x09U); + ASSERT_EQ(header->GetVersion(), 10); ASSERT_EQ(header->GetTargetCrc(), 0x1234U); ASSERT_EQ(header->GetOverlayCrc(), 0x5678U); ASSERT_EQ(header->GetFulfilledPolicies(), 0x11); @@ -143,7 +143,7 @@ TEST(IdmapTests, CreateIdmapFromBinaryStream) { ASSERT_THAT(idmap->GetHeader(), NotNull()); ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U); - ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x09U); + ASSERT_EQ(idmap->GetHeader()->GetVersion(), 10); ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0x1234U); ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0x5678U); ASSERT_EQ(idmap->GetHeader()->GetFulfilledPolicies(), kIdmapRawDataPolicies); @@ -204,7 +204,7 @@ TEST(IdmapTests, CreateIdmapHeaderFromApkAssets) { ASSERT_THAT(idmap->GetHeader(), NotNull()); ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U); - ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x09U); + ASSERT_EQ(idmap->GetHeader()->GetVersion(), 10); 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); diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp index 68164e26f352..7fae1c64f014 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 "00000009 version\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "0000000a version\n", stream.str()); ASSERT_CONTAINS_REGEX( StringPrintf(ADDRESS "%s target crc\n", android::idmap2::TestConstants::TARGET_CRC_STRING), stream.str()); @@ -113,7 +113,7 @@ TEST(RawPrintVisitorTests, CreateRawPrintVisitorWithoutAccessToApks) { (*idmap)->accept(&visitor); ASSERT_CONTAINS_REGEX(ADDRESS "504d4449 magic\n", stream.str()); - ASSERT_CONTAINS_REGEX(ADDRESS "00000009 version\n", stream.str()); + ASSERT_CONTAINS_REGEX(ADDRESS "0000000a 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()); diff --git a/cmds/idmap2/tests/TestHelpers.h b/cmds/idmap2/tests/TestHelpers.h index bf01c32c4c86..2b4ebd1ae800 100644 --- a/cmds/idmap2/tests/TestHelpers.h +++ b/cmds/idmap2/tests/TestHelpers.h @@ -34,7 +34,7 @@ const unsigned char kIdmapRawData[] = { 0x49, 0x44, 0x4d, 0x50, // 0x4: version - 0x09, 0x00, 0x00, 0x00, + 0x0a, 0x00, 0x00, 0x00, // 0x8: target crc 0x34, 0x12, 0x00, 0x00, @@ -95,19 +95,15 @@ const unsigned char kIdmapRawData[] = { // TARGET ENTRIES // 0x6c: target id (0x7f020000) 0x00, 0x00, 0x02, 0x7f, - - // 0x70: overlay_id (0x7f020000) - 0x00, 0x00, 0x02, 0x7f, - - // 0x74: target id (0x7f030000) - 0x00, 0x00, 0x03, 0x7f, - - // 0x78: overlay_id (0x7f030000) + // 0x70: target id (0x7f030000) 0x00, 0x00, 0x03, 0x7f, - - // 0x7c: target id (0x7f030002) + // 0x74: target id (0x7f030002) 0x02, 0x00, 0x03, 0x7f, + // 0x78: overlay_id (0x7f020000) + 0x00, 0x00, 0x02, 0x7f, + // 0x7c: overlay_id (0x7f030000) + 0x00, 0x00, 0x03, 0x7f, // 0x80: overlay_id (0x7f030001) 0x01, 0x00, 0x03, 0x7f, @@ -178,16 +174,20 @@ const unsigned char kIdmapRawData[] = { // 0xe1: padding 0x00, 0x00, 0x00, - // OVERLAY ENTRIES - // 0xe4: 0x7f020000 -> 0x7f020000 - 0x00, 0x00, 0x02, 0x7f, 0x00, 0x00, 0x02, 0x7f, - - // 0xec: 0x7f030000 -> 0x7f030000 - 0x00, 0x00, 0x03, 0x7f, 0x00, 0x00, 0x03, 0x7f, + // 0xe4: 0x7f020000 -> ... + 0x00, 0x00, 0x02, 0x7f, + // 0xe8: 0x7f030000 -> ... + 0x00, 0x00, 0x03, 0x7f, + // 0xec: 0x7f030001 -> ... + 0x01, 0x00, 0x03, 0x7f, - // 0xf4: 0x7f030001 -> 0x7f030002 - 0x01, 0x00, 0x03, 0x7f, 0x02, 0x00, 0x03, 0x7f, + // 0xf0: ... -> 0x7f020000 + 0x00, 0x00, 0x02, 0x7f, + // 0xf4: ... -> 0x7f030000 + 0x00, 0x00, 0x03, 0x7f, + // 0xf8: ... -> 0x7f030002 + 0x02, 0x00, 0x03, 0x7f, // 0xfc: string pool // string length, diff --git a/cmds/uinput/README.md b/cmds/uinput/README.md index 5d3f12e0d59f..6138388b30c7 100644 --- a/cmds/uinput/README.md +++ b/cmds/uinput/README.md @@ -83,6 +83,11 @@ control values to be sent to the uinput device, which depends on the control cod Due to the sequential nature in which this is parsed, the `type` field must be specified before the `data` field in this JSON Object. +Every `register` command will need a `"UI_SET_EVBIT"` configuration entry that lists what types of +axes it declares. This entry should be the first in the list. For example, if the uinput device has +`"UI_SET_KEYBIT"` and `"UI_SET_RELBIT"` configuration entries, it will also need a `"UI_SET_EVBIT"` +entry with data of `["EV_KEY", "EV_REL"]` or the other configuration entries will be ignored. + `ff_effects_max` must be provided if `UI_SET_FFBIT` is used in `configuration`. `abs_info` fields are provided to set the device axes information. It is an array of below objects: |