• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2022 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 #define LOG_TAG "VirtualizationService"
18 
19 #include <android-base/unique_fd.h>
20 #include <android/binder_ibinder_jni.h>
21 #include <jni.h>
22 #include <log/log.h>
23 #include <poll.h>
24 
25 #include <string>
26 
27 #include "common.h"
28 
29 using namespace android::base;
30 
31 static constexpr const char VIRTMGR_PATH[] = "/apex/com.android.virt/bin/virtmgr";
32 static constexpr size_t VIRTMGR_THREADS = 2;
33 
34 extern "C" JNIEXPORT jint JNICALL
Java_android_system_virtualmachine_VirtualizationService_nativeSpawn(JNIEnv * env,jclass clazz)35 Java_android_system_virtualmachine_VirtualizationService_nativeSpawn(
36         JNIEnv* env, [[maybe_unused]] jclass clazz) {
37     unique_fd serverFd, clientFd;
38     if (!Socketpair(SOCK_STREAM, &serverFd, &clientFd)) {
39         env->ThrowNew(env->FindClass("android/system/virtualmachine/VirtualMachineException"),
40                       ("Failed to create socketpair: " + std::string(strerror(errno))).c_str());
41         return -1;
42     }
43 
44     unique_fd waitFd, readyFd;
45     if (!Pipe(&waitFd, &readyFd, 0)) {
46         env->ThrowNew(env->FindClass("android/system/virtualmachine/VirtualMachineException"),
47                       ("Failed to create pipe: " + std::string(strerror(errno))).c_str());
48         return -1;
49     }
50 
51     if (fork() == 0) {
52         // Close client's FDs.
53         clientFd.reset();
54         waitFd.reset();
55 
56         auto strServerFd = std::to_string(serverFd.get());
57         auto strReadyFd = std::to_string(readyFd.get());
58 
59         execl(VIRTMGR_PATH, VIRTMGR_PATH, "--rpc-server-fd", strServerFd.c_str(), "--ready-fd",
60               strReadyFd.c_str(), NULL);
61     }
62 
63     // Close virtmgr's FDs.
64     serverFd.reset();
65     readyFd.reset();
66 
67     // Wait for the server to signal its readiness by closing its end of the pipe.
68     char buf;
69     if (read(waitFd.get(), &buf, sizeof(buf)) < 0) {
70         env->ThrowNew(env->FindClass("android/system/virtualmachine/VirtualMachineException"),
71                       "Failed to wait for VirtualizationService to be ready");
72         return -1;
73     }
74 
75     return clientFd.release();
76 }
77 
78 extern "C" JNIEXPORT jobject JNICALL
Java_android_system_virtualmachine_VirtualizationService_nativeConnect(JNIEnv * env,jobject obj,int clientFd)79 Java_android_system_virtualmachine_VirtualizationService_nativeConnect(JNIEnv* env,
80                                                                        [[maybe_unused]] jobject obj,
81                                                                        int clientFd) {
82     RpcSessionHandle session;
83     ARpcSession_setFileDescriptorTransportMode(session.get(),
84                                                ARpcSession_FileDescriptorTransportMode::Unix);
85     ARpcSession_setMaxIncomingThreads(session.get(), VIRTMGR_THREADS);
86     // SAFETY - ARpcSession_setupUnixDomainBootstrapClient does not take ownership of clientFd.
87     auto client = ARpcSession_setupUnixDomainBootstrapClient(session.get(), clientFd);
88     return AIBinder_toJavaBinder(env, client);
89 }
90 
91 extern "C" JNIEXPORT jboolean JNICALL
Java_android_system_virtualmachine_VirtualizationService_nativeIsOk(JNIEnv * env,jobject obj,int clientFd)92 Java_android_system_virtualmachine_VirtualizationService_nativeIsOk(JNIEnv* env,
93                                                                     [[maybe_unused]] jobject obj,
94                                                                     int clientFd) {
95     /* Setting events=0 only returns POLLERR, POLLHUP or POLLNVAL. */
96     struct pollfd pfds[] = {{.fd = clientFd, .events = 0}};
97     if (poll(pfds, /*nfds*/ 1, /*timeout*/ 0) < 0) {
98         env->ThrowNew(env->FindClass("android/system/virtualmachine/VirtualMachineException"),
99                       ("Failed to poll client FD: " + std::string(strerror(errno))).c_str());
100         return false;
101     }
102     return pfds[0].revents == 0;
103 }
104