Home | History | Annotate | Download | only in releaseparser
      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