/* * Copyright (C) 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ProcessPipe.h" #include #include #include #include #include "HostConnection.h" #include "renderControl_enc.h" #ifndef __Fuchsia__ #include "VirtioGpuPipeStream.h" static VirtioGpuPipeStream* sVirtioGpuPipeStream = 0; static int sStreamHandle = -1; #endif // !__Fuchsia__ static QEMU_PIPE_HANDLE sProcPipe = 0; // sProcUID is a unique ID per process assigned by the host. // It is different from getpid(). static uint64_t sProcUID = 0; static HostConnectionType sConnType = HOST_CONNECTION_VIRTIO_GPU_PIPE; static uint32_t* sSeqnoPtr = 0; // Meant to be called only once per process. static void initSeqno(void) { // So why do we reinitialize here? It's for testing purposes only; // we have a unit test that exercise the case where this sequence // number is reset as a result of guest process kill. if (sSeqnoPtr) delete sSeqnoPtr; sSeqnoPtr = new uint32_t; *sSeqnoPtr = 0; } namespace { static std::mutex sNeedInitMutex; static bool sNeedInit = true; } // namespace #ifndef __Fuchsia__ static void sQemuPipeInit() { sProcPipe = qemu_pipe_open("GLProcessPipe"); if (!qemu_pipe_valid(sProcPipe)) { sProcPipe = 0; ALOGW("Process pipe failed"); return; } // Send a confirmation int to the host int32_t confirmInt = 100; if (qemu_pipe_write_fully(sProcPipe, &confirmInt, sizeof(confirmInt))) { // failed qemu_pipe_close(sProcPipe); sProcPipe = 0; ALOGW("Process pipe failed"); return; } // Ask the host for per-process unique ID if (qemu_pipe_read_fully(sProcPipe, &sProcUID, sizeof(sProcUID))) { qemu_pipe_close(sProcPipe); sProcPipe = 0; sProcUID = 0; ALOGW("Process pipe failed"); return; } } #endif // !__Fuchsia__ static void processPipeDoInit(uint32_t noRenderControlEnc) { initSeqno(); // No need to setup auxiliary pipe stream in this case if (noRenderControlEnc) return; #if defined(__Fuchsia__) // Note: sProcUID is not initialized. ALOGE("Fuchsia: requires noRenderControlEnc"); abort(); #else switch (sConnType) { // TODO: Move those over too case HOST_CONNECTION_QEMU_PIPE: case HOST_CONNECTION_ADDRESS_SPACE: sQemuPipeInit(); break; case HOST_CONNECTION_VIRTIO_GPU_PIPE: case HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE: { sVirtioGpuPipeStream = new VirtioGpuPipeStream(4096, sStreamHandle); sProcUID = sVirtioGpuPipeStream->initProcessPipe(); break; } } #endif } bool processPipeInit(int streamHandle, HostConnectionType connType, uint32_t noRenderControlEnc) { sConnType = connType; #ifndef __Fuchsia__ sStreamHandle = streamHandle; #endif // !__Fuchsia { std::lock_guard lock(sNeedInitMutex); if (sNeedInit) { sNeedInit = false; processPipeDoInit(noRenderControlEnc); if (noRenderControlEnc) { return true; } #ifndef __Fuchsia__ if (!sProcPipe && !sVirtioGpuPipeStream) { return false; } #endif } } return true; } uint64_t getPuid() { return sProcUID; } void processPipeRestart() { std::lock_guard lock(sNeedInitMutex); ALOGW("%s: restarting process pipe\n", __func__); bool isPipe = false; switch (sConnType) { // TODO: Move those over too case HOST_CONNECTION_QEMU_PIPE: case HOST_CONNECTION_ADDRESS_SPACE: isPipe = true; break; case HOST_CONNECTION_VIRTIO_GPU_PIPE: case HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE: { isPipe = false; break; } } sProcUID = 0; if (isPipe) { if (qemu_pipe_valid(sProcPipe)) { qemu_pipe_close(sProcPipe); sProcPipe = 0; } } else { #ifndef __Fuchsia__ if (sVirtioGpuPipeStream) { delete sVirtioGpuPipeStream; sVirtioGpuPipeStream = nullptr; } #endif } if (sConnType == HOST_CONNECTION_VIRTIO_GPU_PIPE || sConnType == HOST_CONNECTION_VIRTIO_GPU_ADDRESS_SPACE) { VirtGpuDevice::resetInstance(); } sNeedInit = true; } void refreshHostConnection() { HostConnection* hostConn = HostConnection::get(); ExtendedRCEncoderContext* rcEnc = hostConn->rcEncoder(); rcEnc->rcSetPuid(rcEnc, sProcUID); } uint32_t* getSeqnoPtrForProcess() { // It's assumed process pipe state has already been initialized. return sSeqnoPtr; }