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