1 /* 2 * Copyright (C) 2023 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 android.os; 18 19 import android.ravenwood.annotation.RavenwoodKeepWholeClass; 20 21 import java.util.Map; 22 import java.util.concurrent.ConcurrentHashMap; 23 import java.util.concurrent.atomic.AtomicLong; 24 25 @RavenwoodKeepWholeClass 26 class MessageQueue_ravenwood { 27 private static final AtomicLong sNextId = new AtomicLong(1); 28 private static final Map<Long, MessageQueue_ravenwood> sInstances = new ConcurrentHashMap<>(); 29 30 private boolean mDeleted = false; 31 32 private final Object mPoller = new Object(); 33 private volatile boolean mPolling; 34 private volatile boolean mPendingWake; 35 validate()36 private void validate() { 37 if (mDeleted) { 38 // TODO: Put more info 39 throw new RuntimeException("MessageQueue already destroyed"); 40 } 41 } 42 getInstance(long id)43 private static MessageQueue_ravenwood getInstance(long id) { 44 MessageQueue_ravenwood q = sInstances.get(id); 45 if (q == null) { 46 throw new RuntimeException("MessageQueue doesn't exist with id=" + id); 47 } 48 q.validate(); 49 return q; 50 } 51 nativeInit()52 public static long nativeInit() { 53 final long id = sNextId.getAndIncrement(); 54 final MessageQueue_ravenwood q = new MessageQueue_ravenwood(); 55 sInstances.put(id, q); 56 return id; 57 } 58 nativeDestroy(long ptr)59 public static void nativeDestroy(long ptr) { 60 getInstance(ptr).mDeleted = true; 61 sInstances.remove(ptr); 62 } 63 nativePollOnce(android.os.MessageQueue queue, long ptr, int timeoutMillis)64 public static void nativePollOnce(android.os.MessageQueue queue, long ptr, int timeoutMillis) { 65 var q = getInstance(ptr); 66 synchronized (q.mPoller) { 67 q.mPolling = true; 68 try { 69 if (q.mPendingWake) { 70 // Calling with pending wake returns immediately 71 } else if (timeoutMillis == 0) { 72 // Calling epoll_wait() with 0 returns immediately 73 } else if (timeoutMillis == -1) { 74 q.mPoller.wait(); 75 } else { 76 q.mPoller.wait(timeoutMillis); 77 } 78 } catch (InterruptedException e) { 79 Thread.currentThread().interrupt(); 80 } 81 // Any reason for returning counts as a "wake", so clear pending 82 q.mPendingWake = false; 83 q.mPolling = false; 84 } 85 } 86 nativeWake(long ptr)87 public static void nativeWake(long ptr) { 88 var q = getInstance(ptr); 89 synchronized (q.mPoller) { 90 q.mPendingWake = true; 91 q.mPoller.notifyAll(); 92 } 93 } 94 nativeIsPolling(long ptr)95 public static boolean nativeIsPolling(long ptr) { 96 var q = getInstance(ptr); 97 return q.mPolling; 98 } 99 nativeSetFileDescriptorEvents(long ptr, int fd, int events)100 public static void nativeSetFileDescriptorEvents(long ptr, int fd, int events) { 101 throw new UnsupportedOperationException(); 102 } 103 } 104