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 
17 package libcore.util;
18 
19 import com.android.layoutlib.bridge.impl.DelegateManager;
20 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
21 
22 import libcore.util.NativeAllocationRegistry.CleanerRunner;
23 import libcore.util.NativeAllocationRegistry.CleanerThunk;
24 import sun.misc.Cleaner;
25 
26 /**
27  * Delegate implementing the native methods of {@link NativeAllocationRegistry}
28  *
29  * Through the layoutlib_create tool, the original native methods of NativeAllocationRegistry have
30  * been replaced by calls to methods of the same name in this delegate class.
31  *
32  * This class behaves like the original native implementation, but in Java, keeping previously
33  * native data into its own objects and mapping them to int that are sent back and forth between
34  * it and the original NativeAllocationRegistry class.
35  *
36  * @see DelegateManager
37  */
38 public class NativeAllocationRegistry_Delegate {
39 
40     // ---- delegate manager ----
41     private static final DelegateManager<NativeAllocationRegistry_Delegate> sManager =
42             new DelegateManager<>(NativeAllocationRegistry_Delegate.class);
43 
44     private final FreeFunction mFinalizer;
45 
NativeAllocationRegistry_Delegate(FreeFunction finalizer)46     private NativeAllocationRegistry_Delegate(FreeFunction finalizer) {
47         mFinalizer = finalizer;
48     }
49 
50     /**
51      * The result of this method should be cached by the class and reused.
52      */
createFinalizer(FreeFunction finalizer)53     public static long createFinalizer(FreeFunction finalizer) {
54         return sManager.addNewDelegate(new NativeAllocationRegistry_Delegate(finalizer));
55     }
56 
57     @LayoutlibDelegate
registerNativeAllocation(long size)58     /*package*/ static void registerNativeAllocation(long size) {
59         NativeAllocationRegistry.registerNativeAllocation_Original(size);
60     }
61 
62     @LayoutlibDelegate
registerNativeAllocation(NativeAllocationRegistry registry, Object referent, long nativePtr)63     /*package*/ static Runnable registerNativeAllocation(NativeAllocationRegistry registry,
64             Object referent,
65             long nativePtr) {
66         // Mark the object as already "natively" tracked.
67         // This allows the DelegateManager to dispose objects without waiting
68         // for an explicit call when the referent does not exist anymore.
69         sManager.markAsNativeAllocation(referent, nativePtr);
70         if (referent == null) {
71             throw new IllegalArgumentException("referent is null");
72         }
73         if (nativePtr == 0) {
74             throw new IllegalArgumentException("nativePtr is null");
75         }
76 
77         CleanerThunk thunk;
78         CleanerRunner result;
79         try {
80             thunk = registry.new CleanerThunk();
81             Cleaner cleaner = Cleaner.create(referent, thunk);
82             result = new CleanerRunner(cleaner);
83             registerNativeAllocation(registry.size);
84         } catch (VirtualMachineError vme /* probably OutOfMemoryError */) {
85             applyFreeFunction(registry.freeFunction, nativePtr);
86             throw vme;
87         } // Other exceptions are impossible.
88         // Enable the cleaner only after we can no longer throw anything, including OOME.
89         thunk.setNativePtr(nativePtr);
90         // Needs to call Reference.reachabilityFence(referent) to ensure that cleaner doesn't
91         // get invoked before we enable it. Unfortunately impossible in OpenJDK 8.
92         return result;
93     }
94 
95     @LayoutlibDelegate
applyFreeFunction(long freeFunction, long nativePtr)96     /*package*/ static void applyFreeFunction(long freeFunction, long nativePtr) {
97         // This method MIGHT run in the context of the finalizer thread. If the delegate method
98         // crashes, it could bring down the VM. That's why we catch all the exceptions and ignore
99         // them.
100         try {
101             NativeAllocationRegistry_Delegate delegate = sManager.getDelegate(freeFunction);
102             if (delegate != null) {
103                 delegate.mFinalizer.free(nativePtr);
104             }
105         } catch (Throwable ignore) {
106         }
107     }
108 
109     public interface FreeFunction {
free(long nativePtr)110         void free(long nativePtr);
111     }
112 }
113