1 /*
2 * Copyright (C) 2020 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 "PowerStateListener.h"
18
19 #include <chrono>
20
21 #include <sys/socket.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <sys/un.h>
25 #include <unistd.h>
26 #include <cstring>
27
28 #include <android-base/logging.h>
29
30 #include "Utils.h"
31
32 namespace android::hardware::automotive::vehicle::V2_0::impl {
33
ForwardSocketToFile(int sockfd,const std::string & filePath)34 static bool ForwardSocketToFile(int sockfd, const std::string& filePath) {
35 char buffer[1024] = {0};
36 auto readlen = read(sockfd, buffer, sizeof(buffer));
37 if (readlen < 0) {
38 LOG(ERROR) << __func__ << ": read error: " << strerror(errno);
39 return false;
40 } else if (readlen > 0) {
41 auto tempFilePath = filePath + ".XXXXXX";
42 auto tempFileFd = mkstemp(const_cast<char*>(tempFilePath.c_str()));
43 LOG(INFO) << "write to temp file " << tempFilePath;
44
45 if (tempFileFd < 0) {
46 LOG(ERROR) << __func__ << ": failed to create temp file " << tempFilePath << ": "
47 << strerror(errno);
48 return false;
49 }
50
51 auto writelen = write(tempFileFd, buffer, readlen);
52 if (writelen < 0) {
53 LOG(ERROR) << __func__ << ": write error to temp file " << tempFilePath << ": "
54 << strerror(errno);
55 return false;
56 } else if (writelen != readlen) {
57 LOG(ERROR) << __func__ << ": failed to write the entire buffer to the temp file, "
58 << "buffer: " << buffer << ", length: " << readlen
59 << "bytes written: " << writelen;
60 }
61
62 close(tempFileFd);
63 LOG(INFO) << "move " << tempFilePath << " to " << filePath;
64 rename(tempFilePath.c_str(), filePath.c_str());
65 }
66 return true;
67 }
68
PowerStateListener(const std::string & socketPath,const std::string & powerStateMarkerFilePath)69 PowerStateListener::PowerStateListener(const std::string& socketPath,
70 const std::string& powerStateMarkerFilePath)
71 : mSocketPath(socketPath), mPowerStateMarkerFilePath(powerStateMarkerFilePath) {}
72
Listen()73 void PowerStateListener::Listen() {
74 using std::literals::chrono_literals::operator""s;
75
76 // Newly created files are not accessible by other users
77 umask(0077);
78
79 int socketfd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);
80
81 if (socketfd < 0) {
82 LOG(ERROR) << __func__ << ": failed to create UNIX socket: " << strerror(errno);
83 return;
84 }
85
86 struct sockaddr_un addr;
87 std::memset(&addr, 0, sizeof(addr));
88 addr.sun_family = AF_UNIX;
89 if (mSocketPath.length() >= sizeof(addr.sun_path)) {
90 LOG(ERROR) << __func__ << ": socket file path " << mSocketPath << " is longer than limit "
91 << sizeof(addr.sun_path);
92 return;
93 }
94 std::strncpy(addr.sun_path, mSocketPath.c_str(), mSocketPath.length());
95
96 unlink(mSocketPath.c_str());
97 if (bind(socketfd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) < 0) {
98 LOG(ERROR) << __func__ << ": failed to bind the address " << mSocketPath
99 << " to the socket: " << strerror(errno);
100 return;
101 }
102
103 if (listen(socketfd, 1) < 0) {
104 LOG(ERROR) << __func__ << ": failed to listen on the socket " << mSocketPath << ": "
105 << strerror(errno);
106 return;
107 }
108
109 constexpr auto kSocketCheckPeriod = 1s;
110
111 while (!mShuttingDownFlag.load()) {
112 if (!WaitForReadWithTimeout(socketfd, kSocketCheckPeriod)) {
113 continue;
114 }
115
116 socklen_t socklen = sizeof(addr);
117 int fd = accept(socketfd, reinterpret_cast<sockaddr*>(&addr), &socklen);
118
119 if (fd == -1) {
120 if (errno != EAGAIN && errno != EWOULDBLOCK) {
121 PLOG(ERROR) << __func__ << ": failed to accept, path: " << mSocketPath;
122 }
123 continue;
124 }
125
126 if (!ForwardSocketToFile(fd, mPowerStateMarkerFilePath)) {
127 LOG(ERROR) << __func__ << ": failed to forward power state, "
128 << "path: " << mPowerStateMarkerFilePath;
129 continue;
130 }
131
132 close(fd);
133 }
134 }
135
Stop()136 void PowerStateListener::Stop() {
137 mShuttingDownFlag.store(true);
138 }
139
140 } // namespace android::hardware::automotive::vehicle::V2_0::impl
141