1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include "codegen/cpp_service_stub_code_emitter.h"
10 #include "util/file.h"
11 #include "util/logger.h"
12
13 namespace OHOS {
14 namespace HDI {
ResolveDirectory(const String & targetDirectory)15 bool CppServiceStubCodeEmitter::ResolveDirectory(const String& targetDirectory)
16 {
17 if (ast_->GetASTFileType() == ASTFileType::AST_IFACE ||
18 ast_->GetASTFileType() == ASTFileType::AST_ICALLBACK) {
19 directory_ = GetFilePath(targetDirectory);
20 } else {
21 return false;
22 }
23
24 if (!File::CreateParentDir(directory_)) {
25 Logger::E("CppServiceStubCodeEmitter", "Create '%s' failed!", directory_.string());
26 return false;
27 }
28
29 return true;
30 }
31
EmitCode()32 void CppServiceStubCodeEmitter::EmitCode()
33 {
34 EmitStubHeaderFile();
35 EmitStubSourceFile();
36 }
37
EmitStubHeaderFile()38 void CppServiceStubCodeEmitter::EmitStubHeaderFile()
39 {
40 String filePath = String::Format("%s/%s.h", directory_.string(), FileName(stubName_).string());
41 File file(filePath, File::WRITE);
42 StringBuilder sb;
43
44 EmitLicense(sb);
45 EmitHeadMacro(sb, stubFullName_);
46 sb.Append("\n");
47 EmitStubHeaderInclusions(sb);
48 sb.Append("\n");
49 EmitStubDecl(sb);
50 sb.Append("\n");
51 EmitTailMacro(sb, stubFullName_);
52
53 String data = sb.ToString();
54 file.WriteData(data.string(), data.GetLength());
55 file.Flush();
56 file.Close();
57 }
58
EmitStubHeaderInclusions(StringBuilder & sb)59 void CppServiceStubCodeEmitter::EmitStubHeaderInclusions(StringBuilder& sb)
60 {
61 HeaderFile::HeaderFileSet headerFiles;
62
63 headerFiles.emplace(HeaderFile(HeaderFileType::OWN_MODULE_HEADER_FILE, EmitVersionHeaderName(interfaceName_)));
64 GetHeaderOtherLibInclusions(headerFiles);
65
66 for (const auto& file : headerFiles) {
67 sb.AppendFormat("%s\n", file.ToString().string());
68 }
69 }
70
GetHeaderOtherLibInclusions(HeaderFile::HeaderFileSet & headerFiles)71 void CppServiceStubCodeEmitter::GetHeaderOtherLibInclusions(HeaderFile::HeaderFileSet& headerFiles)
72 {
73 headerFiles.emplace(HeaderFile(HeaderFileType::OTHER_MODULES_HEADER_FILE, "message_parcel"));
74 headerFiles.emplace(HeaderFile(HeaderFileType::OTHER_MODULES_HEADER_FILE, "message_option"));
75 headerFiles.emplace(HeaderFile(HeaderFileType::OTHER_MODULES_HEADER_FILE, "iremote_stub"));
76 }
77
EmitStubDecl(StringBuilder & sb)78 void CppServiceStubCodeEmitter::EmitStubDecl(StringBuilder& sb)
79 {
80 EmitBeginNamespace(sb);
81 sb.Append("\n");
82 EmitStubUsingNamespace(sb);
83 sb.Append("\n");
84 sb.AppendFormat("class %s : public IRemoteStub<%s> {\n", stubName_.string(), interfaceName_.string());
85 EmitStubBody(sb, g_tab);
86 sb.Append("};\n");
87 sb.Append("\n");
88 EmitEndNamespace(sb);
89 }
90
EmitStubUsingNamespace(StringBuilder & sb)91 void CppServiceStubCodeEmitter::EmitStubUsingNamespace(StringBuilder& sb)
92 {
93 sb.Append("using namespace OHOS;\n");
94 }
95
EmitStubBody(StringBuilder & sb,const String & prefix)96 void CppServiceStubCodeEmitter::EmitStubBody(StringBuilder& sb, const String& prefix)
97 {
98 sb.Append("public:\n");
99 EmitStubDestruction(sb, prefix);
100 sb.Append("\n");
101 EmitStubOnRequestDecl(sb, prefix);
102 sb.Append("\n");
103 EmitGetVersionDecl(sb, prefix);
104 sb.Append("\n");
105 EmitStubMethodDecls(sb, prefix);
106 }
107
EmitStubDestruction(StringBuilder & sb,const String & prefix)108 void CppServiceStubCodeEmitter::EmitStubDestruction(StringBuilder& sb, const String& prefix)
109 {
110 sb.Append(prefix).AppendFormat("virtual ~%s() {}\n", stubName_.string());
111 }
112
EmitStubOnRequestDecl(StringBuilder & sb,const String & prefix)113 void CppServiceStubCodeEmitter::EmitStubOnRequestDecl(StringBuilder& sb, const String& prefix)
114 {
115 sb.Append(prefix).Append("int32_t OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, ");
116 sb.Append("MessageOption &option) override;\n");
117 }
118
EmitGetVersionDecl(StringBuilder & sb,const String & prefix)119 void CppServiceStubCodeEmitter::EmitGetVersionDecl(StringBuilder& sb, const String& prefix)
120 {
121 AutoPtr<ASTMethod> method = interface_->GetVersionMethod();
122
123 StringBuilder paramStr;
124 sb.Append(prefix).AppendFormat("int32_t %s(", method->GetName().string());
125 for (size_t i = 0; i < method->GetParameterNumber(); i++) {
126 AutoPtr<ASTParameter> param = method->GetParameter(i);
127 EmitInterfaceMethodParameter(param, paramStr, "");
128 if (i + 1 < method->GetParameterNumber()) {
129 paramStr.Append(", ");
130 }
131 }
132
133 paramStr.Append(") override;");
134
135 sb.Append(SpecificationParam(paramStr, prefix + g_tab));
136 sb.Append("\n");
137 }
138
EmitStubMethodDecls(StringBuilder & sb,const String & prefix)139 void CppServiceStubCodeEmitter::EmitStubMethodDecls(StringBuilder& sb, const String& prefix)
140 {
141 sb.Append("private:\n");
142 for (size_t i = 0; i < interface_->GetMethodNumber(); i++) {
143 AutoPtr<ASTMethod> method = interface_->GetMethod(i);
144 EmitStubMethodDecl(method, sb, prefix);
145 sb.Append("\n");
146 }
147 EmitStubMethodDecl(interface_->GetVersionMethod(), sb, prefix);
148 }
149
EmitStubMethodDecl(const AutoPtr<ASTMethod> & method,StringBuilder & sb,const String & prefix)150 void CppServiceStubCodeEmitter::EmitStubMethodDecl(const AutoPtr<ASTMethod>& method, StringBuilder& sb,
151 const String& prefix)
152 {
153 sb.Append(prefix).AppendFormat("int32_t %s%s(MessageParcel& %s, MessageParcel& %s, MessageOption& %s);\n",
154 stubName_.string(), method->GetName().string(), dataParcelName_.string(), replyParcelName_.string(),
155 optionName_.string());
156 }
157
EmitStubSourceFile()158 void CppServiceStubCodeEmitter::EmitStubSourceFile()
159 {
160 String filePath = String::Format("%s/%s.cpp", directory_.string(), FileName(stubName_).string());
161 File file(filePath, File::WRITE);
162 StringBuilder sb;
163
164 EmitLicense(sb);
165 EmitStubSourceInclusions(sb);
166 sb.Append("\n");
167 EmitBeginNamespace(sb);
168 sb.Append("\n");
169 EmitStubOnRequestMethodImpl(sb, "");
170 sb.Append("\n");
171 EmitGetVersionMethodImpl(sb, "");
172 sb.Append("\n");
173 EmitStubMethodImpls(sb, "");
174 sb.Append("\n");
175 EmitEndNamespace(sb);
176
177 String data = sb.ToString();
178 file.WriteData(data.string(), data.GetLength());
179 file.Flush();
180 file.Close();
181 }
182
EmitStubSourceInclusions(StringBuilder & sb)183 void CppServiceStubCodeEmitter::EmitStubSourceInclusions(StringBuilder& sb)
184 {
185 HeaderFile::HeaderFileSet headerFiles;
186 headerFiles.emplace(HeaderFile(HeaderFileType::OWN_HEADER_FILE, EmitVersionHeaderName(stubName_)));
187 GetSourceOtherLibInclusions(headerFiles);
188
189 for (const auto& file : headerFiles) {
190 sb.AppendFormat("%s\n", file.ToString().string());
191 }
192 }
193
GetSourceOtherLibInclusions(HeaderFile::HeaderFileSet & headerFiles)194 void CppServiceStubCodeEmitter::GetSourceOtherLibInclusions(HeaderFile::HeaderFileSet& headerFiles)
195 {
196 if (!interface_->IsSerializable()) {
197 headerFiles.emplace(HeaderFile(HeaderFileType::OTHER_MODULES_HEADER_FILE, "securec"));
198 } else {
199 const AST::TypeStringMap& types = ast_->GetTypes();
200 for (const auto& pair : types) {
201 AutoPtr<ASTType> type = pair.second;
202 if (type->GetTypeKind() == TypeKind::TYPE_UNION) {
203 headerFiles.emplace(HeaderFile(HeaderFileType::OTHER_MODULES_HEADER_FILE, "securec"));
204 break;
205 }
206 }
207 }
208
209 headerFiles.emplace(HeaderFile(HeaderFileType::OTHER_MODULES_HEADER_FILE, "hdf_base"));
210 headerFiles.emplace(HeaderFile(HeaderFileType::OTHER_MODULES_HEADER_FILE, "hdf_log"));
211 }
212
EmitStubOnRequestMethodImpl(StringBuilder & sb,const String & prefix)213 void CppServiceStubCodeEmitter::EmitStubOnRequestMethodImpl(StringBuilder& sb, const String& prefix)
214 {
215 sb.Append(prefix).AppendFormat("int32_t %s::OnRemoteRequest(uint32_t code, ", stubName_.string());
216 sb.Append("MessageParcel& data, MessageParcel& reply, MessageOption& option)\n");
217 sb.Append(prefix).Append("{\n");
218
219 sb.Append(prefix + g_tab).Append("switch (code) {\n");
220
221 for (size_t i = 0; i < interface_->GetMethodNumber(); i++) {
222 AutoPtr<ASTMethod> method = interface_->GetMethod(i);
223 sb.Append(prefix + g_tab + g_tab).AppendFormat("case %s:\n", EmitMethodCmdID(method).string());
224 sb.Append(prefix + g_tab + g_tab + g_tab).AppendFormat("return %sStub%s(data, reply, option);\n",
225 baseName_.string(), method->GetName().string());
226 }
227
228 AutoPtr<ASTMethod> getVerMethod = interface_->GetVersionMethod();
229 sb.Append(prefix + g_tab + g_tab).AppendFormat("case %s:\n", EmitMethodCmdID(getVerMethod).string());
230 sb.Append(prefix + g_tab + g_tab + g_tab).AppendFormat("return %sStub%s(data, reply, option);\n",
231 baseName_.string(), getVerMethod->GetName().string());
232
233 sb.Append(prefix + g_tab + g_tab).Append("default: {\n");
234 sb.Append(prefix + g_tab + g_tab + g_tab).Append(
235 "HDF_LOGE(\"%{public}s: not support cmd %{public}d\", __func__, code);\n");
236 sb.Append(prefix + g_tab + g_tab + g_tab).Append(
237 "return IPCObjectStub::OnRemoteRequest(code, data, reply, option);\n");
238 sb.Append(prefix + g_tab + g_tab).Append("}\n");
239 sb.Append(prefix + g_tab).Append("}\n");
240 sb.Append("}\n");
241 }
242
EmitGetVersionMethodImpl(StringBuilder & sb,const String & prefix)243 void CppServiceStubCodeEmitter::EmitGetVersionMethodImpl(StringBuilder& sb, const String& prefix)
244 {
245 AutoPtr<ASTMethod> method = interface_->GetVersionMethod();
246 sb.Append(prefix).AppendFormat("int32_t %sStub::%s(", baseName_.string(), method->GetName().string());
247 for (size_t i = 0; i < method->GetParameterNumber(); i++) {
248 AutoPtr<ASTParameter> param = method->GetParameter(i);
249 EmitInterfaceMethodParameter(param, sb, "");
250 if (i + 1 < method->GetParameterNumber()) {
251 sb.Append(", ");
252 }
253 }
254
255 sb.AppendFormat(")\n");
256 sb.Append(prefix).Append("{\n");
257
258 AutoPtr<ASTParameter> majorParam = method->GetParameter(0);
259 sb.Append(prefix + g_tab).AppendFormat("%s = %s;\n", majorParam->GetName().string(), majorVerName_.string());
260 AutoPtr<ASTParameter> minorParam = method->GetParameter(1);
261 sb.Append(prefix + g_tab).AppendFormat("%s = %s;\n", minorParam->GetName().string(), minorVerName_.string());
262
263 sb.Append(prefix + g_tab).Append("return HDF_SUCCESS;\n");
264 sb.Append(prefix).Append("}\n");
265 }
266
EmitStubMethodImpls(StringBuilder & sb,const String & prefix)267 void CppServiceStubCodeEmitter::EmitStubMethodImpls(StringBuilder& sb, const String& prefix)
268 {
269 for (size_t i = 0; i < interface_->GetMethodNumber(); i++) {
270 AutoPtr<ASTMethod> method = interface_->GetMethod(i);
271 EmitStubMethodImpl(method, sb, prefix);
272 sb.Append("\n");
273 }
274
275 EmitStubMethodImpl(interface_->GetVersionMethod(), sb, prefix);
276 }
277
EmitStubMethodImpl(const AutoPtr<ASTMethod> & method,StringBuilder & sb,const String & prefix)278 void CppServiceStubCodeEmitter::EmitStubMethodImpl(const AutoPtr<ASTMethod>& method, StringBuilder& sb,
279 const String& prefix)
280 {
281 sb.Append(prefix).AppendFormat(
282 "int32_t %s::%s%s(MessageParcel& %s, MessageParcel& %s, MessageOption& %s)\n",
283 stubName_.string(), stubName_.string(), method->GetName().string(),
284 dataParcelName_.string(), replyParcelName_.string(), optionName_.string());
285 sb.Append(prefix).Append("{\n");
286
287 // read interface token and check it
288 EmitStubReadInterfaceToken(dataParcelName_, sb, prefix + g_tab);
289 sb.Append("\n");
290
291 for (size_t i = 0; i < method->GetParameterNumber(); i++) {
292 AutoPtr<ASTParameter> param = method->GetParameter(i);
293 if (param->GetAttribute() == ParamAttr::PARAM_IN) {
294 EmitReadMethodParameter(param, dataParcelName_, true, sb, prefix + g_tab);
295 sb.Append("\n");
296 } else {
297 EmitLocalVariable(param, sb, prefix + g_tab);
298 sb.Append("\n");
299 }
300 }
301
302 EmitStubCallMethod(method, sb, prefix + g_tab);
303 sb.Append("\n");
304
305 if (!method->IsOneWay()) {
306 for (size_t i = 0; i < method->GetParameterNumber(); i++) {
307 AutoPtr<ASTParameter> param = method->GetParameter(i);
308 if (param->GetAttribute() == ParamAttr::PARAM_OUT) {
309 EmitWriteMethodParameter(param, replyParcelName_, sb, prefix + g_tab);
310 sb.Append("\n");
311 }
312 }
313 }
314
315 sb.Append(prefix + g_tab).Append("return HDF_SUCCESS;\n");
316 sb.Append("}\n");
317 }
318
EmitStubCallMethod(const AutoPtr<ASTMethod> & method,StringBuilder & sb,const String & prefix)319 void CppServiceStubCodeEmitter::EmitStubCallMethod(const AutoPtr<ASTMethod>& method, StringBuilder& sb,
320 const String& prefix)
321 {
322 sb.Append(prefix).AppendFormat("int32_t %s = %s(", errorCodeName_.string(), method->GetName().string());
323 for (size_t i = 0; i < method->GetParameterNumber(); i++) {
324 AutoPtr<ASTParameter> param = method->GetParameter(i);
325 sb.Append(param->GetName());
326 if (i + 1 < method->GetParameterNumber()) {
327 sb.Append(", ");
328 }
329 }
330 sb.Append(");\n");
331
332 sb.Append(prefix).AppendFormat("if (%s != HDF_SUCCESS) {\n", errorCodeName_.string());
333 sb.Append(prefix + g_tab).AppendFormat(
334 "HDF_LOGE(\"%%{public}s failed, error code is %%d\", __func__, %s);\n", errorCodeName_.string());
335 sb.Append(prefix + g_tab).AppendFormat("return %s;\n", errorCodeName_.string());
336 sb.Append(prefix).Append("}\n");
337 }
338
EmitStubReadInterfaceToken(const String & parcelName,StringBuilder & sb,const String & prefix)339 void CppServiceStubCodeEmitter::EmitStubReadInterfaceToken(const String& parcelName, StringBuilder& sb,
340 const String& prefix)
341 {
342 sb.Append(prefix).AppendFormat("if (%s.ReadInterfaceToken() != GetDescriptor()) {\n", parcelName.string());
343 sb.Append(prefix + g_tab).AppendFormat("HDF_LOGE(\"%%{public}s: interface token check failed!\", __func__);\n");
344 sb.Append(prefix + g_tab).AppendFormat("return HDF_ERR_INVALID_PARAM;\n");
345 sb.Append(prefix).Append("}\n");
346 }
347 } // namespace HDI
348 } // namespace OHOS