1/* 2 * Copyright (C) 2022 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 17import {TimeUtils} from 'common/time_utils'; 18import configJson from '../../../../../frameworks/base/data/etc/services.core.protolog.json'; 19import {ElapsedTimestamp, RealTimestamp, TimestampType} from './timestamp'; 20 21class LogMessage { 22 text: string; 23 time: string; 24 tag: string; 25 level: string; 26 at: string; 27 timestamp: bigint; 28 29 constructor( 30 text: string, 31 time: string, 32 tag: string, 33 level: string, 34 at: string, 35 timestamp: bigint 36 ) { 37 this.text = text; 38 this.time = time; 39 this.tag = tag; 40 this.level = level; 41 this.at = at; 42 this.timestamp = timestamp; 43 } 44} 45 46class FormattedLogMessage extends LogMessage { 47 constructor( 48 proto: any, 49 timestampType: TimestampType, 50 realToElapsedTimeOffsetNs: bigint | undefined 51 ) { 52 const text = 53 proto.messageHash.toString() + 54 ' - [' + 55 proto.strParams.toString() + 56 '] [' + 57 proto.sint64Params.toString() + 58 '] [' + 59 proto.doubleParams.toString() + 60 '] [' + 61 proto.booleanParams.toString() + 62 ']'; 63 64 let time: string; 65 let timestamp: bigint; 66 if ( 67 timestampType === TimestampType.REAL && 68 realToElapsedTimeOffsetNs !== undefined && 69 realToElapsedTimeOffsetNs !== 0n 70 ) { 71 timestamp = realToElapsedTimeOffsetNs + BigInt(proto.elapsedRealtimeNanos); 72 time = TimeUtils.format(new RealTimestamp(timestamp)); 73 } else { 74 timestamp = BigInt(proto.elapsedRealtimeNanos); 75 time = TimeUtils.format(new ElapsedTimestamp(timestamp)); 76 } 77 78 super(text, time, 'INVALID', 'invalid', '', timestamp); 79 } 80} 81 82class UnformattedLogMessage extends LogMessage { 83 constructor( 84 proto: any, 85 timestampType: TimestampType, 86 realToElapsedTimeOffsetNs: bigint | undefined, 87 message: any 88 ) { 89 let time: string; 90 let timestamp: bigint; 91 if ( 92 timestampType === TimestampType.REAL && 93 realToElapsedTimeOffsetNs !== undefined && 94 realToElapsedTimeOffsetNs !== 0n 95 ) { 96 timestamp = realToElapsedTimeOffsetNs + BigInt(proto.elapsedRealtimeNanos); 97 time = TimeUtils.format( 98 new RealTimestamp(realToElapsedTimeOffsetNs + BigInt(proto.elapsedRealtimeNanos)) 99 ); 100 } else { 101 timestamp = BigInt(proto.elapsedRealtimeNanos); 102 time = TimeUtils.format(new ElapsedTimestamp(timestamp)); 103 } 104 105 super( 106 formatText(message.message, proto), 107 time, 108 (configJson as any).groups[message.group].tag, 109 message.level, 110 message.at, 111 timestamp 112 ); 113 } 114} 115 116function formatText(messageFormat: any, data: any) { 117 let out = ''; 118 119 const strParams: string[] = data.strParams; 120 let strParamsIdx = 0; 121 const sint64Params: number[] = data.sint64Params; 122 let sint64ParamsIdx = 0; 123 const doubleParams: number[] = data.doubleParams; 124 let doubleParamsIdx = 0; 125 const booleanParams: number[] = data.booleanParams; 126 let booleanParamsIdx = 0; 127 128 for (let i = 0; i < messageFormat.length; ) { 129 if (messageFormat[i] === '%') { 130 if (i + 1 >= messageFormat.length) { 131 // Should never happen - protologtool checks for that 132 throw new Error('Invalid format string'); 133 } 134 switch (messageFormat[i + 1]) { 135 case '%': 136 out += '%'; 137 break; 138 case 'd': 139 out += getParam(sint64Params, sint64ParamsIdx++).toString(10); 140 break; 141 case 'o': 142 out += getParam(sint64Params, sint64ParamsIdx++).toString(8); 143 break; 144 case 'x': 145 out += getParam(sint64Params, sint64ParamsIdx++).toString(16); 146 break; 147 case 'f': 148 out += getParam(doubleParams, doubleParamsIdx++).toFixed(6); 149 break; 150 case 'e': 151 out += getParam(doubleParams, doubleParamsIdx++).toExponential(); 152 break; 153 case 'g': 154 out += getParam(doubleParams, doubleParamsIdx++).toString(); 155 break; 156 case 's': 157 out += getParam(strParams, strParamsIdx++); 158 break; 159 case 'b': 160 out += getParam(booleanParams, booleanParamsIdx++).toString(); 161 break; 162 default: 163 // Should never happen - protologtool checks for that 164 throw new Error('Invalid format string conversion: ' + messageFormat[i + 1]); 165 } 166 i += 2; 167 } else { 168 out += messageFormat[i]; 169 i += 1; 170 } 171 } 172 return out; 173} 174 175function getParam<T>(arr: T[], idx: number): T { 176 if (arr.length <= idx) { 177 throw new Error('No param for format string conversion'); 178 } 179 return arr[idx]; 180} 181 182export {FormattedLogMessage, LogMessage, UnformattedLogMessage}; 183