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