mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-09-30 12:27:29 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
1003
hal/Hal.cpp
Normal file
1003
hal/Hal.cpp
Normal file
File diff suppressed because it is too large
Load diff
560
hal/Hal.h
Normal file
560
hal/Hal.h
Normal file
|
|
@ -0,0 +1,560 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_Hal_h
|
||||
#define mozilla_Hal_h
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/platform_thread.h"
|
||||
#include "nsTArray.h"
|
||||
#include "mozilla/dom/battery/Types.h"
|
||||
#include "mozilla/dom/MozPowerManagerBinding.h"
|
||||
#include "mozilla/dom/network/Types.h"
|
||||
#include "mozilla/dom/power/Types.h"
|
||||
#include "mozilla/dom/ScreenOrientation.h"
|
||||
#include "mozilla/hal_sandbox/PHal.h"
|
||||
#include "mozilla/HalScreenConfiguration.h"
|
||||
#include "mozilla/HalTypes.h"
|
||||
#include "mozilla/Observer.h"
|
||||
#include "mozilla/Types.h"
|
||||
|
||||
/*
|
||||
* Hal.h contains the public Hal API.
|
||||
*
|
||||
* By default, this file defines its functions in the hal namespace, but if
|
||||
* MOZ_HAL_NAMESPACE is defined, we'll define our functions in that namespace.
|
||||
*
|
||||
* This is used by HalImpl.h and HalSandbox.h, which define copies of all the
|
||||
* functions here in the hal_impl and hal_sandbox namespaces.
|
||||
*/
|
||||
|
||||
class nsPIDOMWindowInner;
|
||||
|
||||
#ifndef MOZ_HAL_NAMESPACE
|
||||
# define MOZ_HAL_NAMESPACE hal
|
||||
# define MOZ_DEFINED_HAL_NAMESPACE 1
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace hal {
|
||||
|
||||
typedef Observer<void_t> AlarmObserver;
|
||||
|
||||
class WindowIdentifier;
|
||||
|
||||
typedef Observer<int64_t> SystemClockChangeObserver;
|
||||
typedef Observer<SystemTimezoneChangeInformation> SystemTimezoneChangeObserver;
|
||||
|
||||
} // namespace hal
|
||||
|
||||
namespace MOZ_HAL_NAMESPACE {
|
||||
|
||||
/**
|
||||
* Turn the default vibrator device on/off per the pattern specified
|
||||
* by |pattern|. Each element in the pattern is the number of
|
||||
* milliseconds to turn the vibrator on or off. The first element in
|
||||
* |pattern| is an "on" element, the next is "off", and so on.
|
||||
*
|
||||
* If |pattern| is empty, any in-progress vibration is canceled.
|
||||
*
|
||||
* Only an active window within an active tab may call Vibrate; calls
|
||||
* from inactive windows and windows on inactive tabs do nothing.
|
||||
*
|
||||
* If you're calling hal::Vibrate from the outside world, pass an
|
||||
* nsIDOMWindow* in place of the WindowIdentifier parameter.
|
||||
* The method with WindowIdentifier will be called automatically.
|
||||
*/
|
||||
void Vibrate(const nsTArray<uint32_t>& pattern,
|
||||
nsPIDOMWindowInner* aWindow);
|
||||
void Vibrate(const nsTArray<uint32_t>& pattern,
|
||||
const hal::WindowIdentifier &id);
|
||||
|
||||
/**
|
||||
* Cancel a vibration started by the content window identified by
|
||||
* WindowIdentifier.
|
||||
*
|
||||
* If the window was the last window to start a vibration, the
|
||||
* cancellation request will go through even if the window is not
|
||||
* active.
|
||||
*
|
||||
* As with hal::Vibrate(), if you're calling hal::CancelVibrate from the outside
|
||||
* world, pass an nsIDOMWindow*. The method with WindowIdentifier will be called
|
||||
* automatically.
|
||||
*/
|
||||
void CancelVibrate(nsPIDOMWindowInner* aWindow);
|
||||
void CancelVibrate(const hal::WindowIdentifier &id);
|
||||
|
||||
/**
|
||||
* Inform the battery backend there is a new battery observer.
|
||||
* @param aBatteryObserver The observer that should be added.
|
||||
*/
|
||||
void RegisterBatteryObserver(BatteryObserver* aBatteryObserver);
|
||||
|
||||
/**
|
||||
* Inform the battery backend a battery observer unregistered.
|
||||
* @param aBatteryObserver The observer that should be removed.
|
||||
*/
|
||||
void UnregisterBatteryObserver(BatteryObserver* aBatteryObserver);
|
||||
|
||||
/**
|
||||
* Returns the current battery information.
|
||||
*/
|
||||
void GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo);
|
||||
|
||||
/**
|
||||
* Notify of a change in the battery state.
|
||||
* @param aBatteryInfo The new battery information.
|
||||
*/
|
||||
void NotifyBatteryChange(const hal::BatteryInformation& aBatteryInfo);
|
||||
|
||||
/**
|
||||
* Determine whether the device's screen is currently enabled.
|
||||
*/
|
||||
bool GetScreenEnabled();
|
||||
|
||||
/**
|
||||
* Enable or disable the device's screen.
|
||||
*
|
||||
* Note that it may take a few seconds for the screen to turn on or off.
|
||||
*/
|
||||
void SetScreenEnabled(bool aEnabled);
|
||||
|
||||
/**
|
||||
* Determine whether the device's keypad/button backlight is currently enabled.
|
||||
*/
|
||||
bool GetKeyLightEnabled();
|
||||
|
||||
/**
|
||||
* Enable or disable the device's keypad/button backlight.
|
||||
*/
|
||||
void SetKeyLightEnabled(bool aEnabled);
|
||||
|
||||
/**
|
||||
* Get the brightness of the device's screen's backlight, on a scale from 0
|
||||
* (very dim) to 1 (full blast).
|
||||
*
|
||||
* If the display is currently disabled, this returns the brightness the
|
||||
* backlight will have when the display is re-enabled.
|
||||
*/
|
||||
double GetScreenBrightness();
|
||||
|
||||
/**
|
||||
* Set the brightness of the device's screen's backlight, on a scale from 0
|
||||
* (very dimm) to 1 (full blast). Values larger than 1 are treated like 1, and
|
||||
* values smaller than 0 are treated like 0.
|
||||
*
|
||||
* Note that we may reduce the resolution of the given brightness value before
|
||||
* sending it to the screen. Therefore if you call SetScreenBrightness(x)
|
||||
* followed by GetScreenBrightness(), the value returned by
|
||||
* GetScreenBrightness() may not be exactly x.
|
||||
*/
|
||||
void SetScreenBrightness(double aBrightness);
|
||||
|
||||
/**
|
||||
* Determine whether the device is allowed to sleep.
|
||||
*/
|
||||
bool GetCpuSleepAllowed();
|
||||
|
||||
/**
|
||||
* Set whether the device is allowed to suspend automatically after
|
||||
* the screen is disabled.
|
||||
*/
|
||||
void SetCpuSleepAllowed(bool aAllowed);
|
||||
|
||||
/**
|
||||
* Register an observer for the sensor of given type.
|
||||
*
|
||||
* The observer will receive data whenever the data generated by the
|
||||
* sensor is avaiable.
|
||||
*/
|
||||
void RegisterSensorObserver(hal::SensorType aSensor,
|
||||
hal::ISensorObserver *aObserver);
|
||||
|
||||
/**
|
||||
* Unregister an observer for the sensor of given type.
|
||||
*/
|
||||
void UnregisterSensorObserver(hal::SensorType aSensor,
|
||||
hal::ISensorObserver *aObserver);
|
||||
|
||||
/**
|
||||
* Post a value generated by a sensor.
|
||||
*
|
||||
* This API is internal to hal; clients shouldn't call it directly.
|
||||
*/
|
||||
void NotifySensorChange(const hal::SensorData &aSensorData);
|
||||
|
||||
/**
|
||||
* Enable sensor notifications from the backend
|
||||
*
|
||||
* This method is only visible from implementation of sensor manager.
|
||||
* Rest of the system should not try this.
|
||||
*/
|
||||
void EnableSensorNotifications(hal::SensorType aSensor);
|
||||
|
||||
/**
|
||||
* Disable sensor notifications from the backend
|
||||
*
|
||||
* This method is only visible from implementation of sensor manager.
|
||||
* Rest of the system should not try this.
|
||||
*/
|
||||
void DisableSensorNotifications(hal::SensorType aSensor);
|
||||
|
||||
|
||||
/**
|
||||
* Inform the network backend there is a new network observer.
|
||||
* @param aNetworkObserver The observer that should be added.
|
||||
*/
|
||||
void RegisterNetworkObserver(NetworkObserver* aNetworkObserver);
|
||||
|
||||
/**
|
||||
* Inform the network backend a network observer unregistered.
|
||||
* @param aNetworkObserver The observer that should be removed.
|
||||
*/
|
||||
void UnregisterNetworkObserver(NetworkObserver* aNetworkObserver);
|
||||
|
||||
/**
|
||||
* Returns the current network information.
|
||||
*/
|
||||
void GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo);
|
||||
|
||||
/**
|
||||
* Notify of a change in the network state.
|
||||
* @param aNetworkInfo The new network information.
|
||||
*/
|
||||
void NotifyNetworkChange(const hal::NetworkInformation& aNetworkInfo);
|
||||
|
||||
/**
|
||||
* Adjusting system clock.
|
||||
* @param aDeltaMilliseconds The difference compared with current system clock.
|
||||
*/
|
||||
void AdjustSystemClock(int64_t aDeltaMilliseconds);
|
||||
|
||||
/**
|
||||
* Set timezone
|
||||
* @param aTimezoneSpec The definition can be found in
|
||||
* http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
||||
*/
|
||||
void SetTimezone(const nsCString& aTimezoneSpec);
|
||||
|
||||
/**
|
||||
* Get timezone
|
||||
* http://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
||||
*/
|
||||
nsCString GetTimezone();
|
||||
|
||||
/**
|
||||
* Get timezone offset
|
||||
* returns the timezone offset relative to UTC in minutes (DST effect included)
|
||||
*/
|
||||
int32_t GetTimezoneOffset();
|
||||
|
||||
/**
|
||||
* Register observer for system clock changed notification.
|
||||
* @param aObserver The observer that should be added.
|
||||
*/
|
||||
void RegisterSystemClockChangeObserver(
|
||||
hal::SystemClockChangeObserver* aObserver);
|
||||
|
||||
/**
|
||||
* Unregister the observer for system clock changed.
|
||||
* @param aObserver The observer that should be removed.
|
||||
*/
|
||||
void UnregisterSystemClockChangeObserver(
|
||||
hal::SystemClockChangeObserver* aObserver);
|
||||
|
||||
/**
|
||||
* Notify of a change in the system clock.
|
||||
* @param aClockDeltaMS
|
||||
*/
|
||||
void NotifySystemClockChange(const int64_t& aClockDeltaMS);
|
||||
|
||||
/**
|
||||
* Register observer for system timezone changed notification.
|
||||
* @param aObserver The observer that should be added.
|
||||
*/
|
||||
void RegisterSystemTimezoneChangeObserver(
|
||||
hal::SystemTimezoneChangeObserver* aObserver);
|
||||
|
||||
/**
|
||||
* Unregister the observer for system timezone changed.
|
||||
* @param aObserver The observer that should be removed.
|
||||
*/
|
||||
void UnregisterSystemTimezoneChangeObserver(
|
||||
hal::SystemTimezoneChangeObserver* aObserver);
|
||||
|
||||
/**
|
||||
* Notify of a change in the system timezone.
|
||||
* @param aSystemTimezoneChangeInfo
|
||||
*/
|
||||
void NotifySystemTimezoneChange(
|
||||
const hal::SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo);
|
||||
|
||||
/**
|
||||
* Reboot the device.
|
||||
*
|
||||
* This API is currently only allowed to be used from the main process.
|
||||
*/
|
||||
void Reboot();
|
||||
|
||||
/**
|
||||
* Power off the device.
|
||||
*
|
||||
* This API is currently only allowed to be used from the main process.
|
||||
*/
|
||||
void PowerOff();
|
||||
|
||||
/**
|
||||
* Enable wake lock notifications from the backend.
|
||||
*
|
||||
* This method is only used by WakeLockObserversManager.
|
||||
*/
|
||||
void EnableWakeLockNotifications();
|
||||
|
||||
/**
|
||||
* Disable wake lock notifications from the backend.
|
||||
*
|
||||
* This method is only used by WakeLockObserversManager.
|
||||
*/
|
||||
void DisableWakeLockNotifications();
|
||||
|
||||
/**
|
||||
* Inform the wake lock backend there is a new wake lock observer.
|
||||
* @param aWakeLockObserver The observer that should be added.
|
||||
*/
|
||||
void RegisterWakeLockObserver(WakeLockObserver* aObserver);
|
||||
|
||||
/**
|
||||
* Inform the wake lock backend a wake lock observer unregistered.
|
||||
* @param aWakeLockObserver The observer that should be removed.
|
||||
*/
|
||||
void UnregisterWakeLockObserver(WakeLockObserver* aObserver);
|
||||
|
||||
/**
|
||||
* Adjust a wake lock's counts on behalf of a given process.
|
||||
*
|
||||
* In most cases, you shouldn't need to pass the aProcessID argument; the
|
||||
* default of CONTENT_PROCESS_ID_UNKNOWN is probably what you want.
|
||||
*
|
||||
* @param aTopic lock topic
|
||||
* @param aLockAdjust to increase or decrease active locks
|
||||
* @param aHiddenAdjust to increase or decrease hidden locks
|
||||
* @param aProcessID indicates which process we're modifying the wake lock
|
||||
* on behalf of. It is interpreted as
|
||||
*
|
||||
* CONTENT_PROCESS_ID_UNKNOWN: The current process
|
||||
* CONTENT_PROCESS_ID_MAIN: The root process
|
||||
* X: The process with ContentChild::GetID() == X
|
||||
*/
|
||||
void ModifyWakeLock(const nsAString &aTopic,
|
||||
hal::WakeLockControl aLockAdjust,
|
||||
hal::WakeLockControl aHiddenAdjust,
|
||||
uint64_t aProcessID = hal::CONTENT_PROCESS_ID_UNKNOWN);
|
||||
|
||||
/**
|
||||
* Query the wake lock numbers of aTopic.
|
||||
* @param aTopic lock topic
|
||||
* @param aWakeLockInfo wake lock numbers
|
||||
*/
|
||||
void GetWakeLockInfo(const nsAString &aTopic, hal::WakeLockInformation *aWakeLockInfo);
|
||||
|
||||
/**
|
||||
* Notify of a change in the wake lock state.
|
||||
* @param aWakeLockInfo The new wake lock information.
|
||||
*/
|
||||
void NotifyWakeLockChange(const hal::WakeLockInformation& aWakeLockInfo);
|
||||
|
||||
/**
|
||||
* Inform the backend there is a new screen configuration observer.
|
||||
* @param aScreenConfigurationObserver The observer that should be added.
|
||||
*/
|
||||
void RegisterScreenConfigurationObserver(hal::ScreenConfigurationObserver* aScreenConfigurationObserver);
|
||||
|
||||
/**
|
||||
* Inform the backend a screen configuration observer unregistered.
|
||||
* @param aScreenConfigurationObserver The observer that should be removed.
|
||||
*/
|
||||
void UnregisterScreenConfigurationObserver(hal::ScreenConfigurationObserver* aScreenConfigurationObserver);
|
||||
|
||||
/**
|
||||
* Returns the current screen configuration.
|
||||
*/
|
||||
void GetCurrentScreenConfiguration(hal::ScreenConfiguration* aScreenConfiguration);
|
||||
|
||||
/**
|
||||
* Notify of a change in the screen configuration.
|
||||
* @param aScreenConfiguration The new screen orientation.
|
||||
*/
|
||||
void NotifyScreenConfigurationChange(const hal::ScreenConfiguration& aScreenConfiguration);
|
||||
|
||||
/**
|
||||
* Lock the screen orientation to the specific orientation.
|
||||
* @return Whether the lock has been accepted.
|
||||
*/
|
||||
MOZ_MUST_USE bool LockScreenOrientation(const dom::ScreenOrientationInternal& aOrientation);
|
||||
|
||||
/**
|
||||
* Unlock the screen orientation.
|
||||
*/
|
||||
void UnlockScreenOrientation();
|
||||
|
||||
/**
|
||||
* Register an observer for the switch of given SwitchDevice.
|
||||
*
|
||||
* The observer will receive data whenever the data generated by the
|
||||
* given switch.
|
||||
*/
|
||||
void RegisterSwitchObserver(hal::SwitchDevice aDevice, hal::SwitchObserver *aSwitchObserver);
|
||||
|
||||
/**
|
||||
* Unregister an observer for the switch of given SwitchDevice.
|
||||
*/
|
||||
void UnregisterSwitchObserver(hal::SwitchDevice aDevice, hal::SwitchObserver *aSwitchObserver);
|
||||
|
||||
/**
|
||||
* Notify the state of the switch.
|
||||
*
|
||||
* This API is internal to hal; clients shouldn't call it directly.
|
||||
*/
|
||||
void NotifySwitchChange(const hal::SwitchEvent& aEvent);
|
||||
|
||||
/**
|
||||
* Get current switch information.
|
||||
*/
|
||||
hal::SwitchState GetCurrentSwitchState(hal::SwitchDevice aDevice);
|
||||
|
||||
/**
|
||||
* Notify switch status change from input device.
|
||||
*/
|
||||
void NotifySwitchStateFromInputDevice(hal::SwitchDevice aDevice,
|
||||
hal::SwitchState aState);
|
||||
|
||||
/**
|
||||
* Register an observer that is notified when a programmed alarm
|
||||
* expires.
|
||||
*
|
||||
* Currently, there can only be 0 or 1 alarm observers.
|
||||
*/
|
||||
MOZ_MUST_USE bool RegisterTheOneAlarmObserver(hal::AlarmObserver* aObserver);
|
||||
|
||||
/**
|
||||
* Unregister the alarm observer. Doing so will implicitly cancel any
|
||||
* programmed alarm.
|
||||
*/
|
||||
void UnregisterTheOneAlarmObserver();
|
||||
|
||||
/**
|
||||
* Notify that the programmed alarm has expired.
|
||||
*
|
||||
* This API is internal to hal; clients shouldn't call it directly.
|
||||
*/
|
||||
void NotifyAlarmFired();
|
||||
|
||||
/**
|
||||
* Program the real-time clock to expire at the time |aSeconds|,
|
||||
* |aNanoseconds|. These specify a point in real time relative to the
|
||||
* UNIX epoch. The alarm will fire at this time point even if the
|
||||
* real-time clock is changed; that is, this alarm respects changes to
|
||||
* the real-time clock. Return true iff the alarm was programmed.
|
||||
*
|
||||
* The alarm can be reprogrammed at any time.
|
||||
*
|
||||
* This API is currently only allowed to be used from non-sandboxed
|
||||
* contexts.
|
||||
*/
|
||||
MOZ_MUST_USE bool SetAlarm(int32_t aSeconds, int32_t aNanoseconds);
|
||||
|
||||
/**
|
||||
* Set the priority of the given process.
|
||||
*
|
||||
* Exactly what this does will vary between platforms. On *nix we might give
|
||||
* background processes higher nice values. On other platforms, we might
|
||||
* ignore this call entirely.
|
||||
*/
|
||||
void SetProcessPriority(int aPid,
|
||||
hal::ProcessPriority aPriority,
|
||||
uint32_t aLRU = 0);
|
||||
|
||||
|
||||
/**
|
||||
* Set the current thread's priority to appropriate platform-specific value for
|
||||
* given functionality. Instead of providing arbitrary priority numbers you
|
||||
* must specify a type of function like THREAD_PRIORITY_COMPOSITOR.
|
||||
*/
|
||||
void SetCurrentThreadPriority(hal::ThreadPriority aThreadPriority);
|
||||
|
||||
/**
|
||||
* Set a thread priority to appropriate platform-specific value for
|
||||
* given functionality. Instead of providing arbitrary priority numbers you
|
||||
* must specify a type of function like THREAD_PRIORITY_COMPOSITOR.
|
||||
*/
|
||||
void SetThreadPriority(PlatformThreadId aThreadId,
|
||||
hal::ThreadPriority aThreadPriority);
|
||||
|
||||
/**
|
||||
* Start a watchdog to compulsively shutdown the system if it hangs.
|
||||
* @param aMode Specify how to shutdown the system.
|
||||
* @param aTimeoutSecs Specify the delayed seconds to shutdown the system.
|
||||
*
|
||||
* This API is currently only allowed to be used from the main process.
|
||||
*/
|
||||
void StartForceQuitWatchdog(hal::ShutdownMode aMode, int32_t aTimeoutSecs);
|
||||
|
||||
/**
|
||||
* Perform Factory Reset to wipe out all user data.
|
||||
*/
|
||||
void FactoryReset(mozilla::dom::FactoryResetReason& aReason);
|
||||
|
||||
/**
|
||||
* Start monitoring disk space for low space situations.
|
||||
*
|
||||
* This API is currently only allowed to be used from the main process.
|
||||
*/
|
||||
void StartDiskSpaceWatcher();
|
||||
|
||||
/**
|
||||
* Stop monitoring disk space for low space situations.
|
||||
*
|
||||
* This API is currently only allowed to be used from the main process.
|
||||
*/
|
||||
void StopDiskSpaceWatcher();
|
||||
|
||||
/**
|
||||
* Get total system memory of device being run on in bytes.
|
||||
*
|
||||
* Returns 0 if we are unable to determine this information from /proc/meminfo.
|
||||
*/
|
||||
uint32_t GetTotalSystemMemory();
|
||||
|
||||
/**
|
||||
* Determine whether the headphone switch event is from input device
|
||||
*/
|
||||
bool IsHeadphoneEventFromInputDev();
|
||||
|
||||
/**
|
||||
* Start the system service with the specified name and arguments.
|
||||
*/
|
||||
nsresult StartSystemService(const char* aSvcName, const char* aArgs);
|
||||
|
||||
/**
|
||||
* Stop the system service with the specified name.
|
||||
*/
|
||||
void StopSystemService(const char* aSvcName);
|
||||
|
||||
/**
|
||||
* Determine whether the system service with the specified name is running.
|
||||
*/
|
||||
bool SystemServiceIsRunning(const char* aSvcName);
|
||||
|
||||
} // namespace MOZ_HAL_NAMESPACE
|
||||
} // namespace mozilla
|
||||
|
||||
#ifdef MOZ_DEFINED_HAL_NAMESPACE
|
||||
# undef MOZ_DEFINED_HAL_NAMESPACE
|
||||
# undef MOZ_HAL_NAMESPACE
|
||||
#endif
|
||||
|
||||
#endif // mozilla_Hal_h
|
||||
21
hal/HalImpl.h
Normal file
21
hal/HalImpl.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_HalImpl_h
|
||||
#define mozilla_HalImpl_h
|
||||
|
||||
#ifdef MOZ_UNIFIED_BUILD
|
||||
#error Cannot use HalImpl.h in unified builds.
|
||||
#endif
|
||||
|
||||
#define MOZ_HAL_NAMESPACE hal_impl
|
||||
#undef mozilla_Hal_h
|
||||
#undef mozilla_HalInternal_h
|
||||
#include "Hal.h"
|
||||
#include "HalInternal.h"
|
||||
#undef MOZ_HAL_NAMESPACE
|
||||
|
||||
#endif // mozilla_HalImpl_h
|
||||
105
hal/HalInternal.h
Normal file
105
hal/HalInternal.h
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_HalInternal_h
|
||||
#define mozilla_HalInternal_h 1
|
||||
|
||||
/*
|
||||
* This file is included by HalImpl.h and HalSandbox.h with a mechanism similar
|
||||
* to Hal.h. That means those headers set MOZ_HAL_NAMESPACE to specify in which
|
||||
* namespace the internal functions should appear.
|
||||
*
|
||||
* The difference between Hal.h and HalInternal.h is that methods declared in
|
||||
* HalInternal.h don't appear in the hal namespace. That also means this file
|
||||
* should not be included except by HalImpl.h and HalSandbox.h.
|
||||
*/
|
||||
|
||||
#ifndef MOZ_HAL_NAMESPACE
|
||||
# error "You shouldn't directly include HalInternal.h!"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace MOZ_HAL_NAMESPACE {
|
||||
|
||||
/**
|
||||
* Enables battery notifications from the backend.
|
||||
*/
|
||||
void EnableBatteryNotifications();
|
||||
|
||||
/**
|
||||
* Disables battery notifications from the backend.
|
||||
*/
|
||||
void DisableBatteryNotifications();
|
||||
|
||||
/**
|
||||
* Enables network notifications from the backend.
|
||||
*/
|
||||
void EnableNetworkNotifications();
|
||||
|
||||
/**
|
||||
* Disables network notifications from the backend.
|
||||
*/
|
||||
void DisableNetworkNotifications();
|
||||
|
||||
/**
|
||||
* Enables screen orientation notifications from the backend.
|
||||
*/
|
||||
void EnableScreenConfigurationNotifications();
|
||||
|
||||
/**
|
||||
* Disables screen orientation notifications from the backend.
|
||||
*/
|
||||
void DisableScreenConfigurationNotifications();
|
||||
|
||||
/**
|
||||
* Enable switch notifications from the backend
|
||||
*/
|
||||
void EnableSwitchNotifications(hal::SwitchDevice aDevice);
|
||||
|
||||
/**
|
||||
* Disable switch notifications from the backend
|
||||
*/
|
||||
void DisableSwitchNotifications(hal::SwitchDevice aDevice);
|
||||
|
||||
/**
|
||||
* Enable alarm notifications from the backend.
|
||||
*/
|
||||
MOZ_MUST_USE bool EnableAlarm();
|
||||
|
||||
/**
|
||||
* Disable alarm notifications from the backend.
|
||||
*/
|
||||
void DisableAlarm();
|
||||
|
||||
/**
|
||||
* Enable system clock change notifications from the backend.
|
||||
*/
|
||||
void EnableSystemClockChangeNotifications();
|
||||
|
||||
/**
|
||||
* Disable system clock change notifications from the backend.
|
||||
*/
|
||||
void DisableSystemClockChangeNotifications();
|
||||
|
||||
/**
|
||||
* Enable system timezone change notifications from the backend.
|
||||
*/
|
||||
void EnableSystemTimezoneChangeNotifications();
|
||||
|
||||
/**
|
||||
* Disable system timezone change notifications from the backend.
|
||||
*/
|
||||
void DisableSystemTimezoneChangeNotifications();
|
||||
|
||||
/**
|
||||
* Has the child-side HAL IPC object been destroyed? If so, you shouldn't send
|
||||
* messages to hal_sandbox.
|
||||
*/
|
||||
bool HalChildDestroyed();
|
||||
} // namespace MOZ_HAL_NAMESPACE
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_HalInternal_h
|
||||
33
hal/HalLog.h
Normal file
33
hal/HalLog.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_HalLog_h
|
||||
#define mozilla_HalLog_h
|
||||
|
||||
#include "mozilla/Logging.h"
|
||||
|
||||
/*
|
||||
* HalLog.h contains internal macros and functions used for logging.
|
||||
*
|
||||
* This should be considered a private include and not used in non-HAL code.
|
||||
* To enable logging in non-debug builds define the PR_FORCE_LOG macro here.
|
||||
*/
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace hal {
|
||||
|
||||
mozilla::LogModule *GetHalLog();
|
||||
#define HAL_LOG(...) \
|
||||
MOZ_LOG(mozilla::hal::GetHalLog(), LogLevel::Debug, (__VA_ARGS__))
|
||||
#define HAL_ERR(...) \
|
||||
MOZ_LOG(mozilla::hal::GetHalLog(), LogLevel::Error, (__VA_ARGS__))
|
||||
|
||||
} // namespace hal
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_HalLog_h
|
||||
17
hal/HalSandbox.h
Normal file
17
hal/HalSandbox.h
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_hal_HalSandbox_h
|
||||
#define mozilla_hal_HalSandbox_h
|
||||
|
||||
#define MOZ_HAL_NAMESPACE hal_sandbox
|
||||
#undef mozilla_Hal_h
|
||||
#undef mozilla_HalInternal_h
|
||||
#include "Hal.h"
|
||||
#include "HalInternal.h"
|
||||
#undef MOZ_HAL_NAMESPACE
|
||||
|
||||
#endif // mozilla_hal_HalSandbox_h
|
||||
20
hal/HalScreenConfiguration.h
Normal file
20
hal/HalScreenConfiguration.h
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_HalScreenConfiguration_h
|
||||
#define mozilla_HalScreenConfiguration_h
|
||||
|
||||
#include "mozilla/Observer.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal {
|
||||
class ScreenConfiguration;
|
||||
typedef Observer<ScreenConfiguration> ScreenConfigurationObserver;
|
||||
} // namespace hal
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_HalScreenConfiguration_h
|
||||
|
||||
80
hal/HalSensor.h
Normal file
80
hal/HalSensor.h
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef __HAL_SENSOR_H_
|
||||
#define __HAL_SENSOR_H_
|
||||
|
||||
#include "mozilla/Observer.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal {
|
||||
|
||||
/**
|
||||
* Enumeration of sensor types. They are used to specify type while
|
||||
* register or unregister an observer for a sensor of given type.
|
||||
* If you add or change any here, do the same in GeckoHalDefines.java.
|
||||
*/
|
||||
enum SensorType {
|
||||
SENSOR_UNKNOWN = -1,
|
||||
SENSOR_ORIENTATION = 0,
|
||||
SENSOR_ACCELERATION = 1,
|
||||
SENSOR_PROXIMITY = 2,
|
||||
SENSOR_LINEAR_ACCELERATION = 3,
|
||||
SENSOR_GYROSCOPE = 4,
|
||||
SENSOR_LIGHT = 5,
|
||||
SENSOR_ROTATION_VECTOR = 6,
|
||||
SENSOR_GAME_ROTATION_VECTOR = 7,
|
||||
NUM_SENSOR_TYPE
|
||||
};
|
||||
|
||||
class SensorData;
|
||||
|
||||
typedef Observer<SensorData> ISensorObserver;
|
||||
|
||||
/**
|
||||
* Enumeration of sensor accuracy types.
|
||||
*/
|
||||
enum SensorAccuracyType {
|
||||
SENSOR_ACCURACY_UNKNOWN = -1,
|
||||
SENSOR_ACCURACY_UNRELIABLE,
|
||||
SENSOR_ACCURACY_LOW,
|
||||
SENSOR_ACCURACY_MED,
|
||||
SENSOR_ACCURACY_HIGH,
|
||||
NUM_SENSOR_ACCURACY_TYPE
|
||||
};
|
||||
|
||||
class SensorAccuracy;
|
||||
|
||||
typedef Observer<SensorAccuracy> ISensorAccuracyObserver;
|
||||
|
||||
} // namespace hal
|
||||
} // namespace mozilla
|
||||
|
||||
#include "ipc/IPCMessageUtils.h"
|
||||
|
||||
namespace IPC {
|
||||
/**
|
||||
* Serializer for SensorType
|
||||
*/
|
||||
template <>
|
||||
struct ParamTraits<mozilla::hal::SensorType>:
|
||||
public ContiguousEnumSerializer<
|
||||
mozilla::hal::SensorType,
|
||||
mozilla::hal::SENSOR_UNKNOWN,
|
||||
mozilla::hal::NUM_SENSOR_TYPE> {
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::hal::SensorAccuracyType>:
|
||||
public ContiguousEnumSerializer<
|
||||
mozilla::hal::SensorAccuracyType,
|
||||
mozilla::hal::SENSOR_ACCURACY_UNKNOWN,
|
||||
mozilla::hal::NUM_SENSOR_ACCURACY_TYPE> {
|
||||
|
||||
};
|
||||
} // namespace IPC
|
||||
|
||||
#endif /* __HAL_SENSOR_H_ */
|
||||
177
hal/HalTypes.h
Normal file
177
hal/HalTypes.h
Normal file
|
|
@ -0,0 +1,177 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_hal_Types_h
|
||||
#define mozilla_hal_Types_h
|
||||
|
||||
#include "ipc/IPCMessageUtils.h"
|
||||
#include "mozilla/Observer.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal {
|
||||
|
||||
/**
|
||||
* These constants specify special values for content process IDs. You can get
|
||||
* a content process ID by calling ContentChild::GetID() or
|
||||
* ContentParent::GetChildID().
|
||||
*/
|
||||
const uint64_t CONTENT_PROCESS_ID_UNKNOWN = uint64_t(-1);
|
||||
const uint64_t CONTENT_PROCESS_ID_MAIN = 0;
|
||||
|
||||
/**
|
||||
* These are defined by libhardware, specifically, hardware/libhardware/include/hardware/lights.h
|
||||
* in the gonk subsystem.
|
||||
* If these change and are exposed to JS, make sure nsIHal.idl is updated as well.
|
||||
*/
|
||||
enum ShutdownMode {
|
||||
eHalShutdownMode_Unknown = -1,
|
||||
eHalShutdownMode_PowerOff = 0,
|
||||
eHalShutdownMode_Reboot = 1,
|
||||
eHalShutdownMode_Restart = 2,
|
||||
eHalShutdownMode_Count = 3
|
||||
};
|
||||
|
||||
class SwitchEvent;
|
||||
|
||||
enum SwitchDevice {
|
||||
SWITCH_DEVICE_UNKNOWN = -1,
|
||||
SWITCH_HEADPHONES,
|
||||
SWITCH_USB,
|
||||
NUM_SWITCH_DEVICE
|
||||
};
|
||||
|
||||
enum SwitchState {
|
||||
SWITCH_STATE_UNKNOWN = -1,
|
||||
SWITCH_STATE_ON,
|
||||
SWITCH_STATE_OFF,
|
||||
SWITCH_STATE_HEADSET, // Headphone with microphone
|
||||
SWITCH_STATE_HEADPHONE, // without microphone
|
||||
NUM_SWITCH_STATE
|
||||
};
|
||||
|
||||
typedef Observer<SwitchEvent> SwitchObserver;
|
||||
|
||||
// Note that we rely on the order of this enum's entries. Higher priorities
|
||||
// should have larger int values.
|
||||
enum ProcessPriority {
|
||||
PROCESS_PRIORITY_UNKNOWN = -1,
|
||||
PROCESS_PRIORITY_BACKGROUND,
|
||||
PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE,
|
||||
PROCESS_PRIORITY_FOREGROUND_KEYBOARD,
|
||||
// The special class for the preallocated process, high memory priority but
|
||||
// low CPU priority.
|
||||
PROCESS_PRIORITY_PREALLOC,
|
||||
// Any priority greater than or equal to FOREGROUND is considered
|
||||
// "foreground" for the purposes of priority testing, for example
|
||||
// CurrentProcessIsForeground().
|
||||
PROCESS_PRIORITY_FOREGROUND,
|
||||
PROCESS_PRIORITY_FOREGROUND_HIGH,
|
||||
PROCESS_PRIORITY_MASTER,
|
||||
NUM_PROCESS_PRIORITY
|
||||
};
|
||||
|
||||
/**
|
||||
* Values that can be passed to hal::SetCurrentThreadPriority(). These should be
|
||||
* functional in nature, such as COMPOSITOR, instead of levels, like LOW/HIGH.
|
||||
* This allows us to tune our priority scheme for the system in one place such
|
||||
* that it makes sense holistically for the overall operating system. On gonk
|
||||
* or android we may want different priority schemes than on windows, etc.
|
||||
*/
|
||||
enum ThreadPriority {
|
||||
THREAD_PRIORITY_COMPOSITOR,
|
||||
NUM_THREAD_PRIORITY
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert a ProcessPriority enum value to a string. The strings returned by
|
||||
* this function are statically allocated; do not attempt to free one!
|
||||
*
|
||||
* If you pass an unknown process priority, we fatally assert in debug
|
||||
* builds and otherwise return "???".
|
||||
*/
|
||||
const char*
|
||||
ProcessPriorityToString(ProcessPriority aPriority);
|
||||
|
||||
/**
|
||||
* Convert a ThreadPriority enum value to a string. The strings returned by
|
||||
* this function are statically allocated; do not attempt to free one!
|
||||
*
|
||||
* If you pass an unknown process priority, we assert in debug builds
|
||||
* and otherwise return "???".
|
||||
*/
|
||||
const char *
|
||||
ThreadPriorityToString(ThreadPriority aPriority);
|
||||
|
||||
/**
|
||||
* Used by ModifyWakeLock
|
||||
*/
|
||||
enum WakeLockControl {
|
||||
WAKE_LOCK_REMOVE_ONE = -1,
|
||||
WAKE_LOCK_NO_CHANGE = 0,
|
||||
WAKE_LOCK_ADD_ONE = 1,
|
||||
NUM_WAKE_LOCK
|
||||
};
|
||||
|
||||
} // namespace hal
|
||||
} // namespace mozilla
|
||||
|
||||
namespace IPC {
|
||||
|
||||
/**
|
||||
* Serializer for ShutdownMode.
|
||||
*/
|
||||
template <>
|
||||
struct ParamTraits<mozilla::hal::ShutdownMode>
|
||||
: public ContiguousEnumSerializer<
|
||||
mozilla::hal::ShutdownMode,
|
||||
mozilla::hal::eHalShutdownMode_Unknown,
|
||||
mozilla::hal::eHalShutdownMode_Count>
|
||||
{};
|
||||
|
||||
/**
|
||||
* WakeLockControl serializer.
|
||||
*/
|
||||
template <>
|
||||
struct ParamTraits<mozilla::hal::WakeLockControl>
|
||||
: public ContiguousEnumSerializer<
|
||||
mozilla::hal::WakeLockControl,
|
||||
mozilla::hal::WAKE_LOCK_REMOVE_ONE,
|
||||
mozilla::hal::NUM_WAKE_LOCK>
|
||||
{};
|
||||
|
||||
/**
|
||||
* Serializer for SwitchState
|
||||
*/
|
||||
template <>
|
||||
struct ParamTraits<mozilla::hal::SwitchState>:
|
||||
public ContiguousEnumSerializer<
|
||||
mozilla::hal::SwitchState,
|
||||
mozilla::hal::SWITCH_STATE_UNKNOWN,
|
||||
mozilla::hal::NUM_SWITCH_STATE> {
|
||||
};
|
||||
|
||||
/**
|
||||
* Serializer for SwitchDevice
|
||||
*/
|
||||
template <>
|
||||
struct ParamTraits<mozilla::hal::SwitchDevice>:
|
||||
public ContiguousEnumSerializer<
|
||||
mozilla::hal::SwitchDevice,
|
||||
mozilla::hal::SWITCH_DEVICE_UNKNOWN,
|
||||
mozilla::hal::NUM_SWITCH_DEVICE> {
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ParamTraits<mozilla::hal::ProcessPriority>:
|
||||
public ContiguousEnumSerializer<
|
||||
mozilla::hal::ProcessPriority,
|
||||
mozilla::hal::PROCESS_PRIORITY_UNKNOWN,
|
||||
mozilla::hal::NUM_PROCESS_PRIORITY> {
|
||||
};
|
||||
|
||||
|
||||
} // namespace IPC
|
||||
|
||||
#endif // mozilla_hal_Types_h
|
||||
282
hal/HalWakeLock.cpp
Normal file
282
hal/HalWakeLock.cpp
Normal file
|
|
@ -0,0 +1,282 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "mozilla/HalWakeLock.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsIPropertyBag2.h"
|
||||
#include "nsIObserverService.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::hal;
|
||||
|
||||
namespace {
|
||||
|
||||
struct LockCount {
|
||||
LockCount()
|
||||
: numLocks(0)
|
||||
, numHidden(0)
|
||||
{}
|
||||
uint32_t numLocks;
|
||||
uint32_t numHidden;
|
||||
nsTArray<uint64_t> processes;
|
||||
};
|
||||
|
||||
typedef nsDataHashtable<nsUint64HashKey, LockCount> ProcessLockTable;
|
||||
typedef nsClassHashtable<nsStringHashKey, ProcessLockTable> LockTable;
|
||||
|
||||
int sActiveListeners = 0;
|
||||
StaticAutoPtr<LockTable> sLockTable;
|
||||
bool sInitialized = false;
|
||||
bool sIsShuttingDown = false;
|
||||
|
||||
WakeLockInformation
|
||||
WakeLockInfoFromLockCount(const nsAString& aTopic, const LockCount& aLockCount)
|
||||
{
|
||||
// TODO: Once we abandon b2g18, we can switch this to use the
|
||||
// WakeLockInformation constructor, which is better because it doesn't let us
|
||||
// forget to assign a param. For now we have to do it this way, because
|
||||
// b2g18 doesn't have the nsTArray <--> InfallibleTArray conversion (bug
|
||||
// 819791).
|
||||
|
||||
WakeLockInformation info;
|
||||
info.topic() = aTopic;
|
||||
info.numLocks() = aLockCount.numLocks;
|
||||
info.numHidden() = aLockCount.numHidden;
|
||||
info.lockingProcesses().AppendElements(aLockCount.processes);
|
||||
return info;
|
||||
}
|
||||
|
||||
static void
|
||||
CountWakeLocks(ProcessLockTable* aTable, LockCount* aTotalCount)
|
||||
{
|
||||
for (auto iter = aTable->Iter(); !iter.Done(); iter.Next()) {
|
||||
const uint64_t& key = iter.Key();
|
||||
LockCount count = iter.UserData();
|
||||
|
||||
aTotalCount->numLocks += count.numLocks;
|
||||
aTotalCount->numHidden += count.numHidden;
|
||||
|
||||
// This is linear in the number of processes, but that should be small.
|
||||
if (!aTotalCount->processes.Contains(key)) {
|
||||
aTotalCount->processes.AppendElement(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ClearHashtableOnShutdown final : public nsIObserver {
|
||||
~ClearHashtableOnShutdown() {}
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(ClearHashtableOnShutdown, nsIObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
ClearHashtableOnShutdown::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* data)
|
||||
{
|
||||
MOZ_ASSERT(!strcmp(aTopic, "xpcom-shutdown"));
|
||||
|
||||
sIsShuttingDown = true;
|
||||
sLockTable = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class CleanupOnContentShutdown final : public nsIObserver {
|
||||
~CleanupOnContentShutdown() {}
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(CleanupOnContentShutdown, nsIObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
CleanupOnContentShutdown::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* data)
|
||||
{
|
||||
MOZ_ASSERT(!strcmp(aTopic, "ipc:content-shutdown"));
|
||||
|
||||
if (sIsShuttingDown) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(aSubject);
|
||||
if (!props) {
|
||||
NS_WARNING("ipc:content-shutdown message without property bag as subject");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint64_t childID = 0;
|
||||
nsresult rv = props->GetPropertyAsUint64(NS_LITERAL_STRING("childID"),
|
||||
&childID);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
for (auto iter = sLockTable->Iter(); !iter.Done(); iter.Next()) {
|
||||
nsAutoPtr<ProcessLockTable>& table = iter.Data();
|
||||
|
||||
if (table->Get(childID, nullptr)) {
|
||||
table->Remove(childID);
|
||||
|
||||
LockCount totalCount;
|
||||
CountWakeLocks(table, &totalCount);
|
||||
|
||||
if (sActiveListeners) {
|
||||
NotifyWakeLockChange(WakeLockInfoFromLockCount(iter.Key(),
|
||||
totalCount));
|
||||
}
|
||||
|
||||
if (totalCount.numLocks == 0) {
|
||||
iter.Remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NS_WARNING("ipc:content-shutdown message without childID property");
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
Init()
|
||||
{
|
||||
sLockTable = new LockTable();
|
||||
sInitialized = true;
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->AddObserver(new ClearHashtableOnShutdown(), "xpcom-shutdown", false);
|
||||
obs->AddObserver(new CleanupOnContentShutdown(), "ipc:content-shutdown", false);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace hal {
|
||||
|
||||
WakeLockState
|
||||
ComputeWakeLockState(int aNumLocks, int aNumHidden)
|
||||
{
|
||||
if (aNumLocks == 0) {
|
||||
return WAKE_LOCK_STATE_UNLOCKED;
|
||||
} else if (aNumLocks == aNumHidden) {
|
||||
return WAKE_LOCK_STATE_HIDDEN;
|
||||
} else {
|
||||
return WAKE_LOCK_STATE_VISIBLE;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace hal
|
||||
|
||||
namespace hal_impl {
|
||||
|
||||
void
|
||||
EnableWakeLockNotifications()
|
||||
{
|
||||
sActiveListeners++;
|
||||
}
|
||||
|
||||
void
|
||||
DisableWakeLockNotifications()
|
||||
{
|
||||
sActiveListeners--;
|
||||
}
|
||||
|
||||
void
|
||||
ModifyWakeLock(const nsAString& aTopic,
|
||||
hal::WakeLockControl aLockAdjust,
|
||||
hal::WakeLockControl aHiddenAdjust,
|
||||
uint64_t aProcessID)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aProcessID != CONTENT_PROCESS_ID_UNKNOWN);
|
||||
|
||||
if (sIsShuttingDown) {
|
||||
return;
|
||||
}
|
||||
if (!sInitialized) {
|
||||
Init();
|
||||
}
|
||||
|
||||
ProcessLockTable* table = sLockTable->Get(aTopic);
|
||||
LockCount processCount;
|
||||
LockCount totalCount;
|
||||
if (!table) {
|
||||
table = new ProcessLockTable();
|
||||
sLockTable->Put(aTopic, table);
|
||||
} else {
|
||||
table->Get(aProcessID, &processCount);
|
||||
CountWakeLocks(table, &totalCount);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(processCount.numLocks >= processCount.numHidden);
|
||||
MOZ_ASSERT(aLockAdjust >= 0 || processCount.numLocks > 0);
|
||||
MOZ_ASSERT(aHiddenAdjust >= 0 || processCount.numHidden > 0);
|
||||
MOZ_ASSERT(totalCount.numLocks >= totalCount.numHidden);
|
||||
MOZ_ASSERT(aLockAdjust >= 0 || totalCount.numLocks > 0);
|
||||
MOZ_ASSERT(aHiddenAdjust >= 0 || totalCount.numHidden > 0);
|
||||
|
||||
WakeLockState oldState = ComputeWakeLockState(totalCount.numLocks, totalCount.numHidden);
|
||||
bool processWasLocked = processCount.numLocks > 0;
|
||||
|
||||
processCount.numLocks += aLockAdjust;
|
||||
processCount.numHidden += aHiddenAdjust;
|
||||
|
||||
totalCount.numLocks += aLockAdjust;
|
||||
totalCount.numHidden += aHiddenAdjust;
|
||||
|
||||
if (processCount.numLocks) {
|
||||
table->Put(aProcessID, processCount);
|
||||
} else {
|
||||
table->Remove(aProcessID);
|
||||
}
|
||||
if (!totalCount.numLocks) {
|
||||
sLockTable->Remove(aTopic);
|
||||
}
|
||||
|
||||
if (sActiveListeners &&
|
||||
(oldState != ComputeWakeLockState(totalCount.numLocks,
|
||||
totalCount.numHidden) ||
|
||||
processWasLocked != (processCount.numLocks > 0))) {
|
||||
|
||||
WakeLockInformation info;
|
||||
hal::GetWakeLockInfo(aTopic, &info);
|
||||
NotifyWakeLockChange(info);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GetWakeLockInfo(const nsAString& aTopic, WakeLockInformation* aWakeLockInfo)
|
||||
{
|
||||
if (sIsShuttingDown) {
|
||||
NS_WARNING("You don't want to get wake lock information during xpcom-shutdown!");
|
||||
*aWakeLockInfo = WakeLockInformation();
|
||||
return;
|
||||
}
|
||||
if (!sInitialized) {
|
||||
Init();
|
||||
}
|
||||
|
||||
ProcessLockTable* table = sLockTable->Get(aTopic);
|
||||
if (!table) {
|
||||
*aWakeLockInfo = WakeLockInfoFromLockCount(aTopic, LockCount());
|
||||
return;
|
||||
}
|
||||
LockCount totalCount;
|
||||
CountWakeLocks(table, &totalCount);
|
||||
*aWakeLockInfo = WakeLockInfoFromLockCount(aTopic, totalCount);
|
||||
}
|
||||
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
||||
26
hal/HalWakeLock.h
Normal file
26
hal/HalWakeLock.h
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
/* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef __HAL_WAKELOCK_H_
|
||||
#define __HAL_WAKELOCK_H_
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal {
|
||||
|
||||
enum WakeLockState {
|
||||
WAKE_LOCK_STATE_UNLOCKED,
|
||||
WAKE_LOCK_STATE_HIDDEN,
|
||||
WAKE_LOCK_STATE_VISIBLE
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the wake lock state according to the numbers.
|
||||
*/
|
||||
WakeLockState ComputeWakeLockState(int aNumLocks, int aNumHidden);
|
||||
|
||||
} // namespace hal
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* __HAL_WAKELOCK_H_ */
|
||||
80
hal/WindowIdentifier.cpp
Normal file
80
hal/WindowIdentifier.cpp
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||
/* 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 "WindowIdentifier.h"
|
||||
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal {
|
||||
|
||||
WindowIdentifier::WindowIdentifier()
|
||||
: mWindow(nullptr)
|
||||
, mIsEmpty(true)
|
||||
{
|
||||
}
|
||||
|
||||
WindowIdentifier::WindowIdentifier(nsPIDOMWindowInner* window)
|
||||
: mWindow(window)
|
||||
, mIsEmpty(false)
|
||||
{
|
||||
mID.AppendElement(GetWindowID());
|
||||
}
|
||||
|
||||
WindowIdentifier::WindowIdentifier(const InfallibleTArray<uint64_t> &id,
|
||||
nsPIDOMWindowInner* window)
|
||||
: mID(id)
|
||||
, mWindow(window)
|
||||
, mIsEmpty(false)
|
||||
{
|
||||
mID.AppendElement(GetWindowID());
|
||||
}
|
||||
|
||||
WindowIdentifier::WindowIdentifier(const WindowIdentifier &other)
|
||||
: mID(other.mID)
|
||||
, mWindow(other.mWindow)
|
||||
, mIsEmpty(other.mIsEmpty)
|
||||
{
|
||||
}
|
||||
|
||||
const InfallibleTArray<uint64_t>&
|
||||
WindowIdentifier::AsArray() const
|
||||
{
|
||||
MOZ_ASSERT(!mIsEmpty);
|
||||
return mID;
|
||||
}
|
||||
|
||||
bool
|
||||
WindowIdentifier::HasTraveledThroughIPC() const
|
||||
{
|
||||
MOZ_ASSERT(!mIsEmpty);
|
||||
return mID.Length() >= 2;
|
||||
}
|
||||
|
||||
void
|
||||
WindowIdentifier::AppendProcessID()
|
||||
{
|
||||
MOZ_ASSERT(!mIsEmpty);
|
||||
mID.AppendElement(dom::ContentChild::GetSingleton()->GetID());
|
||||
}
|
||||
|
||||
uint64_t
|
||||
WindowIdentifier::GetWindowID() const
|
||||
{
|
||||
MOZ_ASSERT(!mIsEmpty);
|
||||
return mWindow ? mWindow->WindowID() : UINT64_MAX;
|
||||
}
|
||||
|
||||
nsPIDOMWindowInner*
|
||||
WindowIdentifier::GetWindow() const
|
||||
{
|
||||
MOZ_ASSERT(!mIsEmpty);
|
||||
return mWindow;
|
||||
}
|
||||
|
||||
} // namespace hal
|
||||
} // namespace mozilla
|
||||
111
hal/WindowIdentifier.h
Normal file
111
hal/WindowIdentifier.h
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_hal_WindowIdentifier_h
|
||||
#define mozilla_hal_WindowIdentifier_h
|
||||
|
||||
#include "mozilla/Types.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsPIDOMWindowInner;
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal {
|
||||
|
||||
/**
|
||||
* This class serves two purposes.
|
||||
*
|
||||
* First, this class wraps a pointer to a window.
|
||||
*
|
||||
* Second, WindowIdentifier lets us uniquely identify a window across
|
||||
* processes. A window exposes an ID which is unique only within its
|
||||
* process. Thus to identify a window, we need to know the ID of the
|
||||
* process which contains it. But the scope of a process's ID is its
|
||||
* parent; that is, two processes with different parents might have
|
||||
* the same ID.
|
||||
*
|
||||
* So to identify a window, we need its ID plus the IDs of all the
|
||||
* processes in the path from the window's process to the root
|
||||
* process. We throw in the IDs of the intermediate windows (a
|
||||
* content window is contained in a window at each level of the
|
||||
* process tree) for good measures.
|
||||
*
|
||||
* You can access this list of IDs by calling AsArray().
|
||||
*/
|
||||
class WindowIdentifier
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create an empty WindowIdentifier. Calls to any of this object's
|
||||
* public methods will assert -- an empty WindowIdentifier may be
|
||||
* used only as a placeholder to code which promises not to touch
|
||||
* the object.
|
||||
*/
|
||||
WindowIdentifier();
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
*/
|
||||
WindowIdentifier(const WindowIdentifier& other);
|
||||
|
||||
/**
|
||||
* Wrap the given window in a WindowIdentifier. These two
|
||||
* constructors automatically grab the window's ID and append it to
|
||||
* the array of IDs.
|
||||
*
|
||||
* Note that these constructors allow an implicit conversion to a
|
||||
* WindowIdentifier.
|
||||
*/
|
||||
explicit WindowIdentifier(nsPIDOMWindowInner* window);
|
||||
|
||||
/**
|
||||
* Create a new WindowIdentifier with the given id array and window.
|
||||
* This automatically grabs the window's ID and appends it to the
|
||||
* array.
|
||||
*/
|
||||
WindowIdentifier(const InfallibleTArray<uint64_t>& id,
|
||||
nsPIDOMWindowInner* window);
|
||||
|
||||
/**
|
||||
* Get the list of window and process IDs we contain.
|
||||
*/
|
||||
typedef InfallibleTArray<uint64_t> IDArrayType;
|
||||
const IDArrayType& AsArray() const;
|
||||
|
||||
/**
|
||||
* Append the ID of the ContentChild singleton to our array of
|
||||
* window/process IDs.
|
||||
*/
|
||||
void AppendProcessID();
|
||||
|
||||
/**
|
||||
* Does this WindowIdentifier identify both a window and the process
|
||||
* containing that window? If so, we say it has traveled through
|
||||
* IPC.
|
||||
*/
|
||||
bool HasTraveledThroughIPC() const;
|
||||
|
||||
/**
|
||||
* Get the window this object wraps.
|
||||
*/
|
||||
nsPIDOMWindowInner* GetWindow() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Get the ID of the window object we wrap.
|
||||
*/
|
||||
uint64_t GetWindowID() const;
|
||||
|
||||
AutoTArray<uint64_t, 3> mID;
|
||||
nsCOMPtr<nsPIDOMWindowInner> mWindow;
|
||||
bool mIsEmpty;
|
||||
};
|
||||
|
||||
} // namespace hal
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_hal_WindowIdentifier_h
|
||||
48
hal/android/AndroidAlarm.cpp
Normal file
48
hal/android/AndroidAlarm.cpp
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "GeneratedJNINatives.h"
|
||||
#include "GeneratedJNIWrappers.h"
|
||||
|
||||
using namespace mozilla::hal;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class AlarmReceiver : public java::AlarmReceiver::Natives<AlarmReceiver>
|
||||
{
|
||||
private:
|
||||
AlarmReceiver();
|
||||
|
||||
public:
|
||||
static void NotifyAlarmFired() {
|
||||
hal::NotifyAlarmFired();
|
||||
}
|
||||
};
|
||||
|
||||
namespace hal_impl {
|
||||
|
||||
bool
|
||||
EnableAlarm()
|
||||
{
|
||||
AlarmReceiver::Init();
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
DisableAlarm()
|
||||
{
|
||||
java::GeckoAppShell::DisableAlarm();
|
||||
}
|
||||
|
||||
bool
|
||||
SetAlarm(int32_t aSeconds, int32_t aNanoseconds)
|
||||
{
|
||||
return java::GeckoAppShell::SetAlarm(aSeconds, aNanoseconds);
|
||||
}
|
||||
|
||||
} // hal_impl
|
||||
} // mozilla
|
||||
175
hal/android/AndroidHal.cpp
Normal file
175
hal/android/AndroidHal.cpp
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "HalImpl.h"
|
||||
#include "WindowIdentifier.h"
|
||||
#include "AndroidBridge.h"
|
||||
#include "mozilla/dom/network/Constants.h"
|
||||
#include "mozilla/dom/ScreenOrientation.h"
|
||||
#include "nsIScreenManager.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::hal;
|
||||
|
||||
namespace java = mozilla::java;
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
void
|
||||
Vibrate(const nsTArray<uint32_t> &pattern, const WindowIdentifier &)
|
||||
{
|
||||
// Ignore the WindowIdentifier parameter; it's here only because hal::Vibrate,
|
||||
// hal_sandbox::Vibrate, and hal_impl::Vibrate all must have the same
|
||||
// signature.
|
||||
|
||||
// Strangely enough, the Android Java API seems to treat vibrate([0]) as a
|
||||
// nop. But we want to treat vibrate([0]) like CancelVibrate! (Note that we
|
||||
// also need to treat vibrate([]) as a call to CancelVibrate.)
|
||||
bool allZero = true;
|
||||
for (uint32_t i = 0; i < pattern.Length(); i++) {
|
||||
if (pattern[i] != 0) {
|
||||
allZero = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (allZero) {
|
||||
hal_impl::CancelVibrate(WindowIdentifier());
|
||||
return;
|
||||
}
|
||||
|
||||
AndroidBridge* b = AndroidBridge::Bridge();
|
||||
if (!b) {
|
||||
return;
|
||||
}
|
||||
|
||||
b->Vibrate(pattern);
|
||||
}
|
||||
|
||||
void
|
||||
CancelVibrate(const WindowIdentifier &)
|
||||
{
|
||||
// Ignore WindowIdentifier parameter.
|
||||
|
||||
java::GeckoAppShell::CancelVibrate();
|
||||
}
|
||||
|
||||
void
|
||||
EnableBatteryNotifications()
|
||||
{
|
||||
java::GeckoAppShell::EnableBatteryNotifications();
|
||||
}
|
||||
|
||||
void
|
||||
DisableBatteryNotifications()
|
||||
{
|
||||
java::GeckoAppShell::DisableBatteryNotifications();
|
||||
}
|
||||
|
||||
void
|
||||
GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
|
||||
{
|
||||
AndroidBridge::Bridge()->GetCurrentBatteryInformation(aBatteryInfo);
|
||||
}
|
||||
|
||||
void
|
||||
EnableNetworkNotifications()
|
||||
{
|
||||
java::GeckoAppShell::EnableNetworkNotifications();
|
||||
}
|
||||
|
||||
void
|
||||
DisableNetworkNotifications()
|
||||
{
|
||||
java::GeckoAppShell::DisableNetworkNotifications();
|
||||
}
|
||||
|
||||
void
|
||||
GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
|
||||
{
|
||||
AndroidBridge::Bridge()->GetCurrentNetworkInformation(aNetworkInfo);
|
||||
}
|
||||
|
||||
void
|
||||
EnableScreenConfigurationNotifications()
|
||||
{
|
||||
java::GeckoAppShell::EnableScreenOrientationNotifications();
|
||||
}
|
||||
|
||||
void
|
||||
DisableScreenConfigurationNotifications()
|
||||
{
|
||||
java::GeckoAppShell::DisableScreenOrientationNotifications();
|
||||
}
|
||||
|
||||
void
|
||||
GetCurrentScreenConfiguration(ScreenConfiguration* aScreenConfiguration)
|
||||
{
|
||||
AndroidBridge* bridge = AndroidBridge::Bridge();
|
||||
if (!bridge) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIScreenManager> screenMgr =
|
||||
do_GetService("@mozilla.org/gfx/screenmanager;1", &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("Can't find nsIScreenManager!");
|
||||
return;
|
||||
}
|
||||
|
||||
nsIntRect rect;
|
||||
int32_t colorDepth, pixelDepth;
|
||||
int16_t angle;
|
||||
ScreenOrientationInternal orientation;
|
||||
nsCOMPtr<nsIScreen> screen;
|
||||
|
||||
screenMgr->GetPrimaryScreen(getter_AddRefs(screen));
|
||||
screen->GetRect(&rect.x, &rect.y, &rect.width, &rect.height);
|
||||
screen->GetColorDepth(&colorDepth);
|
||||
screen->GetPixelDepth(&pixelDepth);
|
||||
orientation = static_cast<ScreenOrientationInternal>(bridge->GetScreenOrientation());
|
||||
angle = bridge->GetScreenAngle();
|
||||
|
||||
*aScreenConfiguration =
|
||||
hal::ScreenConfiguration(rect, orientation, angle, colorDepth, pixelDepth);
|
||||
}
|
||||
|
||||
bool
|
||||
LockScreenOrientation(const ScreenOrientationInternal& aOrientation)
|
||||
{
|
||||
// Force the default orientation to be portrait-primary.
|
||||
ScreenOrientationInternal orientation =
|
||||
aOrientation == eScreenOrientation_Default ? eScreenOrientation_PortraitPrimary
|
||||
: aOrientation;
|
||||
|
||||
switch (orientation) {
|
||||
// The Android backend only supports these orientations.
|
||||
case eScreenOrientation_PortraitPrimary:
|
||||
case eScreenOrientation_PortraitSecondary:
|
||||
case eScreenOrientation_PortraitPrimary | eScreenOrientation_PortraitSecondary:
|
||||
case eScreenOrientation_LandscapePrimary:
|
||||
case eScreenOrientation_LandscapeSecondary:
|
||||
case eScreenOrientation_LandscapePrimary | eScreenOrientation_LandscapeSecondary:
|
||||
case eScreenOrientation_Default:
|
||||
java::GeckoAppShell::LockScreenOrientation(orientation);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UnlockScreenOrientation()
|
||||
{
|
||||
java::GeckoAppShell::UnlockScreenOrientation();
|
||||
}
|
||||
|
||||
} // hal_impl
|
||||
} // mozilla
|
||||
|
||||
25
hal/android/AndroidSensor.cpp
Normal file
25
hal/android/AndroidSensor.cpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "GeneratedJNIWrappers.h"
|
||||
|
||||
using namespace mozilla::hal;
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
void
|
||||
EnableSensorNotifications(SensorType aSensor) {
|
||||
java::GeckoAppShell::EnableSensor(aSensor);
|
||||
}
|
||||
|
||||
void
|
||||
DisableSensorNotifications(SensorType aSensor) {
|
||||
java::GeckoAppShell::DisableSensor(aSensor);
|
||||
}
|
||||
|
||||
} // hal_impl
|
||||
} // mozilla
|
||||
325
hal/cocoa/CocoaBattery.cpp
Normal file
325
hal/cocoa/CocoaBattery.cpp
Normal file
|
|
@ -0,0 +1,325 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim set: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : */
|
||||
/* 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/. */
|
||||
|
||||
#import <CoreFoundation/CoreFoundation.h>
|
||||
#import <IOKit/ps/IOPowerSources.h>
|
||||
#import <IOKit/ps/IOPSKeys.h>
|
||||
|
||||
#include <mozilla/Hal.h>
|
||||
#include <mozilla/dom/battery/Constants.h>
|
||||
#include <mozilla/Services.h>
|
||||
|
||||
#include <nsIObserverService.h>
|
||||
#include <nsIObserver.h>
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#define IOKIT_FRAMEWORK_PATH "/System/Library/Frameworks/IOKit.framework/IOKit"
|
||||
|
||||
#ifndef kIOPSTimeRemainingUnknown
|
||||
#define kIOPSTimeRemainingUnknown ((CFTimeInterval)-1.0)
|
||||
#endif
|
||||
#ifndef kIOPSTimeRemainingUnlimited
|
||||
#define kIOPSTimeRemainingUnlimited ((CFTimeInterval)-2.0)
|
||||
#endif
|
||||
|
||||
using namespace mozilla::dom::battery;
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
typedef CFTimeInterval (*IOPSGetTimeRemainingEstimateFunc)(void);
|
||||
|
||||
class MacPowerInformationService
|
||||
{
|
||||
public:
|
||||
static MacPowerInformationService* GetInstance();
|
||||
static void Shutdown();
|
||||
static bool IsShuttingDown();
|
||||
|
||||
void BeginListening();
|
||||
void StopListening();
|
||||
|
||||
static void HandleChange(void *aContext);
|
||||
|
||||
~MacPowerInformationService();
|
||||
|
||||
private:
|
||||
MacPowerInformationService();
|
||||
|
||||
// The reference to the runloop that is notified of power changes.
|
||||
CFRunLoopSourceRef mRunLoopSource;
|
||||
|
||||
double mLevel;
|
||||
bool mCharging;
|
||||
double mRemainingTime;
|
||||
bool mShouldNotify;
|
||||
|
||||
friend void GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo);
|
||||
|
||||
static MacPowerInformationService* sInstance;
|
||||
static bool sShuttingDown;
|
||||
|
||||
static void* sIOKitFramework;
|
||||
static IOPSGetTimeRemainingEstimateFunc sIOPSGetTimeRemainingEstimate;
|
||||
};
|
||||
|
||||
void* MacPowerInformationService::sIOKitFramework;
|
||||
IOPSGetTimeRemainingEstimateFunc MacPowerInformationService::sIOPSGetTimeRemainingEstimate;
|
||||
|
||||
/*
|
||||
* Implementation of mozilla::hal_impl::EnableBatteryNotifications,
|
||||
* mozilla::hal_impl::DisableBatteryNotifications,
|
||||
* and mozilla::hal_impl::GetCurrentBatteryInformation.
|
||||
*/
|
||||
|
||||
void
|
||||
EnableBatteryNotifications()
|
||||
{
|
||||
if (!MacPowerInformationService::IsShuttingDown()) {
|
||||
MacPowerInformationService::GetInstance()->BeginListening();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DisableBatteryNotifications()
|
||||
{
|
||||
if (!MacPowerInformationService::IsShuttingDown()) {
|
||||
MacPowerInformationService::GetInstance()->StopListening();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
|
||||
{
|
||||
MacPowerInformationService* powerService = MacPowerInformationService::GetInstance();
|
||||
|
||||
aBatteryInfo->level() = powerService->mLevel;
|
||||
aBatteryInfo->charging() = powerService->mCharging;
|
||||
aBatteryInfo->remainingTime() = powerService->mRemainingTime;
|
||||
}
|
||||
|
||||
bool MacPowerInformationService::sShuttingDown = false;
|
||||
|
||||
/*
|
||||
* Following is the implementation of MacPowerInformationService.
|
||||
*/
|
||||
|
||||
MacPowerInformationService* MacPowerInformationService::sInstance = nullptr;
|
||||
|
||||
namespace {
|
||||
struct SingletonDestroyer final : public nsIObserver
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
private:
|
||||
~SingletonDestroyer() {}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(SingletonDestroyer, nsIObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
SingletonDestroyer::Observe(nsISupports*, const char* aTopic, const char16_t*)
|
||||
{
|
||||
MOZ_ASSERT(!strcmp(aTopic, "xpcom-shutdown"));
|
||||
MacPowerInformationService::Shutdown();
|
||||
return NS_OK;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
/* static */ MacPowerInformationService*
|
||||
MacPowerInformationService::GetInstance()
|
||||
{
|
||||
if (sInstance) {
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
sInstance = new MacPowerInformationService();
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->AddObserver(new SingletonDestroyer(), "xpcom-shutdown", false);
|
||||
}
|
||||
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
bool
|
||||
MacPowerInformationService::IsShuttingDown()
|
||||
{
|
||||
return sShuttingDown;
|
||||
}
|
||||
|
||||
void
|
||||
MacPowerInformationService::Shutdown()
|
||||
{
|
||||
sShuttingDown = true;
|
||||
delete sInstance;
|
||||
sInstance = nullptr;
|
||||
}
|
||||
|
||||
MacPowerInformationService::MacPowerInformationService()
|
||||
: mRunLoopSource(nullptr)
|
||||
, mLevel(kDefaultLevel)
|
||||
, mCharging(kDefaultCharging)
|
||||
, mRemainingTime(kDefaultRemainingTime)
|
||||
, mShouldNotify(false)
|
||||
{
|
||||
// IOPSGetTimeRemainingEstimate (and the related constants) are only available
|
||||
// on 10.7, so we test for their presence at runtime.
|
||||
sIOKitFramework = dlopen(IOKIT_FRAMEWORK_PATH, RTLD_LAZY | RTLD_LOCAL);
|
||||
if (sIOKitFramework) {
|
||||
sIOPSGetTimeRemainingEstimate =
|
||||
(IOPSGetTimeRemainingEstimateFunc)dlsym(sIOKitFramework, "IOPSGetTimeRemainingEstimate");
|
||||
} else {
|
||||
sIOPSGetTimeRemainingEstimate = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
MacPowerInformationService::~MacPowerInformationService()
|
||||
{
|
||||
MOZ_ASSERT(!mRunLoopSource,
|
||||
"The observers have not been correctly removed! "
|
||||
"(StopListening should have been called)");
|
||||
|
||||
if (sIOKitFramework) {
|
||||
dlclose(sIOKitFramework);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacPowerInformationService::BeginListening()
|
||||
{
|
||||
// Set ourselves up to be notified about changes.
|
||||
MOZ_ASSERT(!mRunLoopSource, "IOPS Notification Loop Source already set up. "
|
||||
"(StopListening should have been called)");
|
||||
|
||||
mRunLoopSource = ::IOPSNotificationCreateRunLoopSource(HandleChange, this);
|
||||
if (mRunLoopSource) {
|
||||
::CFRunLoopAddSource(::CFRunLoopGetCurrent(), mRunLoopSource,
|
||||
kCFRunLoopDefaultMode);
|
||||
|
||||
// Invoke our callback now so we have data if GetCurrentBatteryInformation is
|
||||
// called before a change happens.
|
||||
HandleChange(this);
|
||||
mShouldNotify = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacPowerInformationService::StopListening()
|
||||
{
|
||||
MOZ_ASSERT(mRunLoopSource, "IOPS Notification Loop Source not set up. "
|
||||
"(StopListening without BeginListening)");
|
||||
|
||||
::CFRunLoopRemoveSource(::CFRunLoopGetCurrent(), mRunLoopSource,
|
||||
kCFRunLoopDefaultMode);
|
||||
mRunLoopSource = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
MacPowerInformationService::HandleChange(void* aContext) {
|
||||
MacPowerInformationService* power =
|
||||
static_cast<MacPowerInformationService*>(aContext);
|
||||
|
||||
CFTypeRef data = ::IOPSCopyPowerSourcesInfo();
|
||||
if (!data) {
|
||||
::CFRelease(data);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the list of power sources.
|
||||
CFArrayRef list = ::IOPSCopyPowerSourcesList(data);
|
||||
if (!list) {
|
||||
::CFRelease(list);
|
||||
return;
|
||||
}
|
||||
|
||||
// Default values. These will be used if there are 0 sources or we can't find
|
||||
// better information.
|
||||
double level = kDefaultLevel;
|
||||
double charging = kDefaultCharging;
|
||||
double remainingTime = kDefaultRemainingTime;
|
||||
|
||||
// Look for the first battery power source to give us the information we need.
|
||||
// Usually there's only 1 available, depending on current power source.
|
||||
for (CFIndex i = 0; i < ::CFArrayGetCount(list); ++i) {
|
||||
CFTypeRef source = ::CFArrayGetValueAtIndex(list, i);
|
||||
CFDictionaryRef currPowerSourceDesc = ::IOPSGetPowerSourceDescription(data, source);
|
||||
if (!currPowerSourceDesc) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get a battery level estimate. This key is required.
|
||||
int currentCapacity = 0;
|
||||
const void* cfRef = ::CFDictionaryGetValue(currPowerSourceDesc, CFSTR(kIOPSCurrentCapacityKey));
|
||||
::CFNumberGetValue((CFNumberRef)cfRef, kCFNumberSInt32Type, ¤tCapacity);
|
||||
|
||||
// This key is also required.
|
||||
int maxCapacity = 0;
|
||||
cfRef = ::CFDictionaryGetValue(currPowerSourceDesc, CFSTR(kIOPSMaxCapacityKey));
|
||||
::CFNumberGetValue((CFNumberRef)cfRef, kCFNumberSInt32Type, &maxCapacity);
|
||||
|
||||
if (maxCapacity > 0) {
|
||||
level = static_cast<double>(currentCapacity)/static_cast<double>(maxCapacity);
|
||||
}
|
||||
|
||||
// Find out if we're charging.
|
||||
// This key is optional, we fallback to kDefaultCharging if the current power
|
||||
// source doesn't have that info.
|
||||
if(::CFDictionaryGetValueIfPresent(currPowerSourceDesc, CFSTR(kIOPSIsChargingKey), &cfRef)) {
|
||||
charging = ::CFBooleanGetValue((CFBooleanRef)cfRef);
|
||||
|
||||
// Get an estimate of how long it's going to take until we're fully charged.
|
||||
// This key is optional.
|
||||
if (charging) {
|
||||
// Default value that will be changed if we happen to find the actual
|
||||
// remaining time.
|
||||
remainingTime = level == 1.0 ? kDefaultRemainingTime : kUnknownRemainingTime;
|
||||
|
||||
if (::CFDictionaryGetValueIfPresent(currPowerSourceDesc,
|
||||
CFSTR(kIOPSTimeToFullChargeKey), &cfRef)) {
|
||||
int timeToCharge;
|
||||
::CFNumberGetValue((CFNumberRef)cfRef, kCFNumberIntType, &timeToCharge);
|
||||
if (timeToCharge != kIOPSTimeRemainingUnknown) {
|
||||
remainingTime = timeToCharge*60;
|
||||
}
|
||||
}
|
||||
} else if (sIOPSGetTimeRemainingEstimate) { // not charging
|
||||
// See if we can get a time estimate.
|
||||
CFTimeInterval estimate = sIOPSGetTimeRemainingEstimate();
|
||||
if (estimate == kIOPSTimeRemainingUnlimited || estimate == kIOPSTimeRemainingUnknown) {
|
||||
remainingTime = kUnknownRemainingTime;
|
||||
} else {
|
||||
remainingTime = estimate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
bool isNewData = level != power->mLevel || charging != power->mCharging ||
|
||||
remainingTime != power->mRemainingTime;
|
||||
|
||||
power->mRemainingTime = remainingTime;
|
||||
power->mCharging = charging;
|
||||
power->mLevel = level;
|
||||
|
||||
// Notify the observers if stuff changed.
|
||||
if (power->mShouldNotify && isNewData) {
|
||||
hal::NotifyBatteryChange(hal::BatteryInformation(power->mLevel,
|
||||
power->mCharging,
|
||||
power->mRemainingTime));
|
||||
}
|
||||
|
||||
::CFRelease(data);
|
||||
::CFRelease(list);
|
||||
}
|
||||
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
||||
149
hal/cocoa/CocoaSensor.mm
Normal file
149
hal/cocoa/CocoaSensor.mm
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
/* 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 "nsITimer.h"
|
||||
#include "smslib.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
|
||||
#include <mach/mach.h>
|
||||
#include <cmath>
|
||||
#import <IOKit/IOKitLib.h>
|
||||
|
||||
#define MEAN_GRAVITY 9.80665
|
||||
#define DEFAULT_SENSOR_POLL 100
|
||||
using namespace mozilla::hal;
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
static nsITimer* sUpdateTimer = nullptr;
|
||||
static bool sActiveSensors[NUM_SENSOR_TYPE];
|
||||
static io_connect_t sDataPort = IO_OBJECT_NULL;
|
||||
static uint64_t sLastMean = -1;
|
||||
static float
|
||||
LMUvalueToLux(uint64_t aValue)
|
||||
{
|
||||
//Conversion formula from regression. See Bug 793728.
|
||||
// -3*(10^-27)*x^4 + 2.6*(10^-19)*x^3 + -3.4*(10^-12)*x^2 + 3.9*(10^-5)*x - 0.19
|
||||
long double powerC4 = 1/pow((long double)10,27);
|
||||
long double powerC3 = 1/pow((long double)10,19);
|
||||
long double powerC2 = 1/pow((long double)10,12);
|
||||
long double powerC1 = 1/pow((long double)10,5);
|
||||
|
||||
long double term4 = -3.0 * powerC4 * pow(aValue,4);
|
||||
long double term3 = 2.6 * powerC3 * pow(aValue,3);
|
||||
long double term2 = -3.4 * powerC2 * pow(aValue,2);
|
||||
long double term1 = 3.9 * powerC1 * aValue;
|
||||
|
||||
float lux = ceil(static_cast<float>(term4 + term3 + term2 + term1 - 0.19));
|
||||
return lux > 0 ? lux : 0;
|
||||
}
|
||||
void
|
||||
UpdateHandler(nsITimer *aTimer, void *aClosure)
|
||||
{
|
||||
for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
|
||||
if (!sActiveSensors[i]) {
|
||||
continue;
|
||||
}
|
||||
SensorType sensor = static_cast<SensorType>(i);
|
||||
InfallibleTArray<float> values;
|
||||
if (sensor == SENSOR_ACCELERATION) {
|
||||
sms_acceleration accel;
|
||||
smsGetData(&accel);
|
||||
|
||||
values.AppendElement(accel.x * MEAN_GRAVITY);
|
||||
values.AppendElement(accel.y * MEAN_GRAVITY);
|
||||
values.AppendElement(accel.z * MEAN_GRAVITY);
|
||||
} else if (sensor == SENSOR_LIGHT && sDataPort != IO_OBJECT_NULL) {
|
||||
kern_return_t kr;
|
||||
uint32_t outputs = 2;
|
||||
uint64_t lightLMU[outputs];
|
||||
|
||||
kr = IOConnectCallMethod(sDataPort, 0, nil, 0, nil, 0, lightLMU, &outputs, nil, 0);
|
||||
if (kr == KERN_SUCCESS) {
|
||||
uint64_t mean = (lightLMU[0] + lightLMU[1]) / 2;
|
||||
if (mean == sLastMean) {
|
||||
continue;
|
||||
}
|
||||
sLastMean = mean;
|
||||
values.AppendElement(LMUvalueToLux(mean));
|
||||
} else if (kr == kIOReturnBusy) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
hal::SensorData sdata(sensor,
|
||||
PR_Now(),
|
||||
values,
|
||||
hal::SENSOR_ACCURACY_UNKNOWN);
|
||||
hal::NotifySensorChange(sdata);
|
||||
}
|
||||
}
|
||||
void
|
||||
EnableSensorNotifications(SensorType aSensor)
|
||||
{
|
||||
if (aSensor == SENSOR_ACCELERATION) {
|
||||
int result = smsStartup(nil, nil);
|
||||
|
||||
if (result != SMS_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!smsLoadCalibration()) {
|
||||
return;
|
||||
}
|
||||
} else if (aSensor == SENSOR_LIGHT) {
|
||||
io_service_t serviceObject;
|
||||
serviceObject = IOServiceGetMatchingService(kIOMasterPortDefault,
|
||||
IOServiceMatching("AppleLMUController"));
|
||||
if (!serviceObject) {
|
||||
return;
|
||||
}
|
||||
kern_return_t kr;
|
||||
kr = IOServiceOpen(serviceObject, mach_task_self(), 0, &sDataPort);
|
||||
IOObjectRelease(serviceObject);
|
||||
if (kr != KERN_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
NS_WARNING("EnableSensorNotifications called on an unknown sensor type");
|
||||
return;
|
||||
}
|
||||
sActiveSensors[aSensor] = true;
|
||||
|
||||
if (!sUpdateTimer) {
|
||||
CallCreateInstance("@mozilla.org/timer;1", &sUpdateTimer);
|
||||
if (sUpdateTimer) {
|
||||
sUpdateTimer->InitWithFuncCallback(UpdateHandler,
|
||||
nullptr,
|
||||
DEFAULT_SENSOR_POLL,
|
||||
nsITimer::TYPE_REPEATING_SLACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
void
|
||||
DisableSensorNotifications(SensorType aSensor)
|
||||
{
|
||||
if (!sActiveSensors[aSensor] || (aSensor != SENSOR_ACCELERATION && aSensor != SENSOR_LIGHT)) {
|
||||
return;
|
||||
}
|
||||
|
||||
sActiveSensors[aSensor] = false;
|
||||
|
||||
if (aSensor == SENSOR_ACCELERATION) {
|
||||
smsShutdown();
|
||||
} else if (aSensor == SENSOR_LIGHT) {
|
||||
IOServiceClose(sDataPort);
|
||||
}
|
||||
// If all sensors are disabled, cancel the update timer.
|
||||
if (sUpdateTimer) {
|
||||
for (int i = 0; i < NUM_SENSOR_TYPE; i++) {
|
||||
if (sActiveSensors[i]) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
sUpdateTimer->Cancel();
|
||||
NS_RELEASE(sUpdateTimer);
|
||||
}
|
||||
}
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
||||
159
hal/cocoa/smslib.h
Normal file
159
hal/cocoa/smslib.h
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* smslib.h
|
||||
*
|
||||
* SMSLib Sudden Motion Sensor Access Library
|
||||
* Copyright (c) 2010 Suitable Systems
|
||||
* All rights reserved.
|
||||
*
|
||||
* Developed by: Daniel Griscom
|
||||
* Suitable Systems
|
||||
* http://www.suitable.com
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal with the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimers.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimers in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the names of Suitable Systems nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this Software without specific prior written permission.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
|
||||
*
|
||||
* For more information about SMSLib, see
|
||||
* <http://www.suitable.com/tools/smslib.html>
|
||||
* or contact
|
||||
* Daniel Griscom
|
||||
* Suitable Systems
|
||||
* 1 Centre Street, Suite 204
|
||||
* Wakefield, MA 01880
|
||||
* (781) 665-0053
|
||||
*
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#define SMSLIB_VERSION "1.8"
|
||||
|
||||
#pragma mark Structure definitions
|
||||
|
||||
// Structure for specifying a 3-axis acceleration. 0.0 means "zero gravities",
|
||||
// 1.0 means "one gravity".
|
||||
typedef struct sms_acceleration {
|
||||
float x; // Right-left acceleration (positive is rightwards)
|
||||
float y; // Front-rear acceleration (positive is rearwards)
|
||||
float z; // Up-down acceleration (positive is upwards)
|
||||
} sms_acceleration;
|
||||
|
||||
// Structure for specifying a calibration.
|
||||
typedef struct sms_calibration {
|
||||
float zeros[3]; // Zero points for three axes (X, Y, Z)
|
||||
float onegs[3]; // One gravity values for three axes
|
||||
} sms_calibration;
|
||||
|
||||
#pragma mark Return value definitions
|
||||
|
||||
// These are the return values for accelStartup(), giving the
|
||||
// various stages where the most successful attempt at accessing
|
||||
// the accelerometer failed. The higher the value, the further along the
|
||||
// software progressed before failing. The options are:
|
||||
// - Didn't match model name
|
||||
#define SMS_FAIL_MODEL (-7)
|
||||
// - Failure getting dictionary matching desired services
|
||||
#define SMS_FAIL_DICTIONARY (-6)
|
||||
// - Failure getting list of services
|
||||
#define SMS_FAIL_LIST_SERVICES (-5)
|
||||
// - Failure if list of services is empty. The process generally fails
|
||||
// here if run on a machine without a Sudden Motion Sensor.
|
||||
#define SMS_FAIL_NO_SERVICES (-4)
|
||||
// - Failure if error opening device.
|
||||
#define SMS_FAIL_OPENING (-3)
|
||||
// - Failure if opened, but didn't get a connection
|
||||
#define SMS_FAIL_CONNECTION (-2)
|
||||
// - Failure if couldn't access connction using given function and size. This
|
||||
// is where the process would probably fail with a change in Apple's API.
|
||||
// Driver problems often also cause failures here.
|
||||
#define SMS_FAIL_ACCESS (-1)
|
||||
// - Success!
|
||||
#define SMS_SUCCESS (0)
|
||||
|
||||
#pragma mark Function declarations
|
||||
|
||||
// This starts up the accelerometer code, trying each possible sensor
|
||||
// specification. Note that for logging purposes it
|
||||
// takes an object and a selector; the object's selector is then invoked
|
||||
// with a single NSString as argument giving progress messages. Example
|
||||
// logging method:
|
||||
// - (void)logMessage: (NSString *)theString
|
||||
// which would be used in accelStartup's invocation thusly:
|
||||
// result = accelStartup(self, @selector(logMessage:));
|
||||
// If the object is nil, then no logging is done. Sets calibation from built-in
|
||||
// value table. Returns ACCEL_SUCCESS for success, and other (negative)
|
||||
// values for various failures (returns value indicating result of
|
||||
// most successful trial).
|
||||
int smsStartup(id logObject, SEL logSelector);
|
||||
|
||||
// This starts up the library in debug mode, ignoring the actual hardware.
|
||||
// Returned data is in the form of 1Hz sine waves, with the X, Y and Z
|
||||
// axes 120 degrees out of phase; "calibrated" data has range +/- (1.0/5);
|
||||
// "uncalibrated" data has range +/- (256/5). X and Y axes centered on 0.0,
|
||||
// Z axes centered on 1 (calibrated) or 256 (uncalibrated).
|
||||
// Don't use smsGetBufferLength or smsGetBufferData. Always returns SMS_SUCCESS.
|
||||
int smsDebugStartup(id logObject, SEL logSelector);
|
||||
|
||||
// Returns the current calibration values.
|
||||
void smsGetCalibration(sms_calibration *calibrationRecord);
|
||||
|
||||
// Sets the calibration, but does NOT store it as a preference. If the argument
|
||||
// is nil then the current calibration is set from the built-in value table.
|
||||
void smsSetCalibration(sms_calibration *calibrationRecord);
|
||||
|
||||
// Stores the current calibration values as a stored preference.
|
||||
void smsStoreCalibration(void);
|
||||
|
||||
// Loads the stored preference values into the current calibration.
|
||||
// Returns YES if successful.
|
||||
BOOL smsLoadCalibration(void);
|
||||
|
||||
// Deletes any stored calibration, and then takes the current calibration values
|
||||
// from the built-in value table.
|
||||
void smsDeleteCalibration(void);
|
||||
|
||||
// Fills in the accel record with calibrated acceleration data. Takes
|
||||
// 1-2ms to return a value. Returns 0 if success, error number if failure.
|
||||
int smsGetData(sms_acceleration *accel);
|
||||
|
||||
// Fills in the accel record with uncalibrated acceleration data.
|
||||
// Returns 0 if success, error number if failure.
|
||||
int smsGetUncalibratedData(sms_acceleration *accel);
|
||||
|
||||
// Returns the length of a raw block of data for the current type of sensor.
|
||||
int smsGetBufferLength(void);
|
||||
|
||||
// Takes a pointer to accelGetRawLength() bytes; sets those bytes
|
||||
// to return value from sensor. Make darn sure the buffer length is right!
|
||||
void smsGetBufferData(char *buffer);
|
||||
|
||||
// This returns an NSString describing the current calibration in
|
||||
// human-readable form. Also include a description of the machine.
|
||||
NSString *smsGetCalibrationDescription(void);
|
||||
|
||||
// Shuts down the accelerometer.
|
||||
void smsShutdown(void);
|
||||
|
||||
938
hal/cocoa/smslib.mm
Normal file
938
hal/cocoa/smslib.mm
Normal file
|
|
@ -0,0 +1,938 @@
|
|||
/*
|
||||
* smslib.m
|
||||
*
|
||||
* SMSLib Sudden Motion Sensor Access Library
|
||||
* Copyright (c) 2010 Suitable Systems
|
||||
* All rights reserved.
|
||||
*
|
||||
* Developed by: Daniel Griscom
|
||||
* Suitable Systems
|
||||
* http://www.suitable.com
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the
|
||||
* "Software"), to deal with the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimers.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimers in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* - Neither the names of Suitable Systems nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this Software without specific prior written permission.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE.
|
||||
*
|
||||
* For more information about SMSLib, see
|
||||
* <http://www.suitable.com/tools/smslib.html>
|
||||
* or contact
|
||||
* Daniel Griscom
|
||||
* Suitable Systems
|
||||
* 1 Centre Street, Suite 204
|
||||
* Wakefield, MA 01880
|
||||
* (781) 665-0053
|
||||
*
|
||||
*/
|
||||
|
||||
#import <IOKit/IOKitLib.h>
|
||||
#import <sys/sysctl.h>
|
||||
#import <math.h>
|
||||
#import "smslib.h"
|
||||
|
||||
#pragma mark Internal structures
|
||||
|
||||
// Represents a single axis of a type of sensor.
|
||||
typedef struct axisStruct {
|
||||
int enabled; // Non-zero if axis is valid in this sensor
|
||||
int index; // Location in struct of first byte
|
||||
int size; // Number of bytes
|
||||
float zerog; // Value meaning "zero g"
|
||||
float oneg; // Change in value meaning "increase of one g"
|
||||
// (can be negative if axis sensor reversed)
|
||||
} axisStruct;
|
||||
|
||||
// Represents the configuration of a type of sensor.
|
||||
typedef struct sensorSpec {
|
||||
const char *model; // Prefix of model to be tested
|
||||
const char *name; // Name of device to be read
|
||||
unsigned int function; // Kernel function index
|
||||
int recordSize; // Size of record to be sent/received
|
||||
axisStruct axes[3]; // Description of three axes (X, Y, Z)
|
||||
} sensorSpec;
|
||||
|
||||
// Configuration of all known types of sensors. The configurations are
|
||||
// tried in order until one succeeds in returning data.
|
||||
// All default values are set here, but each axis' zerog and oneg values
|
||||
// may be changed to saved (calibrated) values.
|
||||
//
|
||||
// These values came from SeisMaCalibrate calibration reports. In general I've
|
||||
// found the following:
|
||||
// - All Intel-based SMSs have 250 counts per g, centered on 0, but the signs
|
||||
// are different (and in one case two axes are swapped)
|
||||
// - PowerBooks and iBooks all have sensors centered on 0, and reading
|
||||
// 50-53 steps per gravity (but with differing polarities!)
|
||||
// - PowerBooks and iBooks of the same model all have the same axis polarities
|
||||
// - PowerBook and iBook access methods are model- and OS version-specific
|
||||
//
|
||||
// So, the sequence of tests is:
|
||||
// - Try model-specific access methods. Note that the test is for a match to the
|
||||
// beginning of the model name, e.g. the record with model name "MacBook"
|
||||
// matches computer models "MacBookPro1,2" and "MacBook1,1" (and ""
|
||||
// matches any model).
|
||||
// - If no model-specific record's access fails, then try each model-independent
|
||||
// access method in order, stopping when one works.
|
||||
static const sensorSpec sensors[] = {
|
||||
// ****** Model-dependent methods ******
|
||||
// The PowerBook5,6 is one of the G4 models that seems to lose
|
||||
// SMS access until the next reboot.
|
||||
{"PowerBook5,6", "IOI2CMotionSensor", 21, 60, {
|
||||
{1, 0, 1, 0, 51.5},
|
||||
{1, 1, 1, 0, -51.5},
|
||||
{1, 2, 1, 0, -51.5}
|
||||
}
|
||||
},
|
||||
// The PowerBook5,7 is one of the G4 models that seems to lose
|
||||
// SMS access until the next reboot.
|
||||
{"PowerBook5,7", "IOI2CMotionSensor", 21, 60, {
|
||||
{1, 0, 1, 0, 51.5},
|
||||
{1, 1, 1, 0, 51.5},
|
||||
{1, 2, 1, 0, 51.5}
|
||||
}
|
||||
},
|
||||
// Access seems to be reliable on the PowerBook5,8
|
||||
{"PowerBook5,8", "PMUMotionSensor", 21, 60, {
|
||||
{1, 0, 1, 0, -51.5},
|
||||
{1, 1, 1, 0, 51.5},
|
||||
{1, 2, 1, 0, -51.5}
|
||||
}
|
||||
},
|
||||
// Access seems to be reliable on the PowerBook5,9
|
||||
{"PowerBook5,9", "PMUMotionSensor", 21, 60, {
|
||||
{1, 0, 1, 0, 51.5},
|
||||
{1, 1, 1, 0, -51.5},
|
||||
{1, 2, 1, 0, -51.5}
|
||||
}
|
||||
},
|
||||
// The PowerBook6,7 is one of the G4 models that seems to lose
|
||||
// SMS access until the next reboot.
|
||||
{"PowerBook6,7", "IOI2CMotionSensor", 21, 60, {
|
||||
{1, 0, 1, 0, 51.5},
|
||||
{1, 1, 1, 0, 51.5},
|
||||
{1, 2, 1, 0, 51.5}
|
||||
}
|
||||
},
|
||||
// The PowerBook6,8 is one of the G4 models that seems to lose
|
||||
// SMS access until the next reboot.
|
||||
{"PowerBook6,8", "IOI2CMotionSensor", 21, 60, {
|
||||
{1, 0, 1, 0, 51.5},
|
||||
{1, 1, 1, 0, 51.5},
|
||||
{1, 2, 1, 0, 51.5}
|
||||
}
|
||||
},
|
||||
// MacBook Pro Core 2 Duo 17". Note the reversed Y and Z axes.
|
||||
{"MacBookPro2,1", "SMCMotionSensor", 5, 40, {
|
||||
{1, 0, 2, 0, 251},
|
||||
{1, 2, 2, 0, -251},
|
||||
{1, 4, 2, 0, -251}
|
||||
}
|
||||
},
|
||||
// MacBook Pro Core 2 Duo 15" AND 17" with LED backlight, introduced June '07.
|
||||
// NOTE! The 17" machines have the signs of their X and Y axes reversed
|
||||
// from this calibration, but there's no clear way to discriminate between
|
||||
// the two machines.
|
||||
{"MacBookPro3,1", "SMCMotionSensor", 5, 40, {
|
||||
{1, 0, 2, 0, -251},
|
||||
{1, 2, 2, 0, 251},
|
||||
{1, 4, 2, 0, -251}
|
||||
}
|
||||
},
|
||||
// ... specs?
|
||||
{"MacBook5,2", "SMCMotionSensor", 5, 40, {
|
||||
{1, 0, 2, 0, -251},
|
||||
{1, 2, 2, 0, 251},
|
||||
{1, 4, 2, 0, -251}
|
||||
}
|
||||
},
|
||||
// ... specs?
|
||||
{"MacBookPro5,1", "SMCMotionSensor", 5, 40, {
|
||||
{1, 0, 2, 0, -251},
|
||||
{1, 2, 2, 0, -251},
|
||||
{1, 4, 2, 0, 251}
|
||||
}
|
||||
},
|
||||
// ... specs?
|
||||
{"MacBookPro5,2", "SMCMotionSensor", 5, 40, {
|
||||
{1, 0, 2, 0, -251},
|
||||
{1, 2, 2, 0, -251},
|
||||
{1, 4, 2, 0, 251}
|
||||
}
|
||||
},
|
||||
// This is speculative, based on a single user's report. Looks like the X and Y axes
|
||||
// are swapped. This is true for no other known Appple laptop.
|
||||
{"MacBookPro5,3", "SMCMotionSensor", 5, 40, {
|
||||
{1, 2, 2, 0, -251},
|
||||
{1, 0, 2, 0, -251},
|
||||
{1, 4, 2, 0, -251}
|
||||
}
|
||||
},
|
||||
// ... specs?
|
||||
{"MacBookPro5,4", "SMCMotionSensor", 5, 40, {
|
||||
{1, 0, 2, 0, -251},
|
||||
{1, 2, 2, 0, -251},
|
||||
{1, 4, 2, 0, 251}
|
||||
}
|
||||
},
|
||||
// ****** Model-independent methods ******
|
||||
// Seen once with PowerBook6,8 under system 10.3.9; I suspect
|
||||
// other G4-based 10.3.* systems might use this
|
||||
{"", "IOI2CMotionSensor", 24, 60, {
|
||||
{1, 0, 1, 0, 51.5},
|
||||
{1, 1, 1, 0, 51.5},
|
||||
{1, 2, 1, 0, 51.5}
|
||||
}
|
||||
},
|
||||
// PowerBook5,6 , PowerBook5,7 , PowerBook6,7 , PowerBook6,8
|
||||
// under OS X 10.4.*
|
||||
{"", "IOI2CMotionSensor", 21, 60, {
|
||||
{1, 0, 1, 0, 51.5},
|
||||
{1, 1, 1, 0, 51.5},
|
||||
{1, 2, 1, 0, 51.5}
|
||||
}
|
||||
},
|
||||
// PowerBook5,8 , PowerBook5,9 under OS X 10.4.*
|
||||
{"", "PMUMotionSensor", 21, 60, {
|
||||
// Each has two out of three gains negative, but it's different
|
||||
// for the different models. So, this will be right in two out
|
||||
// of three axis for either model.
|
||||
{1, 0, 1, 0, -51.5},
|
||||
{1, 1, 1, -6, -51.5},
|
||||
{1, 2, 1, 0, -51.5}
|
||||
}
|
||||
},
|
||||
// All MacBook, MacBookPro models. Hardware (at least on early MacBookPro 15")
|
||||
// is Kionix KXM52-1050 three-axis accelerometer chip. Data is at
|
||||
// http://kionix.com/Product-Index/product-index.htm. Specific MB and MBP models
|
||||
// that use this are:
|
||||
// MacBook1,1
|
||||
// MacBook2,1
|
||||
// MacBook3,1
|
||||
// MacBook4,1
|
||||
// MacBook5,1
|
||||
// MacBook6,1
|
||||
// MacBookAir1,1
|
||||
// MacBookPro1,1
|
||||
// MacBookPro1,2
|
||||
// MacBookPro4,1
|
||||
// MacBookPro5,5
|
||||
{"", "SMCMotionSensor", 5, 40, {
|
||||
{1, 0, 2, 0, 251},
|
||||
{1, 2, 2, 0, 251},
|
||||
{1, 4, 2, 0, 251}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#define SENSOR_COUNT (sizeof(sensors)/sizeof(sensorSpec))
|
||||
|
||||
#pragma mark Internal prototypes
|
||||
|
||||
static int getData(sms_acceleration *accel, int calibrated, id logObject, SEL logSelector);
|
||||
static float getAxis(int which, int calibrated);
|
||||
static int signExtend(int value, int size);
|
||||
static NSString *getModelName(void);
|
||||
static NSString *getOSVersion(void);
|
||||
static BOOL loadCalibration(void);
|
||||
static void storeCalibration(void);
|
||||
static void defaultCalibration(void);
|
||||
static void deleteCalibration(void);
|
||||
static int prefIntRead(NSString *prefName, BOOL *success);
|
||||
static void prefIntWrite(NSString *prefName, int prefValue);
|
||||
static float prefFloatRead(NSString *prefName, BOOL *success);
|
||||
static void prefFloatWrite(NSString *prefName, float prefValue);
|
||||
static void prefDelete(NSString *prefName);
|
||||
static void prefSynchronize(void);
|
||||
// static long getMicroseconds(void);
|
||||
float fakeData(NSTimeInterval time);
|
||||
|
||||
#pragma mark Static variables
|
||||
|
||||
static int debugging = NO; // True if debugging (synthetic data)
|
||||
static io_connect_t connection; // Connection for reading accel values
|
||||
static int running = NO; // True if we successfully started
|
||||
static unsigned int sensorNum = 0; // The current index into sensors[]
|
||||
static const char *serviceName; // The name of the current service
|
||||
static char *iRecord, *oRecord; // Pointers to read/write records for sensor
|
||||
static int recordSize; // Size of read/write records
|
||||
static unsigned int function; // Which kernel function should be used
|
||||
static float zeros[3]; // X, Y and Z zero calibration values
|
||||
static float onegs[3]; // X, Y and Z one-g calibration values
|
||||
|
||||
#pragma mark Defines
|
||||
|
||||
// Pattern for building axis letter from axis number
|
||||
#define INT_TO_AXIS(a) (a == 0 ? @"X" : a == 1 ? @"Y" : @"Z")
|
||||
// Name of configuration for given axis' zero (axis specified by integer)
|
||||
#define ZERO_NAME(a) [NSString stringWithFormat:@"%@-Axis-Zero", INT_TO_AXIS(a)]
|
||||
// Name of configuration for given axis' oneg (axis specified by integer)
|
||||
#define ONEG_NAME(a) [NSString stringWithFormat:@"%@-Axis-One-g", INT_TO_AXIS(a)]
|
||||
// Name of "Is calibrated" preference
|
||||
#define CALIBRATED_NAME (@"Calibrated")
|
||||
// Application domain for SeisMac library
|
||||
#define APP_ID ((CFStringRef)@"com.suitable.SeisMacLib")
|
||||
|
||||
// These #defines make the accelStartup code a LOT easier to read.
|
||||
#undef LOG
|
||||
#define LOG(message) \
|
||||
if (logObject) { \
|
||||
[logObject performSelector:logSelector withObject:message]; \
|
||||
}
|
||||
#define LOG_ARG(format, var1) \
|
||||
if (logObject) { \
|
||||
[logObject performSelector:logSelector \
|
||||
withObject:[NSString stringWithFormat:format, var1]]; \
|
||||
}
|
||||
#define LOG_2ARG(format, var1, var2) \
|
||||
if (logObject) { \
|
||||
[logObject performSelector:logSelector \
|
||||
withObject:[NSString stringWithFormat:format, var1, var2]]; \
|
||||
}
|
||||
#define LOG_3ARG(format, var1, var2, var3) \
|
||||
if (logObject) { \
|
||||
[logObject performSelector:logSelector \
|
||||
withObject:[NSString stringWithFormat:format, var1, var2, var3]]; \
|
||||
}
|
||||
|
||||
#pragma mark Function definitions
|
||||
|
||||
// This starts up the accelerometer code, trying each possible sensor
|
||||
// specification. Note that for logging purposes it
|
||||
// takes an object and a selector; the object's selector is then invoked
|
||||
// with a single NSString as argument giving progress messages. Example
|
||||
// logging method:
|
||||
// - (void)logMessage: (NSString *)theString
|
||||
// which would be used in accelStartup's invocation thusly:
|
||||
// result = accelStartup(self, @selector(logMessage:));
|
||||
// If the object is nil, then no logging is done. Sets calibation from built-in
|
||||
// value table. Returns ACCEL_SUCCESS for success, and other (negative)
|
||||
// values for various failures (returns value indicating result of
|
||||
// most successful trial).
|
||||
int smsStartup(id logObject, SEL logSelector) {
|
||||
io_iterator_t iterator;
|
||||
io_object_t device;
|
||||
kern_return_t result;
|
||||
sms_acceleration accel;
|
||||
int failure_result = SMS_FAIL_MODEL;
|
||||
|
||||
running = NO;
|
||||
debugging = NO;
|
||||
|
||||
NSString *modelName = getModelName();
|
||||
|
||||
LOG_ARG(@"Machine model: %@\n", modelName);
|
||||
LOG_ARG(@"OS X version: %@\n", getOSVersion());
|
||||
LOG_ARG(@"Accelerometer library version: %s\n", SMSLIB_VERSION);
|
||||
|
||||
for (sensorNum = 0; sensorNum < SENSOR_COUNT; sensorNum++) {
|
||||
|
||||
// Set up all specs for this type of sensor
|
||||
serviceName = sensors[sensorNum].name;
|
||||
recordSize = sensors[sensorNum].recordSize;
|
||||
function = sensors[sensorNum].function;
|
||||
|
||||
LOG_3ARG(@"Trying service \"%s\" with selector %d and %d byte record:\n",
|
||||
serviceName, function, recordSize);
|
||||
|
||||
NSString *targetName = [NSString stringWithCString:sensors[sensorNum].model
|
||||
encoding:NSMacOSRomanStringEncoding];
|
||||
LOG_ARG(@" Comparing model name to target \"%@\": ", targetName);
|
||||
if ([targetName length] == 0 || [modelName hasPrefix:targetName]) {
|
||||
LOG(@"success.\n");
|
||||
} else {
|
||||
LOG(@"failure.\n");
|
||||
// Don't need to increment failure_result.
|
||||
continue;
|
||||
}
|
||||
|
||||
LOG(@" Fetching dictionary for service: ");
|
||||
CFMutableDictionaryRef dict = IOServiceMatching(serviceName);
|
||||
|
||||
if (dict) {
|
||||
LOG(@"success.\n");
|
||||
} else {
|
||||
LOG(@"failure.\n");
|
||||
if (failure_result < SMS_FAIL_DICTIONARY) {
|
||||
failure_result = SMS_FAIL_DICTIONARY;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
LOG(@" Getting list of matching services: ");
|
||||
result = IOServiceGetMatchingServices(kIOMasterPortDefault,
|
||||
dict,
|
||||
&iterator);
|
||||
|
||||
if (result == KERN_SUCCESS) {
|
||||
LOG(@"success.\n");
|
||||
} else {
|
||||
LOG_ARG(@"failure, with return value 0x%x.\n", result);
|
||||
if (failure_result < SMS_FAIL_LIST_SERVICES) {
|
||||
failure_result = SMS_FAIL_LIST_SERVICES;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
LOG(@" Getting first device in list: ");
|
||||
device = IOIteratorNext(iterator);
|
||||
|
||||
if (device == 0) {
|
||||
LOG(@"failure.\n");
|
||||
if (failure_result < SMS_FAIL_NO_SERVICES) {
|
||||
failure_result = SMS_FAIL_NO_SERVICES;
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
LOG(@"success.\n");
|
||||
LOG(@" Opening device: ");
|
||||
}
|
||||
|
||||
result = IOServiceOpen(device, mach_task_self(), 0, &connection);
|
||||
|
||||
if (result != KERN_SUCCESS) {
|
||||
LOG_ARG(@"failure, with return value 0x%x.\n", result);
|
||||
IOObjectRelease(device);
|
||||
if (failure_result < SMS_FAIL_OPENING) {
|
||||
failure_result = SMS_FAIL_OPENING;
|
||||
}
|
||||
continue;
|
||||
} else if (connection == 0) {
|
||||
LOG_ARG(@"'success', but didn't get a connection (return value was: 0x%x).\n", result);
|
||||
IOObjectRelease(device);
|
||||
if (failure_result < SMS_FAIL_CONNECTION) {
|
||||
failure_result = SMS_FAIL_CONNECTION;
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
IOObjectRelease(device);
|
||||
LOG(@"success.\n");
|
||||
}
|
||||
LOG(@" Testing device.\n");
|
||||
|
||||
defaultCalibration();
|
||||
|
||||
iRecord = (char*) malloc(recordSize);
|
||||
oRecord = (char*) malloc(recordSize);
|
||||
|
||||
running = YES;
|
||||
result = getData(&accel, true, logObject, logSelector);
|
||||
running = NO;
|
||||
|
||||
if (result) {
|
||||
LOG_ARG(@" Failure testing device, with result 0x%x.\n", result);
|
||||
free(iRecord);
|
||||
iRecord = 0;
|
||||
free(oRecord);
|
||||
oRecord = 0;
|
||||
if (failure_result < SMS_FAIL_ACCESS) {
|
||||
failure_result = SMS_FAIL_ACCESS;
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
LOG(@" Success testing device!\n");
|
||||
running = YES;
|
||||
return SMS_SUCCESS;
|
||||
}
|
||||
}
|
||||
return failure_result;
|
||||
}
|
||||
|
||||
// This starts up the library in debug mode, ignoring the actual hardware.
|
||||
// Returned data is in the form of 1Hz sine waves, with the X, Y and Z
|
||||
// axes 120 degrees out of phase; "calibrated" data has range +/- (1.0/5);
|
||||
// "uncalibrated" data has range +/- (256/5). X and Y axes centered on 0.0,
|
||||
// Z axes centered on 1 (calibrated) or 256 (uncalibrated).
|
||||
// Don't use smsGetBufferLength or smsGetBufferData. Always returns SMS_SUCCESS.
|
||||
int smsDebugStartup(id logObject, SEL logSelector) {
|
||||
LOG(@"Starting up in debug mode\n");
|
||||
debugging = YES;
|
||||
return SMS_SUCCESS;
|
||||
}
|
||||
|
||||
// Returns the current calibration values.
|
||||
void smsGetCalibration(sms_calibration *calibrationRecord) {
|
||||
int x;
|
||||
|
||||
for (x = 0; x < 3; x++) {
|
||||
calibrationRecord->zeros[x] = (debugging ? 0 : zeros[x]);
|
||||
calibrationRecord->onegs[x] = (debugging ? 256 : onegs[x]);
|
||||
}
|
||||
}
|
||||
|
||||
// Sets the calibration, but does NOT store it as a preference. If the argument
|
||||
// is nil then the current calibration is set from the built-in value table.
|
||||
void smsSetCalibration(sms_calibration *calibrationRecord) {
|
||||
int x;
|
||||
|
||||
if (!debugging) {
|
||||
if (calibrationRecord) {
|
||||
for (x = 0; x < 3; x++) {
|
||||
zeros[x] = calibrationRecord->zeros[x];
|
||||
onegs[x] = calibrationRecord->onegs[x];
|
||||
}
|
||||
} else {
|
||||
defaultCalibration();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stores the current calibration values as a stored preference.
|
||||
void smsStoreCalibration(void) {
|
||||
if (!debugging)
|
||||
storeCalibration();
|
||||
}
|
||||
|
||||
// Loads the stored preference values into the current calibration.
|
||||
// Returns YES if successful.
|
||||
BOOL smsLoadCalibration(void) {
|
||||
if (debugging) {
|
||||
return YES;
|
||||
} else if (loadCalibration()) {
|
||||
return YES;
|
||||
} else {
|
||||
defaultCalibration();
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
// Deletes any stored calibration, and then takes the current calibration values
|
||||
// from the built-in value table.
|
||||
void smsDeleteCalibration(void) {
|
||||
if (!debugging) {
|
||||
deleteCalibration();
|
||||
defaultCalibration();
|
||||
}
|
||||
}
|
||||
|
||||
// Fills in the accel record with calibrated acceleration data. Takes
|
||||
// 1-2ms to return a value. Returns 0 if success, error number if failure.
|
||||
int smsGetData(sms_acceleration *accel) {
|
||||
NSTimeInterval time;
|
||||
if (debugging) {
|
||||
usleep(1500); // Usually takes 1-2 milliseconds
|
||||
time = [NSDate timeIntervalSinceReferenceDate];
|
||||
accel->x = fakeData(time)/5;
|
||||
accel->y = fakeData(time - 1)/5;
|
||||
accel->z = fakeData(time - 2)/5 + 1.0;
|
||||
return true;
|
||||
} else {
|
||||
return getData(accel, true, nil, nil);
|
||||
}
|
||||
}
|
||||
|
||||
// Fills in the accel record with uncalibrated acceleration data.
|
||||
// Returns 0 if success, error number if failure.
|
||||
int smsGetUncalibratedData(sms_acceleration *accel) {
|
||||
NSTimeInterval time;
|
||||
if (debugging) {
|
||||
usleep(1500); // Usually takes 1-2 milliseconds
|
||||
time = [NSDate timeIntervalSinceReferenceDate];
|
||||
accel->x = fakeData(time) * 256 / 5;
|
||||
accel->y = fakeData(time - 1) * 256 / 5;
|
||||
accel->z = fakeData(time - 2) * 256 / 5 + 256;
|
||||
return true;
|
||||
} else {
|
||||
return getData(accel, false, nil, nil);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the length of a raw block of data for the current type of sensor.
|
||||
int smsGetBufferLength(void) {
|
||||
if (debugging) {
|
||||
return 0;
|
||||
} else if (running) {
|
||||
return sensors[sensorNum].recordSize;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Takes a pointer to accelGetRawLength() bytes; sets those bytes
|
||||
// to return value from sensor. Make darn sure the buffer length is right!
|
||||
void smsGetBufferData(char *buffer) {
|
||||
IOItemCount iSize = recordSize;
|
||||
IOByteCount oSize = recordSize;
|
||||
kern_return_t result;
|
||||
|
||||
if (debugging || running == NO) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(iRecord, 1, iSize);
|
||||
memset(buffer, 0, oSize);
|
||||
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
|
||||
const size_t InStructSize = recordSize;
|
||||
size_t OutStructSize = recordSize;
|
||||
result = IOConnectCallStructMethod(connection,
|
||||
function, // magic kernel function number
|
||||
(const void *)iRecord,
|
||||
InStructSize,
|
||||
(void *)buffer,
|
||||
&OutStructSize
|
||||
);
|
||||
#else // __MAC_OS_X_VERSION_MIN_REQUIRED 1050
|
||||
result = IOConnectMethodStructureIStructureO(connection,
|
||||
function, // magic kernel function number
|
||||
iSize,
|
||||
&oSize,
|
||||
iRecord,
|
||||
buffer
|
||||
);
|
||||
#endif // __MAC_OS_X_VERSION_MIN_REQUIRED 1050
|
||||
|
||||
if (result != KERN_SUCCESS) {
|
||||
running = NO;
|
||||
}
|
||||
}
|
||||
|
||||
// This returns an NSString describing the current calibration in
|
||||
// human-readable form. Also include a description of the machine.
|
||||
NSString *smsGetCalibrationDescription(void) {
|
||||
BOOL success;
|
||||
NSMutableString *s = [[NSMutableString alloc] init];
|
||||
|
||||
if (debugging) {
|
||||
[s release];
|
||||
return @"Debugging!";
|
||||
}
|
||||
|
||||
[s appendString:@"---- SeisMac Calibration Record ----\n \n"];
|
||||
[s appendFormat:@"Machine model: %@\n",
|
||||
getModelName()];
|
||||
[s appendFormat:@"OS X build: %@\n",
|
||||
getOSVersion()];
|
||||
[s appendFormat:@"SeisMacLib version %s, record %d\n \n",
|
||||
SMSLIB_VERSION, sensorNum];
|
||||
[s appendFormat:@"Using service \"%s\", function index %d, size %d\n \n",
|
||||
serviceName, function, recordSize];
|
||||
if (prefIntRead(CALIBRATED_NAME, &success) && success) {
|
||||
[s appendString:@"Calibration values (from calibration):\n"];
|
||||
} else {
|
||||
[s appendString:@"Calibration values (from defaults):\n"];
|
||||
}
|
||||
[s appendFormat:@" X-Axis-Zero = %.2f\n", zeros[0]];
|
||||
[s appendFormat:@" X-Axis-One-g = %.2f\n", onegs[0]];
|
||||
[s appendFormat:@" Y-Axis-Zero = %.2f\n", zeros[1]];
|
||||
[s appendFormat:@" Y-Axis-One-g = %.2f\n", onegs[1]];
|
||||
[s appendFormat:@" Z-Axis-Zero = %.2f\n", zeros[2]];
|
||||
[s appendFormat:@" Z-Axis-One-g = %.2f\n \n", onegs[2]];
|
||||
[s appendString:@"---- End Record ----\n"];
|
||||
return s;
|
||||
}
|
||||
|
||||
// Shuts down the accelerometer.
|
||||
void smsShutdown(void) {
|
||||
if (!debugging) {
|
||||
running = NO;
|
||||
if (iRecord) free(iRecord);
|
||||
if (oRecord) free(oRecord);
|
||||
IOServiceClose(connection);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark Internal functions
|
||||
|
||||
// Loads the current calibration from the stored preferences.
|
||||
// Returns true iff successful.
|
||||
BOOL loadCalibration(void) {
|
||||
BOOL thisSuccess, allSuccess;
|
||||
int x;
|
||||
|
||||
prefSynchronize();
|
||||
|
||||
if (prefIntRead(CALIBRATED_NAME, &thisSuccess) && thisSuccess) {
|
||||
// Calibrated. Set all values from saved values.
|
||||
allSuccess = YES;
|
||||
for (x = 0; x < 3; x++) {
|
||||
zeros[x] = prefFloatRead(ZERO_NAME(x), &thisSuccess);
|
||||
allSuccess &= thisSuccess;
|
||||
onegs[x] = prefFloatRead(ONEG_NAME(x), &thisSuccess);
|
||||
allSuccess &= thisSuccess;
|
||||
}
|
||||
return allSuccess;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Stores the current calibration into the stored preferences.
|
||||
static void storeCalibration(void) {
|
||||
int x;
|
||||
prefIntWrite(CALIBRATED_NAME, 1);
|
||||
for (x = 0; x < 3; x++) {
|
||||
prefFloatWrite(ZERO_NAME(x), zeros[x]);
|
||||
prefFloatWrite(ONEG_NAME(x), onegs[x]);
|
||||
}
|
||||
prefSynchronize();
|
||||
}
|
||||
|
||||
|
||||
// Sets the calibration to its default values.
|
||||
void defaultCalibration(void) {
|
||||
int x;
|
||||
for (x = 0; x < 3; x++) {
|
||||
zeros[x] = sensors[sensorNum].axes[x].zerog;
|
||||
onegs[x] = sensors[sensorNum].axes[x].oneg;
|
||||
}
|
||||
}
|
||||
|
||||
// Deletes the stored preferences.
|
||||
static void deleteCalibration(void) {
|
||||
int x;
|
||||
|
||||
prefDelete(CALIBRATED_NAME);
|
||||
for (x = 0; x < 3; x++) {
|
||||
prefDelete(ZERO_NAME(x));
|
||||
prefDelete(ONEG_NAME(x));
|
||||
}
|
||||
prefSynchronize();
|
||||
}
|
||||
|
||||
// Read a named floating point value from the stored preferences. Sets
|
||||
// the success boolean based on, you guessed it, whether it succeeds.
|
||||
static float prefFloatRead(NSString *prefName, BOOL *success) {
|
||||
float result = 0.0f;
|
||||
|
||||
CFPropertyListRef ref = CFPreferencesCopyAppValue((CFStringRef)prefName,
|
||||
APP_ID);
|
||||
// If there isn't such a preference, fail
|
||||
if (ref == NULL) {
|
||||
*success = NO;
|
||||
return result;
|
||||
}
|
||||
CFTypeID typeID = CFGetTypeID(ref);
|
||||
// Is it a number?
|
||||
if (typeID == CFNumberGetTypeID()) {
|
||||
// Is it a floating point number?
|
||||
if (CFNumberIsFloatType((CFNumberRef)ref)) {
|
||||
// Yup: grab it.
|
||||
*success = CFNumberGetValue((__CFNumber*)ref, kCFNumberFloat32Type, &result);
|
||||
} else {
|
||||
// Nope: grab as an integer, and convert to a float.
|
||||
long num;
|
||||
if (CFNumberGetValue((CFNumberRef)ref, kCFNumberLongType, &num)) {
|
||||
result = num;
|
||||
*success = YES;
|
||||
} else {
|
||||
*success = NO;
|
||||
}
|
||||
}
|
||||
// Or is it a string (e.g. set by the command line "defaults" command)?
|
||||
} else if (typeID == CFStringGetTypeID()) {
|
||||
result = (float)CFStringGetDoubleValue((CFStringRef)ref);
|
||||
*success = YES;
|
||||
} else {
|
||||
// Can't convert to a number: fail.
|
||||
*success = NO;
|
||||
}
|
||||
CFRelease(ref);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Writes a named floating point value to the stored preferences.
|
||||
static void prefFloatWrite(NSString *prefName, float prefValue) {
|
||||
CFNumberRef cfFloat = CFNumberCreate(kCFAllocatorDefault,
|
||||
kCFNumberFloatType,
|
||||
&prefValue);
|
||||
CFPreferencesSetAppValue((CFStringRef)prefName,
|
||||
cfFloat,
|
||||
APP_ID);
|
||||
CFRelease(cfFloat);
|
||||
}
|
||||
|
||||
// Reads a named integer value from the stored preferences.
|
||||
static int prefIntRead(NSString *prefName, BOOL *success) {
|
||||
Boolean internalSuccess;
|
||||
CFIndex result = CFPreferencesGetAppIntegerValue((CFStringRef)prefName,
|
||||
APP_ID,
|
||||
&internalSuccess);
|
||||
*success = internalSuccess;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Writes a named integer value to the stored preferences.
|
||||
static void prefIntWrite(NSString *prefName, int prefValue) {
|
||||
CFPreferencesSetAppValue((CFStringRef)prefName,
|
||||
(CFNumberRef)[NSNumber numberWithInt:prefValue],
|
||||
APP_ID);
|
||||
}
|
||||
|
||||
// Deletes the named preference values.
|
||||
static void prefDelete(NSString *prefName) {
|
||||
CFPreferencesSetAppValue((CFStringRef)prefName,
|
||||
NULL,
|
||||
APP_ID);
|
||||
}
|
||||
|
||||
// Synchronizes the local preferences with the stored preferences.
|
||||
static void prefSynchronize(void) {
|
||||
CFPreferencesAppSynchronize(APP_ID);
|
||||
}
|
||||
|
||||
// Internal version of accelGetData, with logging
|
||||
int getData(sms_acceleration *accel, int calibrated, id logObject, SEL logSelector) {
|
||||
IOItemCount iSize = recordSize;
|
||||
IOByteCount oSize = recordSize;
|
||||
kern_return_t result;
|
||||
|
||||
if (running == NO) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(iRecord, 1, iSize);
|
||||
memset(oRecord, 0, oSize);
|
||||
|
||||
LOG_2ARG(@" Querying device (%u, %d): ",
|
||||
sensors[sensorNum].function, sensors[sensorNum].recordSize);
|
||||
|
||||
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1050
|
||||
const size_t InStructSize = recordSize;
|
||||
size_t OutStructSize = recordSize;
|
||||
result = IOConnectCallStructMethod(connection,
|
||||
function, // magic kernel function number
|
||||
(const void *)iRecord,
|
||||
InStructSize,
|
||||
(void *)oRecord,
|
||||
&OutStructSize
|
||||
);
|
||||
#else // __MAC_OS_X_VERSION_MIN_REQUIRED 1050
|
||||
result = IOConnectMethodStructureIStructureO(connection,
|
||||
function, // magic kernel function number
|
||||
iSize,
|
||||
&oSize,
|
||||
iRecord,
|
||||
oRecord
|
||||
);
|
||||
#endif // __MAC_OS_X_VERSION_MIN_REQUIRED 1050
|
||||
|
||||
if (result != KERN_SUCCESS) {
|
||||
LOG(@"failed.\n");
|
||||
running = NO;
|
||||
return result;
|
||||
} else {
|
||||
LOG(@"succeeded.\n");
|
||||
|
||||
accel->x = getAxis(0, calibrated);
|
||||
accel->y = getAxis(1, calibrated);
|
||||
accel->z = getAxis(2, calibrated);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Given the returned record, extracts the value of the given axis. If
|
||||
// calibrated, then zero G is 0.0, and one G is 1.0.
|
||||
float getAxis(int which, int calibrated) {
|
||||
// Get various values (to make code cleaner)
|
||||
int indx = sensors[sensorNum].axes[which].index;
|
||||
int size = sensors[sensorNum].axes[which].size;
|
||||
float zerog = zeros[which];
|
||||
float oneg = onegs[which];
|
||||
// Storage for value to be returned
|
||||
int value = 0;
|
||||
|
||||
// Although the values in the returned record should have the proper
|
||||
// endianness, we still have to get it into the proper end of value.
|
||||
#if (BYTE_ORDER == BIG_ENDIAN)
|
||||
// On PowerPC processors
|
||||
memcpy(((char *)&value) + (sizeof(int) - size), &oRecord[indx], size);
|
||||
#endif
|
||||
#if (BYTE_ORDER == LITTLE_ENDIAN)
|
||||
// On Intel processors
|
||||
memcpy(&value, &oRecord[indx], size);
|
||||
#endif
|
||||
|
||||
value = signExtend(value, size);
|
||||
|
||||
if (calibrated) {
|
||||
// Scale and shift for zero.
|
||||
return ((float)(value - zerog)) / oneg;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// Extends the sign, given the length of the value.
|
||||
int signExtend(int value, int size) {
|
||||
// Extend sign
|
||||
switch (size) {
|
||||
case 1:
|
||||
if (value & 0x00000080)
|
||||
value |= 0xffffff00;
|
||||
break;
|
||||
case 2:
|
||||
if (value & 0x00008000)
|
||||
value |= 0xffff0000;
|
||||
break;
|
||||
case 3:
|
||||
if (value & 0x00800000)
|
||||
value |= 0xff000000;
|
||||
break;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// Returns the model name of the computer (e.g. "MacBookPro1,1")
|
||||
NSString *getModelName(void) {
|
||||
char model[32];
|
||||
size_t len = sizeof(model);
|
||||
int name[2] = {CTL_HW, HW_MODEL};
|
||||
NSString *result;
|
||||
|
||||
if (sysctl(name, 2, &model, &len, NULL, 0) == 0) {
|
||||
result = [NSString stringWithFormat:@"%s", model];
|
||||
} else {
|
||||
result = @"";
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Returns the current OS X version and build (e.g. "10.4.7 (build 8J2135a)")
|
||||
NSString *getOSVersion(void) {
|
||||
NSDictionary *dict = [NSDictionary dictionaryWithContentsOfFile:
|
||||
@"/System/Library/CoreServices/SystemVersion.plist"];
|
||||
NSString *versionString = [dict objectForKey:@"ProductVersion"];
|
||||
NSString *buildString = [dict objectForKey:@"ProductBuildVersion"];
|
||||
NSString *wholeString = [NSString stringWithFormat:@"%@ (build %@)",
|
||||
versionString, buildString];
|
||||
return wholeString;
|
||||
}
|
||||
|
||||
// Returns time within the current second in microseconds.
|
||||
// long getMicroseconds() {
|
||||
// struct timeval t;
|
||||
// gettimeofday(&t, 0);
|
||||
// return t.tv_usec;
|
||||
//}
|
||||
|
||||
// Returns fake data given the time. Range is +/-1.
|
||||
float fakeData(NSTimeInterval time) {
|
||||
long secs = lround(floor(time));
|
||||
int secsMod3 = secs % 3;
|
||||
double angle = time * 10 * M_PI * 2;
|
||||
double mag = exp(-(time - (secs - secsMod3)) * 2);
|
||||
return sin(angle) * mag;
|
||||
}
|
||||
|
||||
79
hal/fallback/FallbackAlarm.cpp
Normal file
79
hal/fallback/FallbackAlarm.cpp
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/* 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 <algorithm>
|
||||
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
static void
|
||||
TimerCallbackFunc(nsITimer *aTimer, void *aClosure)
|
||||
{
|
||||
hal::NotifyAlarmFired();
|
||||
}
|
||||
|
||||
static StaticRefPtr<nsITimer> sTimer;
|
||||
|
||||
bool
|
||||
EnableAlarm()
|
||||
{
|
||||
static bool initialized = false;
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
ClearOnShutdown(&sTimer);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
sTimer = timer;
|
||||
MOZ_ASSERT(sTimer);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
DisableAlarm()
|
||||
{
|
||||
/*
|
||||
* DisableAlarm() may be called after sTimer has been set to null by
|
||||
* ClearOnShutdown().
|
||||
*/
|
||||
if (sTimer) {
|
||||
sTimer->Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
SetAlarm(int32_t aSeconds, int32_t aNanoseconds)
|
||||
{
|
||||
if (!sTimer) {
|
||||
MOZ_ASSERT(false, "We should have enabled the alarm");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do the math to convert aSeconds and aNanoseconds into milliseconds since
|
||||
// the epoch.
|
||||
int64_t milliseconds = static_cast<int64_t>(aSeconds) * 1000 +
|
||||
static_cast<int64_t>(aNanoseconds) / 1000000;
|
||||
|
||||
// nsITimer expects relative milliseconds.
|
||||
int64_t relMilliseconds = milliseconds - PR_Now() / 1000;
|
||||
|
||||
// If the alarm time is in the past relative to PR_Now(),
|
||||
// we choose to immediately fire the alarm. Passing 0 means nsITimer will
|
||||
// queue a timeout event immediately.
|
||||
sTimer->InitWithFuncCallback(TimerCallbackFunc, nullptr,
|
||||
clamped<int64_t>(relMilliseconds, 0, INT32_MAX),
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
||||
30
hal/fallback/FallbackBattery.cpp
Normal file
30
hal/fallback/FallbackBattery.cpp
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||
/* 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 "mozilla/dom/battery/Constants.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
void
|
||||
EnableBatteryNotifications()
|
||||
{}
|
||||
|
||||
void
|
||||
DisableBatteryNotifications()
|
||||
{}
|
||||
|
||||
void
|
||||
GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
|
||||
{
|
||||
aBatteryInfo->level() = dom::battery::kDefaultLevel;
|
||||
aBatteryInfo->charging() = dom::battery::kDefaultCharging;
|
||||
aBatteryInfo->remainingTime() = dom::battery::kDefaultRemainingTime;
|
||||
}
|
||||
|
||||
} // hal_impl
|
||||
} // namespace mozilla
|
||||
19
hal/fallback/FallbackDiskSpaceWatcher.cpp
Normal file
19
hal/fallback/FallbackDiskSpaceWatcher.cpp
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/* 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/. */
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
void
|
||||
StartDiskSpaceWatcher()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
StopDiskSpaceWatcher()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
||||
18
hal/fallback/FallbackFactoryReset.cpp
Normal file
18
hal/fallback/FallbackFactoryReset.cpp
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=8 et :
|
||||
*/
|
||||
/* 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"
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
void
|
||||
FactoryReset(mozilla::dom::FactoryResetReason&)
|
||||
{}
|
||||
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
||||
20
hal/fallback/FallbackMemory.cpp
Normal file
20
hal/fallback/FallbackMemory.cpp
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=8 et :
|
||||
*/
|
||||
/* 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"
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
uint32_t
|
||||
GetTotalSystemMemory()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
||||
31
hal/fallback/FallbackNetwork.cpp
Normal file
31
hal/fallback/FallbackNetwork.cpp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=8 et :
|
||||
*/
|
||||
/* 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 "mozilla/dom/network/Constants.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
void
|
||||
EnableNetworkNotifications()
|
||||
{}
|
||||
|
||||
void
|
||||
DisableNetworkNotifications()
|
||||
{}
|
||||
|
||||
void
|
||||
GetCurrentNetworkInformation(hal::NetworkInformation* aNetworkInfo)
|
||||
{
|
||||
aNetworkInfo->type() = dom::network::kDefaultType;
|
||||
aNetworkInfo->isWifi() = dom::network::kDefaultIsWifi;
|
||||
aNetworkInfo->dhcpGateway() = dom::network::kDefaultDHCPGateway;
|
||||
}
|
||||
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
||||
25
hal/fallback/FallbackPower.cpp
Normal file
25
hal/fallback/FallbackPower.cpp
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||
/* 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"
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
void
|
||||
Reboot()
|
||||
{}
|
||||
|
||||
void
|
||||
PowerOff()
|
||||
{}
|
||||
|
||||
void
|
||||
StartForceQuitWatchdog(hal::ShutdownMode aMode, int32_t aTimeoutSecs)
|
||||
{}
|
||||
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
||||
21
hal/fallback/FallbackProcessPriority.cpp
Normal file
21
hal/fallback/FallbackProcessPriority.cpp
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/* 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 "HalLog.h"
|
||||
|
||||
using namespace mozilla::hal;
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
void
|
||||
SetProcessPriority(int aPid, ProcessPriority aPriority, uint32_t aLRU)
|
||||
{
|
||||
HAL_LOG("FallbackProcessPriority - SetProcessPriority(%d, %s, %u)\n",
|
||||
aPid, ProcessPriorityToString(aPriority), aLRU);
|
||||
}
|
||||
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
||||
63
hal/fallback/FallbackScreenConfiguration.cpp
Normal file
63
hal/fallback/FallbackScreenConfiguration.cpp
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/* 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 "mozilla/dom/ScreenOrientation.h"
|
||||
#include "nsIScreenManager.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
void
|
||||
EnableScreenConfigurationNotifications()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
DisableScreenConfigurationNotifications()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
GetCurrentScreenConfiguration(hal::ScreenConfiguration* aScreenConfiguration)
|
||||
{
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIScreenManager> screenMgr =
|
||||
do_GetService("@mozilla.org/gfx/screenmanager;1", &rv);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("Can't find nsIScreenManager!");
|
||||
return;
|
||||
}
|
||||
|
||||
nsIntRect rect;
|
||||
int32_t colorDepth, pixelDepth;
|
||||
dom::ScreenOrientationInternal orientation;
|
||||
nsCOMPtr<nsIScreen> screen;
|
||||
|
||||
screenMgr->GetPrimaryScreen(getter_AddRefs(screen));
|
||||
screen->GetRect(&rect.x, &rect.y, &rect.width, &rect.height);
|
||||
screen->GetColorDepth(&colorDepth);
|
||||
screen->GetPixelDepth(&pixelDepth);
|
||||
orientation = rect.width >= rect.height
|
||||
? dom::eScreenOrientation_LandscapePrimary
|
||||
: dom::eScreenOrientation_PortraitPrimary;
|
||||
|
||||
*aScreenConfiguration =
|
||||
hal::ScreenConfiguration(rect, orientation, 0, colorDepth, pixelDepth);
|
||||
}
|
||||
|
||||
bool
|
||||
LockScreenOrientation(const dom::ScreenOrientationInternal& aOrientation)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
UnlockScreenOrientation()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
||||
41
hal/fallback/FallbackScreenPower.cpp
Normal file
41
hal/fallback/FallbackScreenPower.cpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||
/* 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/. */
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
bool
|
||||
GetScreenEnabled()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SetScreenEnabled(bool aEnabled)
|
||||
{}
|
||||
|
||||
bool
|
||||
GetKeyLightEnabled()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SetKeyLightEnabled(bool aEnabled)
|
||||
{}
|
||||
|
||||
double
|
||||
GetScreenBrightness()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
SetScreenBrightness(double aBrightness)
|
||||
{}
|
||||
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
||||
23
hal/fallback/FallbackSensor.cpp
Normal file
23
hal/fallback/FallbackSensor.cpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set sw=4 ts=8 et ft=cpp : */
|
||||
/* 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 "mozilla/Hal.h"
|
||||
|
||||
using namespace mozilla::hal;
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
void
|
||||
EnableSensorNotifications(SensorType aSensor) {
|
||||
}
|
||||
|
||||
void
|
||||
DisableSensorNotifications(SensorType aSensor) {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
39
hal/fallback/FallbackSwitch.cpp
Normal file
39
hal/fallback/FallbackSwitch.cpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "mozilla/Hal.h"
|
||||
|
||||
using namespace mozilla::hal;
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
void
|
||||
EnableSwitchNotifications(SwitchDevice aDevice)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
DisableSwitchNotifications(SwitchDevice aDevice)
|
||||
{
|
||||
}
|
||||
|
||||
SwitchState
|
||||
GetCurrentSwitchState(SwitchDevice aDevice) {
|
||||
return SWITCH_STATE_UNKNOWN;
|
||||
}
|
||||
|
||||
void
|
||||
NotifySwitchStateFromInputDevice(SwitchDevice aDevice, SwitchState aState)
|
||||
{
|
||||
}
|
||||
|
||||
bool IsHeadphoneEventFromInputDev()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
||||
35
hal/fallback/FallbackSystemService.cpp
Normal file
35
hal/fallback/FallbackSystemService.cpp
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||
/* 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"
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
nsresult
|
||||
StartSystemService(const char* aSvcName, const char* aArgs)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
void
|
||||
StopSystemService(const char* aSvcName)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
bool
|
||||
SystemServiceIsRunning(const char* aSvcName)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
||||
29
hal/fallback/FallbackThreadPriority.cpp
Normal file
29
hal/fallback/FallbackThreadPriority.cpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/* 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 "HalLog.h"
|
||||
|
||||
using namespace mozilla::hal;
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
void
|
||||
SetCurrentThreadPriority(ThreadPriority aPriority)
|
||||
{
|
||||
HAL_LOG("FallbackThreadPriority - SetCurrentThreadPriority(%d)\n",
|
||||
ThreadPriorityToString(aPriority));
|
||||
}
|
||||
|
||||
void
|
||||
SetThreadPriority(PlatformThreadId aThreadId,
|
||||
ThreadPriority aPriority)
|
||||
{
|
||||
HAL_LOG("FallbackThreadPriority - SetThreadPriority(%d, %d)\n",
|
||||
aThreadId, ThreadPriorityToString(aPriority));
|
||||
}
|
||||
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
||||
54
hal/fallback/FallbackTime.cpp
Normal file
54
hal/fallback/FallbackTime.cpp
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=8 et :
|
||||
*/
|
||||
/* 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"
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
void
|
||||
AdjustSystemClock(int64_t aDeltaMilliseconds)
|
||||
{}
|
||||
|
||||
void
|
||||
SetTimezone(const nsCString& aTimezoneSpec)
|
||||
{}
|
||||
|
||||
nsCString
|
||||
GetTimezone()
|
||||
{
|
||||
return EmptyCString();
|
||||
}
|
||||
|
||||
int32_t
|
||||
GetTimezoneOffset()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
EnableSystemClockChangeNotifications()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
DisableSystemClockChangeNotifications()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
EnableSystemTimezoneChangeNotifications()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
DisableSystemTimezoneChangeNotifications()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
||||
23
hal/fallback/FallbackVibration.cpp
Normal file
23
hal/fallback/FallbackVibration.cpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||
/* 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"
|
||||
|
||||
using mozilla::hal::WindowIdentifier;
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
void
|
||||
Vibrate(const nsTArray<uint32_t>& pattern, const hal::WindowIdentifier &)
|
||||
{}
|
||||
|
||||
void
|
||||
CancelVibrate(const hal::WindowIdentifier &)
|
||||
{}
|
||||
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
||||
23
hal/fallback/FallbackWakeLocks.cpp
Normal file
23
hal/fallback/FallbackWakeLocks.cpp
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||
/* 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"
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
bool
|
||||
GetCpuSleepAllowed()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
SetCpuSleepAllowed(bool allowed)
|
||||
{}
|
||||
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
||||
324
hal/gonk/GonkDiskSpaceWatcher.cpp
Normal file
324
hal/gonk/GonkDiskSpaceWatcher.cpp
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
/* 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
|
||||
2045
hal/gonk/GonkHal.cpp
Normal file
2045
hal/gonk/GonkHal.cpp
Normal file
File diff suppressed because it is too large
Load diff
861
hal/gonk/GonkSensor.cpp
Normal file
861
hal/gonk/GonkSensor.cpp
Normal file
|
|
@ -0,0 +1,861 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* Copyright 2012 Mozilla Foundation and Mozilla contributors
|
||||
*
|
||||
* 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 <pthread.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/Saturate.h"
|
||||
|
||||
#include "base/basictypes.h"
|
||||
#include "base/thread.h"
|
||||
#include "base/task.h"
|
||||
|
||||
#include "GonkSensorsInterface.h"
|
||||
#include "GonkSensorsPollInterface.h"
|
||||
#include "GonkSensorsRegistryInterface.h"
|
||||
#include "Hal.h"
|
||||
#include "HalLog.h"
|
||||
#include "HalSensor.h"
|
||||
#include "hardware/sensors.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
using namespace mozilla::hal;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
//
|
||||
// Internal implementation
|
||||
//
|
||||
|
||||
// The value from SensorDevice.h (Android)
|
||||
#define DEFAULT_DEVICE_POLL_RATE 200000000 /*200ms*/
|
||||
// ProcessOrientation.cpp needs smaller poll rate to detect delay between
|
||||
// different orientation angles
|
||||
#define ACCELEROMETER_POLL_RATE 66667000 /*66.667ms*/
|
||||
|
||||
// This is present in Android from API level 18 onwards, which is 4.3. We might
|
||||
// be building on something before 4.3, so use a local define for its value
|
||||
#define MOZ_SENSOR_TYPE_GAME_ROTATION_VECTOR 15
|
||||
|
||||
double radToDeg(double a) {
|
||||
return a * (180.0 / M_PI);
|
||||
}
|
||||
|
||||
static SensorType
|
||||
HardwareSensorToHalSensor(int type)
|
||||
{
|
||||
switch(type) {
|
||||
case SENSOR_TYPE_ORIENTATION:
|
||||
return SENSOR_ORIENTATION;
|
||||
case SENSOR_TYPE_ACCELEROMETER:
|
||||
return SENSOR_ACCELERATION;
|
||||
case SENSOR_TYPE_PROXIMITY:
|
||||
return SENSOR_PROXIMITY;
|
||||
case SENSOR_TYPE_LIGHT:
|
||||
return SENSOR_LIGHT;
|
||||
case SENSOR_TYPE_GYROSCOPE:
|
||||
return SENSOR_GYROSCOPE;
|
||||
case SENSOR_TYPE_LINEAR_ACCELERATION:
|
||||
return SENSOR_LINEAR_ACCELERATION;
|
||||
case SENSOR_TYPE_ROTATION_VECTOR:
|
||||
return SENSOR_ROTATION_VECTOR;
|
||||
case MOZ_SENSOR_TYPE_GAME_ROTATION_VECTOR:
|
||||
return SENSOR_GAME_ROTATION_VECTOR;
|
||||
default:
|
||||
return SENSOR_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
static SensorAccuracyType
|
||||
HardwareStatusToHalAccuracy(int status) {
|
||||
return static_cast<SensorAccuracyType>(status);
|
||||
}
|
||||
|
||||
static int
|
||||
HalSensorToHardwareSensor(SensorType type)
|
||||
{
|
||||
switch(type) {
|
||||
case SENSOR_ORIENTATION:
|
||||
return SENSOR_TYPE_ORIENTATION;
|
||||
case SENSOR_ACCELERATION:
|
||||
return SENSOR_TYPE_ACCELEROMETER;
|
||||
case SENSOR_PROXIMITY:
|
||||
return SENSOR_TYPE_PROXIMITY;
|
||||
case SENSOR_LIGHT:
|
||||
return SENSOR_TYPE_LIGHT;
|
||||
case SENSOR_GYROSCOPE:
|
||||
return SENSOR_TYPE_GYROSCOPE;
|
||||
case SENSOR_LINEAR_ACCELERATION:
|
||||
return SENSOR_TYPE_LINEAR_ACCELERATION;
|
||||
case SENSOR_ROTATION_VECTOR:
|
||||
return SENSOR_TYPE_ROTATION_VECTOR;
|
||||
case SENSOR_GAME_ROTATION_VECTOR:
|
||||
return MOZ_SENSOR_TYPE_GAME_ROTATION_VECTOR;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
SensorseventStatus(const sensors_event_t& data)
|
||||
{
|
||||
int type = data.type;
|
||||
switch(type) {
|
||||
case SENSOR_ORIENTATION:
|
||||
return data.orientation.status;
|
||||
case SENSOR_LINEAR_ACCELERATION:
|
||||
case SENSOR_ACCELERATION:
|
||||
return data.acceleration.status;
|
||||
case SENSOR_GYROSCOPE:
|
||||
return data.gyro.status;
|
||||
}
|
||||
|
||||
return SENSOR_STATUS_UNRELIABLE;
|
||||
}
|
||||
|
||||
class SensorRunnable : public Runnable
|
||||
{
|
||||
public:
|
||||
SensorRunnable(const sensors_event_t& data, const sensor_t* sensors, ssize_t size)
|
||||
{
|
||||
mSensorData.sensor() = HardwareSensorToHalSensor(data.type);
|
||||
mSensorData.accuracy() = HardwareStatusToHalAccuracy(SensorseventStatus(data));
|
||||
mSensorData.timestamp() = data.timestamp;
|
||||
if (mSensorData.sensor() == SENSOR_GYROSCOPE) {
|
||||
// libhardware returns gyro as rad. convert.
|
||||
mSensorValues.AppendElement(radToDeg(data.data[0]));
|
||||
mSensorValues.AppendElement(radToDeg(data.data[1]));
|
||||
mSensorValues.AppendElement(radToDeg(data.data[2]));
|
||||
} else if (mSensorData.sensor() == SENSOR_PROXIMITY) {
|
||||
mSensorValues.AppendElement(data.data[0]);
|
||||
mSensorValues.AppendElement(0);
|
||||
|
||||
// Determine the maxRange for this sensor.
|
||||
for (ssize_t i = 0; i < size; i++) {
|
||||
if (sensors[i].type == SENSOR_TYPE_PROXIMITY) {
|
||||
mSensorValues.AppendElement(sensors[i].maxRange);
|
||||
}
|
||||
}
|
||||
} else if (mSensorData.sensor() == SENSOR_LIGHT) {
|
||||
mSensorValues.AppendElement(data.data[0]);
|
||||
} else if (mSensorData.sensor() == SENSOR_ROTATION_VECTOR) {
|
||||
mSensorValues.AppendElement(data.data[0]);
|
||||
mSensorValues.AppendElement(data.data[1]);
|
||||
mSensorValues.AppendElement(data.data[2]);
|
||||
if (data.data[3] == 0.0) {
|
||||
// data.data[3] was optional in Android <= API level 18. It can be computed from 012,
|
||||
// but it's better to take the actual value if one is provided. The computation is
|
||||
// v = 1 - d[0]*d[0] - d[1]*d[1] - d[2]*d[2]
|
||||
// d[3] = v > 0 ? sqrt(v) : 0;
|
||||
// I'm assuming that it will be 0 if it's not passed in. (The values form a unit
|
||||
// quaternion, so the angle can be computed from the direction vector.)
|
||||
float sx = data.data[0], sy = data.data[1], sz = data.data[2];
|
||||
float v = 1.0f - sx*sx - sy*sy - sz*sz;
|
||||
mSensorValues.AppendElement(v > 0.0f ? sqrt(v) : 0.0f);
|
||||
} else {
|
||||
mSensorValues.AppendElement(data.data[3]);
|
||||
}
|
||||
} else if (mSensorData.sensor() == SENSOR_GAME_ROTATION_VECTOR) {
|
||||
mSensorValues.AppendElement(data.data[0]);
|
||||
mSensorValues.AppendElement(data.data[1]);
|
||||
mSensorValues.AppendElement(data.data[2]);
|
||||
mSensorValues.AppendElement(data.data[3]);
|
||||
} else {
|
||||
mSensorValues.AppendElement(data.data[0]);
|
||||
mSensorValues.AppendElement(data.data[1]);
|
||||
mSensorValues.AppendElement(data.data[2]);
|
||||
}
|
||||
mSensorData.values() = mSensorValues;
|
||||
}
|
||||
|
||||
~SensorRunnable() {}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
NotifySensorChange(mSensorData);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
SensorData mSensorData;
|
||||
AutoTArray<float, 4> mSensorValues;
|
||||
};
|
||||
|
||||
namespace hal_impl {
|
||||
|
||||
static DebugOnly<int> sSensorRefCount[NUM_SENSOR_TYPE];
|
||||
static base::Thread* sPollingThread;
|
||||
static sensors_poll_device_t* sSensorDevice;
|
||||
static sensors_module_t* sSensorModule;
|
||||
|
||||
static void
|
||||
PollSensors()
|
||||
{
|
||||
const size_t numEventMax = 16;
|
||||
sensors_event_t buffer[numEventMax];
|
||||
const sensor_t* sensors;
|
||||
int size = sSensorModule->get_sensors_list(sSensorModule, &sensors);
|
||||
|
||||
do {
|
||||
// didn't check sSensorDevice because already be done on creating pollingThread.
|
||||
int n = sSensorDevice->poll(sSensorDevice, buffer, numEventMax);
|
||||
if (n < 0) {
|
||||
HAL_ERR("Error polling for sensor data (err=%d)", n);
|
||||
break;
|
||||
}
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
// FIXME: bug 802004, add proper support for the magnetic field sensor.
|
||||
if (buffer[i].type == SENSOR_TYPE_MAGNETIC_FIELD)
|
||||
continue;
|
||||
|
||||
// Bug 938035, transfer HAL data for orientation sensor to meet w3c spec
|
||||
// ex: HAL report alpha=90 means East but alpha=90 means West in w3c spec
|
||||
if (buffer[i].type == SENSOR_TYPE_ORIENTATION) {
|
||||
buffer[i].orientation.azimuth = 360 - buffer[i].orientation.azimuth;
|
||||
buffer[i].orientation.pitch = -buffer[i].orientation.pitch;
|
||||
buffer[i].orientation.roll = -buffer[i].orientation.roll;
|
||||
}
|
||||
|
||||
if (HardwareSensorToHalSensor(buffer[i].type) == SENSOR_UNKNOWN) {
|
||||
// Emulator is broken and gives us events without types set
|
||||
int index;
|
||||
for (index = 0; index < size; index++) {
|
||||
if (sensors[index].handle == buffer[i].sensor) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (index < size &&
|
||||
HardwareSensorToHalSensor(sensors[index].type) != SENSOR_UNKNOWN) {
|
||||
buffer[i].type = sensors[index].type;
|
||||
} else {
|
||||
HAL_LOG("Could not determine sensor type of event");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
NS_DispatchToMainThread(new SensorRunnable(buffer[i], sensors, size));
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
static void
|
||||
SwitchSensor(bool aActivate, sensor_t aSensor, pthread_t aThreadId)
|
||||
{
|
||||
int index = HardwareSensorToHalSensor(aSensor.type);
|
||||
|
||||
MOZ_ASSERT(sSensorRefCount[index] || aActivate);
|
||||
|
||||
sSensorDevice->activate(sSensorDevice, aSensor.handle, aActivate);
|
||||
|
||||
if (aActivate) {
|
||||
if (aSensor.type == SENSOR_TYPE_ACCELEROMETER) {
|
||||
sSensorDevice->setDelay(sSensorDevice, aSensor.handle,
|
||||
ACCELEROMETER_POLL_RATE);
|
||||
} else {
|
||||
sSensorDevice->setDelay(sSensorDevice, aSensor.handle,
|
||||
DEFAULT_DEVICE_POLL_RATE);
|
||||
}
|
||||
}
|
||||
|
||||
if (aActivate) {
|
||||
sSensorRefCount[index]++;
|
||||
} else {
|
||||
sSensorRefCount[index]--;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
SetSensorState(SensorType aSensor, bool activate)
|
||||
{
|
||||
int type = HalSensorToHardwareSensor(aSensor);
|
||||
const sensor_t* sensors = nullptr;
|
||||
|
||||
int size = sSensorModule->get_sensors_list(sSensorModule, &sensors);
|
||||
for (ssize_t i = 0; i < size; i++) {
|
||||
if (sensors[i].type == type) {
|
||||
SwitchSensor(activate, sensors[i], pthread_self());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
EnableSensorNotificationsInternal(SensorType aSensor)
|
||||
{
|
||||
if (!sSensorModule) {
|
||||
hw_get_module(SENSORS_HARDWARE_MODULE_ID,
|
||||
(hw_module_t const**)&sSensorModule);
|
||||
if (!sSensorModule) {
|
||||
HAL_ERR("Can't get sensor HAL module\n");
|
||||
return;
|
||||
}
|
||||
|
||||
sensors_open(&sSensorModule->common, &sSensorDevice);
|
||||
if (!sSensorDevice) {
|
||||
sSensorModule = nullptr;
|
||||
HAL_ERR("Can't get sensor poll device from module \n");
|
||||
return;
|
||||
}
|
||||
|
||||
sensor_t const* sensors;
|
||||
int count = sSensorModule->get_sensors_list(sSensorModule, &sensors);
|
||||
for (size_t i=0 ; i<size_t(count) ; i++) {
|
||||
sSensorDevice->activate(sSensorDevice, sensors[i].handle, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!sPollingThread) {
|
||||
sPollingThread = new base::Thread("GonkSensors");
|
||||
MOZ_ASSERT(sPollingThread);
|
||||
// sPollingThread never terminates because poll may never return
|
||||
sPollingThread->Start();
|
||||
sPollingThread->message_loop()->PostTask(
|
||||
NewRunnableFunction(PollSensors));
|
||||
}
|
||||
|
||||
SetSensorState(aSensor, true);
|
||||
}
|
||||
|
||||
static void
|
||||
DisableSensorNotificationsInternal(SensorType aSensor)
|
||||
{
|
||||
if (!sSensorModule) {
|
||||
return;
|
||||
}
|
||||
SetSensorState(aSensor, false);
|
||||
}
|
||||
|
||||
//
|
||||
// Daemon
|
||||
//
|
||||
|
||||
typedef detail::SaturateOp<uint32_t> SaturateOpUint32;
|
||||
|
||||
/**
|
||||
* The poll notification handler receives all events about sensors and
|
||||
* sensor events.
|
||||
*/
|
||||
class SensorsPollNotificationHandler final
|
||||
: public GonkSensorsPollNotificationHandler
|
||||
{
|
||||
public:
|
||||
SensorsPollNotificationHandler(GonkSensorsPollInterface* aPollInterface)
|
||||
: mPollInterface(aPollInterface)
|
||||
{
|
||||
MOZ_ASSERT(mPollInterface);
|
||||
|
||||
mPollInterface->SetNotificationHandler(this);
|
||||
}
|
||||
|
||||
void EnableSensorsByType(SensorsType aType)
|
||||
{
|
||||
if (SaturateOpUint32(mClasses[aType].mActivated)++) {
|
||||
return;
|
||||
}
|
||||
|
||||
SensorsDeliveryMode deliveryMode = DefaultSensorsDeliveryMode(aType);
|
||||
|
||||
// Old ref-count for the sensor type was 0, so we
|
||||
// activate all sensors of the type.
|
||||
for (size_t i = 0; i < mSensors.Length(); ++i) {
|
||||
if (mSensors[i].mType == aType &&
|
||||
mSensors[i].mDeliveryMode == deliveryMode) {
|
||||
mPollInterface->EnableSensor(mSensors[i].mId, nullptr);
|
||||
mPollInterface->SetPeriod(mSensors[i].mId, DefaultSensorPeriod(aType),
|
||||
nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DisableSensorsByType(SensorsType aType)
|
||||
{
|
||||
if (SaturateOpUint32(mClasses[aType].mActivated)-- != 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
SensorsDeliveryMode deliveryMode = DefaultSensorsDeliveryMode(aType);
|
||||
|
||||
// Old ref-count for the sensor type was 1, so we
|
||||
// deactivate all sensors of the type.
|
||||
for (size_t i = 0; i < mSensors.Length(); ++i) {
|
||||
if (mSensors[i].mType == aType &&
|
||||
mSensors[i].mDeliveryMode == deliveryMode) {
|
||||
mPollInterface->DisableSensor(mSensors[i].mId, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClearSensorClasses()
|
||||
{
|
||||
for (size_t i = 0; i < MOZ_ARRAY_LENGTH(mClasses); ++i) {
|
||||
mClasses[i] = SensorsSensorClass();
|
||||
}
|
||||
}
|
||||
|
||||
void ClearSensors()
|
||||
{
|
||||
mSensors.Clear();
|
||||
}
|
||||
|
||||
// Methods for SensorsPollNotificationHandler
|
||||
//
|
||||
|
||||
void ErrorNotification(SensorsError aError) override
|
||||
{
|
||||
// XXX: Bug 1206056: Try to repair some of the errors or restart cleanly.
|
||||
}
|
||||
|
||||
void SensorDetectedNotification(int32_t aId, SensorsType aType,
|
||||
float aRange, float aResolution,
|
||||
float aPower, int32_t aMinPeriod,
|
||||
int32_t aMaxPeriod,
|
||||
SensorsTriggerMode aTriggerMode,
|
||||
SensorsDeliveryMode aDeliveryMode) override
|
||||
{
|
||||
auto i = FindSensorIndexById(aId);
|
||||
if (i == -1) {
|
||||
// Add a new sensor...
|
||||
i = mSensors.Length();
|
||||
mSensors.AppendElement(SensorsSensor(aId, aType, aRange, aResolution,
|
||||
aPower, aMinPeriod, aMaxPeriod,
|
||||
aTriggerMode, aDeliveryMode));
|
||||
} else {
|
||||
// ...or update an existing one.
|
||||
mSensors[i] = SensorsSensor(aId, aType, aRange, aResolution, aPower,
|
||||
aMinPeriod, aMaxPeriod, aTriggerMode,
|
||||
aDeliveryMode);
|
||||
}
|
||||
|
||||
mClasses[aType].UpdateFromSensor(mSensors[i]);
|
||||
|
||||
if (mClasses[aType].mActivated &&
|
||||
mSensors[i].mDeliveryMode == DefaultSensorsDeliveryMode(aType)) {
|
||||
// The new sensor's type is enabled, so enable sensor.
|
||||
mPollInterface->EnableSensor(aId, nullptr);
|
||||
mPollInterface->SetPeriod(mSensors[i].mId, DefaultSensorPeriod(aType),
|
||||
nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void SensorLostNotification(int32_t aId) override
|
||||
{
|
||||
auto i = FindSensorIndexById(aId);
|
||||
if (i != -1) {
|
||||
mSensors.RemoveElementAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
void EventNotification(int32_t aId, const SensorsEvent& aEvent) override
|
||||
{
|
||||
auto i = FindSensorIndexById(aId);
|
||||
if (i == -1) {
|
||||
HAL_ERR("Sensor %d not registered", aId);
|
||||
return;
|
||||
}
|
||||
|
||||
SensorData sensorData;
|
||||
auto rv = CreateSensorData(aEvent, mClasses[mSensors[i].mType],
|
||||
sensorData);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
NotifySensorChange(sensorData);
|
||||
}
|
||||
|
||||
private:
|
||||
ssize_t FindSensorIndexById(int32_t aId) const
|
||||
{
|
||||
for (size_t i = 0; i < mSensors.Length(); ++i) {
|
||||
if (mSensors[i].mId == aId) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint64_t DefaultSensorPeriod(SensorsType aType) const
|
||||
{
|
||||
return aType == SENSORS_TYPE_ACCELEROMETER ? ACCELEROMETER_POLL_RATE
|
||||
: DEFAULT_DEVICE_POLL_RATE;
|
||||
}
|
||||
|
||||
SensorsDeliveryMode DefaultSensorsDeliveryMode(SensorsType aType) const
|
||||
{
|
||||
if (aType == SENSORS_TYPE_PROXIMITY ||
|
||||
aType == SENSORS_TYPE_SIGNIFICANT_MOTION) {
|
||||
return SENSORS_DELIVERY_MODE_IMMEDIATE;
|
||||
}
|
||||
return SENSORS_DELIVERY_MODE_BEST_EFFORT;
|
||||
}
|
||||
|
||||
SensorType HardwareSensorToHalSensor(SensorsType aType) const
|
||||
{
|
||||
// FIXME: bug 802004, add proper support for the magnetic-field sensor.
|
||||
switch (aType) {
|
||||
case SENSORS_TYPE_ORIENTATION:
|
||||
return SENSOR_ORIENTATION;
|
||||
case SENSORS_TYPE_ACCELEROMETER:
|
||||
return SENSOR_ACCELERATION;
|
||||
case SENSORS_TYPE_PROXIMITY:
|
||||
return SENSOR_PROXIMITY;
|
||||
case SENSORS_TYPE_LIGHT:
|
||||
return SENSOR_LIGHT;
|
||||
case SENSORS_TYPE_GYROSCOPE:
|
||||
return SENSOR_GYROSCOPE;
|
||||
case SENSORS_TYPE_LINEAR_ACCELERATION:
|
||||
return SENSOR_LINEAR_ACCELERATION;
|
||||
case SENSORS_TYPE_ROTATION_VECTOR:
|
||||
return SENSOR_ROTATION_VECTOR;
|
||||
case SENSORS_TYPE_GAME_ROTATION_VECTOR:
|
||||
return SENSOR_GAME_ROTATION_VECTOR;
|
||||
default:
|
||||
NS_NOTREACHED("Invalid sensors type");
|
||||
}
|
||||
return SENSOR_UNKNOWN;
|
||||
}
|
||||
|
||||
SensorAccuracyType HardwareStatusToHalAccuracy(SensorsStatus aStatus) const
|
||||
{
|
||||
return static_cast<SensorAccuracyType>(aStatus - 1);
|
||||
}
|
||||
|
||||
nsresult CreateSensorData(const SensorsEvent& aEvent,
|
||||
const SensorsSensorClass& aSensorClass,
|
||||
SensorData& aSensorData) const
|
||||
{
|
||||
AutoTArray<float, 4> sensorValues;
|
||||
|
||||
auto sensor = HardwareSensorToHalSensor(aEvent.mType);
|
||||
|
||||
if (sensor == SENSOR_UNKNOWN) {
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
aSensorData.sensor() = sensor;
|
||||
aSensorData.accuracy() = HardwareStatusToHalAccuracy(aEvent.mStatus);
|
||||
aSensorData.timestamp() = aEvent.mTimestamp;
|
||||
|
||||
if (aSensorData.sensor() == SENSOR_ORIENTATION) {
|
||||
// Bug 938035: transfer HAL data for orientation sensor to meet W3C spec
|
||||
// ex: HAL report alpha=90 means East but alpha=90 means West in W3C spec
|
||||
sensorValues.AppendElement(360.0 - radToDeg(aEvent.mData.mFloat[0]));
|
||||
sensorValues.AppendElement(-radToDeg(aEvent.mData.mFloat[1]));
|
||||
sensorValues.AppendElement(-radToDeg(aEvent.mData.mFloat[2]));
|
||||
} else if (aSensorData.sensor() == SENSOR_ACCELERATION) {
|
||||
sensorValues.AppendElement(aEvent.mData.mFloat[0]);
|
||||
sensorValues.AppendElement(aEvent.mData.mFloat[1]);
|
||||
sensorValues.AppendElement(aEvent.mData.mFloat[2]);
|
||||
} else if (aSensorData.sensor() == SENSOR_PROXIMITY) {
|
||||
sensorValues.AppendElement(aEvent.mData.mFloat[0]);
|
||||
sensorValues.AppendElement(aSensorClass.mMinValue);
|
||||
sensorValues.AppendElement(aSensorClass.mMaxValue);
|
||||
} else if (aSensorData.sensor() == SENSOR_LINEAR_ACCELERATION) {
|
||||
sensorValues.AppendElement(aEvent.mData.mFloat[0]);
|
||||
sensorValues.AppendElement(aEvent.mData.mFloat[1]);
|
||||
sensorValues.AppendElement(aEvent.mData.mFloat[2]);
|
||||
} else if (aSensorData.sensor() == SENSOR_GYROSCOPE) {
|
||||
sensorValues.AppendElement(radToDeg(aEvent.mData.mFloat[0]));
|
||||
sensorValues.AppendElement(radToDeg(aEvent.mData.mFloat[1]));
|
||||
sensorValues.AppendElement(radToDeg(aEvent.mData.mFloat[2]));
|
||||
} else if (aSensorData.sensor() == SENSOR_LIGHT) {
|
||||
sensorValues.AppendElement(aEvent.mData.mFloat[0]);
|
||||
} else if (aSensorData.sensor() == SENSOR_ROTATION_VECTOR) {
|
||||
sensorValues.AppendElement(aEvent.mData.mFloat[0]);
|
||||
sensorValues.AppendElement(aEvent.mData.mFloat[1]);
|
||||
sensorValues.AppendElement(aEvent.mData.mFloat[2]);
|
||||
sensorValues.AppendElement(aEvent.mData.mFloat[3]);
|
||||
} else if (aSensorData.sensor() == SENSOR_GAME_ROTATION_VECTOR) {
|
||||
sensorValues.AppendElement(aEvent.mData.mFloat[0]);
|
||||
sensorValues.AppendElement(aEvent.mData.mFloat[1]);
|
||||
sensorValues.AppendElement(aEvent.mData.mFloat[2]);
|
||||
sensorValues.AppendElement(aEvent.mData.mFloat[3]);
|
||||
}
|
||||
|
||||
aSensorData.values() = sensorValues;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
GonkSensorsPollInterface* mPollInterface;
|
||||
nsTArray<SensorsSensor> mSensors;
|
||||
SensorsSensorClass mClasses[SENSORS_NUM_TYPES];
|
||||
};
|
||||
|
||||
static StaticAutoPtr<SensorsPollNotificationHandler> sPollNotificationHandler;
|
||||
|
||||
/**
|
||||
* This is the notifiaction handler for the Sensors interface. If the backend
|
||||
* crashes, we can restart it from here.
|
||||
*/
|
||||
class SensorsNotificationHandler final : public GonkSensorsNotificationHandler
|
||||
{
|
||||
public:
|
||||
SensorsNotificationHandler(GonkSensorsInterface* aInterface)
|
||||
: mInterface(aInterface)
|
||||
{
|
||||
MOZ_ASSERT(mInterface);
|
||||
|
||||
mInterface->SetNotificationHandler(this);
|
||||
}
|
||||
|
||||
void BackendErrorNotification(bool aCrashed) override
|
||||
{
|
||||
// XXX: Bug 1206056: restart sensorsd
|
||||
}
|
||||
|
||||
private:
|
||||
GonkSensorsInterface* mInterface;
|
||||
};
|
||||
|
||||
static StaticAutoPtr<SensorsNotificationHandler> sNotificationHandler;
|
||||
|
||||
/**
|
||||
* |SensorsRegisterModuleResultHandler| implements the result-handler
|
||||
* callback for registering the Poll service and activating the first
|
||||
* sensors. If an error occures during the process, the result handler
|
||||
* disconnects and closes the backend.
|
||||
*/
|
||||
class SensorsRegisterModuleResultHandler final
|
||||
: public GonkSensorsRegistryResultHandler
|
||||
{
|
||||
public:
|
||||
SensorsRegisterModuleResultHandler(
|
||||
uint32_t* aSensorsTypeActivated,
|
||||
GonkSensorsInterface* aInterface)
|
||||
: mSensorsTypeActivated(aSensorsTypeActivated)
|
||||
, mInterface(aInterface)
|
||||
{
|
||||
MOZ_ASSERT(mSensorsTypeActivated);
|
||||
MOZ_ASSERT(mInterface);
|
||||
}
|
||||
void OnError(SensorsError aError) override
|
||||
{
|
||||
GonkSensorsRegistryResultHandler::OnError(aError); // print error message
|
||||
Disconnect(); // Registering failed, so close the connection completely
|
||||
}
|
||||
void RegisterModule(uint32_t aProtocolVersion) override
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!sPollNotificationHandler);
|
||||
|
||||
// Init, step 3: set notification handler for poll service and vice versa
|
||||
auto pollInterface = mInterface->GetSensorsPollInterface();
|
||||
if (!pollInterface) {
|
||||
Disconnect();
|
||||
return;
|
||||
}
|
||||
if (NS_FAILED(pollInterface->SetProtocolVersion(aProtocolVersion))) {
|
||||
Disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
sPollNotificationHandler =
|
||||
new SensorsPollNotificationHandler(pollInterface);
|
||||
|
||||
// Init, step 4: activate sensors
|
||||
for (int i = 0; i < SENSORS_NUM_TYPES; ++i) {
|
||||
while (mSensorsTypeActivated[i]) {
|
||||
sPollNotificationHandler->EnableSensorsByType(
|
||||
static_cast<SensorsType>(i));
|
||||
--mSensorsTypeActivated[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
public:
|
||||
void Disconnect()
|
||||
{
|
||||
class DisconnectResultHandler final : public GonkSensorsResultHandler
|
||||
{
|
||||
public:
|
||||
void OnError(SensorsError aError)
|
||||
{
|
||||
GonkSensorsResultHandler::OnError(aError); // print error message
|
||||
sNotificationHandler = nullptr;
|
||||
}
|
||||
void Disconnect() override
|
||||
{
|
||||
sNotificationHandler = nullptr;
|
||||
}
|
||||
};
|
||||
mInterface->Disconnect(new DisconnectResultHandler());
|
||||
}
|
||||
private:
|
||||
uint32_t* mSensorsTypeActivated;
|
||||
GonkSensorsInterface* mInterface;
|
||||
};
|
||||
|
||||
/**
|
||||
* |SensorsConnectResultHandler| implements the result-handler
|
||||
* callback for starting the Sensors backend.
|
||||
*/
|
||||
class SensorsConnectResultHandler final : public GonkSensorsResultHandler
|
||||
{
|
||||
public:
|
||||
SensorsConnectResultHandler(
|
||||
uint32_t* aSensorsTypeActivated,
|
||||
GonkSensorsInterface* aInterface)
|
||||
: mSensorsTypeActivated(aSensorsTypeActivated)
|
||||
, mInterface(aInterface)
|
||||
{
|
||||
MOZ_ASSERT(mSensorsTypeActivated);
|
||||
MOZ_ASSERT(mInterface);
|
||||
}
|
||||
void OnError(SensorsError aError) override
|
||||
{
|
||||
GonkSensorsResultHandler::OnError(aError); // print error message
|
||||
sNotificationHandler = nullptr;
|
||||
}
|
||||
void Connect() override
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Init, step 2: register poll service
|
||||
auto registryInterface = mInterface->GetSensorsRegistryInterface();
|
||||
if (!registryInterface) {
|
||||
return;
|
||||
}
|
||||
registryInterface->RegisterModule(
|
||||
GonkSensorsPollModule::SERVICE_ID,
|
||||
new SensorsRegisterModuleResultHandler(mSensorsTypeActivated,
|
||||
mInterface));
|
||||
}
|
||||
private:
|
||||
uint32_t* mSensorsTypeActivated;
|
||||
GonkSensorsInterface* mInterface;
|
||||
};
|
||||
|
||||
static uint32_t sSensorsTypeActivated[SENSORS_NUM_TYPES];
|
||||
|
||||
static const SensorsType sSensorsType[] = {
|
||||
[SENSOR_ORIENTATION] = SENSORS_TYPE_ORIENTATION,
|
||||
[SENSOR_ACCELERATION] = SENSORS_TYPE_ACCELEROMETER,
|
||||
[SENSOR_PROXIMITY] = SENSORS_TYPE_PROXIMITY,
|
||||
[SENSOR_LINEAR_ACCELERATION] = SENSORS_TYPE_LINEAR_ACCELERATION,
|
||||
[SENSOR_GYROSCOPE] = SENSORS_TYPE_GYROSCOPE,
|
||||
[SENSOR_LIGHT] = SENSORS_TYPE_LIGHT,
|
||||
[SENSOR_ROTATION_VECTOR] = SENSORS_TYPE_ROTATION_VECTOR,
|
||||
[SENSOR_GAME_ROTATION_VECTOR] = SENSORS_TYPE_GAME_ROTATION_VECTOR
|
||||
};
|
||||
|
||||
void
|
||||
EnableSensorNotificationsDaemon(SensorType aSensor)
|
||||
{
|
||||
if ((aSensor < 0) ||
|
||||
(aSensor > static_cast<ssize_t>(MOZ_ARRAY_LENGTH(sSensorsType)))) {
|
||||
HAL_ERR("Sensor type %d not known", aSensor);
|
||||
return; // Unsupported sensor type
|
||||
}
|
||||
|
||||
auto interface = GonkSensorsInterface::GetInstance();
|
||||
if (!interface) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sPollNotificationHandler) {
|
||||
// Everythings already up and running; enable sensor type.
|
||||
sPollNotificationHandler->EnableSensorsByType(sSensorsType[aSensor]);
|
||||
return;
|
||||
}
|
||||
|
||||
++SaturateOpUint32(sSensorsTypeActivated[sSensorsType[aSensor]]);
|
||||
|
||||
if (sNotificationHandler) {
|
||||
// We are in the middle of a pending start up; nothing else to do.
|
||||
return;
|
||||
}
|
||||
|
||||
// Start up
|
||||
|
||||
MOZ_ASSERT(!sPollNotificationHandler);
|
||||
MOZ_ASSERT(!sNotificationHandler);
|
||||
|
||||
sNotificationHandler = new SensorsNotificationHandler(interface);
|
||||
|
||||
// Init, step 1: connect to Sensors backend
|
||||
interface->Connect(
|
||||
sNotificationHandler,
|
||||
new SensorsConnectResultHandler(sSensorsTypeActivated, interface));
|
||||
}
|
||||
|
||||
void
|
||||
DisableSensorNotificationsDaemon(SensorType aSensor)
|
||||
{
|
||||
if ((aSensor < 0) ||
|
||||
(aSensor > static_cast<ssize_t>(MOZ_ARRAY_LENGTH(sSensorsType)))) {
|
||||
HAL_ERR("Sensor type %d not known", aSensor);
|
||||
return; // Unsupported sensor type
|
||||
}
|
||||
|
||||
if (sPollNotificationHandler) {
|
||||
// Everthings up and running; disable sensors type
|
||||
sPollNotificationHandler->DisableSensorsByType(sSensorsType[aSensor]);
|
||||
return;
|
||||
}
|
||||
|
||||
// We might be in the middle of a startup; decrement type's ref-counter.
|
||||
--SaturateOpUint32(sSensorsTypeActivated[sSensorsType[aSensor]]);
|
||||
|
||||
// TODO: stop sensorsd if all sensors are disabled
|
||||
}
|
||||
|
||||
//
|
||||
// Public interface
|
||||
//
|
||||
|
||||
// TODO: Remove in-Gecko sensors code. Until all devices' base
|
||||
// images come with sensorsd installed, we have to support the
|
||||
// in-Gecko implementation as well. So we test for the existance
|
||||
// of the binary. If it's there, we use it. Otherwise we run the
|
||||
// old code.
|
||||
static bool
|
||||
HasDaemon()
|
||||
{
|
||||
static bool tested;
|
||||
static bool hasDaemon;
|
||||
|
||||
if (MOZ_UNLIKELY(!tested)) {
|
||||
hasDaemon = !access("/system/bin/sensorsd", X_OK);
|
||||
tested = true;
|
||||
}
|
||||
|
||||
return hasDaemon;
|
||||
}
|
||||
|
||||
void
|
||||
EnableSensorNotifications(SensorType aSensor)
|
||||
{
|
||||
if (HasDaemon()) {
|
||||
EnableSensorNotificationsDaemon(aSensor);
|
||||
} else {
|
||||
EnableSensorNotificationsInternal(aSensor);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DisableSensorNotifications(SensorType aSensor)
|
||||
{
|
||||
if (HasDaemon()) {
|
||||
DisableSensorNotificationsDaemon(aSensor);
|
||||
} else {
|
||||
DisableSensorNotificationsInternal(aSensor);
|
||||
}
|
||||
}
|
||||
|
||||
} // hal_impl
|
||||
} // mozilla
|
||||
112
hal/gonk/GonkSensorsHelpers.cpp
Normal file
112
hal/gonk/GonkSensorsHelpers.cpp
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "GonkSensorsHelpers.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal {
|
||||
|
||||
//
|
||||
// Unpacking
|
||||
//
|
||||
|
||||
nsresult
|
||||
UnpackPDU(DaemonSocketPDU& aPDU, SensorsEvent& aOut)
|
||||
{
|
||||
nsresult rv = UnpackPDU(aPDU, aOut.mType);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
rv = UnpackPDU(aPDU, aOut.mTimestamp);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
rv = UnpackPDU(aPDU, aOut.mStatus);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
|
||||
switch (aOut.mType) {
|
||||
case SENSORS_TYPE_MAGNETIC_FIELD_UNCALIBRATED:
|
||||
case SENSORS_TYPE_GYROSCOPE_UNCALIBRATED:
|
||||
/* 6 data values */
|
||||
rv = UnpackPDU(aPDU, aOut.mData.mFloat[i++]);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
/* fall through */
|
||||
case SENSORS_TYPE_ROTATION_VECTOR:
|
||||
case SENSORS_TYPE_GAME_ROTATION_VECTOR:
|
||||
case SENSORS_TYPE_GEOMAGNETIC_ROTATION_VECTOR:
|
||||
/* 5 data values */
|
||||
rv = UnpackPDU(aPDU, aOut.mData.mFloat[i++]);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
rv = UnpackPDU(aPDU, aOut.mData.mFloat[i++]);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
/* fall through */
|
||||
case SENSORS_TYPE_ACCELEROMETER:
|
||||
case SENSORS_TYPE_GEOMAGNETIC_FIELD:
|
||||
case SENSORS_TYPE_ORIENTATION:
|
||||
case SENSORS_TYPE_GYROSCOPE:
|
||||
case SENSORS_TYPE_GRAVITY:
|
||||
case SENSORS_TYPE_LINEAR_ACCELERATION:
|
||||
/* 3 data values */
|
||||
rv = UnpackPDU(aPDU, aOut.mData.mFloat[i++]);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
rv = UnpackPDU(aPDU, aOut.mData.mFloat[i++]);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
/* fall through */
|
||||
case SENSORS_TYPE_LIGHT:
|
||||
case SENSORS_TYPE_PRESSURE:
|
||||
case SENSORS_TYPE_TEMPERATURE:
|
||||
case SENSORS_TYPE_PROXIMITY:
|
||||
case SENSORS_TYPE_RELATIVE_HUMIDITY:
|
||||
case SENSORS_TYPE_AMBIENT_TEMPERATURE:
|
||||
case SENSORS_TYPE_HEART_RATE:
|
||||
case SENSORS_TYPE_TILT_DETECTOR:
|
||||
case SENSORS_TYPE_WAKE_GESTURE:
|
||||
case SENSORS_TYPE_GLANCE_GESTURE:
|
||||
case SENSORS_TYPE_PICK_UP_GESTURE:
|
||||
case SENSORS_TYPE_WRIST_TILT_GESTURE:
|
||||
case SENSORS_TYPE_SIGNIFICANT_MOTION:
|
||||
case SENSORS_TYPE_STEP_DETECTED:
|
||||
/* 1 data value */
|
||||
rv = UnpackPDU(aPDU, aOut.mData.mFloat[i++]);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
break;
|
||||
case SENSORS_TYPE_STEP_COUNTER:
|
||||
/* 1 data value */
|
||||
rv = UnpackPDU(aPDU, aOut.mData.mUint[0]);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (MOZ_HAL_IPC_UNPACK_WARN_IF(true, SensorsEvent)) {
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
}
|
||||
rv = UnpackPDU(aPDU, aOut.mDeliveryMode);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace hal
|
||||
} // namespace mozilla
|
||||
226
hal/gonk/GonkSensorsHelpers.h
Normal file
226
hal/gonk/GonkSensorsHelpers.h
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef hal_gonk_GonkSensorsHelpers_h
|
||||
#define hal_gonk_GonkSensorsHelpers_h
|
||||
|
||||
#include <mozilla/ipc/DaemonSocketPDU.h>
|
||||
#include <mozilla/ipc/DaemonSocketPDUHelpers.h>
|
||||
#include "SensorsTypes.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal {
|
||||
|
||||
using mozilla::ipc::DaemonSocketPDU;
|
||||
using mozilla::ipc::DaemonSocketPDUHeader;
|
||||
using mozilla::ipc::DaemonSocketPDUHelpers::Convert;
|
||||
using mozilla::ipc::DaemonSocketPDUHelpers::PackPDU;
|
||||
using mozilla::ipc::DaemonSocketPDUHelpers::UnpackPDU;
|
||||
|
||||
using namespace mozilla::ipc::DaemonSocketPDUHelpers;
|
||||
|
||||
//
|
||||
// Conversion
|
||||
//
|
||||
// The functions below convert the input value to the output value's
|
||||
// type and perform extension tests on the validity of the result. On
|
||||
// success the output value will be returned in |aOut|. The functions
|
||||
// return NS_OK on success, or an XPCOM error code otherwise.
|
||||
//
|
||||
// See the documentation of the HAL IPC framework for more information
|
||||
// on conversion functions.
|
||||
//
|
||||
|
||||
nsresult
|
||||
Convert(int32_t aIn, SensorsStatus& aOut)
|
||||
{
|
||||
static const uint8_t sStatus[] = {
|
||||
[0] = SENSORS_STATUS_NO_CONTACT, // '-1'
|
||||
[1] = SENSORS_STATUS_UNRELIABLE, // '0'
|
||||
[2] = SENSORS_STATUS_ACCURACY_LOW, // '1'
|
||||
[3] = SENSORS_STATUS_ACCURACY_MEDIUM, // '2'
|
||||
[4] = SENSORS_STATUS_ACCURACY_HIGH // '3'
|
||||
};
|
||||
static const int8_t sOffset = -1; // '-1' is the lower bound of the status
|
||||
|
||||
if (MOZ_HAL_IPC_CONVERT_WARN_IF(aIn < sOffset, int32_t, SensorsStatus) ||
|
||||
MOZ_HAL_IPC_CONVERT_WARN_IF(
|
||||
aIn >= (static_cast<ssize_t>(MOZ_ARRAY_LENGTH(sStatus)) + sOffset),
|
||||
int32_t, SensorsStatus)) {
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
aOut = static_cast<SensorsStatus>(sStatus[aIn - sOffset]);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Convert(uint8_t aIn, SensorsDeliveryMode& aOut)
|
||||
{
|
||||
static const uint8_t sMode[] = {
|
||||
[0x00] = SENSORS_DELIVERY_MODE_BEST_EFFORT,
|
||||
[0x01] = SENSORS_DELIVERY_MODE_IMMEDIATE
|
||||
};
|
||||
if (MOZ_HAL_IPC_CONVERT_WARN_IF(
|
||||
aIn >= MOZ_ARRAY_LENGTH(sMode), uint8_t, SensorsDeliveryMode)) {
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
aOut = static_cast<SensorsDeliveryMode>(sMode[aIn]);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Convert(uint8_t aIn, SensorsError& aOut)
|
||||
{
|
||||
static const uint8_t sError[] = {
|
||||
[0x00] = SENSORS_ERROR_NONE,
|
||||
[0x01] = SENSORS_ERROR_FAIL,
|
||||
[0x02] = SENSORS_ERROR_NOT_READY,
|
||||
[0x03] = SENSORS_ERROR_NOMEM,
|
||||
[0x04] = SENSORS_ERROR_BUSY,
|
||||
[0x05] = SENSORS_ERROR_DONE,
|
||||
[0x06] = SENSORS_ERROR_UNSUPPORTED,
|
||||
[0x07] = SENSORS_ERROR_PARM_INVALID
|
||||
};
|
||||
if (MOZ_HAL_IPC_CONVERT_WARN_IF(
|
||||
aIn >= MOZ_ARRAY_LENGTH(sError), uint8_t, SensorsError)) {
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
aOut = static_cast<SensorsError>(sError[aIn]);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Convert(uint8_t aIn, SensorsTriggerMode& aOut)
|
||||
{
|
||||
static const uint8_t sMode[] = {
|
||||
[0x00] = SENSORS_TRIGGER_MODE_CONTINUOUS,
|
||||
[0x01] = SENSORS_TRIGGER_MODE_ON_CHANGE,
|
||||
[0x02] = SENSORS_TRIGGER_MODE_ONE_SHOT,
|
||||
[0x03] = SENSORS_TRIGGER_MODE_SPECIAL
|
||||
};
|
||||
if (MOZ_HAL_IPC_CONVERT_WARN_IF(
|
||||
aIn >= MOZ_ARRAY_LENGTH(sMode), uint8_t, SensorsTriggerMode)) {
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
aOut = static_cast<SensorsTriggerMode>(sMode[aIn]);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Convert(uint32_t aIn, SensorsType& aOut)
|
||||
{
|
||||
static const uint8_t sType[] = {
|
||||
[0x00] = 0, // invalid, required by gcc
|
||||
[0x01] = SENSORS_TYPE_ACCELEROMETER,
|
||||
[0x02] = SENSORS_TYPE_GEOMAGNETIC_FIELD,
|
||||
[0x03] = SENSORS_TYPE_ORIENTATION,
|
||||
[0x04] = SENSORS_TYPE_GYROSCOPE,
|
||||
[0x05] = SENSORS_TYPE_LIGHT,
|
||||
[0x06] = SENSORS_TYPE_PRESSURE,
|
||||
[0x07] = SENSORS_TYPE_TEMPERATURE,
|
||||
[0x08] = SENSORS_TYPE_PROXIMITY,
|
||||
[0x09] = SENSORS_TYPE_GRAVITY,
|
||||
[0x0a] = SENSORS_TYPE_LINEAR_ACCELERATION,
|
||||
[0x0b] = SENSORS_TYPE_ROTATION_VECTOR,
|
||||
[0x0c] = SENSORS_TYPE_RELATIVE_HUMIDITY,
|
||||
[0x0d] = SENSORS_TYPE_AMBIENT_TEMPERATURE,
|
||||
[0x0e] = SENSORS_TYPE_MAGNETIC_FIELD_UNCALIBRATED,
|
||||
[0x0f] = SENSORS_TYPE_GAME_ROTATION_VECTOR,
|
||||
[0x10] = SENSORS_TYPE_GYROSCOPE_UNCALIBRATED,
|
||||
[0x11] = SENSORS_TYPE_SIGNIFICANT_MOTION,
|
||||
[0x12] = SENSORS_TYPE_STEP_DETECTED,
|
||||
[0x13] = SENSORS_TYPE_STEP_COUNTER,
|
||||
[0x14] = SENSORS_TYPE_GEOMAGNETIC_ROTATION_VECTOR,
|
||||
[0x15] = SENSORS_TYPE_HEART_RATE,
|
||||
[0x16] = SENSORS_TYPE_TILT_DETECTOR,
|
||||
[0x17] = SENSORS_TYPE_WAKE_GESTURE,
|
||||
[0x18] = SENSORS_TYPE_GLANCE_GESTURE,
|
||||
[0x19] = SENSORS_TYPE_PICK_UP_GESTURE,
|
||||
[0x1a] = SENSORS_TYPE_WRIST_TILT_GESTURE
|
||||
};
|
||||
if (MOZ_HAL_IPC_CONVERT_WARN_IF(
|
||||
!aIn, uint32_t, SensorsType) ||
|
||||
MOZ_HAL_IPC_CONVERT_WARN_IF(
|
||||
aIn >= MOZ_ARRAY_LENGTH(sType), uint32_t, SensorsType)) {
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
aOut = static_cast<SensorsType>(sType[aIn]);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Convert(nsresult aIn, SensorsError& aOut)
|
||||
{
|
||||
if (NS_SUCCEEDED(aIn)) {
|
||||
aOut = SENSORS_ERROR_NONE;
|
||||
} else if (aIn == NS_ERROR_OUT_OF_MEMORY) {
|
||||
aOut = SENSORS_ERROR_NOMEM;
|
||||
} else if (aIn == NS_ERROR_ILLEGAL_VALUE) {
|
||||
aOut = SENSORS_ERROR_PARM_INVALID;
|
||||
} else {
|
||||
aOut = SENSORS_ERROR_FAIL;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//
|
||||
// Packing
|
||||
//
|
||||
// Pack functions store a value in PDU. See the documentation of the
|
||||
// HAL IPC framework for more information.
|
||||
//
|
||||
// There are currently no sensor-specific pack functions necessary. If
|
||||
// you add one, put it below.
|
||||
//
|
||||
|
||||
//
|
||||
// Unpacking
|
||||
//
|
||||
// Unpack function retrieve a value from a PDU. The functions return
|
||||
// NS_OK on success, or an XPCOM error code otherwise. On sucess, the
|
||||
// returned value is stored in the second argument |aOut|.
|
||||
//
|
||||
// See the documentation of the HAL IPC framework for more information
|
||||
// on unpack functions.
|
||||
//
|
||||
|
||||
nsresult
|
||||
UnpackPDU(DaemonSocketPDU& aPDU, SensorsDeliveryMode& aOut)
|
||||
{
|
||||
return UnpackPDU(aPDU, UnpackConversion<uint8_t, SensorsDeliveryMode>(aOut));
|
||||
}
|
||||
|
||||
nsresult
|
||||
UnpackPDU(DaemonSocketPDU& aPDU, SensorsError& aOut)
|
||||
{
|
||||
return UnpackPDU(aPDU, UnpackConversion<uint8_t, SensorsError>(aOut));
|
||||
}
|
||||
|
||||
nsresult
|
||||
UnpackPDU(DaemonSocketPDU& aPDU, SensorsEvent& aOut);
|
||||
|
||||
nsresult
|
||||
UnpackPDU(DaemonSocketPDU& aPDU, SensorsStatus& aOut)
|
||||
{
|
||||
return UnpackPDU(aPDU, UnpackConversion<int32_t, SensorsStatus>(aOut));
|
||||
}
|
||||
|
||||
nsresult
|
||||
UnpackPDU(DaemonSocketPDU& aPDU, SensorsTriggerMode& aOut)
|
||||
{
|
||||
return UnpackPDU(aPDU, UnpackConversion<uint8_t, SensorsTriggerMode>(aOut));
|
||||
}
|
||||
|
||||
nsresult
|
||||
UnpackPDU(DaemonSocketPDU& aPDU, SensorsType& aOut)
|
||||
{
|
||||
return UnpackPDU(aPDU, UnpackConversion<uint32_t, SensorsType>(aOut));
|
||||
}
|
||||
|
||||
} // namespace hal
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // hal_gonk_GonkSensorsHelpers_h
|
||||
494
hal/gonk/GonkSensorsInterface.cpp
Normal file
494
hal/gonk/GonkSensorsInterface.cpp
Normal file
|
|
@ -0,0 +1,494 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "GonkSensorsInterface.h"
|
||||
#include "GonkSensorsPollInterface.h"
|
||||
#include "GonkSensorsRegistryInterface.h"
|
||||
#include "HalLog.h"
|
||||
#include <mozilla/ipc/DaemonSocket.h>
|
||||
#include <mozilla/ipc/DaemonSocketConnector.h>
|
||||
#include <mozilla/ipc/ListenSocket.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal {
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
//
|
||||
// GonkSensorsResultHandler
|
||||
//
|
||||
|
||||
void
|
||||
GonkSensorsResultHandler::OnError(SensorsError aError)
|
||||
{
|
||||
HAL_ERR("Received error code %d", static_cast<int>(aError));
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsResultHandler::Connect()
|
||||
{ }
|
||||
|
||||
void
|
||||
GonkSensorsResultHandler::Disconnect()
|
||||
{ }
|
||||
|
||||
GonkSensorsResultHandler::~GonkSensorsResultHandler()
|
||||
{ }
|
||||
|
||||
//
|
||||
// GonkSensorsNotificationHandler
|
||||
//
|
||||
|
||||
void
|
||||
GonkSensorsNotificationHandler::BackendErrorNotification(bool aCrashed)
|
||||
{
|
||||
if (aCrashed) {
|
||||
HAL_ERR("Sensors backend crashed");
|
||||
} else {
|
||||
HAL_ERR("Error in sensors backend");
|
||||
}
|
||||
}
|
||||
|
||||
GonkSensorsNotificationHandler::~GonkSensorsNotificationHandler()
|
||||
{ }
|
||||
|
||||
//
|
||||
// GonkSensorsProtocol
|
||||
//
|
||||
|
||||
class GonkSensorsProtocol final
|
||||
: public DaemonSocketIOConsumer
|
||||
, public GonkSensorsRegistryModule
|
||||
, public GonkSensorsPollModule
|
||||
{
|
||||
public:
|
||||
GonkSensorsProtocol();
|
||||
|
||||
void SetConnection(DaemonSocket* aConnection);
|
||||
|
||||
already_AddRefed<DaemonSocketResultHandler> FetchResultHandler(
|
||||
const DaemonSocketPDUHeader& aHeader);
|
||||
|
||||
// Methods for |SensorsRegistryModule| and |SensorsPollModule|
|
||||
//
|
||||
|
||||
nsresult Send(DaemonSocketPDU* aPDU,
|
||||
DaemonSocketResultHandler* aRes) override;
|
||||
|
||||
// Methods for |DaemonSocketIOConsumer|
|
||||
//
|
||||
|
||||
void Handle(DaemonSocketPDU& aPDU) override;
|
||||
void StoreResultHandler(const DaemonSocketPDU& aPDU) override;
|
||||
|
||||
private:
|
||||
void HandleRegistrySvc(const DaemonSocketPDUHeader& aHeader,
|
||||
DaemonSocketPDU& aPDU,
|
||||
DaemonSocketResultHandler* aRes);
|
||||
void HandlePollSvc(const DaemonSocketPDUHeader& aHeader,
|
||||
DaemonSocketPDU& aPDU,
|
||||
DaemonSocketResultHandler* aRes);
|
||||
|
||||
DaemonSocket* mConnection;
|
||||
nsTArray<RefPtr<DaemonSocketResultHandler>> mResultHandlerQ;
|
||||
};
|
||||
|
||||
GonkSensorsProtocol::GonkSensorsProtocol()
|
||||
{ }
|
||||
|
||||
void
|
||||
GonkSensorsProtocol::SetConnection(DaemonSocket* aConnection)
|
||||
{
|
||||
mConnection = aConnection;
|
||||
}
|
||||
|
||||
already_AddRefed<DaemonSocketResultHandler>
|
||||
GonkSensorsProtocol::FetchResultHandler(const DaemonSocketPDUHeader& aHeader)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
if (aHeader.mOpcode & 0x80) {
|
||||
return nullptr; // Ignore notifications
|
||||
}
|
||||
|
||||
RefPtr<DaemonSocketResultHandler> res = mResultHandlerQ.ElementAt(0);
|
||||
mResultHandlerQ.RemoveElementAt(0);
|
||||
|
||||
return res.forget();
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsProtocol::HandleRegistrySvc(
|
||||
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
|
||||
DaemonSocketResultHandler* aRes)
|
||||
{
|
||||
GonkSensorsRegistryModule::HandleSvc(aHeader, aPDU, aRes);
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsProtocol::HandlePollSvc(
|
||||
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
|
||||
DaemonSocketResultHandler* aRes)
|
||||
{
|
||||
GonkSensorsPollModule::HandleSvc(aHeader, aPDU, aRes);
|
||||
}
|
||||
|
||||
// |SensorsRegistryModule|, |SensorsPollModule|
|
||||
|
||||
nsresult
|
||||
GonkSensorsProtocol::Send(DaemonSocketPDU* aPDU,
|
||||
DaemonSocketResultHandler* aRes)
|
||||
{
|
||||
MOZ_ASSERT(mConnection);
|
||||
MOZ_ASSERT(aPDU);
|
||||
|
||||
aPDU->SetConsumer(this);
|
||||
aPDU->SetResultHandler(aRes);
|
||||
aPDU->UpdateHeader();
|
||||
|
||||
if (mConnection->GetConnectionStatus() == SOCKET_DISCONNECTED) {
|
||||
HAL_ERR("Sensors socket is disconnected");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mConnection->SendSocketData(aPDU); // Forward PDU to data channel
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// |DaemonSocketIOConsumer|
|
||||
|
||||
void
|
||||
GonkSensorsProtocol::Handle(DaemonSocketPDU& aPDU)
|
||||
{
|
||||
static void (GonkSensorsProtocol::* const HandleSvc[])(
|
||||
const DaemonSocketPDUHeader&, DaemonSocketPDU&,
|
||||
DaemonSocketResultHandler*) = {
|
||||
[GonkSensorsRegistryModule::SERVICE_ID] =
|
||||
&GonkSensorsProtocol::HandleRegistrySvc,
|
||||
[GonkSensorsPollModule::SERVICE_ID] =
|
||||
&GonkSensorsProtocol::HandlePollSvc
|
||||
};
|
||||
|
||||
DaemonSocketPDUHeader header;
|
||||
|
||||
if (NS_FAILED(UnpackPDU(aPDU, header))) {
|
||||
return;
|
||||
}
|
||||
if (!(header.mService < MOZ_ARRAY_LENGTH(HandleSvc)) ||
|
||||
!HandleSvc[header.mService]) {
|
||||
HAL_ERR("Sensors service %d unknown", header.mService);
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<DaemonSocketResultHandler> res = FetchResultHandler(header);
|
||||
|
||||
(this->*(HandleSvc[header.mService]))(header, aPDU, res);
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsProtocol::StoreResultHandler(const DaemonSocketPDU& aPDU)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
mResultHandlerQ.AppendElement(aPDU.GetResultHandler());
|
||||
}
|
||||
|
||||
//
|
||||
// GonkSensorsInterface
|
||||
//
|
||||
|
||||
GonkSensorsInterface*
|
||||
GonkSensorsInterface::GetInstance()
|
||||
{
|
||||
static GonkSensorsInterface* sGonkSensorsInterface;
|
||||
|
||||
if (sGonkSensorsInterface) {
|
||||
return sGonkSensorsInterface;
|
||||
}
|
||||
|
||||
sGonkSensorsInterface = new GonkSensorsInterface();
|
||||
|
||||
return sGonkSensorsInterface;
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsInterface::SetNotificationHandler(
|
||||
GonkSensorsNotificationHandler* aNotificationHandler)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mNotificationHandler = aNotificationHandler;
|
||||
}
|
||||
|
||||
/*
|
||||
* The connect procedure consists of several steps.
|
||||
*
|
||||
* (1) Start listening for the command channel's socket connection: We
|
||||
* do this before anything else, so that we don't miss connection
|
||||
* requests from the Sensors daemon. This step will create a listen
|
||||
* socket.
|
||||
*
|
||||
* (2) Start the Sensors daemon: When the daemon starts up it will open
|
||||
* a socket connection to Gecko and thus create the data channel.
|
||||
* Gecko already opened the listen socket in step (1). Step (2) ends
|
||||
* with the creation of the data channel.
|
||||
*
|
||||
* (3) Signal success to the caller.
|
||||
*
|
||||
* If any step fails, we roll-back the procedure and signal an error to the
|
||||
* caller.
|
||||
*/
|
||||
void
|
||||
GonkSensorsInterface::Connect(GonkSensorsNotificationHandler* aNotificationHandler,
|
||||
GonkSensorsResultHandler* aRes)
|
||||
{
|
||||
#define BASE_SOCKET_NAME "sensorsd"
|
||||
static unsigned long POSTFIX_LENGTH = 16;
|
||||
|
||||
// If we could not cleanup properly before and an old
|
||||
// instance of the daemon is still running, we kill it
|
||||
// here.
|
||||
mozilla::hal::StopSystemService("sensorsd");
|
||||
|
||||
mNotificationHandler = aNotificationHandler;
|
||||
|
||||
mResultHandlerQ.AppendElement(aRes);
|
||||
|
||||
if (!mProtocol) {
|
||||
mProtocol = MakeUnique<GonkSensorsProtocol>();
|
||||
}
|
||||
|
||||
if (!mListenSocket) {
|
||||
mListenSocket = new ListenSocket(this, LISTEN_SOCKET);
|
||||
}
|
||||
|
||||
// Init, step 1: Listen for data channel... */
|
||||
|
||||
if (!mDataSocket) {
|
||||
mDataSocket = new DaemonSocket(mProtocol.get(), this, DATA_SOCKET);
|
||||
} else if (mDataSocket->GetConnectionStatus() == SOCKET_CONNECTED) {
|
||||
// Command channel should not be open; let's close it.
|
||||
mDataSocket->Close();
|
||||
}
|
||||
|
||||
// The listen socket's name is generated with a random postfix. This
|
||||
// avoids naming collisions if we still have a listen socket from a
|
||||
// previously failed cleanup. It also makes it hard for malicious
|
||||
// external programs to capture the socket name or connect before
|
||||
// the daemon can do so. If no random postfix can be generated, we
|
||||
// simply use the base name as-is.
|
||||
nsresult rv = DaemonSocketConnector::CreateRandomAddressString(
|
||||
NS_LITERAL_CSTRING(BASE_SOCKET_NAME), POSTFIX_LENGTH, mListenSocketName);
|
||||
if (NS_FAILED(rv)) {
|
||||
mListenSocketName.AssignLiteral(BASE_SOCKET_NAME);
|
||||
}
|
||||
|
||||
rv = mListenSocket->Listen(new DaemonSocketConnector(mListenSocketName),
|
||||
mDataSocket);
|
||||
if (NS_FAILED(rv)) {
|
||||
OnConnectError(DATA_SOCKET);
|
||||
return;
|
||||
}
|
||||
|
||||
// The protocol implementation needs a data channel for
|
||||
// sending commands to the daemon. We set it here, because
|
||||
// this is the earliest time when it's available.
|
||||
mProtocol->SetConnection(mDataSocket);
|
||||
}
|
||||
|
||||
/*
|
||||
* Disconnecting is inverse to connecting.
|
||||
*
|
||||
* (1) Close data socket: We close the data channel and the daemon will
|
||||
* will notice. Once we see the socket's disconnect, we continue with
|
||||
* the cleanup.
|
||||
*
|
||||
* (2) Close listen socket: The listen socket is not active any longer
|
||||
* and we simply close it.
|
||||
*
|
||||
* (3) Signal success to the caller.
|
||||
*
|
||||
* We don't have to stop the daemon explicitly. It will cleanup and quit
|
||||
* after it noticed the closing of the data channel
|
||||
*
|
||||
* Rolling back half-completed cleanups is not possible. In the case of
|
||||
* an error, we simply push forward and try to recover during the next
|
||||
* initialization.
|
||||
*/
|
||||
void
|
||||
GonkSensorsInterface::Disconnect(GonkSensorsResultHandler* aRes)
|
||||
{
|
||||
mNotificationHandler = nullptr;
|
||||
|
||||
// Cleanup, step 1: Close data channel
|
||||
mDataSocket->Close();
|
||||
|
||||
mResultHandlerQ.AppendElement(aRes);
|
||||
}
|
||||
|
||||
GonkSensorsRegistryInterface*
|
||||
GonkSensorsInterface::GetSensorsRegistryInterface()
|
||||
{
|
||||
if (mRegistryInterface) {
|
||||
return mRegistryInterface.get();
|
||||
}
|
||||
|
||||
mRegistryInterface = MakeUnique<GonkSensorsRegistryInterface>(mProtocol.get());
|
||||
|
||||
return mRegistryInterface.get();
|
||||
}
|
||||
|
||||
GonkSensorsPollInterface*
|
||||
GonkSensorsInterface::GetSensorsPollInterface()
|
||||
{
|
||||
if (mPollInterface) {
|
||||
return mPollInterface.get();
|
||||
}
|
||||
|
||||
mPollInterface = MakeUnique<GonkSensorsPollInterface>(mProtocol.get());
|
||||
|
||||
return mPollInterface.get();
|
||||
}
|
||||
|
||||
GonkSensorsInterface::GonkSensorsInterface()
|
||||
: mNotificationHandler(nullptr)
|
||||
{ }
|
||||
|
||||
GonkSensorsInterface::~GonkSensorsInterface()
|
||||
{ }
|
||||
|
||||
void
|
||||
GonkSensorsInterface::DispatchError(GonkSensorsResultHandler* aRes,
|
||||
SensorsError aError)
|
||||
{
|
||||
DaemonResultRunnable1<GonkSensorsResultHandler, void,
|
||||
SensorsError, SensorsError>::Dispatch(
|
||||
aRes, &GonkSensorsResultHandler::OnError,
|
||||
ConstantInitOp1<SensorsError>(aError));
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsInterface::DispatchError(
|
||||
GonkSensorsResultHandler* aRes, nsresult aRv)
|
||||
{
|
||||
SensorsError error;
|
||||
|
||||
if (NS_FAILED(Convert(aRv, error))) {
|
||||
error = SENSORS_ERROR_FAIL;
|
||||
}
|
||||
DispatchError(aRes, error);
|
||||
}
|
||||
|
||||
// |DaemonSocketConsumer|, |ListenSocketConsumer|
|
||||
|
||||
void
|
||||
GonkSensorsInterface::OnConnectSuccess(int aIndex)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mResultHandlerQ.IsEmpty());
|
||||
|
||||
switch (aIndex) {
|
||||
case LISTEN_SOCKET: {
|
||||
// Init, step 2: Start Sensors daemon
|
||||
nsCString args("-a ");
|
||||
args.Append(mListenSocketName);
|
||||
mozilla::hal::StartSystemService("sensorsd", args.get());
|
||||
}
|
||||
break;
|
||||
case DATA_SOCKET:
|
||||
if (!mResultHandlerQ.IsEmpty()) {
|
||||
// Init, step 3: Signal success
|
||||
RefPtr<GonkSensorsResultHandler> res = mResultHandlerQ.ElementAt(0);
|
||||
mResultHandlerQ.RemoveElementAt(0);
|
||||
if (res) {
|
||||
res->Connect();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsInterface::OnConnectError(int aIndex)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(!mResultHandlerQ.IsEmpty());
|
||||
|
||||
switch (aIndex) {
|
||||
case DATA_SOCKET:
|
||||
// Stop daemon and close listen socket
|
||||
mozilla::hal::StopSystemService("sensorsd");
|
||||
mListenSocket->Close();
|
||||
// fall through
|
||||
case LISTEN_SOCKET:
|
||||
if (!mResultHandlerQ.IsEmpty()) {
|
||||
// Signal error to caller
|
||||
RefPtr<GonkSensorsResultHandler> res = mResultHandlerQ.ElementAt(0);
|
||||
mResultHandlerQ.RemoveElementAt(0);
|
||||
if (res) {
|
||||
DispatchError(res, SENSORS_ERROR_FAIL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Disconnects can happend
|
||||
*
|
||||
* (a) during startup,
|
||||
* (b) during regular service, or
|
||||
* (c) during shutdown.
|
||||
*
|
||||
* For cases (a) and (c), |mResultHandlerQ| contains an element. For
|
||||
* case (b) |mResultHandlerQ| will be empty. This distinguishes a crash in
|
||||
* the daemon. The following procedure to recover from crashes consists of
|
||||
* several steps for case (b).
|
||||
*
|
||||
* (1) Close listen socket.
|
||||
* (2) Wait for all sockets to be disconnected and inform caller about
|
||||
* the crash.
|
||||
* (3) After all resources have been cleaned up, let the caller restart
|
||||
* the daemon.
|
||||
*/
|
||||
void
|
||||
GonkSensorsInterface::OnDisconnect(int aIndex)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
switch (aIndex) {
|
||||
case DATA_SOCKET:
|
||||
// Cleanup, step 2 (Recovery, step 1): Close listen socket
|
||||
mListenSocket->Close();
|
||||
break;
|
||||
case LISTEN_SOCKET:
|
||||
// Cleanup, step 3: Signal success to caller
|
||||
if (!mResultHandlerQ.IsEmpty()) {
|
||||
RefPtr<GonkSensorsResultHandler> res = mResultHandlerQ.ElementAt(0);
|
||||
mResultHandlerQ.RemoveElementAt(0);
|
||||
if (res) {
|
||||
res->Disconnect();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* For recovery make sure all sockets disconnected, in order to avoid
|
||||
* the remaining disconnects interfere with the restart procedure.
|
||||
*/
|
||||
if (mNotificationHandler && mResultHandlerQ.IsEmpty()) {
|
||||
if (mListenSocket->GetConnectionStatus() == SOCKET_DISCONNECTED &&
|
||||
mDataSocket->GetConnectionStatus() == SOCKET_DISCONNECTED) {
|
||||
// Recovery, step 2: Notify the caller to prepare the restart procedure.
|
||||
mNotificationHandler->BackendErrorNotification(true);
|
||||
mNotificationHandler = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace hal
|
||||
} // namespace mozilla
|
||||
191
hal/gonk/GonkSensorsInterface.h
Normal file
191
hal/gonk/GonkSensorsInterface.h
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
/*
|
||||
* The sensors interface gives you access to the low-level sensors code
|
||||
* in a platform-independent manner. The interfaces in this file allow
|
||||
* for starting an stopping the sensors driver. Specific functionality
|
||||
* is implemented in sub-interfaces.
|
||||
*/
|
||||
|
||||
#ifndef hal_gonk_GonkSensorsInterface_h
|
||||
#define hal_gonk_GonkSensorsInterface_h
|
||||
|
||||
#include <mozilla/ipc/DaemonSocketConsumer.h>
|
||||
#include <mozilla/ipc/DaemonSocketMessageHandlers.h>
|
||||
#include <mozilla/ipc/ListenSocketConsumer.h>
|
||||
#include <mozilla/UniquePtr.h>
|
||||
#include "SensorsTypes.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class DaemonSocket;
|
||||
class ListenSocket;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal {
|
||||
|
||||
class GonkSensorsPollInterface;
|
||||
class GonkSensorsProtocol;
|
||||
class GonkSensorsRegistryInterface;
|
||||
|
||||
/**
|
||||
* This class is the result-handler interface for the Sensors
|
||||
* interface. Methods always run on the main thread.
|
||||
*/
|
||||
class GonkSensorsResultHandler
|
||||
: public mozilla::ipc::DaemonSocketResultHandler
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Called if a command failed.
|
||||
*
|
||||
* @param aError The error code.
|
||||
*/
|
||||
virtual void OnError(SensorsError aError);
|
||||
|
||||
/**
|
||||
* The callback method for |GonkSensorsInterface::Connect|.
|
||||
*/
|
||||
virtual void Connect();
|
||||
|
||||
/**
|
||||
* The callback method for |GonkSensorsInterface::Connect|.
|
||||
*/
|
||||
virtual void Disconnect();
|
||||
|
||||
protected:
|
||||
virtual ~GonkSensorsResultHandler();
|
||||
};
|
||||
|
||||
/**
|
||||
* This is the notification-handler interface. Implement this classes
|
||||
* methods to handle event and notifications from the sensors daemon.
|
||||
* All methods run on the main thread.
|
||||
*/
|
||||
class GonkSensorsNotificationHandler
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* This notification is called when the backend code fails
|
||||
* unexpectedly. Save state in the high-level code and restart
|
||||
* the driver.
|
||||
*
|
||||
* @param aCrash True is the sensors driver crashed.
|
||||
*/
|
||||
virtual void BackendErrorNotification(bool aCrashed);
|
||||
|
||||
protected:
|
||||
virtual ~GonkSensorsNotificationHandler();
|
||||
};
|
||||
|
||||
/**
|
||||
* This class implements the public interface to the Sensors functionality
|
||||
* and driver. Use |GonkSensorsInterface::GetInstance| to retrieve an instance.
|
||||
* All methods run on the main thread.
|
||||
*/
|
||||
class GonkSensorsInterface final
|
||||
: public mozilla::ipc::DaemonSocketConsumer
|
||||
, public mozilla::ipc::ListenSocketConsumer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Returns an instance of the Sensors backend. This code can return
|
||||
* |nullptr| if no Sensors backend is available.
|
||||
*
|
||||
* @return An instance of |GonkSensorsInterface|.
|
||||
*/
|
||||
static GonkSensorsInterface* GetInstance();
|
||||
|
||||
/**
|
||||
* This method sets the notification handler for sensor notifications. Call
|
||||
* this method immediately after retreiving an instance of the class, or you
|
||||
* won't be able able to receive notifications. You may not free the handler
|
||||
* class while the Sensors backend is connected.
|
||||
*
|
||||
* @param aNotificationHandler An instance of a notification handler.
|
||||
*/
|
||||
void SetNotificationHandler(
|
||||
GonkSensorsNotificationHandler* aNotificationHandler);
|
||||
|
||||
/**
|
||||
* This method starts the Sensors backend and establishes ad connection
|
||||
* with Gecko. This is a multi-step process and errors are signalled by
|
||||
* |GonkSensorsNotificationHandler::BackendErrorNotification|. If you see
|
||||
* this notification before the connection has been established, it's
|
||||
* certainly best to assume the Sensors backend to be not evailable.
|
||||
*
|
||||
* @param aRes The result handler.
|
||||
*/
|
||||
void Connect(GonkSensorsNotificationHandler* aNotificationHandler,
|
||||
GonkSensorsResultHandler* aRes);
|
||||
|
||||
/**
|
||||
* This method disconnects Gecko from the Sensors backend and frees
|
||||
* the backend's resources. This will invalidate all interfaces and
|
||||
* state. Don't use any sensors functionality without reconnecting
|
||||
* first.
|
||||
*
|
||||
* @param aRes The result handler.
|
||||
*/
|
||||
void Disconnect(GonkSensorsResultHandler* aRes);
|
||||
|
||||
/**
|
||||
* Returns the Registry interface for the connected Sensors backend.
|
||||
*
|
||||
* @return An instance of the Sensors Registry interface.
|
||||
*/
|
||||
GonkSensorsRegistryInterface* GetSensorsRegistryInterface();
|
||||
|
||||
/**
|
||||
* Returns the Poll interface for the connected Sensors backend.
|
||||
*
|
||||
* @return An instance of the Sensors Poll interface.
|
||||
*/
|
||||
GonkSensorsPollInterface* GetSensorsPollInterface();
|
||||
|
||||
private:
|
||||
enum Channel {
|
||||
LISTEN_SOCKET,
|
||||
DATA_SOCKET
|
||||
};
|
||||
|
||||
GonkSensorsInterface();
|
||||
~GonkSensorsInterface();
|
||||
|
||||
void DispatchError(GonkSensorsResultHandler* aRes, SensorsError aError);
|
||||
void DispatchError(GonkSensorsResultHandler* aRes, nsresult aRv);
|
||||
|
||||
// Methods for |DaemonSocketConsumer| and |ListenSocketConsumer|
|
||||
//
|
||||
|
||||
void OnConnectSuccess(int aIndex) override;
|
||||
void OnConnectError(int aIndex) override;
|
||||
void OnDisconnect(int aIndex) override;
|
||||
|
||||
nsCString mListenSocketName;
|
||||
RefPtr<mozilla::ipc::ListenSocket> mListenSocket;
|
||||
RefPtr<mozilla::ipc::DaemonSocket> mDataSocket;
|
||||
UniquePtr<GonkSensorsProtocol> mProtocol;
|
||||
|
||||
nsTArray<RefPtr<GonkSensorsResultHandler> > mResultHandlerQ;
|
||||
|
||||
GonkSensorsNotificationHandler* mNotificationHandler;
|
||||
|
||||
UniquePtr<GonkSensorsRegistryInterface> mRegistryInterface;
|
||||
UniquePtr<GonkSensorsPollInterface> mPollInterface;
|
||||
};
|
||||
|
||||
} // namespace hal
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // hal_gonk_GonkSensorsInterface_h
|
||||
431
hal/gonk/GonkSensorsPollInterface.cpp
Normal file
431
hal/gonk/GonkSensorsPollInterface.cpp
Normal file
|
|
@ -0,0 +1,431 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "GonkSensorsPollInterface.h"
|
||||
#include "HalLog.h"
|
||||
#include <mozilla/UniquePtr.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal {
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
//
|
||||
// GonkSensorsPollResultHandler
|
||||
//
|
||||
|
||||
void
|
||||
GonkSensorsPollResultHandler::OnError(SensorsError aError)
|
||||
{
|
||||
HAL_ERR("Received error code %d", static_cast<int>(aError));
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsPollResultHandler::EnableSensor()
|
||||
{ }
|
||||
|
||||
void
|
||||
GonkSensorsPollResultHandler::DisableSensor()
|
||||
{ }
|
||||
|
||||
void
|
||||
GonkSensorsPollResultHandler::SetPeriod()
|
||||
{ }
|
||||
|
||||
GonkSensorsPollResultHandler::~GonkSensorsPollResultHandler()
|
||||
{ }
|
||||
|
||||
//
|
||||
// GonkSensorsPollNotificationHandler
|
||||
//
|
||||
|
||||
void
|
||||
GonkSensorsPollNotificationHandler::ErrorNotification(SensorsError aError)
|
||||
{
|
||||
HAL_ERR("Received error code %d", static_cast<int>(aError));
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsPollNotificationHandler::SensorDetectedNotification(
|
||||
int32_t aId,
|
||||
SensorsType aType,
|
||||
float aRange,
|
||||
float aResolution,
|
||||
float aPower,
|
||||
int32_t aMinPeriod,
|
||||
int32_t aMaxPeriod,
|
||||
SensorsTriggerMode aTriggerMode,
|
||||
SensorsDeliveryMode aDeliveryMode)
|
||||
{ }
|
||||
|
||||
void
|
||||
GonkSensorsPollNotificationHandler::SensorLostNotification(int32_t aId)
|
||||
{ }
|
||||
|
||||
void
|
||||
GonkSensorsPollNotificationHandler::EventNotification(int32_t aId,
|
||||
const SensorsEvent& aEvent)
|
||||
{ }
|
||||
|
||||
GonkSensorsPollNotificationHandler::~GonkSensorsPollNotificationHandler()
|
||||
{ }
|
||||
|
||||
//
|
||||
// GonkSensorsPollModule
|
||||
//
|
||||
|
||||
GonkSensorsPollModule::GonkSensorsPollModule()
|
||||
: mProtocolVersion(0)
|
||||
{ }
|
||||
|
||||
GonkSensorsPollModule::~GonkSensorsPollModule()
|
||||
{ }
|
||||
|
||||
nsresult
|
||||
GonkSensorsPollModule::SetProtocolVersion(unsigned long aProtocolVersion)
|
||||
{
|
||||
if ((aProtocolVersion < MIN_PROTOCOL_VERSION) ||
|
||||
(aProtocolVersion > MAX_PROTOCOL_VERSION)) {
|
||||
HAL_ERR("Sensors Poll protocol version %lu not supported",
|
||||
aProtocolVersion);
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
mProtocolVersion = aProtocolVersion;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsPollModule::HandleSvc(const DaemonSocketPDUHeader& aHeader,
|
||||
DaemonSocketPDU& aPDU,
|
||||
DaemonSocketResultHandler* aRes)
|
||||
{
|
||||
static void (GonkSensorsPollModule::* const HandleOp[])(
|
||||
const DaemonSocketPDUHeader&, DaemonSocketPDU&,
|
||||
DaemonSocketResultHandler*) = {
|
||||
[0] = &GonkSensorsPollModule::HandleRsp,
|
||||
[1] = &GonkSensorsPollModule::HandleNtf
|
||||
};
|
||||
|
||||
MOZ_ASSERT(!NS_IsMainThread()); // I/O thread
|
||||
|
||||
// Negate twice to map bit to 0/1
|
||||
unsigned long isNtf = !!(aHeader.mOpcode & 0x80);
|
||||
|
||||
(this->*(HandleOp[isNtf]))(aHeader, aPDU, aRes);
|
||||
}
|
||||
|
||||
// Commands
|
||||
//
|
||||
|
||||
nsresult
|
||||
GonkSensorsPollModule::EnableSensorCmd(int32_t aId, GonkSensorsPollResultHandler* aRes)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
UniquePtr<DaemonSocketPDU> pdu =
|
||||
MakeUnique<DaemonSocketPDU>(SERVICE_ID, OPCODE_ENABLE_SENSOR, 0);
|
||||
|
||||
nsresult rv = PackPDU(aId, *pdu);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
rv = Send(pdu.get(), aRes);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
Unused << pdu.release();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkSensorsPollModule::DisableSensorCmd(int32_t aId, GonkSensorsPollResultHandler* aRes)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
UniquePtr<DaemonSocketPDU> pdu =
|
||||
MakeUnique<DaemonSocketPDU>(SERVICE_ID, OPCODE_DISABLE_SENSOR, 0);
|
||||
|
||||
nsresult rv = PackPDU(aId, *pdu);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
rv = Send(pdu.get(), aRes);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
Unused << pdu.release();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkSensorsPollModule::SetPeriodCmd(int32_t aId, uint64_t aPeriod,
|
||||
GonkSensorsPollResultHandler* aRes)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
UniquePtr<DaemonSocketPDU> pdu =
|
||||
MakeUnique<DaemonSocketPDU>(SERVICE_ID, OPCODE_SET_PERIOD, 0);
|
||||
|
||||
nsresult rv = PackPDU(aId, *pdu);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
rv = PackPDU(aPeriod, *pdu);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
rv = Send(pdu.get(), aRes);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
Unused << pdu.release();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Responses
|
||||
//
|
||||
|
||||
void
|
||||
GonkSensorsPollModule::ErrorRsp(
|
||||
const DaemonSocketPDUHeader& aHeader,
|
||||
DaemonSocketPDU& aPDU, GonkSensorsPollResultHandler* aRes)
|
||||
{
|
||||
ErrorRunnable::Dispatch(
|
||||
aRes, &GonkSensorsPollResultHandler::OnError, UnpackPDUInitOp(aPDU));
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsPollModule::EnableSensorRsp(
|
||||
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
|
||||
GonkSensorsPollResultHandler* aRes)
|
||||
{
|
||||
ResultRunnable::Dispatch(
|
||||
aRes, &GonkSensorsPollResultHandler::EnableSensor, UnpackPDUInitOp(aPDU));
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsPollModule::DisableSensorRsp(
|
||||
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
|
||||
GonkSensorsPollResultHandler* aRes)
|
||||
{
|
||||
ResultRunnable::Dispatch(
|
||||
aRes, &GonkSensorsPollResultHandler::DisableSensor, UnpackPDUInitOp(aPDU));
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsPollModule::SetPeriodRsp(
|
||||
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
|
||||
GonkSensorsPollResultHandler* aRes)
|
||||
{
|
||||
ResultRunnable::Dispatch(
|
||||
aRes, &GonkSensorsPollResultHandler::SetPeriod, UnpackPDUInitOp(aPDU));
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsPollModule::HandleRsp(
|
||||
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
|
||||
DaemonSocketResultHandler* aRes)
|
||||
{
|
||||
static void (GonkSensorsPollModule::* const sHandleRsp[])(
|
||||
const DaemonSocketPDUHeader&, DaemonSocketPDU&,
|
||||
GonkSensorsPollResultHandler*) = {
|
||||
[OPCODE_ERROR] = &GonkSensorsPollModule::ErrorRsp,
|
||||
[OPCODE_ENABLE_SENSOR] = &GonkSensorsPollModule::EnableSensorRsp,
|
||||
[OPCODE_DISABLE_SENSOR] = &GonkSensorsPollModule::DisableSensorRsp,
|
||||
[OPCODE_SET_PERIOD] = &GonkSensorsPollModule::SetPeriodRsp,
|
||||
};
|
||||
|
||||
MOZ_ASSERT(!NS_IsMainThread()); // I/O thread
|
||||
|
||||
if (!(aHeader.mOpcode < MOZ_ARRAY_LENGTH(sHandleRsp)) ||
|
||||
!sHandleRsp[aHeader.mOpcode]) {
|
||||
HAL_ERR("Sensors poll response opcode %d unknown", aHeader.mOpcode);
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<GonkSensorsPollResultHandler> res =
|
||||
static_cast<GonkSensorsPollResultHandler*>(aRes);
|
||||
|
||||
if (!res) {
|
||||
return; // Return early if no result handler has been set for response
|
||||
}
|
||||
|
||||
(this->*(sHandleRsp[aHeader.mOpcode]))(aHeader, aPDU, res);
|
||||
}
|
||||
|
||||
// Notifications
|
||||
//
|
||||
|
||||
// Returns the current notification handler to a notification runnable
|
||||
class GonkSensorsPollModule::NotificationHandlerWrapper final
|
||||
{
|
||||
public:
|
||||
typedef GonkSensorsPollNotificationHandler ObjectType;
|
||||
|
||||
static ObjectType* GetInstance()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
return sNotificationHandler;
|
||||
}
|
||||
|
||||
static GonkSensorsPollNotificationHandler* sNotificationHandler;
|
||||
};
|
||||
|
||||
GonkSensorsPollNotificationHandler*
|
||||
GonkSensorsPollModule::NotificationHandlerWrapper::sNotificationHandler;
|
||||
|
||||
void
|
||||
GonkSensorsPollModule::ErrorNtf(
|
||||
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
|
||||
{
|
||||
ErrorNotification::Dispatch(
|
||||
&GonkSensorsPollNotificationHandler::ErrorNotification,
|
||||
UnpackPDUInitOp(aPDU));
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsPollModule::SensorDetectedNtf(
|
||||
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
|
||||
{
|
||||
SensorDetectedNotification::Dispatch(
|
||||
&GonkSensorsPollNotificationHandler::SensorDetectedNotification,
|
||||
UnpackPDUInitOp(aPDU));
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsPollModule::SensorLostNtf(
|
||||
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
|
||||
{
|
||||
SensorLostNotification::Dispatch(
|
||||
&GonkSensorsPollNotificationHandler::SensorLostNotification,
|
||||
UnpackPDUInitOp(aPDU));
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsPollModule::EventNtf(
|
||||
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU)
|
||||
{
|
||||
EventNotification::Dispatch(
|
||||
&GonkSensorsPollNotificationHandler::EventNotification,
|
||||
UnpackPDUInitOp(aPDU));
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsPollModule::HandleNtf(
|
||||
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
|
||||
DaemonSocketResultHandler* aRes)
|
||||
{
|
||||
static void (GonkSensorsPollModule::* const sHandleNtf[])(
|
||||
const DaemonSocketPDUHeader&, DaemonSocketPDU&) = {
|
||||
[0] = &GonkSensorsPollModule::ErrorNtf,
|
||||
[1] = &GonkSensorsPollModule::SensorDetectedNtf,
|
||||
[2] = &GonkSensorsPollModule::SensorLostNtf,
|
||||
[3] = &GonkSensorsPollModule::EventNtf
|
||||
};
|
||||
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
uint8_t index = aHeader.mOpcode - 0x80;
|
||||
|
||||
if (!(index < MOZ_ARRAY_LENGTH(sHandleNtf)) || !sHandleNtf[index]) {
|
||||
HAL_ERR("Sensors poll notification opcode %d unknown", aHeader.mOpcode);
|
||||
return;
|
||||
}
|
||||
|
||||
(this->*(sHandleNtf[index]))(aHeader, aPDU);
|
||||
}
|
||||
|
||||
//
|
||||
// GonkSensorsPollInterface
|
||||
//
|
||||
|
||||
GonkSensorsPollInterface::GonkSensorsPollInterface(
|
||||
GonkSensorsPollModule* aModule)
|
||||
: mModule(aModule)
|
||||
{ }
|
||||
|
||||
GonkSensorsPollInterface::~GonkSensorsPollInterface()
|
||||
{ }
|
||||
|
||||
void
|
||||
GonkSensorsPollInterface::SetNotificationHandler(
|
||||
GonkSensorsPollNotificationHandler* aNotificationHandler)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
GonkSensorsPollModule::NotificationHandlerWrapper::sNotificationHandler =
|
||||
aNotificationHandler;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkSensorsPollInterface::SetProtocolVersion(unsigned long aProtocolVersion)
|
||||
{
|
||||
MOZ_ASSERT(mModule);
|
||||
|
||||
return mModule->SetProtocolVersion(aProtocolVersion);
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsPollInterface::EnableSensor(int32_t aId,
|
||||
GonkSensorsPollResultHandler* aRes)
|
||||
{
|
||||
MOZ_ASSERT(mModule);
|
||||
|
||||
nsresult rv = mModule->EnableSensorCmd(aId, aRes);
|
||||
if (NS_FAILED(rv)) {
|
||||
DispatchError(aRes, rv);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsPollInterface::DisableSensor(int32_t aId,
|
||||
GonkSensorsPollResultHandler* aRes)
|
||||
{
|
||||
MOZ_ASSERT(mModule);
|
||||
|
||||
nsresult rv = mModule->DisableSensorCmd(aId, aRes);
|
||||
if (NS_FAILED(rv)) {
|
||||
DispatchError(aRes, rv);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsPollInterface::SetPeriod(int32_t aId, uint64_t aPeriod,
|
||||
GonkSensorsPollResultHandler* aRes)
|
||||
{
|
||||
MOZ_ASSERT(mModule);
|
||||
|
||||
nsresult rv = mModule->SetPeriodCmd(aId, aPeriod, aRes);
|
||||
if (NS_FAILED(rv)) {
|
||||
DispatchError(aRes, rv);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsPollInterface::DispatchError(
|
||||
GonkSensorsPollResultHandler* aRes, SensorsError aError)
|
||||
{
|
||||
DaemonResultRunnable1<GonkSensorsPollResultHandler, void,
|
||||
SensorsError, SensorsError>::Dispatch(
|
||||
aRes, &GonkSensorsPollResultHandler::OnError,
|
||||
ConstantInitOp1<SensorsError>(aError));
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsPollInterface::DispatchError(
|
||||
GonkSensorsPollResultHandler* aRes, nsresult aRv)
|
||||
{
|
||||
SensorsError error;
|
||||
|
||||
if (NS_FAILED(Convert(aRv, error))) {
|
||||
error = SENSORS_ERROR_FAIL;
|
||||
}
|
||||
DispatchError(aRes, error);
|
||||
}
|
||||
|
||||
} // namespace hal
|
||||
} // namespace mozilla
|
||||
340
hal/gonk/GonkSensorsPollInterface.h
Normal file
340
hal/gonk/GonkSensorsPollInterface.h
Normal file
|
|
@ -0,0 +1,340 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
/*
|
||||
* The poll interface gives yo access to the Sensors daemon's Poll service,
|
||||
* which handles sensors. The poll service will inform you when sensors are
|
||||
* detected or removed from the system. You can activate (or deactivate)
|
||||
* existing sensors and poll will deliver the sensors' events.
|
||||
*
|
||||
* All public methods and callback methods run on the main thread.
|
||||
*/
|
||||
|
||||
#ifndef hal_gonk_GonkSensorsPollInterface_h
|
||||
#define hal_gonk_GonkSensorsPollInterface_h
|
||||
|
||||
#include <mozilla/ipc/DaemonRunnables.h>
|
||||
#include <mozilla/ipc/DaemonSocketMessageHandlers.h>
|
||||
#include "SensorsTypes.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class DaemonSocketPDU;
|
||||
class DaemonSocketPDUHeader;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal {
|
||||
|
||||
class SensorsInterface;
|
||||
|
||||
using mozilla::ipc::DaemonSocketPDU;
|
||||
using mozilla::ipc::DaemonSocketPDUHeader;
|
||||
using mozilla::ipc::DaemonSocketResultHandler;
|
||||
|
||||
/**
|
||||
* This class is the result-handler interface for the Sensors
|
||||
* Poll interface. Methods always run on the main thread.
|
||||
*/
|
||||
class GonkSensorsPollResultHandler : public DaemonSocketResultHandler
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Called if a poll command failed.
|
||||
*
|
||||
* @param aError The error code.
|
||||
*/
|
||||
virtual void OnError(SensorsError aError);
|
||||
|
||||
/**
|
||||
* The callback method for |GonkSensorsPollInterface::EnableSensor|.
|
||||
*/
|
||||
virtual void EnableSensor();
|
||||
|
||||
/**
|
||||
* The callback method for |GonkSensorsPollInterface::DisableSensor|.
|
||||
*/
|
||||
virtual void DisableSensor();
|
||||
|
||||
/**
|
||||
* The callback method for |GonkSensorsPollInterface::SetPeriod|.
|
||||
*/
|
||||
virtual void SetPeriod();
|
||||
|
||||
protected:
|
||||
virtual ~GonkSensorsPollResultHandler();
|
||||
};
|
||||
|
||||
/**
|
||||
* This is the notification-handler interface. Implement this classes
|
||||
* methods to handle event and notifications from the sensors daemon.
|
||||
*/
|
||||
class GonkSensorsPollNotificationHandler
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* The notification handler for errors. You'll receive this call if
|
||||
* there's been a critical error in the daemon. Either try to handle
|
||||
* the error, or restart the daemon.
|
||||
*
|
||||
* @param aError The error code.
|
||||
*/
|
||||
virtual void ErrorNotification(SensorsError aError);
|
||||
|
||||
/**
|
||||
* This methods gets call when a new sensor has been detected.
|
||||
*
|
||||
* @param aId The sensor's id.
|
||||
* @param aType The sensor's type.
|
||||
* @param aRange The sensor's maximum value.
|
||||
* @param aResolution The minimum difference between two consecutive values.
|
||||
* @param aPower The sensor's power consumption (in mA).
|
||||
* @param aMinPeriod The minimum time between two events (in ns).
|
||||
* @param aMaxPeriod The maximum time between two events (in ns).
|
||||
* @param aTriggerMode The sensor's mode for triggering events.
|
||||
* @param aDeliveryMode The sensor's urgency for event delivery.
|
||||
*/
|
||||
virtual void SensorDetectedNotification(int32_t aId, SensorsType aType,
|
||||
float aRange, float aResolution,
|
||||
float aPower, int32_t aMinPeriod,
|
||||
int32_t aMaxPeriod,
|
||||
SensorsTriggerMode aTriggerMode,
|
||||
SensorsDeliveryMode aDeliveryMode);
|
||||
|
||||
/**
|
||||
* This methods gets call when an existing sensor has been removed.
|
||||
*
|
||||
* @param aId The sensor's id.
|
||||
*/
|
||||
virtual void SensorLostNotification(int32_t aId);
|
||||
|
||||
/**
|
||||
* This is the callback methods for sensor events. Only activated sensors
|
||||
* generate events. All sensors are disabled by default. The actual data
|
||||
* of the event depends on the sensor type.
|
||||
*
|
||||
* @param aId The sensor's id.
|
||||
* @param aEvent The event's data.
|
||||
*/
|
||||
virtual void EventNotification(int32_t aId, const SensorsEvent& aEvent);
|
||||
|
||||
protected:
|
||||
virtual ~GonkSensorsPollNotificationHandler();
|
||||
};
|
||||
|
||||
/**
|
||||
* This is the module class for the Sensors poll component. It handles PDU
|
||||
* packing and unpacking. Methods are either executed on the main thread or
|
||||
* the I/O thread.
|
||||
*
|
||||
* This is an internal class, use |GonkSensorsPollInterface| instead.
|
||||
*/
|
||||
class GonkSensorsPollModule
|
||||
{
|
||||
public:
|
||||
class NotificationHandlerWrapper;
|
||||
|
||||
enum {
|
||||
SERVICE_ID = 0x01
|
||||
};
|
||||
|
||||
enum {
|
||||
OPCODE_ERROR = 0x00,
|
||||
OPCODE_ENABLE_SENSOR = 0x01,
|
||||
OPCODE_DISABLE_SENSOR = 0x02,
|
||||
OPCODE_SET_PERIOD = 0x03
|
||||
};
|
||||
|
||||
enum {
|
||||
MIN_PROTOCOL_VERSION = 1,
|
||||
MAX_PROTOCOL_VERSION = 1
|
||||
};
|
||||
|
||||
virtual nsresult Send(DaemonSocketPDU* aPDU,
|
||||
DaemonSocketResultHandler* aRes) = 0;
|
||||
|
||||
nsresult SetProtocolVersion(unsigned long aProtocolVersion);
|
||||
|
||||
//
|
||||
// Commands
|
||||
//
|
||||
|
||||
nsresult EnableSensorCmd(int32_t aId,
|
||||
GonkSensorsPollResultHandler* aRes);
|
||||
|
||||
nsresult DisableSensorCmd(int32_t aId,
|
||||
GonkSensorsPollResultHandler* aRes);
|
||||
|
||||
nsresult SetPeriodCmd(int32_t aId, uint64_t aPeriod,
|
||||
GonkSensorsPollResultHandler* aRes);
|
||||
|
||||
protected:
|
||||
GonkSensorsPollModule();
|
||||
virtual ~GonkSensorsPollModule();
|
||||
|
||||
void HandleSvc(const DaemonSocketPDUHeader& aHeader,
|
||||
DaemonSocketPDU& aPDU,
|
||||
DaemonSocketResultHandler* aRes);
|
||||
|
||||
private:
|
||||
|
||||
//
|
||||
// Responses
|
||||
//
|
||||
|
||||
typedef mozilla::ipc::DaemonResultRunnable0<
|
||||
GonkSensorsPollResultHandler, void>
|
||||
ResultRunnable;
|
||||
|
||||
typedef mozilla::ipc::DaemonResultRunnable1<
|
||||
GonkSensorsPollResultHandler, void, SensorsError, SensorsError>
|
||||
ErrorRunnable;
|
||||
|
||||
void ErrorRsp(const DaemonSocketPDUHeader& aHeader,
|
||||
DaemonSocketPDU& aPDU,
|
||||
GonkSensorsPollResultHandler* aRes);
|
||||
|
||||
void EnableSensorRsp(const DaemonSocketPDUHeader& aHeader,
|
||||
DaemonSocketPDU& aPDU,
|
||||
GonkSensorsPollResultHandler* aRes);
|
||||
|
||||
void DisableSensorRsp(const DaemonSocketPDUHeader& aHeader,
|
||||
DaemonSocketPDU& aPDU,
|
||||
GonkSensorsPollResultHandler* aRes);
|
||||
|
||||
void SetPeriodRsp(const DaemonSocketPDUHeader& aHeader,
|
||||
DaemonSocketPDU& aPDU,
|
||||
GonkSensorsPollResultHandler* aRes);
|
||||
|
||||
void HandleRsp(const DaemonSocketPDUHeader& aHeader,
|
||||
DaemonSocketPDU& aPDU,
|
||||
DaemonSocketResultHandler* aRes);
|
||||
|
||||
//
|
||||
// Notifications
|
||||
//
|
||||
|
||||
typedef mozilla::ipc::DaemonNotificationRunnable1<
|
||||
NotificationHandlerWrapper, void, SensorsError>
|
||||
ErrorNotification;
|
||||
|
||||
typedef mozilla::ipc::DaemonNotificationRunnable9<
|
||||
NotificationHandlerWrapper, void, int32_t, SensorsType,
|
||||
float, float, float, int32_t, int32_t, SensorsTriggerMode,
|
||||
SensorsDeliveryMode>
|
||||
SensorDetectedNotification;
|
||||
|
||||
typedef mozilla::ipc::DaemonNotificationRunnable1<
|
||||
NotificationHandlerWrapper, void, int32_t>
|
||||
SensorLostNotification;
|
||||
|
||||
typedef mozilla::ipc::DaemonNotificationRunnable2<
|
||||
NotificationHandlerWrapper, void, int32_t, SensorsEvent, int32_t,
|
||||
const SensorsEvent&>
|
||||
EventNotification;
|
||||
|
||||
class SensorDetectedInitOp;
|
||||
class SensorLostInitOp;
|
||||
class EventInitOp;
|
||||
|
||||
void ErrorNtf(const DaemonSocketPDUHeader& aHeader,
|
||||
DaemonSocketPDU& aPDU);
|
||||
|
||||
void SensorDetectedNtf(const DaemonSocketPDUHeader& aHeader,
|
||||
DaemonSocketPDU& aPDU);
|
||||
|
||||
void SensorLostNtf(const DaemonSocketPDUHeader& aHeader,
|
||||
DaemonSocketPDU& aPDU);
|
||||
|
||||
void EventNtf(const DaemonSocketPDUHeader& aHeader,
|
||||
DaemonSocketPDU& aPDU);
|
||||
|
||||
void HandleNtf(const DaemonSocketPDUHeader& aHeader,
|
||||
DaemonSocketPDU& aPDU,
|
||||
DaemonSocketResultHandler* aRes);
|
||||
|
||||
private:
|
||||
unsigned long mProtocolVersion;
|
||||
};
|
||||
|
||||
/**
|
||||
* This class implements the public interface to the Sensors poll
|
||||
* component. Use |SensorsInterface::GetPollInterface| to retrieve
|
||||
* an instance. All methods run on the main thread.
|
||||
*/
|
||||
class GonkSensorsPollInterface final
|
||||
{
|
||||
public:
|
||||
GonkSensorsPollInterface(GonkSensorsPollModule* aModule);
|
||||
~GonkSensorsPollInterface();
|
||||
|
||||
/**
|
||||
* This method sets the notification handler for poll notifications. Call
|
||||
* this method immediately after registering the module. Otherwise you won't
|
||||
* be able able to receive poll notifications. You may not free the handler
|
||||
* class while the poll component is regsitered.
|
||||
*
|
||||
* @param aNotificationHandler An instance of a poll notification handler.
|
||||
*/
|
||||
void SetNotificationHandler(
|
||||
GonkSensorsPollNotificationHandler* aNotificationHandler);
|
||||
|
||||
/**
|
||||
* This method sets the protocol version. You should set it to the
|
||||
* value that has been returned from the backend when registering the
|
||||
* Poll service. You cannot send or receive messages before setting
|
||||
* the protocol version.
|
||||
*
|
||||
* @param aProtocolVersion
|
||||
* @return NS_OK for supported versions, or an XPCOM error code otherwise.
|
||||
*/
|
||||
nsresult SetProtocolVersion(unsigned long aProtocolVersion);
|
||||
|
||||
/**
|
||||
* Enables an existing sensor. The sensor id will have been delivered in
|
||||
* a SensorDetectedNotification.
|
||||
*
|
||||
* @param aId The sensor's id.
|
||||
* @param aRes The result handler.
|
||||
*/
|
||||
void EnableSensor(int32_t aId, GonkSensorsPollResultHandler* aRes);
|
||||
|
||||
/**
|
||||
* Disables an existing sensor. The sensor id will have been delivered in
|
||||
* a SensorDetectedNotification.
|
||||
*
|
||||
* @param aId The sensor's id.
|
||||
* @param aRes The result handler.
|
||||
*/
|
||||
void DisableSensor(int32_t aId, GonkSensorsPollResultHandler* aRes);
|
||||
|
||||
/**
|
||||
* Sets the period for a sensor. The sensor id will have been delivered in
|
||||
* a SensorDetectedNotification. The value for the period should be between
|
||||
* the sensor's minimum and maximum period.
|
||||
*
|
||||
* @param aId The sensor's id.
|
||||
* @param aPeriod The sensor's new period.
|
||||
* @param aRes The result handler.
|
||||
*/
|
||||
void SetPeriod(int32_t aId, uint64_t aPeriod, GonkSensorsPollResultHandler* aRes);
|
||||
|
||||
private:
|
||||
void DispatchError(GonkSensorsPollResultHandler* aRes, SensorsError aError);
|
||||
void DispatchError(GonkSensorsPollResultHandler* aRes, nsresult aRv);
|
||||
|
||||
GonkSensorsPollModule* mModule;
|
||||
};
|
||||
|
||||
} // hal
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // hal_gonk_GonkSensorsPollInterface_h
|
||||
213
hal/gonk/GonkSensorsRegistryInterface.cpp
Normal file
213
hal/gonk/GonkSensorsRegistryInterface.cpp
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "GonkSensorsRegistryInterface.h"
|
||||
#include "GonkSensorsHelpers.h"
|
||||
#include "HalLog.h"
|
||||
#include <mozilla/UniquePtr.h>
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal {
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
//
|
||||
// GonkSensorsRegistryResultHandler
|
||||
//
|
||||
|
||||
void
|
||||
GonkSensorsRegistryResultHandler::OnError(SensorsError aError)
|
||||
{
|
||||
HAL_ERR("Received error code %d", static_cast<int>(aError));
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsRegistryResultHandler::RegisterModule(uint32_t aProtocolVersion)
|
||||
{ }
|
||||
|
||||
void
|
||||
GonkSensorsRegistryResultHandler::UnregisterModule()
|
||||
{ }
|
||||
|
||||
GonkSensorsRegistryResultHandler::~GonkSensorsRegistryResultHandler()
|
||||
{ }
|
||||
|
||||
//
|
||||
// GonkSensorsRegistryModule
|
||||
//
|
||||
|
||||
GonkSensorsRegistryModule::~GonkSensorsRegistryModule()
|
||||
{ }
|
||||
|
||||
void
|
||||
GonkSensorsRegistryModule::HandleSvc(const DaemonSocketPDUHeader& aHeader,
|
||||
DaemonSocketPDU& aPDU,
|
||||
DaemonSocketResultHandler* aRes)
|
||||
{
|
||||
static void (GonkSensorsRegistryModule::* const HandleRsp[])(
|
||||
const DaemonSocketPDUHeader&,
|
||||
DaemonSocketPDU&,
|
||||
GonkSensorsRegistryResultHandler*) = {
|
||||
[OPCODE_ERROR] = &GonkSensorsRegistryModule::ErrorRsp,
|
||||
[OPCODE_REGISTER_MODULE] = &GonkSensorsRegistryModule::RegisterModuleRsp,
|
||||
[OPCODE_UNREGISTER_MODULE] = &GonkSensorsRegistryModule::UnregisterModuleRsp
|
||||
};
|
||||
|
||||
if ((aHeader.mOpcode >= MOZ_ARRAY_LENGTH(HandleRsp)) ||
|
||||
!HandleRsp[aHeader.mOpcode]) {
|
||||
HAL_ERR("Sensors registry response opcode %d unknown", aHeader.mOpcode);
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<GonkSensorsRegistryResultHandler> res =
|
||||
static_cast<GonkSensorsRegistryResultHandler*>(aRes);
|
||||
|
||||
if (!res) {
|
||||
return; // Return early if no result handler has been set
|
||||
}
|
||||
|
||||
(this->*(HandleRsp[aHeader.mOpcode]))(aHeader, aPDU, res);
|
||||
}
|
||||
|
||||
// Commands
|
||||
//
|
||||
|
||||
nsresult
|
||||
GonkSensorsRegistryModule::RegisterModuleCmd(
|
||||
uint8_t aId, GonkSensorsRegistryResultHandler* aRes)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
UniquePtr<DaemonSocketPDU> pdu =
|
||||
MakeUnique<DaemonSocketPDU>(SERVICE_ID, OPCODE_REGISTER_MODULE, 0);
|
||||
|
||||
nsresult rv = PackPDU(aId, *pdu);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
rv = Send(pdu.get(), aRes);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
Unused << pdu.release();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
GonkSensorsRegistryModule::UnregisterModuleCmd(
|
||||
uint8_t aId, GonkSensorsRegistryResultHandler* aRes)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
UniquePtr<DaemonSocketPDU> pdu =
|
||||
MakeUnique<DaemonSocketPDU>(SERVICE_ID, OPCODE_UNREGISTER_MODULE, 0);
|
||||
|
||||
nsresult rv = PackPDU(aId, *pdu);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
rv = Send(pdu.get(), aRes);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
Unused << pdu.release();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Responses
|
||||
//
|
||||
|
||||
void
|
||||
GonkSensorsRegistryModule::ErrorRsp(
|
||||
const DaemonSocketPDUHeader& aHeader,
|
||||
DaemonSocketPDU& aPDU, GonkSensorsRegistryResultHandler* aRes)
|
||||
{
|
||||
ErrorRunnable::Dispatch(
|
||||
aRes, &GonkSensorsRegistryResultHandler::OnError, UnpackPDUInitOp(aPDU));
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsRegistryModule::RegisterModuleRsp(
|
||||
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
|
||||
GonkSensorsRegistryResultHandler* aRes)
|
||||
{
|
||||
Uint32ResultRunnable::Dispatch(
|
||||
aRes,
|
||||
&GonkSensorsRegistryResultHandler::RegisterModule,
|
||||
UnpackPDUInitOp(aPDU));
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsRegistryModule::UnregisterModuleRsp(
|
||||
const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU,
|
||||
GonkSensorsRegistryResultHandler* aRes)
|
||||
{
|
||||
ResultRunnable::Dispatch(
|
||||
aRes,
|
||||
&GonkSensorsRegistryResultHandler::UnregisterModule,
|
||||
UnpackPDUInitOp(aPDU));
|
||||
}
|
||||
|
||||
//
|
||||
// GonkSensorsRegistryInterface
|
||||
//
|
||||
|
||||
GonkSensorsRegistryInterface::GonkSensorsRegistryInterface(
|
||||
GonkSensorsRegistryModule* aModule)
|
||||
: mModule(aModule)
|
||||
{ }
|
||||
|
||||
GonkSensorsRegistryInterface::~GonkSensorsRegistryInterface()
|
||||
{ }
|
||||
|
||||
void
|
||||
GonkSensorsRegistryInterface::RegisterModule(
|
||||
uint8_t aId, GonkSensorsRegistryResultHandler* aRes)
|
||||
{
|
||||
MOZ_ASSERT(mModule);
|
||||
|
||||
nsresult rv = mModule->RegisterModuleCmd(aId, aRes);
|
||||
if (NS_FAILED(rv)) {
|
||||
DispatchError(aRes, rv);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsRegistryInterface::UnregisterModule(
|
||||
uint8_t aId, GonkSensorsRegistryResultHandler* aRes)
|
||||
{
|
||||
MOZ_ASSERT(mModule);
|
||||
|
||||
nsresult rv = mModule->UnregisterModuleCmd(aId, aRes);
|
||||
if (NS_FAILED(rv)) {
|
||||
DispatchError(aRes, rv);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsRegistryInterface::DispatchError(
|
||||
GonkSensorsRegistryResultHandler* aRes, SensorsError aError)
|
||||
{
|
||||
DaemonResultRunnable1<GonkSensorsRegistryResultHandler, void,
|
||||
SensorsError, SensorsError>::Dispatch(
|
||||
aRes, &GonkSensorsRegistryResultHandler::OnError,
|
||||
ConstantInitOp1<SensorsError>(aError));
|
||||
}
|
||||
|
||||
void
|
||||
GonkSensorsRegistryInterface::DispatchError(
|
||||
GonkSensorsRegistryResultHandler* aRes, nsresult aRv)
|
||||
{
|
||||
SensorsError error;
|
||||
|
||||
if (NS_FAILED(Convert(aRv, error))) {
|
||||
error = SENSORS_ERROR_FAIL;
|
||||
}
|
||||
DispatchError(aRes, error);
|
||||
}
|
||||
|
||||
} // namespace hal
|
||||
} // namespace mozilla
|
||||
182
hal/gonk/GonkSensorsRegistryInterface.h
Normal file
182
hal/gonk/GonkSensorsRegistryInterface.h
Normal file
|
|
@ -0,0 +1,182 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
/*
|
||||
* The registry interface gives yo access to the Sensors daemon's Registry
|
||||
* service. The purpose of the service is to register and setup all other
|
||||
* services, and make them available.
|
||||
*
|
||||
* All public methods and callback methods run on the main thread.
|
||||
*/
|
||||
|
||||
#ifndef hal_gonk_GonkSensorsRegistryInterface_h
|
||||
#define hal_gonk_GonkSensorsRegistryInterface_h
|
||||
|
||||
#include <mozilla/ipc/DaemonRunnables.h>
|
||||
#include <mozilla/ipc/DaemonSocketMessageHandlers.h>
|
||||
#include "SensorsTypes.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
class DaemonSocketPDU;
|
||||
class DaemonSocketPDUHeader;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal {
|
||||
|
||||
class SensorsInterface;
|
||||
|
||||
using mozilla::ipc::DaemonSocketPDU;
|
||||
using mozilla::ipc::DaemonSocketPDUHeader;
|
||||
using mozilla::ipc::DaemonSocketResultHandler;
|
||||
|
||||
/**
|
||||
* This class is the result-handler interface for the Sensors
|
||||
* Registry interface. Methods always run on the main thread.
|
||||
*/
|
||||
class GonkSensorsRegistryResultHandler : public DaemonSocketResultHandler
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Called if a registry command failed.
|
||||
*
|
||||
* @param aError The error code.
|
||||
*/
|
||||
virtual void OnError(SensorsError aError);
|
||||
|
||||
/**
|
||||
* The callback method for |GonkSensorsRegistryInterface::RegisterModule|.
|
||||
*
|
||||
* @param aProtocolVersion The daemon's protocol version. Make sure it's
|
||||
* compatible with Gecko's implementation.
|
||||
*/
|
||||
virtual void RegisterModule(uint32_t aProtocolVersion);
|
||||
|
||||
/**
|
||||
* The callback method for |SensorsRegsitryInterface::UnregisterModule|.
|
||||
*/
|
||||
virtual void UnregisterModule();
|
||||
|
||||
protected:
|
||||
virtual ~GonkSensorsRegistryResultHandler();
|
||||
};
|
||||
|
||||
/**
|
||||
* This is the module class for the Sensors registry component. It handles
|
||||
* PDU packing and unpacking. Methods are either executed on the main thread
|
||||
* or the I/O thread.
|
||||
*
|
||||
* This is an internal class, use |GonkSensorsRegistryInterface| instead.
|
||||
*/
|
||||
class GonkSensorsRegistryModule
|
||||
{
|
||||
public:
|
||||
enum {
|
||||
SERVICE_ID = 0x00
|
||||
};
|
||||
|
||||
enum {
|
||||
OPCODE_ERROR = 0x00,
|
||||
OPCODE_REGISTER_MODULE = 0x01,
|
||||
OPCODE_UNREGISTER_MODULE = 0x02
|
||||
};
|
||||
|
||||
virtual nsresult Send(DaemonSocketPDU* aPDU,
|
||||
DaemonSocketResultHandler* aRes) = 0;
|
||||
|
||||
//
|
||||
// Commands
|
||||
//
|
||||
|
||||
nsresult RegisterModuleCmd(uint8_t aId,
|
||||
GonkSensorsRegistryResultHandler* aRes);
|
||||
|
||||
nsresult UnregisterModuleCmd(uint8_t aId,
|
||||
GonkSensorsRegistryResultHandler* aRes);
|
||||
|
||||
protected:
|
||||
virtual ~GonkSensorsRegistryModule();
|
||||
|
||||
void HandleSvc(const DaemonSocketPDUHeader& aHeader,
|
||||
DaemonSocketPDU& aPDU, DaemonSocketResultHandler* aRes);
|
||||
|
||||
//
|
||||
// Responses
|
||||
//
|
||||
|
||||
typedef mozilla::ipc::DaemonResultRunnable0<
|
||||
GonkSensorsRegistryResultHandler, void>
|
||||
ResultRunnable;
|
||||
|
||||
typedef mozilla::ipc::DaemonResultRunnable1<
|
||||
GonkSensorsRegistryResultHandler, void, uint32_t, uint32_t>
|
||||
Uint32ResultRunnable;
|
||||
|
||||
typedef mozilla::ipc::DaemonResultRunnable1<
|
||||
GonkSensorsRegistryResultHandler, void, SensorsError, SensorsError>
|
||||
ErrorRunnable;
|
||||
|
||||
void ErrorRsp(const DaemonSocketPDUHeader& aHeader,
|
||||
DaemonSocketPDU& aPDU,
|
||||
GonkSensorsRegistryResultHandler* aRes);
|
||||
|
||||
void RegisterModuleRsp(const DaemonSocketPDUHeader& aHeader,
|
||||
DaemonSocketPDU& aPDU,
|
||||
GonkSensorsRegistryResultHandler* aRes);
|
||||
|
||||
void UnregisterModuleRsp(const DaemonSocketPDUHeader& aHeader,
|
||||
DaemonSocketPDU& aPDU,
|
||||
GonkSensorsRegistryResultHandler* aRes);
|
||||
};
|
||||
|
||||
/**
|
||||
* This class implements the public interface to the Sensors Registry
|
||||
* component. Use |SensorsInterface::GetRegistryInterface| to retrieve
|
||||
* an instance. All methods run on the main thread.
|
||||
*/
|
||||
class GonkSensorsRegistryInterface final
|
||||
{
|
||||
public:
|
||||
GonkSensorsRegistryInterface(GonkSensorsRegistryModule* aModule);
|
||||
~GonkSensorsRegistryInterface();
|
||||
|
||||
/**
|
||||
* Sends a RegisterModule command to the Sensors daemon. When the
|
||||
* result handler's |RegisterModule| method gets called, the service
|
||||
* has been registered successfully and can be used.
|
||||
*
|
||||
* @param aId The id of the service that is to be registered.
|
||||
* @param aRes The result handler.
|
||||
*/
|
||||
void RegisterModule(uint8_t aId, GonkSensorsRegistryResultHandler* aRes);
|
||||
|
||||
/**
|
||||
* Sends an UnregisterModule command to the Sensors daemon. The service
|
||||
* should not be used afterwards until it has been registered again.
|
||||
*
|
||||
* @param aId The id of the service that is to be unregistered.
|
||||
* @param aRes The result handler.
|
||||
*/
|
||||
void UnregisterModule(uint8_t aId, GonkSensorsRegistryResultHandler* aRes);
|
||||
|
||||
private:
|
||||
void DispatchError(GonkSensorsRegistryResultHandler* aRes,
|
||||
SensorsError aError);
|
||||
void DispatchError(GonkSensorsRegistryResultHandler* aRes,
|
||||
nsresult aRv);
|
||||
|
||||
GonkSensorsRegistryModule* mModule;
|
||||
};
|
||||
|
||||
} // namespace hal
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // hal_gonk_GonkSensorsRegistryInterface_h
|
||||
479
hal/gonk/GonkSwitch.cpp
Normal file
479
hal/gonk/GonkSwitch.cpp
Normal file
|
|
@ -0,0 +1,479 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* Copyright 2012 Mozilla Foundation and Mozilla contributors
|
||||
*
|
||||
* 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 <fcntl.h>
|
||||
#include <sysutils/NetlinkEvent.h>
|
||||
|
||||
#include "base/message_loop.h"
|
||||
#include "base/task.h"
|
||||
|
||||
#include "Hal.h"
|
||||
#include "HalLog.h"
|
||||
#include "mozilla/FileUtils.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "UeventPoller.h"
|
||||
|
||||
using namespace mozilla::hal;
|
||||
|
||||
#define SWITCH_HEADSET_DEVPATH "/devices/virtual/switch/h2w"
|
||||
#define SWITCH_USB_DEVPATH_GB "/devices/virtual/switch/usb_configuration"
|
||||
#define SWITCH_USB_DEVPATH_ICS "/devices/virtual/android_usb/android0"
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
/**
|
||||
* The uevent for a usb on GB insertion looks like:
|
||||
*
|
||||
* change@/devices/virtual/switch/usb_configuration
|
||||
* ACTION=change
|
||||
* DEVPATH=/devices/virtual/switch/usb_configuration
|
||||
* SUBSYSTEM=switch
|
||||
* SWITCH_NAME=usb_configuration
|
||||
* SWITCH_STATE=0
|
||||
* SEQNUM=5038
|
||||
*/
|
||||
class SwitchHandler
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(SwitchHandler)
|
||||
|
||||
SwitchHandler(const char* aDevPath, SwitchDevice aDevice)
|
||||
: mDevPath(aDevPath),
|
||||
mState(SWITCH_STATE_UNKNOWN),
|
||||
mDevice(aDevice)
|
||||
{
|
||||
GetInitialState();
|
||||
}
|
||||
|
||||
bool CheckEvent(NetlinkEvent* aEvent)
|
||||
{
|
||||
if (strcmp(GetSubsystem(), aEvent->getSubsystem()) ||
|
||||
strcmp(mDevPath, aEvent->findParam("DEVPATH"))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mState = ConvertState(GetStateString(aEvent));
|
||||
return mState != SWITCH_STATE_UNKNOWN;
|
||||
}
|
||||
|
||||
SwitchState GetState()
|
||||
{
|
||||
return mState;
|
||||
}
|
||||
|
||||
SwitchDevice GetType()
|
||||
{
|
||||
return mDevice;
|
||||
}
|
||||
protected:
|
||||
virtual ~SwitchHandler()
|
||||
{
|
||||
}
|
||||
|
||||
virtual const char* GetSubsystem()
|
||||
{
|
||||
return "switch";
|
||||
}
|
||||
|
||||
virtual const char* GetStateString(NetlinkEvent* aEvent)
|
||||
{
|
||||
return aEvent->findParam("SWITCH_STATE");
|
||||
}
|
||||
|
||||
void GetInitialState()
|
||||
{
|
||||
nsPrintfCString statePath("/sys%s/state", mDevPath);
|
||||
int fd = open(statePath.get(), O_RDONLY);
|
||||
if (fd <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ScopedClose autoClose(fd);
|
||||
char state[16];
|
||||
ssize_t bytesRead = read(fd, state, sizeof(state));
|
||||
if (bytesRead < 0) {
|
||||
HAL_ERR("Read data from %s fails", statePath.get());
|
||||
return;
|
||||
}
|
||||
|
||||
if (state[bytesRead - 1] == '\n') {
|
||||
bytesRead--;
|
||||
}
|
||||
|
||||
state[bytesRead] = '\0';
|
||||
mState = ConvertState(state);
|
||||
}
|
||||
|
||||
virtual SwitchState ConvertState(const char* aState)
|
||||
{
|
||||
MOZ_ASSERT(aState);
|
||||
return aState[0] == '0' ? SWITCH_STATE_OFF : SWITCH_STATE_ON;
|
||||
}
|
||||
|
||||
const char* mDevPath;
|
||||
SwitchState mState;
|
||||
SwitchDevice mDevice;
|
||||
};
|
||||
|
||||
/**
|
||||
* The uevent delivered for the USB configuration under ICS looks like,
|
||||
*
|
||||
* change@/devices/virtual/android_usb/android0
|
||||
* ACTION=change
|
||||
* DEVPATH=/devices/virtual/android_usb/android0
|
||||
* SUBSYSTEM=android_usb
|
||||
* USB_STATE=CONFIGURED
|
||||
* SEQNUM=1802
|
||||
*/
|
||||
class SwitchHandlerUsbIcs: public SwitchHandler
|
||||
{
|
||||
public:
|
||||
SwitchHandlerUsbIcs(const char* aDevPath) : SwitchHandler(aDevPath, SWITCH_USB)
|
||||
{
|
||||
SwitchHandler::GetInitialState();
|
||||
}
|
||||
|
||||
virtual ~SwitchHandlerUsbIcs() { }
|
||||
|
||||
protected:
|
||||
virtual const char* GetSubsystem()
|
||||
{
|
||||
return "android_usb";
|
||||
}
|
||||
|
||||
virtual const char* GetStateString(NetlinkEvent* aEvent)
|
||||
{
|
||||
return aEvent->findParam("USB_STATE");
|
||||
}
|
||||
|
||||
SwitchState ConvertState(const char* aState)
|
||||
{
|
||||
MOZ_ASSERT(aState);
|
||||
return strcmp(aState, "CONFIGURED") == 0 ? SWITCH_STATE_ON : SWITCH_STATE_OFF;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The uevent delivered for the headset under ICS looks like,
|
||||
*
|
||||
* change@/devices/virtual/switch/h2w
|
||||
* ACTION=change
|
||||
* DEVPATH=/devices/virtual/switch/h2w
|
||||
* SUBSYSTEM=switch
|
||||
* SWITCH_NAME=h2w
|
||||
* SWITCH_STATE=2 // Headset with no mic
|
||||
* SEQNUM=2581
|
||||
* On Otoro, SWITCH_NAME could be Headset/No Device when plug/unplug.
|
||||
* change@/devices/virtual/switch/h2w
|
||||
* ACTION=change
|
||||
* DEVPATH=/devices/virtual/switch/h2w
|
||||
* SUBSYSTEM=switch
|
||||
* SWITCH_NAME=Headset
|
||||
* SWITCH_STATE=1 // Headset with mic
|
||||
* SEQNUM=1602
|
||||
*/
|
||||
class SwitchHandlerHeadphone: public SwitchHandler
|
||||
{
|
||||
public:
|
||||
SwitchHandlerHeadphone(const char* aDevPath) :
|
||||
SwitchHandler(aDevPath, SWITCH_HEADPHONES)
|
||||
{
|
||||
SwitchHandler::GetInitialState();
|
||||
}
|
||||
|
||||
virtual ~SwitchHandlerHeadphone() { }
|
||||
|
||||
protected:
|
||||
SwitchState ConvertState(const char* aState)
|
||||
{
|
||||
MOZ_ASSERT(aState);
|
||||
|
||||
return aState[0] == '0' ? SWITCH_STATE_OFF :
|
||||
(aState[0] == '1' ? SWITCH_STATE_HEADSET : SWITCH_STATE_HEADPHONE);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
typedef nsTArray<RefPtr<SwitchHandler> > SwitchHandlerArray;
|
||||
|
||||
class SwitchEventRunnable : public Runnable
|
||||
{
|
||||
public:
|
||||
SwitchEventRunnable(SwitchEvent& aEvent) : mEvent(aEvent)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
NotifySwitchChange(mEvent);
|
||||
return NS_OK;
|
||||
}
|
||||
private:
|
||||
SwitchEvent mEvent;
|
||||
};
|
||||
|
||||
class SwitchEventObserver final : public IUeventObserver
|
||||
{
|
||||
~SwitchEventObserver()
|
||||
{
|
||||
mHandler.Clear();
|
||||
}
|
||||
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(SwitchEventObserver)
|
||||
SwitchEventObserver()
|
||||
: mEnableCount(0),
|
||||
mHeadphonesFromInputDev(false)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
int GetEnableCount()
|
||||
{
|
||||
return mEnableCount;
|
||||
}
|
||||
|
||||
void EnableSwitch(SwitchDevice aDevice)
|
||||
{
|
||||
mEventInfo[aDevice].mEnabled = true;
|
||||
mEnableCount++;
|
||||
}
|
||||
|
||||
void DisableSwitch(SwitchDevice aDevice)
|
||||
{
|
||||
mEventInfo[aDevice].mEnabled = false;
|
||||
mEnableCount--;
|
||||
}
|
||||
|
||||
void Notify(const NetlinkEvent& aEvent)
|
||||
{
|
||||
SwitchState currState;
|
||||
|
||||
SwitchDevice device = GetEventInfo(aEvent, currState);
|
||||
if (device == SWITCH_DEVICE_UNKNOWN) {
|
||||
return;
|
||||
}
|
||||
|
||||
EventInfo& info = mEventInfo[device];
|
||||
if (currState == info.mEvent.status()) {
|
||||
return;
|
||||
}
|
||||
|
||||
info.mEvent.status() = currState;
|
||||
|
||||
if (info.mEnabled) {
|
||||
NS_DispatchToMainThread(new SwitchEventRunnable(info.mEvent));
|
||||
}
|
||||
}
|
||||
|
||||
void Notify(SwitchDevice aDevice, SwitchState aState)
|
||||
{
|
||||
EventInfo& info = mEventInfo[aDevice];
|
||||
if (aState == info.mEvent.status()) {
|
||||
return;
|
||||
}
|
||||
|
||||
info.mEvent.status() = aState;
|
||||
|
||||
if (info.mEnabled) {
|
||||
NS_DispatchToMainThread(new SwitchEventRunnable(info.mEvent));
|
||||
}
|
||||
}
|
||||
|
||||
SwitchState GetCurrentInformation(SwitchDevice aDevice)
|
||||
{
|
||||
return mEventInfo[aDevice].mEvent.status();
|
||||
}
|
||||
|
||||
void NotifyAnEvent(SwitchDevice aDevice)
|
||||
{
|
||||
EventInfo& info = mEventInfo[aDevice];
|
||||
if (info.mEvent.status() != SWITCH_STATE_UNKNOWN) {
|
||||
NS_DispatchToMainThread(new SwitchEventRunnable(info.mEvent));
|
||||
}
|
||||
}
|
||||
|
||||
bool GetHeadphonesFromInputDev()
|
||||
{
|
||||
return mHeadphonesFromInputDev;
|
||||
}
|
||||
|
||||
private:
|
||||
class EventInfo
|
||||
{
|
||||
public:
|
||||
EventInfo() : mEnabled(false)
|
||||
{
|
||||
mEvent.status() = SWITCH_STATE_UNKNOWN;
|
||||
mEvent.device() = SWITCH_DEVICE_UNKNOWN;
|
||||
}
|
||||
SwitchEvent mEvent;
|
||||
bool mEnabled;
|
||||
};
|
||||
|
||||
EventInfo mEventInfo[NUM_SWITCH_DEVICE];
|
||||
size_t mEnableCount;
|
||||
SwitchHandlerArray mHandler;
|
||||
bool mHeadphonesFromInputDev;
|
||||
|
||||
// This function might also get called on the main thread
|
||||
// (from IsHeadphoneEventFromInputDev)
|
||||
void Init()
|
||||
{
|
||||
RefPtr<SwitchHandlerHeadphone> switchHeadPhone =
|
||||
new SwitchHandlerHeadphone(SWITCH_HEADSET_DEVPATH);
|
||||
|
||||
// If the initial state is unknown, it means the headphone event is from input dev
|
||||
mHeadphonesFromInputDev = switchHeadPhone->GetState() == SWITCH_STATE_UNKNOWN ? true : false;
|
||||
|
||||
if (!mHeadphonesFromInputDev) {
|
||||
mHandler.AppendElement(switchHeadPhone);
|
||||
} else {
|
||||
// If headphone status will be notified from input dev then initialize
|
||||
// status to "off" and wait for event notification.
|
||||
mEventInfo[SWITCH_HEADPHONES].mEvent.device() = SWITCH_HEADPHONES;
|
||||
mEventInfo[SWITCH_HEADPHONES].mEvent.status() = SWITCH_STATE_OFF;
|
||||
}
|
||||
mHandler.AppendElement(new SwitchHandler(SWITCH_USB_DEVPATH_GB, SWITCH_USB));
|
||||
mHandler.AppendElement(new SwitchHandlerUsbIcs(SWITCH_USB_DEVPATH_ICS));
|
||||
|
||||
SwitchHandlerArray::index_type handlerIndex;
|
||||
SwitchHandlerArray::size_type numHandlers = mHandler.Length();
|
||||
|
||||
for (handlerIndex = 0; handlerIndex < numHandlers; handlerIndex++) {
|
||||
SwitchState state = mHandler[handlerIndex]->GetState();
|
||||
if (state == SWITCH_STATE_UNKNOWN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SwitchDevice device = mHandler[handlerIndex]->GetType();
|
||||
mEventInfo[device].mEvent.device() = device;
|
||||
mEventInfo[device].mEvent.status() = state;
|
||||
}
|
||||
}
|
||||
|
||||
SwitchDevice GetEventInfo(const NetlinkEvent& aEvent, SwitchState& aState)
|
||||
{
|
||||
//working around the android code not being const-correct
|
||||
NetlinkEvent *e = const_cast<NetlinkEvent*>(&aEvent);
|
||||
|
||||
for (size_t i = 0; i < mHandler.Length(); i++) {
|
||||
if (mHandler[i]->CheckEvent(e)) {
|
||||
aState = mHandler[i]->GetState();
|
||||
return mHandler[i]->GetType();
|
||||
}
|
||||
}
|
||||
return SWITCH_DEVICE_UNKNOWN;
|
||||
}
|
||||
};
|
||||
|
||||
static RefPtr<SwitchEventObserver> sSwitchObserver;
|
||||
|
||||
static void
|
||||
InitializeResourceIfNeed()
|
||||
{
|
||||
if (!sSwitchObserver) {
|
||||
sSwitchObserver = new SwitchEventObserver();
|
||||
RegisterUeventListener(sSwitchObserver);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ReleaseResourceIfNeed()
|
||||
{
|
||||
if (sSwitchObserver->GetEnableCount() == 0) {
|
||||
UnregisterUeventListener(sSwitchObserver);
|
||||
sSwitchObserver = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
EnableSwitchNotificationsIOThread(SwitchDevice aDevice, Monitor *aMonitor)
|
||||
{
|
||||
InitializeResourceIfNeed();
|
||||
sSwitchObserver->EnableSwitch(aDevice);
|
||||
{
|
||||
MonitorAutoLock lock(*aMonitor);
|
||||
lock.Notify();
|
||||
}
|
||||
|
||||
// Notify the latest state if IO thread has the information.
|
||||
if (sSwitchObserver->GetEnableCount() > 1) {
|
||||
sSwitchObserver->NotifyAnEvent(aDevice);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EnableSwitchNotifications(SwitchDevice aDevice)
|
||||
{
|
||||
Monitor monitor("EnableSwitch.monitor");
|
||||
{
|
||||
MonitorAutoLock lock(monitor);
|
||||
XRE_GetIOMessageLoop()->PostTask(
|
||||
NewRunnableFunction(EnableSwitchNotificationsIOThread, aDevice, &monitor));
|
||||
lock.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
DisableSwitchNotificationsIOThread(SwitchDevice aDevice)
|
||||
{
|
||||
MOZ_ASSERT(sSwitchObserver->GetEnableCount());
|
||||
sSwitchObserver->DisableSwitch(aDevice);
|
||||
ReleaseResourceIfNeed();
|
||||
}
|
||||
|
||||
void
|
||||
DisableSwitchNotifications(SwitchDevice aDevice)
|
||||
{
|
||||
XRE_GetIOMessageLoop()->PostTask(
|
||||
NewRunnableFunction(DisableSwitchNotificationsIOThread, aDevice));
|
||||
}
|
||||
|
||||
SwitchState
|
||||
GetCurrentSwitchState(SwitchDevice aDevice)
|
||||
{
|
||||
MOZ_ASSERT(sSwitchObserver && sSwitchObserver->GetEnableCount());
|
||||
return sSwitchObserver->GetCurrentInformation(aDevice);
|
||||
}
|
||||
|
||||
static void
|
||||
NotifySwitchStateIOThread(SwitchDevice aDevice, SwitchState aState)
|
||||
{
|
||||
InitializeResourceIfNeed();
|
||||
sSwitchObserver->Notify(aDevice, aState);
|
||||
}
|
||||
|
||||
void NotifySwitchStateFromInputDevice(SwitchDevice aDevice, SwitchState aState)
|
||||
{
|
||||
XRE_GetIOMessageLoop()->PostTask(
|
||||
NewRunnableFunction(NotifySwitchStateIOThread, aDevice, aState));
|
||||
}
|
||||
|
||||
bool IsHeadphoneEventFromInputDev()
|
||||
{
|
||||
// Instead of calling InitializeResourceIfNeed, create new SwitchEventObserver
|
||||
// to prevent calling RegisterUeventListener in main thread.
|
||||
RefPtr<SwitchEventObserver> switchObserver = new SwitchEventObserver();
|
||||
return switchObserver->GetHeadphonesFromInputDev();
|
||||
}
|
||||
|
||||
} // hal_impl
|
||||
} //mozilla
|
||||
140
hal/gonk/SensorsTypes.h
Normal file
140
hal/gonk/SensorsTypes.h
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef hal_gonk_SensorsTypes_h
|
||||
#define hal_gonk_SensorsTypes_h
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal {
|
||||
|
||||
enum SensorsDeliveryMode {
|
||||
SENSORS_DELIVERY_MODE_BEST_EFFORT,
|
||||
SENSORS_DELIVERY_MODE_IMMEDIATE
|
||||
};
|
||||
|
||||
enum SensorsError {
|
||||
SENSORS_ERROR_NONE,
|
||||
SENSORS_ERROR_FAIL,
|
||||
SENSORS_ERROR_NOT_READY,
|
||||
SENSORS_ERROR_NOMEM,
|
||||
SENSORS_ERROR_BUSY,
|
||||
SENSORS_ERROR_DONE,
|
||||
SENSORS_ERROR_UNSUPPORTED,
|
||||
SENSORS_ERROR_PARM_INVALID
|
||||
};
|
||||
|
||||
enum SensorsStatus {
|
||||
SENSORS_STATUS_NO_CONTACT,
|
||||
SENSORS_STATUS_UNRELIABLE,
|
||||
SENSORS_STATUS_ACCURACY_LOW,
|
||||
SENSORS_STATUS_ACCURACY_MEDIUM,
|
||||
SENSORS_STATUS_ACCURACY_HIGH
|
||||
};
|
||||
|
||||
enum SensorsTriggerMode {
|
||||
SENSORS_TRIGGER_MODE_CONTINUOUS,
|
||||
SENSORS_TRIGGER_MODE_ON_CHANGE,
|
||||
SENSORS_TRIGGER_MODE_ONE_SHOT,
|
||||
SENSORS_TRIGGER_MODE_SPECIAL
|
||||
};
|
||||
|
||||
enum SensorsType {
|
||||
SENSORS_TYPE_ACCELEROMETER,
|
||||
SENSORS_TYPE_GEOMAGNETIC_FIELD,
|
||||
SENSORS_TYPE_ORIENTATION,
|
||||
SENSORS_TYPE_GYROSCOPE,
|
||||
SENSORS_TYPE_LIGHT,
|
||||
SENSORS_TYPE_PRESSURE,
|
||||
SENSORS_TYPE_TEMPERATURE,
|
||||
SENSORS_TYPE_PROXIMITY,
|
||||
SENSORS_TYPE_GRAVITY,
|
||||
SENSORS_TYPE_LINEAR_ACCELERATION,
|
||||
SENSORS_TYPE_ROTATION_VECTOR,
|
||||
SENSORS_TYPE_RELATIVE_HUMIDITY,
|
||||
SENSORS_TYPE_AMBIENT_TEMPERATURE,
|
||||
SENSORS_TYPE_MAGNETIC_FIELD_UNCALIBRATED,
|
||||
SENSORS_TYPE_GAME_ROTATION_VECTOR,
|
||||
SENSORS_TYPE_GYROSCOPE_UNCALIBRATED,
|
||||
SENSORS_TYPE_SIGNIFICANT_MOTION,
|
||||
SENSORS_TYPE_STEP_DETECTED,
|
||||
SENSORS_TYPE_STEP_COUNTER,
|
||||
SENSORS_TYPE_GEOMAGNETIC_ROTATION_VECTOR,
|
||||
SENSORS_TYPE_HEART_RATE,
|
||||
SENSORS_TYPE_TILT_DETECTOR,
|
||||
SENSORS_TYPE_WAKE_GESTURE,
|
||||
SENSORS_TYPE_GLANCE_GESTURE,
|
||||
SENSORS_TYPE_PICK_UP_GESTURE,
|
||||
SENSORS_TYPE_WRIST_TILT_GESTURE,
|
||||
SENSORS_NUM_TYPES
|
||||
};
|
||||
|
||||
struct SensorsEvent {
|
||||
SensorsType mType;
|
||||
SensorsStatus mStatus;
|
||||
SensorsDeliveryMode mDeliveryMode;
|
||||
int64_t mTimestamp;
|
||||
union {
|
||||
float mFloat[6];
|
||||
uint64_t mUint[1];
|
||||
} mData;
|
||||
};
|
||||
|
||||
/**
|
||||
* |SensorsSensor| represents a device sensor; either single or composite.
|
||||
*/
|
||||
struct SensorsSensor {
|
||||
SensorsSensor(int32_t aId, SensorsType aType,
|
||||
float aRange, float aResolution,
|
||||
float aPower, int32_t aMinPeriod,
|
||||
int32_t aMaxPeriod,
|
||||
SensorsTriggerMode aTriggerMode,
|
||||
SensorsDeliveryMode aDeliveryMode)
|
||||
: mId(aId)
|
||||
, mType(aType)
|
||||
, mRange(aRange)
|
||||
, mResolution(aResolution)
|
||||
, mPower(aPower)
|
||||
, mMinPeriod(aMinPeriod)
|
||||
, mMaxPeriod(aMaxPeriod)
|
||||
, mTriggerMode(aTriggerMode)
|
||||
, mDeliveryMode(aDeliveryMode)
|
||||
{ }
|
||||
|
||||
int32_t mId;
|
||||
SensorsType mType;
|
||||
float mRange;
|
||||
float mResolution;
|
||||
float mPower;
|
||||
int32_t mMinPeriod;
|
||||
int32_t mMaxPeriod;
|
||||
SensorsTriggerMode mTriggerMode;
|
||||
SensorsDeliveryMode mDeliveryMode;
|
||||
};
|
||||
|
||||
/**
|
||||
* |SensorClass| represents the status of a specific sensor type.
|
||||
*/
|
||||
struct SensorsSensorClass {
|
||||
SensorsSensorClass()
|
||||
: mActivated(0)
|
||||
, mMinValue(0)
|
||||
, mMaxValue(0)
|
||||
{ }
|
||||
|
||||
void UpdateFromSensor(const SensorsSensor& aSensor)
|
||||
{
|
||||
mMaxValue = std::max(aSensor.mRange, mMaxValue);
|
||||
}
|
||||
|
||||
uint32_t mActivated;
|
||||
float mMinValue;
|
||||
float mMaxValue;
|
||||
};
|
||||
|
||||
} // namespace hal
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // hal_gonk_SensorsTypes_h
|
||||
131
hal/gonk/SystemService.cpp
Normal file
131
hal/gonk/SystemService.cpp
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||
/* 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 <cutils/properties.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "HalLog.h"
|
||||
#include "nsITimer.h"
|
||||
#include "mozilla/Unused.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
static const int sRetryInterval = 100; // ms
|
||||
|
||||
bool
|
||||
SystemServiceIsRunning(const char* aSvcName)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
char key[PROPERTY_KEY_MAX];
|
||||
auto res = snprintf(key, sizeof(key), "init.svc.%s", aSvcName);
|
||||
|
||||
if (res < 0) {
|
||||
HAL_ERR("snprintf: %s", strerror(errno));
|
||||
return false;
|
||||
} else if (static_cast<size_t>(res) >= sizeof(key)) {
|
||||
HAL_ERR("snprintf: trunctated service name %s", aSvcName);
|
||||
return false;
|
||||
}
|
||||
|
||||
char value[PROPERTY_VALUE_MAX];
|
||||
Unused << NS_WARN_IF(property_get(key, value, "") < 0);
|
||||
|
||||
return !strcmp(value, "running");
|
||||
}
|
||||
|
||||
class StartSystemServiceTimerCallback final : public nsITimerCallback
|
||||
{
|
||||
NS_DECL_THREADSAFE_ISUPPORTS;
|
||||
|
||||
public:
|
||||
StartSystemServiceTimerCallback(const char* aSvcName, const char* aArgs)
|
||||
: mSvcName(aSvcName)
|
||||
, mArgs(aArgs)
|
||||
{
|
||||
MOZ_COUNT_CTOR_INHERITED(StartSystemServiceTimerCallback,
|
||||
nsITimerCallback);
|
||||
}
|
||||
|
||||
NS_IMETHOD Notify(nsITimer* aTimer) override
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
return StartSystemService(mSvcName.get(), mArgs.get());
|
||||
}
|
||||
|
||||
protected:
|
||||
~StartSystemServiceTimerCallback()
|
||||
{
|
||||
MOZ_COUNT_DTOR_INHERITED(StartSystemServiceTimerCallback,
|
||||
nsITimerCallback);
|
||||
}
|
||||
|
||||
private:
|
||||
nsCString mSvcName;
|
||||
nsCString mArgs;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS0(StartSystemServiceTimerCallback);
|
||||
|
||||
nsresult
|
||||
StartSystemService(const char* aSvcName, const char* aArgs)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
char value[PROPERTY_VALUE_MAX];
|
||||
auto res = snprintf(value, sizeof(value), "%s:%s", aSvcName, aArgs);
|
||||
|
||||
if (res < 0) {
|
||||
HAL_ERR("snprintf: %s", strerror(errno));
|
||||
return NS_ERROR_FAILURE;
|
||||
} else if (static_cast<size_t>(res) >= sizeof(value)) {
|
||||
HAL_ERR("snprintf: trunctated service name %s", aSvcName);
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(property_set("ctl.start", value) < 0)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
/* If the system service is not running, re-try later to start it.
|
||||
*
|
||||
* This condition happens when we restart a service immediately
|
||||
* after it crashed, as the service state remains 'stopping'
|
||||
* instead of 'stopped'. Due to the limitation of property service,
|
||||
* hereby add delay. See Bug 1143925 Comment 41.
|
||||
*/
|
||||
if (!SystemServiceIsRunning(aSvcName)) {
|
||||
nsCOMPtr<nsITimer> timer = do_CreateInstance("@mozilla.org/timer;1");
|
||||
if (!timer) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RefPtr<StartSystemServiceTimerCallback> timerCallback =
|
||||
new StartSystemServiceTimerCallback(aSvcName, aArgs);
|
||||
|
||||
timer->InitWithCallback(timerCallback,
|
||||
sRetryInterval,
|
||||
nsITimer::TYPE_ONE_SHOT);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
StopSystemService(const char* aSvcName)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
Unused << NS_WARN_IF(property_set("ctl.stop", aSvcName));
|
||||
}
|
||||
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
||||
312
hal/gonk/UeventPoller.cpp
Normal file
312
hal/gonk/UeventPoller.cpp
Normal file
|
|
@ -0,0 +1,312 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* Copyright 2012 Mozilla Foundation and Mozilla contributors
|
||||
*
|
||||
* 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 <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#include <strings.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "HalLog.h"
|
||||
#include "nsDebug.h"
|
||||
#include "base/message_loop.h"
|
||||
#include "base/task.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/FileUtils.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
#include "UeventPoller.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
static void ShutdownUevent();
|
||||
|
||||
class NetlinkPoller : public MessageLoopForIO::Watcher
|
||||
{
|
||||
public:
|
||||
NetlinkPoller() : mSocket(-1),
|
||||
mIOLoop(MessageLoopForIO::current())
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~NetlinkPoller() {}
|
||||
|
||||
bool OpenSocket();
|
||||
|
||||
virtual void OnFileCanReadWithoutBlocking(int fd);
|
||||
|
||||
// no writing to the netlink socket
|
||||
virtual void OnFileCanWriteWithoutBlocking(int fd)
|
||||
{
|
||||
MOZ_CRASH("Must not write to netlink socket");
|
||||
}
|
||||
|
||||
MessageLoopForIO *GetIOLoop () const { return mIOLoop; }
|
||||
void RegisterObserver(IUeventObserver *aObserver)
|
||||
{
|
||||
mUeventObserverList.AddObserver(aObserver);
|
||||
}
|
||||
|
||||
void UnregisterObserver(IUeventObserver *aObserver)
|
||||
{
|
||||
mUeventObserverList.RemoveObserver(aObserver);
|
||||
if (mUeventObserverList.Length() == 0) {
|
||||
ShutdownUevent(); // this will destroy self
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
ScopedClose mSocket;
|
||||
MessageLoopForIO* mIOLoop;
|
||||
MessageLoopForIO::FileDescriptorWatcher mReadWatcher;
|
||||
|
||||
const static int kBuffsize = 64 * 1024;
|
||||
uint8_t mBuffer [kBuffsize];
|
||||
|
||||
typedef ObserverList<NetlinkEvent> UeventObserverList;
|
||||
UeventObserverList mUeventObserverList;
|
||||
};
|
||||
|
||||
bool
|
||||
NetlinkPoller::OpenSocket()
|
||||
{
|
||||
mSocket.rwget() = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
|
||||
if (mSocket.get() < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int sz = kBuffsize;
|
||||
|
||||
if (setsockopt(mSocket.get(), SOL_SOCKET, SO_RCVBUFFORCE, &sz,
|
||||
sizeof(sz)) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// add FD_CLOEXEC flag
|
||||
int flags = fcntl(mSocket.get(), F_GETFD);
|
||||
if (flags == -1) {
|
||||
return false;
|
||||
}
|
||||
flags |= FD_CLOEXEC;
|
||||
if (fcntl(mSocket.get(), F_SETFD, flags) == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// set non-blocking
|
||||
if (fcntl(mSocket.get(), F_SETFL, O_NONBLOCK) == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
struct sockaddr_nl saddr;
|
||||
bzero(&saddr, sizeof(saddr));
|
||||
saddr.nl_family = AF_NETLINK;
|
||||
saddr.nl_groups = 1;
|
||||
saddr.nl_pid = gettid();
|
||||
|
||||
do {
|
||||
if (bind(mSocket.get(), (struct sockaddr *)&saddr, sizeof(saddr)) == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (errno != EADDRINUSE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (saddr.nl_pid == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Once there was any other place in the same process assigning saddr.nl_pid by
|
||||
// gettid(), we can detect it and print warning message.
|
||||
HAL_LOG("The netlink socket address saddr.nl_pid=%u is in use. "
|
||||
"Let the kernel re-assign.\n", saddr.nl_pid);
|
||||
saddr.nl_pid = 0;
|
||||
} while (true);
|
||||
|
||||
if (!mIOLoop->WatchFileDescriptor(mSocket.get(),
|
||||
true,
|
||||
MessageLoopForIO::WATCH_READ,
|
||||
&mReadWatcher,
|
||||
this)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static StaticAutoPtr<NetlinkPoller> sPoller;
|
||||
|
||||
class UeventInitTask : public Runnable
|
||||
{
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
if (!sPoller) {
|
||||
return NS_OK;
|
||||
}
|
||||
if (sPoller->OpenSocket()) {
|
||||
return NS_OK;
|
||||
}
|
||||
sPoller->GetIOLoop()->PostDelayedTask(MakeAndAddRef<UeventInitTask>(),
|
||||
1000);
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
NetlinkPoller::OnFileCanReadWithoutBlocking(int fd)
|
||||
{
|
||||
MOZ_ASSERT(fd == mSocket.get());
|
||||
while (true) {
|
||||
int ret = read(fd, mBuffer, kBuffsize);
|
||||
if (ret == -1) {
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
||||
return;
|
||||
}
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (ret <= 0) {
|
||||
// fatal error on netlink socket which should not happen
|
||||
_exit(1);
|
||||
}
|
||||
NetlinkEvent netlinkEvent;
|
||||
netlinkEvent.decode(reinterpret_cast<char*>(mBuffer), ret);
|
||||
mUeventObserverList.Broadcast(netlinkEvent);
|
||||
}
|
||||
}
|
||||
|
||||
static bool sShutdown = false;
|
||||
|
||||
class ShutdownNetlinkPoller;
|
||||
static StaticAutoPtr<ShutdownNetlinkPoller> sShutdownPoller;
|
||||
static Monitor* sMonitor = nullptr;
|
||||
|
||||
class ShutdownNetlinkPoller {
|
||||
public:
|
||||
~ShutdownNetlinkPoller()
|
||||
{
|
||||
// This is called from KillClearOnShutdown() on the main thread.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(XRE_GetIOMessageLoop());
|
||||
|
||||
{
|
||||
MonitorAutoLock lock(*sMonitor);
|
||||
|
||||
XRE_GetIOMessageLoop()->PostTask(
|
||||
NewRunnableFunction(ShutdownUeventIOThread));
|
||||
|
||||
while (!sShutdown) {
|
||||
lock.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
sShutdown = true;
|
||||
delete sMonitor;
|
||||
}
|
||||
|
||||
static void MaybeInit()
|
||||
{
|
||||
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
|
||||
if (sShutdown || sMonitor) {
|
||||
// Don't init twice or init after shutdown.
|
||||
return;
|
||||
}
|
||||
|
||||
sMonitor = new Monitor("ShutdownNetlinkPoller.monitor");
|
||||
{
|
||||
ShutdownNetlinkPoller* shutdownPoller = new ShutdownNetlinkPoller();
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction([=] () -> void
|
||||
{
|
||||
sShutdownPoller = shutdownPoller;
|
||||
ClearOnShutdown(&sShutdownPoller); // Must run on the main thread.
|
||||
});
|
||||
MOZ_ASSERT(runnable);
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL));
|
||||
}
|
||||
}
|
||||
private:
|
||||
ShutdownNetlinkPoller() = default;
|
||||
static void ShutdownUeventIOThread()
|
||||
{
|
||||
MonitorAutoLock l(*sMonitor);
|
||||
ShutdownUevent(); // Must run on the IO thread.
|
||||
sShutdown = true;
|
||||
l.NotifyAll();
|
||||
}
|
||||
};
|
||||
|
||||
static void
|
||||
InitializeUevent()
|
||||
{
|
||||
MOZ_ASSERT(!sPoller);
|
||||
sPoller = new NetlinkPoller();
|
||||
sPoller->GetIOLoop()->PostTask(MakeAndAddRef<UeventInitTask>());
|
||||
|
||||
ShutdownNetlinkPoller::MaybeInit();
|
||||
}
|
||||
|
||||
static void
|
||||
ShutdownUevent()
|
||||
{
|
||||
sPoller = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
RegisterUeventListener(IUeventObserver *aObserver)
|
||||
{
|
||||
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
|
||||
|
||||
if (sShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sPoller) {
|
||||
InitializeUevent();
|
||||
}
|
||||
sPoller->RegisterObserver(aObserver);
|
||||
}
|
||||
|
||||
void
|
||||
UnregisterUeventListener(IUeventObserver *aObserver)
|
||||
{
|
||||
MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
|
||||
|
||||
if (sShutdown) {
|
||||
return;
|
||||
}
|
||||
|
||||
sPoller->UnregisterObserver(aObserver);
|
||||
}
|
||||
|
||||
} // hal_impl
|
||||
} // mozilla
|
||||
|
||||
49
hal/gonk/UeventPoller.h
Normal file
49
hal/gonk/UeventPoller.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* Copyright 2012 Mozilla Foundation and Mozilla contributors
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _mozilla_uevent_poller_h_
|
||||
#define _mozilla_uevent_poller_h_
|
||||
|
||||
#include <sysutils/NetlinkEvent.h>
|
||||
#include "mozilla/Observer.h"
|
||||
|
||||
class NetlinkEvent;
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
typedef mozilla::Observer<NetlinkEvent> IUeventObserver;
|
||||
|
||||
/**
|
||||
* Register for uevent notification. Note that the method should run on the
|
||||
* <b> IO Thread </b>
|
||||
* @aObserver the observer to be added. The observer's Notify() is only called
|
||||
* on the <b> IO Thread </b>
|
||||
*/
|
||||
void RegisterUeventListener(IUeventObserver *aObserver);
|
||||
|
||||
/**
|
||||
* Unregister for uevent notification. Note that the method should run on the
|
||||
* <b> IO Thread </b>
|
||||
* @aObserver the observer to be removed
|
||||
*/
|
||||
void UnregisterUeventListener(IUeventObserver *aObserver);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
118
hal/gonk/fanotify.h
Normal file
118
hal/gonk/fanotify.h
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
#ifndef _LINUX_FANOTIFY_H
|
||||
#define _LINUX_FANOTIFY_H
|
||||
|
||||
/* This is a Linux header generated by "make headers_install" */
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/* the following events that user-space can register for */
|
||||
#define FAN_ACCESS 0x00000001 /* File was accessed */
|
||||
#define FAN_MODIFY 0x00000002 /* File was modified */
|
||||
#define FAN_CLOSE_WRITE 0x00000008 /* Writtable file closed */
|
||||
#define FAN_CLOSE_NOWRITE 0x00000010 /* Unwrittable file closed */
|
||||
#define FAN_OPEN 0x00000020 /* File was opened */
|
||||
|
||||
#define FAN_Q_OVERFLOW 0x00004000 /* Event queued overflowed */
|
||||
|
||||
#define FAN_OPEN_PERM 0x00010000 /* File open in perm check */
|
||||
#define FAN_ACCESS_PERM 0x00020000 /* File accessed in perm check */
|
||||
|
||||
#define FAN_ONDIR 0x40000000 /* event occurred against dir */
|
||||
|
||||
#define FAN_EVENT_ON_CHILD 0x08000000 /* interested in child events */
|
||||
|
||||
/* helper events */
|
||||
#define FAN_CLOSE (FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE) /* close */
|
||||
|
||||
/* flags used for fanotify_init() */
|
||||
#define FAN_CLOEXEC 0x00000001
|
||||
#define FAN_NONBLOCK 0x00000002
|
||||
|
||||
/* These are NOT bitwise flags. Both bits are used togther. */
|
||||
#define FAN_CLASS_NOTIF 0x00000000
|
||||
#define FAN_CLASS_CONTENT 0x00000004
|
||||
#define FAN_CLASS_PRE_CONTENT 0x00000008
|
||||
#define FAN_ALL_CLASS_BITS (FAN_CLASS_NOTIF | FAN_CLASS_CONTENT | \
|
||||
FAN_CLASS_PRE_CONTENT)
|
||||
|
||||
#define FAN_UNLIMITED_QUEUE 0x00000010
|
||||
#define FAN_UNLIMITED_MARKS 0x00000020
|
||||
|
||||
#define FAN_ALL_INIT_FLAGS (FAN_CLOEXEC | FAN_NONBLOCK | \
|
||||
FAN_ALL_CLASS_BITS | FAN_UNLIMITED_QUEUE |\
|
||||
FAN_UNLIMITED_MARKS)
|
||||
|
||||
/* flags used for fanotify_modify_mark() */
|
||||
#define FAN_MARK_ADD 0x00000001
|
||||
#define FAN_MARK_REMOVE 0x00000002
|
||||
#define FAN_MARK_DONT_FOLLOW 0x00000004
|
||||
#define FAN_MARK_ONLYDIR 0x00000008
|
||||
#define FAN_MARK_MOUNT 0x00000010
|
||||
#define FAN_MARK_IGNORED_MASK 0x00000020
|
||||
#define FAN_MARK_IGNORED_SURV_MODIFY 0x00000040
|
||||
#define FAN_MARK_FLUSH 0x00000080
|
||||
|
||||
#define FAN_ALL_MARK_FLAGS (FAN_MARK_ADD |\
|
||||
FAN_MARK_REMOVE |\
|
||||
FAN_MARK_DONT_FOLLOW |\
|
||||
FAN_MARK_ONLYDIR |\
|
||||
FAN_MARK_MOUNT |\
|
||||
FAN_MARK_IGNORED_MASK |\
|
||||
FAN_MARK_IGNORED_SURV_MODIFY |\
|
||||
FAN_MARK_FLUSH)
|
||||
|
||||
/*
|
||||
* All of the events - we build the list by hand so that we can add flags in
|
||||
* the future and not break backward compatibility. Apps will get only the
|
||||
* events that they originally wanted. Be sure to add new events here!
|
||||
*/
|
||||
#define FAN_ALL_EVENTS (FAN_ACCESS |\
|
||||
FAN_MODIFY |\
|
||||
FAN_CLOSE |\
|
||||
FAN_OPEN)
|
||||
|
||||
/*
|
||||
* All events which require a permission response from userspace
|
||||
*/
|
||||
#define FAN_ALL_PERM_EVENTS (FAN_OPEN_PERM |\
|
||||
FAN_ACCESS_PERM)
|
||||
|
||||
#define FAN_ALL_OUTGOING_EVENTS (FAN_ALL_EVENTS |\
|
||||
FAN_ALL_PERM_EVENTS |\
|
||||
FAN_Q_OVERFLOW)
|
||||
|
||||
#define FANOTIFY_METADATA_VERSION 3
|
||||
|
||||
struct fanotify_event_metadata {
|
||||
__u32 event_len;
|
||||
__u8 vers;
|
||||
__u8 reserved;
|
||||
__u16 metadata_len;
|
||||
__u64 mask;
|
||||
__s32 fd;
|
||||
__s32 pid;
|
||||
};
|
||||
|
||||
struct fanotify_response {
|
||||
__s32 fd;
|
||||
__u32 response;
|
||||
};
|
||||
|
||||
/* Legit userspace responses to a _PERM event */
|
||||
#define FAN_ALLOW 0x01
|
||||
#define FAN_DENY 0x02
|
||||
/* No fd set in event */
|
||||
#define FAN_NOFD -1
|
||||
|
||||
/* Helper functions to deal with fanotify_event_metadata buffers */
|
||||
#define FAN_EVENT_METADATA_LEN (sizeof(struct fanotify_event_metadata))
|
||||
|
||||
#define FAN_EVENT_NEXT(meta, len) ((len) -= (meta)->event_len, \
|
||||
(struct fanotify_event_metadata*)(((char *)(meta)) + \
|
||||
(meta)->event_len))
|
||||
|
||||
#define FAN_EVENT_OK(meta, len) ((long)(len) >= (long)FAN_EVENT_METADATA_LEN && \
|
||||
(long)(meta)->event_len >= (long)FAN_EVENT_METADATA_LEN && \
|
||||
(long)(meta)->event_len <= (long)(len))
|
||||
|
||||
#endif /* _LINUX_FANOTIFY_H */
|
||||
39
hal/gonk/nsIRecoveryService.idl
Normal file
39
hal/gonk/nsIRecoveryService.idl
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/* 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 "nsISupports.idl"
|
||||
|
||||
[scriptable, uuid(bc24fb33-a0c1-49ca-aa43-05f167e02fb6)]
|
||||
interface nsIRecoveryService : nsISupports
|
||||
{
|
||||
/**
|
||||
* Possible values of fotaStatus.result. These should stay in sync with
|
||||
* librecovery/librecovery.h
|
||||
*/
|
||||
const long FOTA_UPDATE_UNKNOWN = 0;
|
||||
const long FOTA_UPDATE_FAIL = 1;
|
||||
const long FOTA_UPDATE_SUCCESS = 2;
|
||||
|
||||
/**
|
||||
* Uses recovery to wipe the data and cache partitions. If this call is
|
||||
* successful, the device should reboot before the function call ever returns.
|
||||
*
|
||||
* @throws NS_ERROR_FAILURE when rebooting into recovery fails for some reason.
|
||||
*/
|
||||
void factoryReset(in string reason);
|
||||
|
||||
/**
|
||||
* Use recovery to install an OTA update.zip. If this call is
|
||||
* successful, the device should reboot before the function call ever returns.
|
||||
*
|
||||
* @throws NS_ERROR_FAILURE when rebooting into recovery fails for some reason.
|
||||
*/
|
||||
void installFotaUpdate(in string updatePath);
|
||||
|
||||
/**
|
||||
* @return The status of the last FOTA update. One of FOTA_UPDATE_UNKNOWN,
|
||||
* FOTA_UPDATE_FAIL, FOTA_UPDATE_SUCCESS.
|
||||
*/
|
||||
long getFotaUpdateStatus();
|
||||
};
|
||||
484
hal/gonk/tavarua.h
Normal file
484
hal/gonk/tavarua.h
Normal file
|
|
@ -0,0 +1,484 @@
|
|||
#ifndef __LINUX_TAVARUA_H
|
||||
#define __LINUX_TAVARUA_H
|
||||
|
||||
/* This is a Linux header generated by "make headers_install" */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
|
||||
#undef FM_DEBUG
|
||||
|
||||
/* constants */
|
||||
#define RDS_BLOCKS_NUM (4)
|
||||
#define BYTES_PER_BLOCK (3)
|
||||
#define MAX_PS_LENGTH (96)
|
||||
#define MAX_RT_LENGTH (64)
|
||||
|
||||
#define XFRDAT0 (0x20)
|
||||
#define XFRDAT1 (0x21)
|
||||
#define XFRDAT2 (0x22)
|
||||
|
||||
#define INTDET_PEEK_MSB (0x88)
|
||||
#define INTDET_PEEK_LSB (0x26)
|
||||
|
||||
#define RMSSI_PEEK_MSB (0x88)
|
||||
#define RMSSI_PEEK_LSB (0xA8)
|
||||
|
||||
#define MPX_DCC_BYPASS_POKE_MSB (0x88)
|
||||
#define MPX_DCC_BYPASS_POKE_LSB (0xC0)
|
||||
|
||||
#define MPX_DCC_PEEK_MSB_REG1 (0x88)
|
||||
#define MPX_DCC_PEEK_LSB_REG1 (0xC2)
|
||||
|
||||
#define MPX_DCC_PEEK_MSB_REG2 (0x88)
|
||||
#define MPX_DCC_PEEK_LSB_REG2 (0xC3)
|
||||
|
||||
#define MPX_DCC_PEEK_MSB_REG3 (0x88)
|
||||
#define MPX_DCC_PEEK_LSB_REG3 (0xC4)
|
||||
|
||||
#define ON_CHANNEL_TH_MSB (0x0B)
|
||||
#define ON_CHANNEL_TH_LSB (0xA8)
|
||||
|
||||
#define OFF_CHANNEL_TH_MSB (0x0B)
|
||||
#define OFF_CHANNEL_TH_LSB (0xAC)
|
||||
|
||||
#define ENF_200Khz (1)
|
||||
#define SRCH200KHZ_OFFSET (7)
|
||||
#define SRCH_MASK (1 << SRCH200KHZ_OFFSET)
|
||||
|
||||
/* Standard buffer size */
|
||||
#define STD_BUF_SIZE (128)
|
||||
/* Search direction */
|
||||
#define SRCH_DIR_UP (0)
|
||||
#define SRCH_DIR_DOWN (1)
|
||||
|
||||
/* control options */
|
||||
#define CTRL_ON (1)
|
||||
#define CTRL_OFF (0)
|
||||
|
||||
#define US_LOW_BAND (87.5)
|
||||
#define US_HIGH_BAND (108)
|
||||
|
||||
/* constant for Tx */
|
||||
|
||||
#define MASK_PI (0x0000FFFF)
|
||||
#define MASK_PI_MSB (0x0000FF00)
|
||||
#define MASK_PI_LSB (0x000000FF)
|
||||
#define MASK_PTY (0x0000001F)
|
||||
#define MASK_TXREPCOUNT (0x0000000F)
|
||||
|
||||
#undef FMDBG
|
||||
#ifdef FM_DEBUG
|
||||
#define FMDBG(fmt, args...) printk(KERN_INFO "tavarua_radio: " fmt, ##args)
|
||||
#else
|
||||
#define FMDBG(fmt, args...)
|
||||
#endif
|
||||
|
||||
#undef FMDERR
|
||||
#define FMDERR(fmt, args...) printk(KERN_INFO "tavarua_radio: " fmt, ##args)
|
||||
|
||||
#undef FMDBG_I2C
|
||||
#ifdef FM_DEBUG_I2C
|
||||
#define FMDBG_I2C(fmt, args...) printk(KERN_INFO "fm_i2c: " fmt, ##args)
|
||||
#else
|
||||
#define FMDBG_I2C(fmt, args...)
|
||||
#endif
|
||||
|
||||
/* function declarations */
|
||||
/* FM Core audio paths. */
|
||||
#define TAVARUA_AUDIO_OUT_ANALOG_OFF (0)
|
||||
#define TAVARUA_AUDIO_OUT_ANALOG_ON (1)
|
||||
#define TAVARUA_AUDIO_OUT_DIGITAL_OFF (0)
|
||||
#define TAVARUA_AUDIO_OUT_DIGITAL_ON (1)
|
||||
|
||||
int tavarua_set_audio_path(int digital_on, int analog_on);
|
||||
|
||||
/* defines and enums*/
|
||||
|
||||
#define MARIMBA_A0 0x01010013
|
||||
#define MARIMBA_2_1 0x02010204
|
||||
#define BAHAMA_1_0 0x0302010A
|
||||
#define BAHAMA_2_0 0x04020205
|
||||
#define WAIT_TIMEOUT 2000
|
||||
#define RADIO_INIT_TIME 15
|
||||
#define TAVARUA_DELAY 10
|
||||
/*
|
||||
* The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW,
|
||||
* 62.5 kHz otherwise.
|
||||
* The tuner is able to have a channel spacing of 50, 100 or 200 kHz.
|
||||
* tuner->capability is therefore set to V4L2_TUNER_CAP_LOW
|
||||
* The FREQ_MUL is then: 1 MHz / 62.5 Hz = 16000
|
||||
*/
|
||||
#define FREQ_MUL (1000000 / 62.5)
|
||||
|
||||
enum v4l2_cid_private_tavarua_t {
|
||||
V4L2_CID_PRIVATE_TAVARUA_SRCHMODE = (V4L2_CID_PRIVATE_BASE + 1),
|
||||
V4L2_CID_PRIVATE_TAVARUA_SCANDWELL,
|
||||
V4L2_CID_PRIVATE_TAVARUA_SRCHON,
|
||||
V4L2_CID_PRIVATE_TAVARUA_STATE,
|
||||
V4L2_CID_PRIVATE_TAVARUA_TRANSMIT_MODE,
|
||||
V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK,
|
||||
V4L2_CID_PRIVATE_TAVARUA_REGION,
|
||||
V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH,
|
||||
V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY,
|
||||
V4L2_CID_PRIVATE_TAVARUA_SRCH_PI,
|
||||
V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT,
|
||||
V4L2_CID_PRIVATE_TAVARUA_EMPHASIS,
|
||||
V4L2_CID_PRIVATE_TAVARUA_RDS_STD,
|
||||
V4L2_CID_PRIVATE_TAVARUA_SPACING,
|
||||
V4L2_CID_PRIVATE_TAVARUA_RDSON,
|
||||
V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC,
|
||||
V4L2_CID_PRIVATE_TAVARUA_LP_MODE,
|
||||
V4L2_CID_PRIVATE_TAVARUA_ANTENNA,
|
||||
V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF,
|
||||
V4L2_CID_PRIVATE_TAVARUA_PSALL,
|
||||
/*v4l2 Tx controls*/
|
||||
V4L2_CID_PRIVATE_TAVARUA_TX_SETPSREPEATCOUNT,
|
||||
V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_PS_NAME,
|
||||
V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_RT,
|
||||
V4L2_CID_PRIVATE_TAVARUA_IOVERC,
|
||||
V4L2_CID_PRIVATE_TAVARUA_INTDET,
|
||||
V4L2_CID_PRIVATE_TAVARUA_MPX_DCC,
|
||||
V4L2_CID_PRIVATE_TAVARUA_AF_JUMP,
|
||||
V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA,
|
||||
V4L2_CID_PRIVATE_TAVARUA_HLSI,
|
||||
|
||||
/*
|
||||
* Here we have IOCTl's that are specific to IRIS
|
||||
* (V4L2_CID_PRIVATE_BASE + 0x1E to V4L2_CID_PRIVATE_BASE + 0x28)
|
||||
*/
|
||||
V4L2_CID_PRIVATE_SOFT_MUTE,/* 0x800001E*/
|
||||
V4L2_CID_PRIVATE_RIVA_ACCS_ADDR,
|
||||
V4L2_CID_PRIVATE_RIVA_ACCS_LEN,
|
||||
V4L2_CID_PRIVATE_RIVA_PEEK,
|
||||
V4L2_CID_PRIVATE_RIVA_POKE,
|
||||
V4L2_CID_PRIVATE_SSBI_ACCS_ADDR,
|
||||
V4L2_CID_PRIVATE_SSBI_PEEK,
|
||||
V4L2_CID_PRIVATE_SSBI_POKE,
|
||||
V4L2_CID_PRIVATE_TX_TONE,
|
||||
V4L2_CID_PRIVATE_RDS_GRP_COUNTERS,
|
||||
V4L2_CID_PRIVATE_SET_NOTCH_FILTER,/* 0x8000028 */
|
||||
|
||||
V4L2_CID_PRIVATE_TAVARUA_SET_AUDIO_PATH,/* 0x8000029 */
|
||||
V4L2_CID_PRIVATE_TAVARUA_DO_CALIBRATION,/* 0x800002A : IRIS */
|
||||
V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM,/* 0x800002B */
|
||||
V4L2_CID_PRIVATE_IRIS_GET_SINR, /* 0x800002C : IRIS */
|
||||
V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD, /* 0x800002D */
|
||||
V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD, /* 0x800002E */
|
||||
V4L2_CID_PRIVATE_SINR_THRESHOLD, /* 0x800002F : IRIS */
|
||||
V4L2_CID_PRIVATE_SINR_SAMPLES, /* 0x8000030 : IRIS */
|
||||
|
||||
};
|
||||
|
||||
enum tavarua_buf_t {
|
||||
TAVARUA_BUF_SRCH_LIST,
|
||||
TAVARUA_BUF_EVENTS,
|
||||
TAVARUA_BUF_RT_RDS,
|
||||
TAVARUA_BUF_PS_RDS,
|
||||
TAVARUA_BUF_RAW_RDS,
|
||||
TAVARUA_BUF_AF_LIST,
|
||||
TAVARUA_BUF_MAX
|
||||
};
|
||||
|
||||
enum tavarua_xfr_t {
|
||||
TAVARUA_XFR_SYNC,
|
||||
TAVARUA_XFR_ERROR,
|
||||
TAVARUA_XFR_SRCH_LIST,
|
||||
TAVARUA_XFR_RT_RDS,
|
||||
TAVARUA_XFR_PS_RDS,
|
||||
TAVARUA_XFR_AF_LIST,
|
||||
TAVARUA_XFR_MAX
|
||||
};
|
||||
|
||||
enum channel_spacing {
|
||||
FM_CH_SPACE_200KHZ,
|
||||
FM_CH_SPACE_100KHZ,
|
||||
FM_CH_SPACE_50KHZ
|
||||
};
|
||||
|
||||
enum step_size {
|
||||
NO_SRCH200khz,
|
||||
ENF_SRCH200khz
|
||||
};
|
||||
|
||||
enum emphasis {
|
||||
EMP_75,
|
||||
EMP_50
|
||||
};
|
||||
|
||||
enum rds_std {
|
||||
RBDS_STD,
|
||||
RDS_STD
|
||||
};
|
||||
|
||||
/* offsets */
|
||||
#define RAW_RDS 0x0F
|
||||
#define RDS_BLOCK 3
|
||||
|
||||
/* registers*/
|
||||
#define MARIMBA_XO_BUFF_CNTRL 0x07
|
||||
#define RADIO_REGISTERS 0x30
|
||||
#define XFR_REG_NUM 16
|
||||
#define STATUS_REG_NUM 3
|
||||
|
||||
/* TX constants */
|
||||
#define HEADER_SIZE 4
|
||||
#define TX_ON 0x80
|
||||
#define TAVARUA_TX_RT RDS_RT_0
|
||||
#define TAVARUA_TX_PS RDS_PS_0
|
||||
|
||||
enum register_t {
|
||||
STATUS_REG1 = 0,
|
||||
STATUS_REG2,
|
||||
STATUS_REG3,
|
||||
RDCTRL,
|
||||
FREQ,
|
||||
TUNECTRL,
|
||||
SRCHRDS1,
|
||||
SRCHRDS2,
|
||||
SRCHCTRL,
|
||||
IOCTRL,
|
||||
RDSCTRL,
|
||||
ADVCTRL,
|
||||
AUDIOCTRL,
|
||||
RMSSI,
|
||||
IOVERC,
|
||||
AUDIOIND = 0x1E,
|
||||
XFRCTRL,
|
||||
FM_CTL0 = 0xFF,
|
||||
LEAKAGE_CNTRL = 0xFE,
|
||||
};
|
||||
#define BAHAMA_RBIAS_CTL1 0x07
|
||||
#define BAHAMA_FM_MODE_REG 0xFD
|
||||
#define BAHAMA_FM_CTL1_REG 0xFE
|
||||
#define BAHAMA_FM_CTL0_REG 0xFF
|
||||
#define BAHAMA_FM_MODE_NORMAL 0x00
|
||||
#define BAHAMA_LDO_DREG_CTL0 0xF0
|
||||
#define BAHAMA_LDO_AREG_CTL0 0xF4
|
||||
|
||||
/* Radio Control */
|
||||
#define RDCTRL_STATE_OFFSET 0
|
||||
#define RDCTRL_STATE_MASK (3 << RDCTRL_STATE_OFFSET)
|
||||
#define RDCTRL_BAND_OFFSET 2
|
||||
#define RDCTRL_BAND_MASK (1 << RDCTRL_BAND_OFFSET)
|
||||
#define RDCTRL_CHSPACE_OFFSET 3
|
||||
#define RDCTRL_CHSPACE_MASK (3 << RDCTRL_CHSPACE_OFFSET)
|
||||
#define RDCTRL_DEEMPHASIS_OFFSET 5
|
||||
#define RDCTRL_DEEMPHASIS_MASK (1 << RDCTRL_DEEMPHASIS_OFFSET)
|
||||
#define RDCTRL_HLSI_OFFSET 6
|
||||
#define RDCTRL_HLSI_MASK (3 << RDCTRL_HLSI_OFFSET)
|
||||
#define RDSAF_OFFSET 6
|
||||
#define RDSAF_MASK (1 << RDSAF_OFFSET)
|
||||
|
||||
/* Tune Control */
|
||||
#define TUNE_STATION 0x01
|
||||
#define ADD_OFFSET (1 << 1)
|
||||
#define SIGSTATE (1 << 5)
|
||||
#define MOSTSTATE (1 << 6)
|
||||
#define RDSSYNC (1 << 7)
|
||||
/* Search Control */
|
||||
#define SRCH_MODE_OFFSET 0
|
||||
#define SRCH_MODE_MASK (7 << SRCH_MODE_OFFSET)
|
||||
#define SRCH_DIR_OFFSET 3
|
||||
#define SRCH_DIR_MASK (1 << SRCH_DIR_OFFSET)
|
||||
#define SRCH_DWELL_OFFSET 4
|
||||
#define SRCH_DWELL_MASK (7 << SRCH_DWELL_OFFSET)
|
||||
#define SRCH_STATE_OFFSET 7
|
||||
#define SRCH_STATE_MASK (1 << SRCH_STATE_OFFSET)
|
||||
|
||||
/* I/O Control */
|
||||
#define IOC_HRD_MUTE 0x03
|
||||
#define IOC_SFT_MUTE (1 << 2)
|
||||
#define IOC_MON_STR (1 << 3)
|
||||
#define IOC_SIG_BLND (1 << 4)
|
||||
#define IOC_INTF_BLND (1 << 5)
|
||||
#define IOC_ANTENNA (1 << 6)
|
||||
#define IOC_ANTENNA_OFFSET 6
|
||||
#define IOC_ANTENNA_MASK (1 << IOC_ANTENNA_OFFSET)
|
||||
|
||||
/* RDS Control */
|
||||
#define RDS_ON 0x01
|
||||
#define RDSCTRL_STANDARD_OFFSET 1
|
||||
#define RDSCTRL_STANDARD_MASK (1 << RDSCTRL_STANDARD_OFFSET)
|
||||
|
||||
/* Advanced features controls */
|
||||
#define RDSRTEN (1 << 3)
|
||||
#define RDSPSEN (1 << 4)
|
||||
|
||||
/* Audio path control */
|
||||
#define AUDIORX_ANALOG_OFFSET 0
|
||||
#define AUDIORX_ANALOG_MASK (1 << AUDIORX_ANALOG_OFFSET)
|
||||
#define AUDIORX_DIGITAL_OFFSET 1
|
||||
#define AUDIORX_DIGITAL_MASK (1 << AUDIORX_DIGITAL_OFFSET)
|
||||
#define AUDIOTX_OFFSET 2
|
||||
#define AUDIOTX_MASK (1 << AUDIOTX_OFFSET)
|
||||
#define I2SCTRL_OFFSET 3
|
||||
#define I2SCTRL_MASK (1 << I2SCTRL_OFFSET)
|
||||
|
||||
/* Search options */
|
||||
enum search_t {
|
||||
SEEK,
|
||||
SCAN,
|
||||
SCAN_FOR_STRONG,
|
||||
SCAN_FOR_WEAK,
|
||||
RDS_SEEK_PTY,
|
||||
RDS_SCAN_PTY,
|
||||
RDS_SEEK_PI,
|
||||
RDS_AF_JUMP,
|
||||
};
|
||||
|
||||
enum audio_path {
|
||||
FM_DIGITAL_PATH,
|
||||
FM_ANALOG_PATH
|
||||
};
|
||||
#define SRCH_MODE 0x07
|
||||
#define SRCH_DIR 0x08 /* 0-up 1-down */
|
||||
#define SCAN_DWELL 0x70
|
||||
#define SRCH_ON 0x80
|
||||
|
||||
/* RDS CONFIG */
|
||||
#define RDS_CONFIG_PSALL 0x01
|
||||
|
||||
#define FM_ENABLE 0x22
|
||||
#define SET_REG_FIELD(reg, val, offset, mask) \
|
||||
(reg = (reg & ~mask) | (((val) << offset) & mask))
|
||||
#define GET_REG_FIELD(reg, offset, mask) ((reg & mask) >> offset)
|
||||
#define RSH_DATA(val, offset) ((val) >> (offset))
|
||||
#define LSH_DATA(val, offset) ((val) << (offset))
|
||||
#define GET_ABS_VAL(val) ((val) & (0xFF))
|
||||
|
||||
enum radio_state_t {
|
||||
FM_OFF,
|
||||
FM_RECV,
|
||||
FM_TRANS,
|
||||
FM_RESET,
|
||||
};
|
||||
|
||||
#define XFRCTRL_WRITE (1 << 7)
|
||||
|
||||
/* Interrupt status */
|
||||
|
||||
/* interrupt register 1 */
|
||||
#define READY (1 << 0) /* Radio ready after powerup or reset */
|
||||
#define TUNE (1 << 1) /* Tune completed */
|
||||
#define SEARCH (1 << 2) /* Search completed (read FREQ) */
|
||||
#define SCANNEXT (1 << 3) /* Scanning for next station */
|
||||
#define SIGNAL (1 << 4) /* Signal indicator change (read SIGSTATE) */
|
||||
#define INTF (1 << 5) /* Interference cnt has fallen outside range */
|
||||
#define SYNC (1 << 6) /* RDS sync state change (read RDSSYNC) */
|
||||
#define AUDIO (1 << 7) /* Audio Control indicator (read AUDIOIND) */
|
||||
|
||||
/* interrupt register 2 */
|
||||
#define RDSDAT (1 << 0) /* New unread RDS data group available */
|
||||
#define BLOCKB (1 << 1) /* Block-B match condition exists */
|
||||
#define PROGID (1 << 2) /* Block-A or Block-C matched stored PI value*/
|
||||
#define RDSPS (1 << 3) /* New RDS Program Service Table available */
|
||||
#define RDSRT (1 << 4) /* New RDS Radio Text available */
|
||||
#define RDSAF (1 << 5) /* New RDS AF List available */
|
||||
#define TXRDSDAT (1 << 6) /* Transmitted an RDS group */
|
||||
#define TXRDSDONE (1 << 7) /* RDS raw group one-shot transmit completed */
|
||||
|
||||
/* interrupt register 3 */
|
||||
#define TRANSFER (1 << 0) /* Data transfer (XFR) completed */
|
||||
#define RDSPROC (1 << 1) /* Dynamic RDS Processing complete */
|
||||
#define ERROR (1 << 7) /* Err occurred.Read code to determine cause */
|
||||
|
||||
|
||||
#define FM_TX_PWR_LVL_0 0 /* Lowest power lvl that can be set for Tx */
|
||||
#define FM_TX_PWR_LVL_MAX 7 /* Max power lvl for Tx */
|
||||
/* Transfer */
|
||||
enum tavarua_xfr_ctrl_t {
|
||||
RDS_PS_0 = 0x01,
|
||||
RDS_PS_1,
|
||||
RDS_PS_2,
|
||||
RDS_PS_3,
|
||||
RDS_PS_4,
|
||||
RDS_PS_5,
|
||||
RDS_PS_6,
|
||||
RDS_RT_0,
|
||||
RDS_RT_1,
|
||||
RDS_RT_2,
|
||||
RDS_RT_3,
|
||||
RDS_RT_4,
|
||||
RDS_AF_0,
|
||||
RDS_AF_1,
|
||||
RDS_CONFIG,
|
||||
RDS_TX_GROUPS,
|
||||
RDS_COUNT_0,
|
||||
RDS_COUNT_1,
|
||||
RDS_COUNT_2,
|
||||
RADIO_CONFIG,
|
||||
RX_CONFIG,
|
||||
RX_TIMERS,
|
||||
RX_STATIONS_0,
|
||||
RX_STATIONS_1,
|
||||
INT_CTRL,
|
||||
ERROR_CODE,
|
||||
CHIPID,
|
||||
CAL_DAT_0 = 0x20,
|
||||
CAL_DAT_1,
|
||||
CAL_DAT_2,
|
||||
CAL_DAT_3,
|
||||
CAL_CFG_0,
|
||||
CAL_CFG_1,
|
||||
DIG_INTF_0,
|
||||
DIG_INTF_1,
|
||||
DIG_AGC_0,
|
||||
DIG_AGC_1,
|
||||
DIG_AGC_2,
|
||||
DIG_AUDIO_0,
|
||||
DIG_AUDIO_1,
|
||||
DIG_AUDIO_2,
|
||||
DIG_AUDIO_3,
|
||||
DIG_AUDIO_4,
|
||||
DIG_RXRDS,
|
||||
DIG_DCC,
|
||||
DIG_SPUR,
|
||||
DIG_MPXDCC,
|
||||
DIG_PILOT,
|
||||
DIG_DEMOD,
|
||||
DIG_MOST,
|
||||
DIG_TX_0,
|
||||
DIG_TX_1,
|
||||
PHY_TXGAIN = 0x3B,
|
||||
PHY_CONFIG,
|
||||
PHY_TXBLOCK,
|
||||
PHY_TCB,
|
||||
XFR_PEEK_MODE = 0x40,
|
||||
XFR_POKE_MODE = 0xC0,
|
||||
TAVARUA_XFR_CTRL_MAX
|
||||
};
|
||||
|
||||
enum tavarua_evt_t {
|
||||
TAVARUA_EVT_RADIO_READY,
|
||||
TAVARUA_EVT_TUNE_SUCC,
|
||||
TAVARUA_EVT_SEEK_COMPLETE,
|
||||
TAVARUA_EVT_SCAN_NEXT,
|
||||
TAVARUA_EVT_NEW_RAW_RDS,
|
||||
TAVARUA_EVT_NEW_RT_RDS,
|
||||
TAVARUA_EVT_NEW_PS_RDS,
|
||||
TAVARUA_EVT_ERROR,
|
||||
TAVARUA_EVT_BELOW_TH,
|
||||
TAVARUA_EVT_ABOVE_TH,
|
||||
TAVARUA_EVT_STEREO,
|
||||
TAVARUA_EVT_MONO,
|
||||
TAVARUA_EVT_RDS_AVAIL,
|
||||
TAVARUA_EVT_RDS_NOT_AVAIL,
|
||||
TAVARUA_EVT_NEW_SRCH_LIST,
|
||||
TAVARUA_EVT_NEW_AF_LIST,
|
||||
TAVARUA_EVT_TXRDSDAT,
|
||||
TAVARUA_EVT_TXRDSDONE,
|
||||
TAVARUA_EVT_RADIO_DISABLED
|
||||
};
|
||||
|
||||
enum tavarua_region_t {
|
||||
TAVARUA_REGION_US,
|
||||
TAVARUA_REGION_EU,
|
||||
TAVARUA_REGION_JAPAN,
|
||||
TAVARUA_REGION_JAPAN_WIDE,
|
||||
TAVARUA_REGION_OTHER
|
||||
};
|
||||
|
||||
#endif /* __LINUX_TAVARUA_H */
|
||||
39
hal/linux/LinuxMemory.cpp
Normal file
39
hal/linux/LinuxMemory.cpp
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=8 et :
|
||||
*/
|
||||
/* 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 <stdio.h>
|
||||
#include "Hal.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
uint32_t
|
||||
GetTotalSystemMemory()
|
||||
{
|
||||
static uint32_t sTotalMemory;
|
||||
static bool sTotalMemoryObtained = false;
|
||||
|
||||
if (!sTotalMemoryObtained) {
|
||||
sTotalMemoryObtained = true;
|
||||
|
||||
FILE* fd = fopen("/proc/meminfo", "r");
|
||||
if (!fd) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rv = fscanf(fd, "MemTotal: %i kB", &sTotalMemory);
|
||||
|
||||
if (fclose(fd) || rv != 1) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return sTotalMemory * 1024;
|
||||
}
|
||||
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
||||
167
hal/linux/LinuxPower.cpp
Normal file
167
hal/linux/LinuxPower.cpp
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "HalLog.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/reboot.h>
|
||||
#include "nsIObserverService.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "MainThreadUtils.h"
|
||||
|
||||
#if defined(MOZ_WIDGET_GONK)
|
||||
#include "cutils/android_reboot.h"
|
||||
#include "cutils/properties.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
#if (defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 19)
|
||||
static void
|
||||
PowerCtl(const char* aValue, int aCmd)
|
||||
{
|
||||
// this invokes init's powerctl builtin via /init.rc
|
||||
property_set("sys.powerctl", aValue);
|
||||
// device should reboot in few moments, but if it doesn't - call
|
||||
// android_reboot() to make sure that init isn't stuck somewhere
|
||||
sleep(10);
|
||||
HAL_LOG("Powerctl call takes too long, forcing %s.", aValue);
|
||||
android_reboot(aCmd, 0, nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
Reboot()
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
nsCOMPtr<nsIObserverService> obsServ = services::GetObserverService();
|
||||
if (obsServ) {
|
||||
obsServ->NotifyObservers(nullptr, "system-reboot", nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(MOZ_WIDGET_GONK)
|
||||
sync();
|
||||
reboot(RB_AUTOBOOT);
|
||||
#elif (ANDROID_VERSION < 19)
|
||||
android_reboot(ANDROID_RB_RESTART, 0, nullptr);
|
||||
#else
|
||||
PowerCtl("reboot", ANDROID_RB_RESTART);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
PowerOff()
|
||||
{
|
||||
if (NS_IsMainThread()) {
|
||||
nsCOMPtr<nsIObserverService> obsServ = services::GetObserverService();
|
||||
if (obsServ) {
|
||||
obsServ->NotifyObservers(nullptr, "system-power-off", nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(MOZ_WIDGET_GONK)
|
||||
sync();
|
||||
reboot(RB_POWER_OFF);
|
||||
#elif (ANDROID_VERSION < 19)
|
||||
android_reboot(ANDROID_RB_POWEROFF, 0, nullptr);
|
||||
#else
|
||||
PowerCtl("shutdown", ANDROID_RB_POWEROFF);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Structure to specify how watchdog pthread is going to work.
|
||||
typedef struct watchdogParam
|
||||
{
|
||||
hal::ShutdownMode mode; // Specify how to shutdown the system.
|
||||
int32_t timeoutSecs; // Specify the delayed seconds to shutdown the system.
|
||||
|
||||
watchdogParam(hal::ShutdownMode aMode, int32_t aTimeoutSecs)
|
||||
: mode(aMode), timeoutSecs(aTimeoutSecs) {}
|
||||
} watchdogParam_t;
|
||||
|
||||
// Function to complusively shut down the system with a given mode.
|
||||
static void
|
||||
QuitHard(hal::ShutdownMode aMode)
|
||||
{
|
||||
switch (aMode)
|
||||
{
|
||||
case hal::eHalShutdownMode_PowerOff:
|
||||
PowerOff();
|
||||
break;
|
||||
case hal::eHalShutdownMode_Reboot:
|
||||
Reboot();
|
||||
break;
|
||||
case hal::eHalShutdownMode_Restart:
|
||||
// Don't let signal handlers affect forced shutdown.
|
||||
kill(0, SIGKILL);
|
||||
// If we can't SIGKILL our process group, something is badly
|
||||
// wrong. Trying to deliver a catch-able signal to ourselves can
|
||||
// invoke signal handlers and might cause problems. So try
|
||||
// _exit() and hope we go away.
|
||||
_exit(1);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
// Function to complusively shut down the system with a given mode when timeout.
|
||||
static void*
|
||||
ForceQuitWatchdog(void* aParamPtr)
|
||||
{
|
||||
watchdogParam_t* paramPtr = reinterpret_cast<watchdogParam_t*>(aParamPtr);
|
||||
if (paramPtr->timeoutSecs > 0 && paramPtr->timeoutSecs <= 30) {
|
||||
// If we shut down normally before the timeout, this thread will
|
||||
// be harmlessly reaped by the OS.
|
||||
TimeStamp deadline =
|
||||
(TimeStamp::Now() + TimeDuration::FromSeconds(paramPtr->timeoutSecs));
|
||||
while (true) {
|
||||
TimeDuration remaining = (deadline - TimeStamp::Now());
|
||||
int sleepSeconds = int(remaining.ToSeconds());
|
||||
if (sleepSeconds <= 0) {
|
||||
break;
|
||||
}
|
||||
sleep(sleepSeconds);
|
||||
}
|
||||
}
|
||||
hal::ShutdownMode mode = paramPtr->mode;
|
||||
delete paramPtr;
|
||||
QuitHard(mode);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
StartForceQuitWatchdog(hal::ShutdownMode aMode, int32_t aTimeoutSecs)
|
||||
{
|
||||
// Force-quits are intepreted a little more ferociously on Gonk,
|
||||
// because while Gecko is in the process of shutting down, the user
|
||||
// can't call 911, for example. And if we hang on shutdown, bad
|
||||
// things happen. So, make sure that doesn't happen.
|
||||
if (aTimeoutSecs <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Use a raw pthread here to insulate ourselves from bugs in other
|
||||
// Gecko code that we're trying to protect!
|
||||
//
|
||||
// Note that we let the watchdog in charge of releasing |paramPtr|
|
||||
// if the pthread is successfully created.
|
||||
watchdogParam_t* paramPtr = new watchdogParam_t(aMode, aTimeoutSecs);
|
||||
pthread_t watchdog;
|
||||
if (pthread_create(&watchdog, nullptr,
|
||||
ForceQuitWatchdog,
|
||||
reinterpret_cast<void*>(paramPtr))) {
|
||||
// Better safe than sorry.
|
||||
delete paramPtr;
|
||||
QuitHard(aMode);
|
||||
}
|
||||
// The watchdog thread is off and running now.
|
||||
}
|
||||
|
||||
} // hal_impl
|
||||
} // mozilla
|
||||
508
hal/linux/UPowerClient.cpp
Normal file
508
hal/linux/UPowerClient.cpp
Normal file
|
|
@ -0,0 +1,508 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "HalLog.h"
|
||||
#include <dbus/dbus-glib.h>
|
||||
#include <dbus/dbus-glib-lowlevel.h>
|
||||
#include <mozilla/Attributes.h>
|
||||
#include <mozilla/dom/battery/Constants.h>
|
||||
#include "nsAutoRef.h"
|
||||
#include <cmath>
|
||||
|
||||
/*
|
||||
* Helper that manages the destruction of glib objects as soon as they leave
|
||||
* the current scope.
|
||||
*
|
||||
* We are specializing nsAutoRef class.
|
||||
*/
|
||||
|
||||
template <>
|
||||
class nsAutoRefTraits<GHashTable> : public nsPointerRefTraits<GHashTable>
|
||||
{
|
||||
public:
|
||||
static void Release(GHashTable* ptr) { g_hash_table_unref(ptr); }
|
||||
};
|
||||
|
||||
using namespace mozilla::dom::battery;
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
/**
|
||||
* This is the declaration of UPowerClient class. This class is listening and
|
||||
* communicating to upower daemon through DBus.
|
||||
* There is no header file because this class shouldn't be public.
|
||||
*/
|
||||
class UPowerClient
|
||||
{
|
||||
public:
|
||||
static UPowerClient* GetInstance();
|
||||
|
||||
void BeginListening();
|
||||
void StopListening();
|
||||
|
||||
double GetLevel();
|
||||
bool IsCharging();
|
||||
double GetRemainingTime();
|
||||
|
||||
~UPowerClient();
|
||||
|
||||
private:
|
||||
UPowerClient();
|
||||
|
||||
enum States {
|
||||
eState_Unknown = 0,
|
||||
eState_Charging,
|
||||
eState_Discharging,
|
||||
eState_Empty,
|
||||
eState_FullyCharged,
|
||||
eState_PendingCharge,
|
||||
eState_PendingDischarge
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the currently tracked device.
|
||||
* @return whether everything went ok.
|
||||
*/
|
||||
void UpdateTrackedDeviceSync();
|
||||
|
||||
/**
|
||||
* Returns a hash table with the properties of aDevice.
|
||||
* Note: the caller has to unref the hash table.
|
||||
*/
|
||||
GHashTable* GetDevicePropertiesSync(DBusGProxy* aProxy);
|
||||
void GetDevicePropertiesAsync(DBusGProxy* aProxy);
|
||||
static void GetDevicePropertiesCallback(DBusGProxy* aProxy,
|
||||
DBusGProxyCall* aCall,
|
||||
void* aData);
|
||||
|
||||
/**
|
||||
* Using the device properties (aHashTable), this method updates the member
|
||||
* variable storing the values we care about.
|
||||
*/
|
||||
void UpdateSavedInfo(GHashTable* aHashTable);
|
||||
|
||||
/**
|
||||
* Callback used by 'DeviceChanged' signal.
|
||||
*/
|
||||
static void DeviceChanged(DBusGProxy* aProxy, const gchar* aObjectPath,
|
||||
UPowerClient* aListener);
|
||||
|
||||
/**
|
||||
* Callback used by 'PropertiesChanged' signal.
|
||||
* This method is called when the the battery level changes.
|
||||
* (Only with upower >= 0.99)
|
||||
*/
|
||||
static void PropertiesChanged(DBusGProxy* aProxy, const gchar*,
|
||||
GHashTable*, char**,
|
||||
UPowerClient* aListener);
|
||||
|
||||
/**
|
||||
* Callback called when mDBusConnection gets a signal.
|
||||
*/
|
||||
static DBusHandlerResult ConnectionSignalFilter(DBusConnection* aConnection,
|
||||
DBusMessage* aMessage,
|
||||
void* aData);
|
||||
|
||||
// The DBus connection object.
|
||||
DBusGConnection* mDBusConnection;
|
||||
|
||||
// The DBus proxy object to upower.
|
||||
DBusGProxy* mUPowerProxy;
|
||||
|
||||
// The path of the tracked device.
|
||||
gchar* mTrackedDevice;
|
||||
|
||||
// The DBusGProxy for the tracked device.
|
||||
DBusGProxy* mTrackedDeviceProxy;
|
||||
|
||||
double mLevel;
|
||||
bool mCharging;
|
||||
double mRemainingTime;
|
||||
|
||||
static UPowerClient* sInstance;
|
||||
|
||||
static const guint sDeviceTypeBattery = 2;
|
||||
static const guint64 kUPowerUnknownRemainingTime = 0;
|
||||
};
|
||||
|
||||
/*
|
||||
* Implementation of mozilla::hal_impl::EnableBatteryNotifications,
|
||||
* mozilla::hal_impl::DisableBatteryNotifications,
|
||||
* and mozilla::hal_impl::GetCurrentBatteryInformation.
|
||||
*/
|
||||
|
||||
void
|
||||
EnableBatteryNotifications()
|
||||
{
|
||||
UPowerClient::GetInstance()->BeginListening();
|
||||
}
|
||||
|
||||
void
|
||||
DisableBatteryNotifications()
|
||||
{
|
||||
UPowerClient::GetInstance()->StopListening();
|
||||
}
|
||||
|
||||
void
|
||||
GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
|
||||
{
|
||||
UPowerClient* upowerClient = UPowerClient::GetInstance();
|
||||
|
||||
aBatteryInfo->level() = upowerClient->GetLevel();
|
||||
aBatteryInfo->charging() = upowerClient->IsCharging();
|
||||
aBatteryInfo->remainingTime() = upowerClient->GetRemainingTime();
|
||||
}
|
||||
|
||||
/*
|
||||
* Following is the implementation of UPowerClient.
|
||||
*/
|
||||
|
||||
UPowerClient* UPowerClient::sInstance = nullptr;
|
||||
|
||||
/* static */ UPowerClient*
|
||||
UPowerClient::GetInstance()
|
||||
{
|
||||
if (!sInstance) {
|
||||
sInstance = new UPowerClient();
|
||||
}
|
||||
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
UPowerClient::UPowerClient()
|
||||
: mDBusConnection(nullptr)
|
||||
, mUPowerProxy(nullptr)
|
||||
, mTrackedDevice(nullptr)
|
||||
, mTrackedDeviceProxy(nullptr)
|
||||
, mLevel(kDefaultLevel)
|
||||
, mCharging(kDefaultCharging)
|
||||
, mRemainingTime(kDefaultRemainingTime)
|
||||
{
|
||||
}
|
||||
|
||||
UPowerClient::~UPowerClient()
|
||||
{
|
||||
NS_ASSERTION(!mDBusConnection && !mUPowerProxy && !mTrackedDevice && !mTrackedDeviceProxy,
|
||||
"The observers have not been correctly removed! "
|
||||
"(StopListening should have been called)");
|
||||
}
|
||||
|
||||
void
|
||||
UPowerClient::BeginListening()
|
||||
{
|
||||
GError* error = nullptr;
|
||||
mDBusConnection = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error);
|
||||
|
||||
if (!mDBusConnection) {
|
||||
HAL_LOG("Failed to open connection to bus: %s\n", error->message);
|
||||
g_error_free(error);
|
||||
return;
|
||||
}
|
||||
|
||||
DBusConnection* dbusConnection =
|
||||
dbus_g_connection_get_connection(mDBusConnection);
|
||||
|
||||
// Make sure we do not exit the entire program if DBus connection get lost.
|
||||
dbus_connection_set_exit_on_disconnect(dbusConnection, false);
|
||||
|
||||
// Listening to signals the DBus connection is going to get so we will know
|
||||
// when it is lost and we will be able to disconnect cleanly.
|
||||
dbus_connection_add_filter(dbusConnection, ConnectionSignalFilter, this,
|
||||
nullptr);
|
||||
|
||||
mUPowerProxy = dbus_g_proxy_new_for_name(mDBusConnection,
|
||||
"org.freedesktop.UPower",
|
||||
"/org/freedesktop/UPower",
|
||||
"org.freedesktop.UPower");
|
||||
|
||||
UpdateTrackedDeviceSync();
|
||||
|
||||
/*
|
||||
* TODO: we should probably listen to DeviceAdded and DeviceRemoved signals.
|
||||
* If we do that, we would have to disconnect from those in StopListening.
|
||||
* It's not yet implemented because it requires testing hot plugging and
|
||||
* removal of a battery.
|
||||
*/
|
||||
dbus_g_proxy_add_signal(mUPowerProxy, "DeviceChanged", G_TYPE_STRING,
|
||||
G_TYPE_INVALID);
|
||||
dbus_g_proxy_connect_signal(mUPowerProxy, "DeviceChanged",
|
||||
G_CALLBACK (DeviceChanged), this, nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
UPowerClient::StopListening()
|
||||
{
|
||||
// If mDBusConnection isn't initialized, that means we are not really listening.
|
||||
if (!mDBusConnection) {
|
||||
return;
|
||||
}
|
||||
|
||||
dbus_connection_remove_filter(
|
||||
dbus_g_connection_get_connection(mDBusConnection),
|
||||
ConnectionSignalFilter, this);
|
||||
|
||||
dbus_g_proxy_disconnect_signal(mUPowerProxy, "DeviceChanged",
|
||||
G_CALLBACK (DeviceChanged), this);
|
||||
|
||||
g_free(mTrackedDevice);
|
||||
mTrackedDevice = nullptr;
|
||||
|
||||
if (mTrackedDeviceProxy) {
|
||||
dbus_g_proxy_disconnect_signal(mTrackedDeviceProxy, "PropertiesChanged",
|
||||
G_CALLBACK (PropertiesChanged), this);
|
||||
|
||||
g_object_unref(mTrackedDeviceProxy);
|
||||
mTrackedDeviceProxy = nullptr;
|
||||
}
|
||||
|
||||
g_object_unref(mUPowerProxy);
|
||||
mUPowerProxy = nullptr;
|
||||
|
||||
dbus_g_connection_unref(mDBusConnection);
|
||||
mDBusConnection = nullptr;
|
||||
|
||||
// We should now show the default values, not the latest we got.
|
||||
mLevel = kDefaultLevel;
|
||||
mCharging = kDefaultCharging;
|
||||
mRemainingTime = kDefaultRemainingTime;
|
||||
}
|
||||
|
||||
void
|
||||
UPowerClient::UpdateTrackedDeviceSync()
|
||||
{
|
||||
GType typeGPtrArray = dbus_g_type_get_collection("GPtrArray",
|
||||
DBUS_TYPE_G_OBJECT_PATH);
|
||||
GPtrArray* devices = nullptr;
|
||||
GError* error = nullptr;
|
||||
|
||||
// Reset the current tracked device:
|
||||
g_free(mTrackedDevice);
|
||||
mTrackedDevice = nullptr;
|
||||
|
||||
// Reset the current tracked device proxy:
|
||||
if (mTrackedDeviceProxy) {
|
||||
dbus_g_proxy_disconnect_signal(mTrackedDeviceProxy, "PropertiesChanged",
|
||||
G_CALLBACK (PropertiesChanged), this);
|
||||
|
||||
g_object_unref(mTrackedDeviceProxy);
|
||||
mTrackedDeviceProxy = nullptr;
|
||||
}
|
||||
|
||||
// If that fails, that likely means upower isn't installed.
|
||||
if (!dbus_g_proxy_call(mUPowerProxy, "EnumerateDevices", &error, G_TYPE_INVALID,
|
||||
typeGPtrArray, &devices, G_TYPE_INVALID)) {
|
||||
HAL_LOG("Error: %s\n", error->message);
|
||||
g_error_free(error);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* We are looking for the first device that is a battery.
|
||||
* TODO: we could try to combine more than one battery.
|
||||
*/
|
||||
for (guint i=0; i<devices->len; ++i) {
|
||||
gchar* devicePath = static_cast<gchar*>(g_ptr_array_index(devices, i));
|
||||
|
||||
DBusGProxy* proxy = dbus_g_proxy_new_from_proxy(mUPowerProxy,
|
||||
"org.freedesktop.DBus.Properties",
|
||||
devicePath);
|
||||
|
||||
nsAutoRef<GHashTable> hashTable(GetDevicePropertiesSync(proxy));
|
||||
|
||||
if (g_value_get_uint(static_cast<const GValue*>(g_hash_table_lookup(hashTable, "Type"))) == sDeviceTypeBattery) {
|
||||
UpdateSavedInfo(hashTable);
|
||||
mTrackedDevice = devicePath;
|
||||
mTrackedDeviceProxy = proxy;
|
||||
break;
|
||||
}
|
||||
|
||||
g_object_unref(proxy);
|
||||
g_free(devicePath);
|
||||
}
|
||||
|
||||
if (mTrackedDeviceProxy) {
|
||||
dbus_g_proxy_add_signal(mTrackedDeviceProxy, "PropertiesChanged",
|
||||
G_TYPE_STRING,
|
||||
dbus_g_type_get_map("GHashTable", G_TYPE_STRING,
|
||||
G_TYPE_VALUE),
|
||||
G_TYPE_STRV, G_TYPE_INVALID);
|
||||
dbus_g_proxy_connect_signal(mTrackedDeviceProxy, "PropertiesChanged",
|
||||
G_CALLBACK (PropertiesChanged), this, nullptr);
|
||||
}
|
||||
|
||||
g_ptr_array_free(devices, true);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
UPowerClient::DeviceChanged(DBusGProxy* aProxy, const gchar* aObjectPath,
|
||||
UPowerClient* aListener)
|
||||
{
|
||||
if (!aListener->mTrackedDevice) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if GLIB_MAJOR_VERSION >= 2 && GLIB_MINOR_VERSION >= 16
|
||||
if (g_strcmp0(aObjectPath, aListener->mTrackedDevice)) {
|
||||
#else
|
||||
if (g_ascii_strcasecmp(aObjectPath, aListener->mTrackedDevice)) {
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
aListener->GetDevicePropertiesAsync(aListener->mTrackedDeviceProxy);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
UPowerClient::PropertiesChanged(DBusGProxy* aProxy, const gchar*, GHashTable*,
|
||||
char**, UPowerClient* aListener)
|
||||
{
|
||||
aListener->GetDevicePropertiesAsync(aListener->mTrackedDeviceProxy);
|
||||
}
|
||||
|
||||
/* static */ DBusHandlerResult
|
||||
UPowerClient::ConnectionSignalFilter(DBusConnection* aConnection,
|
||||
DBusMessage* aMessage, void* aData)
|
||||
{
|
||||
if (dbus_message_is_signal(aMessage, DBUS_INTERFACE_LOCAL, "Disconnected")) {
|
||||
static_cast<UPowerClient*>(aData)->StopListening();
|
||||
// We do not return DBUS_HANDLER_RESULT_HANDLED here because the connection
|
||||
// might be shared and some other filters might want to do something.
|
||||
}
|
||||
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
}
|
||||
|
||||
GHashTable*
|
||||
UPowerClient::GetDevicePropertiesSync(DBusGProxy* aProxy)
|
||||
{
|
||||
GError* error = nullptr;
|
||||
GHashTable* hashTable = nullptr;
|
||||
GType typeGHashTable = dbus_g_type_get_map("GHashTable", G_TYPE_STRING,
|
||||
G_TYPE_VALUE);
|
||||
if (!dbus_g_proxy_call(aProxy, "GetAll", &error, G_TYPE_STRING,
|
||||
"org.freedesktop.UPower.Device", G_TYPE_INVALID,
|
||||
typeGHashTable, &hashTable, G_TYPE_INVALID)) {
|
||||
HAL_LOG("Error: %s\n", error->message);
|
||||
g_error_free(error);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return hashTable;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
UPowerClient::GetDevicePropertiesCallback(DBusGProxy* aProxy,
|
||||
DBusGProxyCall* aCall, void* aData)
|
||||
{
|
||||
GError* error = nullptr;
|
||||
GHashTable* hashTable = nullptr;
|
||||
GType typeGHashTable = dbus_g_type_get_map("GHashTable", G_TYPE_STRING,
|
||||
G_TYPE_VALUE);
|
||||
if (!dbus_g_proxy_end_call(aProxy, aCall, &error, typeGHashTable,
|
||||
&hashTable, G_TYPE_INVALID)) {
|
||||
HAL_LOG("Error: %s\n", error->message);
|
||||
g_error_free(error);
|
||||
} else {
|
||||
sInstance->UpdateSavedInfo(hashTable);
|
||||
hal::NotifyBatteryChange(hal::BatteryInformation(sInstance->mLevel,
|
||||
sInstance->mCharging,
|
||||
sInstance->mRemainingTime));
|
||||
g_hash_table_unref(hashTable);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
UPowerClient::GetDevicePropertiesAsync(DBusGProxy* aProxy)
|
||||
{
|
||||
dbus_g_proxy_begin_call(aProxy, "GetAll", GetDevicePropertiesCallback, nullptr,
|
||||
nullptr, G_TYPE_STRING,
|
||||
"org.freedesktop.UPower.Device", G_TYPE_INVALID);
|
||||
}
|
||||
|
||||
void
|
||||
UPowerClient::UpdateSavedInfo(GHashTable* aHashTable)
|
||||
{
|
||||
bool isFull = false;
|
||||
|
||||
/*
|
||||
* State values are confusing...
|
||||
* First of all, after looking at upower sources (0.9.13), it seems that
|
||||
* PendingDischarge and PendingCharge are not used.
|
||||
* In addition, FullyCharged and Empty states are not clear because we do not
|
||||
* know if the battery is actually charging or not. Those values come directly
|
||||
* from sysfs (in the Linux kernel) which have four states: "Empty", "Full",
|
||||
* "Charging" and "Discharging". In sysfs, "Empty" and "Full" are also only
|
||||
* related to the level, not to the charging state.
|
||||
* In this code, we are going to assume that Full means charging and Empty
|
||||
* means discharging because if that is not the case, the state should not
|
||||
* last a long time (actually, it should disappear at the following update).
|
||||
* It might be even very hard to see real cases where the state is Empty and
|
||||
* the battery is charging or the state is Full and the battery is discharging
|
||||
* given that plugging/unplugging the battery should have an impact on the
|
||||
* level.
|
||||
*/
|
||||
switch (g_value_get_uint(static_cast<const GValue*>(g_hash_table_lookup(aHashTable, "State")))) {
|
||||
case eState_Unknown:
|
||||
mCharging = kDefaultCharging;
|
||||
break;
|
||||
case eState_FullyCharged:
|
||||
isFull = true;
|
||||
MOZ_FALLTHROUGH;
|
||||
case eState_Charging:
|
||||
case eState_PendingCharge:
|
||||
mCharging = true;
|
||||
break;
|
||||
case eState_Discharging:
|
||||
case eState_Empty:
|
||||
case eState_PendingDischarge:
|
||||
mCharging = false;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* The battery level might be very close to 100% (like 99%) without
|
||||
* increasing. It seems that upower sets the battery state as 'full' in that
|
||||
* case so we should trust it and not even try to get the value.
|
||||
*/
|
||||
if (isFull) {
|
||||
mLevel = 1.0;
|
||||
} else {
|
||||
mLevel = round(g_value_get_double(static_cast<const GValue*>(g_hash_table_lookup(aHashTable, "Percentage"))))*0.01;
|
||||
}
|
||||
|
||||
if (isFull) {
|
||||
mRemainingTime = 0;
|
||||
} else {
|
||||
mRemainingTime = mCharging ? g_value_get_int64(static_cast<const GValue*>(g_hash_table_lookup(aHashTable, "TimeToFull")))
|
||||
: g_value_get_int64(static_cast<const GValue*>(g_hash_table_lookup(aHashTable, "TimeToEmpty")));
|
||||
|
||||
if (mRemainingTime == kUPowerUnknownRemainingTime) {
|
||||
mRemainingTime = kUnknownRemainingTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double
|
||||
UPowerClient::GetLevel()
|
||||
{
|
||||
return mLevel;
|
||||
}
|
||||
|
||||
bool
|
||||
UPowerClient::IsCharging()
|
||||
{
|
||||
return mCharging;
|
||||
}
|
||||
|
||||
double
|
||||
UPowerClient::GetRemainingTime()
|
||||
{
|
||||
return mRemainingTime;
|
||||
}
|
||||
|
||||
} // namespace hal_impl
|
||||
} // namespace mozilla
|
||||
185
hal/moz.build
Normal file
185
hal/moz.build
Normal file
|
|
@ -0,0 +1,185 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'gonk/nsIRecoveryService.idl',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'hal'
|
||||
|
||||
EXPORTS.mozilla += [
|
||||
'Hal.h',
|
||||
'HalImpl.h',
|
||||
'HalSandbox.h',
|
||||
'HalScreenConfiguration.h',
|
||||
'HalSensor.h',
|
||||
'HalTypes.h',
|
||||
'HalWakeLock.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'HalWakeLock.cpp',
|
||||
'sandbox/SandboxHal.cpp',
|
||||
'WindowIdentifier.cpp',
|
||||
]
|
||||
|
||||
# Hal.cpp cannot be built in unified mode because it relies on HalImpl.h.
|
||||
SOURCES += [
|
||||
'Hal.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
|
||||
LOCAL_INCLUDES += [
|
||||
'/widget/android',
|
||||
]
|
||||
UNIFIED_SOURCES += [
|
||||
'android/AndroidAlarm.cpp',
|
||||
'android/AndroidSensor.cpp',
|
||||
'fallback/FallbackPower.cpp',
|
||||
'linux/LinuxMemory.cpp',
|
||||
]
|
||||
# AndroidHal.cpp cannot be built in unified mode because it relies on HalImpl.h.
|
||||
SOURCES += [
|
||||
'android/AndroidHal.cpp',
|
||||
]
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
UNIFIED_SOURCES += [
|
||||
'gonk/GonkDiskSpaceWatcher.cpp',
|
||||
'gonk/GonkSensor.cpp',
|
||||
'gonk/GonkSensorsHelpers.cpp',
|
||||
'gonk/GonkSensorsInterface.cpp',
|
||||
'gonk/GonkSensorsPollInterface.cpp',
|
||||
'gonk/GonkSensorsRegistryInterface.cpp',
|
||||
'gonk/GonkSwitch.cpp',
|
||||
'gonk/SystemService.cpp',
|
||||
'gonk/UeventPoller.cpp',
|
||||
'linux/LinuxMemory.cpp',
|
||||
'linux/LinuxPower.cpp',
|
||||
]
|
||||
# GonkHal.cpp cannot be built in unified mode because it relies on HalImpl.h.
|
||||
SOURCES += [
|
||||
'gonk/GonkHal.cpp',
|
||||
]
|
||||
elif CONFIG['OS_TARGET'] == 'Linux':
|
||||
UNIFIED_SOURCES += [
|
||||
'fallback/FallbackAlarm.cpp',
|
||||
'fallback/FallbackScreenConfiguration.cpp',
|
||||
'fallback/FallbackSensor.cpp',
|
||||
'fallback/FallbackVibration.cpp',
|
||||
'linux/LinuxMemory.cpp',
|
||||
'linux/LinuxPower.cpp',
|
||||
]
|
||||
if CONFIG['MOZ_ENABLE_DBUS']:
|
||||
UNIFIED_SOURCES += [
|
||||
'linux/UPowerClient.cpp',
|
||||
]
|
||||
else:
|
||||
UNIFIED_SOURCES += [
|
||||
'fallback/FallbackBattery.cpp',
|
||||
]
|
||||
elif CONFIG['OS_TARGET'] == 'WINNT':
|
||||
UNIFIED_SOURCES += [
|
||||
'fallback/FallbackAlarm.cpp',
|
||||
'fallback/FallbackMemory.cpp',
|
||||
'fallback/FallbackPower.cpp',
|
||||
'fallback/FallbackScreenConfiguration.cpp',
|
||||
'fallback/FallbackVibration.cpp',
|
||||
'windows/WindowsSensor.cpp',
|
||||
]
|
||||
# WindowsBattery.cpp cannot be built in unified mode because it relies on HalImpl.h.
|
||||
SOURCES += [
|
||||
'windows/WindowsBattery.cpp',
|
||||
]
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
UNIFIED_SOURCES += [
|
||||
'cocoa/CocoaBattery.cpp',
|
||||
'fallback/FallbackAlarm.cpp',
|
||||
'fallback/FallbackMemory.cpp',
|
||||
'fallback/FallbackPower.cpp',
|
||||
'fallback/FallbackScreenConfiguration.cpp',
|
||||
'fallback/FallbackVibration.cpp',
|
||||
]
|
||||
elif CONFIG['OS_TARGET'] in ('OpenBSD', 'NetBSD', 'FreeBSD', 'DragonFly'):
|
||||
UNIFIED_SOURCES += [
|
||||
'fallback/FallbackAlarm.cpp',
|
||||
'fallback/FallbackMemory.cpp',
|
||||
'fallback/FallbackPower.cpp',
|
||||
'fallback/FallbackScreenConfiguration.cpp',
|
||||
'fallback/FallbackSensor.cpp',
|
||||
'fallback/FallbackVibration.cpp',
|
||||
]
|
||||
if CONFIG['MOZ_ENABLE_DBUS']:
|
||||
UNIFIED_SOURCES += [
|
||||
'linux/UPowerClient.cpp',
|
||||
]
|
||||
else:
|
||||
UNIFIED_SOURCES += [
|
||||
'fallback/FallbackBattery.cpp',
|
||||
]
|
||||
else:
|
||||
UNIFIED_SOURCES += [
|
||||
'fallback/FallbackAlarm.cpp',
|
||||
'fallback/FallbackBattery.cpp',
|
||||
'fallback/FallbackMemory.cpp',
|
||||
'fallback/FallbackPower.cpp',
|
||||
'fallback/FallbackScreenConfiguration.cpp',
|
||||
'fallback/FallbackSensor.cpp',
|
||||
'fallback/FallbackVibration.cpp',
|
||||
]
|
||||
|
||||
# Fallbacks for backends implemented on Gonk only.
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
|
||||
UNIFIED_SOURCES += [
|
||||
'fallback/FallbackDiskSpaceWatcher.cpp',
|
||||
'fallback/FallbackFactoryReset.cpp',
|
||||
'fallback/FallbackProcessPriority.cpp',
|
||||
'fallback/FallbackScreenPower.cpp',
|
||||
'fallback/FallbackSwitch.cpp',
|
||||
'fallback/FallbackSystemService.cpp',
|
||||
'fallback/FallbackThreadPriority.cpp',
|
||||
'fallback/FallbackTime.cpp',
|
||||
'fallback/FallbackWakeLocks.cpp',
|
||||
]
|
||||
|
||||
# Fallbacks for backends implemented on Android only.
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android':
|
||||
UNIFIED_SOURCES += [
|
||||
'fallback/FallbackNetwork.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
UNIFIED_SOURCES += [
|
||||
'cocoa/CocoaSensor.mm',
|
||||
'cocoa/smslib.mm',
|
||||
]
|
||||
|
||||
IPDL_SOURCES = [
|
||||
'sandbox/PHal.ipdl',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
if CONFIG['MOZ_GAMEPAD']:
|
||||
LOCAL_INCLUDES += [
|
||||
'/dom/base',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
# So that we can call nsScreenManagerGonk::GetConfiguration().
|
||||
LOCAL_INCLUDES += [
|
||||
'/widget',
|
||||
'/widget/gonk',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
LOCAL_INCLUDES += ['%' + '%s/hardware/libhardware_legacy/include' % CONFIG['ANDROID_SOURCE']]
|
||||
|
||||
CFLAGS += CONFIG['GLIB_CFLAGS']
|
||||
CFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS']
|
||||
CXXFLAGS += CONFIG['GLIB_CFLAGS']
|
||||
CXXFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS']
|
||||
159
hal/sandbox/PHal.ipdl
Normal file
159
hal/sandbox/PHal.ipdl
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||
/* 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 protocol PContent;
|
||||
include protocol PBrowser;
|
||||
|
||||
include "mozilla/GfxMessageUtils.h";
|
||||
|
||||
using mozilla::dom::ScreenOrientationInternal from "mozilla/dom/ScreenOrientation.h";
|
||||
using mozilla::hal::SensorType from "mozilla/HalSensor.h";
|
||||
using mozilla::hal::SensorAccuracyType from "mozilla/HalSensor.h";
|
||||
using mozilla::hal::WakeLockControl from "mozilla/HalTypes.h";
|
||||
using mozilla::hal::SwitchState from "mozilla/HalTypes.h";
|
||||
using mozilla::hal::SwitchDevice from "mozilla/HalTypes.h";
|
||||
using mozilla::hal::ProcessPriority from "mozilla/HalTypes.h";
|
||||
using nsIntRect from "nsRect.h";
|
||||
using PRTime from "prtime.h";
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace hal {
|
||||
struct BatteryInformation {
|
||||
double level;
|
||||
bool charging;
|
||||
double remainingTime;
|
||||
};
|
||||
|
||||
struct SensorData {
|
||||
SensorType sensor;
|
||||
PRTime timestamp;
|
||||
float[] values;
|
||||
SensorAccuracyType accuracy;
|
||||
};
|
||||
|
||||
struct NetworkInformation {
|
||||
uint32_t type;
|
||||
bool isWifi;
|
||||
uint32_t dhcpGateway;
|
||||
};
|
||||
|
||||
struct SwitchEvent {
|
||||
SwitchDevice device;
|
||||
SwitchState status;
|
||||
};
|
||||
|
||||
struct WakeLockInformation {
|
||||
nsString topic;
|
||||
uint32_t numLocks;
|
||||
uint32_t numHidden;
|
||||
uint64_t[] lockingProcesses;
|
||||
};
|
||||
|
||||
struct ScreenConfiguration {
|
||||
nsIntRect rect;
|
||||
ScreenOrientationInternal orientation;
|
||||
uint16_t angle;
|
||||
uint32_t colorDepth;
|
||||
uint32_t pixelDepth;
|
||||
};
|
||||
|
||||
struct SystemTimezoneChangeInformation {
|
||||
// These timezone offsets are relative to UTC in minutes and
|
||||
// have already taken daylight saving time (DST) into account.
|
||||
int32_t oldTimezoneOffsetMinutes;
|
||||
int32_t newTimezoneOffsetMinutes;
|
||||
};
|
||||
|
||||
} // namespace hal
|
||||
|
||||
namespace hal_sandbox {
|
||||
|
||||
nested(upto inside_cpow) sync protocol PHal {
|
||||
manager PContent;
|
||||
|
||||
child:
|
||||
async NotifyBatteryChange(BatteryInformation aBatteryInfo);
|
||||
async NotifyNetworkChange(NetworkInformation aNetworkInfo);
|
||||
async NotifyWakeLockChange(WakeLockInformation aWakeLockInfo);
|
||||
async NotifyScreenConfigurationChange(ScreenConfiguration aScreenOrientation);
|
||||
async NotifySwitchChange(SwitchEvent aEvent);
|
||||
async NotifySystemClockChange(int64_t aClockDeltaMS);
|
||||
async NotifySystemTimezoneChange(SystemTimezoneChangeInformation aSystemTimezoneChangeInfo);
|
||||
|
||||
parent:
|
||||
async Vibrate(uint32_t[] pattern, uint64_t[] id, PBrowser browser);
|
||||
async CancelVibrate(uint64_t[] id, PBrowser browser);
|
||||
|
||||
async EnableBatteryNotifications();
|
||||
async DisableBatteryNotifications();
|
||||
sync GetCurrentBatteryInformation()
|
||||
returns (BatteryInformation aBatteryInfo);
|
||||
|
||||
async EnableNetworkNotifications();
|
||||
async DisableNetworkNotifications();
|
||||
sync GetCurrentNetworkInformation()
|
||||
returns (NetworkInformation aNetworkInfo);
|
||||
|
||||
sync GetScreenEnabled() returns (bool enabled);
|
||||
async SetScreenEnabled(bool aEnabled);
|
||||
|
||||
sync GetKeyLightEnabled() returns (bool enabled);
|
||||
async SetKeyLightEnabled(bool aEnabled);
|
||||
|
||||
sync GetCpuSleepAllowed() returns (bool allowed);
|
||||
async SetCpuSleepAllowed(bool aAllowed);
|
||||
|
||||
sync GetScreenBrightness() returns (double brightness);
|
||||
async SetScreenBrightness(double aBrightness);
|
||||
|
||||
async AdjustSystemClock(int64_t aDeltaMilliseconds);
|
||||
async SetTimezone(nsCString aTimezoneSpec);
|
||||
sync GetTimezone()
|
||||
returns (nsCString aTimezoneSpec);
|
||||
sync GetTimezoneOffset()
|
||||
returns (int32_t aTimezoneOffset);
|
||||
async EnableSystemClockChangeNotifications();
|
||||
async DisableSystemClockChangeNotifications();
|
||||
async EnableSystemTimezoneChangeNotifications();
|
||||
async DisableSystemTimezoneChangeNotifications();
|
||||
|
||||
async ModifyWakeLock(nsString aTopic,
|
||||
WakeLockControl aLockAdjust,
|
||||
WakeLockControl aHiddenAdjust,
|
||||
uint64_t aProcessID);
|
||||
async EnableWakeLockNotifications();
|
||||
async DisableWakeLockNotifications();
|
||||
sync GetWakeLockInfo(nsString aTopic)
|
||||
returns (WakeLockInformation aWakeLockInfo);
|
||||
|
||||
async EnableScreenConfigurationNotifications();
|
||||
async DisableScreenConfigurationNotifications();
|
||||
nested(inside_cpow) sync GetCurrentScreenConfiguration()
|
||||
returns (ScreenConfiguration aScreenConfiguration);
|
||||
sync LockScreenOrientation(ScreenOrientationInternal aOrientation)
|
||||
returns (bool allowed);
|
||||
async UnlockScreenOrientation();
|
||||
|
||||
async EnableSwitchNotifications(SwitchDevice aDevice);
|
||||
async DisableSwitchNotifications(SwitchDevice aDevice);
|
||||
sync GetCurrentSwitchState(SwitchDevice aDevice)
|
||||
returns (SwitchState aState);
|
||||
|
||||
async FactoryReset(nsString aReason);
|
||||
|
||||
child:
|
||||
async NotifySensorChange(SensorData aSensorData);
|
||||
|
||||
parent:
|
||||
async EnableSensorNotifications(SensorType aSensor);
|
||||
async DisableSensorNotifications(SensorType aSensor);
|
||||
|
||||
async __delete__();
|
||||
};
|
||||
|
||||
} // namespace hal
|
||||
} // namespace mozilla
|
||||
907
hal/sandbox/SandboxHal.cpp
Normal file
907
hal/sandbox/SandboxHal.cpp
Normal file
|
|
@ -0,0 +1,907 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||
/* 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 "HalLog.h"
|
||||
#include "mozilla/AppProcessChecker.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/hal_sandbox/PHalChild.h"
|
||||
#include "mozilla/hal_sandbox/PHalParent.h"
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
#include "mozilla/dom/battery/Types.h"
|
||||
#include "mozilla/dom/network/Types.h"
|
||||
#include "mozilla/dom/ScreenOrientation.h"
|
||||
#include "mozilla/Observer.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "WindowIdentifier.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::hal;
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_sandbox {
|
||||
|
||||
static bool sHalChildDestroyed = false;
|
||||
|
||||
bool
|
||||
HalChildDestroyed()
|
||||
{
|
||||
return sHalChildDestroyed;
|
||||
}
|
||||
|
||||
static PHalChild* sHal;
|
||||
static PHalChild*
|
||||
Hal()
|
||||
{
|
||||
if (!sHal) {
|
||||
sHal = ContentChild::GetSingleton()->SendPHalConstructor();
|
||||
}
|
||||
return sHal;
|
||||
}
|
||||
|
||||
void
|
||||
Vibrate(const nsTArray<uint32_t>& pattern, const WindowIdentifier &id)
|
||||
{
|
||||
HAL_LOG("Vibrate: Sending to parent process.");
|
||||
|
||||
AutoTArray<uint32_t, 8> p(pattern);
|
||||
|
||||
WindowIdentifier newID(id);
|
||||
newID.AppendProcessID();
|
||||
Hal()->SendVibrate(p, newID.AsArray(), TabChild::GetFrom(newID.GetWindow()));
|
||||
}
|
||||
|
||||
void
|
||||
CancelVibrate(const WindowIdentifier &id)
|
||||
{
|
||||
HAL_LOG("CancelVibrate: Sending to parent process.");
|
||||
|
||||
WindowIdentifier newID(id);
|
||||
newID.AppendProcessID();
|
||||
Hal()->SendCancelVibrate(newID.AsArray(), TabChild::GetFrom(newID.GetWindow()));
|
||||
}
|
||||
|
||||
void
|
||||
EnableBatteryNotifications()
|
||||
{
|
||||
Hal()->SendEnableBatteryNotifications();
|
||||
}
|
||||
|
||||
void
|
||||
DisableBatteryNotifications()
|
||||
{
|
||||
Hal()->SendDisableBatteryNotifications();
|
||||
}
|
||||
|
||||
void
|
||||
GetCurrentBatteryInformation(BatteryInformation* aBatteryInfo)
|
||||
{
|
||||
Hal()->SendGetCurrentBatteryInformation(aBatteryInfo);
|
||||
}
|
||||
|
||||
void
|
||||
EnableNetworkNotifications()
|
||||
{
|
||||
Hal()->SendEnableNetworkNotifications();
|
||||
}
|
||||
|
||||
void
|
||||
DisableNetworkNotifications()
|
||||
{
|
||||
Hal()->SendDisableNetworkNotifications();
|
||||
}
|
||||
|
||||
void
|
||||
GetCurrentNetworkInformation(NetworkInformation* aNetworkInfo)
|
||||
{
|
||||
Hal()->SendGetCurrentNetworkInformation(aNetworkInfo);
|
||||
}
|
||||
|
||||
void
|
||||
EnableScreenConfigurationNotifications()
|
||||
{
|
||||
Hal()->SendEnableScreenConfigurationNotifications();
|
||||
}
|
||||
|
||||
void
|
||||
DisableScreenConfigurationNotifications()
|
||||
{
|
||||
Hal()->SendDisableScreenConfigurationNotifications();
|
||||
}
|
||||
|
||||
void
|
||||
GetCurrentScreenConfiguration(ScreenConfiguration* aScreenConfiguration)
|
||||
{
|
||||
Hal()->SendGetCurrentScreenConfiguration(aScreenConfiguration);
|
||||
}
|
||||
|
||||
bool
|
||||
LockScreenOrientation(const dom::ScreenOrientationInternal& aOrientation)
|
||||
{
|
||||
bool allowed;
|
||||
Hal()->SendLockScreenOrientation(aOrientation, &allowed);
|
||||
return allowed;
|
||||
}
|
||||
|
||||
void
|
||||
UnlockScreenOrientation()
|
||||
{
|
||||
Hal()->SendUnlockScreenOrientation();
|
||||
}
|
||||
|
||||
bool
|
||||
GetScreenEnabled()
|
||||
{
|
||||
bool enabled = false;
|
||||
Hal()->SendGetScreenEnabled(&enabled);
|
||||
return enabled;
|
||||
}
|
||||
|
||||
void
|
||||
SetScreenEnabled(bool aEnabled)
|
||||
{
|
||||
Hal()->SendSetScreenEnabled(aEnabled);
|
||||
}
|
||||
|
||||
bool
|
||||
GetKeyLightEnabled()
|
||||
{
|
||||
bool enabled = false;
|
||||
Hal()->SendGetKeyLightEnabled(&enabled);
|
||||
return enabled;
|
||||
}
|
||||
|
||||
void
|
||||
SetKeyLightEnabled(bool aEnabled)
|
||||
{
|
||||
Hal()->SendSetKeyLightEnabled(aEnabled);
|
||||
}
|
||||
|
||||
bool
|
||||
GetCpuSleepAllowed()
|
||||
{
|
||||
bool allowed = true;
|
||||
Hal()->SendGetCpuSleepAllowed(&allowed);
|
||||
return allowed;
|
||||
}
|
||||
|
||||
void
|
||||
SetCpuSleepAllowed(bool aAllowed)
|
||||
{
|
||||
Hal()->SendSetCpuSleepAllowed(aAllowed);
|
||||
}
|
||||
|
||||
double
|
||||
GetScreenBrightness()
|
||||
{
|
||||
double brightness = 0;
|
||||
Hal()->SendGetScreenBrightness(&brightness);
|
||||
return brightness;
|
||||
}
|
||||
|
||||
void
|
||||
SetScreenBrightness(double aBrightness)
|
||||
{
|
||||
Hal()->SendSetScreenBrightness(aBrightness);
|
||||
}
|
||||
|
||||
void
|
||||
AdjustSystemClock(int64_t aDeltaMilliseconds)
|
||||
{
|
||||
Hal()->SendAdjustSystemClock(aDeltaMilliseconds);
|
||||
}
|
||||
|
||||
void
|
||||
SetTimezone(const nsCString& aTimezoneSpec)
|
||||
{
|
||||
Hal()->SendSetTimezone(nsCString(aTimezoneSpec));
|
||||
}
|
||||
|
||||
nsCString
|
||||
GetTimezone()
|
||||
{
|
||||
nsCString timezone;
|
||||
Hal()->SendGetTimezone(&timezone);
|
||||
return timezone;
|
||||
}
|
||||
|
||||
int32_t
|
||||
GetTimezoneOffset()
|
||||
{
|
||||
int32_t timezoneOffset;
|
||||
Hal()->SendGetTimezoneOffset(&timezoneOffset);
|
||||
return timezoneOffset;
|
||||
}
|
||||
|
||||
void
|
||||
EnableSystemClockChangeNotifications()
|
||||
{
|
||||
Hal()->SendEnableSystemClockChangeNotifications();
|
||||
}
|
||||
|
||||
void
|
||||
DisableSystemClockChangeNotifications()
|
||||
{
|
||||
Hal()->SendDisableSystemClockChangeNotifications();
|
||||
}
|
||||
|
||||
void
|
||||
EnableSystemTimezoneChangeNotifications()
|
||||
{
|
||||
Hal()->SendEnableSystemTimezoneChangeNotifications();
|
||||
}
|
||||
|
||||
void
|
||||
DisableSystemTimezoneChangeNotifications()
|
||||
{
|
||||
Hal()->SendDisableSystemTimezoneChangeNotifications();
|
||||
}
|
||||
|
||||
void
|
||||
Reboot()
|
||||
{
|
||||
NS_RUNTIMEABORT("Reboot() can't be called from sandboxed contexts.");
|
||||
}
|
||||
|
||||
void
|
||||
PowerOff()
|
||||
{
|
||||
NS_RUNTIMEABORT("PowerOff() can't be called from sandboxed contexts.");
|
||||
}
|
||||
|
||||
void
|
||||
StartForceQuitWatchdog(ShutdownMode aMode, int32_t aTimeoutSecs)
|
||||
{
|
||||
NS_RUNTIMEABORT("StartForceQuitWatchdog() can't be called from sandboxed contexts.");
|
||||
}
|
||||
|
||||
void
|
||||
EnableSensorNotifications(SensorType aSensor) {
|
||||
Hal()->SendEnableSensorNotifications(aSensor);
|
||||
}
|
||||
|
||||
void
|
||||
DisableSensorNotifications(SensorType aSensor) {
|
||||
Hal()->SendDisableSensorNotifications(aSensor);
|
||||
}
|
||||
|
||||
void
|
||||
EnableWakeLockNotifications()
|
||||
{
|
||||
Hal()->SendEnableWakeLockNotifications();
|
||||
}
|
||||
|
||||
void
|
||||
DisableWakeLockNotifications()
|
||||
{
|
||||
Hal()->SendDisableWakeLockNotifications();
|
||||
}
|
||||
|
||||
void
|
||||
ModifyWakeLock(const nsAString &aTopic,
|
||||
WakeLockControl aLockAdjust,
|
||||
WakeLockControl aHiddenAdjust,
|
||||
uint64_t aProcessID)
|
||||
{
|
||||
MOZ_ASSERT(aProcessID != CONTENT_PROCESS_ID_UNKNOWN);
|
||||
Hal()->SendModifyWakeLock(nsString(aTopic), aLockAdjust, aHiddenAdjust, aProcessID);
|
||||
}
|
||||
|
||||
void
|
||||
GetWakeLockInfo(const nsAString &aTopic, WakeLockInformation *aWakeLockInfo)
|
||||
{
|
||||
Hal()->SendGetWakeLockInfo(nsString(aTopic), aWakeLockInfo);
|
||||
}
|
||||
|
||||
void
|
||||
EnableSwitchNotifications(SwitchDevice aDevice)
|
||||
{
|
||||
Hal()->SendEnableSwitchNotifications(aDevice);
|
||||
}
|
||||
|
||||
void
|
||||
DisableSwitchNotifications(SwitchDevice aDevice)
|
||||
{
|
||||
Hal()->SendDisableSwitchNotifications(aDevice);
|
||||
}
|
||||
|
||||
SwitchState
|
||||
GetCurrentSwitchState(SwitchDevice aDevice)
|
||||
{
|
||||
SwitchState state;
|
||||
Hal()->SendGetCurrentSwitchState(aDevice, &state);
|
||||
return state;
|
||||
}
|
||||
|
||||
void
|
||||
NotifySwitchStateFromInputDevice(SwitchDevice aDevice, SwitchState aState)
|
||||
{
|
||||
Unused << aDevice;
|
||||
Unused << aState;
|
||||
NS_RUNTIMEABORT("Only the main process may notify switch state change.");
|
||||
}
|
||||
|
||||
bool
|
||||
EnableAlarm()
|
||||
{
|
||||
NS_RUNTIMEABORT("Alarms can't be programmed from sandboxed contexts. Yet.");
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
DisableAlarm()
|
||||
{
|
||||
NS_RUNTIMEABORT("Alarms can't be programmed from sandboxed contexts. Yet.");
|
||||
}
|
||||
|
||||
bool
|
||||
SetAlarm(int32_t aSeconds, int32_t aNanoseconds)
|
||||
{
|
||||
NS_RUNTIMEABORT("Alarms can't be programmed from sandboxed contexts. Yet.");
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
SetProcessPriority(int aPid, ProcessPriority aPriority, uint32_t aLRU)
|
||||
{
|
||||
NS_RUNTIMEABORT("Only the main process may set processes' priorities.");
|
||||
}
|
||||
|
||||
void
|
||||
SetCurrentThreadPriority(ThreadPriority aThreadPriority)
|
||||
{
|
||||
NS_RUNTIMEABORT("Setting current thread priority cannot be called from sandboxed contexts.");
|
||||
}
|
||||
|
||||
void
|
||||
SetThreadPriority(PlatformThreadId aThreadId,
|
||||
ThreadPriority aThreadPriority)
|
||||
{
|
||||
NS_RUNTIMEABORT("Setting thread priority cannot be called from sandboxed contexts.");
|
||||
}
|
||||
|
||||
void
|
||||
FactoryReset(FactoryResetReason& aReason)
|
||||
{
|
||||
if (aReason == FactoryResetReason::Normal) {
|
||||
Hal()->SendFactoryReset(NS_LITERAL_STRING("normal"));
|
||||
} else if (aReason == FactoryResetReason::Wipe) {
|
||||
Hal()->SendFactoryReset(NS_LITERAL_STRING("wipe"));
|
||||
} else if (aReason == FactoryResetReason::Root) {
|
||||
Hal()->SendFactoryReset(NS_LITERAL_STRING("root"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StartDiskSpaceWatcher()
|
||||
{
|
||||
NS_RUNTIMEABORT("StartDiskSpaceWatcher() can't be called from sandboxed contexts.");
|
||||
}
|
||||
|
||||
void
|
||||
StopDiskSpaceWatcher()
|
||||
{
|
||||
NS_RUNTIMEABORT("StopDiskSpaceWatcher() can't be called from sandboxed contexts.");
|
||||
}
|
||||
|
||||
bool IsHeadphoneEventFromInputDev()
|
||||
{
|
||||
NS_RUNTIMEABORT("IsHeadphoneEventFromInputDev() cannot be called from sandboxed contexts.");
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult StartSystemService(const char* aSvcName, const char* aArgs)
|
||||
{
|
||||
NS_RUNTIMEABORT("System services cannot be controlled from sandboxed contexts.");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
void StopSystemService(const char* aSvcName)
|
||||
{
|
||||
NS_RUNTIMEABORT("System services cannot be controlled from sandboxed contexts.");
|
||||
}
|
||||
|
||||
bool SystemServiceIsRunning(const char* aSvcName)
|
||||
{
|
||||
NS_RUNTIMEABORT("System services cannot be controlled from sandboxed contexts.");
|
||||
return false;
|
||||
}
|
||||
|
||||
class HalParent : public PHalParent
|
||||
, public BatteryObserver
|
||||
, public NetworkObserver
|
||||
, public ISensorObserver
|
||||
, public WakeLockObserver
|
||||
, public ScreenConfigurationObserver
|
||||
, public SwitchObserver
|
||||
, public SystemClockChangeObserver
|
||||
, public SystemTimezoneChangeObserver
|
||||
{
|
||||
public:
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason aWhy) override
|
||||
{
|
||||
// NB: you *must* unconditionally unregister your observer here,
|
||||
// if it *may* be registered below.
|
||||
hal::UnregisterBatteryObserver(this);
|
||||
hal::UnregisterNetworkObserver(this);
|
||||
hal::UnregisterScreenConfigurationObserver(this);
|
||||
for (int32_t sensor = SENSOR_UNKNOWN + 1;
|
||||
sensor < NUM_SENSOR_TYPE; ++sensor) {
|
||||
hal::UnregisterSensorObserver(SensorType(sensor), this);
|
||||
}
|
||||
hal::UnregisterWakeLockObserver(this);
|
||||
hal::UnregisterSystemClockChangeObserver(this);
|
||||
hal::UnregisterSystemTimezoneChangeObserver(this);
|
||||
for (int32_t switchDevice = SWITCH_DEVICE_UNKNOWN + 1;
|
||||
switchDevice < NUM_SWITCH_DEVICE; ++switchDevice) {
|
||||
hal::UnregisterSwitchObserver(SwitchDevice(switchDevice), this);
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvVibrate(InfallibleTArray<unsigned int>&& pattern,
|
||||
InfallibleTArray<uint64_t>&& id,
|
||||
PBrowserParent *browserParent) override
|
||||
{
|
||||
// We give all content vibration permission.
|
||||
// TabParent *tabParent = TabParent::GetFrom(browserParent);
|
||||
/* xxxkhuey wtf
|
||||
nsCOMPtr<nsIDOMWindow> window =
|
||||
do_QueryInterface(tabParent->GetBrowserDOMWindow());
|
||||
*/
|
||||
WindowIdentifier newID(id, nullptr);
|
||||
hal::Vibrate(pattern, newID);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvCancelVibrate(InfallibleTArray<uint64_t> &&id,
|
||||
PBrowserParent *browserParent) override
|
||||
{
|
||||
//TabParent *tabParent = TabParent::GetFrom(browserParent);
|
||||
/* XXXkhuey wtf
|
||||
nsCOMPtr<nsIDOMWindow> window =
|
||||
tabParent->GetBrowserDOMWindow();
|
||||
*/
|
||||
WindowIdentifier newID(id, nullptr);
|
||||
hal::CancelVibrate(newID);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvEnableBatteryNotifications() override {
|
||||
// We give all content battery-status permission.
|
||||
hal::RegisterBatteryObserver(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvDisableBatteryNotifications() override {
|
||||
hal::UnregisterBatteryObserver(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvGetCurrentBatteryInformation(BatteryInformation* aBatteryInfo) override {
|
||||
// We give all content battery-status permission.
|
||||
hal::GetCurrentBatteryInformation(aBatteryInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Notify(const BatteryInformation& aBatteryInfo) override {
|
||||
Unused << SendNotifyBatteryChange(aBatteryInfo);
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvEnableNetworkNotifications() override {
|
||||
// We give all content access to this network-status information.
|
||||
hal::RegisterNetworkObserver(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvDisableNetworkNotifications() override {
|
||||
hal::UnregisterNetworkObserver(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvGetCurrentNetworkInformation(NetworkInformation* aNetworkInfo) override {
|
||||
hal::GetCurrentNetworkInformation(aNetworkInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Notify(const NetworkInformation& aNetworkInfo) override {
|
||||
Unused << SendNotifyNetworkChange(aNetworkInfo);
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvEnableScreenConfigurationNotifications() override {
|
||||
// Screen configuration is used to implement CSS and DOM
|
||||
// properties, so all content already has access to this.
|
||||
hal::RegisterScreenConfigurationObserver(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvDisableScreenConfigurationNotifications() override {
|
||||
hal::UnregisterScreenConfigurationObserver(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvGetCurrentScreenConfiguration(ScreenConfiguration* aScreenConfiguration) override {
|
||||
hal::GetCurrentScreenConfiguration(aScreenConfiguration);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvLockScreenOrientation(const dom::ScreenOrientationInternal& aOrientation, bool* aAllowed) override
|
||||
{
|
||||
// FIXME/bug 777980: unprivileged content may only lock
|
||||
// orientation while fullscreen. We should check whether the
|
||||
// request comes from an actor in a process that might be
|
||||
// fullscreen. We don't have that information currently.
|
||||
*aAllowed = hal::LockScreenOrientation(aOrientation);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvUnlockScreenOrientation() override
|
||||
{
|
||||
hal::UnlockScreenOrientation();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Notify(const ScreenConfiguration& aScreenConfiguration) override {
|
||||
Unused << SendNotifyScreenConfigurationChange(aScreenConfiguration);
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvGetScreenEnabled(bool* aEnabled) override
|
||||
{
|
||||
if (!AssertAppProcessPermission(this, "power")) {
|
||||
return false;
|
||||
}
|
||||
*aEnabled = hal::GetScreenEnabled();
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvSetScreenEnabled(const bool& aEnabled) override
|
||||
{
|
||||
if (!AssertAppProcessPermission(this, "power")) {
|
||||
return false;
|
||||
}
|
||||
hal::SetScreenEnabled(aEnabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvGetKeyLightEnabled(bool* aEnabled) override
|
||||
{
|
||||
if (!AssertAppProcessPermission(this, "power")) {
|
||||
return false;
|
||||
}
|
||||
*aEnabled = hal::GetKeyLightEnabled();
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvSetKeyLightEnabled(const bool& aEnabled) override
|
||||
{
|
||||
if (!AssertAppProcessPermission(this, "power")) {
|
||||
return false;
|
||||
}
|
||||
hal::SetKeyLightEnabled(aEnabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvGetCpuSleepAllowed(bool* aAllowed) override
|
||||
{
|
||||
if (!AssertAppProcessPermission(this, "power")) {
|
||||
return false;
|
||||
}
|
||||
*aAllowed = hal::GetCpuSleepAllowed();
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvSetCpuSleepAllowed(const bool& aAllowed) override
|
||||
{
|
||||
if (!AssertAppProcessPermission(this, "power")) {
|
||||
return false;
|
||||
}
|
||||
hal::SetCpuSleepAllowed(aAllowed);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvGetScreenBrightness(double* aBrightness) override
|
||||
{
|
||||
if (!AssertAppProcessPermission(this, "power")) {
|
||||
return false;
|
||||
}
|
||||
*aBrightness = hal::GetScreenBrightness();
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvSetScreenBrightness(const double& aBrightness) override
|
||||
{
|
||||
if (!AssertAppProcessPermission(this, "power")) {
|
||||
return false;
|
||||
}
|
||||
hal::SetScreenBrightness(aBrightness);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvAdjustSystemClock(const int64_t &aDeltaMilliseconds) override
|
||||
{
|
||||
if (!AssertAppProcessPermission(this, "time")) {
|
||||
return false;
|
||||
}
|
||||
hal::AdjustSystemClock(aDeltaMilliseconds);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvSetTimezone(const nsCString& aTimezoneSpec) override
|
||||
{
|
||||
if (!AssertAppProcessPermission(this, "time")) {
|
||||
return false;
|
||||
}
|
||||
hal::SetTimezone(aTimezoneSpec);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvGetTimezone(nsCString *aTimezoneSpec) override
|
||||
{
|
||||
if (!AssertAppProcessPermission(this, "time")) {
|
||||
return false;
|
||||
}
|
||||
*aTimezoneSpec = hal::GetTimezone();
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvGetTimezoneOffset(int32_t *aTimezoneOffset) override
|
||||
{
|
||||
if (!AssertAppProcessPermission(this, "time")) {
|
||||
return false;
|
||||
}
|
||||
*aTimezoneOffset = hal::GetTimezoneOffset();
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvEnableSystemClockChangeNotifications() override
|
||||
{
|
||||
hal::RegisterSystemClockChangeObserver(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvDisableSystemClockChangeNotifications() override
|
||||
{
|
||||
hal::UnregisterSystemClockChangeObserver(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvEnableSystemTimezoneChangeNotifications() override
|
||||
{
|
||||
hal::RegisterSystemTimezoneChangeObserver(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvDisableSystemTimezoneChangeNotifications() override
|
||||
{
|
||||
hal::UnregisterSystemTimezoneChangeObserver(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvEnableSensorNotifications(const SensorType &aSensor) override {
|
||||
// We currently allow any content to register device-sensor
|
||||
// listeners.
|
||||
hal::RegisterSensorObserver(aSensor, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvDisableSensorNotifications(const SensorType &aSensor) override {
|
||||
hal::UnregisterSensorObserver(aSensor, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Notify(const SensorData& aSensorData) override {
|
||||
Unused << SendNotifySensorChange(aSensorData);
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvModifyWakeLock(const nsString& aTopic,
|
||||
const WakeLockControl& aLockAdjust,
|
||||
const WakeLockControl& aHiddenAdjust,
|
||||
const uint64_t& aProcessID) override
|
||||
{
|
||||
MOZ_ASSERT(aProcessID != CONTENT_PROCESS_ID_UNKNOWN);
|
||||
|
||||
// We allow arbitrary content to use wake locks.
|
||||
hal::ModifyWakeLock(aTopic, aLockAdjust, aHiddenAdjust, aProcessID);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvEnableWakeLockNotifications() override
|
||||
{
|
||||
// We allow arbitrary content to use wake locks.
|
||||
hal::RegisterWakeLockObserver(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvDisableWakeLockNotifications() override
|
||||
{
|
||||
hal::UnregisterWakeLockObserver(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvGetWakeLockInfo(const nsString &aTopic, WakeLockInformation *aWakeLockInfo) override
|
||||
{
|
||||
hal::GetWakeLockInfo(aTopic, aWakeLockInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Notify(const WakeLockInformation& aWakeLockInfo) override
|
||||
{
|
||||
Unused << SendNotifyWakeLockChange(aWakeLockInfo);
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvEnableSwitchNotifications(const SwitchDevice& aDevice) override
|
||||
{
|
||||
// Content has no reason to listen to switch events currently.
|
||||
hal::RegisterSwitchObserver(aDevice, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvDisableSwitchNotifications(const SwitchDevice& aDevice) override
|
||||
{
|
||||
hal::UnregisterSwitchObserver(aDevice, this);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Notify(const SwitchEvent& aSwitchEvent) override
|
||||
{
|
||||
Unused << SendNotifySwitchChange(aSwitchEvent);
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvGetCurrentSwitchState(const SwitchDevice& aDevice, hal::SwitchState *aState) override
|
||||
{
|
||||
// Content has no reason to listen to switch events currently.
|
||||
*aState = hal::GetCurrentSwitchState(aDevice);
|
||||
return true;
|
||||
}
|
||||
|
||||
void Notify(const int64_t& aClockDeltaMS) override
|
||||
{
|
||||
Unused << SendNotifySystemClockChange(aClockDeltaMS);
|
||||
}
|
||||
|
||||
void Notify(const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo) override
|
||||
{
|
||||
Unused << SendNotifySystemTimezoneChange(aSystemTimezoneChangeInfo);
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvFactoryReset(const nsString& aReason) override
|
||||
{
|
||||
if (!AssertAppProcessPermission(this, "power")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FactoryResetReason reason = FactoryResetReason::Normal;
|
||||
if (aReason.EqualsLiteral("normal")) {
|
||||
reason = FactoryResetReason::Normal;
|
||||
} else if (aReason.EqualsLiteral("wipe")) {
|
||||
reason = FactoryResetReason::Wipe;
|
||||
} else if (aReason.EqualsLiteral("root")) {
|
||||
reason = FactoryResetReason::Root;
|
||||
} else {
|
||||
// Invalid factory reset reason. That should never happen.
|
||||
return false;
|
||||
}
|
||||
|
||||
hal::FactoryReset(reason);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class HalChild : public PHalChild {
|
||||
public:
|
||||
virtual void
|
||||
ActorDestroy(ActorDestroyReason aWhy) override
|
||||
{
|
||||
sHalChildDestroyed = true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvNotifyBatteryChange(const BatteryInformation& aBatteryInfo) override {
|
||||
hal::NotifyBatteryChange(aBatteryInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvNotifySensorChange(const hal::SensorData &aSensorData) override;
|
||||
|
||||
virtual bool
|
||||
RecvNotifyNetworkChange(const NetworkInformation& aNetworkInfo) override {
|
||||
hal::NotifyNetworkChange(aNetworkInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvNotifyWakeLockChange(const WakeLockInformation& aWakeLockInfo) override {
|
||||
hal::NotifyWakeLockChange(aWakeLockInfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvNotifyScreenConfigurationChange(const ScreenConfiguration& aScreenConfiguration) override {
|
||||
hal::NotifyScreenConfigurationChange(aScreenConfiguration);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvNotifySwitchChange(const mozilla::hal::SwitchEvent& aEvent) override {
|
||||
hal::NotifySwitchChange(aEvent);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvNotifySystemClockChange(const int64_t& aClockDeltaMS) override {
|
||||
hal::NotifySystemClockChange(aClockDeltaMS);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RecvNotifySystemTimezoneChange(
|
||||
const SystemTimezoneChangeInformation& aSystemTimezoneChangeInfo) override {
|
||||
hal::NotifySystemTimezoneChange(aSystemTimezoneChangeInfo);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
bool
|
||||
HalChild::RecvNotifySensorChange(const hal::SensorData &aSensorData) {
|
||||
hal::NotifySensorChange(aSensorData);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PHalChild* CreateHalChild() {
|
||||
return new HalChild();
|
||||
}
|
||||
|
||||
PHalParent* CreateHalParent() {
|
||||
return new HalParent();
|
||||
}
|
||||
|
||||
} // namespace hal_sandbox
|
||||
} // namespace mozilla
|
||||
23
hal/sandbox/SandboxHal.h
Normal file
23
hal/sandbox/SandboxHal.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 ts=8 et ft=cpp : */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_SandboxHal_h
|
||||
#define mozilla_SandboxHal_h
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_sandbox {
|
||||
|
||||
class PHalChild;
|
||||
class PHalParent;
|
||||
|
||||
PHalChild* CreateHalChild();
|
||||
|
||||
PHalParent* CreateHalParent();
|
||||
|
||||
} // namespace hal_sandbox
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_SandboxHal_h
|
||||
190
hal/windows/WindowsBattery.cpp
Normal file
190
hal/windows/WindowsBattery.cpp
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "HalImpl.h"
|
||||
#include "nsITimer.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/battery/Constants.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
|
||||
using namespace mozilla::dom::battery;
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
static nsCOMPtr<nsITimer> sUpdateTimer;
|
||||
|
||||
/* Power Event API is Vista or later */
|
||||
static decltype(RegisterPowerSettingNotification)* sRegisterPowerSettingNotification = nullptr;
|
||||
static decltype(UnregisterPowerSettingNotification)* sUnregisterPowerSettingNotification = nullptr;
|
||||
static HPOWERNOTIFY sPowerHandle = nullptr;
|
||||
static HPOWERNOTIFY sCapacityHandle = nullptr;
|
||||
static HWND sHWnd = nullptr;
|
||||
|
||||
static void
|
||||
UpdateHandler(nsITimer* aTimer, void* aClosure) {
|
||||
NS_ASSERTION(!IsVistaOrLater(),
|
||||
"We shouldn't call this function for Vista or later version!");
|
||||
|
||||
static hal::BatteryInformation sLastInfo;
|
||||
hal::BatteryInformation currentInfo;
|
||||
|
||||
hal_impl::GetCurrentBatteryInformation(¤tInfo);
|
||||
if (sLastInfo.level() != currentInfo.level() ||
|
||||
sLastInfo.charging() != currentInfo.charging() ||
|
||||
sLastInfo.remainingTime() != currentInfo.remainingTime()) {
|
||||
hal::NotifyBatteryChange(currentInfo);
|
||||
sLastInfo = currentInfo;
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
LRESULT CALLBACK
|
||||
BatteryWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
|
||||
if (msg != WM_POWERBROADCAST || wParam != PBT_POWERSETTINGCHANGE) {
|
||||
return DefWindowProc(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
hal::BatteryInformation currentInfo;
|
||||
|
||||
// Since we need update remainingTime, we cannot use LPARAM.
|
||||
hal_impl::GetCurrentBatteryInformation(¤tInfo);
|
||||
|
||||
hal::NotifyBatteryChange(currentInfo);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
EnableBatteryNotifications()
|
||||
{
|
||||
if (IsVistaOrLater()) {
|
||||
// RegisterPowerSettingNotification is from Vista or later.
|
||||
// Use this API if available.
|
||||
HMODULE hUser32 = GetModuleHandleW(L"USER32.DLL");
|
||||
if (!sRegisterPowerSettingNotification)
|
||||
sRegisterPowerSettingNotification = (decltype(RegisterPowerSettingNotification)*)
|
||||
GetProcAddress(hUser32, "RegisterPowerSettingNotification");
|
||||
if (!sUnregisterPowerSettingNotification)
|
||||
sUnregisterPowerSettingNotification = (decltype(UnregisterPowerSettingNotification)*)
|
||||
GetProcAddress(hUser32, "UnregisterPowerSettingNotification");
|
||||
|
||||
if (!sRegisterPowerSettingNotification ||
|
||||
!sUnregisterPowerSettingNotification) {
|
||||
NS_ASSERTION(false, "Canot find PowerSettingNotification functions.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create custom window to watch battery event
|
||||
// If we can get Gecko's window handle, this is unnecessary.
|
||||
|
||||
if (sHWnd == nullptr) {
|
||||
WNDCLASSW wc;
|
||||
HMODULE hSelf = GetModuleHandle(nullptr);
|
||||
|
||||
if (!GetClassInfoW(hSelf, L"MozillaBatteryClass", &wc)) {
|
||||
ZeroMemory(&wc, sizeof(WNDCLASSW));
|
||||
wc.hInstance = hSelf;
|
||||
wc.lpfnWndProc = BatteryWindowProc;
|
||||
wc.lpszClassName = L"MozillaBatteryClass";
|
||||
RegisterClassW(&wc);
|
||||
}
|
||||
|
||||
sHWnd = CreateWindowW(L"MozillaBatteryClass", L"Battery Watcher",
|
||||
0, 0, 0, 0, 0,
|
||||
nullptr, nullptr, hSelf, nullptr);
|
||||
}
|
||||
|
||||
if (sHWnd == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
sPowerHandle =
|
||||
sRegisterPowerSettingNotification(sHWnd,
|
||||
&GUID_ACDC_POWER_SOURCE,
|
||||
DEVICE_NOTIFY_WINDOW_HANDLE);
|
||||
sCapacityHandle =
|
||||
sRegisterPowerSettingNotification(sHWnd,
|
||||
&GUID_BATTERY_PERCENTAGE_REMAINING,
|
||||
DEVICE_NOTIFY_WINDOW_HANDLE);
|
||||
} else
|
||||
{
|
||||
// for Windows XP. If we remove Windows XP support,
|
||||
// we should remove timer-based power notification
|
||||
sUpdateTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
|
||||
if (sUpdateTimer) {
|
||||
sUpdateTimer->InitWithFuncCallback(UpdateHandler,
|
||||
nullptr,
|
||||
Preferences::GetInt("dom.battery.timer",
|
||||
30000 /* 30s */),
|
||||
nsITimer::TYPE_REPEATING_SLACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DisableBatteryNotifications()
|
||||
{
|
||||
if (IsVistaOrLater()) {
|
||||
if (sPowerHandle) {
|
||||
sUnregisterPowerSettingNotification(sPowerHandle);
|
||||
sPowerHandle = nullptr;
|
||||
}
|
||||
|
||||
if (sCapacityHandle) {
|
||||
sUnregisterPowerSettingNotification(sCapacityHandle);
|
||||
sCapacityHandle = nullptr;
|
||||
}
|
||||
|
||||
if (sHWnd) {
|
||||
DestroyWindow(sHWnd);
|
||||
sHWnd = nullptr;
|
||||
}
|
||||
} else
|
||||
{
|
||||
if (sUpdateTimer) {
|
||||
sUpdateTimer->Cancel();
|
||||
sUpdateTimer = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
|
||||
{
|
||||
SYSTEM_POWER_STATUS status;
|
||||
if (!GetSystemPowerStatus(&status)) {
|
||||
aBatteryInfo->level() = kDefaultLevel;
|
||||
aBatteryInfo->charging() = kDefaultCharging;
|
||||
aBatteryInfo->remainingTime() = kDefaultRemainingTime;
|
||||
return;
|
||||
}
|
||||
|
||||
aBatteryInfo->level() =
|
||||
status.BatteryLifePercent == 255 ? kDefaultLevel
|
||||
: ((double)status.BatteryLifePercent) / 100.0;
|
||||
aBatteryInfo->charging() = (status.ACLineStatus != 0);
|
||||
if (status.ACLineStatus != 0) {
|
||||
if (aBatteryInfo->level() == 1.0) {
|
||||
// GetSystemPowerStatus API may returns -1 for BatteryFullLifeTime.
|
||||
// So, if battery is 100%, set kDefaultRemainingTime at force.
|
||||
aBatteryInfo->remainingTime() = kDefaultRemainingTime;
|
||||
} else {
|
||||
aBatteryInfo->remainingTime() =
|
||||
status.BatteryFullLifeTime == (DWORD)-1 ? kUnknownRemainingTime
|
||||
: status.BatteryFullLifeTime;
|
||||
}
|
||||
} else {
|
||||
aBatteryInfo->remainingTime() =
|
||||
status.BatteryLifeTime == (DWORD)-1 ? kUnknownRemainingTime
|
||||
: status.BatteryLifeTime;
|
||||
}
|
||||
}
|
||||
|
||||
} // hal_impl
|
||||
} // mozilla
|
||||
184
hal/windows/WindowsSensor.cpp
Normal file
184
hal/windows/WindowsSensor.cpp
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
/* 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 <sensorsapi.h>
|
||||
#include <sensors.h>
|
||||
#include <portabledevicetypes.h>
|
||||
|
||||
#define MEAN_GRAVITY 9.80665
|
||||
#define DEFAULT_SENSOR_POLL 100
|
||||
|
||||
using namespace mozilla::hal;
|
||||
|
||||
namespace mozilla {
|
||||
namespace hal_impl {
|
||||
|
||||
static RefPtr<ISensor> sAccelerometer;
|
||||
|
||||
class SensorEvent final : public ISensorEvents {
|
||||
public:
|
||||
SensorEvent() : mCount(0) {
|
||||
}
|
||||
|
||||
// IUnknown interface
|
||||
|
||||
STDMETHODIMP_(ULONG) AddRef() {
|
||||
return InterlockedIncrement(&mCount);
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG) Release() {
|
||||
ULONG count = InterlockedDecrement(&mCount);
|
||||
if (!count) {
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
STDMETHODIMP QueryInterface(REFIID iid, void** ppv) {
|
||||
if (iid == IID_IUnknown) {
|
||||
*ppv = static_cast<IUnknown*>(this);
|
||||
} else if (iid == IID_ISensorEvents) {
|
||||
*ppv = static_cast<ISensorEvents*>(this);
|
||||
} else {
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
// ISensorEvents interface
|
||||
|
||||
STDMETHODIMP OnEvent(ISensor *aSensor, REFGUID aId, IPortableDeviceValues *aData) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP OnLeave(REFSENSOR_ID aId) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP OnStateChanged(ISensor *aSensor, SensorState state) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP OnDataUpdated(ISensor *aSensor, ISensorDataReport *aReport) {
|
||||
PROPVARIANT v;
|
||||
HRESULT hr;
|
||||
InfallibleTArray<float> values;
|
||||
|
||||
// X-axis acceleration in g's
|
||||
hr = aReport->GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_X_G, &v);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
values.AppendElement(float(-v.dblVal * MEAN_GRAVITY));
|
||||
|
||||
// Y-axis acceleration in g's
|
||||
hr = aReport->GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_Y_G, &v);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
values.AppendElement(float(-v.dblVal * MEAN_GRAVITY));
|
||||
|
||||
// Z-axis acceleration in g's
|
||||
hr = aReport->GetSensorValue(SENSOR_DATA_TYPE_ACCELERATION_Z_G, &v);
|
||||
if (FAILED(hr)) {
|
||||
return hr;
|
||||
}
|
||||
values.AppendElement(float(-v.dblVal * MEAN_GRAVITY));
|
||||
|
||||
hal::SensorData sdata(hal::SENSOR_ACCELERATION,
|
||||
PR_Now(),
|
||||
values,
|
||||
hal::SENSOR_ACCURACY_UNKNOWN);
|
||||
hal::NotifySensorChange(sdata);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
ULONG mCount;
|
||||
};
|
||||
|
||||
void
|
||||
EnableSensorNotifications(SensorType aSensor)
|
||||
{
|
||||
if (aSensor != SENSOR_ACCELERATION) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sAccelerometer) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<ISensorManager> manager;
|
||||
if (FAILED(CoCreateInstance(CLSID_SensorManager, nullptr,
|
||||
CLSCTX_INPROC_SERVER,
|
||||
IID_ISensorManager,
|
||||
getter_AddRefs(manager)))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// accelerometer event
|
||||
|
||||
RefPtr<ISensorCollection> collection;
|
||||
if (FAILED(manager->GetSensorsByType(SENSOR_TYPE_ACCELEROMETER_3D,
|
||||
getter_AddRefs(collection)))) {
|
||||
return;
|
||||
}
|
||||
|
||||
ULONG count = 0;
|
||||
collection->GetCount(&count);
|
||||
if (!count) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<ISensor> sensor;
|
||||
collection->GetAt(0, getter_AddRefs(sensor));
|
||||
if (!sensor) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set report interval to 100ms if possible.
|
||||
// Default value depends on drivers.
|
||||
RefPtr<IPortableDeviceValues> values;
|
||||
if (SUCCEEDED(CoCreateInstance(CLSID_PortableDeviceValues, nullptr,
|
||||
CLSCTX_INPROC_SERVER,
|
||||
IID_IPortableDeviceValues,
|
||||
getter_AddRefs(values)))) {
|
||||
if (SUCCEEDED(values->SetUnsignedIntegerValue(
|
||||
SENSOR_PROPERTY_CURRENT_REPORT_INTERVAL,
|
||||
DEFAULT_SENSOR_POLL))) {
|
||||
RefPtr<IPortableDeviceValues> returns;
|
||||
sensor->SetProperties(values, getter_AddRefs(returns));
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<SensorEvent> event = new SensorEvent();
|
||||
RefPtr<ISensorEvents> sensorEvents;
|
||||
if (FAILED(event->QueryInterface(IID_ISensorEvents,
|
||||
getter_AddRefs(sensorEvents)))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (FAILED(sensor->SetEventSink(sensorEvents))) {
|
||||
return;
|
||||
}
|
||||
|
||||
sAccelerometer = sensor;
|
||||
}
|
||||
|
||||
void
|
||||
DisableSensorNotifications(SensorType aSensor)
|
||||
{
|
||||
if (aSensor == SENSOR_ACCELERATION && sAccelerometer) {
|
||||
sAccelerometer->SetEventSink(nullptr);
|
||||
sAccelerometer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // hal_impl
|
||||
} // mozilla
|
||||
Loading…
Add table
Add a link
Reference in a new issue