1/******************************************************************************
2 *
3 *  Copyright (C) 2014 Google, Inc.
4 *
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:
8 *
9 *  http://www.apache.org/licenses/LICENSE-2.0
10 *
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.
16 *
17 ******************************************************************************/
18
19#include "AlarmTestHarness.h"
20
21#include <fcntl.h>
22#include <sys/mman.h>
23#include <unistd.h>
24
25#include <hardware/bluetooth.h>
26
27extern "C" {
28#include "osi/include/alarm.h"
29#include "osi/include/allocation_tracker.h"
30#include "osi/include/wakelock.h"
31}
32
33static timer_t timer;
34static alarm_cb saved_callback;
35static void *saved_data;
36static AlarmTestHarness *current_harness;
37
38static void timer_callback(void *) {
39  saved_callback(saved_data);
40}
41
42void AlarmTestHarness::SetUp() {
43  AllocationTestHarness::SetUp();
44
45  current_harness = this;
46  TIMER_INTERVAL_FOR_WAKELOCK_IN_MS = 100;
47
48  struct sigevent sigevent;
49  memset(&sigevent, 0, sizeof(sigevent));
50  sigevent.sigev_notify = SIGEV_THREAD;
51  sigevent.sigev_notify_function = (void (*)(union sigval))timer_callback;
52  sigevent.sigev_value.sival_ptr = NULL;
53  timer_create(CLOCK_BOOTTIME, &sigevent, &timer);
54
55  // TODO (jamuraa): maybe use base::CreateNewTempDirectory instead?
56#if defined(OS_GENERIC)
57  tmp_dir_ = "/tmp/btwlXXXXXX";
58#else  // !defined(OS_GENERIC)
59  tmp_dir_ = "/data/local/tmp/btwlXXXXXX";
60#endif  // !defined(OS_GENERIC)
61
62  char *buffer = const_cast<char *>(tmp_dir_.c_str());
63  char *dtemp = mkdtemp(buffer);
64  if (!dtemp) {
65    perror("Can't make wake lock test directory: ");
66    assert(false);
67  }
68
69  lock_path_ = tmp_dir_ + "/wake_lock";
70  unlock_path_ = tmp_dir_ + "/wake_unlock";
71
72  creat(lock_path_.c_str(), S_IRWXU);
73  creat(unlock_path_.c_str(), S_IRWXU);
74
75  wakelock_set_paths(lock_path_.c_str(), unlock_path_.c_str());
76}
77
78void AlarmTestHarness::TearDown() {
79  alarm_cleanup();
80  wakelock_cleanup();
81
82  // clean up the temp wake lock directory
83  unlink(lock_path_.c_str());
84  unlink(unlock_path_.c_str());
85  rmdir(tmp_dir_.c_str());
86
87  timer_delete(timer);
88  AllocationTestHarness::TearDown();
89}
90
91
92bool AlarmTestHarness::WakeLockHeld() {
93  bool held = false;
94
95  int lock_fd = open(lock_path_.c_str(), O_RDONLY);
96  assert(lock_fd >= 0);
97
98  int unlock_fd = open(unlock_path_.c_str(), O_RDONLY);
99  assert(unlock_fd >= 0);
100
101  struct stat lock_stat, unlock_stat;
102  fstat(lock_fd, &lock_stat);
103  fstat(unlock_fd, &unlock_stat);
104
105  assert(lock_stat.st_size >= unlock_stat.st_size);
106
107  void *lock_file = mmap(nullptr, lock_stat.st_size, PROT_READ,
108                         MAP_PRIVATE, lock_fd, 0);
109
110  void *unlock_file = mmap(nullptr, unlock_stat.st_size, PROT_READ,
111                           MAP_PRIVATE, unlock_fd, 0);
112
113  if (memcmp(lock_file, unlock_file, unlock_stat.st_size) == 0) {
114    held = lock_stat.st_size > unlock_stat.st_size;
115  } else {
116    // these files should always either be with a lock that has more,
117    // or equal.
118    assert(false);
119  }
120
121  munmap(lock_file, lock_stat.st_size);
122  munmap(unlock_file, unlock_stat.st_size);
123  close(lock_fd);
124  close(unlock_fd);
125
126  return held;
127}
128