blob: 890a1cbfd0f55dd57de594c8d5d3f8eff85c325c [file] [log] [blame]
/*
* 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 <errno.h>
#include <log/log.h>
#include <pthread.h>
#include <qemu_pipe_bp.h>
#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<std::mutex> 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<std::mutex> 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;
}