Loading Ravenwood.bp +10 −84 Original line number Diff line number Diff line Loading @@ -38,8 +38,8 @@ java_genrule { "--out-impl-jar $(location ravenwood.jar) " + "--gen-keep-all-file $(location hoststubgen_keep_all.txt) " + "--gen-input-dump-file $(location hoststubgen_dump.txt) " + "--gen-keep-all-file $(location hoststubgen_framework-minus-apex_keep_all.txt) " + "--gen-input-dump-file $(location hoststubgen_framework-minus-apex_dump.txt) " + "--in-jar $(location :framework-minus-apex-for-hoststubgen) " + "--policy-override-file $(location :ravenwood-framework-policies) " + Loading @@ -54,14 +54,14 @@ java_genrule { "ravenwood.jar", // Following files are created just as FYI. "hoststubgen_keep_all.txt", "hoststubgen_dump.txt", "hoststubgen_framework-minus-apex_keep_all.txt", "hoststubgen_framework-minus-apex_dump.txt", "hoststubgen_framework-minus-apex.log", "hoststubgen_framework-minus-apex_stats.csv", "hoststubgen_framework-minus-apex_apis.csv", ], visibility: ["//visibility:private"], defaults: ["ravenwood-internal-only-visibility-genrule"], } // Extract the impl jar from "framework-minus-apex.ravenwood-base" for subsequent build rules. Loading @@ -79,43 +79,6 @@ java_genrule { ], } // Extract the stats file. genrule { name: "framework-minus-apex.ravenwood.stats", defaults: ["ravenwood-internal-only-visibility-genrule"], cmd: "cp $(in) $(out)", srcs: [ ":framework-minus-apex.ravenwood-base{hoststubgen_framework-minus-apex_stats.csv}", ], out: [ "hoststubgen_framework-minus-apex_stats.csv", ], } genrule { name: "framework-minus-apex.ravenwood.apis", defaults: ["ravenwood-internal-only-visibility-genrule"], cmd: "cp $(in) $(out)", srcs: [ ":framework-minus-apex.ravenwood-base{hoststubgen_framework-minus-apex_apis.csv}", ], out: [ "hoststubgen_framework-minus-apex_apis.csv", ], } genrule { name: "framework-minus-apex.ravenwood.keep_all", defaults: ["ravenwood-internal-only-visibility-genrule"], cmd: "cp $(in) $(out)", srcs: [ ":framework-minus-apex.ravenwood-base{hoststubgen_keep_all.txt}", ], out: [ "hoststubgen_framework-minus-apex_keep_all.txt", ], } java_library { name: "services.core-for-hoststubgen", installable: false, // host only jar. Loading @@ -138,8 +101,8 @@ java_genrule { "--out-impl-jar $(location ravenwood.jar) " + "--gen-keep-all-file $(location hoststubgen_keep_all.txt) " + "--gen-input-dump-file $(location hoststubgen_dump.txt) " + "--gen-keep-all-file $(location hoststubgen_services.core_keep_all.txt) " + "--gen-input-dump-file $(location hoststubgen_services.core_dump.txt) " + "--in-jar $(location :services.core-for-hoststubgen) " + "--policy-override-file $(location :ravenwood-services-policies) " + Loading @@ -154,14 +117,14 @@ java_genrule { "ravenwood.jar", // Following files are created just as FYI. "hoststubgen_keep_all.txt", "hoststubgen_dump.txt", "hoststubgen_services.core_keep_all.txt", "hoststubgen_services.core_dump.txt", "hoststubgen_services.core.log", "hoststubgen_services.core_stats.csv", "hoststubgen_services.core_apis.csv", ], visibility: ["//visibility:private"], defaults: ["ravenwood-internal-only-visibility-genrule"], } java_genrule { Loading @@ -176,43 +139,6 @@ java_genrule { ], } // Extract the stats file. genrule { name: "services.core.ravenwood.stats", defaults: ["ravenwood-internal-only-visibility-genrule"], cmd: "cp $(in) $(out)", srcs: [ ":services.core.ravenwood-base{hoststubgen_services.core_stats.csv}", ], out: [ "hoststubgen_services.core_stats.csv", ], } genrule { name: "services.core.ravenwood.apis", defaults: ["ravenwood-internal-only-visibility-genrule"], cmd: "cp $(in) $(out)", srcs: [ ":services.core.ravenwood-base{hoststubgen_services.core_apis.csv}", ], out: [ "hoststubgen_services.core_apis.csv", ], } genrule { name: "services.core.ravenwood.keep_all", defaults: ["ravenwood-internal-only-visibility-genrule"], cmd: "cp $(in) $(out)", srcs: [ ":services.core.ravenwood-base{hoststubgen_keep_all.txt}", ], out: [ "hoststubgen_services.core_keep_all.txt", ], } java_library { name: "services.core.ravenwood-jarjar", defaults: ["ravenwood-internal-only-visibility-java"], Loading core/java/android/app/ResourcesManager.java +167 −95 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.content.res.AssetManager; import android.content.res.CompatResources; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.content.res.Flags; import android.content.res.Resources; import android.content.res.ResourcesImpl; import android.content.res.ResourcesKey; Loading Loading @@ -138,16 +139,22 @@ public class ResourcesManager { private final ArrayMap<String, SharedLibraryAssets> mSharedLibAssetsMap = new ArrayMap<>(); @VisibleForTesting public ArrayMap<String, SharedLibraryAssets> getRegisteredResourcePaths() { return mSharedLibAssetsMap; } /** * The internal function to register the resources paths of a package (e.g. a shared library). * This will collect the package resources' paths from its ApplicationInfo and add them to all * existing and future contexts while the application is running. */ public void registerResourcePaths(@NonNull String uniqueId, @NonNull ApplicationInfo appInfo) { SharedLibraryAssets sharedLibAssets = new SharedLibraryAssets(appInfo.sourceDir, appInfo.splitSourceDirs, appInfo.sharedLibraryFiles, appInfo.resourceDirs, appInfo.overlayPaths); if (!Flags.registerResourcePaths()) { return; } final var sharedLibAssets = new SharedLibraryAssets(appInfo); synchronized (mLock) { if (mSharedLibAssetsMap.containsKey(uniqueId)) { Slog.v(TAG, "Package resources' paths for uniqueId: " + uniqueId Loading @@ -155,18 +162,37 @@ public class ResourcesManager { return; } mSharedLibAssetsMap.put(uniqueId, sharedLibAssets); appendLibAssetsLocked(sharedLibAssets.getAllAssetPaths()); Slog.v(TAG, "The following resources' paths have been added: " + Arrays.toString(sharedLibAssets.getAllAssetPaths())); appendLibAssetsLocked(sharedLibAssets); Slog.v(TAG, "The following library key has been added: " + sharedLibAssets.getResourcesKey()); } } /** * Apply the registered library paths to the passed impl object * @return the hash code for the current version of the registered paths */ public int updateResourceImplWithRegisteredLibs(@NonNull ResourcesImpl impl) { if (!Flags.registerResourcePaths()) { return 0; } final var collector = new PathCollector(null); final int size = mSharedLibAssetsMap.size(); for (int i = 0; i < size; i++) { final var libraryKey = mSharedLibAssetsMap.valueAt(i).getResourcesKey(); collector.appendKey(libraryKey); } impl.getAssets().addPresetApkKeys(extractApkKeys(collector.collectedKey())); return size; } private static class ApkKey { public static class ApkKey { public final String path; public final boolean sharedLib; public final boolean overlay; ApkKey(String path, boolean sharedLib, boolean overlay) { public ApkKey(String path, boolean sharedLib, boolean overlay) { this.path = path; this.sharedLib = sharedLib; this.overlay = overlay; Loading @@ -190,6 +216,12 @@ public class ResourcesManager { return this.path.equals(other.path) && this.sharedLib == other.sharedLib && this.overlay == other.overlay; } @Override public String toString() { return "ApkKey[" + (sharedLib ? "lib" : "app") + (overlay ? ", overlay" : "") + ": " + path + "]"; } } /** Loading Loading @@ -505,7 +537,10 @@ public class ResourcesManager { return "/data/resource-cache/" + path.substring(1).replace('/', '@') + "@idmap"; } private @NonNull ApkAssets loadApkAssets(@NonNull final ApkKey key) throws IOException { /** * Loads the ApkAssets object for the passed key, or picks the one from the cache if available. */ public @NonNull ApkAssets loadApkAssets(@NonNull final ApkKey key) throws IOException { ApkAssets apkAssets; // Optimistically check if this ApkAssets exists somewhere else. Loading Loading @@ -747,8 +782,8 @@ public class ResourcesManager { private @Nullable ResourcesImpl findOrCreateResourcesImplForKeyLocked( @NonNull ResourcesKey key, @Nullable ApkAssetsSupplier apkSupplier) { ResourcesImpl impl = findResourcesImplForKeyLocked(key); // ResourcesImpl also need to be recreated if its shared library count is not up-to-date. if (impl == null || impl.getSharedLibCount() != mSharedLibAssetsMap.size()) { // ResourcesImpl also need to be recreated if its shared library hash is not up-to-date. if (impl == null || impl.getAppliedSharedLibsHash() != mSharedLibAssetsMap.size()) { impl = createResourcesImpl(key, apkSupplier); if (impl != null) { mResourceImpls.put(key, new WeakReference<>(impl)); Loading Loading @@ -1533,55 +1568,108 @@ public class ResourcesManager { } } private void appendLibAssetsLocked(String[] libAssets) { synchronized (mLock) { // Record which ResourcesImpl need updating // (and what ResourcesKey they should update to). final ArrayMap<ResourcesImpl, ResourcesKey> updatedResourceKeys = new ArrayMap<>(); /** * A utility class to collect resources paths into a ResourcesKey object: * - Separates the libraries and the overlays into different sets as those are loaded in * different ways. * - Allows to start with an existing original key object, and copies all non-path related * properties into the final one. * - Preserves the path order while dropping all duplicates in an efficient manner. */ private static class PathCollector { public final ResourcesKey originalKey; public final ArrayList<String> orderedLibs = new ArrayList<>(); public final ArraySet<String> libsSet = new ArraySet<>(); public final ArrayList<String> orderedOverlays = new ArrayList<>(); public final ArraySet<String> overlaysSet = new ArraySet<>(); static void appendNewPath(@NonNull String path, @NonNull ArraySet<String> uniquePaths, @NonNull ArrayList<String> orderedPaths) { if (uniquePaths.add(path)) { orderedPaths.add(path); } } static void appendAllNewPaths(@Nullable String[] paths, @NonNull ArraySet<String> uniquePaths, @NonNull ArrayList<String> orderedPaths) { if (paths == null) return; for (int i = 0, size = paths.length; i < size; i++) { appendNewPath(paths[i], uniquePaths, orderedPaths); } } PathCollector(@Nullable ResourcesKey original) { originalKey = original; if (originalKey != null) { appendKey(originalKey); } } public void appendKey(@NonNull ResourcesKey key) { appendAllNewPaths(key.mLibDirs, libsSet, orderedLibs); appendAllNewPaths(key.mOverlayPaths, overlaysSet, orderedOverlays); } boolean isSameAsOriginal() { if (originalKey == null) { return orderedLibs.isEmpty() && orderedOverlays.isEmpty(); } return ((originalKey.mLibDirs == null && orderedLibs.isEmpty()) || (originalKey.mLibDirs != null && originalKey.mLibDirs.length == orderedLibs.size())) && ((originalKey.mOverlayPaths == null && orderedOverlays.isEmpty()) || (originalKey.mOverlayPaths != null && originalKey.mOverlayPaths.length == orderedOverlays.size())); } @NonNull ResourcesKey collectedKey() { return new ResourcesKey( originalKey == null ? null : originalKey.mResDir, originalKey == null ? null : originalKey.mSplitResDirs, orderedOverlays.toArray(new String[0]), orderedLibs.toArray(new String[0]), originalKey == null ? 0 : originalKey.mDisplayId, originalKey == null ? null : originalKey.mOverrideConfiguration, originalKey == null ? null : originalKey.mCompatInfo, originalKey == null ? null : originalKey.mLoaders); } } /** * Takes the original resources key and the one containing a set of library paths and overlays * to append, and combines them together. In case when the original key already contains all * those paths this function returns null, otherwise it makes a new ResourcesKey object. */ private @Nullable ResourcesKey createNewResourceKeyIfNeeded( @NonNull ResourcesKey original, @NonNull ResourcesKey library) { final var collector = new PathCollector(original); collector.appendKey(library); return collector.isSameAsOriginal() ? null : collector.collectedKey(); } /** * Append the newly registered shared library asset paths to all existing resources objects. */ private void appendLibAssetsLocked(@NonNull SharedLibraryAssets libAssets) { // Record the ResourcesImpl's that need updating, and what ResourcesKey they should // update to. final ArrayMap<ResourcesImpl, ResourcesKey> updatedResourceKeys = new ArrayMap<>(); final int implCount = mResourceImpls.size(); for (int i = 0; i < implCount; i++) { final ResourcesKey key = mResourceImpls.keyAt(i); final WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.valueAt(i); final ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null; if (impl == null) { Slog.w(TAG, "Found a ResourcesImpl which is null, skip it and continue to " + "append shared library assets for next ResourcesImpl."); Slog.w(TAG, "Found a null ResourcesImpl, skipped."); continue; } var newDirs = new ArrayList<String>(); var dirsSet = new ArraySet<String>(); if (key.mLibDirs != null) { final int dirsLength = key.mLibDirs.length; for (int k = 0; k < dirsLength; k++) { newDirs.add(key.mLibDirs[k]); dirsSet.add(key.mLibDirs[k]); } } final int assetsLength = libAssets.length; for (int j = 0; j < assetsLength; j++) { if (dirsSet.add(libAssets[j])) { newDirs.add(libAssets[j]); } } String[] newLibAssets = newDirs.toArray(new String[0]); if (!Arrays.equals(newLibAssets, key.mLibDirs)) { updatedResourceKeys.put(impl, new ResourcesKey( key.mResDir, key.mSplitResDirs, key.mOverlayPaths, newLibAssets, key.mDisplayId, key.mOverrideConfiguration, key.mCompatInfo, key.mLoaders)); final var newKey = createNewResourceKeyIfNeeded(key, libAssets.getResourcesKey()); if (newKey != null) { updatedResourceKeys.put(impl, newKey); } } redirectAllResourcesToNewImplLocked(updatedResourceKeys); } } private void applyNewResourceDirsLocked(@Nullable final String[] oldSourceDirs, @NonNull final ApplicationInfo appInfo) { Loading Loading @@ -1718,8 +1806,9 @@ public class ResourcesManager { } } // Another redirect function which will loop through all Resources and reload ResourcesImpl // if it needs a shared library asset paths update. // Another redirect function which will loop through all Resources in the process, even the ones // the app created outside of the regular Android Runtime, and reload their ResourcesImpl if it // needs a shared library asset paths update. private void redirectAllResourcesToNewImplLocked( @NonNull final ArrayMap<ResourcesImpl, ResourcesKey> updatedResourceKeys) { cleanupReferences(mAllResourceReferences, mAllResourceReferencesQueue); Loading Loading @@ -1835,52 +1924,35 @@ public class ResourcesManager { } } @VisibleForTesting public static class SharedLibraryAssets { private final String[] mAssetPaths; SharedLibraryAssets(String sourceDir, String[] splitSourceDirs, String[] sharedLibraryFiles, String[] resourceDirs, String[] overlayPaths) { mAssetPaths = collectAssetPaths(sourceDir, splitSourceDirs, sharedLibraryFiles, resourceDirs, overlayPaths); } private @NonNull String[] collectAssetPaths(String sourceDir, String[] splitSourceDirs, String[] sharedLibraryFiles, String[] resourceDirs, String[] overlayPaths) { final String[][] inputLists = { splitSourceDirs, sharedLibraryFiles, resourceDirs, overlayPaths }; final ArraySet<String> assetPathSet = new ArraySet<>(); final List<String> assetPathList = new ArrayList<>(); if (sourceDir != null) { assetPathSet.add(sourceDir); assetPathList.add(sourceDir); } for (int i = 0; i < inputLists.length; i++) { if (inputLists[i] != null) { for (int j = 0; j < inputLists[i].length; j++) { if (assetPathSet.add(inputLists[i][j])) { assetPathList.add(inputLists[i][j]); } } } } return assetPathList.toArray(new String[0]); private final ResourcesKey mResourcesKey; private SharedLibraryAssets(ApplicationInfo appInfo) { // We're loading all library's files as shared libs, regardless where they are in // its own ApplicationInfo. final var collector = new PathCollector(null); PathCollector.appendNewPath(appInfo.sourceDir, collector.libsSet, collector.orderedLibs); PathCollector.appendAllNewPaths(appInfo.splitSourceDirs, collector.libsSet, collector.orderedLibs); PathCollector.appendAllNewPaths(appInfo.sharedLibraryFiles, collector.libsSet, collector.orderedLibs); PathCollector.appendAllNewPaths(appInfo.resourceDirs, collector.overlaysSet, collector.orderedOverlays); PathCollector.appendAllNewPaths(appInfo.overlayPaths, collector.overlaysSet, collector.orderedOverlays); mResourcesKey = collector.collectedKey(); } /** * @return all the asset paths of this collected in this class. * @return the resources key for this library assets. */ public @NonNull String[] getAllAssetPaths() { return mAssetPaths; public @NonNull ResourcesKey getResourcesKey() { return mResourcesKey; } } public @NonNull ArrayMap<String, SharedLibraryAssets> getSharedLibAssetsMap() { return new ArrayMap<>(mSharedLibAssetsMap); } /** * Add all resources references to the list which is designed to help to append shared library * asset paths. This is invoked in Resources constructor to include all Resources instances. Loading core/java/android/app/UiAutomation.java +16 −8 Original line number Diff line number Diff line Loading @@ -1647,10 +1647,13 @@ public final class UiAutomation { // Calling out without a lock held. mUiAutomationConnection.executeShellCommand(command, sink, null); } catch (IOException ioe) { Log.e(LOG_TAG, "Error executing shell command!", ioe); } catch (RemoteException re) { Log.e(LOG_TAG, "Error executing shell command!", re); } catch (IOException | RemoteException e) { Log.e(LOG_TAG, "Error executing shell command!", e); } catch (IllegalArgumentException | NullPointerException | SecurityException e) { // An exception of these types is propagated from the server. // Rethrow it to keep the old behavior. To avoid FD leak, close the source. IoUtils.closeQuietly(source); throw e; } finally { IoUtils.closeQuietly(sink); } Loading Loading @@ -1734,10 +1737,15 @@ public final class UiAutomation { // Calling out without a lock held. mUiAutomationConnection.executeShellCommandWithStderr( command, sink_read, source_write, stderr_sink_read); } catch (IOException ioe) { Log.e(LOG_TAG, "Error executing shell command!", ioe); } catch (RemoteException re) { Log.e(LOG_TAG, "Error executing shell command!", re); } catch (IOException | RemoteException e) { Log.e(LOG_TAG, "Error executing shell command!", e); } catch (IllegalArgumentException | SecurityException | NullPointerException e) { // An exception of these types is propagated from the server. // Rethrow it to keep the old behavior. To avoid FD leaks, close the sources. IoUtils.closeQuietly(sink_write); IoUtils.closeQuietly(source_read); IoUtils.closeQuietly(stderr_source_read); throw e; } finally { IoUtils.closeQuietly(sink_read); IoUtils.closeQuietly(source_write); Loading core/java/android/app/UiAutomationConnection.java +15 −2 Original line number Diff line number Diff line Loading @@ -550,8 +550,21 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { try { process = Runtime.getRuntime().exec(command); } catch (IOException exc) { throw new RuntimeException("Error running shell command '" + command + "'", exc); } catch (IOException ex) { // Make sure the passed FDs are closed. IoUtils.closeQuietly(sink); IoUtils.closeQuietly(source); IoUtils.closeQuietly(stderrSink); // No to need to wrap in RuntimeException. Only to keep the old behavior. // This is just logged and not propagated to the remote caller anyway. throw new RuntimeException("Error running shell command '" + command + "'", ex); } catch (IllegalArgumentException | NullPointerException | SecurityException ex) { // Make sure the passed FDs are closed. IoUtils.closeQuietly(sink); IoUtils.closeQuietly(source); IoUtils.closeQuietly(stderrSink); // Rethrow the exception. This will be propagated to the remote caller. throw ex; } // Read from process and write to pipe Loading core/java/android/companion/virtual/IVirtualDevice.aidl +13 −0 Original line number Diff line number Diff line Loading @@ -17,7 +17,9 @@ package android.companion.virtual; import android.app.PendingIntent; import android.companion.virtual.IVirtualDeviceActivityListener; import android.companion.virtual.IVirtualDeviceIntentInterceptor; import android.companion.virtual.IVirtualDeviceSoundEffectListener; import android.companion.virtual.audio.IAudioConfigChangedCallback; import android.companion.virtual.audio.IAudioRoutingCallback; import android.companion.virtual.sensor.VirtualSensor; Loading Loading @@ -296,4 +298,15 @@ interface IVirtualDevice { */ @EnforcePermission("CREATE_VIRTUAL_DEVICE") String getVirtualCameraId(in VirtualCameraConfig camera); /** * Setter for listeners that live in the client process, namely in * {@link android.companion.virtual.VirtualDeviceInternal}. * * This is needed for virtual devices that are created by the system, as the VirtualDeviceImpl * object is created before the returned VirtualDeviceInternal one. */ @EnforcePermission("CREATE_VIRTUAL_DEVICE") void setListeners(in IVirtualDeviceActivityListener activityListener, in IVirtualDeviceSoundEffectListener soundEffectListener); } Loading
Ravenwood.bp +10 −84 Original line number Diff line number Diff line Loading @@ -38,8 +38,8 @@ java_genrule { "--out-impl-jar $(location ravenwood.jar) " + "--gen-keep-all-file $(location hoststubgen_keep_all.txt) " + "--gen-input-dump-file $(location hoststubgen_dump.txt) " + "--gen-keep-all-file $(location hoststubgen_framework-minus-apex_keep_all.txt) " + "--gen-input-dump-file $(location hoststubgen_framework-minus-apex_dump.txt) " + "--in-jar $(location :framework-minus-apex-for-hoststubgen) " + "--policy-override-file $(location :ravenwood-framework-policies) " + Loading @@ -54,14 +54,14 @@ java_genrule { "ravenwood.jar", // Following files are created just as FYI. "hoststubgen_keep_all.txt", "hoststubgen_dump.txt", "hoststubgen_framework-minus-apex_keep_all.txt", "hoststubgen_framework-minus-apex_dump.txt", "hoststubgen_framework-minus-apex.log", "hoststubgen_framework-minus-apex_stats.csv", "hoststubgen_framework-minus-apex_apis.csv", ], visibility: ["//visibility:private"], defaults: ["ravenwood-internal-only-visibility-genrule"], } // Extract the impl jar from "framework-minus-apex.ravenwood-base" for subsequent build rules. Loading @@ -79,43 +79,6 @@ java_genrule { ], } // Extract the stats file. genrule { name: "framework-minus-apex.ravenwood.stats", defaults: ["ravenwood-internal-only-visibility-genrule"], cmd: "cp $(in) $(out)", srcs: [ ":framework-minus-apex.ravenwood-base{hoststubgen_framework-minus-apex_stats.csv}", ], out: [ "hoststubgen_framework-minus-apex_stats.csv", ], } genrule { name: "framework-minus-apex.ravenwood.apis", defaults: ["ravenwood-internal-only-visibility-genrule"], cmd: "cp $(in) $(out)", srcs: [ ":framework-minus-apex.ravenwood-base{hoststubgen_framework-minus-apex_apis.csv}", ], out: [ "hoststubgen_framework-minus-apex_apis.csv", ], } genrule { name: "framework-minus-apex.ravenwood.keep_all", defaults: ["ravenwood-internal-only-visibility-genrule"], cmd: "cp $(in) $(out)", srcs: [ ":framework-minus-apex.ravenwood-base{hoststubgen_keep_all.txt}", ], out: [ "hoststubgen_framework-minus-apex_keep_all.txt", ], } java_library { name: "services.core-for-hoststubgen", installable: false, // host only jar. Loading @@ -138,8 +101,8 @@ java_genrule { "--out-impl-jar $(location ravenwood.jar) " + "--gen-keep-all-file $(location hoststubgen_keep_all.txt) " + "--gen-input-dump-file $(location hoststubgen_dump.txt) " + "--gen-keep-all-file $(location hoststubgen_services.core_keep_all.txt) " + "--gen-input-dump-file $(location hoststubgen_services.core_dump.txt) " + "--in-jar $(location :services.core-for-hoststubgen) " + "--policy-override-file $(location :ravenwood-services-policies) " + Loading @@ -154,14 +117,14 @@ java_genrule { "ravenwood.jar", // Following files are created just as FYI. "hoststubgen_keep_all.txt", "hoststubgen_dump.txt", "hoststubgen_services.core_keep_all.txt", "hoststubgen_services.core_dump.txt", "hoststubgen_services.core.log", "hoststubgen_services.core_stats.csv", "hoststubgen_services.core_apis.csv", ], visibility: ["//visibility:private"], defaults: ["ravenwood-internal-only-visibility-genrule"], } java_genrule { Loading @@ -176,43 +139,6 @@ java_genrule { ], } // Extract the stats file. genrule { name: "services.core.ravenwood.stats", defaults: ["ravenwood-internal-only-visibility-genrule"], cmd: "cp $(in) $(out)", srcs: [ ":services.core.ravenwood-base{hoststubgen_services.core_stats.csv}", ], out: [ "hoststubgen_services.core_stats.csv", ], } genrule { name: "services.core.ravenwood.apis", defaults: ["ravenwood-internal-only-visibility-genrule"], cmd: "cp $(in) $(out)", srcs: [ ":services.core.ravenwood-base{hoststubgen_services.core_apis.csv}", ], out: [ "hoststubgen_services.core_apis.csv", ], } genrule { name: "services.core.ravenwood.keep_all", defaults: ["ravenwood-internal-only-visibility-genrule"], cmd: "cp $(in) $(out)", srcs: [ ":services.core.ravenwood-base{hoststubgen_keep_all.txt}", ], out: [ "hoststubgen_services.core_keep_all.txt", ], } java_library { name: "services.core.ravenwood-jarjar", defaults: ["ravenwood-internal-only-visibility-java"], Loading
core/java/android/app/ResourcesManager.java +167 −95 Original line number Diff line number Diff line Loading @@ -30,6 +30,7 @@ import android.content.res.AssetManager; import android.content.res.CompatResources; import android.content.res.CompatibilityInfo; import android.content.res.Configuration; import android.content.res.Flags; import android.content.res.Resources; import android.content.res.ResourcesImpl; import android.content.res.ResourcesKey; Loading Loading @@ -138,16 +139,22 @@ public class ResourcesManager { private final ArrayMap<String, SharedLibraryAssets> mSharedLibAssetsMap = new ArrayMap<>(); @VisibleForTesting public ArrayMap<String, SharedLibraryAssets> getRegisteredResourcePaths() { return mSharedLibAssetsMap; } /** * The internal function to register the resources paths of a package (e.g. a shared library). * This will collect the package resources' paths from its ApplicationInfo and add them to all * existing and future contexts while the application is running. */ public void registerResourcePaths(@NonNull String uniqueId, @NonNull ApplicationInfo appInfo) { SharedLibraryAssets sharedLibAssets = new SharedLibraryAssets(appInfo.sourceDir, appInfo.splitSourceDirs, appInfo.sharedLibraryFiles, appInfo.resourceDirs, appInfo.overlayPaths); if (!Flags.registerResourcePaths()) { return; } final var sharedLibAssets = new SharedLibraryAssets(appInfo); synchronized (mLock) { if (mSharedLibAssetsMap.containsKey(uniqueId)) { Slog.v(TAG, "Package resources' paths for uniqueId: " + uniqueId Loading @@ -155,18 +162,37 @@ public class ResourcesManager { return; } mSharedLibAssetsMap.put(uniqueId, sharedLibAssets); appendLibAssetsLocked(sharedLibAssets.getAllAssetPaths()); Slog.v(TAG, "The following resources' paths have been added: " + Arrays.toString(sharedLibAssets.getAllAssetPaths())); appendLibAssetsLocked(sharedLibAssets); Slog.v(TAG, "The following library key has been added: " + sharedLibAssets.getResourcesKey()); } } /** * Apply the registered library paths to the passed impl object * @return the hash code for the current version of the registered paths */ public int updateResourceImplWithRegisteredLibs(@NonNull ResourcesImpl impl) { if (!Flags.registerResourcePaths()) { return 0; } final var collector = new PathCollector(null); final int size = mSharedLibAssetsMap.size(); for (int i = 0; i < size; i++) { final var libraryKey = mSharedLibAssetsMap.valueAt(i).getResourcesKey(); collector.appendKey(libraryKey); } impl.getAssets().addPresetApkKeys(extractApkKeys(collector.collectedKey())); return size; } private static class ApkKey { public static class ApkKey { public final String path; public final boolean sharedLib; public final boolean overlay; ApkKey(String path, boolean sharedLib, boolean overlay) { public ApkKey(String path, boolean sharedLib, boolean overlay) { this.path = path; this.sharedLib = sharedLib; this.overlay = overlay; Loading @@ -190,6 +216,12 @@ public class ResourcesManager { return this.path.equals(other.path) && this.sharedLib == other.sharedLib && this.overlay == other.overlay; } @Override public String toString() { return "ApkKey[" + (sharedLib ? "lib" : "app") + (overlay ? ", overlay" : "") + ": " + path + "]"; } } /** Loading Loading @@ -505,7 +537,10 @@ public class ResourcesManager { return "/data/resource-cache/" + path.substring(1).replace('/', '@') + "@idmap"; } private @NonNull ApkAssets loadApkAssets(@NonNull final ApkKey key) throws IOException { /** * Loads the ApkAssets object for the passed key, or picks the one from the cache if available. */ public @NonNull ApkAssets loadApkAssets(@NonNull final ApkKey key) throws IOException { ApkAssets apkAssets; // Optimistically check if this ApkAssets exists somewhere else. Loading Loading @@ -747,8 +782,8 @@ public class ResourcesManager { private @Nullable ResourcesImpl findOrCreateResourcesImplForKeyLocked( @NonNull ResourcesKey key, @Nullable ApkAssetsSupplier apkSupplier) { ResourcesImpl impl = findResourcesImplForKeyLocked(key); // ResourcesImpl also need to be recreated if its shared library count is not up-to-date. if (impl == null || impl.getSharedLibCount() != mSharedLibAssetsMap.size()) { // ResourcesImpl also need to be recreated if its shared library hash is not up-to-date. if (impl == null || impl.getAppliedSharedLibsHash() != mSharedLibAssetsMap.size()) { impl = createResourcesImpl(key, apkSupplier); if (impl != null) { mResourceImpls.put(key, new WeakReference<>(impl)); Loading Loading @@ -1533,55 +1568,108 @@ public class ResourcesManager { } } private void appendLibAssetsLocked(String[] libAssets) { synchronized (mLock) { // Record which ResourcesImpl need updating // (and what ResourcesKey they should update to). final ArrayMap<ResourcesImpl, ResourcesKey> updatedResourceKeys = new ArrayMap<>(); /** * A utility class to collect resources paths into a ResourcesKey object: * - Separates the libraries and the overlays into different sets as those are loaded in * different ways. * - Allows to start with an existing original key object, and copies all non-path related * properties into the final one. * - Preserves the path order while dropping all duplicates in an efficient manner. */ private static class PathCollector { public final ResourcesKey originalKey; public final ArrayList<String> orderedLibs = new ArrayList<>(); public final ArraySet<String> libsSet = new ArraySet<>(); public final ArrayList<String> orderedOverlays = new ArrayList<>(); public final ArraySet<String> overlaysSet = new ArraySet<>(); static void appendNewPath(@NonNull String path, @NonNull ArraySet<String> uniquePaths, @NonNull ArrayList<String> orderedPaths) { if (uniquePaths.add(path)) { orderedPaths.add(path); } } static void appendAllNewPaths(@Nullable String[] paths, @NonNull ArraySet<String> uniquePaths, @NonNull ArrayList<String> orderedPaths) { if (paths == null) return; for (int i = 0, size = paths.length; i < size; i++) { appendNewPath(paths[i], uniquePaths, orderedPaths); } } PathCollector(@Nullable ResourcesKey original) { originalKey = original; if (originalKey != null) { appendKey(originalKey); } } public void appendKey(@NonNull ResourcesKey key) { appendAllNewPaths(key.mLibDirs, libsSet, orderedLibs); appendAllNewPaths(key.mOverlayPaths, overlaysSet, orderedOverlays); } boolean isSameAsOriginal() { if (originalKey == null) { return orderedLibs.isEmpty() && orderedOverlays.isEmpty(); } return ((originalKey.mLibDirs == null && orderedLibs.isEmpty()) || (originalKey.mLibDirs != null && originalKey.mLibDirs.length == orderedLibs.size())) && ((originalKey.mOverlayPaths == null && orderedOverlays.isEmpty()) || (originalKey.mOverlayPaths != null && originalKey.mOverlayPaths.length == orderedOverlays.size())); } @NonNull ResourcesKey collectedKey() { return new ResourcesKey( originalKey == null ? null : originalKey.mResDir, originalKey == null ? null : originalKey.mSplitResDirs, orderedOverlays.toArray(new String[0]), orderedLibs.toArray(new String[0]), originalKey == null ? 0 : originalKey.mDisplayId, originalKey == null ? null : originalKey.mOverrideConfiguration, originalKey == null ? null : originalKey.mCompatInfo, originalKey == null ? null : originalKey.mLoaders); } } /** * Takes the original resources key and the one containing a set of library paths and overlays * to append, and combines them together. In case when the original key already contains all * those paths this function returns null, otherwise it makes a new ResourcesKey object. */ private @Nullable ResourcesKey createNewResourceKeyIfNeeded( @NonNull ResourcesKey original, @NonNull ResourcesKey library) { final var collector = new PathCollector(original); collector.appendKey(library); return collector.isSameAsOriginal() ? null : collector.collectedKey(); } /** * Append the newly registered shared library asset paths to all existing resources objects. */ private void appendLibAssetsLocked(@NonNull SharedLibraryAssets libAssets) { // Record the ResourcesImpl's that need updating, and what ResourcesKey they should // update to. final ArrayMap<ResourcesImpl, ResourcesKey> updatedResourceKeys = new ArrayMap<>(); final int implCount = mResourceImpls.size(); for (int i = 0; i < implCount; i++) { final ResourcesKey key = mResourceImpls.keyAt(i); final WeakReference<ResourcesImpl> weakImplRef = mResourceImpls.valueAt(i); final ResourcesImpl impl = weakImplRef != null ? weakImplRef.get() : null; if (impl == null) { Slog.w(TAG, "Found a ResourcesImpl which is null, skip it and continue to " + "append shared library assets for next ResourcesImpl."); Slog.w(TAG, "Found a null ResourcesImpl, skipped."); continue; } var newDirs = new ArrayList<String>(); var dirsSet = new ArraySet<String>(); if (key.mLibDirs != null) { final int dirsLength = key.mLibDirs.length; for (int k = 0; k < dirsLength; k++) { newDirs.add(key.mLibDirs[k]); dirsSet.add(key.mLibDirs[k]); } } final int assetsLength = libAssets.length; for (int j = 0; j < assetsLength; j++) { if (dirsSet.add(libAssets[j])) { newDirs.add(libAssets[j]); } } String[] newLibAssets = newDirs.toArray(new String[0]); if (!Arrays.equals(newLibAssets, key.mLibDirs)) { updatedResourceKeys.put(impl, new ResourcesKey( key.mResDir, key.mSplitResDirs, key.mOverlayPaths, newLibAssets, key.mDisplayId, key.mOverrideConfiguration, key.mCompatInfo, key.mLoaders)); final var newKey = createNewResourceKeyIfNeeded(key, libAssets.getResourcesKey()); if (newKey != null) { updatedResourceKeys.put(impl, newKey); } } redirectAllResourcesToNewImplLocked(updatedResourceKeys); } } private void applyNewResourceDirsLocked(@Nullable final String[] oldSourceDirs, @NonNull final ApplicationInfo appInfo) { Loading Loading @@ -1718,8 +1806,9 @@ public class ResourcesManager { } } // Another redirect function which will loop through all Resources and reload ResourcesImpl // if it needs a shared library asset paths update. // Another redirect function which will loop through all Resources in the process, even the ones // the app created outside of the regular Android Runtime, and reload their ResourcesImpl if it // needs a shared library asset paths update. private void redirectAllResourcesToNewImplLocked( @NonNull final ArrayMap<ResourcesImpl, ResourcesKey> updatedResourceKeys) { cleanupReferences(mAllResourceReferences, mAllResourceReferencesQueue); Loading Loading @@ -1835,52 +1924,35 @@ public class ResourcesManager { } } @VisibleForTesting public static class SharedLibraryAssets { private final String[] mAssetPaths; SharedLibraryAssets(String sourceDir, String[] splitSourceDirs, String[] sharedLibraryFiles, String[] resourceDirs, String[] overlayPaths) { mAssetPaths = collectAssetPaths(sourceDir, splitSourceDirs, sharedLibraryFiles, resourceDirs, overlayPaths); } private @NonNull String[] collectAssetPaths(String sourceDir, String[] splitSourceDirs, String[] sharedLibraryFiles, String[] resourceDirs, String[] overlayPaths) { final String[][] inputLists = { splitSourceDirs, sharedLibraryFiles, resourceDirs, overlayPaths }; final ArraySet<String> assetPathSet = new ArraySet<>(); final List<String> assetPathList = new ArrayList<>(); if (sourceDir != null) { assetPathSet.add(sourceDir); assetPathList.add(sourceDir); } for (int i = 0; i < inputLists.length; i++) { if (inputLists[i] != null) { for (int j = 0; j < inputLists[i].length; j++) { if (assetPathSet.add(inputLists[i][j])) { assetPathList.add(inputLists[i][j]); } } } } return assetPathList.toArray(new String[0]); private final ResourcesKey mResourcesKey; private SharedLibraryAssets(ApplicationInfo appInfo) { // We're loading all library's files as shared libs, regardless where they are in // its own ApplicationInfo. final var collector = new PathCollector(null); PathCollector.appendNewPath(appInfo.sourceDir, collector.libsSet, collector.orderedLibs); PathCollector.appendAllNewPaths(appInfo.splitSourceDirs, collector.libsSet, collector.orderedLibs); PathCollector.appendAllNewPaths(appInfo.sharedLibraryFiles, collector.libsSet, collector.orderedLibs); PathCollector.appendAllNewPaths(appInfo.resourceDirs, collector.overlaysSet, collector.orderedOverlays); PathCollector.appendAllNewPaths(appInfo.overlayPaths, collector.overlaysSet, collector.orderedOverlays); mResourcesKey = collector.collectedKey(); } /** * @return all the asset paths of this collected in this class. * @return the resources key for this library assets. */ public @NonNull String[] getAllAssetPaths() { return mAssetPaths; public @NonNull ResourcesKey getResourcesKey() { return mResourcesKey; } } public @NonNull ArrayMap<String, SharedLibraryAssets> getSharedLibAssetsMap() { return new ArrayMap<>(mSharedLibAssetsMap); } /** * Add all resources references to the list which is designed to help to append shared library * asset paths. This is invoked in Resources constructor to include all Resources instances. Loading
core/java/android/app/UiAutomation.java +16 −8 Original line number Diff line number Diff line Loading @@ -1647,10 +1647,13 @@ public final class UiAutomation { // Calling out without a lock held. mUiAutomationConnection.executeShellCommand(command, sink, null); } catch (IOException ioe) { Log.e(LOG_TAG, "Error executing shell command!", ioe); } catch (RemoteException re) { Log.e(LOG_TAG, "Error executing shell command!", re); } catch (IOException | RemoteException e) { Log.e(LOG_TAG, "Error executing shell command!", e); } catch (IllegalArgumentException | NullPointerException | SecurityException e) { // An exception of these types is propagated from the server. // Rethrow it to keep the old behavior. To avoid FD leak, close the source. IoUtils.closeQuietly(source); throw e; } finally { IoUtils.closeQuietly(sink); } Loading Loading @@ -1734,10 +1737,15 @@ public final class UiAutomation { // Calling out without a lock held. mUiAutomationConnection.executeShellCommandWithStderr( command, sink_read, source_write, stderr_sink_read); } catch (IOException ioe) { Log.e(LOG_TAG, "Error executing shell command!", ioe); } catch (RemoteException re) { Log.e(LOG_TAG, "Error executing shell command!", re); } catch (IOException | RemoteException e) { Log.e(LOG_TAG, "Error executing shell command!", e); } catch (IllegalArgumentException | SecurityException | NullPointerException e) { // An exception of these types is propagated from the server. // Rethrow it to keep the old behavior. To avoid FD leaks, close the sources. IoUtils.closeQuietly(sink_write); IoUtils.closeQuietly(source_read); IoUtils.closeQuietly(stderr_source_read); throw e; } finally { IoUtils.closeQuietly(sink_read); IoUtils.closeQuietly(source_write); Loading
core/java/android/app/UiAutomationConnection.java +15 −2 Original line number Diff line number Diff line Loading @@ -550,8 +550,21 @@ public final class UiAutomationConnection extends IUiAutomationConnection.Stub { try { process = Runtime.getRuntime().exec(command); } catch (IOException exc) { throw new RuntimeException("Error running shell command '" + command + "'", exc); } catch (IOException ex) { // Make sure the passed FDs are closed. IoUtils.closeQuietly(sink); IoUtils.closeQuietly(source); IoUtils.closeQuietly(stderrSink); // No to need to wrap in RuntimeException. Only to keep the old behavior. // This is just logged and not propagated to the remote caller anyway. throw new RuntimeException("Error running shell command '" + command + "'", ex); } catch (IllegalArgumentException | NullPointerException | SecurityException ex) { // Make sure the passed FDs are closed. IoUtils.closeQuietly(sink); IoUtils.closeQuietly(source); IoUtils.closeQuietly(stderrSink); // Rethrow the exception. This will be propagated to the remote caller. throw ex; } // Read from process and write to pipe Loading
core/java/android/companion/virtual/IVirtualDevice.aidl +13 −0 Original line number Diff line number Diff line Loading @@ -17,7 +17,9 @@ package android.companion.virtual; import android.app.PendingIntent; import android.companion.virtual.IVirtualDeviceActivityListener; import android.companion.virtual.IVirtualDeviceIntentInterceptor; import android.companion.virtual.IVirtualDeviceSoundEffectListener; import android.companion.virtual.audio.IAudioConfigChangedCallback; import android.companion.virtual.audio.IAudioRoutingCallback; import android.companion.virtual.sensor.VirtualSensor; Loading Loading @@ -296,4 +298,15 @@ interface IVirtualDevice { */ @EnforcePermission("CREATE_VIRTUAL_DEVICE") String getVirtualCameraId(in VirtualCameraConfig camera); /** * Setter for listeners that live in the client process, namely in * {@link android.companion.virtual.VirtualDeviceInternal}. * * This is needed for virtual devices that are created by the system, as the VirtualDeviceImpl * object is created before the returned VirtualDeviceInternal one. */ @EnforcePermission("CREATE_VIRTUAL_DEVICE") void setListeners(in IVirtualDeviceActivityListener activityListener, in IVirtualDeviceSoundEffectListener soundEffectListener); }