• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.tools.metalava;
18 
19 import java.lang.reflect.Method;
20 import java.util.List;
21 
22 /**
23  * A collection of wrapper functions for java.lang.management APIs. Unfortunately we need to
24  * use reflections for them due to b/151224432.
25  *
26  * TODO(b/151224432) Resolve the device-side dependency and stop using reflections here.
27  *
28  * To avoid extra possible allocations around casts in kotlin, it's written in Java.
29  */
30 final class ManagementWrapper {
31     private static Class<?>[] EMPTY_CLASSES = new Class[]{};
32     private static Object[] EMPTY_ARGS = new Object[]{};
33 
onReflectionException(Exception e)34     private static void onReflectionException(Exception e) {
35         throw new RuntimeException(e);
36     }
37 
38     private abstract static class Lazy<T> {
39         private boolean mInitialized;
40         private T mValue;
41 
init()42         abstract T init();
43 
get()44         public T get() {
45             if (!mInitialized) {
46                 mValue = init();
47                 mInitialized = true;
48             }
49             return mValue;
50         }
51     }
52 
53     private static class LazyClass extends Lazy<Class<?>> {
54         private final String mName;
55 
LazyClass(String name)56         private LazyClass(String name) {
57             mName = name;
58         }
59 
60         @Override
init()61         Class<?> init() {
62             try {
63                 return Class.forName(mName);
64             } catch (Exception e) {
65                 onReflectionException(e);
66                 return null;
67             }
68         }
69     }
70 
71     private static class LazyMethod<TV> extends Lazy<Method>  {
72         private final LazyClass mClazz;
73         private final String mName;
74         private TV mCachedInvokeResult;
75         private TV mDefault;
76 
LazyMethod(LazyClass clazz, String name)77         private LazyMethod(LazyClass clazz, String name) {
78             this(clazz, name, null);
79         }
80 
LazyMethod(LazyClass clazz, String name, TV defaultValue)81         private LazyMethod(LazyClass clazz, String name, TV defaultValue) {
82             mClazz = clazz;
83             mName = name;
84             mDefault = defaultValue;
85         }
86 
87         @Override
init()88         Method init() {
89             try {
90                 final Class<?> clazz = mClazz.get();
91                 final Method m = clazz.getMethod(mName, EMPTY_CLASSES);
92                 m.setAccessible(true);
93                 return m;
94             } catch (Exception e) {
95                 onReflectionException(e);
96                 return null;
97             }
98         }
99 
100         @SuppressWarnings("unchecked")
invoke(Object target)101         public TV invoke(Object target) {
102             try {
103                 return (TV) get().invoke(target, EMPTY_ARGS);
104             } catch (Exception e) {
105                 onReflectionException(e);
106                 return mDefault;
107             }
108         }
109 
invokeOnce(Object target)110         public TV invokeOnce(Object target) {
111             if (mCachedInvokeResult == null) {
112                 mCachedInvokeResult = invoke(target);
113             }
114             return mCachedInvokeResult;
115         }
116     }
117 
118     private static LazyClass sFactoryClazz = new LazyClass("java.lang.management.ManagementFactory");
119     private static LazyClass sThreadMxClazz = new LazyClass("java.lang.management.ThreadMXBean");
120     private static LazyClass sRuntimeMxClazz = new LazyClass("java.lang.management.RuntimeMXBean");
121     private static LazyClass sMemoryMxClazz = new LazyClass("java.lang.management.MemoryMXBean");
122     private static LazyClass sMemoryUsageClazz = new LazyClass("java.lang.management.MemoryUsage");
123 
124     private static LazyMethod<Object> sRuntimeMxGetter = new LazyMethod<>(sFactoryClazz, "getRuntimeMXBean");
125     private static LazyMethod<Object> sThreadMxGetter = new LazyMethod<>(sFactoryClazz, "getThreadMXBean");
126     private static LazyMethod<Object> sMemoryMxGetter = new LazyMethod<>(sFactoryClazz, "getMemoryMXBean");
127 
128     // RuntimeMxBean functions
129     private static LazyMethod<List<String>> sGetInputArguments = new LazyMethod<>(sRuntimeMxClazz, "getInputArguments");
130 
131     /** This corresponds to RuntimeMxBean.getInputArguments() */
getVmArguments()132     public static List<String> getVmArguments() {
133         return sGetInputArguments.invoke(sRuntimeMxGetter.invokeOnce(null));
134     }
135 
136     // ThreadMxBean functions
137     private static LazyMethod<Long> sUserTime = new LazyMethod<>(sThreadMxClazz, "getCurrentThreadUserTime", 0L);
138     private static LazyMethod<Long> sCpuTime = new LazyMethod<>(sThreadMxClazz, "getCurrentThreadCpuTime", 0L);
139 
140     /** This corresponds to ThreadMxBean.getCurrentThreadUserTime() */
getUserTimeNano()141     public static long getUserTimeNano() {
142         return sUserTime.invoke(sThreadMxGetter.invokeOnce(null));
143     }
144 
145     /** This corresponds to ThreadMxBean.getCurrentThreadCpuTime() */
getCpuTimeNano()146     public static long getCpuTimeNano() {
147         return sCpuTime.invoke(sThreadMxGetter.invokeOnce(null));
148     }
149 
150     // MemoryMxBean functions
151 
152     /** Corresponds to java.lang.management.MemoryUsage */
153     public static final class MemoryUsage {
154         public final long init;
155         public final long used;
156         public final long committed;
157         public final long max;
158 
MemoryUsage(long init, long used, long committed, long max)159         public MemoryUsage(long init, long used, long committed, long max) {
160             this.init = init;
161             this.used = used;
162             this.committed = committed;
163             this.max = max;
164         }
165     }
166 
167     // This returns a java.lang.management.MemoryUsage instance.
168     private static LazyMethod<Object> sGetHeapMemoryUsage = new LazyMethod<>(sMemoryMxClazz, "getHeapMemoryUsage");
169     private static LazyMethod<Long> sGetInitMemory = new LazyMethod<>(sMemoryUsageClazz, "getInit", 0L);
170     private static LazyMethod<Long> sGetUsedMemory = new LazyMethod<>(sMemoryUsageClazz, "getUsed", 0L);
171     private static LazyMethod<Long> sGetCommittedMemory = new LazyMethod<>(sMemoryUsageClazz, "getCommitted", 0L);
172     private static LazyMethod<Long> sGetMaxMemory = new LazyMethod<>(sMemoryUsageClazz, "getMax", 0L);
173 
174     /** Corresponds to java.lang.management.MemoryUsage.getHeapMemoryUsage() */
getHeapUsage()175     public static MemoryUsage getHeapUsage() {
176         final Object heapUsage = sGetHeapMemoryUsage.invoke(sMemoryMxGetter.invokeOnce(null));
177 
178         return new MemoryUsage(
179             sGetInitMemory.invoke(heapUsage),
180             sGetUsedMemory.invoke(heapUsage),
181             sGetCommittedMemory.invoke(heapUsage),
182             sGetMaxMemory.invoke(heapUsage)
183         );
184     }
185 }
186