• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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 package libcore.util;
17 
18 import com.android.ravenwood.RavenwoodRuntimeNative;
19 
20 import java.lang.ref.Cleaner;
21 import java.lang.ref.Reference;
22 
23 /**
24  * Re-implementation of ART's NativeAllocationRegistry for Ravenwood.
25  * - We don't track the native allocation size on Ravenwood.
26  * - sun.misc.Cleaner isn't available on the desktop JVM, so we use java.lang.ref.Cleaner.
27  *   (Should ART switch to java.lang.ref.Cleaner?)
28  */
29 public class NativeAllocationRegistry {
30     private final long mFreeFunction;
31     private static final Cleaner sCleaner = Cleaner.create();
32 
createNonmalloced( ClassLoader classLoader, long freeFunction, long size)33     public static NativeAllocationRegistry createNonmalloced(
34             ClassLoader classLoader, long freeFunction, long size) {
35         return new NativeAllocationRegistry(classLoader, freeFunction, size);
36     }
37 
createNonmalloced( Class clazz, long freeFunction, long size)38     public static NativeAllocationRegistry createNonmalloced(
39             Class clazz, long freeFunction, long size) {
40         return new NativeAllocationRegistry(clazz.getClassLoader(), freeFunction, size);
41     }
42 
createMalloced( ClassLoader classLoader, long freeFunction, long size)43     public static NativeAllocationRegistry createMalloced(
44             ClassLoader classLoader, long freeFunction, long size) {
45         return new NativeAllocationRegistry(classLoader, freeFunction, size);
46     }
47 
createMalloced( ClassLoader classLoader, long freeFunction)48     public static NativeAllocationRegistry createMalloced(
49             ClassLoader classLoader, long freeFunction) {
50         return new NativeAllocationRegistry(classLoader, freeFunction, 0);
51     }
52 
createMalloced( Class clazz, long freeFunction, long size)53     public static NativeAllocationRegistry createMalloced(
54             Class clazz, long freeFunction, long size) {
55         return new NativeAllocationRegistry(clazz.getClassLoader(), freeFunction, size);
56     }
57 
NativeAllocationRegistry(ClassLoader classLoader, long freeFunction, long size)58     public NativeAllocationRegistry(ClassLoader classLoader, long freeFunction, long size) {
59         if (size < 0) {
60             throw new IllegalArgumentException("Invalid native allocation size: " + size);
61         }
62         mFreeFunction = freeFunction;
63     }
64 
65     private class CleanerThunk implements Runnable {
66         private long nativePtr;
67 
CleanerThunk()68         public CleanerThunk() {
69             nativePtr = 0;
70         }
71 
setNativePtr(long ptr)72         public void setNativePtr(long ptr) {
73             nativePtr = ptr;
74         }
75 
76         @Override
run()77         public void run() {
78             if (nativePtr != 0) {
79                 applyFreeFunction(mFreeFunction, nativePtr);
80             }
81         }
82     }
83 
84     private static class CleanableRunner implements Runnable {
85         private final Cleaner.Cleanable mCleanable;
86 
CleanableRunner(Cleaner.Cleanable cleanable)87         public CleanableRunner(Cleaner.Cleanable cleanable) {
88             mCleanable = cleanable;
89         }
90 
run()91         public void run() {
92             mCleanable.clean();
93         }
94     }
95 
registerNativeAllocation(Object referent, long nativePtr)96     public Runnable registerNativeAllocation(Object referent, long nativePtr) {
97         if (referent == null) {
98             throw new IllegalArgumentException("referent is null");
99         }
100         if (mFreeFunction == 0) {
101             return () -> {}; // do nothing
102         }
103         if (nativePtr == 0) {
104             throw new IllegalArgumentException("nativePtr is null");
105         }
106 
107         final CleanerThunk thunk;
108         final CleanableRunner result;
109         try {
110             thunk = new CleanerThunk();
111             final var cleanable = sCleaner.register(referent, thunk);
112             result = new CleanableRunner(cleanable);
113         } catch (VirtualMachineError vme /* probably OutOfMemoryError */) {
114             applyFreeFunction(mFreeFunction, nativePtr);
115             throw vme;
116         }
117 
118         // Enable the cleaner only after we can no longer throw anything, including OOME.
119         thunk.setNativePtr(nativePtr);
120         // Ensure that cleaner doesn't get invoked before we enable it.
121         Reference.reachabilityFence(referent);
122         return result;
123     }
124 
applyFreeFunction(long freeFunction, long nativePtr)125     public static void applyFreeFunction(long freeFunction, long nativePtr) {
126         RavenwoodRuntimeNative.applyFreeFunction(freeFunction, nativePtr);
127     }
128 }
129