• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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 package ohos.devtools.datasources.transport.grpc;
17 
18 import com.google.protobuf.ByteString;
19 import com.google.protobuf.InvalidProtocolBufferException;
20 import io.grpc.ManagedChannel;
21 import io.grpc.Status;
22 import io.grpc.StatusRuntimeException;
23 import ohos.devtools.datasources.transport.grpc.service.CommonTypes;
24 import ohos.devtools.datasources.transport.grpc.service.ProcessPluginConfig;
25 import ohos.devtools.datasources.transport.grpc.service.ProcessPluginResult;
26 import ohos.devtools.datasources.transport.grpc.service.ProfilerServiceTypes;
27 import ohos.devtools.datasources.utils.common.util.CommonUtil;
28 import ohos.devtools.datasources.utils.common.util.DateTimeUtil;
29 import ohos.devtools.datasources.utils.device.entity.DeviceType;
30 import ohos.devtools.datasources.utils.process.entity.ProcessInfo;
31 import ohos.devtools.datasources.utils.profilerlog.ProfilerLogManager;
32 import ohos.devtools.datasources.utils.session.service.SessionManager;
33 import ohos.devtools.views.common.LayoutConstants;
34 import org.apache.commons.codec.digest.DigestUtils;
35 import org.apache.logging.log4j.LogManager;
36 import org.apache.logging.log4j.Logger;
37 
38 import java.io.File;
39 import java.io.FileInputStream;
40 import java.io.IOException;
41 import java.net.InetAddress;
42 import java.util.ArrayList;
43 import java.util.Iterator;
44 import java.util.List;
45 import java.util.Objects;
46 import java.util.concurrent.ConcurrentHashMap;
47 
48 import static io.grpc.Status.DEADLINE_EXCEEDED;
49 import static io.grpc.Status.INTERNAL;
50 import static io.grpc.Status.UNAVAILABLE;
51 import static ohos.devtools.datasources.utils.common.Constant.DEVTOOLS_PLUGINS_FULL_PATH;
52 import static ohos.devtools.datasources.utils.common.Constant.PROCESS_PLUGS;
53 import static ohos.devtools.datasources.utils.device.entity.DeviceType.LEAN_HOS_DEVICE;
54 import static ohos.devtools.views.common.Constant.IS_SUPPORT_NEW_HDC;
55 
56 /**
57  * Provide device-side grpc interface encapsulation for each module in the application
58  *
59  * @since 2021/11/22
60  */
61 public final class HiProfilerClient {
62     private static final Logger LOGGER = LogManager.getLogger(HiProfilerClient.class);
63 
64     /**
65      * Singleton Class Instance
66      */
67     private static final HiProfilerClient INSTANCE = new HiProfilerClient();
68 
69     private static final String IP = InetAddress.getLoopbackAddress().getHostAddress();
70 
71     private static final int RETRY_COUNT = 2;
72 
73     /**
74      * Used to store the created Profiler
75      */
76     private static ConcurrentHashMap<String, ProfilerClient> profilerClientMap =
77         new ConcurrentHashMap<>(CommonUtil.collectionSize(0));
78 
HiProfilerClient()79     private HiProfilerClient() {
80     }
81 
82     /**
83      * Get instance
84      *
85      * @return HiProfilerClient
86      */
getInstance()87     public static HiProfilerClient getInstance() {
88         if (ProfilerLogManager.isInfoEnabled()) {
89             LOGGER.info("getInstance");
90         }
91         return INSTANCE;
92     }
93 
94     /**
95      * Get profilerclient
96      *
97      * @param ip ip address
98      * @param port port number
99      * @param channel channel
100      * @return ProfilerClient
101      */
getProfilerClient(String ip, int port, ManagedChannel channel)102     public ProfilerClient getProfilerClient(String ip, int port, ManagedChannel channel) {
103         if (ProfilerLogManager.isInfoEnabled()) {
104             LOGGER.info("getProfilerClient");
105         }
106         String mapKey = IP + port;
107         if (port <= 0 || port > LayoutConstants.PORT) {
108             return null;
109         }
110         if (Objects.isNull(profilerClientMap.get(mapKey))) {
111             ProfilerClient profilerClient = null;
112             profilerClient = new ProfilerClient(IP, port, channel);
113             profilerClientMap.put(mapKey, profilerClient);
114             return profilerClient;
115         }
116         return profilerClientMap.get(mapKey);
117     }
118 
119     /**
120      * get profilerClient.
121      *
122      * @param ip ip address
123      * @param port port number
124      * @return ProfilerClient
125      */
getProfilerClient(String ip, int port)126     public ProfilerClient getProfilerClient(String ip, int port) {
127         if (ProfilerLogManager.isInfoEnabled()) {
128             LOGGER.info("getProfilerClient");
129         }
130         if (port <= 0 || port > LayoutConstants.PORT) {
131             return null;
132         }
133         String mapKey = IP + port;
134         if (profilerClientMap.get(mapKey) == null) {
135             ProfilerClient profilerClient = new ProfilerClient(IP, port);
136             profilerClientMap.put(mapKey, profilerClient);
137             return profilerClient;
138         }
139         return profilerClientMap.get(mapKey);
140     }
141 
142     /**
143      * Destroy profilerClient
144      *
145      * @param ip ip address
146      * @param port port number
147      * @return boolean
148      */
destroyProfiler(String ip, int port)149     public boolean destroyProfiler(String ip, int port) {
150         if (ProfilerLogManager.isInfoEnabled()) {
151             LOGGER.info("destroyProfiler");
152         }
153         if (port <= 0 || port > LayoutConstants.PORT) {
154             return false;
155         }
156         String mapKey = IP + port;
157         if (Objects.isNull(profilerClientMap.get(mapKey))) {
158             return true;
159         }
160         ProfilerClient client = profilerClientMap.get(mapKey);
161         client.shutdown();
162         return profilerClientMap.remove(mapKey, client);
163     }
164 
165     /**
166      * requestCreateSession
167      *
168      * @param deviceIp deviceIp
169      * @param port port
170      * @param request request
171      * @return ProfilerServiceTypes.CreateSessionResponse
172      */
requestCreateSession(String deviceIp, int port, ProfilerServiceTypes.CreateSessionRequest request)173     public ProfilerServiceTypes.CreateSessionResponse requestCreateSession(String deviceIp, int port,
174         ProfilerServiceTypes.CreateSessionRequest request) {
175         if (ProfilerLogManager.isInfoEnabled()) {
176             LOGGER.info("requestCreateSession");
177         }
178         if (port <= 0 || port > LayoutConstants.PORT) {
179             return ProfilerServiceTypes.CreateSessionResponse.newBuilder().setSessionId(-1).build();
180         }
181         ProfilerClient client = getProfilerClient(deviceIp, port);
182         try {
183             return client.createSession(request);
184         } catch (StatusRuntimeException exception) {
185             handleGrpcInterface(exception, port, client);
186             if (ProfilerLogManager.isErrorEnabled()) {
187                 LOGGER.error("StatusRuntimeException ", exception);
188             }
189             return ProfilerServiceTypes.CreateSessionResponse.newBuilder().setSessionId(-1).build();
190         }
191     }
192 
193     /**
194      * createSession for ListProcess
195      *
196      * @param port port number
197      * @param name name
198      * @param pid pid
199      * @param reportProcessTree report process tree
200      * @param deviceType DeviceType
201      * @return int
202      */
processListCreateSession(int port, String name, int pid, boolean reportProcessTree, DeviceType deviceType)203     public int processListCreateSession(int port, String name, int pid, boolean reportProcessTree,
204         DeviceType deviceType) {
205         if (ProfilerLogManager.isInfoEnabled()) {
206             LOGGER.info("processListCreateSession");
207         }
208         if (port <= 0 || port > LayoutConstants.PORT) {
209             return -1;
210         }
211         ProcessPluginConfig.ProcessConfig plug =
212             ProcessPluginConfig.ProcessConfig.newBuilder().setReportProcessTree(true).build();
213         ProfilerServiceTypes.ProfilerSessionConfig sessionConfig = ProfilerServiceHelper
214             .profilerSessionConfig(true, null, 10,
215                 ProfilerServiceTypes.ProfilerSessionConfig.BufferConfig.Policy.RECYCLE, 5000);
216         String sha256 = "";
217         CommonTypes.ProfilerPluginConfig plugConfig =
218             ProfilerServiceHelper.profilerPluginConfig(name, sha256, 2, plug.toByteString());
219         List<CommonTypes.ProfilerPluginConfig> plugs = new ArrayList();
220         plugs.add(plugConfig);
221         ProfilerServiceTypes.CreateSessionRequest request =
222             ProfilerServiceHelper.createSessionRequest(CommonUtil.getRequestId(), sessionConfig, plugs);
223         ProfilerServiceTypes.CreateSessionResponse response = null;
224         ProfilerClient client = getProfilerClient("", port);
225         try {
226             response = client.createSession(request);
227             LOGGER.info("process Session start444 {} ", DateTimeUtil.getNowTimeLong());
228         } catch (StatusRuntimeException exception) {
229             handleGrpcInterface(exception, port, client);
230             if (ProfilerLogManager.isErrorEnabled()) {
231                 LOGGER.error("processListCreateSession ", exception);
232             }
233             return -1;
234         }
235         return response.getSessionId();
236     }
237 
238     /**
239      * getSha256
240      *
241      * @param pluginFileName pluginFileName
242      * @return String
243      */
getSha256(String pluginFileName)244     public static String getSha256(String pluginFileName) {
245         return "";
246     }
247 
248     /**
249      * getSTDSha256
250      *
251      * @param pluginFileName pluginFileName
252      * @return String
253      */
getSTDSha256(String pluginFileName)254     public static String getSTDSha256(String pluginFileName) {
255         return "";
256     }
257 
258     /**
259      * Request to start session
260      *
261      * @param deviceIp deviceIp
262      * @param port port number
263      * @param sessionId sessionId
264      * @return boolean
265      */
requestStartSession(String deviceIp, int port, int sessionId)266     public boolean requestStartSession(String deviceIp, int port, int sessionId) {
267         if (ProfilerLogManager.isInfoEnabled()) {
268             LOGGER.info("requestStartSession");
269         }
270         if (port <= 0 || port > LayoutConstants.PORT) {
271             return false;
272         }
273         return requestStartSession(deviceIp, port, sessionId, 0);
274     }
275 
requestStartSession(String deviceIp, int port, int sessionId, int retryCount)276     private boolean requestStartSession(String deviceIp, int port, int sessionId, int retryCount) {
277         if (ProfilerLogManager.isInfoEnabled()) {
278             LOGGER.info("requestStartSession");
279         }
280         ProfilerServiceTypes.StartSessionRequest requestStartSession =
281             ProfilerServiceHelper.startSessionRequest(CommonUtil.getRequestId(), sessionId, new ArrayList<>());
282         ProfilerServiceTypes.StartSessionResponse response = null;
283         ProfilerClient client = getProfilerClient(deviceIp, port);
284         try {
285             response = client.startSession(requestStartSession);
286         } catch (StatusRuntimeException exception) {
287             if (ProfilerLogManager.isErrorEnabled()) {
288                 LOGGER.error("requestStartSession", exception.getMessage());
289             }
290             handleGrpcInterface(exception, port, client);
291             return false;
292         }
293         return response.getStatus() == 0 ? true : false;
294     }
295 
296     /**
297      * requestStopSession
298      *
299      * @param deviceIp deviceIp
300      * @param port port number
301      * @param sessionId sessionId
302      * @param isForce isForce
303      * @return boolean
304      */
requestStopSession(String deviceIp, int port, int sessionId, boolean isForce)305     public boolean requestStopSession(String deviceIp, int port, int sessionId, boolean isForce) {
306         if (ProfilerLogManager.isInfoEnabled()) {
307             LOGGER.info("requestStopSession");
308         }
309         if (port <= 0 || port > LayoutConstants.PORT) {
310             return false;
311         }
312         return requestStopSession(deviceIp, port, sessionId);
313     }
314 
requestStopSession(String deviceIp, int port, int sessionId)315     private boolean requestStopSession(String deviceIp, int port, int sessionId) {
316         if (ProfilerLogManager.isInfoEnabled()) {
317             LOGGER.info("requestStopSession");
318         }
319         ProfilerClient client = getProfilerClient(deviceIp, port);
320         ProfilerServiceTypes.StopSessionRequest stopSession =
321             ProfilerServiceHelper.stopSessionRequest(CommonUtil.getRequestId(), sessionId);
322         ProfilerServiceTypes.StopSessionResponse response = null;
323         try {
324             response = client.stopSession(stopSession);
325         } catch (StatusRuntimeException exception) {
326             if (ProfilerLogManager.isErrorEnabled()) {
327                 LOGGER.info("stopSession has Exception {}", exception.getMessage());
328             }
329             handleGrpcInterface(exception, port, client);
330             return false;
331         }
332         return response.getStatus() == 0 ? true : false;
333     }
334 
335     /**
336      * request destory Session
337      *
338      * @param deviceIp deviceIp
339      * @param port port number
340      * @param sessionId sessionId
341      * @return boolean
342      */
requestDestroySession(String deviceIp, int port, int sessionId)343     public boolean requestDestroySession(String deviceIp, int port, int sessionId) {
344         if (ProfilerLogManager.isInfoEnabled()) {
345             LOGGER.info("requestDestroySession");
346         }
347         if (port <= 0 || port > LayoutConstants.PORT) {
348             return false;
349         }
350         return requestDestroySession(deviceIp, port, sessionId, 0);
351     }
352 
requestDestroySession(String deviceIp, int port, int sessionId, int retryCount)353     private boolean requestDestroySession(String deviceIp, int port, int sessionId, int retryCount) {
354         if (ProfilerLogManager.isInfoEnabled()) {
355             LOGGER.info("requestDestroySession");
356         }
357         ProfilerClient client = getProfilerClient(deviceIp, port);
358         ProfilerServiceTypes.DestroySessionRequest req =
359             ProfilerServiceHelper.destroySessionRequest(CommonUtil.getRequestId(), sessionId);
360         ProfilerServiceTypes.DestroySessionResponse response = null;
361         try {
362             response = client.destroySession(req);
363         } catch (StatusRuntimeException exception) {
364             if (ProfilerLogManager.isErrorEnabled()) {
365                 LOGGER.error("requestDestroySession failed {}", exception.getMessage());
366             }
367             handleGrpcInterface(exception, port, client);
368             int retryCounts = retryCount + 1;
369             if (retryCounts > RETRY_COUNT) {
370                 return true;
371             }
372             return requestDestroySession(deviceIp, port, sessionId, retryCounts);
373         }
374 
375         return response.getStatus() == 0 ? true : false;
376     }
377 
378     /**
379      * Fetch process data
380      *
381      * @param deviceIp deviceIp
382      * @param port port number
383      * @param sessionId sessionId
384      * @return List <ProcessInfo>
385      */
fetchProcessData(String deviceIp, int port, int sessionId)386     public List<ProcessInfo> fetchProcessData(String deviceIp, int port, int sessionId) {
387         if (ProfilerLogManager.isInfoEnabled()) {
388             LOGGER.info("fetchProcessData");
389         }
390         ProfilerClient client = getProfilerClient(deviceIp, port);
391         List<ProcessInfo> processInfos = new ArrayList<>();
392         ProfilerServiceTypes.FetchDataRequest fetchData =
393             ProfilerServiceHelper.fetchDataRequest(CommonUtil.getRequestId(), sessionId, null);
394         Iterator<ProfilerServiceTypes.FetchDataResponse> res = null;
395         try {
396             res = client.fetchData(fetchData);
397         } catch (StatusRuntimeException exception) {
398             if (ProfilerLogManager.isErrorEnabled()) {
399                 LOGGER.info("GrpcException {}", exception.getMessage());
400             }
401             return new ArrayList<>();
402         }
403         try {
404             if (res.hasNext()) {
405                 ProfilerServiceTypes.FetchDataResponse fetchDataResponse = res.next();
406                 int pluginStatus = fetchDataResponse.getStatus();
407                 if (pluginStatus != 0) {
408                     return new ArrayList<>();
409                 }
410                 List<CommonTypes.ProfilerPluginData> lists = fetchDataResponse.getPluginDataList();
411                 processInfos = extractedData(lists);
412             }
413         } catch (StatusRuntimeException statusRuntimeException) {
414             if (ProfilerLogManager.isErrorEnabled()) {
415                 LOGGER.error(" get ProcessInfo failed {}", statusRuntimeException.getMessage());
416             }
417         }
418         return processInfos;
419     }
420 
extractedData(List<CommonTypes.ProfilerPluginData> lists)421     private List<ProcessInfo> extractedData(List<CommonTypes.ProfilerPluginData> lists) {
422         if (ProfilerLogManager.isInfoEnabled()) {
423             LOGGER.info("extractedData");
424         }
425         List<ProcessInfo> process = new ArrayList<>();
426         if (lists.isEmpty()) {
427             return process;
428         }
429         CommonTypes.ProfilerPluginData profilerPluginData = lists.get(0);
430         if (PROCESS_PLUGS.equals(profilerPluginData.getName())) {
431             if (profilerPluginData.getStatus() != 0) {
432                 return process;
433             }
434             ByteString data = profilerPluginData.getData();
435             ProcessPluginResult.ProcessData.Builder builder = ProcessPluginResult.ProcessData.newBuilder();
436             ProcessPluginResult.ProcessData processData = null;
437             try {
438                 processData = builder.mergeFrom(data).build();
439             } catch (InvalidProtocolBufferException exception) {
440                 if (ProfilerLogManager.isErrorEnabled()) {
441                     LOGGER.info("mergeFrom failed {}", exception.getMessage());
442                 }
443             }
444             List<ProcessPluginResult.ProcessInfo> processesinfoList = processData.getProcessesinfoList();
445             for (ProcessPluginResult.ProcessInfo processInfoRes : processesinfoList) {
446                 ProcessInfo processInfo = new ProcessInfo();
447                 processInfo.setProcessId(processInfoRes.getPid());
448                 processInfo.setProcessName(processInfoRes.getName());
449                 process.add(processInfo);
450             }
451         }
452         return process;
453     }
454 
455     /**
456      * Get capabilities
457      *
458      * @param deviceIp deviceIp
459      * @param port port number
460      * @return ProfilerServiceTypes.GetCapabilitiesResponse
461      */
getCapabilities(String deviceIp, int port)462     public ProfilerServiceTypes.GetCapabilitiesResponse getCapabilities(String deviceIp, int port) {
463         if (ProfilerLogManager.isInfoEnabled()) {
464             LOGGER.info("getCapabilities");
465         }
466         if (port <= 0 || port > LayoutConstants.PORT) {
467             return null;
468         }
469         return getCapabilities(deviceIp, port, 0);
470     }
471 
472     /**
473      * Get capabilities
474      *
475      * @param deviceIp deviceIp
476      * @param port port number
477      * @param retryCount retry Count
478      * @return ProfilerServiceTypes.GetCapabilitiesResponse
479      */
getCapabilities(String deviceIp, int port, int retryCount)480     private ProfilerServiceTypes.GetCapabilitiesResponse getCapabilities(String deviceIp, int port, int retryCount) {
481         if (ProfilerLogManager.isInfoEnabled()) {
482             LOGGER.info("getCapabilities");
483         }
484         int counts = retryCount + 1;
485         ProfilerServiceTypes.GetCapabilitiesResponse response;
486         ProfilerClient client = getProfilerClient(deviceIp, port);
487         try {
488             response = client.getCapabilities(
489                 ProfilerServiceTypes.GetCapabilitiesRequest.newBuilder().setRequestId(CommonUtil.getRequestId())
490                     .build());
491         } catch (StatusRuntimeException exception) {
492             handleGrpcInterface(exception, port, client);
493             if (ProfilerLogManager.isErrorEnabled()) {
494                 LOGGER.info("exception Error {}", exception.getMessage());
495             }
496             if (counts > RETRY_COUNT) {
497                 return ProfilerServiceTypes.GetCapabilitiesResponse.newBuilder().build();
498             }
499             return getCapabilities(deviceIp, port, counts);
500         }
501         return response;
502     }
503 
504     /**
505      * keepSession
506      *
507      * @param deviceIp deviceIp
508      * @param port port number
509      * @param sessionId sessionId
510      * @return ProfilerServiceTypes.GetCapabilitiesResponse
511      * @throws StatusRuntimeException StatusRuntimeException
512      */
keepSession(String deviceIp, int port, int sessionId)513     public ProfilerServiceTypes.KeepSessionResponse keepSession(String deviceIp, int port, int sessionId)
514         throws StatusRuntimeException {
515         if (ProfilerLogManager.isInfoEnabled()) {
516             LOGGER.info("keepSession");
517         }
518         if (port <= 0 || port > LayoutConstants.PORT) {
519             return null;
520         }
521         return keepSession(deviceIp, port, sessionId, 0);
522     }
523 
keepSession(String deviceIp, int port, int sessionId, int retryCount)524     private ProfilerServiceTypes.KeepSessionResponse keepSession(String deviceIp, int port, int sessionId,
525         int retryCount) throws StatusRuntimeException {
526         if (ProfilerLogManager.isInfoEnabled()) {
527             LOGGER.info("keepSession");
528         }
529         int counts = retryCount + 1;
530         ProfilerClient client = getProfilerClient(deviceIp, port);
531         ProfilerServiceTypes.KeepSessionResponse response;
532         try {
533             response = Objects.requireNonNull(client).keepSession(
534                 ProfilerServiceTypes.KeepSessionRequest.newBuilder().setRequestId(CommonUtil.getRequestId())
535                     .setSessionId(sessionId).build());
536         } catch (StatusRuntimeException exception) {
537             handleGrpcInterface(exception, port, client);
538             if (counts > 2 || (exception.getStatus() == INTERNAL && exception.getMessage()
539                 .contains("session_id invalid"))) {
540                 if (ProfilerLogManager.isErrorEnabled()) {
541                     LOGGER.error("exception Error ", exception);
542                 }
543                 throw exception;
544             }
545             return keepSession(deviceIp, port, sessionId, counts);
546         }
547         return response;
548     }
549 
handleGrpcInterface(StatusRuntimeException statusRuntimeException, int port, ProfilerClient client)550     private void handleGrpcInterface(StatusRuntimeException statusRuntimeException, int port, ProfilerClient client) {
551         if (statusRuntimeException.getStatus() != Status.OK && statusRuntimeException.getStatus() != INTERNAL
552             && statusRuntimeException.getStatus() != DEADLINE_EXCEEDED) {
553             if (ProfilerLogManager.isErrorEnabled()) {
554                 LOGGER.error("statusRuntimeException", statusRuntimeException);
555             }
556             ManagedChannel channel = client.getChannel();
557             if (channel.isShutdown() || channel.isTerminated() || statusRuntimeException.getStatus() == UNAVAILABLE) {
558                 destroyProfiler("", port);
559             }
560         }
561     }
562 }
563