• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# UIServiceExtensionAbility (for System Applications Only)
2
3## Overview
4
5[UIServiceExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md) is an [ExtensionAbility](../reference/apis-ability-kit/js-apis-app-ability-extensionAbility.md) component of the UIService type. It provides UI pages (such as preview pages) and background service capabilities. This component internally holds a [UIServiceExtensionContext](../reference/apis-ability-kit/js-apis-inner-application-uiserviceExtensionContext-sys.md), which provides a variety of APIs for external systems.
6
7In this document, the component that starts or connects to a UIServiceExtensionAbility is called the client, and the UIServiceExtensionAbility is called the server.
8
9An application can use a UIServiceExtensionAbility in two modes:
10- Call [startUIServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startuiserviceextensionability14) in the [UIAbilityContext](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md), [UIExtensionContext](../reference/apis-ability-kit/js-apis-inner-application-uiExtensionContext.md), or [ServiceExtensionContext](../reference/apis-ability-kit/js-apis-inner-application-serviceExtensionContext-sys.md) class to start a UIServiceExtensionAbility.
11- Call [connectUIServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#connectuiserviceextensionability14) in the [UIAbilityContext](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md) or [UIExtensionContext](../reference/apis-ability-kit/js-apis-inner-application-uiExtensionContext.md) class to connect to a UIServiceExtensionAbility.
12
13Note the following:
14
15- Only one window is created during the start or connection of the UIServiceExtensionAbility.
16- If the window fails to be created or is destroyed, the UIServiceExtensionAbility is automatically destroyed.
17- The start, connection, and disconnection operations can be performed only in the main thread, but not in the Worker and TaskPool threads.
18- Applications can start and connect to a UIServiceExtensionAbility provided by the system only when they gain focus in the foreground.
19
20## Lifecycle
21
22The UIServiceExtensionAbility provides the following lifecycle callbacks: [onCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md#oncreate), [onWindowWillCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md#onwindowwillcreate), [onWindowDidCreate()](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md#onwindowdidcreate), [onRequest()](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md#onrequest), [onConnect()](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md#onconnect), [onDisconnect()](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md#ondisconnect), [onData()](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md#ondata), and [onDestroy()](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md#ondestroy). Override them as required. The figure below shows the lifecycle transitions.
23
24**Figure 1** UIServiceExtensionAbility lifecycle
25
26![UIServiceExtensionAbility-lifecycle](figures/UIServiceExtension-lifecycle.png)
27
28
29
30- **onCreate**
31
32  This callback is invoked when a UIServiceExtensionAbility is created for the first time. You can perform initialization operations, for example, registering a common event listener, in this callback.
33
34  > **NOTE**
35  >
36  > If the UIServiceExtensionAbility has been created, starting it again does not trigger the **onCreate()** callback.
37
38- **onRequest**
39
40  This callback is invoked when another component calls [startUIServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startuiserviceextensionability14) to start a UIServiceExtensionAbility. After This callback is invoked, the UIServiceExtensionAbility is started and runs in the foreground. This callback is invoked each time [startUIServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startuiserviceextensionability14) is called.
41
42- **onWindowWillCreate**
43
44  This callback is invoked before a window is created. Through this callback, you can pass window parameters to the system. If **config.windowAttribute** is set to **window.ExtensionWindowAttribute.SUB_WINDOW**, a subwindow is created. If it is set to **window.ExtensionWindowAttribute.SYSTEM_WINDOW**, a system window is created.
45
46  Currently, both the subwindow and system window can be created for the UIServiceExtensionAbility started by [UIAbilityContext](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md) and [UIExtensionContext](../reference/apis-ability-kit/js-apis-inner-application-uiExtensionContext.md), but only the system window can be created for the UIServiceExtensionAbility started by [ServiceExtensionContext](../reference/apis-ability-kit/js-apis-inner-application-serviceExtensionContext-sys.md). In addition, only one window is created for a UIServiceExtensionAbility.
47
48- **onWindowDidCreate**
49
50  This callback is invoked when a window is created. You can operate the window through a [Window](../reference/apis-arkui/arkts-apis-window-Window.md) object. You can use [window.on('windowVisibilityChange')](../reference/apis-arkui/arkts-apis-window-Window.md#onwindowvisibilitychange11) to bind and process window events, such as window showing, hiding, and destruction.
51
52- **onConnect**
53
54  This callback is invoked when another component calls [connectUIServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#connectuiserviceextensionability14) to connect to a UIServiceExtensionAbility. In this callback, a remote proxy object, namely, [UIServiceHostProxy](../reference/apis-ability-kit/js-apis-inner-application-uiservicehostproxy-sys.md), is returned, through which the server communicates with the client. For the same client, if the values of **DeviceId**, **BundleName**, **ModuleName**, and **AbilityName** in the want object and the callback object are the same, [onConnect()](../reference/apis-ability-kit/js-apis-app-ability-serviceExtensionAbility-sys.md#onconnect) is invoked only for the first connection. If any of them is different, [onConnect()](../reference/apis-ability-kit/js-apis-app-ability-serviceExtensionAbility-sys.md#onconnect) is invoked again.
55
56- **onData**
57
58  This callback is invoked to receive data sent by the caller through [UIServiceProxy](../reference/apis-ability-kit/js-apis-inner-application-uiserviceproxy.md).
59
60- **onDisconnect**
61
62  This callback is invoked when the connection is interrupted, which occurs when the client exits or [disconnectServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#disconnectuiserviceextensionability14) is called.
63
64- **onDestroy**
65
66  This callback is invoked when a UIServiceExtensionAbility is no longer required and the instance is ready for destruction. You can clear resources, for example, deregistering the listener, in this callback.
67
68## Implementing an Extension Base Class of the UIService Type
69
70### Preparations
71
72Only system applications can implement a UIServiceExtensionAbility. You must make the following preparations before development:
73
74- **Switching to the full SDK**: All the APIs provided by the UIServiceExtensionAbility class are marked as system APIs and hidden by default. Therefore, you must manually obtain the full SDK from the mirror and switch to it in DevEco Studio. For details, see [Switching to Full SDK](../faqs/full-sdk-switch-guide.md).
75
76- **Requesting the AllowAppUsePrivilegeExtension privilege**: Only applications with the **AllowAppUsePrivilegeExtension** privilege can implement a UIServiceExtensionAbility. For details about how to request the privilege, see [Application Privilege Configuration](../../device-dev/subsystems/subsys-app-privilege-config-guide.md).
77
78### Creating a UIServiceExtensionAbility
79
80To manually create a UIServiceExtensionAbility in a project in DevEco Studio, perform the following steps:
81
821. In the **ets** directory of the target module, right-click and choose **New > Directory** to create a directory named [UIServiceExtension](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md).
83
842. In the **UIServiceExt** directory, right-click and choose **New > ArkTS File** to create a file named **UIServiceExt.ets**.
85
86    ```
87    ├── ets
88    │ ├── UIServiceExt
89    │ │   ├── UIServiceExt.ets
90    ```
91
923. In the **UIServiceExt.ets** file, import the UIServiceExtensionAbility module. Customize a class that inherits from the UIServiceExtensionAbility and implement the lifecycle callbacks.
93
94    ```ts
95    import { common, UIServiceExtensionAbility, Want } from '@kit.AbilityKit';
96    import { hilog } from '@kit.PerformanceAnalysisKit';
97    import { window } from '@kit.ArkUI';
98
99    export default class UIServiceExtAbility extends UIServiceExtensionAbility {
100      // Create a UIServiceExtensionAbility.
101      onCreate(want: Want) {
102        hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
103      }
104
105      // Callback for request processing.
106      onRequest(want: Want, startId: number) {
107        hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onRequest');
108      }
109
110      // Callback invoked when a connection is set up.
111      onConnect(want: Want, proxy: common.UIServiceHostProxy) {
112        hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onConnect');
113      }
114
115      // Callback invoked when a connection is interrupted.
116      onDisconnect(want: Want, proxy: common.UIServiceHostProxy) {
117        hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDisconnect');
118      }
119
120      // Callback invoked when a window is about to create.
121      onWindowWillCreate(config: window.ExtensionWindowConfig): void {
122        hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowWillCreate');
123        let rect: window.Rect = {
124          left: 100,
125          top: 100,
126          width: 500,
127          height: 500
128        };
129        // Create a subwindow.
130        config.windowName = 'sub_window'
131        config.windowAttribute = window.ExtensionWindowAttribute.SUB_WINDOW;
132        config.windowRect = rect;
133        config.subWindowOptions = {
134          title: 'sub_window_title',
135          decorEnabled: true,
136          // Whether the window is a modal window.
137          isModal: false
138        };
139        hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowWillCreate end');
140      }
141
142      // Callback invoked when a window is created.
143      onWindowDidCreate(window: window.Window) {
144        hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowDidCreate');
145        window.setUIContent('uiservice/page/WindowPage');
146        window.showWindow();
147      }
148
149      // Callback invoked to receive data.
150      onData(proxy: common.UIServiceHostProxy, data: Record<string, Object>) {
151        hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onData');
152      }
153
154      // Callback invoked to destroy the instance.
155      onDestroy() {
156        hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
157      }
158    }
159    ```
160
1614. Register the UIServiceExtensionAbility in the [module.json5 file](../quick-start/module-configuration-file.md) of the module in the project. Set **type** to **"uiService"** and **srcEntry** to the code path of the UIServiceExtensionAbility component.
162
163    ```json
164    {
165      "module": {
166        // ...
167        "extensionAbilities": [
168          {
169            "name": "UIServiceExtAbility",
170            "icon": "$media:icon",
171            "description": "uiService",
172            "type": "uiService",
173            "exported": true,
174            "srcEntry": "./ets/UIServiceExtAbility/UIServiceExtAbility.ets"
175          }
176        ]
177      }
178    }
179    ```
180
181### Starting a UIServiceExtensionAbility
182
183An application calls [startUIServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#startuiserviceextensionability14) to start a UIServiceExtensionAbility. The [onRequest()](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md#onrequest) callback is invoked, through which the background service receives the Want object passed by the caller. Once the UIServiceExtensionAbility is started, its lifecycle is independent of the client. In other words, even if the client is destroyed, the background service remains alive. However, the service is destroyed if the window fails to be created or is destroyed. Therefore, the background service must be stopped by calling [terminateSelf()](../reference/apis-ability-kit/js-apis-inner-application-uiserviceExtensionContext-sys.md#uiserviceextensioncontextterminateself) of [UIServiceExtensionContext](../reference/apis-ability-kit/js-apis-inner-application-uiserviceExtensionContext-sys.md) when its work is complete.
184
185Start a new UIServiceExtensionAbility in a system application. For details about how to obtain the context, see [Obtaining the Context of UIAbility](uiability-usage.md#obtaining-the-context-of-uiability).
186
187
188```ts
189import { common, Want } from '@kit.AbilityKit';
190import { BusinessError } from '@kit.BasicServicesKit';
191
192@Entry
193@Component
194struct Index {
195  build() {
196    Column() {
197      Row() {
198        // Create a Start button.
199        Button('start ability')
200          .enabled(true)
201          .onClick(() => {
202            let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
203            let startWant: Want = {
204              bundleName: 'com.acts.uiserviceextensionability',
205              abilityName: 'UiServiceExtAbility',
206            };
207            try {
208              // Start the UIServiceExtensionAbility.
209              context.startUIServiceExtensionAbility(startWant).then(() => {
210                console.info(`startUIServiceExtensionAbility success.`);
211              }).catch((error: BusinessError) => {
212                console.error(`startUIServiceExtensionAbility failed, err code: ${error.code}, err msg: ${error.message}.`);
213              })
214            } catch (err) {
215              let code = (err as BusinessError).code;
216              let msg = (err as BusinessError).message;
217              console.error(`startUIServiceExtensionAbility failed, err code: ${code}, err msg: ${msg}.`);
218            }
219          })
220      }
221    }
222  }
223}
224```
225
226### Connecting to a UIServiceExtensionAbility
227
228An application can use [connectUIServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#connectuiserviceextensionability14) to connect to a service (specified in the [Want](../reference/apis-ability-kit/js-apis-app-ability-want.md) object). The [onConnect()](../reference/apis-ability-kit/js-apis-app-ability-serviceExtensionAbility-sys.md#onconnect) callback is invoked, through which the service receives the [Want](../reference/apis-ability-kit/js-apis-app-ability-want.md) object passed by the caller. In this way, a connection is established.
229
230When the client calls [connectUIServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#connectuiserviceextensionability14) to connect to the server, the client receives a [UIServiceProxy](../reference/apis-ability-kit/js-apis-inner-application-uiserviceproxy.md) object returned by the server and saves it. Through this proxy object, the client sends data to the server, and disconnects from the server by calling [disconnectServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#disconnectuiserviceextensionability14).
231
232- Call [connectUIServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#connectuiserviceextensionability14) to connect to a UIServiceExtensionAbility. For details about how to obtain the context, see [Obtaining the Context of UIAbility](uiability-usage.md#obtaining-the-context-of-uiability).
233    ```ts
234    import { common, Want } from '@kit.AbilityKit';
235    import { BusinessError } from '@kit.BasicServicesKit';
236
237    @Entry
238    @Component
239    struct Page_UIServiceExtensionAbility {
240      @State uiServiceProxy: common.UIServiceProxy | null = null;
241
242      build() {
243        Column() {
244          //...
245          Row() {
246            //...
247          }.onClick(() => {
248            const context = this.getUIContext().getHostContext() as common.UIAbilityContext;
249            const want: Want = {
250              deviceId: '',
251              bundleName: 'com.example.myapplication',
252              abilityName: ''
253            };
254            // Define a callback.
255            const callback: common.UIServiceExtensionConnectCallback = {
256              onData: (data: Record<string, Object>): void => {
257                console.info(`onData, data: ${JSON.stringify(data)}.`);
258              },
259              onDisconnect: (): void => {
260                console.info(`onDisconnect.`);
261              }
262            };
263            // Connect to the UIServiceExtensionAbility.
264            context.connectUIServiceExtensionAbility(want, callback).then((uiServiceProxy: common.UIServiceProxy) => {
265              this.uiServiceProxy = uiServiceProxy;
266              console.info(`connectUIServiceExtensionAbility success.`);
267            }).catch((error: BusinessError) => {
268              console.error(`connectUIServiceExtensionAbility failed, err code:${error.code}, err msg: ${error.message}.`);
269            });
270          })
271        }
272      }
273    }
274    ```
275
276- Call [disconnectUIServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiAbilityContext.md#disconnectuiserviceextensionability14) to disconnect from a UIServiceExtensionAbility.
277    ```ts
278    import { common } from '@kit.AbilityKit';
279    import { BusinessError } from '@kit.BasicServicesKit';
280
281    @Entry
282    @Component
283    struct Page_UIServiceExtensionAbility {
284      @State uiServiceProxy: common.UIServiceProxy | null = null;
285
286      build() {
287        Column() {
288          //...
289          Row() {
290            //...
291          }.onClick(() => {
292            const context = this.getUIContext().getHostContext() as common.UIAbilityContext;
293            // this.uiServiceProxy is the proxy object saved during connection.
294            context.disconnectUIServiceExtensionAbility(this.uiServiceProxy).then(() => {
295              console.info(`disconnectUIServiceExtensionAbility success.`);
296            }).catch((error: BusinessError) => {
297              console.error(`disconnectUIServiceExtensionAbility failed, err code: ${error.code}, err msg: ${error.message}.`);
298            });
299          })
300        }
301      }
302    }
303    ```
304
305
306
307## Bidirectional Communication Between the Client and Server
308
309After a UIServiceExtensionAbility is started, the following operations are possible:
310
3111. The client calls [connectUIServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiExtensionContext.md#connectuiserviceextensionability14) to obtain a [UIServiceProxy](../reference/apis-ability-kit/js-apis-inner-application-uiserviceproxy.md) object, through which it can send data to the server.
3122. The server obtains a [UIServiceHostProxy](../reference/apis-ability-kit/js-apis-inner-application-uiservicehostproxy-sys.md) object through the [onConnect()](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md#onconnect) callback and sends data to the client through this proxy.
313
314![UIServiceExtensionAbility-bidirectionalcommunication](figures/UIServiceExtension-bidirectionalcommunication.png)
315
316
317### Communication Between the Client and Server
318- Data transmission on the client
319
320  The client connects to the server through [connectUIServiceExtensionAbility()](../reference/apis-ability-kit/js-apis-inner-application-uiExtensionContext.md#connectuiserviceextensionability14) and obtains a [UIServiceProxy](../reference/apis-ability-kit/js-apis-inner-application-uiserviceproxy.md) object. The client calls [sendData()](../reference/apis-ability-kit/js-apis-inner-application-uiserviceproxy.md#uiserviceproxysenddata) of the proxy object to send data to the server. The server receives data through the [onData()](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md#ondata) callback.
321    ```ts
322    import { common, Want } from '@kit.AbilityKit';
323    import { BusinessError } from '@kit.BasicServicesKit';
324
325    @Entry
326    @Component
327    struct Index {
328      comProxy: common.UIServiceProxy | null = null;
329      connectCallback: common.UIServiceExtensionConnectCallback = {
330        onData: (data: Record<string, Object>) => {
331          console.info(`onData, data: ${JSON.stringify(data)}.`);
332        },
333        onDisconnect: () => {
334          console.info(`onDisconnect.`);
335        }
336      }
337
338      build() {
339        Column() {
340          Row() {
341            // Create a Connect button.
342            Button('connect ability')
343              .enabled(true)
344              .onClick(() => {
345                let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
346                let startWant: Want = {
347                  bundleName: 'com.acts.uiserviceextensionability',
348                  abilityName: 'UiServiceExtAbility',
349                };
350                try {
351                  // Connect to the UIServiceExtensionAbility.
352                  context.connectUIServiceExtensionAbility(startWant, this.connectCallback)
353                    .then((proxy: common.UIServiceProxy) => {
354                      this.comProxy = proxy;
355                      let formData: Record<string, string> = {
356                        'test': 'test'
357                      };
358                      try {
359                        this.comProxy.sendData(formData);
360                      } catch (err) {
361                        let code = (err as BusinessError).code;
362                        let msg = (err as BusinessError).message;
363                        console.error(`sendData failed, err code: ${code}, err msg: ${msg}.`);
364                      }
365                    })
366                    .catch((err: BusinessError) => {
367                      console.error(`connectUIServiceExtensionAbility failed, err code: ${err.code}, err msg: ${err.message}.`);
368                    });
369                } catch (err) {
370                  let code = (err as BusinessError).code;
371                  let msg = (err as BusinessError).message;
372                  console.error(`connectUIServiceExtensionAbility failed, err code: ${code}, err msg: ${msg}.`);
373                }
374              })
375          }
376        }
377      }
378    }
379    ```
380
381- Data transmission on the server
382
383  The server receives data transferred by the client through [onData()](../reference/apis-ability-kit/js-apis-app-ability-uiServiceExtensionAbility-sys.md#ondata). Through the [UIServiceHostProxy](../reference/apis-ability-kit/js-apis-inner-application-uiservicehostproxy-sys.md) object, which is saved during the connection, the server calls [sendData()](../reference/apis-ability-kit/js-apis-inner-application-uiservicehostproxy-sys.md#senddata) to send data to the client.
384    ```ts
385    import { common, Want, UIServiceExtensionAbility } from '@kit.AbilityKit';
386    import { window } from '@kit.ArkUI';
387    import { BusinessError } from '@kit.BasicServicesKit';
388
389    export default class MyServiceExtAbility extends UIServiceExtensionAbility {
390      comProxy: common.UIServiceHostProxy | null = null;
391
392      // Callback invoked when a UIServiceExtensionAbility is created.
393      onCreate(want: Want) {
394        console.info('UIServiceExtensionAbility onCreate');
395      }
396
397      // Callback for request processing.
398      onRequest(want: Want, startId: number) {
399        console.info('UIServiceExtensionAbility onRequest');
400      }
401
402      // Callback invoked when a connection is set up.
403      onConnect(want: Want, proxy: common.UIServiceHostProxy) {
404        console.info('UIServiceExtensionAbility onConnect');
405        this.comProxy = proxy;
406      }
407
408      // Callback invoked when a connection is interrupted.
409      onDisconnect(want: Want, proxy: common.UIServiceHostProxy) {
410        console.info('UIServiceExtensionAbility onDisconnect');
411        this.comProxy = null;
412      }
413
414      // Callback invoked to receive data.
415      onData(proxy: common.UIServiceHostProxy, data: Record<string, Object>) {
416        console.info('UIServiceExtensionAbility onData');
417        try {
418          let formData: Record<string, string> = {
419            'Data': 'reply message'
420          };
421          proxy.sendData(formData);
422        } catch (err) {
423          let code = (err as BusinessError).code;
424          let msg = (err as BusinessError).message;
425          console.error(`sendData failed, err code: ${code}, err msg: ${msg}.`);
426        }
427      }
428
429      onWindowWillCreate(extensionWindowConfig: window.ExtensionWindowConfig) {
430        console.info('UIServiceExtensionAbility onWindowWillCreate');
431      }
432
433      onWindowDidCreate(window: window.Window) {
434        console.info('UIServiceExtensionAbility onWindowDidCreate');
435      }
436
437      onDestroy() {
438        console.info('UIServiceExtensionAbility onDestroy');
439      }
440    }
441    ```
442