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