1/* 2 * Copyright (c) 2022 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 */ 15let rpc = requireNapi('rpc'); 16let accessControl = requireNapi('abilityAccessCtrl'); 17let hilog = requireNapi('hilog'); 18 19let domainID = 0xD001320; 20let TAG = 'JSENV'; 21 22const EVENT_CALL_NOTIFY = 1; 23const REQUEST_SUCCESS = 0; 24const REQUEST_FAILED = 1; 25const PERMISSION_ABILITY_BACKGROUND_COMMUNICATION = 'ohos.permission.ABILITY_BACKGROUND_COMMUNICATION'; 26 27const ERROR_CODE_INVALID_PARAM = 401; 28const ERROR_CODE_FUNC_REGISTERED = 16200004; 29const ERROR_CODE_FUNC_NOT_EXIST = 16200005; 30const ERROR_CODE_INNER_ERROR = 16000050; 31 32const ERROR_MSG_INVALID_PARAM = 'Invalid input parameter.'; 33const ERROR_MSG_FUNC_REGISTERED = 'Method registered. The method has registered.'; 34const ERROR_MSG_FUNC_NOT_EXIST = 'The method has not been registered.'; 35const ERROR_MSG_INNER_ERROR = 'Inner Error.'; 36 37let errMap = new Map(); 38errMap.set(ERROR_CODE_INVALID_PARAM, ERROR_MSG_INVALID_PARAM); 39errMap.set(ERROR_CODE_FUNC_REGISTERED, ERROR_MSG_FUNC_REGISTERED); 40errMap.set(ERROR_CODE_FUNC_NOT_EXIST, ERROR_MSG_FUNC_NOT_EXIST); 41errMap.set(ERROR_CODE_INNER_ERROR, ERROR_MSG_INNER_ERROR); 42 43class BusinessError extends Error { 44 constructor(code) { 45 let msg = ''; 46 if (errMap.has(code)) { 47 msg = errMap.get(code); 48 } else { 49 msg = ERROR_MSG_INNER_ERROR; 50 } 51 super(msg); 52 this.code = code; 53 } 54} 55 56class ThrowInvalidParamError extends Error { 57 constructor(msg) { 58 let message = ERROR_MSG_INVALID_PARAM + msg; 59 super(message); 60 this.code = ERROR_CODE_INVALID_PARAM; 61 } 62} 63 64class Callee extends rpc.RemoteObject { 65 constructor(des) { 66 if (typeof des === 'string') { 67 super(des); 68 this.callList = new Map(); 69 this.startUpNewRule = false; 70 hilog.sLogI(domainID, TAG, 'Callee constructor is OK ' + typeof des); 71 } else { 72 hilog.sLogI(domainID, TAG, 'Callee constructor error, des is ' + typeof des); 73 return null; 74 } 75 } 76 77 setNewRuleFlag(flag) { 78 this.startUpNewRule = flag; 79 } 80 81 onRemoteMessageRequest(code, data, reply, option) { 82 hilog.sLogI(domainID, TAG, 'Callee onRemoteMessageRequest code [' + typeof code + ' ' + code + ']'); 83 if (!this.StartUpRuleCheck()) { 84 return false; 85 } 86 87 if (typeof code !== 'number' || typeof data !== 'object' || 88 typeof reply !== 'object' || typeof option !== 'object') { 89 hilog.sLogI(domainID, TAG, 'Callee onRemoteMessageRequest error, code is [' + 90 typeof code + '], data is [' + typeof data + '], reply is [' + 91 typeof reply + '], option is [' + typeof option + ']'); 92 return false; 93 } 94 95 hilog.sLogI(domainID, TAG, 'Callee onRemoteMessageRequest code proc'); 96 if (code === EVENT_CALL_NOTIFY) { 97 if (this.callList == null) { 98 hilog.sLogI(domainID, TAG, 'Callee onRemoteMessageRequest error, this.callList is nullptr'); 99 return false; 100 } 101 102 let method = data.readString(); 103 hilog.sLogI(domainID, TAG, 'Callee onRemoteMessageRequest method [' + method + ']'); 104 let func = this.callList.get(method); 105 if (typeof func !== 'function') { 106 hilog.sLogI(domainID, TAG, 'Callee onRemoteMessageRequest error, get func is ' + typeof func); 107 return false; 108 } 109 110 let result = func(data); 111 if (typeof result === 'object' && result != null) { 112 reply.writeInt(REQUEST_SUCCESS); 113 reply.writeString(typeof result); 114 reply.writeParcelable(result); 115 hilog.sLogI(domainID, TAG, 'Callee onRemoteMessageRequest code proc Packed data'); 116 } else { 117 reply.writeInt(REQUEST_FAILED); 118 reply.writeString(typeof result); 119 hilog.sLogI(domainID, TAG, 'Callee onRemoteMessageRequest error, retval is ' + 120 REQUEST_FAILED + ', type is ' + typeof result, REQUEST_FAILED, typeof result); 121 } 122 } else { 123 hilog.sLogI(domainID, TAG, 'Callee onRemoteMessageRequest error, code is ' + code); 124 return false; 125 } 126 hilog.sLogI(domainID, TAG, 'Callee onRemoteMessageRequest code proc success'); 127 return true; 128 } 129 130 on(method, callback) { 131 if (typeof method !== 'string' || method === '' || typeof callback !== 'function') { 132 hilog.sLogI(domainID, TAG, 133 'Callee on error, method is [' + typeof method + '], typeof callback [' + typeof callback + ']'); 134 throw new ThrowInvalidParamError('Parameter error: Failed to get method or callback.' + 135 'method must be a non-empty string, callback must be a function.'); 136 } 137 138 if (this.callList == null) { 139 hilog.sLogI(domainID, TAG, 'Callee on error, this.callList is nullptr'); 140 throw new BusinessError(ERROR_CODE_INNER_ERROR); 141 } 142 143 if (this.callList.has(method)) { 144 hilog.sLogI(domainID, TAG, 'Callee on error, [' + method + '] has registered'); 145 throw new BusinessError(ERROR_CODE_FUNC_REGISTERED); 146 } 147 148 this.callList.set(method, callback); 149 hilog.sLogI(domainID, TAG, 'Callee on method [' + method + ']'); 150 } 151 152 off(method) { 153 if (typeof method !== 'string' || method === '') { 154 hilog.sLogI(domainID, TAG, 'Callee off error, method is [' + typeof method + ']'); 155 throw new ThrowInvalidParamError('Parameter error: Failed to get method, must be a string.'); 156 } 157 158 if (this.callList == null) { 159 hilog.sLogI(domainID, TAG, 'Callee off error, this.callList is null'); 160 throw new BusinessError(ERROR_CODE_INNER_ERROR); 161 } 162 163 if (!this.callList.has(method)) { 164 hilog.sLogI(domainID, TAG, 'Callee off error, this.callList not found ' + method); 165 throw new BusinessError(ERROR_CODE_FUNC_NOT_EXIST); 166 } 167 168 this.callList.delete(method); 169 hilog.sLogI(domainID, TAG, 'Callee off method [' + method + ']'); 170 } 171 172 StartUpRuleCheck() { 173 if (this.startUpNewRule && rpc.IPCSkeleton.isLocalCalling()) { 174 hilog.sLogI(domainID, TAG, 'Use new start up rule, check caller permission.'); 175 let accessManger = accessControl.createAtManager(); 176 let accessTokenId = rpc.IPCSkeleton.getCallingTokenId(); 177 let grantStatus = 178 accessManger.verifyAccessTokenSync(accessTokenId, PERMISSION_ABILITY_BACKGROUND_COMMUNICATION); 179 if (grantStatus === accessControl.GrantStatus.PERMISSION_DENIED) { 180 hilog.sLogI(domainID, TAG, 181 'Callee onRemoteMessageRequest error, the Caller does not have PERMISSION_ABILITY_BACKGROUND_COMMUNICATION'); 182 return false; 183 } 184 } 185 return true; 186 } 187} 188 189export default Callee; 190