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#include <iostream>
16#include <sstream>
17#include <thread>
18#include <unistd.h>
19#include <fcntl.h>
20#include <sys/stat.h>
21#include "include/sp_utils.h"
22#include "include/Capture.h"
23#include "include/sp_log.h"
24#include "display_manager.h"
25#include "wm_common.h"
26#include "png.h"
27#include <filesystem>
28#include "include/common.h"
29namespace OHOS {
30namespace SmartPerf {
31using namespace OHOS::Media;
32using namespace OHOS::Rosen;
33std::map<std::string, std::string> Capture::ItemData()
34{
35    std::map<std::string, std::string> result;
36    const int two = 2;
37    const int modResult = callNum % two;
38    callNum++;
39    curTime = GetCurTimes();
40    std::string screenCapPath = "data/local/tmp/capture/screenCap_" + std::to_string(curTime);
41    std::string path = "NA";
42    if (isSocketMessage) {
43        if (modResult == 0) {
44            path = screenCapPath + ".jpeg";
45            result["capture"] = path;
46            TriggerGetCatchSocket(curTime);
47            isSocketMessage = false;
48        }
49    } else {
50        if (modResult == 1) {
51            path = screenCapPath + ".png";
52            result["capture"] = path;
53            TriggerGetCatch();
54        }
55    }
56    result["capture"] = path;
57
58    LOGI("Capture::ItemData map size(%u)", result.size());
59    return result;
60}
61
62void Capture::SocketMessage()
63{
64    isSocketMessage = true;
65}
66
67long long Capture::GetCurTimes()
68{
69    return SPUtils::GetCurTime();
70}
71void Capture::ThreadGetCatch()
72{
73    const std::string captureDir = "/data/local/tmp/capture";
74    const std::string savePath = captureDir + "/screenCap_" + std::to_string(curTime) + ".png";
75    std::string cmdResult;
76    if (!SPUtils::FileAccess(captureDir)) {
77        std::string capturePath = CMD_COMMAND_MAP.at(CmdCommand::CAPTURE_FILE);
78        if (!SPUtils::LoadCmd(capturePath, cmdResult)) {
79            LOGI("%s capture not be created!", captureDir.c_str());
80            return;
81        } else {
82            LOGI("%s created successfully!", captureDir.c_str());
83        }
84    };
85    std::ostringstream errorRecv;
86    auto fd = open(savePath.c_str(), O_RDWR | O_CREAT, 0666);
87    if (fd == -1) {
88        LOGI("Failed to open file: %s", savePath.c_str());
89    }
90    if (!TakeScreenCap(savePath)) {
91        LOGE("Screen Capture Failed!");
92    }
93    close(fd);
94}
95
96
97void Capture::ThreadGetCatchSocket(const std::string &captureTime) const
98{
99    std::string captureDir = "/data/local/tmp/capture";
100    std::string savePath = captureDir + "/screenCap_" + captureTime + ".jpeg";
101    std::string cmdResult;
102    if (!SPUtils::FileAccess(captureDir)) {
103        std::string capturePath = CMD_COMMAND_MAP.at(CmdCommand::CAPTURE_FILE);
104        if (!SPUtils::LoadCmd(capturePath, cmdResult)) {
105            LOGI("%s capture not be created!", captureDir.c_str());
106            return;
107        } else {
108            LOGI("%s created successfully!", captureDir.c_str());
109        }
110    };
111
112    char realPath[PATH_MAX] = {0x00};
113    if (realpath(savePath.c_str(), realPath) == nullptr) {
114        std::cout << "" << std::endl;
115    }
116
117    auto fd = open(realPath, O_RDWR | O_CREAT, 0644);
118    if (fd == -1) {
119        LOGI("Failed to open file: %s", savePath.c_str());
120    }
121    std::string snapshot = CMD_COMMAND_MAP.at(CmdCommand::SNAPSHOT);
122    if (!SPUtils::LoadCmd(snapshot + savePath, cmdResult)) {
123        LOGI("snapshot_display command failed!");
124        close(fd);
125        return;
126    }
127    close(fd);
128}
129
130void Capture::TriggerGetCatch()
131{
132    auto tStart = std::thread([this]() {
133        this->ThreadGetCatch();
134    });
135    tStart.detach();
136}
137
138void Capture::TriggerGetCatchSocket(long long captureTime) const
139{
140    std::string curTimeStr = std::to_string(captureTime);
141    auto tStart = std::thread([this, curTimeStr]() {
142        this->ThreadGetCatchSocket(curTimeStr);
143    });
144    tStart.detach();
145}
146
147bool Capture::TakeScreenCap(const std::string &savePath) const
148{
149    Rosen::DisplayManager &displayMgr = Rosen::DisplayManager::GetInstance();
150    std::shared_ptr<Media::PixelMap> pixelMap = displayMgr.GetScreenshot(displayMgr.GetDefaultDisplayId());
151    static constexpr int bitmapDepth = 8;
152    if (pixelMap == nullptr) {
153        LOGE("Failed to get display pixelMap");
154        return false;
155    }
156    auto width = static_cast<uint32_t>(pixelMap->GetWidth());
157    auto height = static_cast<uint32_t>(pixelMap->GetHeight());
158    auto data = pixelMap->GetPixels();
159    auto stride = static_cast<uint32_t>(pixelMap->GetRowBytes());
160    png_structp pngStruct = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
161    if (pngStruct == nullptr) {
162        LOGE("png_create_write_struct nullptr!");
163        return false;
164    }
165    png_infop pngInfo = png_create_info_struct(pngStruct);
166    if (pngInfo == nullptr) {
167        LOGE("png_create_info_struct error nullptr!");
168        png_destroy_write_struct(&pngStruct, nullptr);
169        return false;
170    }
171    char realPath[PATH_MAX] = {0x00};
172    if (realpath(savePath.c_str(), realPath) == nullptr) {
173        std::cout << "" << std::endl;
174    }
175    FILE *fp = fopen(realPath, "wb");
176    if (fp == nullptr) {
177        LOGE("open file error!");
178        png_destroy_write_struct(&pngStruct, &pngInfo);
179        return false;
180    }
181    png_init_io(pngStruct, fp);
182    png_set_IHDR(pngStruct, pngInfo, width, height, bitmapDepth, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE,
183        PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
184    png_set_packing(pngStruct);         // set packing info
185    png_write_info(pngStruct, pngInfo); // write to header
186    for (uint32_t i = 0; i < height; i++) {
187        png_write_row(pngStruct, data + (i * stride));
188    }
189    png_write_end(pngStruct, pngInfo);
190    // free
191    png_destroy_write_struct(&pngStruct, &pngInfo);
192    (void)fclose(fp);
193    return true;
194}
195}
196}
197