1419b0af8Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */ 2419b0af8Sopenharmony_ci/* 3419b0af8Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. 4419b0af8Sopenharmony_ci */ 5419b0af8Sopenharmony_ci#include "ucollection_process_cpu.h" 6419b0af8Sopenharmony_ci 7419b0af8Sopenharmony_ci#include <asm/div64.h> 8419b0af8Sopenharmony_ci#ifdef CONFIG_CPU_FREQ_TIMES 9419b0af8Sopenharmony_ci#include <linux/cpufreq_times.h> 10419b0af8Sopenharmony_ci#endif // CONFIG_CPU_FREQ_TIMES 11419b0af8Sopenharmony_ci#include <linux/sched/stat.h> 12419b0af8Sopenharmony_ci#include <linux/version.h> 13419b0af8Sopenharmony_ci#include <linux/uaccess.h> 14419b0af8Sopenharmony_ci#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)) 15419b0af8Sopenharmony_ci#include <linux/sched.h> 16419b0af8Sopenharmony_ci#include <linux/sched/cputime.h> 17419b0af8Sopenharmony_ci#include <linux/sched/signal.h> 18419b0af8Sopenharmony_ci#endif // LINUX_VERSION_CODE 19419b0af8Sopenharmony_ci#ifdef CONFIG_SMT_MODE_GOV 20419b0af8Sopenharmony_ci#include <platform_include/cee/linux/time_in_state.h> 21419b0af8Sopenharmony_ci#endif // CONFIG_SMT_MODE_GOV 22419b0af8Sopenharmony_ci 23419b0af8Sopenharmony_ci#include "unified_collection_data.h" 24419b0af8Sopenharmony_ci 25419b0af8Sopenharmony_ci#define NS_TO_MS 1000000 26419b0af8Sopenharmony_cistatic char dmips_values[DMIPS_NUM]; 27419b0af8Sopenharmony_ci 28419b0af8Sopenharmony_ciunsigned long long __attribute__((weak)) get_proc_cpu_load(struct task_struct *task, char dmips[], 29419b0af8Sopenharmony_ci unsigned int dmips_num) 30419b0af8Sopenharmony_ci{ 31419b0af8Sopenharmony_ci return 0; 32419b0af8Sopenharmony_ci} 33419b0af8Sopenharmony_ci 34419b0af8Sopenharmony_cistatic void get_process_flt(struct task_struct *task, struct ucollection_process_cpu_item* proc_cpu_entry) 35419b0af8Sopenharmony_ci{ 36419b0af8Sopenharmony_ci unsigned long tmp_min_flt = 0; 37419b0af8Sopenharmony_ci unsigned long tmp_maj_flt = 0; 38419b0af8Sopenharmony_ci 39419b0af8Sopenharmony_ci struct task_struct *t = task; 40419b0af8Sopenharmony_ci signed int thread_count = 0; 41419b0af8Sopenharmony_ci do { 42419b0af8Sopenharmony_ci tmp_min_flt += t->min_flt; 43419b0af8Sopenharmony_ci tmp_maj_flt += t->maj_flt; 44419b0af8Sopenharmony_ci ++thread_count; 45419b0af8Sopenharmony_ci } while_each_thread(task, t); 46419b0af8Sopenharmony_ci 47419b0af8Sopenharmony_ci struct signal_struct *sig = task->signal; 48419b0af8Sopenharmony_ci if (sig != NULL) { 49419b0af8Sopenharmony_ci tmp_min_flt += sig->min_flt; 50419b0af8Sopenharmony_ci tmp_maj_flt += sig->maj_flt; 51419b0af8Sopenharmony_ci } 52419b0af8Sopenharmony_ci 53419b0af8Sopenharmony_ci proc_cpu_entry->min_flt = tmp_min_flt; 54419b0af8Sopenharmony_ci proc_cpu_entry->maj_flt = tmp_maj_flt; 55419b0af8Sopenharmony_ci proc_cpu_entry->thread_total = thread_count; 56419b0af8Sopenharmony_ci} 57419b0af8Sopenharmony_ci 58419b0af8Sopenharmony_cistatic unsigned long long get_process_load_cputime(struct task_struct *task) 59419b0af8Sopenharmony_ci{ 60419b0af8Sopenharmony_ci unsigned long long proc_load_cputime = 0; 61419b0af8Sopenharmony_ci proc_load_cputime = get_proc_cpu_load(task, dmips_values, DMIPS_NUM); 62419b0af8Sopenharmony_ci return proc_load_cputime; 63419b0af8Sopenharmony_ci} 64419b0af8Sopenharmony_ci 65419b0af8Sopenharmony_cistatic void get_process_usage_cputime(struct task_struct *task, unsigned long long *ut, unsigned long long *st) 66419b0af8Sopenharmony_ci{ 67419b0af8Sopenharmony_ci unsigned long long utime, stime; 68419b0af8Sopenharmony_ci 69419b0af8Sopenharmony_ci thread_group_cputime_adjusted(task, &utime, &stime); 70419b0af8Sopenharmony_ci do_div(utime, NS_TO_MS); 71419b0af8Sopenharmony_ci do_div(stime, NS_TO_MS); 72419b0af8Sopenharmony_ci *ut = utime; 73419b0af8Sopenharmony_ci *st = stime; 74419b0af8Sopenharmony_ci} 75419b0af8Sopenharmony_ci 76419b0af8Sopenharmony_cistatic void get_process_load(struct task_struct *task, int cur_count, 77419b0af8Sopenharmony_ci struct ucollection_process_cpu_entry __user *entry) 78419b0af8Sopenharmony_ci{ 79419b0af8Sopenharmony_ci struct ucollection_process_cpu_item proc_cpu_entry; 80419b0af8Sopenharmony_ci memset(&proc_cpu_entry, 0, sizeof(struct ucollection_process_cpu_item)); 81419b0af8Sopenharmony_ci proc_cpu_entry.pid = task->pid; 82419b0af8Sopenharmony_ci get_process_flt(task, &proc_cpu_entry); 83419b0af8Sopenharmony_ci proc_cpu_entry.cpu_load_time = get_process_load_cputime(task); 84419b0af8Sopenharmony_ci get_process_usage_cputime(task, &proc_cpu_entry.cpu_usage_utime, &proc_cpu_entry.cpu_usage_stime); 85419b0af8Sopenharmony_ci (void)copy_to_user(&entry->datas[cur_count], &proc_cpu_entry, sizeof(struct ucollection_process_cpu_item)); 86419b0af8Sopenharmony_ci} 87419b0af8Sopenharmony_ci 88419b0af8Sopenharmony_cistatic void get_thread_load(struct task_struct *task, int cur_count, 89419b0af8Sopenharmony_ci struct ucollection_thread_cpu_entry __user *entry) 90419b0af8Sopenharmony_ci{ 91419b0af8Sopenharmony_ci struct ucollection_thread_cpu_item thread_cpu_item; 92419b0af8Sopenharmony_ci memset(&thread_cpu_item, 0, sizeof(struct ucollection_thread_cpu_item)); 93419b0af8Sopenharmony_ci unsigned long long utime, stime; 94419b0af8Sopenharmony_ci utime = task->utime; 95419b0af8Sopenharmony_ci stime = task->stime; 96419b0af8Sopenharmony_ci do_div(utime, NS_TO_MS); 97419b0af8Sopenharmony_ci do_div(stime, NS_TO_MS); 98419b0af8Sopenharmony_ci thread_cpu_item.tid = task->pid; 99419b0af8Sopenharmony_ci strcpy(thread_cpu_item.name, task->comm); 100419b0af8Sopenharmony_ci thread_cpu_item.cpu_usage_utime = utime; 101419b0af8Sopenharmony_ci thread_cpu_item.cpu_usage_stime = stime; 102419b0af8Sopenharmony_ci thread_cpu_item.cpu_load_time = 0; 103419b0af8Sopenharmony_ci (void)copy_to_user(&entry->datas[cur_count], &thread_cpu_item, sizeof(struct ucollection_thread_cpu_item)); 104419b0af8Sopenharmony_ci} 105419b0af8Sopenharmony_ci 106419b0af8Sopenharmony_cistatic long ioctrl_collect_process_cpu(void __user *argp) 107419b0af8Sopenharmony_ci{ 108419b0af8Sopenharmony_ci struct task_struct *task = NULL; 109419b0af8Sopenharmony_ci struct ucollection_process_cpu_entry kentry; 110419b0af8Sopenharmony_ci struct ucollection_process_cpu_entry __user *entry = argp; 111419b0af8Sopenharmony_ci if (entry == NULL) { 112419b0af8Sopenharmony_ci pr_err("cpu entry is null"); 113419b0af8Sopenharmony_ci return -EINVAL; 114419b0af8Sopenharmony_ci } 115419b0af8Sopenharmony_ci 116419b0af8Sopenharmony_ci memset(&kentry, 0, sizeof(struct ucollection_process_cpu_entry)); 117419b0af8Sopenharmony_ci (void)copy_from_user(&kentry, entry, sizeof(struct ucollection_process_cpu_entry)); 118419b0af8Sopenharmony_ci 119419b0af8Sopenharmony_ci rcu_read_lock(); 120419b0af8Sopenharmony_ci task = &init_task; 121419b0af8Sopenharmony_ci for_each_process(task) { 122419b0af8Sopenharmony_ci if (task->pid != task->tgid) 123419b0af8Sopenharmony_ci continue; 124419b0af8Sopenharmony_ci 125419b0af8Sopenharmony_ci if (kentry.cur_count >= kentry.total_count) { 126419b0af8Sopenharmony_ci pr_err("process over total count"); 127419b0af8Sopenharmony_ci break; 128419b0af8Sopenharmony_ci } 129419b0af8Sopenharmony_ci 130419b0af8Sopenharmony_ci get_process_load(task, kentry.cur_count, entry); 131419b0af8Sopenharmony_ci kentry.cur_count++; 132419b0af8Sopenharmony_ci } 133419b0af8Sopenharmony_ci put_user(kentry.cur_count, &entry->cur_count); 134419b0af8Sopenharmony_ci rcu_read_unlock(); 135419b0af8Sopenharmony_ci return 0; 136419b0af8Sopenharmony_ci} 137419b0af8Sopenharmony_ci 138419b0af8Sopenharmony_cistatic struct task_struct* get_alive_task_by_pid(unsigned int pid) 139419b0af8Sopenharmony_ci{ 140419b0af8Sopenharmony_ci struct task_struct *task = NULL; 141419b0af8Sopenharmony_ci task = find_task_by_pid_ns(pid, &init_pid_ns); 142419b0af8Sopenharmony_ci if (task == NULL || !pid_alive(task)) { 143419b0af8Sopenharmony_ci return NULL; 144419b0af8Sopenharmony_ci } 145419b0af8Sopenharmony_ci return task; 146419b0af8Sopenharmony_ci} 147419b0af8Sopenharmony_ci 148419b0af8Sopenharmony_cistatic long ioctrl_collect_process_count(void __user *argp) 149419b0af8Sopenharmony_ci{ 150419b0af8Sopenharmony_ci struct task_struct *task = NULL; 151419b0af8Sopenharmony_ci unsigned int process_count = 0; 152419b0af8Sopenharmony_ci unsigned int __user *count = argp; 153419b0af8Sopenharmony_ci rcu_read_lock(); 154419b0af8Sopenharmony_ci task = &init_task; 155419b0af8Sopenharmony_ci for_each_process(task) { 156419b0af8Sopenharmony_ci if (task->pid != task->tgid) { 157419b0af8Sopenharmony_ci continue; 158419b0af8Sopenharmony_ci } 159419b0af8Sopenharmony_ci ++process_count; 160419b0af8Sopenharmony_ci } 161419b0af8Sopenharmony_ci rcu_read_unlock(); 162419b0af8Sopenharmony_ci put_user(process_count, count); 163419b0af8Sopenharmony_ci return 0; 164419b0af8Sopenharmony_ci} 165419b0af8Sopenharmony_ci 166419b0af8Sopenharmony_cistatic long read_thread_count_locked(struct ucollection_process_thread_count *kcount, 167419b0af8Sopenharmony_ci struct ucollection_process_thread_count __user *count) 168419b0af8Sopenharmony_ci{ 169419b0af8Sopenharmony_ci rcu_read_lock(); 170419b0af8Sopenharmony_ci struct task_struct *task = get_alive_task_by_pid(kcount->pid); 171419b0af8Sopenharmony_ci if (task == NULL) { 172419b0af8Sopenharmony_ci pr_info("pid=%d is task NULL or not alive", kcount->pid); 173419b0af8Sopenharmony_ci rcu_read_unlock(); 174419b0af8Sopenharmony_ci return -EINVAL; 175419b0af8Sopenharmony_ci } 176419b0af8Sopenharmony_ci unsigned int thread_count = 0; 177419b0af8Sopenharmony_ci struct task_struct *t = task; 178419b0af8Sopenharmony_ci do { 179419b0af8Sopenharmony_ci thread_count++; 180419b0af8Sopenharmony_ci } while_each_thread(task, t); 181419b0af8Sopenharmony_ci put_user(thread_count, &count->thread_count); 182419b0af8Sopenharmony_ci rcu_read_unlock(); 183419b0af8Sopenharmony_ci return 0; 184419b0af8Sopenharmony_ci} 185419b0af8Sopenharmony_ci 186419b0af8Sopenharmony_cistatic long ioctrl_collect_thread_count(void __user *argp) 187419b0af8Sopenharmony_ci{ 188419b0af8Sopenharmony_ci struct ucollection_process_thread_count kcount; 189419b0af8Sopenharmony_ci struct ucollection_process_thread_count __user *count = argp; 190419b0af8Sopenharmony_ci if (count == NULL) { 191419b0af8Sopenharmony_ci pr_err("cpu entry is null"); 192419b0af8Sopenharmony_ci return -EINVAL; 193419b0af8Sopenharmony_ci } 194419b0af8Sopenharmony_ci memset(&kcount, 0, sizeof(struct ucollection_process_thread_count)); 195419b0af8Sopenharmony_ci (void)copy_from_user(&kcount, count, sizeof(struct ucollection_process_thread_count)); 196419b0af8Sopenharmony_ci return read_thread_count_locked(&kcount, count); 197419b0af8Sopenharmony_ci} 198419b0af8Sopenharmony_ci 199419b0af8Sopenharmony_cistatic long ioctrl_collect_app_thread_count(void __user *argp) 200419b0af8Sopenharmony_ci{ 201419b0af8Sopenharmony_ci struct ucollection_process_thread_count kcount; 202419b0af8Sopenharmony_ci struct ucollection_process_thread_count __user *count = argp; 203419b0af8Sopenharmony_ci if (count == NULL) { 204419b0af8Sopenharmony_ci pr_err("cpu entry is null"); 205419b0af8Sopenharmony_ci return -EINVAL; 206419b0af8Sopenharmony_ci } 207419b0af8Sopenharmony_ci memset(&kcount, 0, sizeof(struct ucollection_process_thread_count)); 208419b0af8Sopenharmony_ci (void)copy_from_user(&kcount, count, sizeof(struct ucollection_process_thread_count)); 209419b0af8Sopenharmony_ci if (current->tgid != kcount.pid) { 210419b0af8Sopenharmony_ci pr_err("pid=%d is not self current tgid:%d", kcount.pid, current->tgid); 211419b0af8Sopenharmony_ci return -EINVAL; 212419b0af8Sopenharmony_ci } 213419b0af8Sopenharmony_ci return read_thread_count_locked(&kcount, count); 214419b0af8Sopenharmony_ci} 215419b0af8Sopenharmony_ci 216419b0af8Sopenharmony_cistatic long read_thread_info_locked(struct ucollection_thread_cpu_entry *kentry, 217419b0af8Sopenharmony_ci struct ucollection_thread_cpu_entry __user *entry) 218419b0af8Sopenharmony_ci{ 219419b0af8Sopenharmony_ci rcu_read_lock(); 220419b0af8Sopenharmony_ci struct task_struct *task = get_alive_task_by_pid(kentry->filter.pid); 221419b0af8Sopenharmony_ci if (task == NULL) { 222419b0af8Sopenharmony_ci pr_info("pid=%d is task NULL not alive", kentry->filter.pid); 223419b0af8Sopenharmony_ci rcu_read_unlock(); 224419b0af8Sopenharmony_ci return -EINVAL; 225419b0af8Sopenharmony_ci } 226419b0af8Sopenharmony_ci unsigned int thread_count = 0; 227419b0af8Sopenharmony_ci struct task_struct *t = task; 228419b0af8Sopenharmony_ci do { 229419b0af8Sopenharmony_ci if (thread_count >= kentry->total_count) { 230419b0af8Sopenharmony_ci pr_err("thread over total count"); 231419b0af8Sopenharmony_ci break; 232419b0af8Sopenharmony_ci } 233419b0af8Sopenharmony_ci get_thread_load(t, thread_count, entry); 234419b0af8Sopenharmony_ci thread_count++; 235419b0af8Sopenharmony_ci } while_each_thread(task, t); 236419b0af8Sopenharmony_ci put_user(thread_count, &entry->cur_count); 237419b0af8Sopenharmony_ci rcu_read_unlock(); 238419b0af8Sopenharmony_ci return 0; 239419b0af8Sopenharmony_ci} 240419b0af8Sopenharmony_ci 241419b0af8Sopenharmony_cistatic long ioctrl_collect_app_thread_cpu(void __user *argp) 242419b0af8Sopenharmony_ci{ 243419b0af8Sopenharmony_ci struct ucollection_thread_cpu_entry kentry; 244419b0af8Sopenharmony_ci struct ucollection_thread_cpu_entry __user *entry = argp; 245419b0af8Sopenharmony_ci if (entry == NULL) { 246419b0af8Sopenharmony_ci pr_err("cpu entry is null"); 247419b0af8Sopenharmony_ci return -EINVAL; 248419b0af8Sopenharmony_ci } 249419b0af8Sopenharmony_ci memset(&kentry, 0, sizeof(struct ucollection_thread_cpu_entry)); 250419b0af8Sopenharmony_ci (void)copy_from_user(&kentry, entry, sizeof(struct ucollection_thread_cpu_entry)); 251419b0af8Sopenharmony_ci if (current->tgid != kentry.filter.pid || kentry.cur_count >= kentry.total_count) { 252419b0af8Sopenharmony_ci pr_err("pid=%d is not self current tgid:%d , or current count over total count" 253419b0af8Sopenharmony_ci , kentry.filter.pid, current->tgid); 254419b0af8Sopenharmony_ci return -EINVAL; 255419b0af8Sopenharmony_ci } 256419b0af8Sopenharmony_ci return read_thread_info_locked(&kentry, entry); 257419b0af8Sopenharmony_ci} 258419b0af8Sopenharmony_ci 259419b0af8Sopenharmony_cistatic long ioctrl_collect_the_thread_cpu(void __user *argp) 260419b0af8Sopenharmony_ci{ 261419b0af8Sopenharmony_ci struct ucollection_thread_cpu_entry kentry; 262419b0af8Sopenharmony_ci struct ucollection_thread_cpu_entry __user *entry = argp; 263419b0af8Sopenharmony_ci if (entry == NULL) { 264419b0af8Sopenharmony_ci pr_err("cpu entry is null"); 265419b0af8Sopenharmony_ci return -EINVAL; 266419b0af8Sopenharmony_ci } 267419b0af8Sopenharmony_ci memset(&kentry, 0, sizeof(struct ucollection_thread_cpu_entry)); 268419b0af8Sopenharmony_ci (void)copy_from_user(&kentry, entry, sizeof(struct ucollection_thread_cpu_entry)); 269419b0af8Sopenharmony_ci if (kentry.cur_count >= kentry.total_count) { 270419b0af8Sopenharmony_ci pr_err("pid=%d is not self current:%d , or current count over total count" 271419b0af8Sopenharmony_ci , kentry.filter.pid, current->pid); 272419b0af8Sopenharmony_ci return -EINVAL; 273419b0af8Sopenharmony_ci } 274419b0af8Sopenharmony_ci return read_thread_info_locked(&kentry, entry); 275419b0af8Sopenharmony_ci} 276419b0af8Sopenharmony_ci 277419b0af8Sopenharmony_cistatic long ioctrl_collect_the_process_cpu(void __user *argp) 278419b0af8Sopenharmony_ci{ 279419b0af8Sopenharmony_ci struct ucollection_process_cpu_entry kentry; 280419b0af8Sopenharmony_ci struct ucollection_process_cpu_entry __user *entry = argp; 281419b0af8Sopenharmony_ci if (entry == NULL) { 282419b0af8Sopenharmony_ci pr_err("cpu entry is null"); 283419b0af8Sopenharmony_ci return -EINVAL; 284419b0af8Sopenharmony_ci } 285419b0af8Sopenharmony_ci 286419b0af8Sopenharmony_ci memset(&kentry, 0, sizeof(struct ucollection_process_cpu_entry)); 287419b0af8Sopenharmony_ci (void)copy_from_user(&kentry, entry, sizeof(struct ucollection_process_cpu_entry)); 288419b0af8Sopenharmony_ci 289419b0af8Sopenharmony_ci if (kentry.cur_count >= kentry.total_count) { 290419b0af8Sopenharmony_ci pr_err("current count over total count"); 291419b0af8Sopenharmony_ci return -EINVAL; 292419b0af8Sopenharmony_ci } 293419b0af8Sopenharmony_ci 294419b0af8Sopenharmony_ci rcu_read_lock(); 295419b0af8Sopenharmony_ci struct task_struct *task = get_alive_task_by_pid(kentry.filter.pid); 296419b0af8Sopenharmony_ci if (task == NULL) { 297419b0af8Sopenharmony_ci pr_info("pid=%d is task null or not alive", kentry.filter.pid); 298419b0af8Sopenharmony_ci rcu_read_unlock(); 299419b0af8Sopenharmony_ci return -EINVAL; 300419b0af8Sopenharmony_ci } 301419b0af8Sopenharmony_ci 302419b0af8Sopenharmony_ci get_process_load(task, kentry.cur_count, entry); 303419b0af8Sopenharmony_ci kentry.cur_count++; 304419b0af8Sopenharmony_ci put_user(kentry.cur_count, &entry->cur_count); 305419b0af8Sopenharmony_ci rcu_read_unlock(); 306419b0af8Sopenharmony_ci return 0; 307419b0af8Sopenharmony_ci} 308419b0af8Sopenharmony_ci 309419b0af8Sopenharmony_cilong unified_collection_collect_process_cpu(unsigned int cmd, void __user *argp) 310419b0af8Sopenharmony_ci{ 311419b0af8Sopenharmony_ci long ret = 0; 312419b0af8Sopenharmony_ci switch(cmd) { 313419b0af8Sopenharmony_ci case IOCTRL_COLLECT_ALL_PROC_CPU: 314419b0af8Sopenharmony_ci ret = ioctrl_collect_process_cpu(argp); 315419b0af8Sopenharmony_ci break; 316419b0af8Sopenharmony_ci case IOCTRL_COLLECT_THE_PROC_CPU: 317419b0af8Sopenharmony_ci ret = ioctrl_collect_the_process_cpu(argp); 318419b0af8Sopenharmony_ci break; 319419b0af8Sopenharmony_ci case IOCTRL_COLLECT_THREAD_COUNT: 320419b0af8Sopenharmony_ci ret = ioctrl_collect_thread_count(argp); 321419b0af8Sopenharmony_ci break; 322419b0af8Sopenharmony_ci case IOCTRL_COLLECT_APP_THREAD_COUNT: 323419b0af8Sopenharmony_ci ret = ioctrl_collect_app_thread_count(argp); 324419b0af8Sopenharmony_ci break; 325419b0af8Sopenharmony_ci case IOCTRL_COLLECT_APP_THREAD: 326419b0af8Sopenharmony_ci ret = ioctrl_collect_app_thread_cpu(argp); 327419b0af8Sopenharmony_ci break; 328419b0af8Sopenharmony_ci case IOCTRL_COLLECT_THE_THREAD: 329419b0af8Sopenharmony_ci ret = ioctrl_collect_the_thread_cpu(argp); 330419b0af8Sopenharmony_ci break; 331419b0af8Sopenharmony_ci case IOCTRL_COLLECT_PROC_COUNT: 332419b0af8Sopenharmony_ci ret = ioctrl_collect_process_count(argp); 333419b0af8Sopenharmony_ci break; 334419b0af8Sopenharmony_ci default: 335419b0af8Sopenharmony_ci pr_err("handle ioctrl cmd %u, _IOC_TYPE(cmd)=%d", cmd, _IOC_TYPE(cmd)); 336419b0af8Sopenharmony_ci ret = 0; 337419b0af8Sopenharmony_ci } 338419b0af8Sopenharmony_ci return ret; 339419b0af8Sopenharmony_ci}