1 /* 2 * Copyright (C) 2021 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.car.internal.util; 18 19 import static java.lang.Integer.toHexString; 20 21 import android.annotation.Nullable; 22 import android.car.VehicleAreaDoor; 23 import android.car.VehicleAreaMirror; 24 import android.car.VehicleAreaSeat; 25 import android.car.VehicleAreaType; 26 import android.car.VehicleAreaWheel; 27 import android.car.VehicleAreaWindow; 28 import android.car.VehiclePropertyIds; 29 import android.util.Slog; 30 31 import com.android.car.internal.property.CarPropertyHelper; 32 import com.android.car.internal.property.PropIdAreaId; 33 34 import java.util.List; 35 36 // Copied from frameworks/base and kept only used codes 37 /** 38 * <p>Various utilities for debugging and logging.</p> 39 */ 40 public final class DebugUtils { 41 public static final String TAG = DebugUtils.class.getSimpleName(); 42 DebugUtils()43 private DebugUtils() { 44 } 45 46 /** 47 * Gets human-readable representation of constants (static final values). 48 * 49 * @see #constantToString(Class, String, int) 50 */ constantToString(Class<?> clazz, int value)51 public static String constantToString(Class<?> clazz, int value) { 52 return constantToString(clazz, "", value); 53 } 54 55 /** 56 * Use prefixed constants (static final values) on given class to turn value 57 * into human-readable string. 58 */ constantToString(Class<?> clazz, String prefix, int value)59 public static String constantToString(Class<?> clazz, String prefix, int value) { 60 String constantString = ConstantDebugUtils.toName(clazz, prefix, value); 61 return constantString != null ? constantString : prefix + value; 62 } 63 64 /** 65 * Use prefixed constants (public static final int values) on a given class to turn flags into 66 * human-readable string. 67 */ flagsToString(Class<?> bitFlagClazz, String prefix, int flagsToConvert)68 public static String flagsToString(Class<?> bitFlagClazz, String prefix, int flagsToConvert) { 69 String flagsString = flagsToOptionalString(bitFlagClazz, prefix, flagsToConvert); 70 return flagsString != null ? flagsString : "0x" + Integer.toHexString(flagsToConvert); 71 } 72 73 /** 74 * Use constants (public static final int values) on given class to turn flags into 75 * human-readable string if possible. If no conversion found, returns {@code null}. 76 */ flagsToOptionalString(Class<?> bitFlagClazz, int flagsToConvert)77 public static @Nullable String flagsToOptionalString(Class<?> bitFlagClazz, 78 int flagsToConvert) { 79 return flagsToOptionalString(bitFlagClazz, "", flagsToConvert); 80 } 81 82 /** 83 * Use prefixed constants (public static final int values) on a given class to turn flags into 84 * human-readable string if possible. If no conversion found, returns {@code null}. 85 */ flagsToOptionalString(Class<?> bitFlagClazz, String prefix, int flagsToConvert)86 public static @Nullable String flagsToOptionalString(Class<?> bitFlagClazz, String prefix, 87 int flagsToConvert) { 88 boolean inputFlagsWasZero = flagsToConvert == 0; 89 int flagsToConvertCopy = flagsToConvert; 90 final StringBuilder result = new StringBuilder(); 91 92 List<Integer> bitFlags = ConstantDebugUtils.getValues(bitFlagClazz, prefix); 93 for (int i = 0; i < bitFlags.size(); i++) { 94 int bitFlag = bitFlags.get(i); 95 96 if (bitFlag == 0 && inputFlagsWasZero) { 97 return ConstantDebugUtils.toName(bitFlagClazz, prefix, bitFlag); 98 } 99 if (bitFlag != 0 && (flagsToConvertCopy & bitFlag) == bitFlag) { 100 flagsToConvertCopy &= ~bitFlag; 101 result.append(ConstantDebugUtils.toName(bitFlagClazz, prefix, bitFlag)).append('|'); 102 } 103 } 104 105 if (result.isEmpty()) { 106 return null; 107 } else if (flagsToConvertCopy != 0) { 108 result.append("0x").append(Integer.toHexString(flagsToConvertCopy)); 109 } else { 110 result.deleteCharAt(result.length() - 1); 111 } 112 113 return result.toString(); 114 } 115 116 /** 117 * Gets a user-friendly string representation of an {@code areaId} for the given 118 * {@code propertyId}. 119 */ toAreaIdString(int propertyId, int areaId)120 public static String toAreaIdString(int propertyId, int areaId) { 121 int areaType; 122 try { 123 areaType = CarPropertyHelper.getAreaType(propertyId); 124 } catch (IllegalArgumentException e) { 125 Slog.w(TAG, "Property ID: " + VehiclePropertyIds.toString(propertyId) 126 + " has invalid area type for area ID: " + areaId, e); 127 areaType = -1; 128 } 129 130 switch (areaType) { 131 case VehicleAreaType.VEHICLE_AREA_TYPE_GLOBAL -> { 132 if (areaId == 0) { 133 return "GLOBAL"; 134 } 135 return "INVALID_GLOBAL_AREA_ID(0x" + toHexString(areaId) + ")"; 136 } 137 case VehicleAreaType.VEHICLE_AREA_TYPE_DOOR -> { 138 return areaIdToString(VehicleAreaDoor.class, "DOOR_", areaId); 139 } 140 case VehicleAreaType.VEHICLE_AREA_TYPE_MIRROR -> { 141 return areaIdToString(VehicleAreaMirror.class, "MIRROR_", areaId); 142 } 143 case VehicleAreaType.VEHICLE_AREA_TYPE_SEAT -> { 144 return areaIdToString(VehicleAreaSeat.class, "SEAT_", areaId); 145 } 146 case VehicleAreaType.VEHICLE_AREA_TYPE_WHEEL -> { 147 return areaIdToString(VehicleAreaWheel.class, "WHEEL_", areaId); 148 } 149 case VehicleAreaType.VEHICLE_AREA_TYPE_WINDOW -> { 150 return areaIdToString(VehicleAreaWindow.class, "WINDOW_", areaId); 151 } 152 case VehicleAreaType.VEHICLE_AREA_TYPE_VENDOR -> { 153 return "VENDOR_AREA_ID(0x" + toHexString(areaId) + ")"; 154 } 155 default -> { 156 return "UNKNOWN_AREA_TYPE_AREA_ID(0x" + toHexString(areaId) + ")"; 157 } 158 } 159 } 160 161 /** 162 * Gets human-readable representation of a {@code PropIdAreaId} structure. 163 */ toDebugString(PropIdAreaId propIdAreaId)164 public static String toDebugString(PropIdAreaId propIdAreaId) { 165 return "PropIdAreaId{propId=" + VehiclePropertyIds.toString(propIdAreaId.propId) 166 + ", areaId=" + toAreaIdString(propIdAreaId.propId, propIdAreaId.areaId) + "}"; 167 } 168 169 /** 170 * Gets human-readable representation of a list of {@code PropIdAreaId} structure. 171 */ toDebugString(List<PropIdAreaId> propIdAreaIds)172 public static String toDebugString(List<PropIdAreaId> propIdAreaIds) { 173 StringBuilder sb = new StringBuilder(); 174 sb.append("propIdAreaIds: ["); 175 boolean first = true; 176 for (int i = 0; i < propIdAreaIds.size(); i++) { 177 var propIdAreaId = propIdAreaIds.get(i); 178 if (first) { 179 first = false; 180 } else { 181 sb.append(", "); 182 } 183 sb.append(toDebugString(propIdAreaId)); 184 } 185 return sb.append("]").toString(); 186 } 187 areaIdToString(Class<?> areaTypeClazz, String prefix, int areaId)188 private static String areaIdToString(Class<?> areaTypeClazz, String prefix, int areaId) { 189 String areaIdString = flagsToOptionalString(areaTypeClazz, prefix, areaId); 190 if (areaIdString != null) { 191 return areaIdString; 192 } 193 return "UNKNOWN_" + prefix + "AREA_ID(0x" + toHexString(areaId) + ")"; 194 } 195 } 196