1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "calibrationfile.h"
18 
19 #include "file.h"
20 #include "log.h"
21 
22 namespace android {
23 
24 constexpr char kCalibrationFile[] = "/persist/sensorcal.json";
25 
26 std::shared_ptr<CalibrationFile> CalibrationFile::instance_;
27 
Instance()28 std::shared_ptr<CalibrationFile> CalibrationFile::Instance() {
29     if (!CalibrationFile::instance_) {
30         auto inst = std::shared_ptr<CalibrationFile>(new CalibrationFile());
31         if (inst->Initialize()) {
32             CalibrationFile::instance_ = inst;
33         }
34     }
35 
36     return CalibrationFile::instance_;
37 }
38 
Initialize()39 bool CalibrationFile::Initialize() {
40     file_ = std::unique_ptr<File>(new File(kCalibrationFile, "rw"));
41 
42     status_t err = file_->initCheck();
43     if (err != OK) {
44         LOGE("Couldn't open calibration file: %d (%s)", err, strerror(-err));
45         return false;
46     }
47 
48     off64_t file_size = file_->seekTo(0, SEEK_END);
49     if (file_size > 0) {
50         auto file_data = std::vector<char>(file_size);
51         file_->seekTo(0, SEEK_SET);
52         ssize_t bytes_read = file_->read(file_data.data(), file_size);
53         if (bytes_read != file_size) {
54             LOGE("Read of configuration file returned %zd, expected %" PRIu64,
55                  bytes_read, file_size);
56             return false;
57         }
58 
59         sp<JSONCompound> json = JSONCompound::Parse(file_data.data(), file_size);
60         if (json == nullptr || !json->isObject()) {
61             // If there's an existing file and we couldn't parse it, or it
62             // parsed to something unexpected, then we don't want to wipe out
63             // the file - the user needs to decide what to do, e.g. they can
64             // manually edit to fix corruption, or delete it, etc.
65             LOGE("Couldn't parse sensor calibration file (requires manual "
66                  "resolution)");
67             return false;
68         } else {
69             json_root_ = reinterpret_cast<JSONObject*>(json.get());
70             LOGD("Parsed JSONObject from file:\n%s",
71                  json_root_->toString().c_str());
72         }
73     }
74 
75     // No errors, but there was no existing calibration data so construct a new
76     // object
77     if (json_root_ == nullptr) {
78         json_root_ = new JSONObject();
79     }
80 
81     return true;
82 }
83 
GetJSONObject() const84 const sp<JSONObject> CalibrationFile::GetJSONObject() const {
85     return json_root_;
86 }
87 
SetSingleAxis(const char * key,int32_t value)88 bool CalibrationFile::SetSingleAxis(const char *key, int32_t value) {
89     json_root_->setInt32(key, value);
90     return true;
91 }
92 
SetSingleAxis(const char * key,float value)93 bool CalibrationFile::SetSingleAxis(const char *key, float value) {
94     json_root_->setFloat(key, value);
95     return true;
96 }
97 
SetTripleAxis(const char * key,int32_t x,int32_t y,int32_t z)98 bool CalibrationFile::SetTripleAxis(const char *key, int32_t x, int32_t y,
99         int32_t z) {
100     sp<JSONArray> json_array = new JSONArray();
101     json_array->addInt32(x);
102     json_array->addInt32(y);
103     json_array->addInt32(z);
104     json_root_->setArray(key, json_array);
105     return true;
106 }
107 
SetFourAxis(const char * key,int32_t x,int32_t y,int32_t z,int32_t w)108 bool CalibrationFile::SetFourAxis(const char *key, int32_t x, int32_t y,
109         int32_t z, int32_t w) {
110     sp<JSONArray> json_array = new JSONArray();
111     json_array->addInt32(x);
112     json_array->addInt32(y);
113     json_array->addInt32(z);
114     json_array->addInt32(w);
115     json_root_->setArray(key, json_array);
116     return true;
117 }
118 
Save()119 bool CalibrationFile::Save() {
120     AString json_str = json_root_->toString();
121     LOGD("Saving JSONObject to file (%zd bytes):\n%s", json_str.size(),
122          json_str.c_str());
123     file_->seekTo(0, SEEK_SET);
124     ssize_t bytes_written = file_->write(json_str.c_str(), json_str.size());
125     if (bytes_written < 0 || static_cast<size_t>(bytes_written) != json_str.size()) {
126         LOGE("Write returned %zd, expected %zu", bytes_written, json_str.size());
127         return false;
128     }
129     return true;
130 }
131 
132 }  // namespace android
133