2 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 #include "helper-cgroup.h"
26 #include "helper-file.h"
27 #include "helper-net-cls.h"
29 #define CUR_CLASSID_PATH "/tmp/cur_classid"
30 #define CLASSID_FILE_NAME "net_cls.classid"
32 typedef GArray task_classid_array;
34 static uint32_t __produce_classid(check_classid_used_cb check_classid_cb)
36 uint32_t classid = STC_RESERVED_CLASSID_MAX;
37 int classid_test_count = 0;
38 int ret = fread_uint(CUR_CLASSID_PATH, &classid);
40 STC_LOGE("Can not read current classid");
43 for (classid_test_count = 0; classid_test_count < UINT32_MAX;
45 if (!check_classid_cb(classid))
49 if (classid_test_count == UINT32_MAX) {
50 STC_LOGE("there is no available classid due to kernel limitation");
51 return STC_UNKNOWN_CLASSID;
54 ret = fwrite_uint(CUR_CLASSID_PATH, ++classid);
56 STC_LOGE("Can not write classid");
61 static int __place_classid_to_cgroup(const char *cgroup, const char *subdir,
63 check_classid_used_cb cb)
65 char buf[MAX_PATH_LENGTH];
66 uint32_t result_classid = (classid && *classid) ? *classid :
67 __produce_classid(cb);
69 /* set classid as out argument */
70 if (classid && !*classid)
71 *classid = result_classid;
73 snprintf(buf, sizeof(buf), "%s/%s", cgroup, subdir);
74 return cgroup_write_node_uint32(buf, CLASSID_FILE_NAME, result_classid);
77 static uint32_t __get_classid_from_cgroup(const char *cgroup,
80 char buf[MAX_PATH_LENGTH];
81 uint32_t classid = STC_UNKNOWN_CLASSID;
82 snprintf(buf, sizeof(buf), "%s/%s", cgroup, subdir);
84 int ret = cgroup_read_node_uint32(buf, CLASSID_FILE_NAME, &classid);
86 STC_LOGE("Can't read classid from cgroup %s", buf);
90 /* TODO: background tasks update from list */
91 static void __add_background_apps(GSList *background_pid_list)
93 if (background_pid_list == NULL)
100 static stc_error_e __make_net_cls_cgroup(const char *pkg_name, uint32_t classid,
101 check_classid_used_cb cb)
103 stc_error_e ret = STC_ERROR_NONE;
106 if (pkg_name == NULL) {
107 STC_LOGE("package name must be not empty");
108 return STC_ERROR_INVALID_PARAMETER;
111 ret = cgroup_make_subdir(PATH_TO_NET_CGROUP_DIR, (char *)pkg_name,
113 ret_value_if(ret < 0, STC_ERROR_FAIL);
116 ret = __place_classid_to_cgroup(PATH_TO_NET_CGROUP_DIR,
118 classid ? &classid : NULL, cb);
119 ret_value_if(ret < 0, STC_ERROR_FAIL);
124 uint32_t get_classid_by_app_id(const char *app_id, int create)
128 uint32_t classid = STC_UNKNOWN_CLASSID;
130 if (app_id == NULL) {
131 STC_LOGE("app_id must be not empty");
132 return STC_UNKNOWN_CLASSID;
135 if (!strcmp(app_id, STC_ALL_APP))
136 return STC_ALL_APP_CLASSID;
138 if (!strcmp(app_id, TETHERING_APP_NAME))
139 return STC_TETHERING_APP_CLASSID;
141 if (!strcmp(app_id, STC_BACKGROUND_APP_NAME))
142 return STC_BACKGROUND_APP_CLASSID;
144 if (!strcmp(app_id, NETWORK_RESTRICTION_APP_NAME))
145 return STC_NETWORK_RESTRICTION_APP_CLASSID;
149 classid = __get_classid_from_cgroup(PATH_TO_NET_CGROUP_DIR,
152 if (classid != STC_UNKNOWN_CLASSID)
155 ret = cgroup_make_subdir(PATH_TO_NET_CGROUP_DIR, (char *)app_id,
161 classid = __get_classid_from_cgroup(PATH_TO_NET_CGROUP_DIR,
164 ret = __place_classid_to_cgroup(PATH_TO_NET_CGROUP_DIR,
165 (char *)app_id, &classid, NULL);
173 STC_LOGE("error_code: [%d]", ret);
174 return STC_UNKNOWN_CLASSID;
177 stc_error_e place_pids_to_net_cgroup(const int pid, const char *pkg_name)
179 char child_buf[21 + MAX_DEC_SIZE(int) + MAX_DEC_SIZE(int)];
180 snprintf(child_buf, sizeof(child_buf), PROC_TASK_CHILDREN, pid, pid);
182 if (pkg_name == NULL) {
183 STC_LOGE("package name must be not empty");
184 return STC_ERROR_INVALID_PARAMETER;
187 if (access(child_buf, F_OK)) {
188 STC_LOGD("%s of %s is not existed", child_buf, pkg_name);
189 return cgroup_write_pid(PATH_TO_NET_CGROUP_DIR, pkg_name, pid);
192 return cgroup_write_pidtree(PATH_TO_NET_CGROUP_DIR, pkg_name, pid);
195 void create_net_background_cgroup(GSList *background_pid_list)
197 stc_error_e ret = __make_net_cls_cgroup(STC_BACKGROUND_APP_NAME,
198 STC_BACKGROUND_APP_CLASSID,
200 if (ret == STC_ERROR_NONE)
201 __add_background_apps(background_pid_list);
203 STC_LOGD("Could not support quota for background applications");
206 void add_pid_to_background_cgroup(pid_t pid)
208 place_pids_to_net_cgroup(pid, STC_BACKGROUND_APP_NAME);
211 void remove_pid_from_background_cgroup(pid_t pid)
213 cgroup_remove_pid(PATH_TO_NET_CGROUP_DIR, STC_BACKGROUND_APP_NAME, pid);