Bug 1529105 - Replace tmpname in OpenVRSession when using action input. r=kip
authorDaosheng Mu <daoshengmu@gmail.com>
Mon, 22 Apr 2019 20:41:38 +0000
changeset 470411 bb714fa13ef971094987d7b37363f7a45732914b
parent 470410 b3ff6570a179d4fdcc9ffce068f20d45be05cc44
child 470412 abcd7426fb63f078b3d5e2566c28baa1dd923616
push id35905
push userdvarga@mozilla.com
push dateTue, 23 Apr 2019 09:53:27 +0000
treeherdermozilla-central@831918f009f6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskip
bugs1529105
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1529105 - Replace tmpname in OpenVRSession when using action input. r=kip Differential Revision: https://phabricator.services.mozilla.com/D28136
gfx/vr/service/OpenVRSession.cpp
gfx/vr/service/OpenVRSession.h
--- a/gfx/vr/service/OpenVRSession.cpp
+++ b/gfx/vr/service/OpenVRSession.cpp
@@ -14,16 +14,20 @@
 
 #if defined(XP_WIN)
 #  include <d3d11.h>
 #  include "mozilla/gfx/DeviceManagerDx.h"
 #elif defined(XP_MACOSX)
 #  include "mozilla/gfx/MacIOSurface.h"
 #endif
 
+#if !defined(XP_WIN)
+#  include <sys/stat.h>  // for umask()
+#endif
+
 #include "mozilla/dom/GamepadEventTypes.h"
 #include "mozilla/dom/GamepadBinding.h"
 #include "binding/OpenVRKnucklesBinding.h"
 #include "binding/OpenVRViveBinding.h"
 #if defined(XP_WIN)  // Windows Mixed Reality is only available in Windows.
 #  include "binding/OpenVRWMRBinding.h"
 #endif
 
@@ -48,36 +52,35 @@ using namespace mozilla::gfx;
 
 namespace mozilla {
 namespace gfx {
 
 namespace {
 
 // This is for controller action file writer.
 struct StringWriteFunc : public JSONWriteFunc {
-  nsAString& mBuffer;  // This struct must not outlive this buffer
-
-  explicit StringWriteFunc(nsAString& buffer) : mBuffer(buffer) {}
+  nsACString& mBuffer;  // This struct must not outlive this buffer
 
-  void Write(const char* aStr) override {
-    mBuffer.Append(NS_ConvertUTF8toUTF16(aStr));
-  }
+  explicit StringWriteFunc(nsACString& buffer) : mBuffer(buffer) {}
+
+  void Write(const char* aStr) override { mBuffer.Append(aStr); }
 };
 
 class ControllerManifestFile {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ControllerManifestFile)
 
  public:
   static already_AddRefed<ControllerManifestFile> CreateManifest() {
     RefPtr<ControllerManifestFile> manifest = new ControllerManifestFile();
     return manifest.forget();
   }
 
   bool IsExisting() {
-    if (mFileName.IsEmpty() || !std::ifstream(mFileName.BeginReading())) {
+    if (mFileName.IsEmpty() ||
+        !std::ifstream(mFileName.BeginReading()).good()) {
       return false;
     }
     return true;
   }
 
   void SetFileName(const char* aName) { mFileName = aName; }
 
   const char* GetFileName() const { return mFileName.BeginReading(); }
@@ -167,24 +170,70 @@ void UpdateButton(VRControllerState& aSt
     aState.buttonTouched &= ~mask;
   } else {
     // touched
     aState.buttonTouched |= mask;
   }
 }
 
 bool FileIsExisting(const nsCString& aPath) {
-  if (aPath.IsEmpty() || !std::ifstream(aPath.BeginReading())) {
+  if (aPath.IsEmpty() || !std::ifstream(aPath.BeginReading()).good()) {
     return false;
   }
   return true;
 }
 
 };  // anonymous namespace
 
+#if defined(XP_WIN)
+bool GenerateTempFileName(nsCString& aPath) {
+  TCHAR tempPathBuffer[MAX_PATH];
+  TCHAR tempFileName[MAX_PATH];
+
+  // Gets the temp path env string (no guarantee it's a valid path).
+  DWORD dwRetVal = GetTempPath(MAX_PATH, tempPathBuffer);
+  if (dwRetVal > MAX_PATH || (dwRetVal == 0)) {
+    NS_WARNING("OpenVR - Creating temp path failed.");
+    return false;
+  }
+
+  // Generates a temporary file name.
+  UINT uRetVal = GetTempFileName(tempPathBuffer,  // directory for tmp files
+                                 TEXT("mozvr"),   // temp file name prefix
+                                 0,               // create unique name
+                                 tempFileName);   // buffer for name
+  if (uRetVal == 0) {
+    NS_WARNING("OpenVR - Creating temp file failed.");
+    return false;
+  }
+
+  aPath.Assign(NS_ConvertUTF16toUTF8(tempFileName));
+  return true;
+}
+#else
+bool GenerateTempFileName(nsCString& aPath) {
+  const char tmp[] = "/tmp/mozvrXXXXXX";
+  char fileName[PATH_MAX];
+
+  strcpy(fileName, tmp);
+  const mode_t prevMask = umask(S_IXUSR | S_IRWXO | S_IRWXG);
+  const int fd = mkstemp(fileName);
+  umask(prevMask);
+  if (fd == -1) {
+    NS_WARNING(nsPrintfCString("OpenVR - Creating temp file failed: %s",
+                               strerror(errno)).get());
+    return false;
+  }
+  close(fd);
+
+  aPath.Assign(fileName);
+  return true;
+}
+#endif  // defined(XP_WIN)
+
 OpenVRSession::OpenVRSession()
     : VRSession(),
       mVRSystem(nullptr),
       mVRChaperone(nullptr),
       mVRCompositor(nullptr),
       mControllerDeviceIndexObsolete{},
       mHapticPulseRemaining{},
       mHapticPulseIntensity{},
@@ -251,127 +300,136 @@ bool OpenVRSession::Initialize(mozilla::
   // Configure coordinate system
   mVRCompositor->SetTrackingSpace(::vr::TrackingUniverseSeated);
 
   if (!InitState(aSystemState)) {
     Shutdown();
     return false;
   }
 
-  if (gfxPrefs::VROpenVRActionInputEnabled()) {
-    SetupContollerActions();
+  if (gfxPrefs::VROpenVRActionInputEnabled() && !SetupContollerActions()) {
+    return false;
   }
 
   NS_DispatchToMainThread(NS_NewRunnableFunction(
       "OpenVRSession::StartHapticThread", [this]() { StartHapticThread(); }));
 
   // Succeeded
   return true;
 }
 
-void OpenVRSession::SetupContollerActions() {
+bool OpenVRSession::SetupContollerActions() {
   // Check if this device binding file has been created.
   // If it didn't exist yet, create a new temp file.
   nsCString controllerAction;
   nsCString viveManifest;
   nsCString WMRManifest;
   nsCString knucklesManifest;
 
+  // Getting / Generating manifest file paths.
   if (gfxPrefs::VRProcessEnabled()) {
     VRParent* vrParent = VRProcessChild::GetVRParent();
     nsCString output;
 
     if (vrParent->GetOpenVRControllerActionPath(&output)) {
       controllerAction = output;
-    } else {
-      controllerAction = std::tmpnam(nullptr);
     }
 
     if (vrParent->GetOpenVRControllerManifestPath(OpenVRControllerType::Vive,
                                                   &output)) {
       viveManifest = output;
-    } else {
-      viveManifest = std::tmpnam(nullptr);
     }
-    if (!FileIsExisting(viveManifest)) {
+    if (!viveManifest.Length() || !FileIsExisting(viveManifest)) {
+      if (!GenerateTempFileName(viveManifest)) {
+        return false;
+      }
       OpenVRViveBinding viveBinding;
       std::ofstream viveBindingFile(viveManifest.BeginReading());
       if (viveBindingFile.is_open()) {
         viveBindingFile << viveBinding.binding;
         viveBindingFile.close();
       }
     }
 
 #if defined(XP_WIN)
     if (vrParent->GetOpenVRControllerManifestPath(OpenVRControllerType::WMR,
                                                   &output)) {
       WMRManifest = output;
-    } else {
-      WMRManifest = std::tmpnam(nullptr);
     }
-    if (!FileIsExisting(WMRManifest)) {
+    if (!WMRManifest.Length() || !FileIsExisting(WMRManifest)) {
+      if (!GenerateTempFileName(WMRManifest)) {
+        return false;
+      }
       OpenVRWMRBinding WMRBinding;
       std::ofstream WMRBindingFile(WMRManifest.BeginReading());
       if (WMRBindingFile.is_open()) {
         WMRBindingFile << WMRBinding.binding;
         WMRBindingFile.close();
       }
     }
 #endif
 
     if (vrParent->GetOpenVRControllerManifestPath(
             OpenVRControllerType::Knuckles, &output)) {
       knucklesManifest = output;
-    } else {
-      knucklesManifest = std::tmpnam(nullptr);
     }
-    if (!FileIsExisting(knucklesManifest)) {
+    if (!knucklesManifest.Length() || !FileIsExisting(knucklesManifest)) {
+      if (!GenerateTempFileName(knucklesManifest)) {
+        return false;
+      }
       OpenVRKnucklesBinding knucklesBinding;
       std::ofstream knucklesBindingFile(knucklesManifest.BeginReading());
       if (knucklesBindingFile.is_open()) {
         knucklesBindingFile << knucklesBinding.binding;
         knucklesBindingFile.close();
       }
     }
   } else {
+    // Without using VR process
     if (!sControllerActionFile) {
       sControllerActionFile = ControllerManifestFile::CreateManifest();
       NS_DispatchToMainThread(NS_NewRunnableFunction(
           "ClearOnShutdown ControllerManifestFile",
           []() { ClearOnShutdown(&sControllerActionFile); }));
-
-      sControllerActionFile->SetFileName(std::tmpnam(nullptr));
     }
     controllerAction = sControllerActionFile->GetFileName();
 
     if (!sViveBindingFile) {
       sViveBindingFile = ControllerManifestFile::CreateManifest();
       NS_DispatchToMainThread(
           NS_NewRunnableFunction("ClearOnShutdown ControllerManifestFile",
                                  []() { ClearOnShutdown(&sViveBindingFile); }));
     }
     if (!sViveBindingFile->IsExisting()) {
-      sViveBindingFile->SetFileName(std::tmpnam(nullptr));
+      nsCString viveBindingPath;
+      if (!GenerateTempFileName(viveBindingPath)) {
+        return false;
+      }
+      sViveBindingFile->SetFileName(viveBindingPath.BeginReading());
       OpenVRViveBinding viveBinding;
       std::ofstream viveBindingFile(sViveBindingFile->GetFileName());
       if (viveBindingFile.is_open()) {
         viveBindingFile << viveBinding.binding;
         viveBindingFile.close();
       }
     }
     viveManifest = sViveBindingFile->GetFileName();
 
     if (!sKnucklesBindingFile) {
       sKnucklesBindingFile = ControllerManifestFile::CreateManifest();
       NS_DispatchToMainThread(NS_NewRunnableFunction(
           "ClearOnShutdown ControllerManifestFile",
           []() { ClearOnShutdown(&sKnucklesBindingFile); }));
     }
     if (!sKnucklesBindingFile->IsExisting()) {
-      sKnucklesBindingFile->SetFileName(std::tmpnam(nullptr));
+      nsCString knucklesBindingPath;
+      if (!GenerateTempFileName(knucklesBindingPath)) {
+        return false;
+      }
+      sKnucklesBindingFile->SetFileName(knucklesBindingPath.BeginReading());
       OpenVRKnucklesBinding knucklesBinding;
       std::ofstream knucklesBindingFile(sKnucklesBindingFile->GetFileName());
       if (knucklesBindingFile.is_open()) {
         knucklesBindingFile << knucklesBinding.binding;
         knucklesBindingFile.close();
       }
     }
     knucklesManifest = sKnucklesBindingFile->GetFileName();
@@ -379,28 +437,34 @@ void OpenVRSession::SetupContollerAction
 #if defined(XP_WIN)
     if (!sWMRBindingFile) {
       sWMRBindingFile = ControllerManifestFile::CreateManifest();
       NS_DispatchToMainThread(
           NS_NewRunnableFunction("ClearOnShutdown ControllerManifestFile",
                                  []() { ClearOnShutdown(&sWMRBindingFile); }));
     }
     if (!sWMRBindingFile->IsExisting()) {
-      sWMRBindingFile->SetFileName(std::tmpnam(nullptr));
+      nsCString WMRBindingPath;
+      if (!GenerateTempFileName(WMRBindingPath)) {
+        return false;
+      }
+      sWMRBindingFile->SetFileName(WMRBindingPath.BeginReading());
       OpenVRWMRBinding WMRBinding;
       std::ofstream WMRBindingFile(sWMRBindingFile->GetFileName());
       if (WMRBindingFile.is_open()) {
         WMRBindingFile << WMRBinding.binding;
         WMRBindingFile.close();
       }
     }
     WMRManifest = sWMRBindingFile->GetFileName();
 #endif
   }
+  // End of Getting / Generating manifest file paths.
 
+  // Setup controller actions.
   ControllerInfo leftContollerInfo;
   leftContollerInfo.mActionPose =
       ControllerAction("/actions/firefox/in/LHand_pose", "pose");
   leftContollerInfo.mActionHaptic =
       ControllerAction("/actions/firefox/out/LHand_haptic", "vibration");
   leftContollerInfo.mActionTrackpad_Analog =
       ControllerAction("/actions/firefox/in/LHand_trackpad_analog", "vector2");
   leftContollerInfo.mActionTrackpad_Pressed =
@@ -490,18 +554,21 @@ void OpenVRSession::SetupContollerAction
   rightContollerInfo.mActionFingerRing_Value = ControllerAction(
       "/actions/firefox/in/RHand_finger_ring_value", "vector1");
   rightContollerInfo.mActionFingerPinky_Value = ControllerAction(
       "/actions/firefox/in/RHand_finger_pinky_value", "vector1");
 
   mControllerHand[OpenVRHand::Left] = leftContollerInfo;
   mControllerHand[OpenVRHand::Right] = rightContollerInfo;
 
-  if (!FileIsExisting(controllerAction)) {
-    nsAutoString actionData;
+  if (!controllerAction.Length() || !FileIsExisting(controllerAction)) {
+    if (!GenerateTempFileName(controllerAction)) {
+      return false;
+    }
+    nsCString actionData;
     JSONWriter actionWriter(MakeUnique<StringWriteFunc>(actionData));
     actionWriter.Start();
 
     actionWriter.StringProperty("version",
                                 "0.1.0");  // TODO: adding a version check.
     // "default_bindings": []
     actionWriter.StartArrayProperty("default_bindings");
     actionWriter.StartObjectElement();
@@ -685,41 +752,46 @@ void OpenVRSession::SetupContollerAction
       actionWriter.StringProperty("type",
                                   controller.mActionHaptic.type.BeginReading());
       actionWriter.EndObject();
     }
     actionWriter.EndArray();  // End "actions": []
     actionWriter.End();
 
     std::ofstream actionfile(controllerAction.BeginReading());
-    nsCString actionResult(NS_ConvertUTF16toUTF8(actionData.get()));
+    nsCString actionResult(actionData.get());
     if (actionfile.is_open()) {
       actionfile << actionResult.get();
       actionfile.close();
     }
   }
 
   vr::VRInput()->SetActionManifestPath(controllerAction.BeginReading());
+  // End of setup controller actions.
 
   // Notify the parent process these manifest files are already been recorded.
   if (gfxPrefs::VRProcessEnabled()) {
     NS_DispatchToMainThread(NS_NewRunnableFunction(
         "SendOpenVRControllerActionPathToParent",
         [controllerAction, viveManifest, WMRManifest, knucklesManifest]() {
           VRParent* vrParent = VRProcessChild::GetVRParent();
           Unused << vrParent->SendOpenVRControllerActionPathToParent(
               controllerAction);
           Unused << vrParent->SendOpenVRControllerManifestPathToParent(
               OpenVRControllerType::Vive, viveManifest);
           Unused << vrParent->SendOpenVRControllerManifestPathToParent(
               OpenVRControllerType::WMR, WMRManifest);
           Unused << vrParent->SendOpenVRControllerManifestPathToParent(
               OpenVRControllerType::Knuckles, knucklesManifest);
         }));
+  } else {
+    sControllerActionFile->SetFileName(controllerAction.BeginReading());
   }
+
+  return true;
 }
 
 #if defined(XP_WIN)
 bool OpenVRSession::CreateD3DObjects() {
   RefPtr<ID3D11Device> device = gfx::DeviceManagerDx::Get()->GetVRDevice();
   if (!device) {
     return false;
   }
--- a/gfx/vr/service/OpenVRSession.h
+++ b/gfx/vr/service/OpenVRSession.h
@@ -124,17 +124,17 @@ class OpenVRSession : public VRSession {
   void UpdateHeadsetPose(mozilla::gfx::VRSystemState& aState);
   void EnumerateControllers(VRSystemState& aState);
   void EnumerateControllersObsolete(VRSystemState& aState);
   void UpdateControllerPoses(VRSystemState& aState);
   void UpdateControllerPosesObsolete(VRSystemState& aState);
   void UpdateControllerButtons(VRSystemState& aState);
   void UpdateControllerButtonsObsolete(VRSystemState& aState);
   void UpdateTelemetry(VRSystemState& aSystemState);
-  void SetupContollerActions();
+  bool SetupContollerActions();
 
   bool SubmitFrame(const VRLayerTextureHandle& aTextureHandle,
                    ::vr::ETextureType aTextureType,
                    const VRLayerEyeRect& aLeftEyeRect,
                    const VRLayerEyeRect& aRightEyeRect);
 #if defined(XP_WIN)
   bool CreateD3DObjects();
 #endif