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

Commit 81528b1d authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 12025384 from ba1079c8 to 24Q4-release

Change-Id: If762269d56eb189994966103522bbbf3a28ea897
parents 3a3b155c ba1079c8
Loading
Loading
Loading
Loading
+10 −84
Original line number Diff line number Diff line
@@ -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) " +
@@ -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.
@@ -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.
@@ -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) " +
@@ -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 {
@@ -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"],
+167 −95
Original line number Diff line number Diff line
@@ -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;
@@ -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
@@ -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;
@@ -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 + "]";
        }
    }

    /**
@@ -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.
@@ -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));
@@ -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) {
@@ -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);
@@ -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.
+16 −8
Original line number Diff line number Diff line
@@ -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);
        }
@@ -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);
+15 −2
Original line number Diff line number Diff line
@@ -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
+13 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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