1/******************************************************************************
2 *
3 *  Copyright (C) 2016 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 <gtest/gtest.h>
20
21#include <base/logging.h>
22#include <fcntl.h>
23#include <sys/mman.h>
24#include <sys/stat.h>
25#include <sys/types.h>
26
27#include "osi/include/wakelock.h"
28
29#include "AllocationTestHarness.h"
30
31static bool is_wake_lock_acquired = false;
32
33static int acquire_wake_lock_cb(const char* lock_name) {
34  is_wake_lock_acquired = true;
35  return BT_STATUS_SUCCESS;
36}
37
38static int release_wake_lock_cb(const char* lock_name) {
39  is_wake_lock_acquired = false;
40  return BT_STATUS_SUCCESS;
41}
42
43static bt_os_callouts_t bt_wakelock_callouts = {
44    sizeof(bt_os_callouts_t), NULL, acquire_wake_lock_cb, release_wake_lock_cb};
45
46class WakelockTest : public AllocationTestHarness {
47 protected:
48  virtual void SetUp() {
49    AllocationTestHarness::SetUp();
50
51// TODO (jamuraa): maybe use base::CreateNewTempDirectory instead?
52#if defined(OS_GENERIC)
53    tmp_dir_ = "/tmp/btwlXXXXXX";
54#else
55    tmp_dir_ = "/data/local/tmp/btwlXXXXXX";
56#endif  // !defined(OS_GENERIC)
57
58    char* buffer = const_cast<char*>(tmp_dir_.c_str());
59    char* dtemp = mkdtemp(buffer);
60    if (!dtemp) {
61      perror("Can't make wake lock test directory: ");
62      CHECK(false);
63    }
64
65    lock_path_ = tmp_dir_ + "/wake_lock";
66    unlock_path_ = tmp_dir_ + "/wake_unlock";
67
68    creat(lock_path_.c_str(), S_IRWXU);
69    creat(unlock_path_.c_str(), S_IRWXU);
70  }
71
72  virtual void TearDown() {
73    is_wake_lock_acquired = false;
74    wakelock_cleanup();
75    wakelock_set_os_callouts(NULL);
76
77    // Clean up the temp wake lock directory
78    unlink(lock_path_.c_str());
79    unlink(unlock_path_.c_str());
80    rmdir(tmp_dir_.c_str());
81
82    AllocationTestHarness::TearDown();
83  }
84
85  //
86  // Test whether the file-based wakelock is acquired.
87  //
88  bool IsFileWakeLockAcquired() {
89    bool acquired = false;
90
91    int lock_fd = open(lock_path_.c_str(), O_RDONLY);
92    CHECK(lock_fd >= 0);
93
94    int unlock_fd = open(unlock_path_.c_str(), O_RDONLY);
95    CHECK(unlock_fd >= 0);
96
97    struct stat lock_stat, unlock_stat;
98    fstat(lock_fd, &lock_stat);
99    fstat(unlock_fd, &unlock_stat);
100
101    CHECK(lock_stat.st_size >= unlock_stat.st_size);
102
103    void* lock_file =
104        mmap(nullptr, lock_stat.st_size, PROT_READ, MAP_PRIVATE, lock_fd, 0);
105
106    void* unlock_file = mmap(nullptr, unlock_stat.st_size, PROT_READ,
107                             MAP_PRIVATE, unlock_fd, 0);
108
109    if (memcmp(lock_file, unlock_file, unlock_stat.st_size) == 0) {
110      acquired = lock_stat.st_size > unlock_stat.st_size;
111    } else {
112      // these files should always either be with a lock that has more,
113      // or equal.
114      CHECK(false);
115    }
116
117    munmap(lock_file, lock_stat.st_size);
118    munmap(unlock_file, unlock_stat.st_size);
119    close(lock_fd);
120    close(unlock_fd);
121
122    return acquired;
123  }
124
125  std::string tmp_dir_;
126  std::string lock_path_;
127  std::string unlock_path_;
128};
129
130TEST_F(WakelockTest, test_set_os_callouts) {
131  wakelock_set_os_callouts(&bt_wakelock_callouts);
132
133  // Initially, the wakelock is not acquired
134  ASSERT_FALSE(is_wake_lock_acquired);
135
136  for (size_t i = 0; i < 1000; i++) {
137    wakelock_acquire();
138    ASSERT_TRUE(is_wake_lock_acquired);
139    wakelock_release();
140    ASSERT_FALSE(is_wake_lock_acquired);
141  }
142}
143
144TEST_F(WakelockTest, test_set_paths) {
145  wakelock_set_os_callouts(NULL);  // Make sure we use native wakelocks
146  wakelock_set_paths(lock_path_.c_str(), unlock_path_.c_str());
147
148  // Initially, the wakelock is not acquired
149  ASSERT_FALSE(IsFileWakeLockAcquired());
150
151  for (size_t i = 0; i < 1000; i++) {
152    wakelock_acquire();
153    ASSERT_TRUE(IsFileWakeLockAcquired());
154    wakelock_release();
155    ASSERT_FALSE(IsFileWakeLockAcquired());
156  }
157}
158