Files
UnrealEngine/Engine/Source/Developer/Linux/LinuxTargetPlatformControls/Public/LinuxTargetDevice.h
2025-05-18 13:04:45 +08:00

224 lines
5.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Misc/Paths.h"
#include "HAL/FileManager.h"
#include "HAL/PlatformProcess.h"
#include "Interfaces/ITargetPlatform.h"
#include "Interfaces/ITargetDevice.h"
#include "Interfaces/TargetDeviceId.h"
#if PLATFORM_LINUX
#include <signal.h>
#include <pwd.h>
#endif // PLATFORM_LINUX
class IFileManager;
struct FProcHandle;
/**
* Type definition for shared pointers to instances of FLinuxTargetDevice.
*/
typedef TSharedPtr<class FLinuxTargetDevice, ESPMode::ThreadSafe> FLinuxTargetDevicePtr;
/**
* Type definition for shared references to instances of FLinuxTargetDevice.
*/
typedef TSharedRef<class FLinuxTargetDevice, ESPMode::ThreadSafe> FLinuxTargetDeviceRef;
/**
* Implements a Linux target device.
*/
class FLinuxTargetDevice
: public ITargetDevice
{
public:
/**
* Creates and initializes a new device for the specified target platform.
*
* @param InTargetPlatformControls - The target platform controls.
*/
FLinuxTargetDevice(const ITargetPlatformControls& InTargetPlatformControls, const FString& InDeviceName, TFunction<void()> InSavePlatformDevices)
: TargetPlatformControls(InTargetPlatformControls)
, DeviceName(InDeviceName)
, SavePlatformDevices(InSavePlatformDevices)
{ }
/**
* Minimal constructor for use with SteamDeck devices */
FLinuxTargetDevice(const ITargetPlatformControls& InTargetPlatformControls)
: FLinuxTargetDevice(InTargetPlatformControls, TEXT("UnknownName"), nullptr)
{ }
public:
virtual bool Connect( ) override
{
return true;
}
virtual void Disconnect( ) override
{ }
virtual ETargetDeviceTypes GetDeviceType( ) const override
{
return ETargetDeviceTypes::Desktop;
}
virtual FTargetDeviceId GetId() const override
{
return FTargetDeviceId(TargetPlatformControls.PlatformName(), GetName());
}
virtual FString GetName( ) const override
{
return DeviceName;
}
virtual FString GetOperatingSystemName( ) override
{
return TEXT("GNU/Linux");
}
virtual int32 GetProcessSnapshot( TArray<FTargetDeviceProcessInfo>& OutProcessInfos ) override
{
STUBBED("FLinuxTargetDevice::GetProcessSnapshot");
return 0;
}
virtual const class ITargetPlatformSettings& GetPlatformSettings() const override
{
return *(TargetPlatformControls.GetTargetPlatformSettings());
}
virtual const class ITargetPlatformControls& GetPlatformControls() const override
{
return TargetPlatformControls;
}
virtual bool IsConnected( ) override
{
return true;
}
virtual bool IsDefault( ) const override
{
return true;
}
virtual bool PowerOff( bool Force ) override
{
return false;
}
virtual bool PowerOn( ) override
{
return false;
}
virtual bool Reboot( bool bReconnect = false ) override
{
STUBBED("FLinuxTargetDevice::Reboot");
return false;
}
virtual bool SupportsFeature( ETargetDeviceFeatures Feature ) const override
{
switch (Feature)
{
case ETargetDeviceFeatures::MultiLaunch:
return true;
// @todo to be implemented
case ETargetDeviceFeatures::PowerOff:
return false;
// @todo to be implemented turning on remote PCs (wake on LAN)
case ETargetDeviceFeatures::PowerOn:
return false;
// @todo to be implemented
case ETargetDeviceFeatures::ProcessSnapshot:
return false;
// @todo to be implemented
case ETargetDeviceFeatures::Reboot:
return false;
}
return false;
}
virtual void SetUserCredentials( const FString& InUserName, const FString& InUserPassword ) override
{
UserName = InUserName;
UserPassword = InUserPassword;
if (SavePlatformDevices)
{
SavePlatformDevices();
}
}
virtual bool GetUserCredentials( FString& OutUserName, FString& OutUserPassword ) override
{
OutUserName = UserName;
OutUserPassword = UserPassword;
return true;
}
virtual bool TerminateProcess( const int64 ProcessId ) override
{
#if PLATFORM_LINUX // if running natively, just terminate the local process
// get process path from the ProcessId
const int32 ReadLinkSize = 1024;
char ReadLinkCmd[ReadLinkSize] = { 0 };
FCStringAnsi::Sprintf(ReadLinkCmd, "/proc/%lld/exe", ProcessId);
char ProcessPath[UNIX_MAX_PATH + 1] = { 0 };
int32 Ret = readlink(ReadLinkCmd, ProcessPath, UE_ARRAY_COUNT(ProcessPath) - 1);
if (Ret != -1)
{
struct stat st;
uid_t euid;
stat(ProcessPath, &st);
euid = geteuid(); // get effective uid of current application, as this user is asking to kill a process
// now check if we own the process
if (st.st_uid == euid)
{
// terminate it (will this terminate children as well because we set their pgid?)
kill(ProcessId, SIGTERM);
sleep(2); // sleep in case process still remains then send a more strict signal
kill(ProcessId, SIGKILL);
return true;
}
}
#else
// @todo: support remote termination
STUBBED("FLinuxTargetDevice::TerminateProcess");
#endif // PLATFORM_LINUX
return false;
}
protected:
// Holds a reference to the device's target platform.
const ITargetPlatformControls& TargetPlatformControls;
/** Device display name */
FString DeviceName;
/** User name on the remote machine */
FString UserName;
/** User password on the remote machine */
FString UserPassword;
/** Target platform function to save device state */
TFunction<void()> SavePlatformDevices;
};