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