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