Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5a74e2df authored by Narayan Kamath's avatar Narayan Kamath
Browse files

Reimplement ZipFileRO in terms of libziparchive.

This lets us share zip archive processing code with both
the runtime (Art, dalvik) and critical java code
(StrictJarFile).

This change also moves several utility methods to ZipUtils
and dedups code across several zip inflation methods.

One of the side effects of this change is that several
processing loops are now O(n) instead of O(n^2).

bug: 10193060

(cherry picked from commit afd31e08)

Change-Id: I86a2c528575d4a3ca86b94be068dcdc3c17c2ed6
parent 35547409
Loading
Loading
Loading
Loading
+59 −39
Original line number Diff line number Diff line
@@ -63,14 +63,19 @@ extern "C" int clock_nanosleep(clockid_t clock_id, int flags,

namespace android {

static const int ANIM_ENTRY_NAME_MAX = 256;

// ---------------------------------------------------------------------------

BootAnimation::BootAnimation() : Thread(false)
BootAnimation::BootAnimation() : Thread(false), mZip(NULL)
{
    mSession = new SurfaceComposerClient();
}

BootAnimation::~BootAnimation() {
    if (mZip != NULL) {
        delete mZip;
    }
}

void BootAnimation::onFirstRef() {
@@ -86,7 +91,7 @@ sp<SurfaceComposerClient> BootAnimation::session() const {
}


void BootAnimation::binderDied(const wp<IBinder>& who)
void BootAnimation::binderDied(const wp<IBinder>&)
{
    // woah, surfaceflinger died!
    ALOGD("SurfaceFlinger died, exiting...");
@@ -268,8 +273,6 @@ status_t BootAnimation::readyToRun() {
    mFlingerSurfaceControl = control;
    mFlingerSurface = s;

    mAndroidAnimation = true;

    // 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];
@@ -277,16 +280,17 @@ status_t BootAnimation::readyToRun() {

    bool encryptedAnimation = atoi(decrypt) != 0 || !strcmp("trigger_restart_min_framework", decrypt);

    ZipFileRO* zipFile = NULL;
    if ((encryptedAnimation &&
            (access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) &&
            (mZip.open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE) == NO_ERROR)) ||
            ((zipFile = ZipFileRO::open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE)) != NULL)) ||

            ((access(USER_BOOTANIMATION_FILE, R_OK) == 0) &&
            (mZip.open(USER_BOOTANIMATION_FILE) == NO_ERROR)) ||
            ((zipFile = ZipFileRO::open(USER_BOOTANIMATION_FILE)) != NULL)) ||

            ((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) &&
            (mZip.open(SYSTEM_BOOTANIMATION_FILE) == NO_ERROR))) {
        mAndroidAnimation = false;
            ((zipFile = ZipFileRO::open(SYSTEM_BOOTANIMATION_FILE)) != NULL))) {
        mZip = zipFile;
    }

    return NO_ERROR;
@@ -295,7 +299,9 @@ status_t BootAnimation::readyToRun() {
bool BootAnimation::threadLoop()
{
    bool r;
    if (mAndroidAnimation) {
    // We have no bootanimation file, so we use the stock android logo
    // animation.
    if (mZip == NULL) {
        r = android();
    } else {
        r = movie();
@@ -392,11 +398,14 @@ void BootAnimation::checkExit() {

bool BootAnimation::movie()
{
    ZipFileRO& zip(mZip);
    ZipEntryRO desc = mZip->findEntryByName("desc.txt");
    ALOGE_IF(!desc, "couldn't find desc.txt");
    if (!desc) {
        return false;
    }

    size_t numEntries = zip.getNumEntries();
    ZipEntryRO desc = zip.findEntryByName("desc.txt");
    FileMap* descMap = zip.createEntryFileMap(desc);
    FileMap* descMap = mZip->createEntryFileMap(desc);
    mZip->releaseEntry(desc);
    ALOGE_IF(!descMap, "descMap is null");
    if (!descMap) {
        return false;
@@ -415,7 +424,7 @@ bool BootAnimation::movie()
        String8 line(s, endl - s);
        const char* l = line.string();
        int fps, width, height, count, pause;
        char path[256];
        char path[ANIM_ENTRY_NAME_MAX];
        char pathType;
        if (sscanf(l, "%d %d %d", &width, &height, &fps) == 3) {
            //LOGD("> w=%d, h=%d, fps=%d", width, height, fps);
@@ -438,21 +447,31 @@ bool BootAnimation::movie()

    // read all the data structures
    const size_t pcount = animation.parts.size();
    for (size_t i=0 ; i<numEntries ; i++) {
        char name[256];
        ZipEntryRO entry = zip.findEntryByIndex(i);
        if (zip.getEntryFileName(entry, name, 256) == 0) {
    void *cookie = NULL;
    if (!mZip->startIteration(&cookie)) {
        return false;
    }

    ZipEntryRO entry;
    char name[ANIM_ENTRY_NAME_MAX];
    while ((entry = mZip->nextEntry(cookie)) != NULL) {
        const int foundEntryName = mZip->getEntryFileName(entry, name, ANIM_ENTRY_NAME_MAX);
        if (foundEntryName > ANIM_ENTRY_NAME_MAX || foundEntryName == -1) {
            ALOGE("Error fetching entry file name");
            continue;
        }

        const String8 entryName(name);
        const String8 path(entryName.getPathDir());
        const String8 leaf(entryName.getPathLeaf());
        if (leaf.size() > 0) {
                for (int j=0 ; j<pcount ; j++) {
            for (size_t j=0 ; j<pcount ; j++) {
                if (path == animation.parts[j].path) {
                    int method;
                    // supports only stored png files
                        if (zip.getEntryInfo(entry, &method, 0, 0, 0, 0, 0)) {
                    if (mZip->getEntryInfo(entry, &method, NULL, NULL, NULL, NULL, NULL)) {
                        if (method == ZipFileRO::kCompressStored) {
                                FileMap* map = zip.createEntryFileMap(entry);
                            FileMap* map = mZip->createEntryFileMap(entry);
                            if (map) {
                                Animation::Frame frame;
                                frame.name = leaf;
@@ -466,7 +485,8 @@ bool BootAnimation::movie()
            }
        }
    }
    }

    mZip->endIteration(cookie);

    // clear screen
    glShadeModel(GL_FLAT);
@@ -494,7 +514,7 @@ bool BootAnimation::movie()
    Region clearReg(Rect(mWidth, mHeight));
    clearReg.subtractSelf(Rect(xc, yc, xc+animation.width, yc+animation.height));

    for (int i=0 ; i<pcount ; i++) {
    for (size_t i=0 ; i<pcount ; i++) {
        const Animation::Part& part(animation.parts[i]);
        const size_t fcount = part.frames.size();
        glBindTexture(GL_TEXTURE_2D, 0);
@@ -504,7 +524,7 @@ bool BootAnimation::movie()
            if(exitPending() && !part.playUntilComplete)
                break;

            for (int j=0 ; j<fcount && (!exitPending() || part.playUntilComplete) ; j++) {
            for (size_t j=0 ; j<fcount && (!exitPending() || part.playUntilComplete) ; j++) {
                const Animation::Frame& frame(part.frames[j]);
                nsecs_t lastFrame = systemTime();

@@ -564,7 +584,7 @@ bool BootAnimation::movie()

        // free the textures for this part
        if (part.count != 1) {
            for (int j=0 ; j<fcount ; j++) {
            for (size_t j=0 ; j<fcount ; j++) {
                const Animation::Frame& frame(part.frames[j]);
                glDeleteTextures(1, &frame.tid);
            }
+1 −2
Original line number Diff line number Diff line
@@ -95,8 +95,7 @@ private:
    EGLDisplay  mSurface;
    sp<SurfaceControl> mFlingerSurfaceControl;
    sp<Surface> mFlingerSurface;
    bool        mAndroidAnimation;
    ZipFileRO   mZip;
    ZipFileRO   *mZip;
};

// ---------------------------------------------------------------------------
+18 −14
Original line number Diff line number Diff line
@@ -21,7 +21,9 @@

#include <utils/Log.h>
#include <androidfw/ZipFileRO.h>
#include <androidfw/ZipUtils.h>
#include <ScopedUtfChars.h>
#include <UniquePtr.h>

#include <zlib.h>

@@ -143,7 +145,7 @@ isFileDifferent(const char* filePath, size_t fileSize, time_t modifiedTime,
}

static install_status_t
sumFiles(JNIEnv* env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char* fileName)
sumFiles(JNIEnv*, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntry, const char*)
{
    size_t* total = (size_t*) arg;
    size_t uncompLen;
@@ -178,7 +180,7 @@ copyFileIfChanged(JNIEnv *env, void* arg, ZipFileRO* zipFile, ZipEntryRO zipEntr
        return INSTALL_FAILED_INVALID_APK;
    } else {
        struct tm t;
        ZipFileRO::zipTimeToTimespec(when, &t);
        ZipUtils::zipTimeToTimespec(when, &t);
        modTime = mktime(&t);
    }

@@ -273,26 +275,25 @@ iterateOverNativeFiles(JNIEnv *env, jstring javaFilePath, jstring javaCpuAbi, js
    ScopedUtfChars cpuAbi(env, javaCpuAbi);
    ScopedUtfChars cpuAbi2(env, javaCpuAbi2);

    ZipFileRO zipFile;

    if (zipFile.open(filePath.c_str()) != NO_ERROR) {
    UniquePtr<ZipFileRO> zipFile(ZipFileRO::open(filePath.c_str()));
    if (zipFile.get() == NULL) {
        ALOGI("Couldn't open APK %s\n", filePath.c_str());
        return INSTALL_FAILED_INVALID_APK;
    }

    const int N = zipFile.getNumEntries();

    char fileName[PATH_MAX];
    bool hasPrimaryAbi = false;

    for (int i = 0; i < N; i++) {
        const ZipEntryRO entry = zipFile.findEntryByIndex(i);
        if (entry == NULL) {
            continue;
    void* cookie = NULL;
    if (!zipFile->startIteration(&cookie)) {
        ALOGI("Couldn't iterate over APK%s\n", filePath.c_str());
        return INSTALL_FAILED_INVALID_APK;
    }

    ZipEntryRO entry = NULL;
    while ((entry = zipFile->nextEntry(cookie)) != NULL) {
        // Make sure this entry has a filename.
        if (zipFile.getEntryFileName(entry, fileName, sizeof(fileName))) {
        if (zipFile->getEntryFileName(entry, fileName, sizeof(fileName))) {
            continue;
        }

@@ -346,15 +347,18 @@ iterateOverNativeFiles(JNIEnv *env, jstring javaFilePath, jstring javaCpuAbi, js
                    && isFilenameSafe(lastSlash + 1))
                || !strncmp(lastSlash + 1, GDBSERVER, GDBSERVER_LEN)) {

            install_status_t ret = callFunc(env, callArg, &zipFile, entry, lastSlash + 1);
            install_status_t ret = callFunc(env, callArg, zipFile.get(), entry, lastSlash + 1);

            if (ret != INSTALL_SUCCEEDED) {
                ALOGV("Failure for entry %s", lastSlash + 1);
                zipFile->endIteration(cookie);
                return ret;
            }
        }
    }

    zipFile->endIteration(cookie);

    return INSTALL_SUCCEEDED;
}