1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <errno.h> 18 #include <fcntl.h> 19 #include <linux/rtc.h> 20 #include <sys/ioctl.h> 21 #include <sys/stat.h> 22 #include <sys/types.h> 23 #include <unistd.h> 24 25 #include <gtest/gtest.h> 26 27 #include <android-base/unique_fd.h> 28 29 static int hwtime(int flag, int request, struct rtc_time *tm) { 30 static const char rtc[] = "/dev/rtc0"; 31 32 int ret = access(rtc, flag & O_WRONLY); 33 if (ret < 0) { 34 return -errno; 35 } 36 37 if (flag & O_WRONLY) { 38 struct stat st; 39 ret = TEMP_FAILURE_RETRY(stat(rtc, &st)); 40 if (ret < 0) { 41 return -errno; 42 } else if (!(st.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH))) { 43 return -EACCES; 44 } 45 } 46 47 for (int count = 0; count < 10; count++) { 48 ret = TEMP_FAILURE_RETRY(open(rtc, flag)); 49 if (ret < 0) { 50 if (errno == EBUSY) { 51 sleep(1); 52 continue; 53 } 54 return -errno; 55 } 56 break; 57 } 58 android::base::unique_fd fd(ret); 59 60 for (int count = 0; count < 10; count++) { 61 ret = TEMP_FAILURE_RETRY(ioctl(fd.get(), request, tm)); 62 if (ret < 0) { 63 if (errno == EBUSY) { 64 sleep(1); 65 continue; 66 } 67 return -errno; 68 } 69 return ret; 70 }; 71 return -EBUSY; 72 } 73 74 static int rd_hwtime(struct rtc_time *tm) { 75 return hwtime(O_RDONLY, RTC_RD_TIME, tm); 76 } 77 78 static int set_hwtime(struct rtc_time *tm) { 79 return hwtime(O_WRONLY, RTC_SET_TIME, tm); 80 } 81 82 static void rtc_rollover(int start, int end) { 83 struct rtc_time roll; 84 memset(&roll, 0, sizeof(roll)); 85 ASSERT_LE(0, rd_hwtime(&roll)); 86 int mday[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 87 mday[1] = (roll.tm_year % 4) ? 28 : 29; 88 ASSERT_LE(0, roll.tm_sec); 89 ASSERT_GT(60, roll.tm_sec); 90 ASSERT_LE(0, roll.tm_min); 91 ASSERT_GT(60, roll.tm_min); 92 ASSERT_LE(0, roll.tm_hour); 93 ASSERT_GT(24, roll.tm_hour); 94 ASSERT_LE(0, roll.tm_mday); 95 ASSERT_GE(mday[roll.tm_mon], roll.tm_mday); 96 ASSERT_LE(0, roll.tm_mon); 97 ASSERT_GT(12, roll.tm_mon); 98 ASSERT_LE(0, roll.tm_year); 99 ASSERT_GT(138, roll.tm_year); 100 101 // Wait for granular clock 102 struct rtc_time save = roll; 103 static const useconds_t timeout_sleep = 10000; 104 static const int timeout_num = 2000000 / timeout_sleep; 105 int timeout; 106 for (timeout = timeout_num; timeout && (roll.tm_year == save.tm_year); --timeout) { 107 ASSERT_LE(0, rd_hwtime(&save)); 108 usleep(timeout_sleep); 109 } 110 111 memset(&roll, 0, sizeof(roll)); 112 roll.tm_sec = 59; 113 roll.tm_min = 59; 114 roll.tm_hour = 23; 115 roll.tm_mday = 31; 116 roll.tm_mon = 11; 117 roll.tm_year = 70; 118 roll.tm_wday = 0; 119 roll.tm_yday = 0; 120 roll.tm_isdst = 0; 121 122 bool eacces = true; 123 for (roll.tm_year = start; roll.tm_year < end; ++roll.tm_year) { 124 struct rtc_time tm = roll; 125 int __set_hwtime = set_hwtime(&tm); 126 // Allowed to be 100% denied for writing 127 if ((__set_hwtime == -EACCES) && (eacces == true)) { 128 continue; 129 } 130 eacces = false; 131 // below 2016, permitted to error out. 132 if ((__set_hwtime == -EINVAL) && (roll.tm_year < 116)) { 133 continue; 134 } 135 ASSERT_LE(0, __set_hwtime); 136 ASSERT_LE(0, rd_hwtime(&tm)); 137 ASSERT_EQ(roll.tm_sec, tm.tm_sec); 138 ASSERT_EQ(roll.tm_min, tm.tm_min); 139 ASSERT_EQ(roll.tm_hour, tm.tm_hour); 140 ASSERT_EQ(roll.tm_mday, tm.tm_mday); 141 ASSERT_EQ(roll.tm_mon, tm.tm_mon); 142 ASSERT_EQ(roll.tm_year, tm.tm_year); 143 for (timeout = timeout_num; timeout && (roll.tm_year == tm.tm_year); --timeout) { 144 ASSERT_LE(0, rd_hwtime(&tm)); 145 usleep(timeout_sleep); 146 } 147 ASSERT_EQ(roll.tm_year + 1, tm.tm_year); 148 EXPECT_LT(timeout_num * 5 / 100, timeout); 149 EXPECT_GT(timeout_num * 95 / 100, timeout); 150 151 // correct saved time to compensate for rollover check 152 if (++save.tm_sec >= 60) { 153 save.tm_sec = 0; 154 if (++save.tm_min >= 60) { 155 save.tm_min = 0; 156 if (++save.tm_hour >= 24) { 157 save.tm_hour = 0; 158 mday[1] = (save.tm_year % 4) ? 28 : 29; 159 if (++save.tm_mday >= mday[save.tm_mon]) { 160 save.tm_mday = 1; 161 if (++save.tm_mon >= 12) { 162 save.tm_mon = 0; 163 ++save.tm_year; 164 } 165 } 166 } 167 } 168 } 169 } 170 171 if (!eacces) { 172 ASSERT_LE(0, set_hwtime(&save)); 173 } 174 ASSERT_LE(0, rd_hwtime(&roll)); 175 176 if (!eacces) { 177 ASSERT_EQ(save.tm_sec, roll.tm_sec); 178 ASSERT_EQ(save.tm_min, roll.tm_min); 179 ASSERT_EQ(save.tm_hour, roll.tm_hour); 180 ASSERT_EQ(save.tm_mday, roll.tm_mday); 181 ASSERT_EQ(save.tm_mon, roll.tm_mon); 182 ASSERT_EQ(save.tm_year, roll.tm_year); 183 } 184 } 185 186 TEST(time, rtc_rollover_1970_1990) { 187 rtc_rollover(70, 90); 188 } 189 190 TEST(time, rtc_rollover_1990_2010) { 191 rtc_rollover(90, 110); 192 } 193 194 TEST(time, rtc_rollover_2010_2030) { 195 rtc_rollover(110, 130); 196 } 197 198 TEST(time, rtc_rollover_2030_2037) { 199 rtc_rollover(130, 137); 200 } 201