1 /*
2  * Copyright (C) 2013 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 import java.lang.reflect.*;
18 import java.lang.Runtime;
19 
20 public class Main {
21     static Object nativeLock = new Object();
22     static Object deadlockLock = new Object();
23     static boolean aboutToDeadlockLock = false;
24     static int nativeBytes = 0;
25     static Object runtime;
26     static Method register_native_allocation;
27     static Method register_native_free;
28     static long maxMem = 0;
29 
30     static class NativeAllocation {
31         private int bytes;
32 
NativeAllocation(int bytes, boolean testingDeadlock)33         NativeAllocation(int bytes, boolean testingDeadlock) throws Exception {
34             this.bytes = bytes;
35             register_native_allocation.invoke(runtime, bytes);
36             synchronized (nativeLock) {
37                 if (!testingDeadlock) {
38                     nativeBytes += bytes;
39                     if (nativeBytes > maxMem) {
40                         throw new OutOfMemoryError();
41                     }
42                 }
43             }
44         }
45 
finalize()46         protected void finalize() throws Exception {
47             synchronized (nativeLock) {
48                 nativeBytes -= bytes;
49             }
50             register_native_free.invoke(runtime, bytes);
51             aboutToDeadlockLock = true;
52             synchronized (deadlockLock) {
53             }
54         }
55     }
56 
main(String[] args)57     public static void main(String[] args) throws Exception {
58         Class<?> vm_runtime = Class.forName("dalvik.system.VMRuntime");
59         Method get_runtime = vm_runtime.getDeclaredMethod("getRuntime");
60         runtime = get_runtime.invoke(null);
61         register_native_allocation = vm_runtime.getDeclaredMethod("registerNativeAllocation", Integer.TYPE);
62         register_native_free = vm_runtime.getDeclaredMethod("registerNativeFree", Integer.TYPE);
63         maxMem = Runtime.getRuntime().maxMemory();
64         int count = 16;
65         int size = (int)(maxMem / 2 / count);
66         int allocation_count = 256;
67         NativeAllocation[] allocations = new NativeAllocation[count];
68         for (int i = 0; i < allocation_count; ++i) {
69             allocations[i % count] = new NativeAllocation(size, false);
70         }
71         // Test that we don't get a deadlock if we are holding nativeLock. If there is no timeout,
72         // then we will get a finalizer timeout exception.
73         aboutToDeadlockLock = false;
74         synchronized (deadlockLock) {
75             for (int i = 0; aboutToDeadlockLock != true; ++i) {
76                 allocations[i % count] = new NativeAllocation(size, true);
77             }
78             // Do more allocations now that the finalizer thread is deadlocked so that we force
79             // finalization and timeout.
80             for (int i = 0; i < 10; ++i) {
81                 allocations[i % count] = new NativeAllocation(size, true);
82             }
83         }
84         System.out.println("Test complete");
85     }
86 }
87 
88