diff options
Diffstat (limited to 'hal/gonk/GonkDiskSpaceWatcher.cpp')
-rw-r--r-- | hal/gonk/GonkDiskSpaceWatcher.cpp | 324 |
1 files changed, 0 insertions, 324 deletions
diff --git a/hal/gonk/GonkDiskSpaceWatcher.cpp b/hal/gonk/GonkDiskSpaceWatcher.cpp deleted file mode 100644 index cdc48ef89..000000000 --- a/hal/gonk/GonkDiskSpaceWatcher.cpp +++ /dev/null @@ -1,324 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "Hal.h" -#include <sys/syscall.h> -#include <sys/vfs.h> -#include <fcntl.h> -#include <errno.h> -#include "base/message_loop.h" -#include "base/task.h" -#include "DiskSpaceWatcher.h" -#include "fanotify.h" -#include "nsIObserverService.h" -#include "nsIDiskSpaceWatcher.h" -#include "nsThreadUtils.h" -#include "nsXULAppAPI.h" -#include "mozilla/ModuleUtils.h" -#include "mozilla/Preferences.h" -#include "mozilla/Services.h" - -using namespace mozilla; - -namespace mozilla { namespace hal_impl { class GonkDiskSpaceWatcher; } } - -using namespace mozilla::hal_impl; - -namespace mozilla { -namespace hal_impl { - -// NOTE: this should be unnecessary once we no longer support ICS. -#ifndef __NR_fanotify_init -#if defined(__ARM_EABI__) -#define __NR_fanotify_init 367 -#define __NR_fanotify_mark 368 -#elif defined(__i386__) -#define __NR_fanotify_init 338 -#define __NR_fanotify_mark 339 -#else -#error "Unhandled architecture" -#endif -#endif - -// fanotify_init and fanotify_mark functions are syscalls. -// The user space bits are not part of bionic so we add them here -// as well as fanotify.h -int fanotify_init (unsigned int flags, unsigned int event_f_flags) -{ - return syscall(__NR_fanotify_init, flags, event_f_flags); -} - -// Add, remove, or modify an fanotify mark on a filesystem object. -int fanotify_mark (int fanotify_fd, unsigned int flags, - uint64_t mask, int dfd, const char *pathname) -{ - - // On 32 bits platforms we have to convert the 64 bits mask into - // two 32 bits ints. - if (sizeof(void *) == 4) { - union { - uint64_t _64; - uint32_t _32[2]; - } _mask; - _mask._64 = mask; - return syscall(__NR_fanotify_mark, fanotify_fd, flags, - _mask._32[0], _mask._32[1], dfd, pathname); - } - - return syscall(__NR_fanotify_mark, fanotify_fd, flags, mask, dfd, pathname); -} - -class GonkDiskSpaceWatcher final : public MessageLoopForIO::Watcher -{ -public: - GonkDiskSpaceWatcher(); - ~GonkDiskSpaceWatcher() {}; - - virtual void OnFileCanReadWithoutBlocking(int aFd); - - // We should never write to the fanotify fd. - virtual void OnFileCanWriteWithoutBlocking(int aFd) - { - MOZ_CRASH("Must not write to fanotify fd"); - } - - void DoStart(); - void DoStop(); - -private: - void NotifyUpdate(); - - uint64_t mLowThreshold; - uint64_t mHighThreshold; - TimeDuration mTimeout; - TimeStamp mLastTimestamp; - uint64_t mLastFreeSpace; - uint32_t mSizeDelta; - - bool mIsDiskFull; - uint64_t mFreeSpace; - - int mFd; - MessageLoopForIO::FileDescriptorWatcher mReadWatcher; -}; - -static GonkDiskSpaceWatcher* gHalDiskSpaceWatcher = nullptr; - -#define WATCHER_PREF_LOW "disk_space_watcher.low_threshold" -#define WATCHER_PREF_HIGH "disk_space_watcher.high_threshold" -#define WATCHER_PREF_TIMEOUT "disk_space_watcher.timeout" -#define WATCHER_PREF_SIZE_DELTA "disk_space_watcher.size_delta" - -static const char kWatchedPath[] = "/data"; - -// Helper class to dispatch calls to xpcom on the main thread. -class DiskSpaceNotifier : public Runnable -{ -public: - DiskSpaceNotifier(const bool aIsDiskFull, const uint64_t aFreeSpace) : - mIsDiskFull(aIsDiskFull), - mFreeSpace(aFreeSpace) {} - - NS_IMETHOD Run() override - { - MOZ_ASSERT(NS_IsMainThread()); - DiskSpaceWatcher::UpdateState(mIsDiskFull, mFreeSpace); - return NS_OK; - } - -private: - bool mIsDiskFull; - uint64_t mFreeSpace; -}; - -// Helper runnable to delete the watcher on the main thread. -class DiskSpaceCleaner : public Runnable -{ -public: - NS_IMETHOD Run() override - { - MOZ_ASSERT(NS_IsMainThread()); - if (gHalDiskSpaceWatcher) { - delete gHalDiskSpaceWatcher; - gHalDiskSpaceWatcher = nullptr; - } - return NS_OK; - } -}; - -GonkDiskSpaceWatcher::GonkDiskSpaceWatcher() : - mLastFreeSpace(UINT64_MAX), - mIsDiskFull(false), - mFreeSpace(UINT64_MAX), - mFd(-1) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(gHalDiskSpaceWatcher == nullptr); - - // Default values: 5MB for low threshold, 10MB for high threshold, and - // a timeout of 5 seconds. - mLowThreshold = Preferences::GetInt(WATCHER_PREF_LOW, 5) * 1024 * 1024; - mHighThreshold = Preferences::GetInt(WATCHER_PREF_HIGH, 10) * 1024 * 1024; - mTimeout = TimeDuration::FromSeconds(Preferences::GetInt(WATCHER_PREF_TIMEOUT, 5)); - mSizeDelta = Preferences::GetInt(WATCHER_PREF_SIZE_DELTA, 1) * 1024 * 1024; -} - -void -GonkDiskSpaceWatcher::DoStart() -{ - NS_ASSERTION(XRE_GetIOMessageLoop() == MessageLoopForIO::current(), - "Not on the correct message loop"); - - mFd = fanotify_init(FAN_CLASS_NOTIF, FAN_CLOEXEC | O_LARGEFILE); - if (mFd == -1) { - if (errno == ENOSYS) { - // Don't change these printf_stderr since we need these logs even - // in opt builds. - printf_stderr("Warning: No fanotify support in this device's kernel.\n"); -#if ANDROID_VERSION >= 19 - MOZ_CRASH("Fanotify support must be enabled in the kernel."); -#endif - } else { - printf_stderr("Error calling fanotify_init()"); - } - return; - } - - if (fanotify_mark(mFd, FAN_MARK_ADD | FAN_MARK_MOUNT, FAN_CLOSE, - 0, kWatchedPath) < 0) { - NS_WARNING("Error calling fanotify_mark"); - close(mFd); - mFd = -1; - return; - } - - if (!MessageLoopForIO::current()->WatchFileDescriptor( - mFd, /* persistent = */ true, - MessageLoopForIO::WATCH_READ, - &mReadWatcher, gHalDiskSpaceWatcher)) { - NS_WARNING("Unable to watch fanotify fd."); - close(mFd); - mFd = -1; - } -} - -void -GonkDiskSpaceWatcher::DoStop() -{ - NS_ASSERTION(XRE_GetIOMessageLoop() == MessageLoopForIO::current(), - "Not on the correct message loop"); - - if (mFd != -1) { - mReadWatcher.StopWatchingFileDescriptor(); - fanotify_mark(mFd, FAN_MARK_FLUSH, 0, 0, kWatchedPath); - close(mFd); - mFd = -1; - } - - // Dispatch the cleanup to the main thread. - nsCOMPtr<nsIRunnable> runnable = new DiskSpaceCleaner(); - NS_DispatchToMainThread(runnable); -} - -// We are called off the main thread, so we proxy first to the main thread -// before calling the xpcom object. -void -GonkDiskSpaceWatcher::NotifyUpdate() -{ - mLastTimestamp = TimeStamp::Now(); - mLastFreeSpace = mFreeSpace; - - nsCOMPtr<nsIRunnable> runnable = - new DiskSpaceNotifier(mIsDiskFull, mFreeSpace); - NS_DispatchToMainThread(runnable); -} - -void -GonkDiskSpaceWatcher::OnFileCanReadWithoutBlocking(int aFd) -{ - struct fanotify_event_metadata* fem = nullptr; - char buf[4096]; - struct statfs sfs; - int32_t len, rc; - - do { - len = read(aFd, buf, sizeof(buf)); - } while(len == -1 && errno == EINTR); - - // Bail out if the file is busy. - if (len < 0 && errno == ETXTBSY) { - return; - } - - // We should get an exact multiple of fanotify_event_metadata - if (len <= 0 || (len % FAN_EVENT_METADATA_LEN != 0)) { - MOZ_CRASH("About to crash: fanotify_event_metadata read error."); - } - - fem = reinterpret_cast<fanotify_event_metadata *>(buf); - - while (FAN_EVENT_OK(fem, len)) { - rc = fstatfs(fem->fd, &sfs); - if (rc < 0) { - NS_WARNING("Unable to stat fan_notify fd"); - } else { - bool firstRun = mFreeSpace == UINT64_MAX; - mFreeSpace = sfs.f_bavail * sfs.f_bsize; - // We change from full <-> free depending on the free space and the - // low and high thresholds. - // Once we are in 'full' mode we send updates for all size changes with - // a minimum of time between messages or when we cross a size change - // threshold. - if (firstRun) { - mIsDiskFull = mFreeSpace <= mLowThreshold; - // Always notify the current state at first run. - NotifyUpdate(); - } else if (!mIsDiskFull && (mFreeSpace <= mLowThreshold)) { - mIsDiskFull = true; - NotifyUpdate(); - } else if (mIsDiskFull && (mFreeSpace > mHighThreshold)) { - mIsDiskFull = false; - NotifyUpdate(); - } else if (mIsDiskFull) { - if (mTimeout < TimeStamp::Now() - mLastTimestamp || - mSizeDelta < llabs(mFreeSpace - mLastFreeSpace)) { - NotifyUpdate(); - } - } - } - close(fem->fd); - fem = FAN_EVENT_NEXT(fem, len); - } -} - -void -StartDiskSpaceWatcher() -{ - MOZ_ASSERT(NS_IsMainThread()); - - // Bail out if called several times. - if (gHalDiskSpaceWatcher != nullptr) { - return; - } - - gHalDiskSpaceWatcher = new GonkDiskSpaceWatcher(); - - XRE_GetIOMessageLoop()->PostTask( - NewNonOwningRunnableMethod(gHalDiskSpaceWatcher, &GonkDiskSpaceWatcher::DoStart)); -} - -void -StopDiskSpaceWatcher() -{ - MOZ_ASSERT(NS_IsMainThread()); - if (!gHalDiskSpaceWatcher) { - return; - } - - XRE_GetIOMessageLoop()->PostTask( - NewNonOwningRunnableMethod(gHalDiskSpaceWatcher, &GonkDiskSpaceWatcher::DoStop)); -} - -} // namespace hal_impl -} // namespace mozilla |