Bumping manifests a=b2g-bump
[gecko.git] / hal / gonk / GonkHal.cpp
blob6aeb5e4314123d7c77737a33f4f2d8c51473109e
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.
18 #include <ctype.h>
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <linux/android_alarm.h>
22 #include <math.h>
23 #include <regex.h>
24 #include <sched.h>
25 #include <stdio.h>
26 #include <sys/klog.h>
27 #include <sys/syscall.h>
28 #include <sys/resource.h>
29 #include <time.h>
30 #include <asm/page.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"
46 #include "Hal.h"
47 #include "HalImpl.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"
70 #include <algorithm>
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.
78 #ifndef OOM_DISABLE
79 #define OOM_DISABLE (-17)
80 #endif
82 #ifndef OOM_ADJUST_MIN
83 #define OOM_ADJUST_MIN (-16)
84 #endif
86 #ifndef OOM_ADJUST_MAX
87 #define OOM_ADJUST_MAX 15
88 #endif
90 #ifndef OOM_SCORE_ADJ_MIN
91 #define OOM_SCORE_ADJ_MIN (-1000)
92 #endif
94 #ifndef OOM_SCORE_ADJ_MAX
95 #define OOM_SCORE_ADJ_MAX 1000
96 #endif
98 #ifndef BATTERY_CHARGING_ARGB
99 #define BATTERY_CHARGING_ARGB 0x00FF0000
100 #endif
101 #ifndef BATTERY_FULL_ARGB
102 #define BATTERY_FULL_ARGB 0x0000FF00
103 #endif
105 using namespace mozilla;
106 using namespace mozilla::hal;
107 using namespace mozilla::dom;
109 namespace mozilla {
110 namespace hal_impl {
112 struct LightConfiguration {
113 hal::LightType light;
114 hal::LightMode mode;
115 hal::FlashMode flash;
116 uint32_t flashOnMS;
117 uint32_t flashOffMS;
118 uint32_t color;
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)
126 int err;
127 hw_device_t* device;
128 err = module->methods->open(module, name, &device);
129 if (err == 0) {
130 return (light_device_t*)device;
131 } else {
132 return nullptr;
136 static void
137 InitLights()
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]) {
142 int err;
143 hw_module_t* module;
145 err = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
146 if (err == 0) {
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.
183 static bool
184 SetLight(hal::LightType light, const LightConfiguration& aConfig)
186 light_state_t state;
188 InitLights();
190 if (light < 0 || light >= hal::eHalLightID_Count ||
191 sLights[light] == nullptr) {
192 return false;
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;
204 return true;
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.
211 static bool
212 GetLight(hal::LightType light, LightConfiguration* aConfig)
214 light_state_t state;
216 if (light < 0 || light >= hal::eHalLightID_Count ||
217 sLights[light] == nullptr) {
218 return false;
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);
231 return true;
234 namespace {
237 * This runnable runs for the lifetime of the program, once started. It's
238 * responsible for "playing" vibration patterns.
240 class VibratorRunnable
241 : public nsIRunnable
242 , public nsIObserver
244 public:
245 VibratorRunnable()
246 : mMonitor("VibratorRunnable")
247 , mIndex(0)
249 nsCOMPtr<nsIObserverService> os = services::GetObserverService();
250 if (!os) {
251 NS_WARNING("Could not get observer service!");
252 return;
255 os->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
258 NS_DECL_THREADSAFE_ISUPPORTS
259 NS_DECL_NSIRUNNABLE
260 NS_DECL_NSIOBSERVER
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; }
268 private:
269 Monitor mMonitor;
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.
276 uint32_t mIndex;
278 // Set to true in our shutdown observer. When this is true, we kill the
279 // vibrator thread.
280 static bool sShuttingDown;
283 NS_IMPL_ISUPPORTS(VibratorRunnable, nsIRunnable, nsIObserver);
285 bool VibratorRunnable::sShuttingDown = false;
287 static StaticRefPtr<VibratorRunnable> sVibratorRunnable;
289 NS_IMETHODIMP
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
301 // the timing here.
303 while (!sShuttingDown) {
304 if (mIndex < mPattern.Length()) {
305 uint32_t duration = mPattern[mIndex];
306 if (mIndex % 2 == 0) {
307 vibrator_on(duration);
309 mIndex++;
310 mMonitor.Wait(PR_MillisecondsToInterval(duration));
312 else {
313 mMonitor.Wait();
316 sVibratorRunnable = nullptr;
317 return NS_OK;
320 NS_IMETHODIMP
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;
327 mMonitor.Notify();
329 return NS_OK;
332 void
333 VibratorRunnable::Vibrate(const nsTArray<uint32_t> &pattern)
335 MonitorAutoLock lock(mMonitor);
336 mPattern = pattern;
337 mIndex = 0;
338 mMonitor.Notify();
341 void
342 VibratorRunnable::CancelVibrate()
344 MonitorAutoLock lock(mMonitor);
345 mPattern.Clear();
346 mPattern.AppendElement(0);
347 mIndex = 0;
348 mMonitor.Notify();
351 void
352 EnsureVibratorThreadInitialized()
354 if (sVibratorRunnable) {
355 return;
358 sVibratorRunnable = new VibratorRunnable();
359 nsCOMPtr<nsIThread> thread;
360 NS_NewThread(getter_AddRefs(thread), sVibratorRunnable);
363 } // anonymous namespace
365 void
366 Vibrate(const nsTArray<uint32_t> &pattern, const hal::WindowIdentifier &)
368 MOZ_ASSERT(NS_IsMainThread());
369 if (VibratorRunnable::ShuttingDown()) {
370 return;
372 EnsureVibratorThreadInitialized();
373 sVibratorRunnable->Vibrate(pattern);
376 void
377 CancelVibrate(const hal::WindowIdentifier &)
379 MOZ_ASSERT(NS_IsMainThread());
380 if (VibratorRunnable::ShuttingDown()) {
381 return;
383 EnsureVibratorThreadInitialized();
384 sVibratorRunnable->CancelVibrate();
387 namespace {
389 class BatteryUpdater : public nsRunnable {
390 public:
391 NS_IMETHOD Run()
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);
419 // bug 975667
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"),
428 info.charging());
429 propbag->SetPropertyAsDouble(NS_LITERAL_STRING("level"),
430 info.level());
432 obsService->NotifyObservers(propbag, "gonkhal-battery-notifier", nullptr);
436 return NS_OK;
440 } // anonymous namespace
442 class BatteryObserver : public IUeventObserver
444 public:
445 NS_INLINE_DECL_REFCOUNTING(BatteryObserver)
447 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);
466 private:
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;
474 static void
475 RegisterBatteryObserverIOThread()
477 MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
478 MOZ_ASSERT(!sBatteryObserver);
480 sBatteryObserver = new BatteryObserver();
481 RegisterUeventListener(sBatteryObserver);
484 void
485 EnableBatteryNotifications()
487 XRE_GetIOMessageLoop()->PostTask(
488 FROM_HERE,
489 NewRunnableFunction(RegisterBatteryObserverIOThread));
492 static void
493 UnregisterBatteryObserverIOThread()
495 MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop());
496 MOZ_ASSERT(sBatteryObserver);
498 UnregisterUeventListener(sBatteryObserver);
499 sBatteryObserver = nullptr;
502 void
503 DisableBatteryNotifications()
505 XRE_GetIOMessageLoop()->PostTask(
506 FROM_HERE,
507 NewRunnableFunction(UnregisterBatteryObserverIOThread));
510 static bool
511 GetCurrentBatteryCharge(int* aCharge)
513 bool success = ReadSysFile("/sys/class/power_supply/battery/capacity",
514 aCharge);
515 if (!success) {
516 return false;
519 #ifdef DEBUG
520 if ((*aCharge < 0) || (*aCharge > 100)) {
521 HAL_LOG(("charge level contains unknown value: %d", *aCharge));
523 #endif
525 return (*aCharge >= 0) && (*aCharge <= 100);
528 static bool
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
537 int chargingSrc;
538 bool success =
539 ReadSysFile("/sys/class/power_supply/battery/charging_source", &chargingSrc);
541 if (success) {
542 #ifdef DEBUG
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));
548 #endif
550 *aCharging = (chargingSrc == BATTERY_CHARGING_USB ||
551 chargingSrc == BATTERY_CHARGING_AC);
552 return true;
555 // Otoro device support
557 char chargingSrcString[16];
559 success = ReadSysFile("/sys/class/power_supply/battery/status",
560 chargingSrcString, sizeof(chargingSrcString));
561 if (success) {
562 *aCharging = strcmp(chargingSrcString, "Charging") == 0 ||
563 strcmp(chargingSrcString, "Full") == 0;
564 return true;
567 return false;
570 void
571 GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo)
573 int charge;
575 if (GetCurrentBatteryCharge(&charge)) {
576 aBatteryInfo->level() = (double)charge / 100.0;
577 } else {
578 aBatteryInfo->level() = dom::battery::kDefaultLevel;
581 int charging;
583 if (GetCurrentBatteryCharging(&charging)) {
584 aBatteryInfo->charging() = charging;
585 } else {
586 aBatteryInfo->charging() = true;
589 if (!aBatteryInfo->charging() || (aBatteryInfo->level() < 1.0)) {
590 aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime;
591 } else {
592 aBatteryInfo->remainingTime() = dom::battery::kDefaultRemainingTime;
596 namespace {
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";
604 template<ssize_t n>
605 bool ReadFromFile(const char *filename, char (&buf)[n])
607 int fd = open(filename, O_RDONLY);
608 ScopedClose autoClose(fd);
609 if (fd < 0) {
610 HAL_LOG(("Unable to open file %s.", filename));
611 return false;
614 ssize_t numRead = read(fd, buf, n);
615 if (numRead < 0) {
616 HAL_LOG(("Error reading from file %s.", filename));
617 return false;
620 buf[std::min(numRead, n - 1)] = '\0';
621 return true;
624 bool WriteToFile(const char *filename, const char *toWrite)
626 int fd = open(filename, O_WRONLY);
627 ScopedClose autoClose(fd);
628 if (fd < 0) {
629 HAL_LOG(("Unable to open file %s.", filename));
630 return false;
633 if (write(fd, toWrite, strlen(toWrite)) < 0) {
634 HAL_LOG(("Unable to write to file %s.", filename));
635 return false;
638 return true;
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
659 bool
660 GetScreenEnabled()
662 return sScreenEnabled;
665 void
666 SetScreenEnabled(bool aEnabled)
668 GetGonkDisplay()->SetEnabled(aEnabled);
669 sScreenEnabled = aEnabled;
672 bool
673 GetKeyLightEnabled()
675 LightConfiguration config;
676 GetLight(hal::eHalLightID_Buttons, &config);
677 return (config.color != 0x00000000);
680 void
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;
689 if (aEnabled) {
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
692 // channel.
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);
704 double
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;
716 void
717 SetScreenBrightness(double brightness)
719 // Don't use De Morgan's law to push the ! into this expression; we want to
720 // catch NaN too.
721 if (!(0 <= brightness && brightness <= 1)) {
722 HAL_LOG(("SetScreenBrightness: Dropping illegal brightness %f.",
723 brightness));
724 return;
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;
746 static void
747 UpdateCpuSleepState()
749 sInternalLockCpuMonitor->AssertCurrentThreadOwns();
750 bool allowed = sCpuSleepAllowed && !sInternalLockCpuCount;
751 WriteToFile(allowed ? wakeUnlockFilename : wakeLockFilename, "gecko");
754 static void
755 InternalLockCpu() {
756 MonitorAutoLock monitor(*sInternalLockCpuMonitor);
757 ++sInternalLockCpuCount;
758 UpdateCpuSleepState();
761 static void
762 InternalUnlockCpu() {
763 MonitorAutoLock monitor(*sInternalLockCpuMonitor);
764 --sInternalLockCpuCount;
765 UpdateCpuSleepState();
768 bool
769 GetCpuSleepAllowed()
771 return sCpuSleepAllowed;
774 void
775 SetCpuSleepAllowed(bool aAllowed)
777 MonitorAutoLock monitor(*sInternalLockCpuMonitor);
778 sCpuSleepAllowed = aAllowed;
779 UpdateCpuSleepState();
782 void
783 AdjustSystemClock(int64_t aDeltaMilliseconds)
785 int fd;
786 struct timespec now;
788 if (aDeltaMilliseconds == 0) {
789 return;
792 // Preventing context switch before setting system clock
793 sched_yield();
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) {
798 now.tv_sec += 1;
799 now.tv_nsec -= NsecPerSec;
802 if (now.tv_nsec < 0) {
803 now.tv_nsec += NsecPerSec;
804 now.tv_sec -= 1;
807 do {
808 fd = open("/dev/alarm", O_RDWR);
809 } while (fd == -1 && errno == EINTR);
810 ScopedClose autoClose(fd);
811 if (fd < 0) {
812 HAL_LOG(("Failed to open /dev/alarm: %s", strerror(errno)));
813 return;
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);
823 int32_t
824 GetTimezoneOffset()
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;
839 static void
840 UpdateKernelTimezone(int32_t timezoneOffset)
842 if (sKernelTimezoneOffset == timezoneOffset) {
843 return;
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).
853 struct timezone tz;
854 memset(&tz, 0, sizeof(tz));
855 tz.tz_minuteswest = timezoneOffset;
856 settimeofday(nullptr, &tz);
857 sKernelTimezoneOffset = timezoneOffset;
860 void
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());
869 return;
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.
876 tzset();
877 int32_t newTimezoneOffsetMinutes = GetTimezoneOffset();
878 UpdateKernelTimezone(newTimezoneOffsetMinutes);
879 hal::NotifySystemTimezoneChange(
880 hal::SystemTimezoneChangeInformation(
881 oldTimezoneOffsetMinutes, newTimezoneOffsetMinutes));
884 nsCString
885 GetTimezone()
887 char timezone[32];
888 property_get("persist.sys.timezone", timezone, "");
889 return nsCString(timezone);
892 void
893 EnableSystemClockChangeNotifications()
897 void
898 DisableSystemClockChangeNotifications()
902 void
903 EnableSystemTimezoneChangeNotifications()
907 void
908 DisableSystemTimezoneChangeNotifications()
912 // Nothing to do here. Gonk widgetry always listens for screen
913 // orientation changes.
914 void
915 EnableScreenConfigurationNotifications()
919 void
920 DisableScreenConfigurationNotifications()
924 void
925 GetCurrentScreenConfiguration(hal::ScreenConfiguration* aScreenConfiguration)
927 *aScreenConfiguration = nsScreenGonk::GetConfiguration();
930 bool
931 LockScreenOrientation(const dom::ScreenOrientation& aOrientation)
933 return OrientationObserver::GetInstance()->LockScreenOrientation(aOrientation);
936 void
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.
946 struct AlarmData {
947 public:
948 AlarmData(int aFd) : mFd(aFd),
949 mGeneration(sNextGeneration++),
950 mShuttingDown(false) {}
951 ScopedClose mFd;
952 int mGeneration;
953 bool mShuttingDown;
955 static int sNextGeneration;
959 int AlarmData::sNextGeneration = 0;
961 AlarmData* sAlarmData = nullptr;
963 class AlarmFiredEvent : public nsRunnable {
964 public:
965 AlarmFiredEvent(int aGeneration) : mGeneration(aGeneration) {}
967 NS_IMETHOD Run() {
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.
976 InternalUnlockCpu();
977 return NS_OK;
980 private:
981 int mGeneration;
984 // Runs on alarm-watcher thread.
985 static void
986 DestroyAlarmData(void* aData)
988 AlarmData* alarmData = static_cast<AlarmData*>(aData);
989 delete alarmData;
992 // Runs on alarm-watcher thread.
993 void ShutDownAlarm(int aSigno)
995 if (aSigno == SIGUSR1 && sAlarmData) {
996 sAlarmData->mShuttingDown = true;
998 return;
1001 static void*
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.
1015 do {
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.
1025 InternalLockCpu();
1026 nsRefPtr<AlarmFiredEvent> event =
1027 new AlarmFiredEvent(alarmData->mGeneration);
1028 NS_DispatchToMainThread(event);
1032 pthread_cleanup_pop(1);
1033 return nullptr;
1036 bool
1037 EnableAlarm()
1039 MOZ_ASSERT(!sAlarmData);
1041 int alarmFd = open("/dev/alarm", O_RDWR);
1042 if (alarmFd < 0) {
1043 HAL_LOG(("Failed to open alarm device: %s.", strerror(errno)));
1044 return false;
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."));
1056 return false;
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,
1067 alarmData.get());
1068 if (status) {
1069 alarmData = nullptr;
1070 delete sInternalLockCpuMonitor;
1071 HAL_LOG(("Failed to create alarm-watcher thread. Status: %d.", status));
1072 return false;
1075 pthread_attr_destroy(&attr);
1077 // The thread owns this now. We only hold a pointer.
1078 sAlarmData = alarmData.forget();
1079 return true;
1082 void
1083 DisableAlarm()
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);
1093 MOZ_ASSERT(!err);
1095 delete sInternalLockCpuMonitor;
1098 bool
1099 SetAlarm(int32_t aSeconds, int32_t aNanoseconds)
1101 if (!sAlarmData) {
1102 HAL_LOG(("We should have enabled the alarm."));
1103 return false;
1106 struct timespec ts;
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);
1114 if (result < 0) {
1115 HAL_LOG(("Unable to set alarm: %s.", strerror(errno)));
1116 return false;
1119 return true;
1122 static int
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.
1128 int adj;
1130 if (aOomScoreAdj < 0) {
1131 adj = (OOM_DISABLE * aOomScoreAdj) / OOM_SCORE_ADJ_MIN;
1132 } else {
1133 adj = (OOM_ADJUST_MAX * aOomScoreAdj) / OOM_SCORE_ADJ_MAX;
1136 return adj;
1139 static void
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.
1144 aOomScoreAdj +=
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
1152 public:
1153 OomVictimLogger()
1154 : mLastLineChecked(-1.0),
1155 mRegexes(nullptr)
1157 // Enable timestamps in kernel's printk
1158 WriteToFile("/sys/module/printk/parameters/time", "Y");
1161 NS_DECL_ISUPPORTS
1162 NS_DECL_NSIOBSERVER
1163 private:
1164 double mLastLineChecked;
1165 ScopedFreePtr<regex_t> mRegexes;
1167 NS_IMPL_ISUPPORTS(OomVictimLogger, nsIObserver);
1169 NS_IMETHODIMP
1170 OomVictimLogger::Observe(
1171 nsISupports* aSubject,
1172 const char* aTopic,
1173 const char16_t* aData)
1175 nsDependentCString event_type(aTopic);
1176 if (!event_type.EqualsLiteral("ipc:content-shutdown")) {
1177 return NS_OK;
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.*",
1188 ".*oom-killer.*",
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
1198 if (!mRegexes) {
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]);
1204 return NS_OK;
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
1216 #else
1217 // Once the change hits our bionic this ifndef
1218 // can be removed.
1219 #warning "Please remove KLOG_UNREAD_SIZE compatability def"
1220 #endif
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';
1230 // Foreach line
1231 char* line_end;
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
1235 *line_end = '\0';
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, '[');
1246 char after_float;
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) {
1256 continue;
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);
1267 if (matching) {
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);
1280 break;
1285 return NS_OK;
1288 static void
1289 EnsureKernelLowMemKillerParamsSet()
1291 static bool kernelLowMemKillerParamsSet;
1292 if (kernelLowMemKillerParamsSet) {
1293 return;
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
1308 // memory free.
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
1324 // crash loudly.
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(),
1332 &oomScoreAdj))) {
1333 MOZ_CRASH();
1336 int32_t killUnderKB;
1337 if (!NS_SUCCEEDED(Preferences::GetInt(
1338 nsPrintfCString("hal.processPriorityManager.gonk.%s.KillUnderKB",
1339 ProcessPriorityToString(priority)).get(),
1340 &killUnderKB))) {
1341 // ProcessPriority values like PROCESS_PRIORITY_FOREGROUND_KEYBOARD,
1342 // which has only OomScoreAdjust but lacks KillUnderMB value, will not
1343 // create new LMK parameters.
1344 continue;
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();
1388 if (os) {
1389 os->AddObserver(oomLogger, "ipc:content-shutdown", false);
1393 static void
1394 SetNiceForPid(int aPid, int aNice)
1396 errno = 0;
1397 int origProcPriority = getpriority(PRIO_PROCESS, aPid);
1398 if (errno) {
1399 HAL_LOG(("Unable to get nice for pid=%d; error %d. SetNiceForPid bailing.",
1400 aPid, errno));
1401 return;
1404 int rv = setpriority(PRIO_PROCESS, aPid, aNice);
1405 if (rv) {
1406 HAL_LOG(("Unable to set nice for pid=%d; error %d. SetNiceForPid bailing.",
1407 aPid, errno));
1408 return;
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());
1420 if (!tasksDir) {
1421 HAL_LOG(("Unable to open /proc/%d/task. SetNiceForPid bailing.", aPid));
1422 return;
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.)
1437 continue;
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) {
1447 continue;
1450 errno = 0;
1451 // Get and set the task's new priority.
1452 int origtaskpriority = getpriority(PRIO_PROCESS, tid);
1453 if (errno) {
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.",
1456 tid, aPid, errno));
1457 continue;
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) {
1468 continue;
1471 rv = setpriority(PRIO_PROCESS, tid, newtaskpriority);
1473 if (rv) {
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.",
1476 tid, aPid, errno));
1477 continue;
1481 HAL_LOG(("Changed nice for pid %d from %d to %d.",
1482 aPid, origProcPriority, aNice));
1484 closedir(tasksDir);
1487 void
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,
1514 OOM_SCORE_ADJ_MAX);
1515 if(clampedOomScoreAdj != oomScoreAdj) {
1516 HAL_LOG(("Clamping OOM adjustment for pid %d to %d", aPid,
1517 clampedOomScoreAdj));
1518 } else {
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
1524 // on failure.
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());
1534 } else {
1535 HAL_ERR(("Unable to read oom_score_adj pref for priority %s; "
1536 "are the prefs messed up?", ProcessPriorityToString(aPriority)));
1537 MOZ_ASSERT(false);
1540 int32_t nice = 0;
1542 if (aCPUPriority == PROCESS_CPU_PRIORITY_NORMAL) {
1543 rv = Preferences::GetInt(
1544 nsPrintfCString("hal.processPriorityManager.gonk.%s.Nice",
1545 ProcessPriorityToString(aPriority)).get(),
1546 &nice);
1547 } else if (aCPUPriority == PROCESS_CPU_PRIORITY_LOW) {
1548 rv = Preferences::GetInt("hal.processPriorityManager.gonk.LowCPUNice",
1549 &nice);
1550 } else {
1551 HAL_ERR(("Unable to read niceness pref for priority %s; "
1552 "are the prefs messed up?", ProcessPriorityToString(aPriority)));
1553 MOZ_ASSERT(false);
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);
1563 static bool
1564 IsValidRealTimePriority(int aValue, int aSchedulePolicy)
1566 return (aValue >= sched_get_priority_min(aSchedulePolicy)) &&
1567 (aValue <= sched_get_priority_max(aSchedulePolicy));
1570 static void
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);
1580 if (rv) {
1581 HAL_LOG(("Failed to set thread %d to priority level %s; error %s", aTid,
1582 ThreadPriorityToString(aThreadPriority), strerror(errno)));
1586 static void
1587 SetRealTimeThreadPriority(pid_t aTid,
1588 ThreadPriority aThreadPriority,
1589 int aValue)
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),
1600 aValue));
1601 sched_param schedParam;
1602 schedParam.sched_priority = aValue;
1603 int rv = sched_setscheduler(aTid, policy, &schedParam);
1605 if (rv) {
1606 HAL_LOG(("Failed to set thread %d to real time priority level %s; error %s",
1607 aTid, ThreadPriorityToString(aThreadPriority), strerror(errno)));
1611 static void
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);
1623 break;
1624 default:
1625 HAL_ERR(("Unrecognized thread priority %d; Doing nothing",
1626 aThreadPriority));
1627 return;
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);
1635 return;
1638 int niceValue = Preferences::GetInt(
1639 nsPrintfCString("hal.gonk.%s.nice", threadPriorityStr).get());
1641 SetThreadNiceValue(aTid, aThreadPriority, niceValue);
1644 namespace {
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
1652 * main thread.
1654 class SetThreadPriorityRunnable : public nsRunnable
1656 public:
1657 SetThreadPriorityRunnable(pid_t aThreadId, hal::ThreadPriority aThreadPriority)
1658 : mThreadId(aThreadId)
1659 , mThreadPriority(aThreadPriority)
1662 NS_IMETHOD Run()
1664 NS_ASSERTION(NS_IsMainThread(), "Can only set thread priorities on main thread");
1665 hal_impl::SetThreadPriority(mThreadId, mThreadPriority);
1666 return NS_OK;
1669 private:
1670 pid_t mThreadId;
1671 hal::ThreadPriority mThreadPriority;
1674 } // anonymous namespace
1676 void
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);
1685 break;
1687 default:
1688 HAL_LOG(("Unrecognized thread priority %d; Doing nothing",
1689 aThreadPriority));
1690 return;
1694 void
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!");
1701 return;
1704 if (aReason == FactoryResetReason::Wipe) {
1705 recoveryService->FactoryReset("wipe");
1706 } else {
1707 recoveryService->FactoryReset("normal");
1711 } // hal_impl
1712 } // mozilla