This source file includes following definitions.
- Start
- Stop
- ActivateCurtain
- InstallEventHandler
- RemoveEventHandler
- DisconnectSession
- SessionActivateHandler
- Activate
- Create
#include "remoting/host/curtain_mode.h"
#include <ApplicationServices/ApplicationServices.h>
#include <Carbon/Carbon.h>
#include <Security/Security.h>
#include <unistd.h>
#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/mac/mac_util.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/single_thread_task_runner.h"
#include "remoting/host/client_session_control.h"
namespace {
using remoting::ClientSessionControl;
const char* kCGSessionPath =
"/System/Library/CoreServices/Menu Extras/User.menu/Contents/Resources/"
"CGSession";
class SessionWatcher : public base::RefCountedThreadSafe<SessionWatcher> {
public:
SessionWatcher(
scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
base::WeakPtr<ClientSessionControl> client_session_control);
void Start();
void Stop();
private:
friend class base::RefCountedThreadSafe<SessionWatcher>;
virtual ~SessionWatcher();
void ActivateCurtain();
bool InstallEventHandler();
void RemoveEventHandler();
void DisconnectSession();
static OSStatus SessionActivateHandler(EventHandlerCallRef handler,
EventRef event,
void* user_data);
scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner_;
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner_;
base::WeakPtr<ClientSessionControl> client_session_control_;
EventHandlerRef event_handler_;
DISALLOW_COPY_AND_ASSIGN(SessionWatcher);
};
SessionWatcher::SessionWatcher(
scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
base::WeakPtr<ClientSessionControl> client_session_control)
: caller_task_runner_(caller_task_runner),
ui_task_runner_(ui_task_runner),
client_session_control_(client_session_control),
event_handler_(NULL) {
}
void SessionWatcher::Start() {
DCHECK(caller_task_runner_->BelongsToCurrentThread());
ui_task_runner_->PostTask(
FROM_HERE, base::Bind(&SessionWatcher::ActivateCurtain, this));
}
void SessionWatcher::Stop() {
DCHECK(caller_task_runner_->BelongsToCurrentThread());
client_session_control_.reset();
ui_task_runner_->PostTask(
FROM_HERE, base::Bind(&SessionWatcher::RemoveEventHandler, this));
}
SessionWatcher::~SessionWatcher() {
DCHECK(!event_handler_);
}
void SessionWatcher::ActivateCurtain() {
if (base::mac::IsOSLion()) {
LOG(ERROR) << "Host curtaining is not supported on Mac OS X 10.7.";
DisconnectSession();
return;
}
if (!InstallEventHandler()) {
LOG(ERROR) << "Failed to install the switch-in handler.";
DisconnectSession();
return;
}
base::ScopedCFTypeRef<CFDictionaryRef> session(
CGSessionCopyCurrentDictionary());
CHECK(session != NULL);
const void* on_console = CFDictionaryGetValue(session,
kCGSessionOnConsoleKey);
const void* logged_in = CFDictionaryGetValue(session, kCGSessionLoginDoneKey);
if (logged_in == kCFBooleanTrue && on_console == kCFBooleanTrue) {
pid_t child = fork();
if (child == 0) {
execl(kCGSessionPath, kCGSessionPath, "-suspend", NULL);
_exit(1);
} else if (child > 0) {
int status = 0;
waitpid(child, &status, 0);
if (status != 0) {
LOG(ERROR) << kCGSessionPath << " failed.";
DisconnectSession();
return;
}
} else {
LOG(ERROR) << "fork() failed.";
DisconnectSession();
return;
}
}
}
bool SessionWatcher::InstallEventHandler() {
DCHECK(ui_task_runner_->BelongsToCurrentThread());
DCHECK(!event_handler_);
EventTypeSpec event;
event.eventClass = kEventClassSystem;
event.eventKind = kEventSystemUserSessionActivated;
OSStatus result = ::InstallApplicationEventHandler(
NewEventHandlerUPP(SessionActivateHandler), 1, &event, this,
&event_handler_);
if (result != noErr) {
event_handler_ = NULL;
DisconnectSession();
return false;
}
return true;
}
void SessionWatcher::RemoveEventHandler() {
DCHECK(ui_task_runner_->BelongsToCurrentThread());
if (event_handler_) {
::RemoveEventHandler(event_handler_);
event_handler_ = NULL;
}
}
void SessionWatcher::DisconnectSession() {
if (!caller_task_runner_->BelongsToCurrentThread()) {
caller_task_runner_->PostTask(
FROM_HERE, base::Bind(&SessionWatcher::DisconnectSession, this));
return;
}
if (client_session_control_)
client_session_control_->DisconnectSession();
}
OSStatus SessionWatcher::SessionActivateHandler(EventHandlerCallRef handler,
EventRef event,
void* user_data) {
static_cast<SessionWatcher*>(user_data)->DisconnectSession();
return noErr;
}
}
namespace remoting {
class CurtainModeMac : public CurtainMode {
public:
CurtainModeMac(
scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
base::WeakPtr<ClientSessionControl> client_session_control);
virtual ~CurtainModeMac();
virtual bool Activate() OVERRIDE;
private:
scoped_refptr<SessionWatcher> session_watcher_;
DISALLOW_COPY_AND_ASSIGN(CurtainModeMac);
};
CurtainModeMac::CurtainModeMac(
scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
base::WeakPtr<ClientSessionControl> client_session_control)
: session_watcher_(new SessionWatcher(caller_task_runner,
ui_task_runner,
client_session_control)) {
}
CurtainModeMac::~CurtainModeMac() {
session_watcher_->Stop();
}
bool CurtainModeMac::Activate() {
session_watcher_->Start();
return true;
}
scoped_ptr<CurtainMode> CurtainMode::Create(
scoped_refptr<base::SingleThreadTaskRunner> caller_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner,
base::WeakPtr<ClientSessionControl> client_session_control) {
return scoped_ptr<CurtainMode>(new CurtainModeMac(caller_task_runner,
ui_task_runner,
client_session_control));
}
}