1 /* 2 * Copyright (C) 2016 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.loganalysis.parser; 18 19 import com.android.loganalysis.item.IItem; 20 import com.android.loganalysis.item.LatencyItem; 21 import com.android.loganalysis.item.TransitionDelayItem; 22 23 import java.io.BufferedReader; 24 import java.io.IOException; 25 import java.util.ArrayList; 26 import java.util.HashMap; 27 import java.util.List; 28 import java.util.Map; 29 import java.util.regex.Matcher; 30 import java.util.regex.Pattern; 31 32 /** 33 * Parse the events logs. </p> 34 */ 35 public class EventsLogParser implements IParser { 36 37 // 09-18 23:56:19.376 1140 1221 I sysui_multi_action: 38 // [319,51,321,50,322,190,325,670,757,761,758,7,759,1,806,com.google.android.calculator,871, 39 // com.android.calculator2.Calculator,905,0,945,41] 40 private static final Pattern SYSUI_TRANSITION_INFO_PATTERN = Pattern.compile( 41 "^(?<date>[0-9-]*)\\s+(?<time>[0-9:.]*)\\s+\\d+\\s+\\d+ I sysui_multi_action:" 42 + " \\[(?<transitioninfo>.*)\\]$"); 43 44 // 08-21 17:53:53.876 1053 2135 I sysui_latency: [1,50] 45 private static final Pattern ACTION_LATENCY = Pattern.compile("^(?<date>[0-9-]*)\\s+" 46 + "(?<time>[0-9:.]*)\\s+\\d+\\s+\\d+ I sysui_latency: \\[(?<action>.*)," 47 + "(?<delay>.*)\\]$"); 48 49 private static final String DATE = "date"; 50 private static final String TIME = "time"; 51 private static final String TRANSITION_INFO = "transitioninfo"; 52 private static final String PACKAGE_KEY = "806"; 53 private static final String ACTIVITY_KEY = "871"; 54 private static final String TRANSITION_DELAY_KEY = "319"; 55 private static final String STARTING_WINDOW_DELAY_KEY = "321"; 56 private static final String COLD_LAUNCH_KEY = "945"; 57 private static final String WINDOWS_DRAWN_DELAY_KEY = "322"; 58 59 @Override parse(List<String> lines)60 public IItem parse(List<String> lines) { 61 throw new UnsupportedOperationException("Method has not been implemented in lieu" 62 + " of others"); 63 } 64 65 /** 66 * Parse the transition delay information from the events log. 67 * @param input 68 * @return list of transition delay items. 69 * @throws IOException 70 */ parseTransitionDelayInfo(BufferedReader input)71 public List<TransitionDelayItem> parseTransitionDelayInfo(BufferedReader input) 72 throws IOException { 73 List<TransitionDelayItem> transitionDelayItems = new ArrayList<TransitionDelayItem>(); 74 String line; 75 Matcher match = null; 76 while ((line = input.readLine()) != null) { 77 if ((match = matches(SYSUI_TRANSITION_INFO_PATTERN, line)) != null) { 78 Map<String, String> transitionInfoMap = getTransitionInfoMap( 79 match.group(TRANSITION_INFO)); 80 if (transitionInfoMap.containsKey(TRANSITION_DELAY_KEY)) { 81 TransitionDelayItem delayItem = new TransitionDelayItem(); 82 if (null != transitionInfoMap.get(PACKAGE_KEY) 83 && null != transitionInfoMap.get(ACTIVITY_KEY) 84 && null != transitionInfoMap.get(TRANSITION_DELAY_KEY) 85 && null != transitionInfoMap.get(WINDOWS_DRAWN_DELAY_KEY)) { 86 delayItem.setComponentName(transitionInfoMap.get(PACKAGE_KEY) + "/" 87 + transitionInfoMap.get(ACTIVITY_KEY)); 88 delayItem.setTransitionDelay(Long.parseLong(transitionInfoMap 89 .get(TRANSITION_DELAY_KEY))); 90 delayItem.setDateTime(String.format("%s %s", match.group(DATE), 91 match.group(TIME))); 92 delayItem.setWindowDrawnDelay( 93 Long.parseLong(transitionInfoMap.get(WINDOWS_DRAWN_DELAY_KEY))); 94 } 95 if (transitionInfoMap.containsKey(COLD_LAUNCH_KEY)) { 96 if (null != transitionInfoMap.get(STARTING_WINDOW_DELAY_KEY)) { 97 delayItem.setStartingWindowDelay(Long.parseLong(transitionInfoMap 98 .get(STARTING_WINDOW_DELAY_KEY))); 99 } 100 } 101 transitionDelayItems.add(delayItem); 102 } 103 } 104 } 105 return transitionDelayItems; 106 } 107 108 /** 109 * Split the transition info string in to key, values and return a map. 110 * @param transitionInfo transition info map in hey value format. 111 * @return 112 */ getTransitionInfoMap(String transitionInfo)113 public Map<String, String> getTransitionInfoMap(String transitionInfo) { 114 String[] transitionSplit = transitionInfo.split(","); 115 Map<String, String> transitionInfoMap = new HashMap<>(); 116 if (transitionSplit.length % 2 == 0) { 117 for (int i = 0; i < transitionSplit.length; i = i + 2) { 118 transitionInfoMap.put(transitionSplit[i], transitionSplit[i + 1]); 119 } 120 } 121 return transitionInfoMap; 122 } 123 124 /** 125 * Method to parse the latency information from the events log 126 * @param input 127 * @return 128 * @throws IOException 129 */ parseLatencyInfo(BufferedReader input)130 public List<LatencyItem> parseLatencyInfo(BufferedReader input) throws IOException { 131 List<LatencyItem> latencyItems = new ArrayList<LatencyItem>(); 132 String line; 133 while ((line = input.readLine()) != null) { 134 Matcher match = null; 135 if (((match = matches(ACTION_LATENCY, line))) != null) { 136 LatencyItem latencyItem = new LatencyItem(); 137 latencyItem.setActionId(Integer.parseInt(match.group("action"))); 138 latencyItem.setDelay(Long.parseLong(match.group("delay"))); 139 latencyItems.add(latencyItem); 140 } 141 } 142 return latencyItems; 143 } 144 145 /** 146 * Checks whether {@code line} matches the given {@link Pattern}. 147 * 148 * @return The resulting {@link Matcher} obtained by matching the {@code line} against 149 * {@code pattern}, or null if the {@code line} does not match. 150 */ matches(Pattern pattern, String line)151 private static Matcher matches(Pattern pattern, String line) { 152 Matcher ret = pattern.matcher(line); 153 return ret.matches() ? ret : null; 154 } 155 156 } 157