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

Commit fd2649b1 authored by Sergey Ten's avatar Sergey Ten
Browse files

Add support for modifying ResTable on fly.

This change allows to either delete or add asset path after
a ResTable object has been created for a given AssetManager.
In past, the lack of such support forced us to implement
update configuration functionality suboptimally, by recreating
new AssetManager object from scratch on theme change.
With this change, we can simply remove the "old" theme asset path
and add the new asset path. We also need to make sure the Resources
object nukes internal caches.

CR:JoshG.
parent 3aa0e506
Loading
Loading
Loading
Loading
+36 −9
Original line number Diff line number Diff line
@@ -41,13 +41,7 @@ import android.content.ContextWrapper;
import android.content.IContentProvider;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.InstrumentationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.*;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -3445,6 +3439,19 @@ public final class ActivityThread {
        }
    }

    private String getPackageResDir(String packageName) {
        android.content.pm.PackageInfo pi;
        try {
            pi = getPackageManager().getPackageInfo(packageName, 0);
            if (pi == null || pi.applicationInfo == null)
                return null;
            return pi.applicationInfo.publicSourceDir;
        } catch (RemoteException e) {
            Log.e("ActivityThread", "Exception in getPackageResDir", e);
        }
        return null;
    }

    final void handleConfigurationChanged(Configuration config) {
        
        synchronized (mRelaunchingActivities) {
@@ -3458,6 +3465,7 @@ public final class ActivityThread {
                = new ArrayList<ComponentCallbacks>();
        
        int diff;
        String originalThemePackageName = (mConfiguration == null)? null : mConfiguration.customTheme.getThemePackageName();
        
        synchronized(mPackages) {
            if (mConfiguration == null) {
@@ -3486,8 +3494,27 @@ public final class ActivityThread {
                    /* If the theme has changed, remove the cached Resources
                     * object anyway.  Similarly, each Application will need
                     * to refresh its internal resources object. */
                    if (r != null && (diff & ActivityInfo.CONFIG_THEME_RESOURCE) == 0) {
                    if (r != null) {
                        if ((diff & ActivityInfo.CONFIG_THEME_RESOURCE) == 0) {
                            r.updateConfiguration(config, dm);
                        } else {
                            AssetManager am = r.getAssets();
                            if (originalThemePackageName != null) {
//                                Log.i(TAG, "============ Dump resources BEFORE removeAssetPath");
//                                am.dumpResources();
                                am.removeAssetPath(originalThemePackageName, getPackageResDir(originalThemePackageName));
//                                Log.i(TAG, "============ Dump resources AFTER removeAssetPath");
//                                am.dumpResources();
                            }
                            String resDir = getPackageResDir(config.customTheme.getThemePackageName());
                            if (resDir != null) {
                                am.updateResourcesWithAssetPath(resDir);
//                                Log.i(TAG, "============ Dump resources AFTER addAssetPath");
//                                am.dumpResources();
                            }
                            r.clearCaches();
                            r.getConfiguration().customTheme = config.customTheme;
                        }
                        //Log.i(TAG, "Updated app resources " + v.getKey()
                        //        + " " + r + ": " + r.getConfiguration());
                    } else {
+31 −21
Original line number Diff line number Diff line
@@ -237,6 +237,12 @@ public final class AssetManager {
        }
    }

    /*package*/ final void recreateStringBlocks() {
        synchronized (mSync) {
            makeStringBlocks(true);
        }
    }

    private final void makeStringBlocks(boolean copyFromSystem) {
        final int sysNum = copyFromSystem ? mSystem.mStringBlocks.length : 0;
        final int num = getStringBlockCount();
@@ -453,25 +459,6 @@ public final class AssetManager {
        return splitThemePackage(packageFileName, lockedFileName, drmProtectedresources);
    }

    /**
     * {@hide}
     * Mark asset paths stack for future un-install.
     * 
     */
    public final int markAssetPaths() {
        return markAssetPathStack();
    }

    /**
     * {@hide}
     * Un-install asset paths added after the mark.
     * 
     * @param restoreMark Un-install mark (all assets added the mark would be un-installed).
     */
    public final void restoreAssetPaths(int restoreMark) {
        restoreAssetPathStack(restoreMark);
    }

    /**
     * {@hide}
     * Retrieve a non-asset as a compiled XML file.  Not for use by
@@ -603,6 +590,31 @@ public final class AssetManager {
     */
    public native final int addAssetPath(String path);

    /**
     * Delete a set of assets from the asset manager.  This can be
     * either a directory or ZIP file.  Not for use by applications.  Returns
     * true if succeeded or false on failure.
     * {@hide}
     */
    public native final boolean removeAssetPath(String packageName, String path);

    /**
     * Add an additional set of assets to the asset manager.  This can be
     * either a directory or ZIP file. Force updating of ResTable object.
     * Not for use by applications.
     * Returnsthe cookie of the added asset, or 0 on failure.
     * {@hide}
     */
    public native final int updateResourcesWithAssetPath(String path);

    /**
     * Delete a set of assets from the asset manager.  This can be
     * either a directory or ZIP file.  Not for use by applications.  Returns
     * true if succeeded or false on failure.
     * {@hide}
     */
    public native final void dumpResources();

    /**
     * Determine whether the state in this asset manager is up-to-date with
     * the files on the filesystem.  If false is returned, you need to
@@ -715,8 +727,6 @@ public final class AssetManager {
    /*package*/ native final int[] getArrayIntResource(int arrayRes);

    private native final int splitThemePackage(String srcFileName, String dstFileName, String [] drmProtectedAssetNames);
    private native final int markAssetPathStack();
    private native final void restoreAssetPathStack(int restoreMark);

    private native final void init();
    private native final void destroy();
+14 −1
Original line number Diff line number Diff line
@@ -1601,6 +1601,19 @@ public class Resources {
        }
    }

    /**
     * {@hide}
     */
    public final void clearCaches() {
        synchronized (mTmpValue) {
            mCachedStyledAttributes = null;
            mDrawableCache.clear();
            mColorStateListCache.clear();
            flushLayoutCache();
            mAssets.recreateStringBlocks();
        }
    }

    /*package*/ Drawable loadDrawable(TypedValue value, int id)
            throws NotFoundException {

+60 −32
Original line number Diff line number Diff line
@@ -1580,31 +1580,6 @@ static jint android_content_AssetManager_splitThemePackage(JNIEnv* env, jobject
    return (jint)result;
}

static jint android_content_AssetManager_markAssetPathStack(JNIEnv* env, jobject clazz)
{
    AssetManager* am = assetManagerForJavaObject(env, clazz);
    if (am == NULL) {
        doThrow(env, "java/lang/OutOfMemoryError");
        return -1;
    }

    LOGV("markAssetPathStack in %p (Java object %p)\n", am, clazz);

    return (jint)am->markAssetPathStack();
}

static void android_content_AssetManager_restoreAssetPathStack(JNIEnv* env, jobject clazz, jint restoreIndex)
{
    AssetManager* am = assetManagerForJavaObject(env, clazz);
    if (am == NULL) {
        doThrow(env, "java/lang/OutOfMemoryError");
        return;
    }

    LOGV("restoreAssetPathStack in %p (Java object %p)\n", am, clazz);
    am->restoreAssetPathStack(restoreIndex);
}

static void android_content_AssetManager_init(JNIEnv* env, jobject clazz)
{
    AssetManager* am = new AssetManager();
@@ -1640,6 +1615,60 @@ static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env,
    return AssetManager::getGlobalCount();
}

static jboolean android_content_AssetManager_removeAssetPath(JNIEnv* env, jobject clazz,
            jstring packageName, jstring path)
{
    if (path == NULL) {
        doThrow(env, "java/lang/NullPointerException");
        return JNI_FALSE;
    }

    AssetManager* am = assetManagerForJavaObject(env, clazz);
    if (am == NULL) {
        return JNI_FALSE;
    }

    const char* name8 = env->GetStringUTFChars(packageName, NULL);
    const char* path8 = env->GetStringUTFChars(path, NULL);
    bool res = am->removeAssetPath(String8(name8), String8(path8));
    env->ReleaseStringUTFChars(path, path8);
    env->ReleaseStringUTFChars(packageName, name8);

    return res;
}

static jint android_content_AssetManager_updateResourcesWithAssetPath(
            JNIEnv* env, jobject clazz, jstring path)
{
    if (path == NULL) {
        doThrow(env, "java/lang/NullPointerException");
        return JNI_FALSE;
    }

    AssetManager* am = assetManagerForJavaObject(env, clazz);
    if (am == NULL) {
        return JNI_FALSE;
    }

    const char* path8 = env->GetStringUTFChars(path, NULL);

    void* cookie;
    bool res = am->updateWithAssetPath(String8(path8), &cookie);

    env->ReleaseStringUTFChars(path, path8);

    return (res) ? (jint)cookie : 0;
}

static void android_content_AssetManager_dumpRes(JNIEnv* env, jobject clazz)
{
    AssetManager* am = assetManagerForJavaObject(env, clazz);
    if (am == NULL) {
        return;
    }
    am->dumpRes();
}

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

/*
@@ -1754,13 +1783,12 @@ static JNINativeMethod gAssetManagerMethods[] = {
    { "splitThemePackage","(Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)I",
        (void*) android_content_AssetManager_splitThemePackage },

    // Mark asset path "stack".
    { "markAssetPathStack","()I",
        (void*) android_content_AssetManager_markAssetPathStack },

    // Restore asset path "stack".
    { "restoreAssetPathStack","(I)V",
        (void*) android_content_AssetManager_restoreAssetPathStack },
    { "removeAssetPath", "(Ljava/lang/String;Ljava/lang/String;)Z",
        (void*) android_content_AssetManager_removeAssetPath },
    { "updateResourcesWithAssetPath",   "(Ljava/lang/String;)I",
        (void*) android_content_AssetManager_updateResourcesWithAssetPath },
    { "dumpResources", "()V",
        (void*) android_content_AssetManager_dumpRes },
};

int register_android_content_AssetManager(JNIEnv* env)
+9 −8
Original line number Diff line number Diff line
@@ -186,15 +186,15 @@ public:
    void getLocales(Vector<String8>* locales) const;

    /*
     * Mark asset path "stack" to support un-install from the mAssetPaths.
     */
    int markAssetPathStack();

    /*
     * Restore asset path "stack" by un-installing from the mAssetPaths
     * all assets installed after restoreIndex.
     * Remove existing source for assets.  It can be either a directory (for
     * deleting assets as raw files on the disk) or a ZIP file.
     * Also, updates the ResTable object to reflect the change.
     *
     * Returns "true" on success, "false" on failure.
     */
    void restoreAssetPathStack(int restoreIndex);
    bool removeAssetPath(const String8 &packageName, const String8 &assetPath);
    bool updateWithAssetPath(const String8& path, void** cookie);
    void dumpRes();

private:
    struct asset_path
@@ -203,6 +203,7 @@ private:
        FileType type;
    };

    void updateResTableFromAssetPath(ResTable *rt, const asset_path& ap, void *cookie) const;
    Asset* openInPathLocked(const char* fileName, AccessMode mode,
        const asset_path& path);
    Asset* openNonAssetInPathLocked(const char* fileName, AccessMode mode,
Loading