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

Commit eccad0c4 authored by John Wu's avatar John Wu Committed by Android (Google) Code Review
Browse files

Merge "[Ravenwood] Remove runtime-helper-src" into main

parents 105c903d 4b664042
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@ filegroup {
    ],
    // Exactly one MessageQueue.java will be added to srcs by messagequeue-gen
    exclude_srcs: [
        "**/*_ravenwood.java",
        ":framework-ravenwood-sources",
        ":dropboxmanager_aidl_sources",
        ":dynamic_instrumentation_manager_aidl_sources",
        "android/os/*MessageQueue/**/*.java",
+1 −2
Original line number Diff line number Diff line
@@ -123,11 +123,10 @@ java_import {
java_library {
    name: "ravenwood-junit-impl",
    srcs: [
        ":framework-configinfrastructure-ravenwood-sources",
        ":framework-ravenwood-sources",
        "junit-impl-src/**/*.java",
        "junit-src/**/*.java",
        // TODO: Remove this directory once the sources are moved out
        "runtime-helper-src/framework/**/*.java",
    ],
    static_libs: [
        "ravenwood-androidx",
+6 −14
Original line number Diff line number Diff line
@@ -13,30 +13,22 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.platform.test.ravenwood.runtimehelper;
package android.platform.test.ravenwood;

/**
 * Standard class loader hook.
 */
public class ClassLoadHook {
    private ClassLoadHook() {
public class RavenwoodClassLoadHooks {
    private RavenwoodClassLoadHooks() {
    }

    /**
     * Called when classes with
     * {@code @HostSideTestClassLoadHook(
     * "com.android.hoststubgen.runtimehelper.LibandroidLoadingHook.onClassLoaded") }
     * are loaded.
     * Calls global initialization.
     */
    public static void onClassLoaded(Class<?> clazz) {
    public static void globalInitOnce(Class<?> clazz) {
        System.out.println("Framework class loaded: " + clazz.getCanonicalName());

        // Always try to initialize the environment in case classes are loaded before
        // RavenwoodAwareTestRunner is initialized
        try {
            Class.forName("android.platform.test.ravenwood.RavenwoodDriver")
                    .getMethod("globalInitOnce").invoke(null);
        } catch (ReflectiveOperationException ignored) {
        }
        RavenwoodDriver.globalInitOnce();
    }
}
+0 −33
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package android.provider;

public class DeviceConfig_ravenwood {

    /**
     * Called by Ravenwood runtime to reset all local changes.
     */
    public static void reset() {
        RavenwoodConfigDataStore.getInstance().clearAll();
    }

    /**
     * Called by {@link DeviceConfig#newDataStore()}
     */
    public static DeviceConfigDataStore newDataStore() {
        return RavenwoodConfigDataStore.getInstance();
    }
}
+0 −253
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package android.provider;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import android.provider.DeviceConfig.BadConfigException;
import android.provider.DeviceConfig.MonitorCallback;
import android.provider.DeviceConfig.Properties;

import com.android.internal.annotations.GuardedBy;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;

/**
 * {@link DeviceConfigDataStore} used only on Ravenwood.
 *
 * TODO(b/368591527) Support monitor callback related features
 * TODO(b/368591527) Support "default" related features
 */
final class RavenwoodConfigDataStore implements DeviceConfigDataStore {
    private static final RavenwoodConfigDataStore sInstance = new RavenwoodConfigDataStore();

    private final Object mLock = new Object();

    @GuardedBy("mLock")
    private int mSyncDisabledMode = DeviceConfig.SYNC_DISABLED_MODE_NONE;

    @GuardedBy("mLock")
    private final HashMap<String, HashMap<String, String>> mStore = new HashMap<>();

    private record ObserverInfo(String namespace, ContentObserver observer) {
    }

    @GuardedBy("mLock")
    private final ArrayList<ObserverInfo> mObservers = new ArrayList<>();

    static RavenwoodConfigDataStore getInstance() {
        return sInstance;
    }

    private static void shouldNotBeCalled() {
        throw new RuntimeException("shouldNotBeCalled");
    }

    void clearAll() {
        synchronized (mLock) {
            mSyncDisabledMode = DeviceConfig.SYNC_DISABLED_MODE_NONE;
            mStore.clear();
        }
    }

    @GuardedBy("mLock")
    private HashMap<String, String> getNamespaceLocked(@NonNull String namespace) {
        Objects.requireNonNull(namespace);
        return mStore.computeIfAbsent(namespace, k -> new HashMap<>());
    }

    /** {@inheritDoc} */
    @NonNull
    @Override
    public Map<String, String> getAllProperties() {
        synchronized (mLock) {
            var ret = new HashMap<String, String>();

            for (var namespaceAndMap : mStore.entrySet()) {
                for (var nameAndValue : namespaceAndMap.getValue().entrySet()) {
                    ret.put(namespaceAndMap.getKey() + "/" + nameAndValue.getKey(),
                            nameAndValue.getValue());
                }
            }
            return ret;
        }
    }

    /** {@inheritDoc} */
    @NonNull
    @Override
    public Properties getProperties(@NonNull String namespace, @NonNull String... names) {
        Objects.requireNonNull(namespace);

        synchronized (mLock) {
            var namespaceMap = getNamespaceLocked(namespace);

            if (names.length == 0) {
                return new Properties(namespace, Map.copyOf(namespaceMap));
            } else {
                var map = new HashMap<String, String>();
                for (var name : names) {
                    Objects.requireNonNull(name);
                    map.put(name, namespaceMap.get(name));
                }
                return new Properties(namespace, map);
            }
        }
    }

    /** {@inheritDoc} */
    @Override
    public boolean setProperties(@NonNull Properties properties) throws BadConfigException {
        Objects.requireNonNull(properties);

        synchronized (mLock) {
            var namespaceMap = getNamespaceLocked(properties.getNamespace());
            for (var kv : properties.getPropertyValues().entrySet()) {
                namespaceMap.put(
                        Objects.requireNonNull(kv.getKey()),
                        Objects.requireNonNull(kv.getValue())
                );
            }
            notifyObserversLock(properties.getNamespace(),
                    properties.getKeyset().toArray(new String[0]));
        }
        return true;
    }

    /** {@inheritDoc} */
    @Override
    public boolean setProperty(@NonNull String namespace, @NonNull String name,
            @Nullable String value, boolean makeDefault) {
        Objects.requireNonNull(namespace);
        Objects.requireNonNull(name);

        synchronized (mLock) {
            var namespaceMap = getNamespaceLocked(namespace);
            namespaceMap.put(name, value);

            // makeDefault not supported.
            notifyObserversLock(namespace, new String[]{name});
        }
        return true;
    }

    /** {@inheritDoc} */
    @Override
    public boolean deleteProperty(@NonNull String namespace, @NonNull String name) {
        Objects.requireNonNull(namespace);
        Objects.requireNonNull(name);

        synchronized (mLock) {
            var namespaceMap = getNamespaceLocked(namespace);
            if (namespaceMap.remove(name) != null) {
                notifyObserversLock(namespace, new String[]{name});
            }
        }
        return true;
    }

    /** {@inheritDoc} */
    @Override
    public void resetToDefaults(int resetMode, @Nullable String namespace) {
        // not supported in DeviceConfig.java
        shouldNotBeCalled();
    }

    /** {@inheritDoc} */
    @Override
    public void setSyncDisabledMode(int syncDisabledMode) {
        synchronized (mLock) {
            mSyncDisabledMode = syncDisabledMode;
        }
    }

    /** {@inheritDoc} */
    @Override
    public int getSyncDisabledMode() {
        synchronized (mLock) {
            return mSyncDisabledMode;
        }
    }

    /** {@inheritDoc} */
    @Override
    public void setMonitorCallback(@NonNull ContentResolver resolver, @NonNull Executor executor,
            @NonNull MonitorCallback callback) {
        // not supported in DeviceConfig.java
        shouldNotBeCalled();
    }

    /** {@inheritDoc} */
    @Override
    public void clearMonitorCallback(@NonNull ContentResolver resolver) {
        // not supported in DeviceConfig.java
        shouldNotBeCalled();
    }

    /** {@inheritDoc} */
    @Override
    public void registerContentObserver(@NonNull String namespace, boolean notifyForescendants,
            ContentObserver contentObserver) {
        synchronized (mLock) {
            mObservers.add(new ObserverInfo(
                    Objects.requireNonNull(namespace),
                    Objects.requireNonNull(contentObserver)
            ));
        }
    }

    /** {@inheritDoc} */
    @Override
    public void unregisterContentObserver(@NonNull ContentObserver contentObserver) {
        synchronized (mLock) {
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                if (mObservers.get(i).observer == contentObserver) {
                    mObservers.remove(i);
                }
            }
        }
    }

    private static final Uri CONTENT_URI = Uri.parse("content://settings/config");

    @GuardedBy("mLock")
    private void notifyObserversLock(@NonNull String namespace, String[] keys) {
        var urib = CONTENT_URI.buildUpon().appendPath(namespace);
        for (var key : keys) {
            urib.appendEncodedPath(key);
        }
        var uri = urib.build();

        final var copy = List.copyOf(mObservers);
        new Handler(Looper.getMainLooper()).post(() -> {
            for (int i = copy.size() - 1; i >= 0; i--) {
                if (copy.get(i).namespace.equals(namespace)) {
                    copy.get(i).observer.dispatchChange(false, uri);
                }
            }
        });
    }
}