• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "platform/ohos/rs_irender_service_connection_ipc_interface_code_access_verifier.h"
17 
18 namespace OHOS {
19 namespace Rosen {
RSIRenderServiceConnectionInterfaceCodeAccessVerifier()20 RSIRenderServiceConnectionInterfaceCodeAccessVerifier::RSIRenderServiceConnectionInterfaceCodeAccessVerifier()
21 {
22     CheckCodeUnderlyingTypeStandardized<CodeEnumType>(codeEnumTypeName_);
23 #ifdef ENABLE_IPC_SECURITY
24     AddRSIRenderServiceConnectionInterfaceCodePermission();
25 #endif
26 }
27 
IsExclusiveVerificationPassed(CodeUnderlyingType code)28 bool RSIRenderServiceConnectionInterfaceCodeAccessVerifier::IsExclusiveVerificationPassed(CodeUnderlyingType code)
29 {
30     bool hasPermission = true;
31     switch (code) {
32         case static_cast<CodeUnderlyingType>(CodeEnumType::CREATE_VIRTUAL_SCREEN): {
33             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::CREATE_VIRTUAL_SCREEN");
34             break;
35         }
36         case static_cast<CodeUnderlyingType>(CodeEnumType::DISABLE_RENDER_CONTROL_SCREEN): {
37             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::DISABLE_RENDER_CONTROL_SCREEN");
38             break;
39         }
40         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_ACTIVE_SCREEN_ID): {
41             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_ACTIVE_SCREEN_ID");
42             break;
43         }
44         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_ALL_SCREEN_IDS): {
45             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_ALL_SCREEN_IDS");
46             break;
47         }
48         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_DEFAULT_SCREEN_ID): {
49             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_DEFAULT_SCREEN_ID");
50             break;
51         }
52         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_SCREEN_ACTIVE_MODE): {
53             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_SCREEN_ACTIVE_MODE");
54             break;
55         }
56         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_SCREEN_BACK_LIGHT): {
57             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_SCREEN_BACK_LIGHT");
58             break;
59         }
60         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_SCREEN_CAPABILITY): {
61             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_SCREEN_CAPABILITY");
62             break;
63         }
64         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_SCREEN_DATA): {
65             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_SCREEN_DATA");
66             break;
67         }
68         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_SCREEN_GAMUT): {
69             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_SCREEN_GAMUT");
70             break;
71         }
72         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_SCREEN_GAMUT_MAP): {
73             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_SCREEN_GAMUT_MAP");
74             break;
75         }
76         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_SCREEN_HDR_CAPABILITY): {
77             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_SCREEN_HDR_CAPABILITY");
78             break;
79         }
80         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_SCREEN_POWER_STATUS): {
81             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_SCREEN_POWER_STATUS");
82             break;
83         }
84         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_SCREEN_SUPPORTED_GAMUTS): {
85             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_SCREEN_SUPPORTED_GAMUTS");
86             break;
87         }
88         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_SCREEN_SUPPORTED_METADATAKEYS): {
89             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_SCREEN_SUPPORTED_METADATAKEYS");
90             break;
91         }
92         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_SCREEN_SUPPORTED_MODES): {
93             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_SCREEN_SUPPORTED_MODES");
94             break;
95         }
96         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_SCREEN_TYPE): {
97             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_SCREEN_TYPE");
98             break;
99         }
100         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_VIRTUAL_SCREEN_RESOLUTION): {
101             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_VIRTUAL_SCREEN_RESOLUTION");
102             break;
103         }
104         case static_cast<CodeUnderlyingType>(CodeEnumType::MARK_POWER_OFF_NEED_PROCESS_ONE_FRAME): {
105             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::MARK_POWER_OFF_NEED_PROCESS_ONE_FRAME");
106             break;
107         }
108         case static_cast<CodeUnderlyingType>(CodeEnumType::REGISTER_OCCLUSION_CHANGE_CALLBACK): {
109             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::REGISTER_OCCLUSION_CHANGE_CALLBACK");
110             break;
111         }
112         case static_cast<CodeUnderlyingType>(CodeEnumType::REGISTER_UIEXTENSION_CALLBACK): {
113             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::REGISTER_UIEXTENSION_CALLBACK");
114             break;
115         }
116         case static_cast<CodeUnderlyingType>(CodeEnumType::REMOVE_VIRTUAL_SCREEN): {
117             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::REMOVE_VIRTUAL_SCREEN");
118             break;
119         }
120         case static_cast<CodeUnderlyingType>(CodeEnumType::RESIZE_VIRTUAL_SCREEN): {
121             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::RESIZE_VIRTUAL_SCREEN");
122             break;
123         }
124         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_CAST_SCREEN_ENABLE_SKIP_WINDOW): {
125             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_CAST_SCREEN_ENABLE_SKIP_WINDOW");
126             break;
127         }
128         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_CURTAIN_SCREEN_USING_STATUS): {
129             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_CURTAIN_SCREEN_USING_STATUS");
130             break;
131         }
132         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_FOCUS_APP_INFO): {
133             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_FOCUS_APP_INFO");
134             break;
135         }
136         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_SCREEN_ACTIVE_MODE): {
137             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_SCREEN_ACTIVE_MODE");
138             break;
139         }
140         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_SCREEN_BACK_LIGHT): {
141             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_SCREEN_BACK_LIGHT");
142             break;
143         }
144         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_SCREEN_CHANGE_CALLBACK): {
145             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_SCREEN_CHANGE_CALLBACK");
146             break;
147         }
148         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_SCREEN_CORRECTION): {
149             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_SCREEN_CORRECTION");
150             break;
151         }
152         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_SCREEN_GAMUT): {
153             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_SCREEN_GAMUT");
154             break;
155         }
156         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_SCREEN_GAMUT_MAP): {
157             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_SCREEN_GAMUT_MAP");
158             break;
159         }
160         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_SYSTEM_ANIMATED_SCENES): {
161             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_SYSTEM_ANIMATED_SCENES");
162             break;
163         }
164         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_TP_FEATURE_CONFIG): {
165             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_TP_FEATURE_CONFIG");
166             break;
167         }
168         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_VIRTUAL_MIRROR_SCREEN_CANVAS_ROTATION): {
169             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_VIRTUAL_MIRROR_SCREEN_CANVAS_ROTATION");
170             break;
171         }
172         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_VIRTUAL_MIRROR_SCREEN_SCALE_MODE): {
173             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_VIRTUAL_MIRROR_SCREEN_SCALE_MODE");
174             break;
175         }
176         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_GLOBAL_DARK_COLOR_MODE): {
177             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_GLOBAL_DARK_COLOR_MODE");
178             break;
179         }
180         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_VIRTUAL_SCREEN_BLACKLIST): {
181             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_VIRTUAL_SCREEN_BLACKLIST");
182             break;
183         }
184         case static_cast<CodeUnderlyingType>(CodeEnumType::ADD_VIRTUAL_SCREEN_BLACKLIST): {
185             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::ADD_VIRTUAL_SCREEN_BLACKLIST");
186             break;
187         }
188         case static_cast<CodeUnderlyingType>(CodeEnumType::REMOVE_VIRTUAL_SCREEN_BLACKLIST): {
189             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::REMOVE_VIRTUAL_SCREEN_BLACKLIST");
190             break;
191         }
192         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_VIRTUAL_SCREEN_RESOLUTION): {
193             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_VIRTUAL_SCREEN_RESOLUTION");
194             break;
195         }
196         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_VIRTUAL_SCREEN_SURFACE): {
197             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_VIRTUAL_SCREEN_SURFACE");
198             break;
199         }
200         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_VIRTUAL_SCREEN_USING_STATUS): {
201             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_VIRTUAL_SCREEN_USING_STATUS");
202             break;
203         }
204         case static_cast<CodeUnderlyingType>(CodeEnumType::SHOW_WATERMARK): {
205             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SHOW_WATERMARK") &&
206                 CheckPermission(code);
207             break;
208         }
209         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_REFRESH_RATE_MODE): {
210             hasPermission = IsSystemApp();
211             break;
212         }
213         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_CURRENT_REFRESH_RATE_MODE): {
214             hasPermission = IsSystemApp();
215             break;
216         }
217         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_SCREEN_SUPPORTED_REFRESH_RATES): {
218             hasPermission = IsSystemApp() ||
219                 IsSystemCalling(codeEnumTypeName_ + "::GET_SCREEN_SUPPORTED_REFRESH_RATES");
220             break;
221         }
222         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_SHOW_REFRESH_RATE_ENABLED): {
223             hasPermission = IsSystemApp();
224             break;
225         }
226         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_SHOW_REFRESH_RATE_ENABLED): {
227             hasPermission = IsSystemApp();
228             break;
229         }
230         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_DEFAULT_DEVICE_ROTATION_OFFSET): {
231             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_DEFAULT_DEVICE_ROTATION_OFFSET");
232             break;
233         }
234         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_SCREEN_REFRESH_RATE): {
235             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_SCREEN_REFRESH_RATE");
236             break;
237         }
238         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_SCREEN_CURRENT_REFRESH_RATE): {
239             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_SCREEN_CURRENT_REFRESH_RATE");
240             break;
241         }
242         case static_cast<CodeUnderlyingType>(CodeEnumType::NOTIFY_LIGHT_FACTOR_STATUS): {
243             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::NOTIFY_LIGHT_FACTOR_STATUS");
244             break;
245         }
246         case static_cast<CodeUnderlyingType>(CodeEnumType::NOTIFY_PACKAGE_EVENT): {
247             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::NOTIFY_PACKAGE_EVENT");
248             break;
249         }
250         case static_cast<CodeUnderlyingType>(CodeEnumType::NOTIFY_REFRESH_RATE_EVENT): {
251             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::NOTIFY_REFRESH_RATE_EVENT");
252             break;
253         }
254         case static_cast<CodeUnderlyingType>(CodeEnumType::NOTIFY_DYNAMIC_MODE_EVENT): {
255             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::NOTIFY_DYNAMIC_MODE_EVENT");
256             break;
257         }
258         case static_cast<CodeUnderlyingType>(CodeEnumType::NOTIFY_TOUCH_EVENT): {
259             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::NOTIFY_TOUCH_EVENT");
260             break;
261         }
262         case static_cast<CodeUnderlyingType>(CodeEnumType::TAKE_SURFACE_CAPTURE): {
263             hasPermission = CheckPermission(code);
264             break;
265         }
266         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_MEMORY_GRAPHICS): {
267             hasPermission = CheckPermission(code);
268             break;
269         }
270         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_SCREEN_POWER_STATUS): {
271             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_SCREEN_POWER_STATUS");
272             break;
273         }
274         case static_cast<CodeUnderlyingType>(CodeEnumType::REPORT_EVENT_GAMESTATE): {
275             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::REPORT_EVENT_GAMESTATE");
276             break;
277         }
278         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_VMA_CACHE_STATUS): {
279             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_VMA_CACHE_STATUS");
280             break;
281         }
282         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_PIXEL_FORMAT): {
283             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_PIXEL_FORMAT");
284             break;
285         }
286         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_PIXEL_FORMAT): {
287             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_PIXEL_FORMAT");
288             break;
289         }
290         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_SCREEN_SUPPORTED_HDR_FORMATS): {
291             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_SCREEN_SUPPORTED_HDR_FORMATS");
292             break;
293         }
294         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_SCREEN_HDR_FORMAT): {
295             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_SCREEN_HDR_FORMAT");
296             break;
297         }
298         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_SCREEN_HDR_FORMAT): {
299             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_SCREEN_HDR_FORMAT");
300             break;
301         }
302         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_SCREEN_SUPPORTED_COLORSPACES): {
303             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_SCREEN_SUPPORTED_COLORSPACES");
304             break;
305         }
306         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_SCREEN_COLORSPACE): {
307             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_SCREEN_COLORSPACE");
308             break;
309         }
310         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_SCREEN_COLORSPACE): {
311             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_SCREEN_COLORSPACE");
312             break;
313         }
314         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_VIRTUAL_SCREEN_SECURITY_EXEMPTION_LIST): {
315             hasPermission = IsFoundationCalling(codeEnumTypeName_ + "::SET_VIRTUAL_SCREEN_SECURITY_EXEMPTION_LIST");
316             break;
317         }
318         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_ANCO_FORCE_DO_DIRECT): {
319             hasPermission = IsAncoCalling(codeEnumTypeName_ + "::SET_ANCO_FORCE_DO_DIRECT");
320             break;
321         }
322         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_ROTATION_CACHE_ENABLED): {
323             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_ROTATION_CACHE_ENABLED");
324             break;
325         }
326         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_SCREEN_SKIP_FRAME_INTERVAL): {
327             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::SET_SCREEN_SKIP_FRAME_INTERVAL");
328             break;
329         }
330         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_ACTIVE_DIRTY_REGION_INFO): {
331             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_ACTIVE_DIRTY_REGION_INFO");
332             break;
333         }
334         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_GLOBAL_DIRTY_REGION_INFO): {
335             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_GLOBAL_DIRTY_REGION_INFO");
336             break;
337         }
338         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_LAYER_COMPOSE_INFO): {
339             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_LAYER_COMPOSE_INFO");
340             break;
341         }
342         case static_cast<CodeUnderlyingType>(CodeEnumType::GET_HARDWARE_COMPOSE_DISABLED_REASON_INFO): {
343             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::GET_HARDWARE_COMPOSE_DISABLED_REASON_INFO");
344             break;
345         }
346         case static_cast<CodeUnderlyingType>(CodeEnumType::CREATE_DISPLAY_NODE): {
347             hasPermission = IsSystemCalling(codeEnumTypeName_ + "::CREATE_DISPLAY_NODE");
348             break;
349         }
350         case static_cast<CodeUnderlyingType>(CodeEnumType::SET_LAYER_TOP): {
351             hasPermission = IsStylusServiceCalling(codeEnumTypeName_ + "::SET_LAYER_TOP");
352             break;
353         }
354         default: {
355             break;
356         }
357     }
358     return hasPermission;
359 }
360 
361 #ifdef ENABLE_IPC_SECURITY
AddRSIRenderServiceConnectionInterfaceCodePermission()362 void RSIRenderServiceConnectionInterfaceCodeAccessVerifier::AddRSIRenderServiceConnectionInterfaceCodePermission()
363 {
364     for (auto& mapping : permissionRSIRenderServiceConnectionInterfaceMappings_) {
365         CodeEnumType interfaceName = mapping.first;
366         PermissionType permission = mapping.second;
367         std::string newPermission = PermissionEnumToString(permission);
368         if (newPermission == "unknown") {
369             continue;
370         }
371         CodeUnderlyingType code = static_cast<CodeUnderlyingType>(interfaceName);
372         AddPermission(code, newPermission);
373     }
374 }
375 
IsAccessTimesVerificationPassed(CodeUnderlyingType code,uint32_t times) const376 bool RSIRenderServiceConnectionInterfaceCodeAccessVerifier::IsAccessTimesVerificationPassed(
377     CodeUnderlyingType code, uint32_t times) const
378 {
379     auto interfaceName = static_cast<CodeEnumType>(code);
380     if (accessRSIRenderServiceConnectionInterfaceTimesRestrictions_.count(interfaceName) == 0) {
381         return true;
382     }
383     uint32_t restrictedTimes = accessRSIRenderServiceConnectionInterfaceTimesRestrictions_.at(interfaceName);
384     return times < restrictedTimes;
385 }
386 #endif
387 
388 } // namespace Rosen
389 } // namespace OHOS
390