1 /* 2 * Copyright (C) 2020 Google LLC 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.google.carrier; 17 18 import static java.nio.charset.StandardCharsets.UTF_8; 19 20 import com.beust.jcommander.JCommander; 21 import com.beust.jcommander.Parameter; 22 import com.beust.jcommander.Parameters; 23 import com.google.carrier.CarrierSettings; 24 import com.google.carrier.MultiCarrierSettings; 25 import com.google.protobuf.ExtensionRegistry; 26 import com.google.protobuf.Message; 27 import com.google.protobuf.TextFormat; 28 import java.io.BufferedReader; 29 import java.io.BufferedWriter; 30 import java.io.File; 31 import java.io.IOException; 32 import java.io.OutputStream; 33 import java.nio.file.Files; 34 import java.nio.file.Paths; 35 36 /** 37 * This command line tool generates device-specific settings from device overlay and base settings. 38 */ 39 @Parameters(separators = "=") 40 public class GenDeviceSettings { 41 @Parameter( 42 names = "--version_offset", 43 description = 44 "The value to be added to file version, used to differentiate releases/branches.") 45 private long versionOffset = 0L; 46 47 @Parameter(names = "--device_overlay", description = "The input device override textpb file.") 48 private String deviceFileName = "/tmp/device/muskie.textpb"; 49 50 @Parameter(names = "--base_setting_dir", description = "The path to input settings directory.") 51 private String baseSettingDirName = "/tmp/setting"; 52 53 @Parameter( 54 names = "--others_file", 55 description = "The file name of others carrier settings in the input directory.") 56 private String othersFileName = "others.textpb"; 57 58 @Parameter( 59 names = "--device_setting_dir", 60 description = "The path to output <device>_settings directory.") 61 private String deviceSettingDirName = "/tmp/muskie_setting"; 62 63 @Parameter( 64 names = "--with_version_number", 65 description = "Encode version number into output pb filename.") 66 private boolean versionInFileName = false; 67 68 @Parameter(names = "--with_device_name", description = "Encode device name into output filename.") 69 private String deviceInFileName = ""; 70 71 private static final String PB_SUFFIX = ".pb"; 72 private static final String TEXT_PB_SUFFIX = ".textpb"; 73 74 private static final ExtensionRegistry registry = ExtensionRegistry.newInstance(); 75 main(String[] args)76 public static void main(String[] args) throws IOException { 77 GenDeviceSettings generator = new GenDeviceSettings(); 78 new JCommander(generator, args); 79 generator.generate(); 80 } 81 generate()82 private void generate() throws IOException { 83 // Load device overlay 84 MultiCarrierSettings deviceOverlay = null; 85 try (BufferedReader br = Files.newBufferedReader(Paths.get(deviceFileName), UTF_8)) { 86 MultiCarrierSettings.Builder builder = MultiCarrierSettings.newBuilder(); 87 TextFormat.getParser().merge(br, registry, builder); 88 deviceOverlay = builder.build(); 89 } 90 91 // Create output settings directory if not exist. 92 File deviceSettingDir = new File(deviceSettingDirName); 93 if (!deviceSettingDir.exists()) { 94 deviceSettingDir.mkdirs(); 95 } 96 97 // For each carrier (and others) in baseSettingDir, find its overlay and apply. 98 File baseSettingDir = new File(baseSettingDirName); 99 for (String childName : baseSettingDir.list((dir, name) -> name.endsWith(TEXT_PB_SUFFIX))) { 100 System.out.println("Processing " + childName); 101 102 File baseSettingFile = new File(baseSettingDir, childName); 103 104 Message generatedMessage = null; 105 long version = 0L; 106 107 if (othersFileName.equals(childName)) { 108 109 // Load others setting 110 MultiCarrierSettings.Builder othersSetting = null; 111 try (BufferedReader br = Files.newBufferedReader(baseSettingFile.toPath(), UTF_8)) { 112 MultiCarrierSettings.Builder builder = MultiCarrierSettings.newBuilder(); 113 TextFormat.getParser().merge(br, registry, builder); 114 othersSetting = builder; 115 } 116 117 /* 118 * For non-tier1 carriers, DO NOT allow device overlay for now. 119 * There is no easy way to generate a mononical increasing version number with overlay. 120 * And if we do device overlay for a carrier, it should probobaly be tier-1. 121 */ 122 123 // Bump version according to the release 124 othersSetting.setVersion( 125 CarrierProtoUtils.addVersionOffset(othersSetting.getVersion(), versionOffset)); 126 127 // Convert vendor specific data into binary format 128 // Can be customized 129 130 generatedMessage = othersSetting.build(); 131 version = othersSetting.getVersion(); 132 133 } else { // a tier-1 carrier's setting 134 135 // Load carrier setting 136 CarrierSettings.Builder carrierSetting = null; 137 try (BufferedReader br = Files.newBufferedReader(baseSettingFile.toPath(), UTF_8)) { 138 CarrierSettings.Builder builder = CarrierSettings.newBuilder(); 139 TextFormat.getParser().merge(br, registry, builder); 140 carrierSetting = builder; 141 } 142 143 // Apply device overlay 144 carrierSetting = 145 CarrierProtoUtils.applyDeviceOverlayToCarrierSettings(deviceOverlay, carrierSetting); 146 147 // Bump version according to the release 148 carrierSetting.setVersion( 149 CarrierProtoUtils.addVersionOffset(carrierSetting.getVersion(), versionOffset)); 150 151 // Convert vendor specific data into binary format 152 // Can be customized 153 154 generatedMessage = carrierSetting.build(); 155 version = carrierSetting.getVersion(); 156 157 } 158 159 // Output 160 String outFileMainName = childName.replace(TEXT_PB_SUFFIX, ""); 161 162 File deviceSettingTextFile = new File(deviceSettingDir, outFileMainName + TEXT_PB_SUFFIX); 163 try (BufferedWriter bw = Files.newBufferedWriter(deviceSettingTextFile.toPath(), UTF_8)) { 164 TextFormat.printUnicode(generatedMessage, bw); 165 } 166 167 if (!deviceInFileName.isEmpty()) { 168 outFileMainName = deviceInFileName + "-" + outFileMainName; 169 } 170 if (versionInFileName) { 171 outFileMainName += "-" + version; 172 } 173 File deviceSettingFile = new File(deviceSettingDir, outFileMainName + PB_SUFFIX); 174 try (OutputStream os = Files.newOutputStream(deviceSettingFile.toPath())) { 175 generatedMessage.writeTo(os); 176 } 177 } 178 } 179 GenDeviceSettings()180 private GenDeviceSettings() {} 181 } 182