diff options
38 files changed, 561 insertions, 60 deletions
diff --git a/core/java/android/app/LocaleConfig.java b/core/java/android/app/LocaleConfig.java index 4a06f7d1a1c3..f56bf4d434e7 100644 --- a/core/java/android/app/LocaleConfig.java +++ b/core/java/android/app/LocaleConfig.java @@ -28,6 +28,8 @@ import android.content.res.XmlResourceParser; import android.os.LocaleList; import android.os.Parcel; import android.os.Parcelable; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; +import android.ravenwood.annotation.RavenwoodThrow; import android.util.AttributeSet; import android.util.Slog; import android.util.Xml; @@ -64,6 +66,7 @@ import java.util.Set; // Add following to last Note: when guide is written: // For more information about the LocaleConfig overridden by the application, see TODO(b/261528306): // add link to guide +@RavenwoodKeepWholeClass public class LocaleConfig implements Parcelable { private static final String TAG = "LocaleConfig"; public static final String TAG_LOCALE_CONFIG = "locale-config"; @@ -104,6 +107,7 @@ public class LocaleConfig implements Parcelable { * * @see Context#createPackageContext(String, int). */ + @RavenwoodThrow(blockedBy = LocaleManager.class) public LocaleConfig(@NonNull Context context) { this(context, true); } @@ -117,10 +121,12 @@ public class LocaleConfig implements Parcelable { * @see Context#createPackageContext(String, int). */ @NonNull + @RavenwoodThrow(blockedBy = LocaleManager.class) public static LocaleConfig fromContextIgnoringOverride(@NonNull Context context) { return new LocaleConfig(context, false); } + @RavenwoodThrow(blockedBy = LocaleManager.class) private LocaleConfig(@NonNull Context context, boolean allowOverride) { if (allowOverride) { LocaleManager localeManager = context.getSystemService(LocaleManager.class); diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index 0cc210b7db41..2d5dad05f54e 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -40,6 +40,8 @@ import android.os.IBinder; import android.os.LocaleList; import android.os.Process; import android.os.Trace; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; +import android.ravenwood.annotation.RavenwoodThrow; import android.util.ArrayMap; import android.util.ArraySet; import android.util.DisplayMetrics; @@ -70,6 +72,7 @@ import java.util.WeakHashMap; import java.util.function.Function; /** @hide */ +@RavenwoodKeepWholeClass public class ResourcesManager { static final String TAG = "ResourcesManager"; private static final boolean DEBUG = false; @@ -149,6 +152,7 @@ public class ResourcesManager { * This will collect the package resources' paths from its ApplicationInfo and add them to all * existing and future contexts while the application is running. */ + @RavenwoodThrow(reason = "FLAG_REGISTER_RESOURCE_PATHS is unsupported") public void registerResourcePaths(@NonNull String uniqueId, @NonNull ApplicationInfo appInfo) { if (!Flags.registerResourcePaths()) { return; @@ -1877,6 +1881,7 @@ public class ResourcesManager { * instance uses. */ @Override + @RavenwoodThrow(blockedBy = ResourcesLoader.class) public void onLoadersChanged(@NonNull Resources resources, @NonNull List<ResourcesLoader> newLoader) { synchronized (mLock) { @@ -1906,6 +1911,7 @@ public class ResourcesManager { * {@code loader} to apply any changes of the set of {@link ApkAssets}. **/ @Override + @RavenwoodThrow(blockedBy = ResourcesLoader.class) public void onLoaderUpdated(@NonNull ResourcesLoader loader) { synchronized (mLock) { final ArrayMap<ResourcesImpl, ResourcesKey> updatedResourceImplKeys = diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java index a12faca71bf6..c6d0f61b529e 100644 --- a/core/java/android/app/WindowConfiguration.java +++ b/core/java/android/app/WindowConfiguration.java @@ -34,6 +34,7 @@ import android.content.res.Configuration; import android.graphics.Rect; import android.os.Parcel; import android.os.Parcelable; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.util.proto.ProtoInputStream; import android.util.proto.ProtoOutputStream; import android.util.proto.WireTypeMismatchException; @@ -55,6 +56,7 @@ import java.util.Objects; * @hide */ @TestApi +@RavenwoodKeepWholeClass public class WindowConfiguration implements Parcelable, Comparable<WindowConfiguration> { /** * bounds that can differ from app bounds, which may include things such as insets. diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 9dccc9ae7145..ffcb1cbec94e 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -87,6 +87,8 @@ import android.os.UserManager; import android.os.storage.StorageManager; import android.provider.E2eeContactKeysManager; import android.provider.MediaStore; +import android.ravenwood.annotation.RavenwoodKeep; +import android.ravenwood.annotation.RavenwoodKeepPartialClass; import android.telephony.TelephonyRegistryManager; import android.util.AttributeSet; import android.view.Display; @@ -128,6 +130,7 @@ import java.util.function.IntConsumer; * up-calls for application-level operations such as launching activities, * broadcasting and receiving intents, etc. */ +@RavenwoodKeepPartialClass public abstract class Context { /** * After {@link Build.VERSION_CODES#TIRAMISU}, @@ -931,6 +934,7 @@ public abstract class Context { * @param resId Resource id for the CharSequence text */ @NonNull + @RavenwoodKeep public final CharSequence getText(@StringRes int resId) { return getResources().getText(resId); } @@ -944,6 +948,7 @@ public abstract class Context { * text information. */ @NonNull + @RavenwoodKeep public final String getString(@StringRes int resId) { return getResources().getString(resId); } @@ -960,6 +965,7 @@ public abstract class Context { * stripped of styled text information. */ @NonNull + @RavenwoodKeep public final String getString(@StringRes int resId, Object... formatArgs) { return getResources().getString(resId, formatArgs); } @@ -976,6 +982,7 @@ public abstract class Context { * does not exist. */ @ColorInt + @RavenwoodKeep public final int getColor(@ColorRes int id) { return getResources().getColor(id, getTheme()); } @@ -1043,6 +1050,7 @@ public abstract class Context { * @see android.content.res.Resources.Theme#obtainStyledAttributes(int[]) */ @NonNull + @RavenwoodKeep public final TypedArray obtainStyledAttributes(@NonNull @StyleableRes int[] attrs) { return getTheme().obtainStyledAttributes(attrs); } @@ -1055,6 +1063,7 @@ public abstract class Context { * @see android.content.res.Resources.Theme#obtainStyledAttributes(int, int[]) */ @NonNull + @RavenwoodKeep public final TypedArray obtainStyledAttributes(@StyleRes int resid, @NonNull @StyleableRes int[] attrs) throws Resources.NotFoundException { return getTheme().obtainStyledAttributes(resid, attrs); @@ -1068,6 +1077,7 @@ public abstract class Context { * @see android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int) */ @NonNull + @RavenwoodKeep public final TypedArray obtainStyledAttributes( @Nullable AttributeSet set, @NonNull @StyleableRes int[] attrs) { return getTheme().obtainStyledAttributes(set, attrs, 0, 0); @@ -1081,6 +1091,7 @@ public abstract class Context { * @see android.content.res.Resources.Theme#obtainStyledAttributes(AttributeSet, int[], int, int) */ @NonNull + @RavenwoodKeep public final TypedArray obtainStyledAttributes(@Nullable AttributeSet set, @NonNull @StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) { @@ -4530,6 +4541,7 @@ public abstract class Context { * <b>never</b> throw a {@link RuntimeException} if the name is not supported. */ @SuppressWarnings("unchecked") + @RavenwoodKeep // TODO(b/347269120): Re-add @Nullable public final <T> T getSystemService(@NonNull Class<T> serviceClass) { // Because subclasses may override getSystemService(String) we cannot diff --git a/core/java/android/content/res/ApkAssets.java b/core/java/android/content/res/ApkAssets.java index 653e243f5e06..68b5d782bfbf 100644 --- a/core/java/android/content/res/ApkAssets.java +++ b/core/java/android/content/res/ApkAssets.java @@ -22,6 +22,8 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.om.OverlayableInfo; import android.content.res.loader.AssetsProvider; import android.content.res.loader.ResourcesProvider; +import android.ravenwood.annotation.RavenwoodClassLoadHook; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.text.TextUtils; import com.android.internal.annotations.GuardedBy; @@ -45,6 +47,8 @@ import java.util.Objects; * making the creation of AssetManagers very cheap. * @hide */ +@RavenwoodKeepWholeClass +@RavenwoodClassLoadHook(RavenwoodClassLoadHook.LIBANDROID_LOADING_HOOK) public final class ApkAssets { /** diff --git a/core/java/android/content/res/AssetFileDescriptor.java b/core/java/android/content/res/AssetFileDescriptor.java index afddc7798244..986d88103ac3 100644 --- a/core/java/android/content/res/AssetFileDescriptor.java +++ b/core/java/android/content/res/AssetFileDescriptor.java @@ -24,6 +24,8 @@ import android.os.Bundle; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Parcelable; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; +import android.ravenwood.annotation.RavenwoodReplace; import android.system.ErrnoException; import android.system.Os; import android.system.StructStat; @@ -45,6 +47,7 @@ import java.nio.channels.WritableByteChannel; * opened FileDescriptor that can be used to read the data, as well as the * offset and length of that entry's data in the file. */ +@RavenwoodKeepWholeClass public class AssetFileDescriptor implements Parcelable, Closeable { /** * Length used with {@link #AssetFileDescriptor(ParcelFileDescriptor, long, long)} @@ -300,10 +303,30 @@ public class AssetFileDescriptor implements Parcelable, Closeable { NonSeekableAutoCloseInputStream(AssetFileDescriptor fd) throws IOException { super(fd.getParcelFileDescriptor()); - super.skip(fd.getStartOffset()); + skipRaw(fd.getStartOffset()); mRemaining = (int) fd.getLength(); } + @RavenwoodReplace + private long skipRaw(long count) throws IOException { + return super.skip(count); + } + + private long skipRaw$ravenwood(long count) throws IOException { + // OpenJDK doesn't allow skip on pipes, so just use read. + final byte[] buf = new byte[(int) Math.min(1024, count)]; + long totalRead = 0; + while (totalRead < count) { + final int toRead = (int) Math.min(count - totalRead, buf.length); + final int read = super.read(buf, 0, toRead); + if (read == -1) { + break; + } + totalRead += read; + } + return totalRead; + } + @Override public int available() throws IOException { return mRemaining >= 0 @@ -341,12 +364,12 @@ public class AssetFileDescriptor implements Parcelable, Closeable { if (mRemaining >= 0) { if (mRemaining == 0) return -1; if (count > mRemaining) count = mRemaining; - long res = super.skip(count); + long res = skipRaw(count); if (res >= 0) mRemaining -= res; return res; } - return super.skip(count); + return skipRaw(count); } @Override diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index 899c2d6eec74..6fd4d0141977 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -16,8 +16,8 @@ package android.content.res; -import static android.content.res.Resources.ID_NULL; import static android.app.ResourcesManager.ApkKey; +import static android.content.res.Resources.ID_NULL; import android.annotation.AnyRes; import android.annotation.ArrayRes; @@ -34,6 +34,9 @@ import android.content.res.Configuration.NativeConfig; import android.content.res.loader.ResourcesLoader; import android.os.Build; import android.os.ParcelFileDescriptor; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; +import android.ravenwood.annotation.RavenwoodReplace; +import android.ravenwood.annotation.RavenwoodThrow; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; @@ -43,6 +46,7 @@ import android.util.TypedValue; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.om.OverlayConfig; +import com.android.internal.ravenwood.RavenwoodEnvironment; import java.io.FileDescriptor; import java.io.FileNotFoundException; @@ -66,11 +70,14 @@ import java.util.Objects; * files that have been bundled with the application as a simple stream of * bytes. */ +@RavenwoodKeepWholeClass public final class AssetManager implements AutoCloseable { private static final String TAG = "AssetManager"; private static final boolean DEBUG_REFS = false; - private static final String FRAMEWORK_APK_PATH = "/system/framework/framework-res.apk"; + private static final String FRAMEWORK_APK_PATH = getFrameworkApkPath(); + private static final String FRAMEWORK_APK_PATH_DEVICE = "/system/framework/framework-res.apk"; + private static final String FRAMEWORK_APK_PATH_RAVENWOOD = "ravenwood-data/framework-res.apk"; private static final Object sSync = new Object(); @@ -147,6 +154,7 @@ public final class AssetManager implements AutoCloseable { return this; } + @RavenwoodThrow(blockedBy = ResourcesLoader.class) public Builder addLoader(ResourcesLoader loader) { mLoaders.add(loader); return this; @@ -206,6 +214,16 @@ public final class AssetManager implements AutoCloseable { } } + @RavenwoodReplace + private static String getFrameworkApkPath() { + return FRAMEWORK_APK_PATH_DEVICE; + } + + private static String getFrameworkApkPath$ravenwood() { + return RavenwoodEnvironment.getInstance().getRavenwoodRuntimePath() + + FRAMEWORK_APK_PATH_RAVENWOOD; + } + /** * Create a new AssetManager containing only the basic system assets. * Applications will not generally use this method, instead retrieving the @@ -260,7 +278,9 @@ public final class AssetManager implements AutoCloseable { final ArrayList<ApkAssets> apkAssets = new ArrayList<>(); apkAssets.add(ApkAssets.loadFromPath(frameworkPath, ApkAssets.PROPERTY_SYSTEM)); + // TODO(Ravenwood): overlay support? final String[] systemIdmapPaths = + RavenwoodEnvironment.getInstance().isRunningOnRavenwood() ? new String[0] : OverlayConfig.getZygoteInstance().createImmutableFrameworkIdmapsInZygote(); for (String idmapPath : systemIdmapPaths) { apkAssets.add(ApkAssets.loadOverlayFromPath(idmapPath, ApkAssets.PROPERTY_SYSTEM)); @@ -351,6 +371,7 @@ public final class AssetManager implements AutoCloseable { * Changes the {@link ResourcesLoader ResourcesLoaders} used in this AssetManager. * @hide */ + @RavenwoodThrow(blockedBy = ResourcesLoader.class) void setLoaders(@NonNull List<ResourcesLoader> newLoaders) { Objects.requireNonNull(newLoaders, "newLoaders"); @@ -578,6 +599,7 @@ public final class AssetManager implements AutoCloseable { /** @hide */ @NonNull + @RavenwoodThrow(blockedBy = ResourcesLoader.class) public List<ResourcesLoader> getLoaders() { return mLoaders == null ? Collections.emptyList() : Arrays.asList(mLoaders); } @@ -1216,6 +1238,7 @@ public final class AssetManager implements AutoCloseable { } @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @RavenwoodReplace void applyStyle(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, @Nullable XmlBlock.Parser parser, @NonNull int[] inAttrs, long outValuesAddress, long outIndicesAddress) { @@ -1799,4 +1822,37 @@ public final class AssetManager implements AutoCloseable { */ @UnsupportedAppUsage public static native int getGlobalAssetManagerCount(); + + // Ravenwood Workarounds + + /** + * ART has explicit support for allocating pinned (non-movable) array objects. + * On Ravenwood we allocate regular arrays and use critical array access in + * JNI as a best effort to reduce memory copying. + * TODO(b/359983716): Remove when Ravenwood switch to ART + */ + void applyStyle$ravenwood(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes, + @Nullable XmlBlock.Parser parser, @NonNull int[] inAttrs, long outValuesAddress, + long outIndicesAddress) { + Objects.requireNonNull(inAttrs, "inAttrs"); + var runtime = RavenwoodEnvironment.getInstance(); + final int[] outValues = runtime.fromAddress(outValuesAddress); + final int[] outIndices = runtime.fromAddress(outIndicesAddress); + synchronized (this) { + // Need to synchronize on AssetManager because we will be accessing + // the native implementation of AssetManager. + ensureValidLocked(); + nativeApplyStyleWithArray(mObject, themePtr, defStyleAttr, defStyleRes, + parser != null ? parser.mParseState : 0, inAttrs, outValues, + outIndices); + } + } + + /** + * A variant of nativeApplyStyle(), accepting java arrays instead of raw pointers. + * TODO(b/359983716): Remove when Ravenwood switch to ART + */ + private static native void nativeApplyStyleWithArray(long ptr, long themePtr, + @AttrRes int defStyleAttr, @StyleRes int defStyleRes, + long xmlParserPtr, @NonNull int[] inAttrs, int[] outData, int[] outIndices); } diff --git a/core/java/android/content/res/DrawableCache.java b/core/java/android/content/res/DrawableCache.java index d0ebe3304065..c139de6685c8 100644 --- a/core/java/android/content/res/DrawableCache.java +++ b/core/java/android/content/res/DrawableCache.java @@ -19,13 +19,17 @@ package android.content.res; import android.compat.annotation.UnsupportedAppUsage; import android.graphics.drawable.Drawable; import android.os.Build; +import android.ravenwood.annotation.RavenwoodKeep; +import android.ravenwood.annotation.RavenwoodKeepPartialClass; /** * Class which can be used to cache Drawable resources against a theme. */ +@RavenwoodKeepPartialClass class DrawableCache extends ThemedResourceCache<Drawable.ConstantState> { @UnsupportedAppUsage + @RavenwoodKeep DrawableCache() { } diff --git a/core/java/android/content/res/Element.java b/core/java/android/content/res/Element.java index 6ff96f42e433..798f9062a7e4 100644 --- a/core/java/android/content/res/Element.java +++ b/core/java/android/content/res/Element.java @@ -19,6 +19,7 @@ package android.content.res; import static android.os.SystemProperties.PROP_VALUE_MAX; import android.annotation.NonNull; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.util.Pools.SimplePool; import android.util.Slog; @@ -33,6 +34,7 @@ import java.util.Set; * * {@hide} */ +@RavenwoodKeepWholeClass public class Element { private static final int DEFAULT_MAX_STRING_ATTR_LENGTH = 32_768; private static final int MAX_POOL_SIZE = 128; diff --git a/core/java/android/content/res/ResourceId.java b/core/java/android/content/res/ResourceId.java index 3c7b5fc11164..c9e900f8ecb6 100644 --- a/core/java/android/content/res/ResourceId.java +++ b/core/java/android/content/res/ResourceId.java @@ -16,11 +16,13 @@ package android.content.res; import android.annotation.AnyRes; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; /** * Provides a set of utility methods for dealing with Resource IDs. * @hide */ +@RavenwoodKeepWholeClass public final class ResourceId { /** * Checks whether the integer {@code id} is a valid resource ID, as generated by AAPT. diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 248ef1d4d9c4..bf4d97d602d8 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -58,6 +58,8 @@ import android.graphics.drawable.DrawableInflater; import android.os.Build; import android.os.Bundle; import android.os.SystemClock; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; +import android.ravenwood.annotation.RavenwoodThrow; import android.util.ArrayMap; import android.util.ArraySet; import android.util.AttributeSet; @@ -124,6 +126,7 @@ import java.util.WeakHashMap; * <p>For more information about using resources, see the documentation about <a * href="{@docRoot}guide/topics/resources/index.html">Application Resources</a>.</p> */ +@RavenwoodKeepWholeClass public class Resources { /** * The {@code null} resource ID. This denotes an invalid resource ID that is returned by the @@ -417,6 +420,7 @@ public class Resources { * @hide Pending API finalization. */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @RavenwoodThrow(blockedBy = DrawableInflater.class) public final DrawableInflater getDrawableInflater() { if (mDrawableInflater == null) { mDrawableInflater = new DrawableInflater(this, mClassLoader); @@ -478,6 +482,7 @@ public class Resources { * * @return Typeface The Typeface data associated with the resource. */ + @RavenwoodThrow(blockedBy = Typeface.class) @NonNull public Typeface getFont(@FontRes int id) throws NotFoundException { final TypedValue value = obtainTempTypedValue(); try { @@ -502,6 +507,7 @@ public class Resources { /** * @hide */ + @RavenwoodThrow(blockedBy = Typeface.class) public void preloadFonts(@ArrayRes int id) { final TypedArray array = obtainTypedArray(id); try { @@ -915,6 +921,7 @@ public class Resources { * @deprecated Use {@link #getDrawable(int, Theme)} instead. */ @Deprecated + @RavenwoodThrow(blockedBy = Drawable.class) public Drawable getDrawable(@DrawableRes int id) throws NotFoundException { final Drawable d = getDrawable(id, null); if (d != null && d.canApplyTheme()) { @@ -939,6 +946,7 @@ public class Resources { * @throws NotFoundException Throws NotFoundException if the given ID does * not exist. */ + @RavenwoodThrow(blockedBy = Drawable.class) public Drawable getDrawable(@DrawableRes int id, @Nullable Theme theme) throws NotFoundException { return getDrawableForDensity(id, 0, theme); @@ -974,6 +982,7 @@ public class Resources { */ @Nullable @Deprecated + @RavenwoodThrow(blockedBy = Drawable.class) public Drawable getDrawableForDensity(@DrawableRes int id, int density) throws NotFoundException { return getDrawableForDensity(id, density, null); @@ -997,6 +1006,7 @@ public class Resources { * not exist. */ @Nullable + @RavenwoodThrow(blockedBy = Drawable.class) public Drawable getDrawableForDensity(@DrawableRes int id, int density, @Nullable Theme theme) { final TypedValue value = obtainTempTypedValue(); try { @@ -1025,6 +1035,7 @@ public class Resources { * @deprecated Prefer {@link android.graphics.drawable.AnimatedImageDrawable}. */ @Deprecated + @RavenwoodThrow(blockedBy = Movie.class) public Movie getMovie(@RawRes int id) throws NotFoundException { final InputStream is = openRawResource(id); final Movie movie = Movie.decodeStream(is); @@ -1113,6 +1124,7 @@ public class Resources { */ @NonNull @Deprecated + @RavenwoodThrow(blockedBy = ColorStateList.class) public ColorStateList getColorStateList(@ColorRes int id) throws NotFoundException { final ColorStateList csl = getColorStateList(id, null); if (csl != null && csl.canApplyTheme()) { @@ -1143,6 +1155,7 @@ public class Resources { * color or multiple colors that can be selected based on a state. */ @NonNull + @RavenwoodThrow(blockedBy = ColorStateList.class) public ColorStateList getColorStateList(@ColorRes int id, @Nullable Theme theme) throws NotFoundException { final TypedValue value = obtainTempTypedValue(); @@ -1156,6 +1169,7 @@ public class Resources { } @NonNull + @RavenwoodThrow(blockedBy = ColorStateList.class) ColorStateList loadColorStateList(@NonNull TypedValue value, int id, @Nullable Theme theme) throws NotFoundException { return mResourcesImpl.loadColorStateList(this, value, id, theme); @@ -1165,6 +1179,7 @@ public class Resources { * @hide */ @NonNull + @RavenwoodThrow(blockedBy = ComplexColor.class) public ComplexColor loadComplexColor(@NonNull TypedValue value, int id, @Nullable Theme theme) { return mResourcesImpl.loadComplexColor(this, value, id, theme); } @@ -1783,6 +1798,7 @@ public class Resources { * @throws NotFoundException Throws NotFoundException if the given ID * does not exist. */ + @RavenwoodThrow(blockedBy = Drawable.class) public Drawable getDrawable(@DrawableRes int id) throws NotFoundException { return Resources.this.getDrawable(id, this); } @@ -2845,6 +2861,7 @@ public class Resources { * @param appInfo The ApplicationInfo that contains resources paths of the package. */ @FlaggedApi(android.content.res.Flags.FLAG_REGISTER_RESOURCE_PATHS) + @RavenwoodThrow(reason = "FLAG_REGISTER_RESOURCE_PATHS is unsupported") public static void registerResourcePaths(@NonNull String uniqueId, @NonNull ApplicationInfo appInfo) { if (Flags.registerResourcePaths()) { diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java index d874270b4653..90420dec64d1 100644 --- a/core/java/android/content/res/ResourcesImpl.java +++ b/core/java/android/content/res/ResourcesImpl.java @@ -47,6 +47,8 @@ import android.os.Build; import android.os.LocaleList; import android.os.ParcelFileDescriptor; import android.os.Trace; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; +import android.ravenwood.annotation.RavenwoodThrow; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.Log; @@ -82,6 +84,7 @@ import java.util.Locale; * * @hide */ +@RavenwoodKeepWholeClass public class ResourcesImpl { static final String TAG = "Resources"; @@ -689,6 +692,7 @@ public class ResourcesImpl { } @Nullable + @RavenwoodThrow(blockedBy = Drawable.class) Drawable loadDrawable(@NonNull Resources wrapper, @NonNull TypedValue value, int id, int density, @Nullable Resources.Theme theme) throws NotFoundException { @@ -1035,6 +1039,7 @@ public class ResourcesImpl { * Loads a font from XML or resources stream. */ @Nullable + @RavenwoodThrow(blockedBy = Typeface.class) public Typeface loadFont(Resources wrapper, TypedValue value, int id) { if (value.string == null) { throw new NotFoundException("Resource \"" + getResourceName(id) + "\" (" @@ -1121,6 +1126,7 @@ public class ResourcesImpl { } @Nullable + @RavenwoodThrow(blockedBy = ComplexColor.class) ComplexColor loadComplexColor(Resources wrapper, @NonNull TypedValue value, int id, Resources.Theme theme) { if (TRACE_FOR_PRELOAD) { @@ -1162,6 +1168,7 @@ public class ResourcesImpl { } @NonNull + @RavenwoodThrow(blockedBy = ColorStateList.class) ColorStateList loadColorStateList(Resources wrapper, TypedValue value, int id, Resources.Theme theme) throws NotFoundException { diff --git a/core/java/android/content/res/ResourcesKey.java b/core/java/android/content/res/ResourcesKey.java index 99b56a82173e..99a9d89689db 100644 --- a/core/java/android/content/res/ResourcesKey.java +++ b/core/java/android/content/res/ResourcesKey.java @@ -22,12 +22,14 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.content.res.loader.ResourcesLoader; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.text.TextUtils; import java.util.Arrays; import java.util.Objects; /** @hide */ +@RavenwoodKeepWholeClass public final class ResourcesKey { @Nullable @UnsupportedAppUsage diff --git a/core/java/android/content/res/StringBlock.java b/core/java/android/content/res/StringBlock.java index 0070a6f920db..290bc10b64a6 100644 --- a/core/java/android/content/res/StringBlock.java +++ b/core/java/android/content/res/StringBlock.java @@ -25,6 +25,8 @@ import android.graphics.Paint; import android.graphics.Rect; import android.graphics.Typeface; import android.graphics.text.LineBreakConfig; +import android.ravenwood.annotation.RavenwoodClassLoadHook; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.text.Annotation; import android.text.Spannable; import android.text.SpannableString; @@ -60,6 +62,8 @@ import java.util.Arrays; * * {@hide} */ +@RavenwoodKeepWholeClass +@RavenwoodClassLoadHook(RavenwoodClassLoadHook.LIBANDROID_LOADING_HOOK) public final class StringBlock implements Closeable { private static final String TAG = "AssetManager"; private static final boolean localLOGV = false; diff --git a/core/java/android/content/res/TagCounter.java b/core/java/android/content/res/TagCounter.java index 94deee7ab55c..c69a133e214b 100644 --- a/core/java/android/content/res/TagCounter.java +++ b/core/java/android/content/res/TagCounter.java @@ -16,11 +16,14 @@ package android.content.res; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; + /** * Counter used to track the number of tags seen during manifest validation. * * {@hide} */ +@RavenwoodKeepWholeClass public class TagCounter { private static final int DEFAULT_MAX_COUNT = 512; diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java index bb2d2a0cc5c6..f8eeaa93872a 100644 --- a/core/java/android/content/res/TypedArray.java +++ b/core/java/android/content/res/TypedArray.java @@ -27,6 +27,9 @@ import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.StrictMode; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; +import android.ravenwood.annotation.RavenwoodReplace; +import android.ravenwood.annotation.RavenwoodThrow; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.TypedValue; @@ -46,6 +49,7 @@ import java.util.Arrays; * The indices used to retrieve values from this structure correspond to * the positions of the attributes given to obtainStyledAttributes. */ +@RavenwoodKeepWholeClass public class TypedArray implements AutoCloseable { static TypedArray obtain(Resources res, int len) { @@ -557,6 +561,7 @@ public class TypedArray implements AutoCloseable { * @hide */ @Nullable + @RavenwoodThrow(blockedBy = ComplexColor.class) public ComplexColor getComplexColor(@StyleableRes int index) { if (mRecycled) { throw new RuntimeException("Cannot make calls to a recycled instance!"); @@ -593,6 +598,7 @@ public class TypedArray implements AutoCloseable { * not an integer color or color state list. */ @Nullable + @RavenwoodThrow(blockedBy = ColorStateList.class) public ColorStateList getColorStateList(@StyleableRes int index) { if (mRecycled) { throw new RuntimeException("Cannot make calls to a recycled instance!"); @@ -991,6 +997,7 @@ public class TypedArray implements AutoCloseable { * not a color or drawable resource. */ @Nullable + @RavenwoodThrow(blockedBy = Drawable.class) public Drawable getDrawable(@StyleableRes int index) { return getDrawableForDensity(index, 0); } @@ -1000,6 +1007,7 @@ public class TypedArray implements AutoCloseable { * @hide */ @Nullable + @RavenwoodThrow(blockedBy = Drawable.class) public Drawable getDrawableForDensity(@StyleableRes int index, int density) { if (mRecycled) { throw new RuntimeException("Cannot make calls to a recycled instance!"); @@ -1037,6 +1045,7 @@ public class TypedArray implements AutoCloseable { * not a font resource. */ @Nullable + @RavenwoodThrow(blockedBy = Typeface.class) public Typeface getFont(@StyleableRes int index) { if (mRecycled) { throw new RuntimeException("Cannot make calls to a recycled instance!"); diff --git a/core/java/android/content/res/Validator.java b/core/java/android/content/res/Validator.java index f72f3c49ee48..152076887f2c 100644 --- a/core/java/android/content/res/Validator.java +++ b/core/java/android/content/res/Validator.java @@ -18,6 +18,7 @@ package android.content.res; import android.annotation.NonNull; import android.annotation.StyleableRes; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; import com.android.internal.R; @@ -32,6 +33,7 @@ import java.util.ArrayDeque; * * {@hide} */ +@RavenwoodKeepWholeClass public class Validator { private final ArrayDeque<Element> mElements = new ArrayDeque<>(); diff --git a/core/java/android/content/res/XmlBlock.java b/core/java/android/content/res/XmlBlock.java index 7649b32a6c7a..40c532498fbc 100644 --- a/core/java/android/content/res/XmlBlock.java +++ b/core/java/android/content/res/XmlBlock.java @@ -24,6 +24,8 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; +import android.ravenwood.annotation.RavenwoodClassLoadHook; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.util.TypedValue; import com.android.internal.annotations.VisibleForTesting; @@ -44,6 +46,8 @@ import java.io.Reader; * {@hide} */ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) +@RavenwoodKeepWholeClass +@RavenwoodClassLoadHook(RavenwoodClassLoadHook.LIBANDROID_LOADING_HOOK) public final class XmlBlock implements AutoCloseable { private static final boolean DEBUG=false; diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java index cae33d05b6ed..85e33a8b4496 100644 --- a/core/java/android/hardware/display/DisplayManagerGlobal.java +++ b/core/java/android/hardware/display/DisplayManagerGlobal.java @@ -174,10 +174,14 @@ public final class DisplayManagerGlobal { /** * Gets an instance of the display manager global singleton. * + * This method is actually unsupported on Ravenwood, however to support + * {@link android.app.ResourcesManager} we make this method always return null. + * * @return The display manager instance, may be null early in system startup * before the display manager has been fully initialized. */ @UnsupportedAppUsage + // @RavenwoodIgnore(value = "null") public static DisplayManagerGlobal getInstance() { synchronized (DisplayManagerGlobal.class) { if (sInstance == null) { diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java index 6ea462eb969f..032f5923d3f2 100644 --- a/core/java/android/text/TextUtils.java +++ b/core/java/android/text/TextUtils.java @@ -84,6 +84,8 @@ import java.util.List; import java.util.Locale; import java.util.regex.Pattern; +@android.ravenwood.annotation.RavenwoodKeepStaticInitializer +@android.ravenwood.annotation.RavenwoodKeepPartialClass public class TextUtils { private static final String TAG = "TextUtils"; @@ -1704,7 +1706,7 @@ public class TextUtils { return true; } - @android.ravenwood.annotation.RavenwoodReplace + @android.ravenwood.annotation.RavenwoodKeep /* package */ static char[] obtain(int len) { char[] buf; @@ -1719,11 +1721,7 @@ public class TextUtils { return buf; } - /* package */ static char[] obtain$ravenwood(int len) { - return new char[len]; - } - - @android.ravenwood.annotation.RavenwoodReplace + @android.ravenwood.annotation.RavenwoodKeep /* package */ static void recycle(char[] temp) { if (temp.length > 1000) return; @@ -1733,10 +1731,6 @@ public class TextUtils { } } - /* package */ static void recycle$ravenwood(char[] temp) { - // Handled by typical GC - } - /** * Html-encode the string. * @param s the string to be encoded @@ -2161,6 +2155,7 @@ public class TextUtils { * * Be careful: this code will need to be updated when vertical scripts will be supported */ + @android.ravenwood.annotation.RavenwoodKeep public static int getLayoutDirectionFromLocale(Locale locale) { return ((locale != null && !locale.equals(Locale.ROOT) && ULocale.forLocale(locale).isRightToLeft()) diff --git a/core/java/android/util/DisplayMetrics.java b/core/java/android/util/DisplayMetrics.java index f14485b09424..c5d3c1d1f349 100644 --- a/core/java/android/util/DisplayMetrics.java +++ b/core/java/android/util/DisplayMetrics.java @@ -24,6 +24,7 @@ import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.content.res.FontScaleConverter; import android.os.SystemProperties; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.view.WindowManager; import java.lang.annotation.Retention; @@ -45,6 +46,7 @@ import java.lang.annotation.RetentionPolicy; * </p> * */ +@RavenwoodKeepWholeClass public class DisplayMetrics { @IntDef(prefix = { "DENSITY_" }, value = { diff --git a/core/java/android/util/TypedValue.java b/core/java/android/util/TypedValue.java index 9668b6ad1f72..26ab5885c9ea 100644 --- a/core/java/android/util/TypedValue.java +++ b/core/java/android/util/TypedValue.java @@ -22,6 +22,7 @@ import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.content.pm.ActivityInfo.Config; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -30,6 +31,7 @@ import java.lang.annotation.RetentionPolicy; * Container for a dynamically typed data value. Primarily used with * {@link android.content.res.Resources} for holding resource values. */ +@RavenwoodKeepWholeClass public class TypedValue { /** The value contains no data. */ public static final int TYPE_NULL = 0x00; @@ -827,4 +829,3 @@ public class TypedValue { return sb.toString(); } } - diff --git a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java index 8fe1813b7ba0..ee3a3c27ca77 100644 --- a/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java +++ b/core/java/com/android/internal/ravenwood/RavenwoodEnvironment.java @@ -15,24 +15,33 @@ */ package com.android.internal.ravenwood; +import android.ravenwood.annotation.RavenwoodKeepWholeClass; import android.ravenwood.annotation.RavenwoodNativeSubstitutionClass; +import android.ravenwood.annotation.RavenwoodReplace; /** * Class to interact with the Ravenwood environment. */ -@android.ravenwood.annotation.RavenwoodKeepWholeClass +@RavenwoodKeepWholeClass @RavenwoodNativeSubstitutionClass( "com.android.platform.test.ravenwood.nativesubstitution.RavenwoodEnvironment_host") public final class RavenwoodEnvironment { public static final String TAG = "RavenwoodEnvironment"; - private static RavenwoodEnvironment sInstance = new RavenwoodEnvironment(); - private static Workaround sWorkaround = new Workaround(); + private static final RavenwoodEnvironment sInstance; + private static final Workaround sWorkaround; private RavenwoodEnvironment() { - if (isRunningOnRavenwood()) { - ensureRavenwoodInitializedInternal(); - } + } + + static { + sInstance = new RavenwoodEnvironment(); + sWorkaround = new Workaround(); + ensureRavenwoodInitialized(); + } + + private static RuntimeException notSupportedOnDevice() { + return new UnsupportedOperationException("This method can only be used on Ravenwood"); } /** @@ -47,15 +56,11 @@ public final class RavenwoodEnvironment { * * No-op if called on the device side. */ + @RavenwoodReplace public static void ensureRavenwoodInitialized() { } - private static void ensureRavenwoodInitialized$ravenwood() { - getInstance(); // This is enough to initialize the environment. - } - - /** Initialize the ravenwood environment */ - private static native void ensureRavenwoodInitializedInternal(); + private static native void ensureRavenwoodInitialized$ravenwood(); /** * USE IT SPARINGLY! Returns true if it's running on Ravenwood, hostside test environment. @@ -69,7 +74,7 @@ public final class RavenwoodEnvironment { * <p>If someone needs it without having access to the SDK, the following hack would work too. * <code>System.getProperty("java.class.path").contains("ravenwood")</code> */ - @android.ravenwood.annotation.RavenwoodReplace + @RavenwoodReplace public boolean isRunningOnRavenwood() { return false; } @@ -79,16 +84,39 @@ public final class RavenwoodEnvironment { } /** - * See {@link Workaround}. It's only usablke on Ravenwood. + * Get the object back from the address obtained from + * {@link dalvik.system.VMRuntime#addressOf(Object)}. + */ + @RavenwoodReplace + public <T> T fromAddress(long address) { + throw notSupportedOnDevice(); + } + + private native <T> T fromAddress$ravenwood(long address); + + /** + * See {@link Workaround}. It's only usable on Ravenwood. */ + @RavenwoodReplace public static Workaround workaround() { - if (getInstance().isRunningOnRavenwood()) { - return sWorkaround; - } - throw new IllegalStateException("Workaround can only be used on Ravenwood"); + throw notSupportedOnDevice(); + } + + private static Workaround workaround$ravenwood() { + return sWorkaround; } /** + * @return the "ravenwood-runtime" directory. + */ + @RavenwoodReplace + public String getRavenwoodRuntimePath() { + throw notSupportedOnDevice(); + } + + private native String getRavenwoodRuntimePath$ravenwood(); + + /** * A set of APIs used to work around missing features on Ravenwood. Ideally, this class should * be empty, and all its APIs should be able to be implemented properly. */ diff --git a/core/jni/android_content_res_ApkAssets.cpp b/core/jni/android_content_res_ApkAssets.cpp index 52a9578466d8..0b801b96afaa 100644 --- a/core/jni/android_content_res_ApkAssets.cpp +++ b/core/jni/android_content_res_ApkAssets.cpp @@ -428,7 +428,7 @@ static jlong NativeGetStringBlock(JNIEnv* /*env*/, jclass /*clazz*/, jlong ptr) return reinterpret_cast<jlong>(apk_assets->GetLoadedArsc()->GetStringPool()); } -static jboolean NativeIsUpToDate(jlong ptr) { +static jboolean NativeIsUpToDate(CRITICAL_JNI_PARAMS_COMMA jlong ptr) { auto scoped_apk_assets = ScopedLock(ApkAssetsFromLong(ptr)); auto apk_assets = scoped_apk_assets->get(); return apk_assets->IsUpToDate() ? JNI_TRUE : JNI_FALSE; diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index 3d0ab4ef0981..7fe6731b7116 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -36,7 +36,6 @@ #include "android-base/stringprintf.h" #include "android_content_res_ApkAssets.h" #include "android_runtime/AndroidRuntime.h" -#include "android_util_Binder.h" #include "androidfw/Asset.h" #include "androidfw/AssetManager.h" #include "androidfw/AssetManager2.h" @@ -104,6 +103,11 @@ static struct arraymap_offsets_t { jmethodID put; } gArrayMapOffsets; +static struct parcel_file_descriptor_offsets_t { + jclass mClass; + jmethodID mAdoptFd; +} gParcelFileDescriptorOffsets; + static jclass g_stringClass = nullptr; // ---------------------------------------------------------------------------- @@ -244,7 +248,6 @@ static jstring NativeGetOverlayablesToString(JNIEnv* env, jclass /*clazz*/, jlon return env->NewStringUTF(result.c_str()); } -#ifdef __ANDROID__ // Layoutlib does not support parcel static jobject ReturnParcelFileDescriptor(JNIEnv* env, std::unique_ptr<Asset> asset, jlongArray out_offsets) { off64_t start_offset, length; @@ -269,22 +272,10 @@ static jobject ReturnParcelFileDescriptor(JNIEnv* env, std::unique_ptr<Asset> as env->ReleasePrimitiveArrayCritical(out_offsets, offsets, 0); - jobject file_desc = jniCreateFileDescriptor(env, fd); - if (file_desc == nullptr) { - close(fd); - return nullptr; - } - return newParcelFileDescriptor(env, file_desc); -} -#else -static jobject ReturnParcelFileDescriptor(JNIEnv* env, std::unique_ptr<Asset> asset, - jlongArray out_offsets) { - jniThrowException(env, "java/lang/UnsupportedOperationException", - "Implement me"); - // never reached - return nullptr; + return env->CallStaticObjectMethod(gParcelFileDescriptorOffsets.mClass, + gParcelFileDescriptorOffsets.mAdoptFd, + fd); } -#endif static jint NativeGetGlobalAssetCount(JNIEnv* /*env*/, jobject /*clazz*/) { return Asset::getGlobalCount(); @@ -1202,6 +1193,28 @@ static void NativeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong the env->ReleasePrimitiveArrayCritical(java_attrs, attrs, JNI_ABORT); } +// This version is compatible with standard JVMs, however slower without ART optimizations +static void NativeApplyStyleWithArray(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr, + jint def_style_attr, jint def_style_resid, + jlong xml_parser_ptr, jintArray java_attrs, + jintArray java_values, jintArray java_indices) { + auto assetmanager = LockAndStartAssetManager(ptr); + Theme* theme = reinterpret_cast<Theme*>(theme_ptr); + CHECK(theme->GetAssetManager() == &(*assetmanager)); + (void) assetmanager; + + ResXMLParser* xml_parser = reinterpret_cast<ResXMLParser*>(xml_parser_ptr); + ScopedIntCriticalArrayRW out_values(env, java_values); + ScopedIntCriticalArrayRW out_indices(env, java_indices); + ScopedIntCriticalArrayRO attrs(env, java_attrs); + + ApplyStyle(theme, xml_parser, static_cast<uint32_t>(def_style_attr), + static_cast<uint32_t>(def_style_resid), + reinterpret_cast<const uint32_t*>(attrs.get()), attrs.size(), + reinterpret_cast<uint32_t*>(out_values.get()), + reinterpret_cast<uint32_t*>(out_indices.get())); +} + static jboolean NativeResolveAttrs(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr, jint def_style_attr, jint def_style_resid, jintArray java_values, jintArray java_attrs, jintArray out_java_values, @@ -1581,6 +1594,7 @@ static const JNINativeMethod gAssetManagerMethods[] = { // Style attribute related methods. {"nativeAttributeResolutionStack", "(JJIII)[I", (void*)NativeAttributeResolutionStack}, {"nativeApplyStyle", "(JJIIJ[IJJ)V", (void*)NativeApplyStyle}, + {"nativeApplyStyleWithArray", "(JJIIJ[I[I[I)V", (void*)NativeApplyStyleWithArray}, {"nativeResolveAttrs", "(JJII[I[I[I[I)Z", (void*)NativeResolveAttrs}, {"nativeRetrieveAttributes", "(JJ[I[I[I)Z", (void*)NativeRetrieveAttributes}, @@ -1666,6 +1680,11 @@ int register_android_content_AssetManager(JNIEnv* env) { GetMethodIDOrDie(env, gArrayMapOffsets.classObject, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + jclass pfdClass = FindClassOrDie(env, "android/os/ParcelFileDescriptor"); + gParcelFileDescriptorOffsets.mClass = MakeGlobalRefOrDie(env, pfdClass); + gParcelFileDescriptorOffsets.mAdoptFd = + GetStaticMethodIDOrDie(env, pfdClass, "adoptFd", "(I)Landroid/os/ParcelFileDescriptor;"); + return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods)); } diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java index 1dd5e1ddd630..48bed7942cdf 100644 --- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java +++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodContext.java @@ -16,8 +16,13 @@ package android.platform.test.ravenwood; +import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_RESOURCE_APK; + import android.content.ClipboardManager; import android.content.Context; +import android.content.res.AssetManager; +import android.content.res.Resources; +import android.content.res.Resources.Theme; import android.hardware.ISerialManager; import android.hardware.SerialManager; import android.os.Handler; @@ -31,11 +36,18 @@ import android.ravenwood.example.RedManager; import android.util.ArrayMap; import android.util.Singleton; +import com.android.internal.annotations.GuardedBy; + +import java.io.File; +import java.io.IOException; import java.util.Objects; import java.util.concurrent.Executor; import java.util.function.Supplier; public class RavenwoodContext extends RavenwoodBaseContext { + private static final String TAG = "Ravenwood"; + + private final Object mLock = new Object(); private final String mPackageName; private final HandlerThread mMainThread; @@ -44,15 +56,29 @@ public class RavenwoodContext extends RavenwoodBaseContext { private final ArrayMap<Class<?>, String> mClassToName = new ArrayMap<>(); private final ArrayMap<String, Supplier<?>> mNameToFactory = new ArrayMap<>(); + private final File mFilesDir; + private final File mCacheDir; + private final Supplier<Resources> mResourcesSupplier; + + @GuardedBy("mLock") + private Resources mResources; + + @GuardedBy("mLock") + private Resources.Theme mTheme; + private void registerService(Class<?> serviceClass, String serviceName, Supplier<?> serviceSupplier) { mClassToName.put(serviceClass, serviceName); mNameToFactory.put(serviceName, serviceSupplier); } - public RavenwoodContext(String packageName, HandlerThread mainThread) { + public RavenwoodContext(String packageName, HandlerThread mainThread, + Supplier<Resources> resourcesSupplier) throws IOException { mPackageName = packageName; mMainThread = mainThread; + mResourcesSupplier = resourcesSupplier; + mFilesDir = createTempDir("files-dir"); + mCacheDir = createTempDir("cache-dir"); // Services provided by a typical shipping device registerService(ClipboardManager.class, @@ -85,6 +111,11 @@ public class RavenwoodContext extends RavenwoodBaseContext { } } + void cleanUp() { + deleteDir(mFilesDir); + deleteDir(mCacheDir); + } + @Override public String getSystemServiceName(Class<?> serviceClass) { // TODO: pivot to using SystemServiceRegistry @@ -150,6 +181,52 @@ public class RavenwoodContext extends RavenwoodBaseContext { return Context.DEVICE_ID_DEFAULT; } + @Override + public File getFilesDir() { + return mFilesDir; + } + + @Override + public File getCacheDir() { + return mCacheDir; + } + + @Override + public boolean deleteFile(String name) { + File f = new File(name); + return f.delete(); + } + + @Override + public Resources getResources() { + synchronized (mLock) { + if (mResources == null) { + mResources = mResourcesSupplier.get(); + } + return mResources; + } + } + + @Override + public AssetManager getAssets() { + return getResources().getAssets(); + } + + @Override + public Theme getTheme() { + synchronized (mLock) { + if (mTheme == null) { + mTheme = getResources().newTheme(); + } + return mTheme; + } + } + + @Override + public String getPackageResourcePath() { + return new File(RAVENWOOD_RESOURCE_APK).getAbsolutePath(); + } + /** * Wrap the given {@link Supplier} to become memoized. * @@ -175,4 +252,26 @@ public class RavenwoodContext extends RavenwoodBaseContext { public interface ThrowingSupplier<T> { T get() throws Exception; } + + + static File createTempDir(String prefix) throws IOException { + // Create a temp file, delete it and recreate it as a directory. + final File dir = File.createTempFile(prefix + "-", ""); + dir.delete(); + dir.mkdirs(); + return dir; + } + + static void deleteDir(File dir) { + File[] children = dir.listFiles(); + if (children != null) { + for (File child : children) { + if (child.isDirectory()) { + deleteDir(child); + } else { + child.delete(); + } + } + } + } } diff --git a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java index 4357f2b8660a..3ea4cb7fb69f 100644 --- a/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java +++ b/ravenwood/junit-impl-src/android/platform/test/ravenwood/RavenwoodRuleImpl.java @@ -16,16 +16,23 @@ package android.platform.test.ravenwood; +import static com.android.ravenwood.common.RavenwoodCommonUtils.RAVENWOOD_RESOURCE_APK; + import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; import android.app.ActivityManager; import android.app.Instrumentation; +import android.app.ResourcesManager; +import android.content.res.Resources; import android.os.Build; import android.os.Bundle; import android.os.HandlerThread; import android.os.Looper; import android.os.ServiceManager; import android.util.Log; +import android.view.DisplayAdjustments; import androidx.test.platform.app.InstrumentationRegistry; @@ -42,6 +49,8 @@ import org.junit.runner.Description; import org.junit.runner.RunWith; import org.junit.runners.model.Statement; +import java.io.File; +import java.io.IOException; import java.io.PrintStream; import java.lang.annotation.Annotation; import java.lang.reflect.Method; @@ -55,6 +64,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Supplier; public class RavenwoodRuleImpl { private static final String MAIN_THREAD_NAME = "RavenwoodMain"; @@ -89,7 +99,7 @@ public class RavenwoodRuleImpl { sPendingUncaughtException.compareAndSet(null, throwable); }; - public static void init(RavenwoodRule rule) { + public static void init(RavenwoodRule rule) throws IOException { if (ENABLE_UNCAUGHT_EXCEPTION_DETECTION) { maybeThrowPendingUncaughtException(false); Thread.setDefaultUncaughtExceptionHandler(sUncaughtExceptionHandler); @@ -119,7 +129,28 @@ public class RavenwoodRuleImpl { main = null; } - rule.mContext = new RavenwoodContext(rule.mPackageName, main); + // TODO This should be integrated into LoadedApk + final Supplier<Resources> resourcesSupplier = () -> { + final var resApkFile = new File(RAVENWOOD_RESOURCE_APK).getAbsoluteFile(); + assertTrue(resApkFile.isFile()); + + final var res = resApkFile.getAbsolutePath(); + + final var emptyPaths = new String[0]; + + ResourcesManager.getInstance().initializeApplicationPaths(res, emptyPaths); + + final var ret = ResourcesManager.getInstance().getResources(null, res, + emptyPaths, emptyPaths, emptyPaths, + emptyPaths, null, null, + new DisplayAdjustments().getCompatibilityInfo(), + RavenwoodRuleImpl.class.getClassLoader(), null); + + assertNotNull(ret); + return ret; + }; + + rule.mContext = new RavenwoodContext(rule.mPackageName, main, resourcesSupplier); rule.mInstrumentation = new Instrumentation(); rule.mInstrumentation.basicInit(rule.mContext); InstrumentationRegistry.registerInstance(rule.mInstrumentation, Bundle.EMPTY); @@ -145,6 +176,9 @@ public class RavenwoodRuleImpl { InstrumentationRegistry.registerInstance(null, Bundle.EMPTY); rule.mInstrumentation = null; + if (rule.mContext != null) { + ((RavenwoodContext) rule.mContext).cleanUp(); + } rule.mContext = null; if (rule.mProvideMainThread) { @@ -161,6 +195,8 @@ public class RavenwoodRuleImpl { android.os.Binder.reset$ravenwood(); android.os.Process.reset$ravenwood(); + ResourcesManager.setInstance(null); // Better structure needed. + if (ENABLE_UNCAUGHT_EXCEPTION_DETECTION) { maybeThrowPendingUncaughtException(true); } diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java index 825c91a1b6dc..19ee56ecee9e 100644 --- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java +++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodRule.java @@ -36,6 +36,7 @@ import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -362,7 +363,7 @@ public class RavenwoodRule implements TestRule { } } - private void commonPrologue(Statement base, Description description) { + private void commonPrologue(Statement base, Description description) throws IOException { RavenwoodRuleImpl.logTestRunner("started", description); RavenwoodRuleImpl.validate(base, description, ENABLE_OPTIONAL_VALIDATION); RavenwoodRuleImpl.init(RavenwoodRule.this); diff --git a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java index 5f1b0c2c929f..ef8f5840f949 100644 --- a/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java +++ b/ravenwood/junit-src/android/platform/test/ravenwood/RavenwoodSystemProperties.java @@ -48,11 +48,13 @@ public class RavenwoodSystemProperties { switch (key) { case "gsm.version.baseband": case "no.such.thing": + case "qemu.sf.lcd_density": case "ro.bootloader": case "ro.debuggable": case "ro.hardware": case "ro.hw_timeout_multiplier": case "ro.odm.build.media_performance_class": + case "ro.sf.lcd_density": case "ro.treble.enabled": case "ro.vndk.version": return true; diff --git a/ravenwood/runtime-common-src/com/android/ravenwood/common/JvmWorkaround.java b/ravenwood/runtime-common-src/com/android/ravenwood/common/JvmWorkaround.java index 0238baa2dcbf..02153a757cd8 100644 --- a/ravenwood/runtime-common-src/com/android/ravenwood/common/JvmWorkaround.java +++ b/ravenwood/runtime-common-src/com/android/ravenwood/common/JvmWorkaround.java @@ -38,7 +38,6 @@ public abstract class JvmWorkaround { */ public abstract void setFdInt(FileDescriptor fd, int fdInt); - /** * Equivalent to Android's FileDescriptor.getInt$(). */ @@ -49,6 +48,10 @@ public abstract class JvmWorkaround { */ public abstract void closeFd(FileDescriptor fd) throws IOException; + public abstract long addressOf(Object o); + + public abstract <T> T fromAddress(long address); + /** * Placeholder implementation for the host side. * @@ -75,5 +78,15 @@ public abstract class JvmWorkaround { public void closeFd(FileDescriptor fd) { throw calledOnHostside(); } + + @Override + public long addressOf(Object o) { + throw calledOnHostside(); + } + + @Override + public <T> T fromAddress(long address) { + throw calledOnHostside(); + } } } diff --git a/ravenwood/runtime-common-src/com/android/ravenwood/common/OpenJdkWorkaround.java b/ravenwood/runtime-common-src/com/android/ravenwood/common/OpenJdkWorkaround.java index a260147654cd..2323c65de5cf 100644 --- a/ravenwood/runtime-common-src/com/android/ravenwood/common/OpenJdkWorkaround.java +++ b/ravenwood/runtime-common-src/com/android/ravenwood/common/OpenJdkWorkaround.java @@ -18,8 +18,16 @@ package com.android.ravenwood.common; import java.io.FileDescriptor; import java.io.IOException; import java.lang.reflect.InvocationTargetException; +import java.util.Map; +import java.util.WeakHashMap; class OpenJdkWorkaround extends JvmWorkaround { + + // @GuardedBy("sAddressMap") + private static final Map<Object, Long> sAddressMap = new WeakHashMap<>(); + // @GuardedBy("sAddressMap") + private static long sCurrentAddress = 1; + @Override public void setFdInt(FileDescriptor fd, int fdInt) { try { @@ -60,4 +68,28 @@ class OpenJdkWorkaround extends JvmWorkaround { + " perhaps JRE has changed?", e); } } + + @Override + public long addressOf(Object o) { + synchronized (sAddressMap) { + Long address = sAddressMap.get(o); + if (address == null) { + address = sCurrentAddress++; + sAddressMap.put(o, address); + } + return address; + } + } + + @Override + public <T> T fromAddress(long address) { + synchronized (sAddressMap) { + for (var e : sAddressMap.entrySet()) { + if (e.getValue() == address) { + return (T) e.getKey(); + } + } + } + return null; + } } diff --git a/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java b/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java index c8cc8d9fe273..129802378cd4 100644 --- a/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java +++ b/ravenwood/runtime-common-src/com/android/ravenwood/common/RavenwoodCommonUtils.java @@ -46,6 +46,8 @@ public class RavenwoodCommonUtils { public static final String RAVENWOOD_SYSPROP = "ro.is_on_ravenwood"; + public static final String RAVENWOOD_RESOURCE_APK = "ravenwood-res-apks/ravenwood-res.apk"; + // @GuardedBy("sLock") private static boolean sIntegrityChecked = false; diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/RavenwoodEnvironment_host.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/RavenwoodEnvironment_host.java index b00cee02f611..706a055c9faf 100644 --- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/RavenwoodEnvironment_host.java +++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/nativesubstitution/RavenwoodEnvironment_host.java @@ -19,6 +19,7 @@ import android.platform.test.ravenwood.RavenwoodSystemProperties; import android.util.Log; import com.android.internal.ravenwood.RavenwoodEnvironment; +import com.android.ravenwood.common.JvmWorkaround; import com.android.ravenwood.common.RavenwoodCommonUtils; public class RavenwoodEnvironment_host { @@ -35,7 +36,7 @@ public class RavenwoodEnvironment_host { /** * Called from {@link RavenwoodEnvironment#ensureRavenwoodInitialized()}. */ - public static void ensureRavenwoodInitializedInternal() { + public static void ensureRavenwoodInitialized() { synchronized (sInitializeLock) { if (sInitialized) { return; @@ -55,4 +56,18 @@ public class RavenwoodEnvironment_host { sInitialized = true; } } -}
\ No newline at end of file + + /** + * Called from {@link RavenwoodEnvironment#getRavenwoodRuntimePath()}. + */ + public static String getRavenwoodRuntimePath(RavenwoodEnvironment env) { + return RavenwoodCommonUtils.getRavenwoodRuntimePath(); + } + + /** + * Called from {@link RavenwoodEnvironment#fromAddress(long)}. + */ + public static <T> T fromAddress(RavenwoodEnvironment env, long address) { + return JvmWorkaround.getInstance().fromAddress(address); + } +} diff --git a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java index e198646d4e27..0f955e772445 100644 --- a/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java +++ b/ravenwood/runtime-helper-src/framework/com/android/platform/test/ravenwood/runtimehelper/ClassLoadHook.java @@ -151,6 +151,11 @@ public class ClassLoadHook { */ private static final Class<?>[] sLibandroidClasses = { android.util.Log.class, + android.os.Parcel.class, + android.content.res.ApkAssets.class, + android.content.res.AssetManager.class, + android.content.res.StringBlock.class, + android.content.res.XmlBlock.class, }; /** diff --git a/ravenwood/runtime-helper-src/libcore-fake/android/system/Os.java b/ravenwood/runtime-helper-src/libcore-fake/android/system/Os.java index ecaa8161ee46..7371d0a029b9 100644 --- a/ravenwood/runtime-helper-src/libcore-fake/android/system/Os.java +++ b/ravenwood/runtime-helper-src/libcore-fake/android/system/Os.java @@ -19,7 +19,11 @@ import com.android.ravenwood.common.JvmWorkaround; import com.android.ravenwood.common.RavenwoodRuntimeNative; import java.io.FileDescriptor; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InterruptedIOException; +import java.nio.ByteBuffer; +import java.nio.channels.AsynchronousCloseException; /** * OS class replacement used on Ravenwood. For now, we just implement APIs as we need them... @@ -36,6 +40,11 @@ public final class Os { return RavenwoodRuntimeNative.pipe2(flags); } + /** Ravenwood version of the OS API. */ + public static FileDescriptor[] pipe() throws ErrnoException { + return RavenwoodRuntimeNative.pipe2(0); + } + public static FileDescriptor dup(FileDescriptor fd) throws ErrnoException { return RavenwoodRuntimeNative.dup(fd); } @@ -69,4 +78,19 @@ public final class Os { public static FileDescriptor open(String path, int flags, int mode) throws ErrnoException { return RavenwoodRuntimeNative.open(path, flags, mode); } + + /** Ravenwood version of the OS API. */ + public static int pread(FileDescriptor fd, byte[] bytes, int byteOffset, int byteCount, + long offset) throws ErrnoException, InterruptedIOException { + var channel = new FileInputStream(fd).getChannel(); + var buf = ByteBuffer.wrap(bytes, byteOffset, byteCount); + try { + return channel.read(buf, offset); + } catch (AsynchronousCloseException e) { + throw new InterruptedIOException(e.getMessage()); + } catch (IOException e) { + // Most likely EIO + throw new ErrnoException("pread", OsConstants.EIO, e); + } + } } diff --git a/ravenwood/runtime-helper-src/libcore-fake/dalvik/system/VMRuntime.java b/ravenwood/runtime-helper-src/libcore-fake/dalvik/system/VMRuntime.java index 7d2b00d9420d..ed5a587cdccc 100644 --- a/ravenwood/runtime-helper-src/libcore-fake/dalvik/system/VMRuntime.java +++ b/ravenwood/runtime-helper-src/libcore-fake/dalvik/system/VMRuntime.java @@ -19,6 +19,8 @@ package dalvik.system; // The original is here: // $ANDROID_BUILD_TOP/libcore/libart/src/main/java/dalvik/system/VMRuntime.java +import com.android.ravenwood.common.JvmWorkaround; + import java.lang.reflect.Array; public class VMRuntime { @@ -42,4 +44,12 @@ public class VMRuntime { public Object newUnpaddedArray(Class<?> componentType, int minLength) { return Array.newInstance(componentType, minLength); } + + public Object newNonMovableArray(Class<?> componentType, int length) { + return Array.newInstance(componentType, length); + } + + public long addressOf(Object obj) { + return JvmWorkaround.getInstance().addressOf(obj); + } } diff --git a/ravenwood/texts/ravenwood-annotation-allowed-classes.txt b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt index 639ebab4515b..231179b53ce8 100644 --- a/ravenwood/texts/ravenwood-annotation-allowed-classes.txt +++ b/ravenwood/texts/ravenwood-annotation-allowed-classes.txt @@ -39,6 +39,7 @@ android.util.ContainerHelpers android.util.DataUnit android.util.DayOfMonthCursor android.util.DebugUtils +android.util.DisplayMetrics android.util.Dumpable android.util.DumpableContainer android.util.EmptyArray @@ -102,6 +103,7 @@ android.util.StringBuilderPrinter android.util.TeeWriter android.util.TimeUtils android.util.TimingsTraceLog +android.util.TypedValue android.util.UtilConfig android.util.Xml @@ -193,6 +195,7 @@ android.content.ClipboardManager android.content.ComponentName android.content.ContentUris android.content.ContentValues +android.content.Context android.content.ContextWrapper android.content.Intent android.content.IntentFilter @@ -215,6 +218,23 @@ android.content.pm.ServiceInfo android.content.pm.Signature android.content.pm.UserInfo +android.content.res.ApkAssets +android.content.res.AssetFileDescriptor +android.content.res.AssetManager +android.content.res.AssetManager$Builder +android.content.res.DrawableCache +android.content.res.Element +android.content.res.Resources +android.content.res.Resources$Theme +android.content.res.ResourceId +android.content.res.ResourcesImpl +android.content.res.ResourcesKey +android.content.res.StringBlock +android.content.res.TagCounter +android.content.res.TypedArray +android.content.res.Validator +android.content.res.XmlBlock + android.database.AbstractCursor android.database.CharArrayBuffer android.database.ContentObservable @@ -258,6 +278,10 @@ android.app.ActivityOptions android.app.BroadcastOptions android.app.ComponentOptions android.app.Instrumentation +android.app.LocaleConfig +android.app.ResourcesManager +android.app.ResourcesManager$UpdateHandler +android.app.WindowConfiguration android.metrics.LogMaker diff --git a/ravenwood/texts/ravenwood-framework-policies.txt b/ravenwood/texts/ravenwood-framework-policies.txt index 4012bdc5be62..3062863052d2 100644 --- a/ravenwood/texts/ravenwood-framework-policies.txt +++ b/ravenwood/texts/ravenwood-framework-policies.txt @@ -9,8 +9,11 @@ class :feature_flags keepclass # Keep all sysprops generated code implementations class :sysprops keepclass +# Keep all resource R classes +class :r keepclass + # To avoid VerifyError on nano proto files (b/324063814), we rename nano proto classes. -# Note: The "rename" directive must use shashes (/) as a package name separator. +# Note: The "rename" directive must use slashes (/) as a package name separator. rename com/.*/nano/ devicenano/ rename android/.*/nano/ devicenano/ @@ -62,3 +65,24 @@ class android.content.pm.PackageManager keep method <init> ()V keep class android.text.ClipboardManager keep method <init> ()V keep + +# Just enough to allow ResourcesManager to run +class android.hardware.display.DisplayManagerGlobal keep + method getInstance ()Landroid/hardware/display/DisplayManagerGlobal; ignore + +# These classes will be properly enabled in follow-up CLs + +class android.content.res.FontResourcesParser keepclass +class android.content.res.FontResourcesParser.FamilyResourceEntry keepclass +class android.content.res.FontResourcesParser.ProviderResourceEntry keepclass +class android.content.res.FontResourcesParser.FontFamilyFilesResourceEntry keepclass +class android.content.res.FontResourcesParser.FontFileResourceEntry keepclass +class android.content.res.FontScaleConverter keepclass +class android.content.res.FontScaleConverterImpl keepclass +class android.content.res.FontScaleConverterFactory keepclass +class android.content.res.ThemedResourceCache keepclass +class android.content.res.ConfigurationBoundResourceCache keepclass +class android.content.res.Configuration keepclass +class android.content.res.CompatibilityInfo keepclass +class android.content.res.ConstantState keepclass +class android.view.DisplayAdjustments keepclass |