MessageUtils.java revision d2457a3ee39ea55ed8e302bd93feede793cb5055
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 17package com.android.internal.util; 18 19import android.os.Message; 20import android.util.Log; 21import android.util.SparseArray; 22 23import java.lang.reflect.Field; 24 25/** 26 * Static utility class for dealing with {@link Message} objects. 27 */ 28public class MessageUtils { 29 30 private static final String TAG = MessageUtils.class.getSimpleName(); 31 private static final boolean DBG = false; 32 33 /** Thrown when two different constants have the same value. */ 34 public static class DuplicateConstantError extends Error { 35 private DuplicateConstantError() {} 36 public DuplicateConstantError(String name1, String name2, int value) { 37 super(String.format("Duplicate constant value: both %s and %s = %d", 38 name1, name2, value)); 39 } 40 } 41 42 /** 43 * Finds the names of integer constants. Searches the specified {@code classes}, looking for 44 * accessible static integer fields whose names begin with one of the specified {@prefixes}. 45 * 46 * @param classes the classes to examine. 47 * @prefixes only consider fields names starting with one of these prefixes. 48 * @return a {@link SparseArray} mapping integer constants to their names. 49 */ 50 public static SparseArray<String> findMessageNames(Class[] classes, String[] prefixes) { 51 SparseArray<String> messageNames = new SparseArray<>(); 52 for (Class c : classes) { 53 String className = c.getName(); 54 if (DBG) Log.d(TAG, "Examining class " + className); 55 56 Field[] fields; 57 try { 58 fields = c.getDeclaredFields(); 59 } catch (SecurityException e) { 60 Log.e(TAG, "Can't list fields of class " + className); 61 continue; 62 } 63 64 for (Field field : fields) { 65 String name = field.getName(); 66 67 for (String prefix : prefixes) { 68 // Does this look like a constant? 69 if (!name.startsWith(prefix)) { 70 continue; 71 } 72 73 try { 74 // TODO: can we have the caller try to access the field instead, so we don't 75 // expose constants it does not have access to? 76 field.setAccessible(true); 77 78 // Fetch the constant's value. 79 int value; 80 try { 81 value = field.getInt(null); 82 } catch (IllegalArgumentException | ExceptionInInitializerError e) { 83 // The field is not an integer (or short or byte), or c's static 84 // initializer failed and we have no idea what its value is. 85 // Either way, give up on this field. 86 break; 87 } 88 89 // Check for duplicate values. 90 String previousName = messageNames.get(value); 91 if (previousName != null && !previousName.equals(name)) { 92 throw new DuplicateConstantError(name, previousName, value); 93 } 94 95 messageNames.put(value, name); 96 if (DBG) { 97 Log.d(TAG, String.format("Found constant: %s.%s = %d", 98 className, name, value)); 99 } 100 } catch (SecurityException | IllegalAccessException e) { 101 // Not allowed to make the field accessible, or no access. Ignore. 102 continue; 103 } 104 } 105 } 106 } 107 return messageNames; 108 } 109 110 /** 111 * Default prefixes for constants. 112 */ 113 public static final String[] DEFAULT_PREFIXES = {"CMD_", "EVENT_"}; 114 115 /** 116 * Finds the names of integer constants. Searches the specified {@code classes}, looking for 117 * accessible static integer values whose names begin with {@link #DEFAULT_PREFIXES}. 118 * 119 * @param classNames the classes to examine. 120 * @prefixes only consider fields names starting with one of these prefixes. 121 * @return a {@link SparseArray} mapping integer constants to their names. 122 */ 123 public static SparseArray<String> findMessageNames(Class[] classNames) { 124 return findMessageNames(classNames, DEFAULT_PREFIXES); 125 } 126} 127 128