From ce18bd7587fc7524c1a4aaf51032c3bae4d3d6ad Mon Sep 17 00:00:00 2001 From: DeviceInfra Date: Sat, 28 Feb 2026 03:49:53 -0800 Subject: [PATCH] Internal change PiperOrigin-RevId: 876640803 --- .../fe/v6/service/config/util/BUILD | 14 ++ .../config/util/ConfigServiceCapability.java | 148 ++++++++++++++ .../util/ConfigServiceCapabilityFactory.java | 23 +++ .../shared/util/flags/Flags.java | 8 + .../fe/v6/service/config/util/BUILD | 5 + .../util/ConfigServiceCapabilityTest.java | 183 ++++++++++++++++++ 6 files changed, 381 insertions(+) create mode 100644 src/java/com/google/devtools/mobileharness/fe/v6/service/config/util/ConfigServiceCapability.java create mode 100644 src/java/com/google/devtools/mobileharness/fe/v6/service/config/util/ConfigServiceCapabilityFactory.java create mode 100644 src/javatests/com/google/devtools/mobileharness/fe/v6/service/config/util/ConfigServiceCapabilityTest.java diff --git a/src/java/com/google/devtools/mobileharness/fe/v6/service/config/util/BUILD b/src/java/com/google/devtools/mobileharness/fe/v6/service/config/util/BUILD index 2848d77d0..ddcacfddc 100644 --- a/src/java/com/google/devtools/mobileharness/fe/v6/service/config/util/BUILD +++ b/src/java/com/google/devtools/mobileharness/fe/v6/service/config/util/BUILD @@ -33,3 +33,17 @@ java_library( "@maven//:com_google_protobuf_protobuf_java", ], ) + +java_library( + name = "config_service_capability", + srcs = [ + "ConfigServiceCapability.java", + "ConfigServiceCapabilityFactory.java", + ], + deps = [ + "//src/devtools/mobileharness/fe/v6/service/proto/config:config_resources_java_proto", + "//src/java/com/google/devtools/mobileharness/fe/v6/service/util", + "//src/java/com/google/devtools/mobileharness/shared/util/flags", + "@maven//:com_google_inject_extensions_guice_assistedinject", + ], +) diff --git a/src/java/com/google/devtools/mobileharness/fe/v6/service/config/util/ConfigServiceCapability.java b/src/java/com/google/devtools/mobileharness/fe/v6/service/config/util/ConfigServiceCapability.java new file mode 100644 index 000000000..9da140bbf --- /dev/null +++ b/src/java/com/google/devtools/mobileharness/fe/v6/service/config/util/ConfigServiceCapability.java @@ -0,0 +1,148 @@ +/* + * Copyright 2022 Google LLC + * + * 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 + * + * https://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 com.google.devtools.mobileharness.fe.v6.service.config.util; + +import com.google.devtools.mobileharness.fe.v6.service.proto.config.DeviceConfigUiStatus; +import com.google.devtools.mobileharness.fe.v6.service.proto.config.Editability; +import com.google.devtools.mobileharness.fe.v6.service.proto.config.HostConfigUiStatus; +import com.google.devtools.mobileharness.fe.v6.service.proto.config.HostDeviceConfigUiStatus; +import com.google.devtools.mobileharness.fe.v6.service.proto.config.HostPropertiesUiStatus; +import com.google.devtools.mobileharness.fe.v6.service.proto.config.PartStatus; +import com.google.devtools.mobileharness.fe.v6.service.util.Environment; +import com.google.devtools.mobileharness.shared.util.flags.Flags; +import com.google.inject.assistedinject.Assisted; +import com.google.inject.assistedinject.AssistedInject; + +/** + * Defines the capabilities and scope of the Config Service based on the current environment and + * target universe. + */ +public class ConfigServiceCapability { + + private final Environment environment; + private final String universe; + + @AssistedInject + ConfigServiceCapability(Environment environment, @Assisted String universe) { + this.environment = environment; + this.universe = universe; + } + + /** Returns true if the configuration service is available for the current context. */ + public boolean isConfigServiceAvailable() { + if (!Flags.instance().feConnectToConfigServer.get()) { + return false; + } + + if (environment.isGoogleInternal()) { + return universe.isEmpty() || universe.equals("google_1p"); + } + + // OSS/ATS only supports the default context (empty universe). + return universe.isEmpty(); + } + + /** + * Checks if the configuration service is available and throws an {@link + * UnsupportedOperationException} with an environment-aware message if not. + */ + public void checkConfigServiceAvailability() { + if (isConfigServiceAvailable()) { + return; + } + + if (!Flags.instance().feConnectToConfigServer.getNonNull()) { + throw new UnsupportedOperationException("Configuration service is currently disabled."); + } + + if (environment.isGoogleInternal()) { + throw new UnsupportedOperationException( + String.format( + "Configuration operations are not currently supported for universe '%s'.", universe)); + } + + throw new UnsupportedOperationException( + "Configuration operations are not currently supported."); + } + + /** Calculates UI status for host configuration components. */ + public HostConfigUiStatus calculateHostUiStatus() { + boolean isAts = environment.isAts(); + + return HostConfigUiStatus.newBuilder() + .setHostAdmins( + PartStatus.newBuilder() + .setVisible(!isAts) + .setEditability(Editability.newBuilder().setEditable(!isAts).build()) + .build()) + .setDeviceConfigMode( + PartStatus.newBuilder() + .setVisible(true) + .setEditability(Editability.newBuilder().setEditable(true).build()) + .build()) + .setDeviceConfig( + HostDeviceConfigUiStatus.newBuilder() + .setSectionStatus( + PartStatus.newBuilder() + .setVisible(true) + .setEditability(Editability.newBuilder().setEditable(true).build()) + .build()) + .setSubSections(calculateDeviceUiStatus()) + .build()) + .setHostProperties( + HostPropertiesUiStatus.newBuilder() + .setSectionStatus( + PartStatus.newBuilder() + .setVisible(!isAts) + .setEditability(Editability.newBuilder().setEditable(!isAts).build()) + .build()) + .build()) + .setDeviceDiscovery( + PartStatus.newBuilder() + .setVisible(!isAts) + .setEditability(Editability.newBuilder().setEditable(!isAts).build()) + .build()) + .build(); + } + + /** Calculates UI status for device configuration components. */ + public DeviceConfigUiStatus calculateDeviceUiStatus() { + boolean isAts = environment.isAts(); + return DeviceConfigUiStatus.newBuilder() + .setPermissions( + PartStatus.newBuilder() + .setVisible(!isAts) + .setEditability(Editability.newBuilder().setEditable(!isAts).build()) + .build()) + .setWifi( + PartStatus.newBuilder() + .setVisible(true) + .setEditability(Editability.newBuilder().setEditable(true).build()) + .build()) + .setDimensions( + PartStatus.newBuilder() + .setVisible(true) + .setEditability(Editability.newBuilder().setEditable(true).build()) + .build()) + .setSettings( + PartStatus.newBuilder() + .setVisible(!isAts) + .setEditability(Editability.newBuilder().setEditable(!isAts).build()) + .build()) + .build(); + } +} diff --git a/src/java/com/google/devtools/mobileharness/fe/v6/service/config/util/ConfigServiceCapabilityFactory.java b/src/java/com/google/devtools/mobileharness/fe/v6/service/config/util/ConfigServiceCapabilityFactory.java new file mode 100644 index 000000000..2f2a4cba5 --- /dev/null +++ b/src/java/com/google/devtools/mobileharness/fe/v6/service/config/util/ConfigServiceCapabilityFactory.java @@ -0,0 +1,23 @@ +/* + * Copyright 2022 Google LLC + * + * 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 + * + * https://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 com.google.devtools.mobileharness.fe.v6.service.config.util; + +/** Factory for creating {@link ConfigServiceCapability} instances. */ +public interface ConfigServiceCapabilityFactory { + + ConfigServiceCapability create(String universe); +} diff --git a/src/java/com/google/devtools/mobileharness/shared/util/flags/Flags.java b/src/java/com/google/devtools/mobileharness/shared/util/flags/Flags.java index 92c610790..190f6d5be 100644 --- a/src/java/com/google/devtools/mobileharness/shared/util/flags/Flags.java +++ b/src/java/com/google/devtools/mobileharness/shared/util/flags/Flags.java @@ -1457,6 +1457,14 @@ public enum ConfigServiceStorageType { converter = Flag.StringConverter.class) public Flag fastbootPathFromUser = fastbootPathFromUserDefault; + private static final Flag feConnectToConfigServerDefault = Flag.value(false); + + @com.beust.jcommander.Parameter( + names = "--fe_connect_to_config_server", + description = "Whether to connect to the config server in the FE server.", + converter = Flag.BooleanConverter.class) + public Flag feConnectToConfigServer = feConnectToConfigServerDefault; + private static final Flag feEnableDeviceFlashingDefault = Flag.value(false); @com.beust.jcommander.Parameter( diff --git a/src/javatests/com/google/devtools/mobileharness/fe/v6/service/config/util/BUILD b/src/javatests/com/google/devtools/mobileharness/fe/v6/service/config/util/BUILD index 99465728d..bf0823acc 100644 --- a/src/javatests/com/google/devtools/mobileharness/fe/v6/service/config/util/BUILD +++ b/src/javatests/com/google/devtools/mobileharness/fe/v6/service/config/util/BUILD @@ -25,6 +25,7 @@ java_library( testonly = 1, srcs = [ "ConfigConverterTest.java", + "ConfigServiceCapabilityTest.java", ], deps = [ "//src/devtools/mobileharness/api/deviceconfig/proto:basic_java_proto", @@ -34,10 +35,14 @@ java_library( "//src/devtools/mobileharness/fe/v6/service/proto/common:common_resources_java_proto", "//src/devtools/mobileharness/fe/v6/service/proto/config:config_resources_java_proto", "//src/java/com/google/devtools/mobileharness/fe/v6/service/config/util:config_converter", + "//src/java/com/google/devtools/mobileharness/fe/v6/service/config/util:config_service_capability", + "//src/java/com/google/devtools/mobileharness/fe/v6/service/util", "//src/javatests/com/google/devtools/mobileharness/builddefs:truth", + "//src/javatests/com/google/devtools/mobileharness/shared/util/junit/rule:set_flags_oss", "@maven//:com_google_guava_guava", "@maven//:com_google_protobuf_protobuf_java", "@maven//:junit_junit", + "@maven//:org_mockito_mockito_core", ], ) diff --git a/src/javatests/com/google/devtools/mobileharness/fe/v6/service/config/util/ConfigServiceCapabilityTest.java b/src/javatests/com/google/devtools/mobileharness/fe/v6/service/config/util/ConfigServiceCapabilityTest.java new file mode 100644 index 000000000..a5d0f641d --- /dev/null +++ b/src/javatests/com/google/devtools/mobileharness/fe/v6/service/config/util/ConfigServiceCapabilityTest.java @@ -0,0 +1,183 @@ +/* + * Copyright 2022 Google LLC + * + * 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 + * + * https://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 com.google.devtools.mobileharness.fe.v6.service.config.util; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; +import static org.mockito.Mockito.when; + +import com.google.common.collect.ImmutableMap; +import com.google.devtools.mobileharness.fe.v6.service.proto.config.DeviceConfigUiStatus; +import com.google.devtools.mobileharness.fe.v6.service.proto.config.HostConfigUiStatus; +import com.google.devtools.mobileharness.fe.v6.service.util.Environment; +import com.google.devtools.mobileharness.shared.util.junit.rule.SetFlagsOss; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +@RunWith(JUnit4.class) +public final class ConfigServiceCapabilityTest { + + @Rule public final MockitoRule mocks = MockitoJUnit.rule(); + @Rule public final SetFlagsOss flags = new SetFlagsOss(); + + @Mock private Environment environment; + + @Before + public void setUp() { + flags.setAllFlags(ImmutableMap.of("fe_connect_to_config_server", "true")); + } + + @Test + public void isConfigServiceAvailable_googleInternal_supported() { + when(environment.isGoogleInternal()).thenReturn(true); + + assertThat(new ConfigServiceCapability(environment, "google_1p").isConfigServiceAvailable()) + .isTrue(); + assertThat(new ConfigServiceCapability(environment, "").isConfigServiceAvailable()).isTrue(); + } + + @Test + public void isConfigServiceAvailable_googleInternal_unsupported() { + when(environment.isGoogleInternal()).thenReturn(true); + + assertThat(new ConfigServiceCapability(environment, "other").isConfigServiceAvailable()) + .isFalse(); + } + + @Test + public void isConfigServiceAvailable_notGoogleInternal_supported() { + when(environment.isGoogleInternal()).thenReturn(false); + + assertThat(new ConfigServiceCapability(environment, "").isConfigServiceAvailable()).isTrue(); + } + + @Test + public void isConfigServiceAvailable_notGoogleInternal_unsupported() { + when(environment.isGoogleInternal()).thenReturn(false); + + assertThat(new ConfigServiceCapability(environment, "other").isConfigServiceAvailable()) + .isFalse(); + } + + @Test + public void checkConfigServiceAvailability_googleInternal_unsupported() { + when(environment.isGoogleInternal()).thenReturn(true); + ConfigServiceCapability capability = + new ConfigServiceCapability(environment, "unsupported_env"); + + UnsupportedOperationException exception = + assertThrows( + UnsupportedOperationException.class, capability::checkConfigServiceAvailability); + + assertThat(exception) + .hasMessageThat() + .contains( + "Configuration operations are not currently supported for universe 'unsupported_env'"); + } + + @Test + public void checkConfigServiceAvailability_notGoogleInternal_unsupported() { + when(environment.isGoogleInternal()).thenReturn(false); + ConfigServiceCapability capability = + new ConfigServiceCapability(environment, "unsupported_env"); + + UnsupportedOperationException exception = + assertThrows( + UnsupportedOperationException.class, capability::checkConfigServiceAvailability); + + assertThat(exception) + .hasMessageThat() + .isEqualTo("Configuration operations are not currently supported."); + } + + @Test + public void checkConfigServiceAvailability_disabledByFlag() { + flags.setAllFlags(ImmutableMap.of("fe_connect_to_config_server", "false")); + ConfigServiceCapability capability = new ConfigServiceCapability(environment, ""); + + UnsupportedOperationException exception = + assertThrows( + UnsupportedOperationException.class, capability::checkConfigServiceAvailability); + + assertThat(exception) + .hasMessageThat() + .isEqualTo("Configuration service is currently disabled."); + } + + @Test + public void calculateHostUiStatus_ats() { + when(environment.isAts()).thenReturn(true); + ConfigServiceCapability capability = new ConfigServiceCapability(environment, ""); + + HostConfigUiStatus status = capability.calculateHostUiStatus(); + + assertThat(status.getHostAdmins().getVisible()).isFalse(); + assertThat(status.getDeviceConfigMode().getVisible()).isTrue(); + assertThat(status.getDeviceConfig().getSectionStatus().getVisible()).isTrue(); + assertThat(status.getHostProperties().getSectionStatus().getVisible()).isFalse(); + assertThat(status.getDeviceDiscovery().getVisible()).isFalse(); + } + + @Test + public void calculateHostUiStatus_notAts() { + when(environment.isAts()).thenReturn(false); + ConfigServiceCapability capability = new ConfigServiceCapability(environment, ""); + + HostConfigUiStatus status = capability.calculateHostUiStatus(); + + assertThat(status.getHostAdmins().getVisible()).isTrue(); + assertThat(status.getHostAdmins().getEditability().getEditable()).isTrue(); + assertThat(status.getDeviceConfigMode().getVisible()).isTrue(); + assertThat(status.getDeviceConfig().getSectionStatus().getVisible()).isTrue(); + assertThat(status.getHostProperties().getSectionStatus().getVisible()).isTrue(); + assertThat(status.getDeviceDiscovery().getVisible()).isTrue(); + } + + @Test + public void calculateDeviceUiStatus_ats() { + when(environment.isAts()).thenReturn(true); + ConfigServiceCapability capability = new ConfigServiceCapability(environment, ""); + + DeviceConfigUiStatus status = capability.calculateDeviceUiStatus(); + + assertThat(status.getPermissions().getVisible()).isFalse(); + assertThat(status.getWifi().getVisible()).isTrue(); + assertThat(status.getDimensions().getVisible()).isTrue(); + assertThat(status.getSettings().getVisible()).isFalse(); + } + + @Test + public void calculateDeviceUiStatus_notAts() { + when(environment.isAts()).thenReturn(false); + ConfigServiceCapability capability = new ConfigServiceCapability(environment, ""); + + DeviceConfigUiStatus status = capability.calculateDeviceUiStatus(); + + assertThat(status.getPermissions().getVisible()).isTrue(); + assertThat(status.getPermissions().getEditability().getEditable()).isTrue(); + assertThat(status.getWifi().getVisible()).isTrue(); + assertThat(status.getDimensions().getVisible()).isTrue(); + assertThat(status.getSettings().getVisible()).isTrue(); + assertThat(status.getSettings().getEditability().getEditable()).isTrue(); + } +}