Adding WinUWP compilation support to WebRTC.

Windows UWP allows an application to be built that targets
across all Windows 10 based systems and the Windows store.

Change-Id: I69694bb7e83fb01ad6db2438b065b55738cf01fd
Bug: webrtc:10046
Reviewed-on: https://webrtc-review.googlesource.com/c/110570
Commit-Queue: Patrik Höglund <phoglund@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Patrik Höglund <phoglund@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#25814}
This commit is contained in:
Robin Raymond 2018-11-22 20:10:11 -05:00 committed by Commit Bot
parent 3bc24bcd3e
commit ce1b140b8d
15 changed files with 270 additions and 44 deletions

View file

@ -47,12 +47,14 @@ group("examples") {
if (is_linux || is_win) {
deps += [
":peerconnection_client",
":peerconnection_server",
":relayserver",
":stunserver",
":turnserver",
]
if (current_os != "winuwp") {
deps += [ ":peerconnection_client" ]
}
}
if (is_android || is_win) {

View file

@ -870,11 +870,13 @@ rtc_static_library("rtc_base") {
]
if (is_win) {
sources += [
"win32socketinit.h",
"win32socketserver.cc",
"win32socketserver.h",
]
sources += [ "win32socketinit.h" ]
if (current_os != "winuwp") {
sources += [
"win32socketserver.cc",
"win32socketserver.h",
]
}
}
} # !build_with_chromium

View file

@ -38,7 +38,7 @@
namespace rtc {
namespace {
#if defined(WEBRTC_WIN)
#if defined(WEBRTC_WIN) && !defined(WINUWP)
///////////////////////////////////////////////////////////////////////////////
// ConstantToLabel can be used to easily generate string names from constant
// values. This can be useful for logging descriptive names of error messages.
@ -113,7 +113,7 @@ const ConstantToLabel SECURITY_ERRORS[] = {
LASTLABEL};
#undef KLABEL
#undef LASTLABEL
#endif // defined(WEBRTC_WIN)
#endif // defined(WEBRTC_WIN) && !defined(WINUWP)
typedef std::pair<std::string, std::string> HttpAttribute;
typedef std::vector<HttpAttribute> HttpAttributeList;
@ -225,7 +225,7 @@ std::string quote(const std::string& str) {
return result;
}
#if defined(WEBRTC_WIN)
#if defined(WEBRTC_WIN) && !defined(WINUWP)
struct NegotiateAuthContext : public HttpAuthContext {
CredHandle cred;
CtxtHandle ctx;
@ -244,7 +244,7 @@ struct NegotiateAuthContext : public HttpAuthContext {
FreeCredentialsHandle(&cred);
}
};
#endif // WEBRTC_WIN
#endif // defined(WEBRTC_WIN) && !defined(WINUWP)
} // anonymous namespace
@ -359,7 +359,7 @@ HttpAuthResult HttpAuthenticate(const char* challenge,
return HAR_RESPONSE;
}
#if defined(WEBRTC_WIN)
#if defined(WEBRTC_WIN) && !defined(WINUWP)
#if 1
bool want_negotiate = absl::EqualsIgnoreCase(auth_method, "negotiate");
bool want_ntlm = absl::EqualsIgnoreCase(auth_method, "ntlm");
@ -544,7 +544,7 @@ HttpAuthResult HttpAuthenticate(const char* challenge,
return HAR_RESPONSE;
}
#endif
#endif // WEBRTC_WIN
#endif // defined(WEBRTC_WIN) && !defined(WINUWP)
return HAR_IGNORE;
}

View file

@ -327,7 +327,7 @@ void LogMessage::ConfigureLogging(const char* params) {
}
}
#if defined(WEBRTC_WIN)
#if defined(WEBRTC_WIN) && !defined(WINUWP)
if ((LS_NONE != debug_level) && !::IsDebuggerPresent()) {
// First, attempt to attach to our parent's console... so if you invoke
// from the command line, we'll see the output there. Otherwise, create
@ -336,7 +336,7 @@ void LogMessage::ConfigureLogging(const char* params) {
if (!AttachConsole(ATTACH_PARENT_PROCESS))
::AllocConsole();
}
#endif // WEBRTC_WIN
#endif // defined(WEBRTC_WIN) && !defined(WINUWP)
LogToDebug(debug_level);
}

View file

@ -161,7 +161,10 @@ bool HasIPv4Enabled() {
}
bool HasIPv6Enabled() {
#if defined(WEBRTC_WIN)
#if defined(WINUWP)
// WinUWP always has IPv6 capability.
return true;
#elif defined(WEBRTC_WIN)
if (IsWindowsVistaOrLater()) {
return true;
}

View file

@ -427,7 +427,7 @@ void AsyncHttpsProxySocket::ProcessLine(char* data, size_t len) {
// std::string msg("Please report the following information to
// foo@bar.com:\r\nUnknown methods: ");
msg.append(unknown_mechanisms_);
#if defined(WEBRTC_WIN)
#if defined(WEBRTC_WIN) && !defined(WINUWP)
MessageBoxA(0, msg.c_str(), "Oops!", MB_OK);
#endif
#if defined(WEBRTC_POSIX)

View file

@ -14,23 +14,19 @@
namespace webrtc {
static bool native_rw_locks_supported = false;
static bool module_load_attempted = false;
static HMODULE library = NULL;
typedef void(WINAPI* PInitializeSRWLock)(PSRWLOCK);
typedef void(WINAPI* InitializeSRWLock)(PSRWLOCK);
typedef void(WINAPI* PAcquireSRWLockExclusive)(PSRWLOCK);
typedef void(WINAPI* PReleaseSRWLockExclusive)(PSRWLOCK);
typedef void(WINAPI* AcquireSRWLockExclusive)(PSRWLOCK);
typedef void(WINAPI* ReleaseSRWLockExclusive)(PSRWLOCK);
typedef void(WINAPI* PAcquireSRWLockShared)(PSRWLOCK);
typedef void(WINAPI* PReleaseSRWLockShared)(PSRWLOCK);
typedef void(WINAPI* AcquireSRWLockShared)(PSRWLOCK);
typedef void(WINAPI* ReleaseSRWLockShared)(PSRWLOCK);
InitializeSRWLock initialize_srw_lock;
AcquireSRWLockExclusive acquire_srw_lock_exclusive;
AcquireSRWLockShared acquire_srw_lock_shared;
ReleaseSRWLockShared release_srw_lock_shared;
ReleaseSRWLockExclusive release_srw_lock_exclusive;
PInitializeSRWLock initialize_srw_lock;
PAcquireSRWLockExclusive acquire_srw_lock_exclusive;
PAcquireSRWLockShared acquire_srw_lock_shared;
PReleaseSRWLockShared release_srw_lock_shared;
PReleaseSRWLockExclusive release_srw_lock_exclusive;
RWLockWin::RWLockWin() {
initialize_srw_lock(&lock_);
@ -60,28 +56,31 @@ void RWLockWin::ReleaseLockShared() {
}
bool RWLockWin::LoadModule() {
static bool module_load_attempted = false;
static bool native_rw_locks_supported = false;
if (module_load_attempted) {
return native_rw_locks_supported;
}
module_load_attempted = true;
#if !defined(WINUWP)
// Use native implementation if supported (i.e Vista+)
library = LoadLibrary(TEXT("Kernel32.dll"));
static HMODULE library = LoadLibrary(TEXT("Kernel32.dll"));
if (!library) {
return false;
}
RTC_LOG(LS_VERBOSE) << "Loaded Kernel.dll";
initialize_srw_lock =
(InitializeSRWLock)GetProcAddress(library, "InitializeSRWLock");
(PInitializeSRWLock)GetProcAddress(library, "InitializeSRWLock");
acquire_srw_lock_exclusive = (AcquireSRWLockExclusive)GetProcAddress(
acquire_srw_lock_exclusive = (PAcquireSRWLockExclusive)GetProcAddress(
library, "AcquireSRWLockExclusive");
release_srw_lock_exclusive = (ReleaseSRWLockExclusive)GetProcAddress(
release_srw_lock_exclusive = (PReleaseSRWLockExclusive)GetProcAddress(
library, "ReleaseSRWLockExclusive");
acquire_srw_lock_shared =
(AcquireSRWLockShared)GetProcAddress(library, "AcquireSRWLockShared");
(PAcquireSRWLockShared)GetProcAddress(library, "AcquireSRWLockShared");
release_srw_lock_shared =
(ReleaseSRWLockShared)GetProcAddress(library, "ReleaseSRWLockShared");
(PReleaseSRWLockShared)GetProcAddress(library, "ReleaseSRWLockShared");
if (initialize_srw_lock && acquire_srw_lock_exclusive &&
release_srw_lock_exclusive && acquire_srw_lock_shared &&
@ -89,6 +88,18 @@ bool RWLockWin::LoadModule() {
RTC_LOG(LS_VERBOSE) << "Loaded Native RW Lock";
native_rw_locks_supported = true;
}
#else
// On WinUWP the symbols loaded from this library are directly present
// in the headers and thus loading the library is not required (and
// manually loading libraries is restricted due to WinUWP sandboxing).
initialize_srw_lock = InitializeSRWLock;
acquire_srw_lock_exclusive = AcquireSRWLockExclusive;
release_srw_lock_exclusive = ReleaseSRWLockExclusive;
acquire_srw_lock_shared = AcquireSRWLockShared;
release_srw_lock_shared = ReleaseSRWLockShared;
native_rw_locks_supported = true;
#endif // !defined(WINUWP)
return native_rw_locks_supported;
}

View file

@ -45,6 +45,104 @@ ClockInterface* GetClockForTesting() {
return g_clock;
}
#if defined(WINUWP)
namespace {
class TimeHelper final {
public:
TimeHelper(const TimeHelper&) = delete;
// Resets the clock based upon an NTP server. This routine must be called
// prior to the main system start-up to ensure all clocks are based upon
// an NTP server time if NTP synchronization is required. No critical
// section is used thus this method must be called prior to any clock
// routines being used.
static void SyncWithNtp(int64_t ntp_server_time_ms) {
auto& singleton = Singleton();
TIME_ZONE_INFORMATION time_zone;
GetTimeZoneInformation(&time_zone);
int64_t time_zone_bias_ns =
rtc::dchecked_cast<int64_t>(time_zone.Bias) * 60 * 1000 * 1000 * 1000;
singleton.app_start_time_ns_ =
(ntp_server_time_ms - kNTPTimeToUnixTimeEpochOffset) * 1000000 -
time_zone_bias_ns;
singleton.UpdateReferenceTime();
}
// Returns the number of nanoseconds that have passed since unix epoch.
static int64_t TicksNs() {
auto& singleton = Singleton();
int64_t result = 0;
LARGE_INTEGER qpcnt;
QueryPerformanceCounter(&qpcnt);
result = rtc::dchecked_cast<int64_t>(
(rtc::dchecked_cast<uint64_t>(qpcnt.QuadPart) * 100000 /
rtc::dchecked_cast<uint64_t>(singleton.os_ticks_per_second_)) *
10000);
result = singleton.app_start_time_ns_ + result -
singleton.time_since_os_start_ns_;
return result;
}
private:
TimeHelper() {
TIME_ZONE_INFORMATION time_zone;
GetTimeZoneInformation(&time_zone);
int64_t time_zone_bias_ns =
rtc::dchecked_cast<int64_t>(time_zone.Bias) * 60 * 1000 * 1000 * 1000;
FILETIME ft;
// This will give us system file in UTC format.
GetSystemTimeAsFileTime(&ft);
LARGE_INTEGER li;
li.HighPart = ft.dwHighDateTime;
li.LowPart = ft.dwLowDateTime;
app_start_time_ns_ = (li.QuadPart - kFileTimeToUnixTimeEpochOffset) * 100 -
time_zone_bias_ns;
UpdateReferenceTime();
}
static TimeHelper& Singleton() {
static TimeHelper singleton;
return singleton;
}
void UpdateReferenceTime() {
LARGE_INTEGER qpfreq;
QueryPerformanceFrequency(&qpfreq);
os_ticks_per_second_ = rtc::dchecked_cast<int64_t>(qpfreq.QuadPart);
LARGE_INTEGER qpcnt;
QueryPerformanceCounter(&qpcnt);
time_since_os_start_ns_ = rtc::dchecked_cast<int64_t>(
(rtc::dchecked_cast<uint64_t>(qpcnt.QuadPart) * 100000 /
rtc::dchecked_cast<uint64_t>(os_ticks_per_second_)) *
10000);
}
private:
static constexpr uint64_t kFileTimeToUnixTimeEpochOffset =
116444736000000000ULL;
static constexpr uint64_t kNTPTimeToUnixTimeEpochOffset = 2208988800000L;
// The number of nanoseconds since unix system epoch
int64_t app_start_time_ns_;
// The number of nanoseconds since the OS started
int64_t time_since_os_start_ns_;
// The OS calculated ticks per second
int64_t os_ticks_per_second_;
};
} // namespace
void SyncWithNtp(int64_t time_from_ntp_server_ms) {
TimeHelper::SyncWithNtp(time_from_ntp_server_ms);
}
#endif // defined(WINUWP)
int64_t SystemTimeNanos() {
int64_t ticks;
#if defined(WEBRTC_MAC)
@ -71,6 +169,8 @@ int64_t SystemTimeNanos() {
clock_gettime(CLOCK_MONOTONIC, &ts);
ticks = kNumNanosecsPerSec * static_cast<int64_t>(ts.tv_sec) +
static_cast<int64_t>(ts.tv_nsec);
#elif defined(WINUWP)
ticks = TimeHelper::TicksNs();
#elif defined(WEBRTC_WIN)
static volatile LONG last_timegettime = 0;
static volatile int64_t num_wrap_timegettime = 0;

View file

@ -58,6 +58,12 @@ ClockInterface* SetClockForTesting(ClockInterface* clock);
// Returns previously set clock, or nullptr if no custom clock is being used.
ClockInterface* GetClockForTesting();
#if defined(WINUWP)
// Synchronizes the current clock based upon an NTP server's epoch in
// milliseconds.
void SyncWithNtp(int64_t time_from_ntp_server_ms);
#endif // defined(WINUWP)
// Returns the actual system time, even if a clock is set for testing.
// Useful for timeouts while using a test clock, or for logging.
int64_t SystemTimeNanos();

View file

@ -28,6 +28,8 @@
#error Creators Update SDK (10.0.15063.468) required.
#endif
#if !defined(WINUWP)
namespace {
typedef BOOL(WINAPI* GetProductInfoPtr)(DWORD, DWORD, DWORD, DWORD, PDWORD);
@ -171,6 +173,8 @@ class RegKey {
} // namespace
#endif // !defined(WINUWP)
namespace rtc {
namespace rtc_win {
namespace {
@ -221,6 +225,10 @@ Version MajorMinorBuildToVersion(int major, int minor, int build) {
// this undocumented value appears to be similar to a patch number.
// Returns 0 if the value does not exist or it could not be read.
int GetUBR() {
#if defined(WINUWP)
// The registry is not accessible for WinUWP sandboxed store applications.
return 0;
#else
// The values under the CurrentVersion registry hive are mirrored under
// the corresponding Wow6432 hive.
static constexpr wchar_t kRegKeyWindowsNTCurrentVersion[] =
@ -236,6 +244,7 @@ int GetUBR() {
key.ReadValueDW(L"UBR", &ubr);
return static_cast<int>(ubr);
#endif // defined(WINUWP)
}
} // namespace
@ -294,6 +303,7 @@ OSInfo::OSInfo()
processors_ = system_info.dwNumberOfProcessors;
allocation_granularity_ = system_info.dwAllocationGranularity;
#if !defined(WINUWP)
GetProductInfoPtr get_product_info;
DWORD os_type;
@ -366,11 +376,21 @@ OSInfo::OSInfo()
// Windows is pre XP so we don't care but pick a safe default.
version_type_ = SUITE_HOME;
}
#else
// WinUWP sandboxed store apps do not have a mechanism to determine
// product suite thus the most restricted suite is chosen.
version_type_ = SUITE_HOME;
#endif // !defined(WINUWP)
}
OSInfo::~OSInfo() {}
std::string OSInfo::processor_model_name() {
#if defined(WINUWP)
// WinUWP sandboxed store apps do not have the ability to
// probe the name of the current processor.
return "Unknown Processor (UWP)";
#else
if (processor_model_name_.empty()) {
const wchar_t kProcessorNameString[] =
L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0";
@ -380,18 +400,24 @@ std::string OSInfo::processor_model_name() {
processor_model_name_ = rtc::ToUtf8(value);
}
return processor_model_name_;
#endif // defined(WINUWP)
}
// static
OSInfo::WOW64Status OSInfo::GetWOW64StatusForProcess(HANDLE process_handle) {
BOOL is_wow64;
#if defined(WINUWP)
if (!IsWow64Process(process_handle, &is_wow64))
return WOW64_UNKNOWN;
#else
typedef BOOL(WINAPI * IsWow64ProcessFunc)(HANDLE, PBOOL);
IsWow64ProcessFunc is_wow64_process = reinterpret_cast<IsWow64ProcessFunc>(
GetProcAddress(GetModuleHandle(L"kernel32.dll"), "IsWow64Process"));
if (!is_wow64_process)
return WOW64_DISABLED;
BOOL is_wow64 = FALSE;
if (!(*is_wow64_process)(process_handle, &is_wow64))
return WOW64_UNKNOWN;
#endif // defined(WINUWP)
return is_wow64 ? WOW64_ENABLED : WOW64_DISABLED;
}

View file

@ -331,6 +331,11 @@ bool Utf8ToWindowsFilename(const std::string& utf8, std::wstring* filename) {
}
// Replace forward slashes with backslashes
std::replace(wfilename, wfilename + wlen, L'/', L'\\');
#if defined(WINUWP)
// WinUWP sandboxed store applications require the paths to remain as
// relative paths.
filename->assign(wfilename);
#else
// Convert to complete filename
DWORD full_len = ::GetFullPathName(wfilename, 0, nullptr, nullptr);
if (0 == full_len) {
@ -360,9 +365,18 @@ bool Utf8ToWindowsFilename(const std::string& utf8, std::wstring* filename) {
// Already in long-path form.
}
filename->assign(start);
#endif // defined(WINUWP)
return true;
}
// Windows UWP applications cannot obtain versioning information from
// the sandbox with intention (as behehaviour based on OS versioning rather
// than feature discovery / compilation flags is discoraged and Windows
// 10 is living continously updated version unlike previous versions
// of Windows).
#if !defined(WINUWP)
bool GetOsVersion(int* major, int* minor, int* build) {
OSVERSIONINFO info = {0};
info.dwOSVersionInfoSize = sizeof(info);
@ -399,4 +413,6 @@ bool GetCurrentProcessIntegrityLevel(int* level) {
return ret;
}
#endif // !defined(WINUWP)
} // namespace rtc

View file

@ -54,6 +54,8 @@ enum WindowsMajorVersions {
kWindowsVista = 6,
kWindows10 = 10,
};
#if !defined(WINUWP)
bool GetOsVersion(int* major, int* minor, int* build);
inline bool IsWindowsVistaOrLater() {
@ -87,6 +89,34 @@ inline bool IsCurrentProcessLowIntegrity() {
level < SECURITY_MANDATORY_MEDIUM_RID);
}
#else
// When targetting WinUWP the OS must be Windows 10 (or greater) as lesser
// Windows OS targets are not supported.
inline bool IsWindowsVistaOrLater() {
return true;
}
inline bool IsWindowsXpOrLater() {
return true;
}
inline bool IsWindows8OrLater() {
return true;
}
inline bool IsWindows10OrLater() {
return true;
}
inline bool IsCurrentProcessLowIntegrity() {
// For WinUWP sandboxed store assume this is NOT a low integrity level run
// as application privileges can be requested in manifest as appropriate.
return true;
}
#endif // !defined(WINUWP)
} // namespace rtc
#endif // RTC_BASE_WIN32_H_

View file

@ -80,7 +80,29 @@ class RealTimeClock : public Clock {
}
};
#if defined(WEBRTC_WIN)
#if defined(WINUWP)
class WinUwpRealTimeClock final : public RealTimeClock {
public:
WinUwpRealTimeClock() = default;
~WinUwpRealTimeClock() override {}
protected:
timeval CurrentTimeVal() const override {
// The rtc::SystemTimeNanos() method is already time offset from a base
// epoch value and might as be synchronized against an NTP time server as
// an added bonus.
auto nanos = rtc::SystemTimeNanos();
struct timeval tv;
tv.tv_sec = rtc::dchecked_cast<long>(nanos / 1000000000);
tv.tv_usec = rtc::dchecked_cast<long>(nanos / 1000);
return tv;
}
};
#elif defined(WEBRTC_WIN)
// TODO(pbos): Consider modifying the implementation to synchronize itself
// against system time (update ref_point_, make it non-const) periodically to
// prevent clock drift.
@ -202,7 +224,9 @@ class UnixRealTimeClock : public RealTimeClock {
#endif // defined(WEBRTC_POSIX)
Clock* Clock::GetRealTimeClock() {
#if defined(WEBRTC_WIN)
#if defined(WINUWP)
static Clock* const clock = new WinUwpRealTimeClock();
#elif defined(WEBRTC_WIN)
static Clock* const clock = new WindowsRealTimeClock();
#elif defined(WEBRTC_POSIX)
static Clock* const clock = new UnixRealTimeClock();

View file

@ -6,8 +6,8 @@
# in the file PATENTS. All contributing project authors may
# be found in the AUTHORS file in the root of the source tree.
import("../webrtc.gni")
import("//build/config/ui.gni")
import("../webrtc.gni")
if (is_android) {
import("//build/config/android/rules.gni")
}
@ -647,9 +647,15 @@ rtc_source_set("test_common") {
"statistics.h",
"video_decoder_proxy_factory.h",
"video_encoder_proxy_factory.h",
"win/run_loop_win.cc",
]
if (!is_win) {
if (current_os != "winuwp") {
# The filtering of *_win.cc is not done for WinUWP (intentionally) as
# most _win.cc files are compatible with WinUWP. However, the
# peek/dispatch Win32 runloops are entirely WinUWP incompatible thus
# WinUWP uses the generic runloop as defined for non-Windows targets.
sources += [ "win/run_loop_win.cc" ]
}
if (!is_win || current_os == "winuwp") {
sources += [
"run_loop.cc",
"run_loop.h",

View file

@ -233,8 +233,8 @@ rtc_libvpx_dir = "//third_party/libvpx"
rtc_opus_dir = "//third_party/opus"
# Desktop capturer is supported only on Windows, OSX and Linux.
rtc_desktop_capture_supported =
is_win || is_mac || (is_linux && (rtc_use_x11 || rtc_use_pipewire))
rtc_desktop_capture_supported = (is_win && current_os != "winuwp") || is_mac ||
(is_linux && (rtc_use_x11 || rtc_use_pipewire))
###############################################################################
# Templates