1 /*
2 * Copyright (C) 2019 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 "lmkd_service.h"
18
19 #include <errno.h>
20
21 #include <android-base/logging.h>
22 #include <liblmkd_utils.h>
23
24 #include "service_list.h"
25
26 namespace android {
27 namespace init {
28
29 enum LmkdRegistrationResult {
30 LMKD_REG_SUCCESS,
31 LMKD_CONN_FAILED,
32 LMKD_REG_FAILED,
33 };
34
35 static int lmkd_socket = -1;
36
RegisterProcess(uid_t uid,pid_t pid,int oom_score_adjust)37 static LmkdRegistrationResult RegisterProcess(uid_t uid, pid_t pid, int oom_score_adjust) {
38 // connect to lmkd if not already connected
39 if (lmkd_socket < 0) {
40 lmkd_socket = lmkd_connect();
41 if (lmkd_socket < 0) {
42 return LMKD_CONN_FAILED;
43 }
44 }
45
46 // register service with lmkd
47 struct lmk_procprio params;
48 params.pid = pid;
49 params.uid = uid;
50 params.oomadj = oom_score_adjust;
51 params.ptype = PROC_TYPE_SERVICE;
52 if (lmkd_register_proc(lmkd_socket, ¶ms) != 0) {
53 // data transfer failed, reset the connection
54 close(lmkd_socket);
55 lmkd_socket = -1;
56 return LMKD_REG_FAILED;
57 }
58
59 return LMKD_REG_SUCCESS;
60 }
61
UnregisterProcess(pid_t pid)62 static bool UnregisterProcess(pid_t pid) {
63 if (lmkd_socket < 0) {
64 // no connection or it was lost, no need to unregister
65 return false;
66 }
67
68 // unregister service
69 struct lmk_procremove params;
70 params.pid = pid;
71 if (lmkd_unregister_proc(lmkd_socket, ¶ms) != 0) {
72 // data transfer failed, reset the connection
73 close(lmkd_socket);
74 lmkd_socket = -1;
75 return false;
76 }
77
78 return true;
79 }
80
RegisterServices(pid_t exclude_pid)81 static void RegisterServices(pid_t exclude_pid) {
82 for (const auto& service : ServiceList::GetInstance()) {
83 auto svc = service.get();
84 if (svc->oom_score_adjust() != DEFAULT_OOM_SCORE_ADJUST) {
85 // skip if process is excluded or not yet forked (pid==0)
86 if (svc->pid() == exclude_pid || svc->pid() == 0) {
87 continue;
88 }
89 if (RegisterProcess(svc->uid(), svc->pid(), svc->oom_score_adjust()) !=
90 LMKD_REG_SUCCESS) {
91 // a failure here resets the connection, will retry during next registration
92 break;
93 }
94 }
95 }
96 }
97
LmkdRegister(const std::string & name,uid_t uid,pid_t pid,int oom_score_adjust)98 void LmkdRegister(const std::string& name, uid_t uid, pid_t pid, int oom_score_adjust) {
99 bool new_connection = lmkd_socket == -1;
100 LmkdRegistrationResult result;
101
102 result = RegisterProcess(uid, pid, oom_score_adjust);
103 if (result == LMKD_REG_FAILED) {
104 // retry one time if connection to lmkd was lost
105 result = RegisterProcess(uid, pid, oom_score_adjust);
106 new_connection = result == LMKD_REG_SUCCESS;
107 }
108 switch (result) {
109 case LMKD_REG_SUCCESS:
110 // register existing services once new connection is established
111 if (new_connection) {
112 RegisterServices(pid);
113 }
114 break;
115 case LMKD_CONN_FAILED:
116 PLOG(ERROR) << "lmkd connection failed when " << name << " process got started";
117 break;
118 case LMKD_REG_FAILED:
119 PLOG(ERROR) << "lmkd failed to register " << name << " process";
120 break;
121 }
122 }
123
LmkdUnregister(const std::string & name,pid_t pid)124 void LmkdUnregister(const std::string& name, pid_t pid) {
125 if (!UnregisterProcess(pid)) {
126 PLOG(ERROR) << "lmkd failed to unregister " << name << " process";
127 }
128 }
129
130 } // namespace init
131 } // namespace android
132