From 5c9672edebef5990fe9fc81fa917287448ac1ac4 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 17 Jun 2014 09:46:48 +0200 Subject: [PATCH] Add watching support for installation location package changes Can be requested/stopped via BPackageRoster::{Start,Stop}Watching(). The notification message has the what code B_PACKAGE_UPDATE and contains fields "event", "location", and "change count". --- headers/os/app/AppDefs.h | 1 + headers/os/package/PackageRoster.h | 23 +++- headers/private/app/RegistrarDefs.h | 4 + src/kits/package/Jamfile | 1 + src/kits/package/PackageRoster.cpp | 70 ++++++++++++ src/servers/package/Volume.cpp | 17 +++ src/servers/registrar/Jamfile | 1 + .../registrar/PackageWatchingManager.cpp | 107 ++++++++++++++++++ .../registrar/PackageWatchingManager.h | 29 +++++ src/servers/registrar/Registrar.cpp | 19 +++- src/servers/registrar/Registrar.h | 2 + 11 files changed, 271 insertions(+), 3 deletions(-) create mode 100644 src/servers/registrar/PackageWatchingManager.cpp create mode 100644 src/servers/registrar/PackageWatchingManager.h diff --git a/headers/os/app/AppDefs.h b/headers/os/app/AppDefs.h index cdc0045e04a..3cc349bd8fe 100644 --- a/headers/os/app/AppDefs.h +++ b/headers/os/app/AppDefs.h @@ -48,6 +48,7 @@ enum { B_MOUSE_UP = '_MUP', B_MOUSE_WHEEL_CHANGED = '_MWC', B_OPEN_IN_WORKSPACE = '_OWS', + B_PACKAGE_UPDATE = '_PKU', B_PRINTER_CHANGED = '_PCH', B_PULSE = '_PUL', B_READY_TO_RUN = '_RTR', diff --git a/headers/os/package/PackageRoster.h b/headers/os/package/PackageRoster.h index 15487c23c12..a9134f52b25 100644 --- a/headers/os/package/PackageRoster.h +++ b/headers/os/package/PackageRoster.h @@ -1,5 +1,5 @@ /* - * Copyright 2011, Haiku, Inc. + * Copyright 2011-2014, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. */ #ifndef _PACKAGE__PACKAGE_ROSTER_H_ @@ -34,6 +34,23 @@ class BRepositoryCache; class BRepositoryConfig; +// watchable events +enum { + B_WATCH_PACKAGE_INSTALLATION_LOCATIONS = 0x0001, + // de-/activation of packages in standard installation locations +}; + +// notification message "event" field values +enum { + B_INSTALLATION_LOCATION_PACKAGES_CHANGED, + // "location": int32 + // the installation location + // (B_PACKAGE_INSTALLATION_LOCATION_{SYSTEM,HOME} + // "change count": int64 + // the installation location change count +}; + + class BPackageRoster { public: BPackageRoster(); @@ -68,6 +85,10 @@ class BPackageRoster { BPackageInstallationLocation location, BPackageInfoSet& packageInfos); + status_t StartWatching(const BMessenger& target, + uint32 eventMask); + status_t StopWatching(const BMessenger& target); + private: status_t _GetRepositoryPath(BPath* path, bool create, directory_which whichDir) const; diff --git a/headers/private/app/RegistrarDefs.h b/headers/private/app/RegistrarDefs.h index ea3d20a70c1..ebc879408fa 100644 --- a/headers/private/app/RegistrarDefs.h +++ b/headers/private/app/RegistrarDefs.h @@ -124,6 +124,10 @@ enum { B_REG_DELETE_USER = 'rdus', B_REG_UPDATE_GROUP = 'rugr', B_REG_DELETE_GROUP = 'rdgr', + + // package watching requests + B_REG_PACKAGE_START_WATCHING = 'rgPw', + B_REG_PACKAGE_STOP_WATCHING = 'rgPx', }; // B_REG_MIME_SET_PARAM "which" constants diff --git a/src/kits/package/Jamfile b/src/kits/package/Jamfile index 3863cd1ea30..8b9644946e3 100644 --- a/src/kits/package/Jamfile +++ b/src/kits/package/Jamfile @@ -1,6 +1,7 @@ SubDir HAIKU_TOP src kits package ; UsePrivateHeaders + app kernel shared storage diff --git a/src/kits/package/PackageRoster.cpp b/src/kits/package/PackageRoster.cpp index 3c0e5125c15..f5c8a42d80c 100644 --- a/src/kits/package/PackageRoster.cpp +++ b/src/kits/package/PackageRoster.cpp @@ -31,6 +31,8 @@ #if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU) # include +# include +# include #endif @@ -225,6 +227,74 @@ BPackageRoster::GetActivePackages(BPackageInstallationLocation location, } +status_t +BPackageRoster::StartWatching(const BMessenger& target, uint32 eventMask) +{ +// This method makes sense only on an installed Haiku, but not for the build +// tools. +#if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU) + // compose the registrar request + BMessage request(::BPrivate::B_REG_PACKAGE_START_WATCHING); + status_t error; + if ((error = request.AddMessenger("target", target)) != B_OK + || (error = request.AddUInt32("events", eventMask)) != B_OK) { + return error; + } + + // send it + BMessage reply; + error = BRoster::Private().SendTo(&request, &reply, false); + if (error != B_OK) + return error; + + // get result + if (reply.what != ::BPrivate::B_REG_SUCCESS) { + int32 result; + if (reply.FindInt32("error", &result) != B_OK) + result = B_ERROR; + return (status_t)error; + } + + return B_OK; +#else + return B_NOT_SUPPORTED; +#endif +} + + +status_t +BPackageRoster::StopWatching(const BMessenger& target) +{ +// This method makes sense only on an installed Haiku, but not for the build +// tools. +#if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU) + // compose the registrar request + BMessage request(::BPrivate::B_REG_PACKAGE_STOP_WATCHING); + status_t error = request.AddMessenger("target", target); + if (error != B_OK) + return error; + + // send it + BMessage reply; + error = BRoster::Private().SendTo(&request, &reply, false); + if (error != B_OK) + return error; + + // get result + if (reply.what != ::BPrivate::B_REG_SUCCESS) { + int32 result; + if (reply.FindInt32("error", &result) != B_OK) + result = B_ERROR; + return (status_t)error; + } + + return B_OK; +#else + return B_NOT_SUPPORTED; +#endif +} + + status_t BPackageRoster::_GetRepositoryPath(BPath* path, bool create, directory_which whichDir) const diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp index acec55b35be..38453dd0bee 100644 --- a/src/servers/package/Volume.cpp +++ b/src/servers/package/Volume.cpp @@ -22,8 +22,10 @@ #include #include #include +#include #include +#include #include #include #include @@ -35,12 +37,14 @@ #include #include #include +#include #include "CommitTransactionHandler.h" #include "Constants.h" #include "DebugSupport.h" #include "Exception.h" #include "PackageFileManager.h" +#include "Root.h" #include "VolumeState.h" @@ -1193,6 +1197,19 @@ Volume::_SetLatestState(VolumeState* state, bool isActive) delete fLatestState; fLatestState = state; fChangeCount++; + + locker.Unlock(); + + // Send a notification, if this is a system root volume. + if (fRoot->IsSystemRoot()) { + BMessage message(B_PACKAGE_UPDATE); + if (message.AddInt32("event", + (int32)B_INSTALLATION_LOCATION_PACKAGES_CHANGED) == B_OK + && message.AddInt32("location", (int32)Location()) == B_OK + && message.AddInt64("change count", fChangeCount) == B_OK) { + BRoster::Private().SendTo(&message, NULL, false); + } + } } diff --git a/src/servers/registrar/Jamfile b/src/servers/registrar/Jamfile index 40b34162a0d..7aef8a29bfa 100644 --- a/src/servers/registrar/Jamfile +++ b/src/servers/registrar/Jamfile @@ -27,6 +27,7 @@ Server registrar MessageRunnerManager.cpp MessagingService.cpp MIMEManager.cpp + PackageWatchingManager.cpp PriorityMessageQueue.cpp RecentApps.cpp RecentEntries.cpp diff --git a/src/servers/registrar/PackageWatchingManager.cpp b/src/servers/registrar/PackageWatchingManager.cpp new file mode 100644 index 00000000000..6716cb5d98c --- /dev/null +++ b/src/servers/registrar/PackageWatchingManager.cpp @@ -0,0 +1,107 @@ +/* + * Copyright 2014, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "PackageWatchingManager.h" + +#include + +#include + +#include + +#include "Debug.h" +#include "EventMaskWatcher.h" + + +using namespace BPackageKit; +using namespace BPrivate; + + +PackageWatchingManager::PackageWatchingManager() +{ +} + + +PackageWatchingManager::~PackageWatchingManager() +{ +} + + +void +PackageWatchingManager::HandleStartStopWatching(BMessage* request) +{ + status_t error = request->what == B_REG_PACKAGE_START_WATCHING + ? _AddWatcher(request) : _RemoveWatcher(request); + + if (error == B_OK) { + BMessage reply(B_REG_SUCCESS); + request->SendReply(&reply); + } else { + BMessage reply(B_REG_ERROR); + reply.AddInt32("error", error); + request->SendReply(&reply); + } +} + + +void +PackageWatchingManager::NotifyWatchers(BMessage* message) +{ + int32 event; + if (message->FindInt32("event", &event) != B_OK) { + WARNING("No event field in notification message\n"); + return; + } + + uint32 eventMask; + switch (event) { + case B_INSTALLATION_LOCATION_PACKAGES_CHANGED: + eventMask = B_WATCH_PACKAGE_INSTALLATION_LOCATIONS; + break; + default: + WARNING("Invalid event: %" B_PRId32 "\n", event); + return; + } + + EventMaskWatcherFilter filter(eventMask); + fWatchingService.NotifyWatchers(message, &filter); +} + + +status_t +PackageWatchingManager::_AddWatcher(const BMessage* request) +{ + BMessenger target; + uint32 eventMask; + status_t error; + if ((error = request->FindMessenger("target", &target)) != B_OK + || (error = request->FindUInt32("events", &eventMask)) != B_OK) { + return error; + } + + Watcher* watcher = new(std::nothrow) EventMaskWatcher(target, eventMask); + if (watcher == NULL || !fWatchingService.AddWatcher(watcher)) { + delete watcher; + return B_NO_MEMORY; + } + + return B_OK; +} + + +status_t +PackageWatchingManager::_RemoveWatcher(const BMessage* request) +{ + BMessenger target; + status_t error; + if ((error = request->FindMessenger("target", &target)) != B_OK) + return error; + + if (!fWatchingService.RemoveWatcher(target)) + return B_BAD_VALUE; + + return B_OK; +} diff --git a/src/servers/registrar/PackageWatchingManager.h b/src/servers/registrar/PackageWatchingManager.h new file mode 100644 index 00000000000..9e07829d4d7 --- /dev/null +++ b/src/servers/registrar/PackageWatchingManager.h @@ -0,0 +1,29 @@ +/* + * Copyright 2014, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef PACKAGE_WATCHING_MANAGER_H +#define PACKAGE_WATCHING_MANAGER_H + + +#include "WatchingService.h" + + +class PackageWatchingManager { +public: + PackageWatchingManager(); + ~PackageWatchingManager(); + + void HandleStartStopWatching(BMessage* request); + void NotifyWatchers(BMessage* message); + +private: + status_t _AddWatcher(const BMessage* request); + status_t _RemoveWatcher(const BMessage* request); + +private: + WatchingService fWatchingService; +}; + + +#endif // PACKAGE_WATCHING_MANAGER_H diff --git a/src/servers/registrar/Registrar.cpp b/src/servers/registrar/Registrar.cpp index 5a54d19b3a8..76cf3e3ca24 100644 --- a/src/servers/registrar/Registrar.cpp +++ b/src/servers/registrar/Registrar.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2001-2009, Haiku, Inc. All Rights Reserved. + * Copyright 2001-2014, Haiku, Inc. All Rights Reserved. * Distributed under the terms of the MIT License. * * Authors: @@ -29,6 +29,7 @@ #include "MessageRunnerManager.h" #include "MessagingService.h" #include "MIMEManager.h" +#include "PackageWatchingManager.h" #include "ShutdownProcess.h" #include "TRoster.h" @@ -64,7 +65,8 @@ Registrar::Registrar(status_t *error) fMessageRunnerManager(NULL), fSanityEvent(NULL), fShutdownProcess(NULL), - fAuthenticationManager(NULL) + fAuthenticationManager(NULL), + fPackageWatchingManager(NULL) { FUNCTION_START(); @@ -83,6 +85,7 @@ Registrar::~Registrar() Lock(); fEventQueue->Die(); delete fAuthenticationManager; + delete fPackageWatchingManager; delete fMessageRunnerManager; delete fEventQueue; delete fSanityEvent; @@ -166,6 +169,9 @@ Registrar::ReadyToRun() "(that's by design when running under R5): %s\n", strerror(error)); } + // create the package watching manager + fPackageWatchingManager = new PackageWatchingManager; + // create and schedule the sanity message event fSanityEvent = new MessageEvent(system_time() + kRosterSanityEventInterval, this, B_REG_ROSTER_SANITY_EVENT); @@ -336,6 +342,15 @@ Registrar::_MessageReceived(BMessage *message) fMessageRunnerManager->HandleGetRunnerInfo(message); break; + // package watching requests + case B_REG_PACKAGE_START_WATCHING: + case B_REG_PACKAGE_STOP_WATCHING: + fPackageWatchingManager->HandleStartStopWatching(message); + break; + case B_PACKAGE_UPDATE: + fPackageWatchingManager->NotifyWatchers(message); + break; + // internal messages case B_REG_ROSTER_SANITY_EVENT: fRoster->CheckSanity(); diff --git a/src/servers/registrar/Registrar.h b/src/servers/registrar/Registrar.h index 26c4a50f7d9..8be92571158 100644 --- a/src/servers/registrar/Registrar.h +++ b/src/servers/registrar/Registrar.h @@ -36,6 +36,7 @@ class EventQueue; class MessageEvent; class MessageRunnerManager; class MIMEManager; +class PackageWatchingManager; class ShutdownProcess; class TRoster; @@ -66,6 +67,7 @@ class Registrar : public BServer { MessageEvent *fSanityEvent; ShutdownProcess *fShutdownProcess; AuthenticationManager *fAuthenticationManager; + PackageWatchingManager *fPackageWatchingManager; }; #endif // REGISTRAR_H