1 /* 2 * Copyright (C) 2020 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.internal.os; 18 19 import android.os.Binder; 20 21 import com.android.internal.annotations.VisibleForTesting; 22 23 import java.lang.reflect.InvocationTargetException; 24 import java.lang.reflect.Method; 25 import java.lang.reflect.Modifier; 26 import java.util.HashMap; 27 28 /** 29 * Maps a binder class and transaction code to the default transaction name. Since this 30 * resolution is class-based as opposed to instance-based, any custom implementation of 31 * {@link Binder#getTransactionName} will be ignored. 32 * 33 * The class is NOT thread safe 34 * 35 * @hide 36 */ 37 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) 38 public class BinderTransactionNameResolver { 39 private static final Method NO_GET_DEFAULT_TRANSACTION_NAME_METHOD; 40 41 /** 42 * Generates the default transaction method name, which is just the transaction code. 43 * Used when the binder does not define a static "getDefaultTransactionName" method. 44 * 45 * @hide 46 */ noDefaultTransactionName(int transactionCode)47 public static String noDefaultTransactionName(int transactionCode) { 48 return String.valueOf(transactionCode); 49 } 50 51 static { 52 try { 53 NO_GET_DEFAULT_TRANSACTION_NAME_METHOD = BinderTransactionNameResolver.class.getMethod( 54 "noDefaultTransactionName", int.class); 55 } catch (NoSuchMethodException e) { 56 throw new RuntimeException(e); 57 } 58 } 59 60 private final HashMap<Class<? extends Binder>, Method> 61 mGetDefaultTransactionNameMethods = new HashMap<>(); 62 63 /** 64 * Given a binder class name and transaction code, returns the corresponding method name. 65 * 66 * @hide 67 */ getMethodName(Class<? extends Binder> binderClass, int transactionCode)68 public String getMethodName(Class<? extends Binder> binderClass, int transactionCode) { 69 Method method = mGetDefaultTransactionNameMethods.get(binderClass); 70 if (method == null) { 71 try { 72 method = binderClass.getMethod("getDefaultTransactionName", int.class); 73 } catch (NoSuchMethodException e) { 74 method = NO_GET_DEFAULT_TRANSACTION_NAME_METHOD; 75 } 76 if (method.getReturnType() != String.class 77 || !Modifier.isStatic(method.getModifiers())) { 78 method = NO_GET_DEFAULT_TRANSACTION_NAME_METHOD; 79 } 80 mGetDefaultTransactionNameMethods.put(binderClass, method); 81 } 82 83 try { 84 return (String) method.invoke(null, transactionCode); 85 } catch (IllegalAccessException | InvocationTargetException e) { 86 throw new RuntimeException(e); 87 } 88 } 89 } 90