Add satellite ConfigDataGenerator tool
This tool generates a binary file of TelephonyConfigProto
Bug: 348112315
Bug: 342287366
Flag: EXEMPT adding a new host-based tool
Test: check generated telephony_config.pb
Change-Id: I14869dec7f64ab1b71156ddf757420c7031c1360
diff --git a/utils/satellite/README.md b/utils/satellite/README.md
index 77ee0fb..34a8794 100644
--- a/utils/satellite/README.md
+++ b/utils/satellite/README.md
@@ -15,11 +15,15 @@
for dumping the binary file into human-readable format.
- `src/test` Contains the test code for the tools.
+`configdatagenerator`
+- `src/main` Contains the tool for generating satellite configdata protobuf file.
+- `src/test` Contains the test code for the configdatagenerator tool.
+
Run unit tests
=
- Build the tools and test code: Go to the tool directory (`packages/services/Telephony/tools/
satellite`) in the local workspace and run `mm`, e.g.,
-- Run unit tests: `$atest SatelliteToolsTests`
+- Run unit tests: `$atest SatelliteToolsTests`, `$atest SatelliteGenerateProtoTests`
Data file generate tools
=
@@ -43,6 +47,55 @@
- Example run command: `$satellite_createsats2file --input-file s2cells.txt --s2-level 12
--is-allowed-list true --output-file sats2.dat`
+`satellite_generateprotobuf`
+- Runs the `satellite_generateprotobuf` to create a binary file of TelephonyConfigProto whose format
+ is defined in telephony_config_update.proto
+- Command: `satellite_generateprotobuf --input-file <input.xml> --output-file <telephony_config.pb>`
+ - `--input-file` input XML file contains input information such as carrier id, carrier plmn,
+ allowed service list and country code list. This is example of input file.
+ ```xml
+ <satelliteconfig>
+ <!-- version -->
+ <version>14</version>
+
+ <!-- CarrierSupportedSatelliteServicesProto -->
+ <carriersupportedservices>
+ <carrier_id>1</carrier_id>
+ <providercapability>
+ <carrier_plmn>310160</carrier_plmn>
+ <service>1</service>
+ </providercapability>
+ <providercapability>
+ <carrier_plmn>310240</carrier_plmn>
+ <service>6</service>
+ </providercapability>
+ </carriersupportedservices>
+
+ <carriersupportedservices>
+ <carrier_id>1891</carrier_id>
+ <providercapability>
+ <carrier_plmn>45005</carrier_plmn>
+ <service>1</service>
+ <service>2</service>
+ </providercapability>
+ </carriersupportedservices>
+
+ <!-- SatelliteRegionProto -->
+ <satelliteregion>
+ <s2_cell_file>sats2.dat</s2_cell_file>
+ <country_code>US</country_code>
+ <country_code>KR</country_code>
+ <is_allowed>TRUE</is_allowed>
+ </satelliteregion>
+ </satelliteconfig>
+ ```
+ - `--output-file` The created binary TelephonyConfigProto file, which will be used by
+ the `ConfigUpdater` module for Satellite Project.
+- Build the tools: Go to the tool directory (`packages/services/Telephony/tools/satellite`)
+ in the local workspace and run `mm`.
+- Example run command: `satellite_generateprotobuf --input-file input.xml --output-file
+ telephony_config.pb`
+
Debug tools
=
@@ -64,4 +117,4 @@
`satellite_location_lookup`
- Check if a location is present in the input satellite S2 file.
- Run the tool: `$satellite_location_lookup --input-file <...> --lat-degrees <...>
- --lng-degrees <...>`
\ No newline at end of file
+ --lng-degrees <...>`
diff --git a/utils/satellite/configdatagenerator/Android.bp b/utils/satellite/configdatagenerator/Android.bp
new file mode 100644
index 0000000..b64b941
--- /dev/null
+++ b/utils/satellite/configdatagenerator/Android.bp
@@ -0,0 +1,49 @@
+// 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 {
+ default_team: "trendy_team_fwk_telephony",
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_library_host {
+ name: "satellite-generateproto-lib",
+ srcs: [
+ "src/main/java/**/*.java",
+ ],
+ static_libs: [
+ "telephony-config-update-proto-lite",
+ "jcommander",
+ ],
+}
+
+// A tool to generate configdata protubuf file
+java_binary_host {
+ name: "satellite_generateprotobuf",
+ main_class: "com.android.telephony.tools.configdatagenerate.ConfigDataGenerator",
+ static_libs: [
+ "satellite-generateproto-lib",
+ ],
+}
+
+// Tests for ConfigDataGenerator.
+java_test_host {
+ name: "SatelliteGenerateProtoTests",
+ srcs: ["src/test/java/**/*.java"],
+ static_libs: [
+ "junit",
+ "satellite-generateproto-lib",
+ ],
+ test_suites: ["general-tests"],
+}
diff --git a/utils/satellite/configdatagenerator/TEST_MAPPING b/utils/satellite/configdatagenerator/TEST_MAPPING
new file mode 100644
index 0000000..13a3e13
--- /dev/null
+++ b/utils/satellite/configdatagenerator/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "postsubmit": [
+ {
+ "name": "SatelliteGenerateProtoTests"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/utils/satellite/configdatagenerator/src/main/java/com/android/telephony/tools/configdatagenerate/ConfigDataGenerator.java b/utils/satellite/configdatagenerator/src/main/java/com/android/telephony/tools/configdatagenerate/ConfigDataGenerator.java
new file mode 100644
index 0000000..7e29e9a
--- /dev/null
+++ b/utils/satellite/configdatagenerator/src/main/java/com/android/telephony/tools/configdatagenerate/ConfigDataGenerator.java
@@ -0,0 +1,233 @@
+/*
+ * 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 com.android.telephony.tools.configdatagenerate;
+
+import com.beust.jcommander.JCommander;
+import com.beust.jcommander.Parameter;
+import com.beust.jcommander.ParameterException;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+/** Creates a protubuf file **/
+public class ConfigDataGenerator {
+ public static final String TAG_SATELLITE_CONFIG = "satelliteconfig";
+ public static final String TAG_VERSION = "version";
+ public static final String TAG_SUPPORTED_SERVICES = "carriersupportedservices";
+ public static final String TAG_CARRIER_ID = "carrier_id";
+ public static final String TAG_PROVIDER_CAPABILITY = "providercapability";
+ public static final String TAG_CARRIER_PLMN = "carrier_plmn";
+ public static final String TAG_SERVICE = "service";
+ public static final String TAG_SATELLITE_REGION = "satelliteregion";
+ public static final String TAG_S2_CELL_FILE = "s2_cell_file";
+ public static final String TAG_COUNTRY_CODE = "country_code";
+ public static final String TAG_IS_ALLOWED = "is_allowed";
+
+ /**
+ * Creates a protubuf file with user inputs
+ */
+ public static void main(String[] args) {
+ Arguments arguments = new Arguments();
+ JCommander.newBuilder()
+ .addObject(arguments)
+ .build()
+ .parse(args);
+ // Refer to the README file for an example of the input XML file
+ String inputFile = arguments.inputFile;
+ String outputFile = arguments.outputFile;
+ SatelliteConfigProtoGenerator.sProtoResultFile = outputFile;
+
+ Document doc = getDocumentFromInput(inputFile);
+
+ setSatelliteConfigVersion(doc);
+ createStarlinkConfigProto(doc);
+ createSkyloConfigProto(doc);
+
+ SatelliteConfigProtoGenerator.generateProto();
+
+ System.out.print("\n" + SatelliteConfigProtoGenerator.sProtoResultFile + " is generated\n");
+ }
+
+ private static class Arguments {
+ @Parameter(names = "--input-file",
+ description = "input xml file",
+ required = true)
+ public String inputFile;
+
+ @Parameter(names = "--output-file",
+ description = "out protobuf file",
+ required = false)
+ public String outputFile = SatelliteConfigProtoGenerator.sProtoResultFile;
+ }
+
+ private static Document getDocumentFromInput(String inputFile) {
+ File xmlFile = new File(inputFile);
+ DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder dBuilder = null;
+ Document doc = null;
+ try {
+ dBuilder = dbFactory.newDocumentBuilder();
+ doc = dBuilder.parse(xmlFile);
+ } catch (ParserConfigurationException | SAXException | IOException e) {
+ throw new RuntimeException("getDocumentFromInput: e=" + e);
+ }
+ doc.getDocumentElement().normalize();
+ return doc;
+ }
+
+ /**
+ * Set version after getting version from the input document
+ *
+ * @param doc the input document. Format of document should be
+ * <pre>
+ * <version>value1</version>
+ * </pre>
+ */
+ public static void setSatelliteConfigVersion(Document doc) {
+ NodeList versionList = doc.getElementsByTagName(TAG_VERSION);
+ Node versionNode = versionList.item(0);
+ System.out.println("Version: " + versionNode.getTextContent());
+ SatelliteConfigProtoGenerator.sVersion = Integer.parseInt(versionNode.getTextContent());
+ }
+
+
+ /**
+ * Creates a list of ServiceProto from the input document
+ *
+ * @param doc the input document. Format of document should be
+ * <pre>
+ * <carriersupportedservices>
+ * <carrier_id>value1</carrier_id>
+ * <providercapability>
+ * <carrier_plmn>value2</carrier_plmn>
+ * <service>value3</service>
+ * </providercapability>
+ * </carriersupportedservices>
+ * </pre>
+ */
+ public static void createStarlinkConfigProto(Document doc) {
+ NodeList carrierServicesList = doc.getElementsByTagName(TAG_SUPPORTED_SERVICES);
+ SatelliteConfigProtoGenerator.sServiceProtoList = new ArrayList<>();
+ for (int i = 0; i < carrierServicesList.getLength(); i++) {
+ Node carrierServiceNode = carrierServicesList.item(i);
+ if (carrierServiceNode.getNodeType() == Node.ELEMENT_NODE) {
+ Element carrierServiceElement = (Element) carrierServiceNode;
+ String carrierId = carrierServiceElement.getElementsByTagName(TAG_CARRIER_ID)
+ .item(0).getTextContent();
+ System.out.println("\nCarrier ID: " + carrierId);
+
+ NodeList providerCapabilityList = carrierServiceElement.getElementsByTagName(
+ TAG_PROVIDER_CAPABILITY);
+ ProviderCapabilityProto[] capabilityProtoList =
+ new ProviderCapabilityProto[providerCapabilityList.getLength()];
+ for (int j = 0; j < providerCapabilityList.getLength(); j++) {
+ Node providerCapabilityNode = providerCapabilityList.item(j);
+ if (providerCapabilityNode.getNodeType() == Node.ELEMENT_NODE) {
+ Element providerCapabilityElement = (Element) providerCapabilityNode;
+ String carrierPlmn = providerCapabilityElement.getElementsByTagName(
+ TAG_CARRIER_PLMN).item(0).getTextContent();
+ System.out.println(" Carrier PLMN: " + carrierPlmn);
+ if (!Util.isValidPlmn(carrierPlmn)) {
+ throw new ParameterException("Invalid plmn:" + carrierPlmn);
+ }
+
+ NodeList allowedServicesList = providerCapabilityElement
+ .getElementsByTagName(TAG_SERVICE);
+ System.out.print(" Allowed services: ");
+ int[] allowedServiceArray = new int[allowedServicesList.getLength()];
+ for (int k = 0; k < allowedServicesList.getLength(); k++) {
+ int service = Integer.parseInt(allowedServicesList.item(k)
+ .getTextContent());
+ System.out.print(service + " ");
+ if (!Util.isValidService(service)) {
+ throw new ParameterException("Invalid service:" + service);
+ }
+ allowedServiceArray[k] = service;
+ }
+ System.out.println();
+ ProviderCapabilityProto capabilityProto =
+ new ProviderCapabilityProto(carrierPlmn, allowedServiceArray);
+ capabilityProtoList[j] = capabilityProto;
+ }
+ }
+ ServiceProto serviceProto = new ServiceProto(Integer.parseInt(carrierId),
+ capabilityProtoList);
+ SatelliteConfigProtoGenerator.sServiceProtoList.add(serviceProto);
+ }
+ }
+ }
+
+ /**
+ * Creates a RegionProto from the input document
+ *
+ * @param doc the input document. Format of document should be
+ * <pre>
+ * <satelliteregion>
+ * <s2_cell_file>value1</s2_cell_file>
+ * <country_code>value2</country_code>
+ * <country_code>value3</country_code>
+ * <is_allowed>value4</is_allowed>
+ * </satelliteregion>
+ * </pre>
+ */
+ public static void createSkyloConfigProto(Document doc) {
+ NodeList satelliteRegionList = doc.getElementsByTagName(TAG_SATELLITE_REGION);
+ Node satelliteRegionNode = satelliteRegionList.item(0);
+ if (satelliteRegionNode != null && satelliteRegionNode.getNodeType() == Node.ELEMENT_NODE) {
+ Element satelliteRegionElement = (Element) satelliteRegionNode;
+ String s2CellFileName = satelliteRegionElement.getElementsByTagName(TAG_S2_CELL_FILE)
+ .item(0).getTextContent();
+ String isAllowedString = satelliteRegionElement.getElementsByTagName(TAG_IS_ALLOWED)
+ .item(0).getTextContent();
+ boolean isAllowed = false;
+ if (isAllowedString.equals("TRUE")) {
+ isAllowed = true;
+ }
+ System.out.println("\nSatellite Region:");
+ System.out.println(" S2 Cell File: " + s2CellFileName);
+ System.out.println(" Is Allowed: " + isAllowed);
+
+ NodeList countryCodesList = satelliteRegionElement.getElementsByTagName(
+ TAG_COUNTRY_CODE);
+ String[] listCountryCode = new String[countryCodesList.getLength()];
+ System.out.print(" Country Codes: ");
+ for (int k = 0; k < countryCodesList.getLength(); k++) {
+ String countryCode = countryCodesList.item(k).getTextContent();
+ System.out.print(countryCode + " ");
+ if (!Util.isValidCountryCode(countryCode)) {
+ throw new ParameterException("Invalid countryCode:" + countryCode);
+ }
+ listCountryCode[k] = countryCode;
+ }
+ System.out.println();
+ SatelliteConfigProtoGenerator.sRegionProto =
+ new RegionProto(s2CellFileName, listCountryCode, isAllowed);
+ }
+ }
+}
+
diff --git a/utils/satellite/configdatagenerator/src/main/java/com/android/telephony/tools/configdatagenerate/ProviderCapabilityProto.java b/utils/satellite/configdatagenerator/src/main/java/com/android/telephony/tools/configdatagenerate/ProviderCapabilityProto.java
new file mode 100644
index 0000000..9fe692d
--- /dev/null
+++ b/utils/satellite/configdatagenerator/src/main/java/com/android/telephony/tools/configdatagenerate/ProviderCapabilityProto.java
@@ -0,0 +1,28 @@
+/*
+ * 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 com.android.telephony.tools.configdatagenerate;
+
+public class ProviderCapabilityProto {
+
+ public String mPlmn;
+ public int[] mAllowedServices;
+
+ public ProviderCapabilityProto(String plmn, int[] allowedServices) {
+ mPlmn = plmn;
+ mAllowedServices = allowedServices;
+ }
+}
diff --git a/utils/satellite/configdatagenerator/src/main/java/com/android/telephony/tools/configdatagenerate/RegionProto.java b/utils/satellite/configdatagenerator/src/main/java/com/android/telephony/tools/configdatagenerate/RegionProto.java
new file mode 100644
index 0000000..be3b0cc
--- /dev/null
+++ b/utils/satellite/configdatagenerator/src/main/java/com/android/telephony/tools/configdatagenerate/RegionProto.java
@@ -0,0 +1,30 @@
+/*
+ * 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 com.android.telephony.tools.configdatagenerate;
+
+public class RegionProto {
+
+ String mS2CellFileName;
+ String[] mCountryCodeList;
+ boolean mIsAllowed;
+
+ public RegionProto(String s2CellFileName, String[] countryCodeList, boolean isAllowed) {
+ mS2CellFileName = s2CellFileName;
+ mCountryCodeList = countryCodeList;
+ mIsAllowed = isAllowed;
+ }
+}
diff --git a/utils/satellite/configdatagenerator/src/main/java/com/android/telephony/tools/configdatagenerate/SatelliteConfigProtoGenerator.java b/utils/satellite/configdatagenerator/src/main/java/com/android/telephony/tools/configdatagenerate/SatelliteConfigProtoGenerator.java
new file mode 100644
index 0000000..740e2ea
--- /dev/null
+++ b/utils/satellite/configdatagenerator/src/main/java/com/android/telephony/tools/configdatagenerate/SatelliteConfigProtoGenerator.java
@@ -0,0 +1,155 @@
+/*
+ * 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 com.android.telephony.tools.configdatagenerate;
+
+import com.android.internal.telephony.satellite.SatelliteConfigData;
+
+import com.google.protobuf.ByteString;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+
+public class SatelliteConfigProtoGenerator {
+
+ private static final String TAG = "ProtoGenerator";
+ public static String sProtoResultFile = "telephony_config.pb";
+ public static int sVersion;
+ public static ArrayList<ServiceProto> sServiceProtoList;
+ public static RegionProto sRegionProto;
+
+ /**
+ * Generate Protobuf.
+ *
+ * The output file is a binary file of TelephonyConfigProto.
+ *
+ * The format of TelephonyConfigProto is defined in
+ * https://source.corp.google.com/android/frameworks/opt/telephony/proto/src/
+ * telephony_config_update.proto
+ */
+ public static void generateProto() {
+ SatelliteConfigData.TelephonyConfigProto.Builder telephonyConfigBuilder =
+ SatelliteConfigData.TelephonyConfigProto.newBuilder();
+ SatelliteConfigData.SatelliteConfigProto.Builder satelliteConfigBuilder =
+ SatelliteConfigData.SatelliteConfigProto.newBuilder();
+
+ satelliteConfigBuilder.setVersion(sVersion); // Input version
+
+ if (sServiceProtoList != null) {
+ // carrierSupportedSatelliteServiceBuilder
+ SatelliteConfigData.CarrierSupportedSatelliteServicesProto.Builder
+ carrierSupportedSatelliteServiceBuilder =
+ SatelliteConfigData.CarrierSupportedSatelliteServicesProto.newBuilder();
+ for (int i = 0; i < sServiceProtoList.size(); i++) {
+ ServiceProto proto = sServiceProtoList.get(i);
+ carrierSupportedSatelliteServiceBuilder.setCarrierId(proto.mCarrierId);
+ SatelliteConfigData.SatelliteProviderCapabilityProto.Builder
+ satelliteProviderCapabilityBuilder =
+ SatelliteConfigData.SatelliteProviderCapabilityProto.newBuilder();
+ ProviderCapabilityProto[] capabilityProtoList = proto.mCapabilityProtoList;
+ for (int j = 0; j < capabilityProtoList.length; j++) {
+ ProviderCapabilityProto capabilityProto = capabilityProtoList[j];
+ satelliteProviderCapabilityBuilder.setCarrierPlmn(capabilityProto.mPlmn);
+ int[] allowedServiceList = capabilityProto.mAllowedServices;
+ for (int k = 0; k < allowedServiceList.length; k++) {
+ satelliteProviderCapabilityBuilder
+ .addAllowedServices(allowedServiceList[k]);
+ }
+ carrierSupportedSatelliteServiceBuilder
+ .addSupportedSatelliteProviderCapabilities(
+ satelliteProviderCapabilityBuilder);
+ satelliteProviderCapabilityBuilder.clear();
+ }
+ satelliteConfigBuilder.addCarrierSupportedSatelliteServices(
+ carrierSupportedSatelliteServiceBuilder);
+ carrierSupportedSatelliteServiceBuilder.clear();
+ }
+ } else {
+ System.out.print("ServiceProtoList does not exist");
+ }
+
+ if (sRegionProto != null) {
+ // satelliteRegionBuilder
+ SatelliteConfigData.SatelliteRegionProto.Builder satelliteRegionBuilder =
+ SatelliteConfigData.SatelliteRegionProto.newBuilder();
+ byte[] binaryData;
+ try {
+ binaryData = readFileToByteArray(sRegionProto.mS2CellFileName);
+ } catch (IOException e) {
+ throw new RuntimeException("Got exception in reading the file "
+ + sRegionProto.mS2CellFileName + ", e=" + e);
+ }
+ if (binaryData != null) {
+ satelliteRegionBuilder.setS2CellFile(ByteString.copyFrom(binaryData));
+ }
+
+ String[] countryCodeList = sRegionProto.mCountryCodeList;
+ for (int i = 0; i < countryCodeList.length; i++) {
+ satelliteRegionBuilder.addCountryCodes(countryCodeList[i]);
+ }
+ satelliteRegionBuilder.setIsAllowed(sRegionProto.mIsAllowed);
+ satelliteConfigBuilder.setDeviceSatelliteRegion(satelliteRegionBuilder);
+ } else {
+ System.out.print("RegionProto does not exist");
+ }
+
+ telephonyConfigBuilder.setSatellite(satelliteConfigBuilder);
+
+ writeToResultFile(telephonyConfigBuilder);
+ }
+
+ private static void writeToResultFile(SatelliteConfigData
+ .TelephonyConfigProto.Builder telephonyConfigBuilder) {
+ try {
+ File file = new File(sProtoResultFile);
+ if (file.exists()) {
+ file.delete();
+ }
+ FileOutputStream fos = new FileOutputStream(file);
+ SatelliteConfigData.TelephonyConfigProto telephonyConfigData =
+ telephonyConfigBuilder.build();
+ telephonyConfigData.writeTo(fos);
+
+ fos.close();
+ } catch (Exception e) {
+ throw new RuntimeException("Got exception in writing the file "
+ + sProtoResultFile + ", e=" + e);
+ }
+ }
+
+ private static byte[] readFileToByteArray(String fileName) throws IOException {
+ File sat2File = new File(fileName);
+ if (!sat2File.exists()) {
+ throw new IOException("sat2File " + fileName + " does not exist");
+ }
+
+ if (sat2File.exists() && sat2File.canRead()) {
+ FileInputStream fileInputStream = new FileInputStream(sat2File);
+ long fileSize = fileInputStream.available();
+ byte[] bytes = new byte[(int) fileSize];
+ int bytesRead = fileInputStream.read(bytes);
+ fileInputStream.close();
+ if (bytesRead != fileSize) {
+ throw new IOException("file read fail: " + sat2File.getCanonicalPath());
+ }
+ return bytes;
+ }
+ return null;
+ }
+}
diff --git a/utils/satellite/configdatagenerator/src/main/java/com/android/telephony/tools/configdatagenerate/ServiceProto.java b/utils/satellite/configdatagenerator/src/main/java/com/android/telephony/tools/configdatagenerate/ServiceProto.java
new file mode 100644
index 0000000..a17e1dd
--- /dev/null
+++ b/utils/satellite/configdatagenerator/src/main/java/com/android/telephony/tools/configdatagenerate/ServiceProto.java
@@ -0,0 +1,28 @@
+/*
+ * 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 com.android.telephony.tools.configdatagenerate;
+
+public class ServiceProto {
+
+ public int mCarrierId;
+ public ProviderCapabilityProto[] mCapabilityProtoList;
+
+ public ServiceProto(int carrierId, ProviderCapabilityProto[] capabilityProtolist) {
+ mCarrierId = carrierId;
+ mCapabilityProtoList = capabilityProtolist;
+ }
+}
diff --git a/utils/satellite/configdatagenerator/src/main/java/com/android/telephony/tools/configdatagenerate/Util.java b/utils/satellite/configdatagenerator/src/main/java/com/android/telephony/tools/configdatagenerate/Util.java
new file mode 100644
index 0000000..925e828
--- /dev/null
+++ b/utils/satellite/configdatagenerator/src/main/java/com/android/telephony/tools/configdatagenerate/Util.java
@@ -0,0 +1,68 @@
+/*
+ * 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 com.android.telephony.tools.configdatagenerate;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class Util {
+
+ public static final int SERVICE_TYPE_VOICE = 1;
+ public static final int SERVICE_TYPE_MMS = 6;
+
+ private static final int FIRST_SERVICE_TYPE = SERVICE_TYPE_VOICE;
+ private static final int LAST_SERVICE_TYPE = SERVICE_TYPE_MMS;
+
+ private static boolean isValidPattern(String input, String regex) {
+ if ((input == null) || (regex == null)) {
+ return false;
+ }
+ Pattern pattern = Pattern.compile(regex);
+ Matcher matcher = pattern.matcher(input);
+ if (!matcher.matches()) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @param countryCode two letters country code based on the ISO 3166-1.
+ * @return {@code true} if the countryCode is valid {@code false} otherwise.
+ */
+ public static boolean isValidCountryCode(String countryCode) {
+ return isValidPattern(countryCode, "^[A-Za-z]{2}$");
+ }
+
+ /**
+ * @param plmn target plmn for validation.
+ * @return {@code true} if the target plmn is valid {@code false} otherwise.
+ */
+ public static boolean isValidPlmn(String plmn) {
+ return isValidPattern(plmn, "^(?:[0-9]{3})(?:[0-9]{2}|[0-9]{3})$");
+ }
+
+ /**
+ * @param serviceType target serviceType for validation.
+ * @return {@code true} if the target serviceType is valid {@code false} otherwise.
+ */
+ public static boolean isValidService(int serviceType) {
+ if (serviceType < FIRST_SERVICE_TYPE || serviceType > LAST_SERVICE_TYPE) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/utils/satellite/configdatagenerator/src/test/java/com/android/telephony/tools/configdatagenerate/ConfigDataGeneratorTest.java b/utils/satellite/configdatagenerator/src/test/java/com/android/telephony/tools/configdatagenerate/ConfigDataGeneratorTest.java
new file mode 100644
index 0000000..f588815
--- /dev/null
+++ b/utils/satellite/configdatagenerator/src/test/java/com/android/telephony/tools/configdatagenerate/ConfigDataGeneratorTest.java
@@ -0,0 +1,324 @@
+/*
+ * 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 com.android.telephony.tools.configdatagenerate;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+
+import com.android.internal.telephony.satellite.SatelliteConfigData.CarrierSupportedSatelliteServicesProto;
+import com.android.internal.telephony.satellite.SatelliteConfigData.SatelliteConfigProto;
+import com.android.internal.telephony.satellite.SatelliteConfigData.SatelliteProviderCapabilityProto;
+import com.android.internal.telephony.satellite.SatelliteConfigData.SatelliteRegionProto;
+import com.android.internal.telephony.satellite.SatelliteConfigData.TelephonyConfigProto;
+
+import com.google.protobuf.ByteString;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+public class ConfigDataGeneratorTest {
+ private Path mTempDirPath;
+
+ @Before
+ public void setUp() throws IOException {
+ mTempDirPath = createTempDir(this.getClass());
+ }
+
+ @After
+ public void tearDown() throws IOException {
+ if (mTempDirPath != null) {
+ deleteDirectory(mTempDirPath);
+ }
+ }
+
+ @Test
+ public void testConfigDataGeneratorWithInvalidPlmn() throws Exception {
+ Path inputDirPath = mTempDirPath.resolve("input");
+ Files.createDirectory(inputDirPath);
+ Path inputFilePath = inputDirPath.resolve("test_input.xml");
+ Path inputS2CellFilePath = inputDirPath.resolve("sats2.dat");
+
+ Path outputDirPath = mTempDirPath.resolve("output");
+ Files.createDirectory(outputDirPath);
+ Path outputFilePath = outputDirPath.resolve("test_out.pb");
+ String inputfileName = inputFilePath.toAbsolutePath().toString();
+ String inputS2CellFileName = inputS2CellFilePath.toAbsolutePath().toString();
+ File inputFile = new File(inputfileName);
+ ByteString inputByteStringForS2Cell = ByteString.copyFromUtf8("Test ByteString!");
+ writeByteStringToFile(inputS2CellFileName, inputByteStringForS2Cell);
+
+ createInputXml(inputFile, 14, 1, "310062222", 1,
+ "US", true, inputS2CellFileName);
+ String[] args = {
+ "--input-file", inputFilePath.toAbsolutePath().toString(),
+ "--output-file", outputFilePath.toAbsolutePath().toString()
+ };
+ try {
+ ConfigDataGenerator.main(args);
+ } catch (Exception ex) {
+ // Expected exception because input plmn is invalid
+ return;
+ }
+ fail("Exception should have been caught");
+ }
+
+ @Test
+ public void testConfigDataGeneratorWithInvalidService() throws Exception {
+ Path inputDirPath = mTempDirPath.resolve("input");
+ Files.createDirectory(inputDirPath);
+ Path inputFilePath = inputDirPath.resolve("test_input.xml");
+ Path inputS2CellFilePath = inputDirPath.resolve("sats2.dat");
+
+ Path outputDirPath = mTempDirPath.resolve("output");
+ Files.createDirectory(outputDirPath);
+ Path outputFilePath = outputDirPath.resolve("test_out.pb");
+ String inputfileName = inputFilePath.toAbsolutePath().toString();
+ String inputS2CellFileName = inputS2CellFilePath.toAbsolutePath().toString();
+ File inputFile = new File(inputfileName);
+ ByteString inputByteStringForS2Cell = ByteString.copyFromUtf8("Test ByteString!");
+ writeByteStringToFile(inputS2CellFileName, inputByteStringForS2Cell);
+
+ createInputXml(inputFile, 14, 1, "31006", -1,
+ "US", true, inputS2CellFileName);
+ String[] args = {
+ "--input-file", inputFilePath.toAbsolutePath().toString(),
+ "--output-file", outputFilePath.toAbsolutePath().toString()
+ };
+ try {
+ ConfigDataGenerator.main(args);
+ } catch (Exception ex) {
+ // Expected exception because input allowed service is invalid
+ return;
+ }
+ fail("Exception should have been caught");
+ }
+
+ @Test
+ public void testConfigDataGeneratorWithInvalidCountryCode() throws Exception {
+ Path inputDirPath = mTempDirPath.resolve("input");
+ Files.createDirectory(inputDirPath);
+ Path inputFilePath = inputDirPath.resolve("test_input.xml");
+ Path inputS2CellFilePath = inputDirPath.resolve("sats2.dat");
+
+ Path outputDirPath = mTempDirPath.resolve("output");
+ Files.createDirectory(outputDirPath);
+ Path outputFilePath = outputDirPath.resolve("test_out.pb");
+ String inputfileName = inputFilePath.toAbsolutePath().toString();
+ String inputS2CellFileName = inputS2CellFilePath.toAbsolutePath().toString();
+ File inputFile = new File(inputfileName);
+ ByteString inputByteStringForS2Cell = ByteString.copyFromUtf8("Test ByteString!");
+ writeByteStringToFile(inputS2CellFileName, inputByteStringForS2Cell);
+
+ createInputXml(inputFile, 14, 1, "31006", 1,
+ "USSSS", true, inputS2CellFileName);
+ String[] args = {
+ "--input-file", inputFilePath.toAbsolutePath().toString(),
+ "--output-file", outputFilePath.toAbsolutePath().toString()
+ };
+ try {
+ ConfigDataGenerator.main(args);
+ } catch (Exception ex) {
+ // Expected exception because input country code is invalid
+ return;
+ }
+ fail("Exception should have been caught");
+ }
+
+ @Test
+ public void testConfigDataGeneratorWithValidInput() throws Exception {
+ Path inputDirPath = mTempDirPath.resolve("input");
+ Files.createDirectory(inputDirPath);
+ Path inputFilePath = inputDirPath.resolve("test_input.xml");
+ Path inputS2CellFilePath = inputDirPath.resolve("sats2.dat");
+
+ Path outputDirPath = mTempDirPath.resolve("output");
+ Files.createDirectory(outputDirPath);
+ Path outputFilePath = outputDirPath.resolve("test_out.pb");
+ String inputfileName = inputFilePath.toAbsolutePath().toString();
+ String inputS2CellFileName = inputS2CellFilePath.toAbsolutePath().toString();
+ File inputFile = new File(inputfileName);
+ String outputFileName = outputFilePath.toAbsolutePath().toString();
+
+
+ int inputVersion = 14;
+ int inputCarrierId = 1;
+ String inputPlmn = "31006";
+ int inputAllowedService = 1;
+ String inputCountryCode = "US";
+ boolean inputIsAllowed = true;
+ ByteString inputByteStringForS2Cell = ByteString.copyFromUtf8("Test ByteString!");
+ writeByteStringToFile(inputS2CellFileName, inputByteStringForS2Cell);
+ createInputXml(inputFile, inputVersion, inputCarrierId, inputPlmn, inputAllowedService,
+ inputCountryCode, inputIsAllowed, inputS2CellFileName);
+ String[] args = {
+ "--input-file", inputFilePath.toAbsolutePath().toString(),
+ "--output-file", outputFilePath.toAbsolutePath().toString()
+ };
+ try {
+ ConfigDataGenerator.main(args);
+ } catch (Exception ex) {
+ fail("Unexpected exception when executing the tool ex=" + ex);
+ }
+
+ Path filePath = Paths.get(outputFileName);
+ byte[] fileBytes = Files.readAllBytes(filePath);
+ TelephonyConfigProto telephonyConfigProto = TelephonyConfigProto.parseFrom(fileBytes);
+ SatelliteConfigProto satelliteConfigProto = telephonyConfigProto.getSatellite();
+ int version = satelliteConfigProto.getVersion();
+ assertEquals(inputVersion, version);
+ CarrierSupportedSatelliteServicesProto serviceProto =
+ satelliteConfigProto.getCarrierSupportedSatelliteServices(0);
+ int carrierId = serviceProto.getCarrierId();
+ assertEquals(inputCarrierId, carrierId);
+ SatelliteProviderCapabilityProto providerCapabilityProto =
+ serviceProto.getSupportedSatelliteProviderCapabilities(0);
+ String plmn = providerCapabilityProto.getCarrierPlmn();
+ assertEquals(inputPlmn, plmn);
+ int allowedService = providerCapabilityProto.getAllowedServices(0);
+ assertEquals(inputAllowedService, allowedService);
+
+ SatelliteRegionProto regionProto = satelliteConfigProto.getDeviceSatelliteRegion();
+ String countryCode = regionProto.getCountryCodes(0);
+ assertEquals(inputCountryCode, countryCode);
+ ByteString s2cellfile = regionProto.getS2CellFile();
+ byte[] fileBytesForInputS2CellFile = Files.readAllBytes(Paths.get(inputS2CellFileName));
+ ByteString inputS2CellFile = ByteString.copyFrom(fileBytesForInputS2CellFile);
+ assertEquals(inputS2CellFile, s2cellfile);
+ boolean isAllowed = regionProto.getIsAllowed();
+ assertEquals(inputIsAllowed, isAllowed);
+ }
+
+ private void createInputXml(File outputFile, int version, int carrierId, String plmn,
+ int allowedService, String countryCode, boolean isAllowed, String inputS2CellFileName) {
+ try {
+ DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
+
+ // Create Document and Root Element
+ Document doc = docBuilder.newDocument();
+ Element rootElement = doc.createElement(ConfigDataGenerator.TAG_SATELLITE_CONFIG);
+ doc.appendChild(rootElement);
+
+ // Add <version>
+ Element versionElement = doc.createElement(ConfigDataGenerator.TAG_VERSION);
+ versionElement.appendChild(doc.createTextNode(String.valueOf(version)));
+ rootElement.appendChild(versionElement);
+
+ // Add <carriersupportedservices>
+ rootElement.appendChild(
+ createCarrierSupportedServices(doc, carrierId, plmn, allowedService));
+
+ // Add <satelliteregion>
+ Element satelliteRegion = doc.createElement(ConfigDataGenerator.TAG_SATELLITE_REGION);
+ satelliteRegion.appendChild(
+ createElementWithText(doc, ConfigDataGenerator.TAG_S2_CELL_FILE,
+ inputS2CellFileName));
+ satelliteRegion.appendChild(
+ createElementWithText(doc, ConfigDataGenerator.TAG_COUNTRY_CODE, countryCode));
+ satelliteRegion.appendChild(
+ createElementWithText(doc, ConfigDataGenerator.TAG_IS_ALLOWED,
+ isAllowed ? "TRUE" : "FALSE"));
+ rootElement.appendChild(satelliteRegion);
+
+ // Write XML to File
+ TransformerFactory transformerFactory = TransformerFactory.newInstance();
+ Transformer transformer = transformerFactory.newTransformer();
+ DOMSource source = new DOMSource(doc);
+ StreamResult result = new StreamResult(outputFile);
+ transformer.transform(source, result);
+
+ } catch (Exception e) {
+ throw new RuntimeException("Got exception in creating input file , e=" + e);
+ }
+ }
+
+ private static Element createCarrierSupportedServices(Document doc, int carrierId,
+ String carrierPlmn, int... services) {
+ Element carrierSupportedServices = doc.createElement(
+ ConfigDataGenerator.TAG_SUPPORTED_SERVICES);
+ carrierSupportedServices.appendChild(createElementWithText(doc,
+ ConfigDataGenerator.TAG_CARRIER_ID, String.valueOf(carrierId)));
+
+ Element providerCapability = doc.createElement(ConfigDataGenerator.TAG_PROVIDER_CAPABILITY);
+ providerCapability.appendChild(createElementWithText(doc,
+ ConfigDataGenerator.TAG_CARRIER_PLMN, carrierPlmn));
+ for (int service : services) {
+ providerCapability.appendChild(createElementWithText(doc,
+ ConfigDataGenerator.TAG_SERVICE, String.valueOf(service)));
+ }
+ carrierSupportedServices.appendChild(providerCapability);
+
+ return carrierSupportedServices;
+ }
+
+ private static Element createElementWithText(Document doc, String tagName, String textContent) {
+ Element element = doc.createElement(tagName);
+ element.appendChild(doc.createTextNode(textContent));
+ return element;
+ }
+
+ private static Path createTempDir(Class<?> testClass) throws IOException {
+ return Files.createTempDirectory(testClass.getSimpleName());
+ }
+
+ private static void deleteDirectory(Path dir) throws IOException {
+ Files.walkFileTree(dir, new SimpleFileVisitor<>() {
+ @Override
+ public FileVisitResult visitFile(Path path, BasicFileAttributes basicFileAttributes)
+ throws IOException {
+ Files.deleteIfExists(path);
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory(Path path, IOException e) throws IOException {
+ Files.delete(path);
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ assertFalse(Files.exists(dir));
+ }
+
+ private void writeByteStringToFile(String fileName, ByteString byteString) {
+ try (FileOutputStream fos = new FileOutputStream(fileName)) {
+ fos.write(byteString.toByteArray());
+ } catch (IOException e) {
+ System.err.println("Error writing to file: " + e.getMessage());
+ }
+ }
+}