RDK Documentation (Open Sourced RDK Components)
pwrMgrHelper.cpp
1 /*
2  * If not stated otherwise in this file or this component's Licenses.txt file the
3  * following copyright and licenses apply:
4  *
5  * Copyright 2016 RDK Management
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18 */
19 
20 #include <stdio.h>
21 #include "pwrlogger.h"
22 
23 #ifdef FTUE_CHECK_ENABLED
24 #include <string.h>
25 #include <fcntl.h>
26 #include <unistd.h>
27 #include <thread>
28 #include <string>
29 //#include <iconv.h>
30 #include <sqlite3.h>
31 #include <fstream>
32 #include <glib.h>
33 
34 static const char *ftue_flag_file = "/opt/persistent/ftue_complete.flag";
35 #endif
36 
37 #ifdef FTUE_CHECK_ENABLED
38 #if 0
39 static bool convert_text_encoding(char * input, std::string &output, size_t input_size)
40 {
41  bool ret = true;
42  iconv_t conv = iconv_open("UTF-8", "UTF-16LE");
43  if((size_t)-1 == (size_t)conv)
44  {
45  LOG("%s: there was an error.\n", __func__);
46  return false;
47  }
48 
49  char output_buffer[1024] = {0};
50  char * output_ptr = &output_buffer[0];
51  size_t out_bytes_left = sizeof(output_buffer);
52  size_t result = iconv(conv, &input, &input_size, &output_ptr, &out_bytes_left);
53  if((size_t)-1 == result)
54  {
55  LOG("%s: conversion failed.\n", __func__);
56  ret = false;
57  }
58 
59  iconv_close(conv);
60  output = output_buffer;
61  return true;
62 
63 }
64 #endif
65 
66 static bool convert_text_encoding2(const char *input, std::string &output, size_t input_length) //Caller must free output if successful
67 {
68  /*
69  This is a limited convertor to translate UTF-16 to ASCII. All non-ASCII characters
70  will be skipped in the conversion.
71  */
72  static const unsigned int MAX_BUFFER_SIZE = 1024;
73  bool ret = false;
74 
75  if (0 != (input_length % 2))
76  {
77  LOG("%s: Input buffer length is not a multiple of 2. This cannot be UTF-16.\n", __func__);
78  return ret;
79  }
80  //Allocate enough memory to hold convered output.
81  size_t output_length = input_length / 2;
82  if (output_length > MAX_BUFFER_SIZE)
83  {
84  //Incoming buffer is too big for our limits. Truncate processing at max supported size.
85  output_length = MAX_BUFFER_SIZE;
86  input_length = output_length * 2;
87  }
88 
89  char *output_buffer = static_cast<char *>(malloc(output_length + 1)); //extra byte for string terminator
90  if (nullptr == output_buffer)
91  {
92  LOG("%s: Failed to allocate memory.\n", __func__);
93  return ret;
94  }
95  output_buffer[output_length] = 0; //String terminator.
96 
97  for (int i = 0, j = 0; i < input_length; i += 2)
98  {
99  char ch = input[i];
100  if ((0 == input[i + 1]) && (0x20 <= ch) && (0x7e >= ch)) //Verifies that the UTF-16 character is within ASCII range.
101  output_buffer[j++] = ch; //Assuming endianness ab 00 cd 00
102  }
103  output = output_buffer;
104  free(output_buffer);
105  return true;
106 }
107 
108 static int get_last_station(const std::string &input)
109 {
110  const char *search_pattern = R"(lastStation":)";
111  int ret = -1;
112  std::size_t start = input.find(search_pattern);
113  if (std::string::npos != start)
114  {
115  start += strlen(search_pattern);
116  std::size_t stop = input.find(",", start);
117  if (std::string::npos != stop)
118  {
119  std::string station_number_text = input.substr(start, (stop - start));
120  try
121  {
122  ret = std::stoi(station_number_text);
123  }
124  catch (...)
125  {
126  LOG("%s: Exception when converting to number.\n", __func__);
127  ret = -1;
128  }
129  }
130  else
131  LOG("%s: Could not locate end of string\n", __func__);
132  }
133  else
134  LOG("%s: Search pattern <%s> not found\n", __func__, search_pattern);
135  return ret;
136 }
137 
138 static bool set_ftue_status_from_ra_store()
139 {
140  const char *resident_app_local_storage = "/opt/persistent/rdkservices/ResidentApp/wpe/local-storage/http_platco.thor.local_50050.localstorage";
141  sqlite3 *db;
142  const char *query = R"(select * from ItemTable where key = "ftue";)";
143  sqlite3_stmt *prepared_statement = nullptr;
144  static const int FTUE_DONE_STATION_NUMBER = 14;
145  bool retStatus = false;
146 
147  LOG("%s: start.\n", __func__);
148  int ret = sqlite3_open_v2(resident_app_local_storage, &db, SQLITE_OPEN_READWRITE, NULL);
149 
150  if (0 != ret)
151  {
152  LOG("%s: Can't open database: %s\n", __func__, sqlite3_errmsg(db));
153  goto clean_up_db;
154  }
155  ret = sqlite3_prepare_v2(db, query, -1, &prepared_statement, nullptr);
156  if (SQLITE_OK != ret)
157  {
158  LOG("%s: Prepare failed: %s\n", __func__, sqlite3_errmsg(db));
159  goto clean_up_db;
160  }
161 
162  do
163  {
164  ret = sqlite3_step(prepared_statement);
165  switch (ret)
166  {
167  case SQLITE_ROW:
168  {
169  //The data we need is in JSON form (blob) in the second column. Read as text for convenience.
170  const char *second_column = static_cast<const char *>(sqlite3_column_blob(prepared_statement, 1));
171  int data_size = sqlite3_column_bytes(prepared_statement, 1);
172 
173  std::string converted_text;
174  if (true == convert_text_encoding2(second_column, converted_text, data_size))
175  {
176  int station = get_last_station(converted_text);
177  LOG("%s: station number %d\n", __func__, station);
178  if (FTUE_DONE_STATION_NUMBER == station)
179  {
180  LOG("%s: detected FTUE complete.\n", __func__);
181  std::ofstream flag(ftue_flag_file);
182  if (false == flag.is_open())
183  LOG("%s: Error creating file %s\n", __func__, ftue_flag_file);
184  retStatus = true;
185  }
186  ret = SQLITE_DONE; //To break out of do-while loop.
187  }
188  break;
189  }
190 
191  case SQLITE_DONE:
192  break;
193 
194  default:
195  LOG("Step returned unhandled error %d\n", ret);
196  }
197  } while (SQLITE_ROW == ret);
198 
199  sqlite3_finalize(prepared_statement);
200 clean_up_db:
201  sqlite3_close(db);
202  return retStatus;
203  LOG("%s: exit.\n", __func__);
204 }
205 #endif // FTUE_CHECK_ENABLED
206 
207 bool isTVOperatingInFactory()
208 {
209 #ifdef FTUE_CHECK_ENABLED
210  bool ret = true;
211  if (0 == access(ftue_flag_file, F_OK))
212  ret = false;
213  else
214  {
215  /*FTUE was not completed according to last known data. Implications are two-fold
216  1. It's safer to assume that we're in factory right now.
217  2. Launch a deferred job to check FTUE status and touch the flag if complete.
218  */
219  static const auto CALLBACK_DELAY_SECONDS = 3;
220  auto deferred_callback = [](gpointer data)
221  {
222  bool retFtueStatus = set_ftue_status_from_ra_store();
223  LOG("%s: %s\n", __func__, (true == retFtueStatus ? "true" : "false"));
224  return (retFtueStatus)?G_SOURCE_REMOVE:G_SOURCE_CONTINUE;
225  };
226  g_timeout_add_seconds(CALLBACK_DELAY_SECONDS, deferred_callback, nullptr);
227  }
228  LOG("%s: %s\n", __func__, (true == ret ? "true" : "false"));
229  return ret;
230 #else
231  LOG("%s: Warning! This is an unhandled control flow.\n", __func__);
232  return false; //Dummy
233 #endif
234 }