blob: fbcebc92f5e813432e1c8c03b28b339a2390c986 [file] [log] [blame]
// Copyright 2017 Google Inc. All Rights Reserved.
//
// 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 "starboard/shared/uwp/log_file_impl.h"
#include <string>
#include "starboard/log.h"
#include "starboard/mutex.h"
#include "starboard/once.h"
#include "starboard/shared/win32/wchar_utils.h"
#include "starboard/string.h"
using Windows::Foundation::AsyncOperationCompletedHandler;
using Windows::Foundation::AsyncStatus;
using Windows::Foundation::IAsyncOperation;
using Windows::Storage::FileAccessMode;
using Windows::Storage::StorageFile;
using Windows::Storage::StorageFolder;
using Windows::Storage::Streams::DataWriter;
using Windows::Storage::Streams::IRandomAccessStream;
using Windows::Storage::Streams::IOutputStream;
namespace {
SbMutex log_mutex_ = SB_MUTEX_INITIALIZER;
// The Windows Storage API must be used in order to access files in priviledged
// areas (e.g. KnownFolders::RemovableDevices). The win32 file API used by
// SbFile returns access denied errors in these situations.
DataWriter^ log_writer_ = nullptr;
// SbMutex is not reentrant, so factor out close log file functionality for use
// by other functions.
void CloseLogFileWithoutLock() {
log_writer_ = nullptr;
}
} // namespace
namespace starboard {
namespace shared {
namespace uwp {
void CloseLogFile() {
SbMutexAcquire(&log_mutex_);
CloseLogFileWithoutLock();
SbMutexRelease(&log_mutex_);
}
void OpenLogFile(StorageFolder^ folder, const char* filename) {
std::wstring wfilename = win32::CStringToWString(filename);
SbMutexAcquire(&log_mutex_);
CloseLogFileWithoutLock();
// Manually set the completion callback function instead of using
// concurrency::create_task() since those tasks may not execute before the
// UI thread wants the log_mutex_ to output another log.
auto task = folder->CreateFileAsync(
ref new Platform::String(wfilename.c_str()),
Windows::Storage::CreationCollisionOption::ReplaceExisting);
task->Completed = ref new AsyncOperationCompletedHandler<StorageFile^>(
[folder](IAsyncOperation<StorageFile^>^ op, AsyncStatus) {
try {
auto task = op->GetResults()->OpenAsync(FileAccessMode::ReadWrite);
task->Completed = ref new
AsyncOperationCompletedHandler<IRandomAccessStream^>(
[](IAsyncOperation<IRandomAccessStream^>^ op, AsyncStatus) {
log_writer_ = ref new DataWriter(
op->GetResults()->GetOutputStreamAt(0));
SbMutexRelease(&log_mutex_);
});
} catch(Platform::Exception^) {
SbMutexRelease(&log_mutex_);
SB_LOG(ERROR) << "Unable to open log file in folder "
<< win32::platformStringToString(folder->Name);
}
});
}
void WriteToLogFile(const char* text, int text_length) {
if (text_length <= 0) {
return;
}
SbMutexAcquire(&log_mutex_);
if (log_writer_) {
log_writer_->WriteBytes(ref new Platform::Array<unsigned char>(
(unsigned char*) text, text_length));
// Manually set the completion callback function instead of using
// concurrency::create_task() since those tasks may not execute before the
// UI thread wants the log_mutex_ to output another log.
auto task = log_writer_->StoreAsync();
task->Completed = ref new AsyncOperationCompletedHandler<unsigned int>(
[](IAsyncOperation<unsigned int>^, AsyncStatus) {
auto task = log_writer_->FlushAsync();
task->Completed = ref new AsyncOperationCompletedHandler<bool>(
[](IAsyncOperation<bool>^, AsyncStatus) {
SbMutexRelease(&log_mutex_);
});
});
} else {
SbMutexRelease(&log_mutex_);
}
}
} // namespace uwp
} // namespace shared
} // namespace starboard