blob: 0bba6a5b8f8ea8d8121ed307b4a67c7e56da85da [file] [log] [blame]
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/updater/test/test_app/update_client_mac.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/mac/bundle_locations.h"
#include "base/mac/foundation_util.h"
#include "base/mac/scoped_nsobject.h"
#include "base/memory/scoped_refptr.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/strcat.h"
#include "base/strings/sys_string_conversions.h"
#include "base/task/post_task.h"
#include "base/version.h"
#import "chrome/updater/app/server/mac/service_protocol.h"
#import "chrome/updater/app/server/mac/update_service_wrappers.h"
#include "chrome/updater/test/test_app/test_app_version.h"
namespace {
NSString* GetLaunchdServiceName() {
return base::SysUTF8ToNSString(
base::StrCat({UPDATER_APP_BUNDLE_IDENTIFIER_STRING, ".service"}));
}
NSString* GetMachServiceName() {
return [GetLaunchdServiceName()
stringByAppendingFormat:@".%lu", [GetLaunchdServiceName() hash]];
}
} // namespace
@interface CRUUpdateClientOnDemandImpl : NSObject <CRUUpdateChecking> {
base::scoped_nsobject<NSXPCConnection> _xpcConnection;
}
- (BOOL)CanDialIPC;
@end
@implementation CRUUpdateClientOnDemandImpl
- (instancetype)init {
if (self = [super init]) {
_xpcConnection.reset([[NSXPCConnection alloc]
initWithMachServiceName:GetMachServiceName()
options:0]);
_xpcConnection.get().remoteObjectInterface =
updater::GetXPCUpdateCheckingInterface();
_xpcConnection.get().interruptionHandler = ^{
LOG(WARNING)
<< "CRUUpdateClientOnDemandImpl: XPC connection interrupted.";
};
_xpcConnection.get().invalidationHandler = ^{
LOG(WARNING)
<< "CRUUpdateClientOnDemandImpl: XPC connection invalidated.";
};
[_xpcConnection resume];
}
return self;
}
- (void)registerForUpdatesWithAppId:(NSString* _Nullable)appId
brandCode:(NSString* _Nullable)brandCode
tag:(NSString* _Nullable)tag
version:(NSString* _Nullable)version
existenceCheckerPath:(NSString* _Nullable)existenceCheckerPath
reply:(void (^_Nonnull)(int rc))reply {
auto errorHandler = ^(NSError* xpcError) {
LOG(ERROR) << "XPC Connection failed: "
<< base::SysNSStringToUTF8([xpcError description]);
reply(-1);
};
[[_xpcConnection.get() remoteObjectProxyWithErrorHandler:errorHandler]
registerForUpdatesWithAppId:appId
brandCode:brandCode
tag:tag
version:version
existenceCheckerPath:existenceCheckerPath
reply:reply];
}
- (void)checkForUpdatesWithUpdateState:
(id<CRUUpdateStateObserving> _Nonnull)updateState
reply:(void (^_Nonnull)(int rc))reply {
}
- (void)checkForUpdateWithAppID:(NSString* _Nonnull)appID
priority:(CRUPriorityWrapper* _Nonnull)priority
updateState:
(id<CRUUpdateStateObserving> _Nonnull)updateState
reply:(void (^_Nonnull)(int rc))reply {
auto errorHandler = ^(NSError* xpcError) {
LOG(ERROR) << "XPC Connection failed: "
<< base::SysNSStringToUTF8([xpcError description]);
reply(-1);
};
[[_xpcConnection remoteObjectProxyWithErrorHandler:errorHandler]
checkForUpdateWithAppID:appID
priority:priority
updateState:updateState
reply:reply];
}
- (BOOL)CanDialIPC {
return true;
}
@end
namespace updater {
UpdateClientMac::UpdateClientMac() {
client_.reset([[CRUUpdateClientOnDemandImpl alloc] init]);
}
UpdateClientMac::~UpdateClientMac() {}
bool UpdateClientMac::CanDialIPC() {
return client_.get().CanDialIPC;
}
void UpdateClientMac::BeginRegister(const std::string& brand_code,
const std::string& tag,
const std::string& version,
UpdateService::Callback callback) {
__block base::OnceCallback<void(UpdateService::Result)> block_callback =
std::move(callback);
auto reply = ^(int error) {
task_runner()->PostTask(
FROM_HERE, base::BindOnce(std::move(block_callback),
static_cast<UpdateService::Result>(error)));
};
[client_.get() registerForUpdatesWithAppId:base::SysUTF8ToNSString(
base::mac::BaseBundleID())
brandCode:base::SysUTF8ToNSString(brand_code)
tag:base::SysUTF8ToNSString(tag)
version:base::SysUTF8ToNSString(version)
existenceCheckerPath:base::mac::FilePathToNSString(
base::mac::OuterBundlePath())
reply:reply];
}
void UpdateClientMac::BeginUpdateCheck(
UpdateService::StateChangeCallback state_update,
UpdateService::Callback callback) {
__block base::OnceCallback<void(UpdateService::Result)> block_callback =
std::move(callback);
auto reply = ^(int error) {
task_runner()->PostTask(
FROM_HERE, base::BindOnce(std::move(block_callback),
static_cast<UpdateService::Result>(error)));
};
base::scoped_nsobject<CRUPriorityWrapper> priorityWrapper(
[[CRUPriorityWrapper alloc]
initWithPriority:UpdateService::Priority::kForeground]);
base::scoped_nsprotocol<id<CRUUpdateStateObserving>> stateObserver(
[[CRUUpdateStateObserver alloc] initWithRepeatingCallback:state_update
callbackRunner:task_runner()]);
[client_.get()
checkForUpdateWithAppID:base::SysUTF8ToNSString(base::mac::BaseBundleID())
priority:priorityWrapper.get()
updateState:stateObserver.get()
reply:reply];
}
scoped_refptr<UpdateClient> UpdateClient::Create() {
return base::MakeRefCounted<UpdateClientMac>();
}
} // namespace updater