1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=8 et ft=cpp : */
3 /* Copyright 2012 Mozilla Foundation and Mozilla contributors
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
21 #include <linux/android_alarm.h>
27 #include <sys/syscall.h>
28 #include <sys/resource.h>
32 #include "mozilla/DebugOnly.h"
34 #include "android/log.h"
35 #include "cutils/properties.h"
36 #include "hardware/hardware.h"
37 #include "hardware/lights.h"
38 #include "hardware_legacy/uevent.h"
39 #include "hardware_legacy/vibrator.h"
40 #include "hardware_legacy/power.h"
41 #include "libdisplay/GonkDisplay.h"
42 #include "utils/threads.h"
44 #include "base/message_loop.h"
48 #include "mozilla/ArrayUtils.h"
49 #include "mozilla/dom/battery/Constants.h"
50 #include "mozilla/FileUtils.h"
51 #include "mozilla/Monitor.h"
52 #include "mozilla/RefPtr.h"
53 #include "mozilla/Services.h"
54 #include "mozilla/StaticPtr.h"
55 #include "mozilla/Preferences.h"
56 #include "nsAlgorithm.h"
57 #include "nsPrintfCString.h"
58 #include "nsIObserver.h"
59 #include "nsIObserverService.h"
60 #include "nsIRecoveryService.h"
61 #include "nsIRunnable.h"
62 #include "nsScreenManagerGonk.h"
63 #include "nsThreadUtils.h"
64 #include "nsThreadUtils.h"
65 #include "nsIThread.h"
66 #include "nsXULAppAPI.h"
67 #include "OrientationObserver.h"
68 #include "UeventPoller.h"
69 #include "nsIWritablePropertyBag2.h"
72 #define NsecPerMsec 1000000LL
73 #define NsecPerSec 1000000000
75 // The header linux/oom.h is not available in bionic libc. We
76 // redefine some of its constants here.
79 #define OOM_DISABLE (-17)
82 #ifndef OOM_ADJUST_MIN
83 #define OOM_ADJUST_MIN (-16)
86 #ifndef OOM_ADJUST_MAX
87 #define OOM_ADJUST_MAX 15
90 #ifndef OOM_SCORE_ADJ_MIN
91 #define OOM_SCORE_ADJ_MIN (-1000)
94 #ifndef OOM_SCORE_ADJ_MAX
95 #define OOM_SCORE_ADJ_MAX 1000
98 #ifndef BATTERY_CHARGING_ARGB
99 #define BATTERY_CHARGING_ARGB 0x00FF0000
101 #ifndef BATTERY_FULL_ARGB
102 #define BATTERY_FULL_ARGB 0x0000FF00
105 using namespace mozilla
;
106 using namespace mozilla::hal
;
107 using namespace mozilla::dom
;
112 struct LightConfiguration
{
113 hal::LightType light
;
115 hal::FlashMode flash
;
121 static light_device_t
* sLights
[hal::eHalLightID_Count
]; // will be initialized to nullptr
123 static light_device_t
*
124 GetDevice(hw_module_t
* module
, char const* name
)
128 err
= module
->methods
->open(module
, name
, &device
);
130 return (light_device_t
*)device
;
139 // assume that if backlight is nullptr, nothing has been set yet
140 // if this is not true, the initialization will occur everytime a light is read or set!
141 if (!sLights
[hal::eHalLightID_Backlight
]) {
145 err
= hw_get_module(LIGHTS_HARDWARE_MODULE_ID
, (hw_module_t
const**)&module
);
147 sLights
[hal::eHalLightID_Backlight
]
148 = GetDevice(module
, LIGHT_ID_BACKLIGHT
);
149 sLights
[hal::eHalLightID_Keyboard
]
150 = GetDevice(module
, LIGHT_ID_KEYBOARD
);
151 sLights
[hal::eHalLightID_Buttons
]
152 = GetDevice(module
, LIGHT_ID_BUTTONS
);
153 sLights
[hal::eHalLightID_Battery
]
154 = GetDevice(module
, LIGHT_ID_BATTERY
);
155 sLights
[hal::eHalLightID_Notifications
]
156 = GetDevice(module
, LIGHT_ID_NOTIFICATIONS
);
157 sLights
[hal::eHalLightID_Attention
]
158 = GetDevice(module
, LIGHT_ID_ATTENTION
);
159 sLights
[hal::eHalLightID_Bluetooth
]
160 = GetDevice(module
, LIGHT_ID_BLUETOOTH
);
161 sLights
[hal::eHalLightID_Wifi
]
162 = GetDevice(module
, LIGHT_ID_WIFI
);
168 * The state last set for the lights until liblights supports
169 * getting the light state.
171 static light_state_t sStoredLightState
[hal::eHalLightID_Count
];
174 * Set the value of a light to a particular color, with a specific flash pattern.
175 * light specifices which light. See Hal.idl for the list of constants
176 * mode specifies user set or based on ambient light sensor
177 * flash specifies whether or how to flash the light
178 * flashOnMS and flashOffMS specify the pattern for XXX flash mode
179 * color specifies the color. If the light doesn't support color, the given color is
180 * transformed into a brightness, or just an on/off if that is all the light is capable of.
181 * returns true if successful and false if failed.
184 SetLight(hal::LightType light
, const LightConfiguration
& aConfig
)
190 if (light
< 0 || light
>= hal::eHalLightID_Count
||
191 sLights
[light
] == nullptr) {
195 memset(&state
, 0, sizeof(light_state_t
));
196 state
.color
= aConfig
.color
;
197 state
.flashMode
= aConfig
.flash
;
198 state
.flashOnMS
= aConfig
.flashOnMS
;
199 state
.flashOffMS
= aConfig
.flashOffMS
;
200 state
.brightnessMode
= aConfig
.mode
;
202 sLights
[light
]->set_light(sLights
[light
], &state
);
203 sStoredLightState
[light
] = state
;
208 * GET the value of a light returning a particular color, with a specific flash pattern.
209 * returns true if successful and false if failed.
212 GetLight(hal::LightType light
, LightConfiguration
* aConfig
)
216 if (light
< 0 || light
>= hal::eHalLightID_Count
||
217 sLights
[light
] == nullptr) {
221 memset(&state
, 0, sizeof(light_state_t
));
222 state
= sStoredLightState
[light
];
224 aConfig
->light
= light
;
225 aConfig
->color
= state
.color
;
226 aConfig
->flash
= hal::FlashMode(state
.flashMode
);
227 aConfig
->flashOnMS
= state
.flashOnMS
;
228 aConfig
->flashOffMS
= state
.flashOffMS
;
229 aConfig
->mode
= hal::LightMode(state
.brightnessMode
);
237 * This runnable runs for the lifetime of the program, once started. It's
238 * responsible for "playing" vibration patterns.
240 class VibratorRunnable
246 : mMonitor("VibratorRunnable")
249 nsCOMPtr
<nsIObserverService
> os
= services::GetObserverService();
251 NS_WARNING("Could not get observer service!");
255 os
->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID
, false);
258 NS_DECL_THREADSAFE_ISUPPORTS
262 // Run on the main thread, not the vibrator thread.
263 void Vibrate(const nsTArray
<uint32_t> &pattern
);
264 void CancelVibrate();
266 static bool ShuttingDown() { return sShuttingDown
; }
271 // The currently-playing pattern.
272 nsTArray
<uint32_t> mPattern
;
274 // The index we're at in the currently-playing pattern. If mIndex >=
275 // mPattern.Length(), then we're not currently playing anything.
278 // Set to true in our shutdown observer. When this is true, we kill the
280 static bool sShuttingDown
;
283 NS_IMPL_ISUPPORTS(VibratorRunnable
, nsIRunnable
, nsIObserver
);
285 bool VibratorRunnable::sShuttingDown
= false;
287 static StaticRefPtr
<VibratorRunnable
> sVibratorRunnable
;
290 VibratorRunnable::Run()
292 MonitorAutoLock
lock(mMonitor
);
294 // We currently assume that mMonitor.Wait(X) waits for X milliseconds. But in
295 // reality, the kernel might not switch to this thread for some time after the
296 // wait expires. So there's potential for some inaccuracy here.
298 // This doesn't worry me too much. Note that we don't even start vibrating
299 // immediately when VibratorRunnable::Vibrate is called -- we go through a
300 // condvar onto another thread. Better just to be chill about small errors in
303 while (!sShuttingDown
) {
304 if (mIndex
< mPattern
.Length()) {
305 uint32_t duration
= mPattern
[mIndex
];
306 if (mIndex
% 2 == 0) {
307 vibrator_on(duration
);
310 mMonitor
.Wait(PR_MillisecondsToInterval(duration
));
316 sVibratorRunnable
= nullptr;
321 VibratorRunnable::Observe(nsISupports
*subject
, const char *topic
,
322 const char16_t
*data
)
324 MOZ_ASSERT(strcmp(topic
, NS_XPCOM_SHUTDOWN_OBSERVER_ID
) == 0);
325 MonitorAutoLock
lock(mMonitor
);
326 sShuttingDown
= true;
333 VibratorRunnable::Vibrate(const nsTArray
<uint32_t> &pattern
)
335 MonitorAutoLock
lock(mMonitor
);
342 VibratorRunnable::CancelVibrate()
344 MonitorAutoLock
lock(mMonitor
);
346 mPattern
.AppendElement(0);
352 EnsureVibratorThreadInitialized()
354 if (sVibratorRunnable
) {
358 sVibratorRunnable
= new VibratorRunnable();
359 nsCOMPtr
<nsIThread
> thread
;
360 NS_NewThread(getter_AddRefs(thread
), sVibratorRunnable
);
363 } // anonymous namespace
366 Vibrate(const nsTArray
<uint32_t> &pattern
, const hal::WindowIdentifier
&)
368 MOZ_ASSERT(NS_IsMainThread());
369 if (VibratorRunnable::ShuttingDown()) {
372 EnsureVibratorThreadInitialized();
373 sVibratorRunnable
->Vibrate(pattern
);
377 CancelVibrate(const hal::WindowIdentifier
&)
379 MOZ_ASSERT(NS_IsMainThread());
380 if (VibratorRunnable::ShuttingDown()) {
383 EnsureVibratorThreadInitialized();
384 sVibratorRunnable
->CancelVibrate();
389 class BatteryUpdater
: public nsRunnable
{
393 hal::BatteryInformation info
;
394 hal_impl::GetCurrentBatteryInformation(&info
);
396 // Control the battery indicator (led light) here using BatteryInformation
397 // we just retrieved.
398 uint32_t color
= 0; // Format: 0x00rrggbb.
399 if (info
.charging() && (info
.level() == 1)) {
400 // Charging and battery full.
401 color
= BATTERY_FULL_ARGB
;
402 } else if (info
.charging() && (info
.level() < 1)) {
403 // Charging but not full.
404 color
= BATTERY_CHARGING_ARGB
;
405 } // else turn off battery indicator.
407 LightConfiguration aConfig
;
408 aConfig
.light
= hal::eHalLightID_Battery
;
409 aConfig
.mode
= hal::eHalLightMode_User
;
410 aConfig
.flash
= hal::eHalLightFlash_None
;
411 aConfig
.flashOnMS
= aConfig
.flashOffMS
= 0;
412 aConfig
.color
= color
;
414 SetLight(hal::eHalLightID_Battery
, aConfig
);
416 hal::NotifyBatteryChange(info
);
420 // Gecko gonk hal is required to emit battery charging/level notification via nsIObserverService.
421 // This is useful for XPCOM components that are not statically linked to Gecko and cannot call
422 // hal::EnableBatteryNotifications
423 nsCOMPtr
<nsIObserverService
> obsService
= mozilla::services::GetObserverService();
424 nsCOMPtr
<nsIWritablePropertyBag2
> propbag
=
425 do_CreateInstance("@mozilla.org/hash-property-bag;1");
426 if (obsService
&& propbag
) {
427 propbag
->SetPropertyAsBool(NS_LITERAL_STRING("charging"),
429 propbag
->SetPropertyAsDouble(NS_LITERAL_STRING("level"),
432 obsService
->NotifyObservers(propbag
, "gonkhal-battery-notifier", nullptr);
440 } // anonymous namespace
442 class BatteryObserver
: public IUeventObserver
445 NS_INLINE_DECL_REFCOUNTING(BatteryObserver
)
448 :mUpdater(new BatteryUpdater())
452 virtual void Notify(const NetlinkEvent
&aEvent
)
454 // this will run on IO thread
455 NetlinkEvent
*event
= const_cast<NetlinkEvent
*>(&aEvent
);
456 const char *subsystem
= event
->getSubsystem();
457 // e.g. DEVPATH=/devices/platform/sec-battery/power_supply/battery
458 const char *devpath
= event
->findParam("DEVPATH");
459 if (strcmp(subsystem
, "power_supply") == 0 &&
460 strstr(devpath
, "battery")) {
461 // aEvent will be valid only in this method.
462 NS_DispatchToMainThread(mUpdater
);
467 nsRefPtr
<BatteryUpdater
> mUpdater
;
470 // sBatteryObserver is owned by the IO thread. Only the IO thread may
471 // create or destroy it.
472 static StaticRefPtr
<BatteryObserver
> sBatteryObserver
;
475 RegisterBatteryObserverIOThread()
477 MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
478 MOZ_ASSERT(!sBatteryObserver
);
480 sBatteryObserver
= new BatteryObserver();
481 RegisterUeventListener(sBatteryObserver
);
485 EnableBatteryNotifications()
487 XRE_GetIOMessageLoop()->PostTask(
489 NewRunnableFunction(RegisterBatteryObserverIOThread
));
493 UnregisterBatteryObserverIOThread()
495 MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
496 MOZ_ASSERT(sBatteryObserver
);
498 UnregisterUeventListener(sBatteryObserver
);
499 sBatteryObserver
= nullptr;
503 DisableBatteryNotifications()
505 XRE_GetIOMessageLoop()->PostTask(
507 NewRunnableFunction(UnregisterBatteryObserverIOThread
));
511 GetCurrentBatteryCharge(int* aCharge
)
513 bool success
= ReadSysFile("/sys/class/power_supply/battery/capacity",
520 if ((*aCharge
< 0) || (*aCharge
> 100)) {
521 HAL_LOG(("charge level contains unknown value: %d", *aCharge
));
525 return (*aCharge
>= 0) && (*aCharge
<= 100);
529 GetCurrentBatteryCharging(int* aCharging
)
531 static const int BATTERY_NOT_CHARGING
= 0;
532 static const int BATTERY_CHARGING_USB
= 1;
533 static const int BATTERY_CHARGING_AC
= 2;
535 // Generic device support
539 ReadSysFile("/sys/class/power_supply/battery/charging_source", &chargingSrc
);
543 if (chargingSrc
!= BATTERY_NOT_CHARGING
&&
544 chargingSrc
!= BATTERY_CHARGING_USB
&&
545 chargingSrc
!= BATTERY_CHARGING_AC
) {
546 HAL_LOG(("charging_source contained unknown value: %d", chargingSrc
));
550 *aCharging
= (chargingSrc
== BATTERY_CHARGING_USB
||
551 chargingSrc
== BATTERY_CHARGING_AC
);
555 // Otoro device support
557 char chargingSrcString
[16];
559 success
= ReadSysFile("/sys/class/power_supply/battery/status",
560 chargingSrcString
, sizeof(chargingSrcString
));
562 *aCharging
= strcmp(chargingSrcString
, "Charging") == 0 ||
563 strcmp(chargingSrcString
, "Full") == 0;
571 GetCurrentBatteryInformation(hal::BatteryInformation
* aBatteryInfo
)
575 if (GetCurrentBatteryCharge(&charge
)) {
576 aBatteryInfo
->level() = (double)charge
/ 100.0;
578 aBatteryInfo
->level() = dom::battery::kDefaultLevel
;
583 if (GetCurrentBatteryCharging(&charging
)) {
584 aBatteryInfo
->charging() = charging
;
586 aBatteryInfo
->charging() = true;
589 if (!aBatteryInfo
->charging() || (aBatteryInfo
->level() < 1.0)) {
590 aBatteryInfo
->remainingTime() = dom::battery::kUnknownRemainingTime
;
592 aBatteryInfo
->remainingTime() = dom::battery::kDefaultRemainingTime
;
599 * RAII class to help us remember to close file descriptors.
601 const char *wakeLockFilename
= "/sys/power/wake_lock";
602 const char *wakeUnlockFilename
= "/sys/power/wake_unlock";
605 bool ReadFromFile(const char *filename
, char (&buf
)[n
])
607 int fd
= open(filename
, O_RDONLY
);
608 ScopedClose
autoClose(fd
);
610 HAL_LOG(("Unable to open file %s.", filename
));
614 ssize_t numRead
= read(fd
, buf
, n
);
616 HAL_LOG(("Error reading from file %s.", filename
));
620 buf
[std::min(numRead
, n
- 1)] = '\0';
624 bool WriteToFile(const char *filename
, const char *toWrite
)
626 int fd
= open(filename
, O_WRONLY
);
627 ScopedClose
autoClose(fd
);
629 HAL_LOG(("Unable to open file %s.", filename
));
633 if (write(fd
, toWrite
, strlen(toWrite
)) < 0) {
634 HAL_LOG(("Unable to write to file %s.", filename
));
641 // We can write to screenEnabledFilename to enable/disable the screen, but when
642 // we read, we always get "mem"! So we have to keep track ourselves whether
643 // the screen is on or not.
644 bool sScreenEnabled
= true;
646 // We can read wakeLockFilename to find out whether the cpu wake lock
647 // is already acquired, but reading and parsing it is a lot more work
648 // than tracking it ourselves, and it won't be accurate anyway (kernel
649 // internal wake locks aren't counted here.)
650 bool sCpuSleepAllowed
= true;
652 // Some CPU wake locks may be acquired internally in HAL. We use a counter to
653 // keep track of these needs. Note we have to hold |sInternalLockCpuMonitor|
654 // when reading or writing this variable to ensure thread-safe.
655 int32_t sInternalLockCpuCount
= 0;
657 } // anonymous namespace
662 return sScreenEnabled
;
666 SetScreenEnabled(bool aEnabled
)
668 GetGonkDisplay()->SetEnabled(aEnabled
);
669 sScreenEnabled
= aEnabled
;
675 LightConfiguration config
;
676 GetLight(hal::eHalLightID_Buttons
, &config
);
677 return (config
.color
!= 0x00000000);
681 SetKeyLightEnabled(bool aEnabled
)
683 LightConfiguration config
;
684 config
.mode
= hal::eHalLightMode_User
;
685 config
.flash
= hal::eHalLightFlash_None
;
686 config
.flashOnMS
= config
.flashOffMS
= 0;
687 config
.color
= 0x00000000;
690 // Convert the value in [0, 1] to an int between 0 and 255 and then convert
691 // it to a color. Note that the high byte is FF, corresponding to the alpha
693 double brightness
= GetScreenBrightness();
694 uint32_t val
= static_cast<int>(round(brightness
* 255.0));
695 uint32_t color
= (0xff<<24) + (val
<<16) + (val
<<8) + val
;
697 config
.color
= color
;
700 SetLight(hal::eHalLightID_Buttons
, config
);
701 SetLight(hal::eHalLightID_Keyboard
, config
);
705 GetScreenBrightness()
707 LightConfiguration config
;
708 hal::LightType light
= hal::eHalLightID_Backlight
;
710 GetLight(light
, &config
);
711 // backlight is brightness only, so using one of the RGB elements as value.
712 int brightness
= config
.color
& 0xFF;
713 return brightness
/ 255.0;
717 SetScreenBrightness(double brightness
)
719 // Don't use De Morgan's law to push the ! into this expression; we want to
721 if (!(0 <= brightness
&& brightness
<= 1)) {
722 HAL_LOG(("SetScreenBrightness: Dropping illegal brightness %f.",
727 // Convert the value in [0, 1] to an int between 0 and 255 and convert to a color
728 // note that the high byte is FF, corresponding to the alpha channel.
729 uint32_t val
= static_cast<int>(round(brightness
* 255.0));
730 uint32_t color
= (0xff<<24) + (val
<<16) + (val
<<8) + val
;
732 LightConfiguration config
;
733 config
.mode
= hal::eHalLightMode_User
;
734 config
.flash
= hal::eHalLightFlash_None
;
735 config
.flashOnMS
= config
.flashOffMS
= 0;
736 config
.color
= color
;
737 SetLight(hal::eHalLightID_Backlight
, config
);
738 if (GetKeyLightEnabled()) {
739 SetLight(hal::eHalLightID_Buttons
, config
);
740 SetLight(hal::eHalLightID_Keyboard
, config
);
744 static Monitor
* sInternalLockCpuMonitor
= nullptr;
747 UpdateCpuSleepState()
749 sInternalLockCpuMonitor
->AssertCurrentThreadOwns();
750 bool allowed
= sCpuSleepAllowed
&& !sInternalLockCpuCount
;
751 WriteToFile(allowed
? wakeUnlockFilename
: wakeLockFilename
, "gecko");
756 MonitorAutoLock
monitor(*sInternalLockCpuMonitor
);
757 ++sInternalLockCpuCount
;
758 UpdateCpuSleepState();
762 InternalUnlockCpu() {
763 MonitorAutoLock
monitor(*sInternalLockCpuMonitor
);
764 --sInternalLockCpuCount
;
765 UpdateCpuSleepState();
771 return sCpuSleepAllowed
;
775 SetCpuSleepAllowed(bool aAllowed
)
777 MonitorAutoLock
monitor(*sInternalLockCpuMonitor
);
778 sCpuSleepAllowed
= aAllowed
;
779 UpdateCpuSleepState();
783 AdjustSystemClock(int64_t aDeltaMilliseconds
)
788 if (aDeltaMilliseconds
== 0) {
792 // Preventing context switch before setting system clock
794 clock_gettime(CLOCK_REALTIME
, &now
);
795 now
.tv_sec
+= (time_t)(aDeltaMilliseconds
/ 1000LL);
796 now
.tv_nsec
+= (long)((aDeltaMilliseconds
% 1000LL) * NsecPerMsec
);
797 if (now
.tv_nsec
>= NsecPerSec
) {
799 now
.tv_nsec
-= NsecPerSec
;
802 if (now
.tv_nsec
< 0) {
803 now
.tv_nsec
+= NsecPerSec
;
808 fd
= open("/dev/alarm", O_RDWR
);
809 } while (fd
== -1 && errno
== EINTR
);
810 ScopedClose
autoClose(fd
);
812 HAL_LOG(("Failed to open /dev/alarm: %s", strerror(errno
)));
816 if (ioctl(fd
, ANDROID_ALARM_SET_RTC
, &now
) < 0) {
817 HAL_LOG(("ANDROID_ALARM_SET_RTC failed: %s", strerror(errno
)));
820 hal::NotifySystemClockChange(aDeltaMilliseconds
);
826 PRExplodedTime prTime
;
827 PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters
, &prTime
);
829 // Daylight saving time (DST) will be taken into account.
830 int32_t offset
= prTime
.tm_params
.tp_gmt_offset
;
831 offset
+= prTime
.tm_params
.tp_dst_offset
;
833 // Returns the timezone offset relative to UTC in minutes.
834 return -(offset
/ 60);
837 static int32_t sKernelTimezoneOffset
= 0;
840 UpdateKernelTimezone(int32_t timezoneOffset
)
842 if (sKernelTimezoneOffset
== timezoneOffset
) {
846 // Tell the kernel about the new time zone as well, so that FAT filesystems
847 // will get local timestamps rather than UTC timestamps.
849 // We assume that /init.rc has a sysclktz entry so that settimeofday has
850 // already been called once before we call it (there is a side-effect in
851 // the kernel the very first time settimeofday is called where it does some
852 // special processing if you only set the timezone).
854 memset(&tz
, 0, sizeof(tz
));
855 tz
.tz_minuteswest
= timezoneOffset
;
856 settimeofday(nullptr, &tz
);
857 sKernelTimezoneOffset
= timezoneOffset
;
861 SetTimezone(const nsCString
& aTimezoneSpec
)
863 if (aTimezoneSpec
.Equals(GetTimezone())) {
864 // Even though the timezone hasn't changed, we still need to tell the
865 // kernel what the current timezone is. The timezone is persisted in
866 // a property and doesn't change across reboots, but the kernel still
867 // needs to be updated on every boot.
868 UpdateKernelTimezone(GetTimezoneOffset());
872 int32_t oldTimezoneOffsetMinutes
= GetTimezoneOffset();
873 property_set("persist.sys.timezone", aTimezoneSpec
.get());
874 // This function is automatically called by the other time conversion
875 // functions that depend on the timezone. To be safe, we call it manually.
877 int32_t newTimezoneOffsetMinutes
= GetTimezoneOffset();
878 UpdateKernelTimezone(newTimezoneOffsetMinutes
);
879 hal::NotifySystemTimezoneChange(
880 hal::SystemTimezoneChangeInformation(
881 oldTimezoneOffsetMinutes
, newTimezoneOffsetMinutes
));
888 property_get("persist.sys.timezone", timezone
, "");
889 return nsCString(timezone
);
893 EnableSystemClockChangeNotifications()
898 DisableSystemClockChangeNotifications()
903 EnableSystemTimezoneChangeNotifications()
908 DisableSystemTimezoneChangeNotifications()
912 // Nothing to do here. Gonk widgetry always listens for screen
913 // orientation changes.
915 EnableScreenConfigurationNotifications()
920 DisableScreenConfigurationNotifications()
925 GetCurrentScreenConfiguration(hal::ScreenConfiguration
* aScreenConfiguration
)
927 *aScreenConfiguration
= nsScreenGonk::GetConfiguration();
931 LockScreenOrientation(const dom::ScreenOrientation
& aOrientation
)
933 return OrientationObserver::GetInstance()->LockScreenOrientation(aOrientation
);
937 UnlockScreenOrientation()
939 OrientationObserver::GetInstance()->UnlockScreenOrientation();
942 // This thread will wait for the alarm firing by a blocking IO.
943 static pthread_t sAlarmFireWatcherThread
;
945 // If |sAlarmData| is non-null, it's owned by the alarm-watcher thread.
948 AlarmData(int aFd
) : mFd(aFd
),
949 mGeneration(sNextGeneration
++),
950 mShuttingDown(false) {}
955 static int sNextGeneration
;
959 int AlarmData::sNextGeneration
= 0;
961 AlarmData
* sAlarmData
= nullptr;
963 class AlarmFiredEvent
: public nsRunnable
{
965 AlarmFiredEvent(int aGeneration
) : mGeneration(aGeneration
) {}
968 // Guard against spurious notifications caused by an alarm firing
969 // concurrently with it being disabled.
970 if (sAlarmData
&& !sAlarmData
->mShuttingDown
&&
971 mGeneration
== sAlarmData
->mGeneration
) {
972 hal::NotifyAlarmFired();
974 // The fired alarm event has been delivered to the observer (if needed);
975 // we can now release a CPU wake lock.
984 // Runs on alarm-watcher thread.
986 DestroyAlarmData(void* aData
)
988 AlarmData
* alarmData
= static_cast<AlarmData
*>(aData
);
992 // Runs on alarm-watcher thread.
993 void ShutDownAlarm(int aSigno
)
995 if (aSigno
== SIGUSR1
&& sAlarmData
) {
996 sAlarmData
->mShuttingDown
= true;
1002 WaitForAlarm(void* aData
)
1004 pthread_cleanup_push(DestroyAlarmData
, aData
);
1006 AlarmData
* alarmData
= static_cast<AlarmData
*>(aData
);
1008 while (!alarmData
->mShuttingDown
) {
1009 int alarmTypeFlags
= 0;
1011 // ALARM_WAIT apparently will block even if an alarm hasn't been
1012 // programmed, although this behavior doesn't seem to be
1013 // documented. We rely on that here to avoid spinning the CPU
1014 // while awaiting an alarm to be programmed.
1016 alarmTypeFlags
= ioctl(alarmData
->mFd
, ANDROID_ALARM_WAIT
);
1017 } while (alarmTypeFlags
< 0 && errno
== EINTR
&&
1018 !alarmData
->mShuttingDown
);
1020 if (!alarmData
->mShuttingDown
&& alarmTypeFlags
>= 0 &&
1021 (alarmTypeFlags
& ANDROID_ALARM_RTC_WAKEUP_MASK
)) {
1022 // To make sure the observer can get the alarm firing notification
1023 // *on time* (the system won't sleep during the process in any way),
1024 // we need to acquire a CPU wake lock before firing the alarm event.
1026 nsRefPtr
<AlarmFiredEvent
> event
=
1027 new AlarmFiredEvent(alarmData
->mGeneration
);
1028 NS_DispatchToMainThread(event
);
1032 pthread_cleanup_pop(1);
1039 MOZ_ASSERT(!sAlarmData
);
1041 int alarmFd
= open("/dev/alarm", O_RDWR
);
1043 HAL_LOG(("Failed to open alarm device: %s.", strerror(errno
)));
1047 nsAutoPtr
<AlarmData
> alarmData(new AlarmData(alarmFd
));
1049 struct sigaction actions
;
1050 memset(&actions
, 0, sizeof(actions
));
1051 sigemptyset(&actions
.sa_mask
);
1052 actions
.sa_flags
= 0;
1053 actions
.sa_handler
= ShutDownAlarm
;
1054 if (sigaction(SIGUSR1
, &actions
, nullptr)) {
1055 HAL_LOG(("Failed to set SIGUSR1 signal for alarm-watcher thread."));
1059 pthread_attr_t attr
;
1060 pthread_attr_init(&attr
);
1061 pthread_attr_setdetachstate(&attr
, PTHREAD_CREATE_DETACHED
);
1063 // Initialize the monitor for internally locking CPU to ensure thread-safe
1064 // before running the alarm-watcher thread.
1065 sInternalLockCpuMonitor
= new Monitor("sInternalLockCpuMonitor");
1066 int status
= pthread_create(&sAlarmFireWatcherThread
, &attr
, WaitForAlarm
,
1069 alarmData
= nullptr;
1070 delete sInternalLockCpuMonitor
;
1071 HAL_LOG(("Failed to create alarm-watcher thread. Status: %d.", status
));
1075 pthread_attr_destroy(&attr
);
1077 // The thread owns this now. We only hold a pointer.
1078 sAlarmData
= alarmData
.forget();
1085 MOZ_ASSERT(sAlarmData
);
1087 // NB: this must happen-before the thread cancellation.
1088 sAlarmData
= nullptr;
1090 // The cancel will interrupt the thread and destroy it, freeing the
1091 // data pointed at by sAlarmData.
1092 DebugOnly
<int> err
= pthread_kill(sAlarmFireWatcherThread
, SIGUSR1
);
1095 delete sInternalLockCpuMonitor
;
1099 SetAlarm(int32_t aSeconds
, int32_t aNanoseconds
)
1102 HAL_LOG(("We should have enabled the alarm."));
1107 ts
.tv_sec
= aSeconds
;
1108 ts
.tv_nsec
= aNanoseconds
;
1110 // Currently we only support RTC wakeup alarm type.
1111 const int result
= ioctl(sAlarmData
->mFd
,
1112 ANDROID_ALARM_SET(ANDROID_ALARM_RTC_WAKEUP
), &ts
);
1115 HAL_LOG(("Unable to set alarm: %s.", strerror(errno
)));
1123 OomAdjOfOomScoreAdj(int aOomScoreAdj
)
1125 // Convert OOM adjustment from the domain of /proc/<pid>/oom_score_adj
1126 // to the domain of /proc/<pid>/oom_adj.
1130 if (aOomScoreAdj
< 0) {
1131 adj
= (OOM_DISABLE
* aOomScoreAdj
) / OOM_SCORE_ADJ_MIN
;
1133 adj
= (OOM_ADJUST_MAX
* aOomScoreAdj
) / OOM_SCORE_ADJ_MAX
;
1140 RoundOomScoreAdjUpWithBackroundLRU(int& aOomScoreAdj
, uint32_t aBackgroundLRU
)
1142 // We want to add minimum value to round OomScoreAdj up according to
1143 // the steps by aBackgroundLRU.
1145 ceil(((float)OOM_SCORE_ADJ_MAX
/ OOM_ADJUST_MAX
) * aBackgroundLRU
);
1148 #define OOM_LOG(level, args...) __android_log_print(level, "OomLogger", ##args)
1149 class OomVictimLogger MOZ_FINAL
1150 : public nsIObserver
1154 : mLastLineChecked(-1.0),
1157 // Enable timestamps in kernel's printk
1158 WriteToFile("/sys/module/printk/parameters/time", "Y");
1164 double mLastLineChecked
;
1165 ScopedFreePtr
<regex_t
> mRegexes
;
1167 NS_IMPL_ISUPPORTS(OomVictimLogger
, nsIObserver
);
1170 OomVictimLogger::Observe(
1171 nsISupports
* aSubject
,
1173 const char16_t
* aData
)
1175 nsDependentCString
event_type(aTopic
);
1176 if (!event_type
.EqualsLiteral("ipc:content-shutdown")) {
1180 // OOM message finding regexes
1181 const char* const regexes_raw
[] = {
1182 ".*select.*to kill.*",
1183 ".*send sigkill to.*",
1184 ".*lowmem_shrink.*",
1185 ".*[Oo]ut of [Mm]emory.*",
1186 ".*[Kk]ill [Pp]rocess.*",
1187 ".*[Kk]illed [Pp]rocess.*",
1189 // The regexes below are for the output of dump_task from oom_kill.c
1190 // 1st - title 2nd - body lines (8 ints and a string)
1191 // oom_adj and oom_score_adj can be negative
1192 "\\[ pid \\] uid tgid total_vm rss cpu oom_adj oom_score_adj name",
1193 "\\[.*[0-9][0-9]*\\][ ]*[0-9][0-9]*[ ]*[0-9][0-9]*[ ]*[0-9][0-9]*[ ]*[0-9][0-9]*[ ]*[0-9][0-9]*[ ]*.[0-9][0-9]*[ ]*.[0-9][0-9]*.*"
1195 const size_t regex_count
= ArrayLength(regexes_raw
);
1197 // Compile our regex just in time
1199 mRegexes
= static_cast<regex_t
*>(malloc(sizeof(regex_t
) * regex_count
));
1200 for (size_t i
= 0; i
< regex_count
; i
++) {
1201 int compilation_err
= regcomp(&(mRegexes
[i
]), regexes_raw
[i
], REG_NOSUB
);
1202 if (compilation_err
) {
1203 OOM_LOG(ANDROID_LOG_ERROR
, "Cannot compile regex \"%s\"\n", regexes_raw
[i
]);
1209 #ifndef KLOG_SIZE_BUFFER
1210 // Upstream bionic in commit
1211 // e249b059637b49a285ed9f58a2a18bfd054e5d95
1212 // deprecated the old klog defs.
1213 // Our current bionic does not hit this
1214 // change yet so handle the future change.
1215 #define KLOG_SIZE_BUFFER KLOG_WRITE
1217 // Once the change hits our bionic this ifndef
1219 #warning "Please remove KLOG_UNREAD_SIZE compatability def"
1221 // Retreive kernel log
1222 int msg_buf_size
= klogctl(KLOG_SIZE_BUFFER
, NULL
, 0);
1223 ScopedFreePtr
<char> msg_buf(static_cast<char *>(malloc(msg_buf_size
+ 1)));
1224 int read_size
= klogctl(KLOG_READ_ALL
, msg_buf
.rwget(), msg_buf_size
);
1226 // Turn buffer into cstring
1227 read_size
= read_size
> msg_buf_size
? msg_buf_size
: read_size
;
1228 msg_buf
.rwget()[read_size
] = '\0';
1232 char* line_begin
= msg_buf
.rwget();
1233 for (; (line_end
= strchr(line_begin
, '\n')); line_begin
= line_end
+ 1) {
1234 // make line into cstring
1237 // Note: Kernel messages look like:
1238 // <5>[63648.286409] sd 35:0:0:0: Attached scsi generic sg1 type 0
1239 // 5 is the loging level
1240 // [*] is the time timestamp, seconds since boot
1241 // last comes the logged message
1243 // Since the logging level can be a string we must
1244 // skip it since scanf lacks wildcard matching
1245 char* timestamp_begin
= strchr(line_begin
, '[');
1247 double lineTimestamp
= -1;
1248 bool lineTimestampFound
= false;
1249 if (timestamp_begin
&&
1250 // Note: scanf treats a ' ' as [ ]*
1251 // Note: scanf treats [ %lf] as [ %lf thus we must check
1252 // for the closing bracket outselves.
1253 2 == sscanf(timestamp_begin
, "[ %lf%c", &lineTimestamp
, &after_float
) &&
1254 after_float
== ']') {
1255 if (lineTimestamp
<= mLastLineChecked
) {
1259 lineTimestampFound
= true;
1260 mLastLineChecked
= lineTimestamp
;
1264 // Log interesting lines
1265 for (size_t i
= 0; i
< regex_count
; i
++) {
1266 int matching
= !regexec(&(mRegexes
[i
]), line_begin
, 0, NULL
, 0);
1268 // Log content of kernel message. We try to skip the ], but if for
1269 // some reason (most likely due to buffer overflow/wraparound), we
1270 // can't find the ] then we just log the entire line.
1271 char* endOfTimestamp
= strchr(line_begin
, ']');
1272 if (endOfTimestamp
&& endOfTimestamp
[1] == ' ') {
1273 // skip the ] and the space that follows it
1274 line_begin
= endOfTimestamp
+ 2;
1276 if (!lineTimestampFound
) {
1277 OOM_LOG(ANDROID_LOG_WARN
, "following kill message may be a duplicate");
1279 OOM_LOG(ANDROID_LOG_ERROR
, "[Kill]: %s\n", line_begin
);
1289 EnsureKernelLowMemKillerParamsSet()
1291 static bool kernelLowMemKillerParamsSet
;
1292 if (kernelLowMemKillerParamsSet
) {
1295 kernelLowMemKillerParamsSet
= true;
1297 HAL_LOG(("Setting kernel's low-mem killer parameters."));
1299 // Set /sys/module/lowmemorykiller/parameters/{adj,minfree,notify_trigger}
1300 // according to our prefs. These files let us tune when the kernel kills
1301 // processes when we're low on memory, and when it notifies us that we're
1302 // running low on available memory.
1304 // adj and minfree are both comma-separated lists of integers. If adj="A,B"
1305 // and minfree="X,Y", then the kernel will kill processes with oom_adj
1306 // A or higher once we have fewer than X pages of memory free, and will kill
1307 // processes with oom_adj B or higher once we have fewer than Y pages of
1310 // notify_trigger is a single integer. If we set notify_trigger=Z, then
1311 // we'll get notified when there are fewer than Z pages of memory free. (See
1312 // GonkMemoryPressureMonitoring.cpp.)
1314 // Build the adj and minfree strings.
1315 nsAutoCString adjParams
;
1316 nsAutoCString minfreeParams
;
1318 int32_t lowerBoundOfNextOomScoreAdj
= OOM_SCORE_ADJ_MIN
- 1;
1319 int32_t lowerBoundOfNextKillUnderKB
= 0;
1320 int32_t countOfLowmemorykillerParametersSets
= 0;
1322 for (int i
= NUM_PROCESS_PRIORITY
- 1; i
>= 0; i
--) {
1323 // The system doesn't function correctly if we're missing these prefs, so
1326 ProcessPriority priority
= static_cast<ProcessPriority
>(i
);
1328 int32_t oomScoreAdj
;
1329 if (!NS_SUCCEEDED(Preferences::GetInt(
1330 nsPrintfCString("hal.processPriorityManager.gonk.%s.OomScoreAdjust",
1331 ProcessPriorityToString(priority
)).get(),
1336 int32_t killUnderKB
;
1337 if (!NS_SUCCEEDED(Preferences::GetInt(
1338 nsPrintfCString("hal.processPriorityManager.gonk.%s.KillUnderKB",
1339 ProcessPriorityToString(priority
)).get(),
1341 // ProcessPriority values like PROCESS_PRIORITY_FOREGROUND_KEYBOARD,
1342 // which has only OomScoreAdjust but lacks KillUnderMB value, will not
1343 // create new LMK parameters.
1347 // The LMK in kernel silently malfunctions if we assign the parameters
1348 // in non-increasing order, so we add this assertion here. See bug 887192.
1349 MOZ_ASSERT(oomScoreAdj
> lowerBoundOfNextOomScoreAdj
);
1350 MOZ_ASSERT(killUnderKB
> lowerBoundOfNextKillUnderKB
);
1352 // The LMK in kernel only accept 6 sets of LMK parameters. See bug 914728.
1353 MOZ_ASSERT(countOfLowmemorykillerParametersSets
< 6);
1355 // adj is in oom_adj units.
1356 adjParams
.AppendPrintf("%d,", OomAdjOfOomScoreAdj(oomScoreAdj
));
1358 // minfree is in pages.
1359 minfreeParams
.AppendPrintf("%d,", killUnderKB
* 1024 / PAGE_SIZE
);
1361 lowerBoundOfNextOomScoreAdj
= oomScoreAdj
;
1362 lowerBoundOfNextKillUnderKB
= killUnderKB
;
1363 countOfLowmemorykillerParametersSets
++;
1366 // Strip off trailing commas.
1367 adjParams
.Cut(adjParams
.Length() - 1, 1);
1368 minfreeParams
.Cut(minfreeParams
.Length() - 1, 1);
1369 if (!adjParams
.IsEmpty() && !minfreeParams
.IsEmpty()) {
1370 WriteToFile("/sys/module/lowmemorykiller/parameters/adj", adjParams
.get());
1371 WriteToFile("/sys/module/lowmemorykiller/parameters/minfree", minfreeParams
.get());
1374 // Set the low-memory-notification threshold.
1375 int32_t lowMemNotifyThresholdKB
;
1376 if (NS_SUCCEEDED(Preferences::GetInt(
1377 "hal.processPriorityManager.gonk.notifyLowMemUnderKB",
1378 &lowMemNotifyThresholdKB
))) {
1380 // notify_trigger is in pages.
1381 WriteToFile("/sys/module/lowmemorykiller/parameters/notify_trigger",
1382 nsPrintfCString("%d", lowMemNotifyThresholdKB
* 1024 / PAGE_SIZE
).get());
1385 // Ensure OOM events appear in logcat
1386 nsRefPtr
<OomVictimLogger
> oomLogger
= new OomVictimLogger();
1387 nsCOMPtr
<nsIObserverService
> os
= services::GetObserverService();
1389 os
->AddObserver(oomLogger
, "ipc:content-shutdown", false);
1394 SetNiceForPid(int aPid
, int aNice
)
1397 int origProcPriority
= getpriority(PRIO_PROCESS
, aPid
);
1399 HAL_LOG(("Unable to get nice for pid=%d; error %d. SetNiceForPid bailing.",
1404 int rv
= setpriority(PRIO_PROCESS
, aPid
, aNice
);
1406 HAL_LOG(("Unable to set nice for pid=%d; error %d. SetNiceForPid bailing.",
1411 // On Linux, setpriority(aPid) modifies the priority only of the main
1412 // thread of that process. We have to modify the priorities of all of the
1413 // process's threads as well, so iterate over all the threads and increase
1414 // each of their priorites by aNice - origProcPriority (and also ensure that
1415 // none of the tasks has a lower priority than the main thread).
1417 // This is horribly racy.
1419 DIR* tasksDir
= opendir(nsPrintfCString("/proc/%d/task/", aPid
).get());
1421 HAL_LOG(("Unable to open /proc/%d/task. SetNiceForPid bailing.", aPid
));
1425 // Be careful not to leak tasksDir; after this point, we must call closedir().
1427 while (struct dirent
* de
= readdir(tasksDir
)) {
1428 char* endptr
= nullptr;
1429 long tidlong
= strtol(de
->d_name
, &endptr
, /* base */ 10);
1430 if (*endptr
|| tidlong
< 0 || tidlong
> INT32_MAX
|| tidlong
== aPid
) {
1431 // if dp->d_name was not an integer, was negative (?!) or too large, or
1432 // was the same as aPid, we're not interested.
1434 // (The |tidlong == aPid| check is very important; without it, we'll
1435 // renice aPid twice, and the second renice will be relative to the
1436 // priority set by the first renice.)
1440 int tid
= static_cast<int>(tidlong
);
1442 // Do not set the priority of threads running with a real-time policy
1443 // as part of the bulk process adjustment. These threads need to run
1444 // at their specified priority in order to meet timing guarantees.
1445 int schedPolicy
= sched_getscheduler(tid
);
1446 if (schedPolicy
== SCHED_FIFO
|| schedPolicy
== SCHED_RR
) {
1451 // Get and set the task's new priority.
1452 int origtaskpriority
= getpriority(PRIO_PROCESS
, tid
);
1454 HAL_LOG(("Unable to get nice for tid=%d (pid=%d); error %d. This isn't "
1455 "necessarily a problem; it could be a benign race condition.",
1460 int newtaskpriority
=
1461 std::max(origtaskpriority
- origProcPriority
+ aNice
, aNice
);
1463 // Do not reduce priority of threads already running at priorities greater
1464 // than normal. These threads are likely special service threads that need
1465 // elevated priorities to process audio, display composition, etc.
1466 if (newtaskpriority
> origtaskpriority
&&
1467 origtaskpriority
< ANDROID_PRIORITY_NORMAL
) {
1471 rv
= setpriority(PRIO_PROCESS
, tid
, newtaskpriority
);
1474 HAL_LOG(("Unable to set nice for tid=%d (pid=%d); error %d. This isn't "
1475 "necessarily a problem; it could be a benign race condition.",
1481 HAL_LOG(("Changed nice for pid %d from %d to %d.",
1482 aPid
, origProcPriority
, aNice
));
1488 SetProcessPriority(int aPid
,
1489 ProcessPriority aPriority
,
1490 ProcessCPUPriority aCPUPriority
,
1491 uint32_t aBackgroundLRU
)
1493 HAL_LOG(("SetProcessPriority(pid=%d, priority=%d, cpuPriority=%d, LRU=%u)",
1494 aPid
, aPriority
, aCPUPriority
, aBackgroundLRU
));
1496 // If this is the first time SetProcessPriority was called, set the kernel's
1497 // OOM parameters according to our prefs.
1499 // We could/should do this on startup instead of waiting for the first
1500 // SetProcessPriorityCall. But in practice, the master process needs to set
1501 // its priority early in the game, so we can reasonably rely on
1502 // SetProcessPriority being called early in startup.
1503 EnsureKernelLowMemKillerParamsSet();
1505 int32_t oomScoreAdj
= 0;
1506 nsresult rv
= Preferences::GetInt(nsPrintfCString(
1507 "hal.processPriorityManager.gonk.%s.OomScoreAdjust",
1508 ProcessPriorityToString(aPriority
)).get(), &oomScoreAdj
);
1510 RoundOomScoreAdjUpWithBackroundLRU(oomScoreAdj
, aBackgroundLRU
);
1512 if (NS_SUCCEEDED(rv
)) {
1513 int clampedOomScoreAdj
= clamped
<int>(oomScoreAdj
, OOM_SCORE_ADJ_MIN
,
1515 if(clampedOomScoreAdj
!= oomScoreAdj
) {
1516 HAL_LOG(("Clamping OOM adjustment for pid %d to %d", aPid
,
1517 clampedOomScoreAdj
));
1519 HAL_LOG(("Setting OOM adjustment for pid %d to %d", aPid
,
1520 clampedOomScoreAdj
));
1523 // We try the newer interface first, and fall back to the older interface
1526 if (!WriteToFile(nsPrintfCString("/proc/%d/oom_score_adj", aPid
).get(),
1527 nsPrintfCString("%d", clampedOomScoreAdj
).get()))
1529 int oomAdj
= OomAdjOfOomScoreAdj(clampedOomScoreAdj
);
1531 WriteToFile(nsPrintfCString("/proc/%d/oom_adj", aPid
).get(),
1532 nsPrintfCString("%d", oomAdj
).get());
1535 HAL_ERR(("Unable to read oom_score_adj pref for priority %s; "
1536 "are the prefs messed up?", ProcessPriorityToString(aPriority
)));
1542 if (aCPUPriority
== PROCESS_CPU_PRIORITY_NORMAL
) {
1543 rv
= Preferences::GetInt(
1544 nsPrintfCString("hal.processPriorityManager.gonk.%s.Nice",
1545 ProcessPriorityToString(aPriority
)).get(),
1547 } else if (aCPUPriority
== PROCESS_CPU_PRIORITY_LOW
) {
1548 rv
= Preferences::GetInt("hal.processPriorityManager.gonk.LowCPUNice",
1551 HAL_ERR(("Unable to read niceness pref for priority %s; "
1552 "are the prefs messed up?", ProcessPriorityToString(aPriority
)));
1554 rv
= NS_ERROR_FAILURE
;
1557 if (NS_SUCCEEDED(rv
)) {
1558 HAL_LOG(("Setting nice for pid %d to %d", aPid
, nice
));
1559 SetNiceForPid(aPid
, nice
);
1564 IsValidRealTimePriority(int aValue
, int aSchedulePolicy
)
1566 return (aValue
>= sched_get_priority_min(aSchedulePolicy
)) &&
1567 (aValue
<= sched_get_priority_max(aSchedulePolicy
));
1571 SetThreadNiceValue(pid_t aTid
, ThreadPriority aThreadPriority
, int aValue
)
1573 MOZ_ASSERT(aThreadPriority
< NUM_THREAD_PRIORITY
);
1574 MOZ_ASSERT(aThreadPriority
>= 0);
1576 HAL_LOG(("Setting thread %d to priority level %s; nice level %d",
1577 aTid
, ThreadPriorityToString(aThreadPriority
), aValue
));
1578 int rv
= setpriority(PRIO_PROCESS
, aTid
, aValue
);
1581 HAL_LOG(("Failed to set thread %d to priority level %s; error %s", aTid
,
1582 ThreadPriorityToString(aThreadPriority
), strerror(errno
)));
1587 SetRealTimeThreadPriority(pid_t aTid
,
1588 ThreadPriority aThreadPriority
,
1591 int policy
= SCHED_FIFO
;
1593 MOZ_ASSERT(aThreadPriority
< NUM_THREAD_PRIORITY
);
1594 MOZ_ASSERT(aThreadPriority
>= 0);
1595 MOZ_ASSERT(IsValidRealTimePriority(aValue
, policy
), "Invalid real time priority");
1597 // Setting real time priorities requires using sched_setscheduler
1598 HAL_LOG(("Setting thread %d to priority level %s; Real Time priority %d, "
1599 "Schedule FIFO", aTid
, ThreadPriorityToString(aThreadPriority
),
1601 sched_param schedParam
;
1602 schedParam
.sched_priority
= aValue
;
1603 int rv
= sched_setscheduler(aTid
, policy
, &schedParam
);
1606 HAL_LOG(("Failed to set thread %d to real time priority level %s; error %s",
1607 aTid
, ThreadPriorityToString(aThreadPriority
), strerror(errno
)));
1612 SetThreadPriority(pid_t aTid
, hal::ThreadPriority aThreadPriority
)
1614 // See bug 999115, we can only read preferences on the main thread otherwise
1615 // we create a race condition in HAL
1616 MOZ_ASSERT(NS_IsMainThread(), "Can only set thread priorities on main thread");
1617 MOZ_ASSERT(aThreadPriority
>= 0);
1619 const char* threadPriorityStr
;
1620 switch (aThreadPriority
) {
1621 case THREAD_PRIORITY_COMPOSITOR
:
1622 threadPriorityStr
= ThreadPriorityToString(aThreadPriority
);
1625 HAL_ERR(("Unrecognized thread priority %d; Doing nothing",
1630 int realTimePriority
= Preferences::GetInt(
1631 nsPrintfCString("hal.gonk.%s.rt_priority", threadPriorityStr
).get());
1633 if (IsValidRealTimePriority(realTimePriority
, SCHED_FIFO
)) {
1634 SetRealTimeThreadPriority(aTid
, aThreadPriority
, realTimePriority
);
1638 int niceValue
= Preferences::GetInt(
1639 nsPrintfCString("hal.gonk.%s.nice", threadPriorityStr
).get());
1641 SetThreadNiceValue(aTid
, aThreadPriority
, niceValue
);
1647 * This class sets the priority of threads given the kernel thread's id and a
1648 * value taken from hal::ThreadPriority.
1650 * This runnable must always be dispatched to the main thread otherwise it will fail.
1651 * We have to run this from the main thread since preferences can only be read on
1654 class SetThreadPriorityRunnable
: public nsRunnable
1657 SetThreadPriorityRunnable(pid_t aThreadId
, hal::ThreadPriority aThreadPriority
)
1658 : mThreadId(aThreadId
)
1659 , mThreadPriority(aThreadPriority
)
1664 NS_ASSERTION(NS_IsMainThread(), "Can only set thread priorities on main thread");
1665 hal_impl::SetThreadPriority(mThreadId
, mThreadPriority
);
1671 hal::ThreadPriority mThreadPriority
;
1674 } // anonymous namespace
1677 SetCurrentThreadPriority(ThreadPriority aThreadPriority
)
1679 switch (aThreadPriority
) {
1680 case THREAD_PRIORITY_COMPOSITOR
: {
1681 pid_t threadId
= gettid();
1682 nsCOMPtr
<nsIRunnable
> runnable
=
1683 new SetThreadPriorityRunnable(threadId
, aThreadPriority
);
1684 NS_DispatchToMainThread(runnable
);
1688 HAL_LOG(("Unrecognized thread priority %d; Doing nothing",
1695 FactoryReset(FactoryResetReason
& aReason
)
1697 nsCOMPtr
<nsIRecoveryService
> recoveryService
=
1698 do_GetService("@mozilla.org/recovery-service;1");
1699 if (!recoveryService
) {
1700 NS_WARNING("Could not get recovery service!");
1704 if (aReason
== FactoryResetReason::Wipe
) {
1705 recoveryService
->FactoryReset("wipe");
1707 recoveryService
->FactoryReset("normal");