1 /* 2 * Copyright (C) 2018 The Android Open Source Project 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 17 package com.android.cts.releaseparser; 18 19 import com.android.cts.releaseparser.ReleaseProto.*; 20 21 import java.io.BufferedReader; 22 import java.io.File; 23 import java.io.FileReader; 24 import java.io.IOException; 25 import java.util.ArrayList; 26 import java.util.Arrays; 27 import java.util.HashMap; 28 import java.util.List; 29 import java.util.Map; 30 31 public class RcParser extends FileParser { 32 private static String OPTION_CLASS = "class "; 33 private static String OPTION_USER = "user "; 34 private static String OPTION_GROUP = "group "; 35 private static String OPTION_WRITEPID = "writepid "; 36 private static String SECTION_SERVICE = "service"; 37 private static String SECTION_IMPORT = "import"; 38 39 private Entry.EntryType mType; 40 private List<Service> mServices; 41 private List<String> mImportRc; 42 RcParser(File file)43 public RcParser(File file) { 44 super(file); 45 } 46 47 @Override getType()48 public Entry.EntryType getType() { 49 if (mType == null) { 50 parseFile(); 51 } 52 return mType; 53 } 54 55 @Override setAdditionalInfo()56 public void setAdditionalInfo() { 57 getFileEntryBuilder().addAllServices(getServiceList()); 58 } 59 60 @Override getDependencies()61 public List<String> getDependencies() { 62 if (mServices == null) { 63 parseFile(); 64 } 65 66 Map<String, Integer> dependencies = new HashMap<>(); 67 for (Service service : mServices) { 68 // skip /, e.g. /system/bin/sh 69 try { 70 String file = service.getFile().substring(1); 71 dependencies.put(file, 1); 72 } catch (Exception e) { 73 System.err.println( 74 "err Service " + service.getName() + " File:" + service.getFile()); 75 } 76 } 77 78 for (String importRc : mImportRc) { 79 // skip /, e.g. /init.usb.rc 80 String file = importRc.substring(1); 81 dependencies.put(file, 1); 82 } 83 84 return new ArrayList<String>(dependencies.keySet()); 85 } 86 87 @Override getCodeId()88 public String getCodeId() { 89 return getFileContentId(); 90 } 91 getServiceList()92 public List<Service> getServiceList() { 93 if (mServices == null) { 94 parseFile(); 95 } 96 return mServices; 97 } 98 toString()99 public String toString() { 100 return toString(mServices); 101 } 102 toString(List<Service> services)103 public static String toString(List<Service> services) { 104 StringBuilder result = new StringBuilder(); 105 for (Service service : services) { 106 result.append( 107 String.format( 108 "%s %s %s %s;", 109 service.getName(), 110 service.getClazz(), 111 service.getUser(), 112 service.getGroup())); 113 // System.err.println(String.format("RcParser-toString %s %s %s ", service.getName(), 114 // service.getFile(), String.join(" ", service.getArgumentsList()))); 115 } 116 return result.toString(); 117 } 118 parseFile()119 private void parseFile() { 120 // rc file spec. at android/system/core/init/README.md 121 // android/system/core/init/init.cpp?q=CreateParser 122 mServices = new ArrayList<Service>(); 123 mImportRc = new ArrayList<String>(); 124 try { 125 FileReader fileReader = new FileReader(getFile()); 126 BufferedReader buffReader = new BufferedReader(fileReader); 127 128 String line; 129 while ((line = buffReader.readLine()) != null) { 130 if (line.startsWith(SECTION_SERVICE)) { 131 parseService(line, buffReader); 132 } else if (line.startsWith(SECTION_IMPORT)) { 133 parseImport(line); 134 } 135 } 136 fileReader.close(); 137 mType = Entry.EntryType.RC; 138 } catch (IOException e) { 139 // file is not a RC Config 140 System.err.println("RcParser err:" + getFileName() + "\n" + e.getMessage()); 141 mType = super.getType(); 142 } 143 // System.err.println(this.toString()); 144 } 145 parseService(String line, BufferedReader buffReader)146 private void parseService(String line, BufferedReader buffReader) throws IOException { 147 Service.Builder serviceBld = Service.newBuilder(); 148 String[] phases = line.split("\\s+"); 149 serviceBld.setName(phases[1]); 150 serviceBld.setFile(phases[2]); 151 if (phases.length > 3) { 152 serviceBld.addAllArguments(Arrays.asList(phases).subList(3, phases.length)); 153 } 154 String sLine; 155 while ((sLine = buffReader.readLine()) != null) { 156 String sTrimLine = sLine.trim(); 157 if (sTrimLine.isEmpty()) { 158 // End of a service block 159 break; 160 } 161 if (sTrimLine.startsWith("#")) { 162 // Skips comment 163 continue; 164 } else if (sTrimLine.startsWith(OPTION_CLASS)) { 165 serviceBld.setClazz(sTrimLine.substring(OPTION_CLASS.length())); 166 } else if (sTrimLine.startsWith(OPTION_USER)) { 167 serviceBld.setUser(sTrimLine.substring(OPTION_USER.length())); 168 } else if (sTrimLine.startsWith(OPTION_GROUP)) { 169 serviceBld.setGroup(sTrimLine.substring(OPTION_GROUP.length())); 170 } else if (sTrimLine.startsWith(OPTION_WRITEPID)) { 171 serviceBld.setGroup(sTrimLine.substring(OPTION_WRITEPID.length())); 172 } else { 173 serviceBld.addOptions(sTrimLine); 174 } 175 } 176 mServices.add(serviceBld.build()); 177 } 178 parseImport(String line)179 private void parseImport(String line) { 180 // e.g.: import /init.environ.rc 181 String[] phases = line.split(" "); 182 mImportRc.add(phases[1]); 183 } 184 } 185