// Copyright 2021-2023 Google LLC // // 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 // // https://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 "internal/platform/implementation/windows/device_info.h" #include #include #include #include // NOLINT #include #include #include #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" #include "internal/base/files.h" #include "internal/platform/implementation/device_info.h" #include "internal/platform/implementation/windows/generated/winrt/base.h" #include "internal/platform/logging.h" #include "winrt/Windows.Foundation.Collections.h" #include "winrt/Windows.Foundation.h" #include "winrt/Windows.System.h" namespace nearby { namespace windows { using IInspectable = winrt::Windows::Foundation::IInspectable; using KnownUserProperties = winrt::Windows::System::KnownUserProperties; using User = winrt::Windows::System::User; using UserType = winrt::Windows::System::UserType; using UserAuthenticationStatus = winrt::Windows::System::UserAuthenticationStatus; template using IVectorView = winrt::Windows::Foundation::Collections::IVectorView; template using IAsyncOperation = winrt::Windows::Foundation::IAsyncOperation; constexpr char logs_relative_path[] = "Google\\Nearby\\Sharing\\Logs"; constexpr char crash_dumps_relative_path[] = "Google\\Nearby\\Sharing\\CrashDumps"; std::optional DeviceInfo::GetOsDeviceName() const { DWORD size = 0; // Get length of the computer name. if (!GetComputerNameExW(ComputerNameDnsHostname, nullptr, &size)) { if (GetLastError() != ERROR_MORE_DATA) { NEARBY_LOGS(ERROR) << ": Failed to get device name size, error:" << GetLastError(); return std::nullopt; } } WCHAR device_name[size]; if (GetComputerNameExW(ComputerNameDnsHostname, device_name, &size)) { winrt::hstring device_name_str(device_name); return winrt::to_string(device_name_str); } NEARBY_LOGS(ERROR) << ": Failed to get device name, error:" << GetLastError(); return std::nullopt; } api::DeviceInfo::DeviceType DeviceInfo::GetDeviceType() const { // TODO(b/230132370): return correct device type on the Windows platform. return api::DeviceInfo::DeviceType::kLaptop; } api::DeviceInfo::OsType DeviceInfo::GetOsType() const { return api::DeviceInfo::OsType::kWindows; } std::optional DeviceInfo::GetFullName() const { // FindAllAsync finds all users that are using this app. When we "Switch User" // on Desktop,FindAllAsync() will still return the current user instead of all // of them because the users who are switched out are not using the apps of // the user who is switched in, so FindAllAsync() will not find them. (Under // the UWP application model, each process runs under its own user account. // That user account is different from the user account of the logged-in user. // Processes aren't owned by the logged-in user for purposes of isolation.) IVectorView users = User::FindAllAsync(UserType::LocalUser, UserAuthenticationStatus::LocallyAuthenticated) .get(); if (users == nullptr) { NEARBY_LOGS(ERROR) << __func__ << ": Error retrieving locally authenticated user."; return std::nullopt; } // On Windows Desktop apps, the first Windows.System.User instance // returned in the IVectorView is always the current user. // https://github.com/microsoft/Windows-task-snippets/blob/master/tasks/User-info.md User current_user = users.GetAt(0); // Retrieve the human-readable properties for the current user IAsyncOperation full_name_obj_async = current_user.GetPropertyAsync(KnownUserProperties::DisplayName()); IInspectable full_name_obj = full_name_obj_async.get(); if (full_name_obj == nullptr) { NEARBY_LOGS(ERROR) << __func__ << ": Error retrieving full name of user."; return std::nullopt; } winrt::hstring full_name = full_name_obj.as(); std::string full_name_str = winrt::to_string(full_name); if (full_name_str.empty()) { NEARBY_LOGS(ERROR) << __func__ << ": Error unboxing string value for full name of user."; return std::nullopt; } return full_name_str; } std::optional DeviceInfo::GetGivenName() const { // FindAllAsync finds all users that are using this app. When we "Switch User" // on Desktop,FindAllAsync() will still return the current user instead of all // of them because the users who are switched out are not using the apps of // the user who is switched in, so FindAllAsync() will not find them. (Under // the UWP application model, each process runs under its own user account. // That user account is different from the user account of the logged-in user. // Processes aren't owned by the logged-in user for purposes of isolation.) IVectorView users = User::FindAllAsync(UserType::LocalUser, UserAuthenticationStatus::LocallyAuthenticated) .get(); if (users == nullptr) { NEARBY_LOGS(ERROR) << __func__ << ": Error retrieving locally authenticated user."; return std::nullopt; } // On Windows Desktop apps, the first Windows.System.User instance // returned in the IVectorView is always the current user. // https://github.com/microsoft/Windows-task-snippets/blob/master/tasks/User-info.md User current_user = users.GetAt(0); // Retrieve the human-readable properties for the current user IAsyncOperation given_name_obj_async = current_user.GetPropertyAsync(KnownUserProperties::FirstName()); IInspectable given_name_obj = given_name_obj_async.get(); if (given_name_obj == nullptr) { NEARBY_LOGS(ERROR) << __func__ << ": Error retrieving first name of user."; return std::nullopt; } winrt::hstring given_name = given_name_obj.as(); std::string given_name_str = winrt::to_string(given_name); if (given_name_str.empty()) { NEARBY_LOGS(ERROR) << __func__ << ": Error unboxing string value for first name of user."; return std::nullopt; } return given_name_str; } std::optional DeviceInfo::GetLastName() const { // FindAllAsync finds all users that are using this app. When we "Switch User" // on Desktop,FindAllAsync() will still return the current user instead of all // of them because the users who are switched out are not using the apps of // the user who is switched in, so FindAllAsync() will not find them. (Under // the UWP application model, each process runs under its own user account. // That user account is different from the user account of the logged-in user. // Processes aren't owned by the logged-in user for purposes of isolation.) IVectorView users = User::FindAllAsync(UserType::LocalUser, UserAuthenticationStatus::LocallyAuthenticated) .get(); if (users == nullptr) { NEARBY_LOGS(ERROR) << __func__ << ": Error retrieving locally authenticated user."; return std::nullopt; } // On Windows Desktop apps, the first Windows.System.User instance // returned in the IVectorView is always the current user. // https://github.com/microsoft/Windows-task-snippets/blob/master/tasks/User-info.md User current_user = users.GetAt(0); // Retrieve the human-readable properties for the current user IAsyncOperation last_name_obj_async = current_user.GetPropertyAsync(KnownUserProperties::LastName()); IInspectable last_name_obj = last_name_obj_async.get(); if (last_name_obj == nullptr) { NEARBY_LOGS(ERROR) << __func__ << ": Error retrieving last name of user."; return std::nullopt; } winrt::hstring last_name = last_name_obj.as(); std::string last_name_str = winrt::to_string(last_name); if (last_name_str.empty()) { NEARBY_LOGS(ERROR) << __func__ << ": Error unboxing string value for last name of user."; return std::nullopt; } return last_name_str; } std::optional DeviceInfo::GetProfileUserName() const { // FindAllAsync finds all users that are using this app. When we "Switch User" // on Desktop,FindAllAsync() will still return the current user instead of all // of them because the users who are switched out are not using the apps of // the user who is switched in, so FindAllAsync() will not find them. (Under // the UWP application model, each process runs under its own user account. // That user account is different from the user account of the logged-in user. // Processes aren't owned by the logged-in user for purposes of isolation.) IVectorView users = User::FindAllAsync(UserType::LocalUser, UserAuthenticationStatus::LocallyAuthenticated) .get(); if (users == nullptr) { NEARBY_LOGS(ERROR) << __func__ << ": Error retrieving locally authenticated user."; return std::nullopt; } // On Windows Desktop apps, the first Windows.System.User instance // returned in the IVectorView is always the current user. // https://github.com/microsoft/Windows-task-snippets/blob/master/tasks/User-info.md User current_user = users.GetAt(0); // Retrieve the human-readable properties for the current user IAsyncOperation account_name_obj_async = current_user.GetPropertyAsync(KnownUserProperties::AccountName()); IInspectable account_name_obj = account_name_obj_async.get(); if (account_name_obj == nullptr) { NEARBY_LOGS(ERROR) << __func__ << ": Error retrieving account name of user."; return std::nullopt; } winrt::hstring account_name = account_name_obj.as(); std::string account_name_string = winrt::to_string(account_name); if (account_name_string.empty()) { NEARBY_LOGS(ERROR) << __func__ << ": Error unboxing string value for profile username of user."; return std::nullopt; } return account_name_string; } std::optional DeviceInfo::GetDownloadPath() const { PWSTR path; HRESULT result = SHGetKnownFolderPath(FOLDERID_Downloads, KF_FLAG_DEFAULT, nullptr, &path); if (result == S_OK) { std::wstring download_path{path}; CoTaskMemFree(path); return std::filesystem::path(download_path); } CoTaskMemFree(path); return std::nullopt; } std::optional DeviceInfo::GetLocalAppDataPath() const { PWSTR path; HRESULT result = SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_DEFAULT, /*hToken=*/nullptr, &path); if (result == S_OK) { std::wstring local_appdata_path{path}; CoTaskMemFree(path); return std::filesystem::path(local_appdata_path); } CoTaskMemFree(path); return std::nullopt; } std::optional DeviceInfo::GetCommonAppDataPath() const { PWSTR path; HRESULT result = SHGetKnownFolderPath(FOLDERID_ProgramData, KF_FLAG_DEFAULT, /*hToken=*/nullptr, &path); if (result == S_OK) { std::wstring common_app_data_path{path}; CoTaskMemFree(path); return std::filesystem::path(common_app_data_path); } CoTaskMemFree(path); return std::nullopt; } std::optional DeviceInfo::GetTemporaryPath() const { return nearby::sharing::GetTemporaryDirectory(); } std::optional DeviceInfo::GetLogPath() const { auto prefix_path = GetLocalAppDataPath(); if (prefix_path.has_value()) { return std::filesystem::path(prefix_path.value() / logs_relative_path); } return std::nullopt; } std::optional DeviceInfo::GetCrashDumpPath() const { auto prefix_path = GetLocalAppDataPath(); if (prefix_path.has_value()) { return std::filesystem::path(prefix_path.value() / crash_dumps_relative_path); } return std::nullopt; } bool DeviceInfo::IsScreenLocked() const { absl::MutexLock lock(&mutex_); return session_manager_.IsScreenLocked(); } void DeviceInfo::RegisterScreenLockedListener( absl::string_view listener_name, std::function callback) { absl::MutexLock lock(&mutex_); session_manager_.RegisterSessionListener( listener_name, [callback = std::move(callback)](SessionManager::SessionState state) { if (state == SessionManager::SessionState::kLock) { callback(api::DeviceInfo::ScreenStatus::kLocked); } else if (state == SessionManager::SessionState::kUnlock) { callback(api::DeviceInfo::ScreenStatus::kUnlocked); } }); } void DeviceInfo::UnregisterScreenLockedListener( absl::string_view listener_name) { absl::MutexLock lock(&mutex_); session_manager_.UnregisterSessionListener(listener_name); } bool DeviceInfo::PreventSleep() { absl::MutexLock lock(&mutex_); return session_manager_.PreventSleep(); } bool DeviceInfo::AllowSleep() { absl::MutexLock lock(&mutex_); return session_manager_.AllowSleep(); } } // namespace windows } // namespace nearby