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

Commit 2c5fcf44 authored by Jernej Virag's avatar Jernej Virag Committed by Android (Google) Code Review
Browse files

Merge "Prevent loading of Icon resources from the wrong package" into tm-qpr-dev

parents f1840aed 166d420c
Loading
Loading
Loading
Loading
+61 −4
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@ package com.android.internal.widget;
import android.annotation.DrawableRes;
import android.annotation.Nullable;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.ImageDecoder;
@@ -109,13 +111,13 @@ public class LocalImageResolver {
                }
                break;
            case Icon.TYPE_RESOURCE:
                if (!(TextUtils.isEmpty(icon.getResPackage())
                        || context.getPackageName().equals(icon.getResPackage()))) {
                    // We can't properly resolve icons from other packages here, so fall back.
                Resources res = resolveResourcesForIcon(context, icon);
                if (res == null) {
                    // We couldn't resolve resources properly, fall back to icon loading.
                    return icon.loadDrawable(context);
                }

                Drawable result = resolveImage(icon.getResId(), context, maxWidth, maxHeight);
                Drawable result = resolveImage(res, icon.getResId(), maxWidth, maxHeight);
                if (result != null) {
                    return tintDrawable(icon, result);
                }
@@ -158,6 +160,13 @@ public class LocalImageResolver {
        return resolveImage(source, maxWidth, maxHeight);
    }

    @Nullable
    private static Drawable resolveImage(Resources res, @DrawableRes int resId, int maxWidth,
            int maxHeight) {
        final ImageDecoder.Source source = ImageDecoder.createSource(res, resId);
        return resolveImage(source, maxWidth, maxHeight);
    }

    @Nullable
    private static Drawable resolveBitmapImage(Icon icon, Context context, int maxWidth,
            int maxHeight) {
@@ -259,4 +268,52 @@ public class LocalImageResolver {
        }
        return icon.getUri();
    }

    /**
     * Resolves the correct resources package for a given Icon - it may come from another
     * package.
     *
     * @see Icon#loadDrawableInner(Context)
     * @hide
     *
     * @return resources instance if the operation succeeded, null otherwise
     */
    @Nullable
    @VisibleForTesting
    public static Resources resolveResourcesForIcon(Context context, Icon icon) {
        if (icon.getType() != Icon.TYPE_RESOURCE) {
            return null;
        }

        // Icons cache resolved resources, use cache if available.
        Resources res = icon.getResources();
        if (res != null) {
            return res;
        }

        String resPackage = icon.getResPackage();
        // No package means we try to use current context.
        if (TextUtils.isEmpty(resPackage) || context.getPackageName().equals(resPackage)) {
            return context.getResources();
        }

        if ("android".equals(resPackage)) {
            return Resources.getSystem();
        }

        final PackageManager pm = context.getPackageManager();
        try {
            ApplicationInfo ai = pm.getApplicationInfo(resPackage,
                    PackageManager.MATCH_UNINSTALLED_PACKAGES
                            | PackageManager.GET_SHARED_LIBRARY_FILES);
            if (ai != null) {
                return pm.getResourcesForApplication(ai);
            }
        } catch (PackageManager.NameNotFoundException e) {
            Log.e(TAG, String.format("Unable to resolve package %s for icon %s", resPackage, icon));
            return null;
        }

        return null;
    }
}
+47 −0
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
package com.android.internal.widget;

import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.BitmapFactory;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.BitmapDrawable;
@@ -279,4 +281,49 @@ public class LocalImageResolverTest {
        // This drawable must not be loaded - if it was, the code ignored the package specification.
        assertThat(d).isNull();
    }

    @Test
    public void resolveResourcesForIcon_notAResourceIcon_returnsNull() {
        Icon icon = Icon.createWithContentUri(Uri.parse("some_uri"));
        assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon)).isNull();
    }

    @Test
    public void resolveResourcesForIcon_localPackageIcon_returnsPackageResources() {
        Icon icon = Icon.createWithResource(mContext, R.drawable.test32x24);
        assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon))
                .isSameInstanceAs(mContext.getResources());
    }

    @Test
    public void resolveResourcesForIcon_iconWithoutPackageSpecificed_returnsPackageResources() {
        Icon icon = Icon.createWithResource("", R.drawable.test32x24);
        assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon))
                .isSameInstanceAs(mContext.getResources());
    }

    @Test
    public void resolveResourcesForIcon_systemPackageSpecified_returnsSystemPackage() {
        Icon icon = Icon.createWithResource("android", R.drawable.test32x24);
        assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon)).isSameInstanceAs(
                Resources.getSystem());
    }

    @Test
    public void resolveResourcesForIcon_differentPackageSpecified_returnsPackageResources() throws
            PackageManager.NameNotFoundException {
        String pkg = "com.android.settings";
        Resources res = mContext.getPackageManager().getResourcesForApplication(pkg);
        int resId = res.getIdentifier("ic_android", "drawable", pkg);
        Icon icon = Icon.createWithResource(pkg, resId);

        assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon).getDrawable(resId,
                mContext.getTheme())).isNotNull();
    }

    @Test
    public void resolveResourcesForIcon_invalidPackageSpecified_returnsNull() {
        Icon icon = Icon.createWithResource("invalid.package", R.drawable.test32x24);
        assertThat(LocalImageResolver.resolveResourcesForIcon(mContext, icon)).isNull();
    }
}