RDK Documentation (Open Sourced RDK Components)
dsMgrHelper.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 "dsMgrInternal.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  INT_DEBUG("%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  INT_DEBUG("%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  INT_DEBUG("%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  INT_DEBUG("%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  INT_DEBUG("%s: Exception when converting to number.\n", __func__);
127  ret = -1;
128  }
129  }
130  else
131  INT_DEBUG("%s: Could not locate end of string\n", __func__);
132  }
133  else
134  INT_DEBUG("%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  INT_DEBUG("%s: start.\n", __func__);
148  int ret = sqlite3_open_v2(resident_app_local_storage, &db, SQLITE_OPEN_READWRITE, NULL);
149  if (0 != ret)
150  {
151  INT_DEBUG("%s: Can't open database: %s\n", __func__, sqlite3_errmsg(db));
152  goto clean_up_db;
153  }
154  ret = sqlite3_prepare_v2(db, query, -1, &prepared_statement, nullptr);
155  if (SQLITE_OK != ret)
156  {
157  INT_DEBUG("%s: Prepare failed: %s\n", __func__, sqlite3_errmsg(db));
158  goto clean_up_db;
159  }
160 
161  do
162  {
163  ret = sqlite3_step(prepared_statement);
164  switch (ret)
165  {
166  case SQLITE_ROW:
167  {
168  //The data we need is in JSON form (blob) in the second column. Read as text for convenience.
169  const char *second_column = static_cast<const char *>(sqlite3_column_blob(prepared_statement, 1));
170  int data_size = sqlite3_column_bytes(prepared_statement, 1);
171 
172  std::string converted_text;
173  if (true == convert_text_encoding2(second_column, converted_text, data_size))
174  {
175  int station = get_last_station(converted_text);
176  INT_DEBUG("%s: station number %d\n", __func__, station);
177  if (FTUE_DONE_STATION_NUMBER == station)
178  {
179  INT_DEBUG("%s: detected FTUE complete.\n", __func__);
180  std::ofstream flag(ftue_flag_file);
181  if (false == flag.is_open())
182  INT_DEBUG("%s: Error creating file %s\n", __func__, ftue_flag_file);
183  retStatus = true;
184  }
185  ret = SQLITE_DONE; //To break out of do-while loop.
186  }
187  break;
188  }
189 
190  case SQLITE_DONE:
191  break;
192 
193  default:
194  INT_DEBUG("Step returned unhandled error %d\n", ret);
195  }
196  } while (SQLITE_ROW == ret);
197 
198  sqlite3_finalize(prepared_statement);
199 clean_up_db:
200  sqlite3_close(db);
201  return retStatus;
202  INT_DEBUG("%s: exit.\n", __func__);
203 }
204 #endif // FTUE_CHECK_ENABLED
205 
206 bool isTVOperatingInFactory()
207 {
208 #ifdef FTUE_CHECK_ENABLED
209  bool ret = true;
210  if (0 == access(ftue_flag_file, F_OK))
211  ret = false;
212  else
213  {
214  /*FTUE was not completed according to last known data. Implications are two-fold
215  1. It's safer to assume that we're in factory right now.
216  2. Launch a deferred job to check FTUE status and touch the flag if complete.
217  */
218  static const auto CALLBACK_DELAY_SECONDS = 3;
219  auto deferred_callback = [](gpointer data)
220  {
221  bool retFtueStatus = set_ftue_status_from_ra_store();
222  INT_DEBUG("%s: %s\n", __func__, (true == retFtueStatus ? "true" : "false"));
223  return (retFtueStatus)?G_SOURCE_REMOVE:G_SOURCE_CONTINUE;
224  };
225  g_timeout_add_seconds(CALLBACK_DELAY_SECONDS, deferred_callback, nullptr);
226  }
227  INT_DEBUG("%s: %s\n", __func__, (true == ret ? "true" : "false"));
228  return ret;
229 #else
230  INT_DEBUG("%s: Warning! This is an unhandled control flow.\n", __func__);
231  return false; //Dummy
232 #endif
233 }
dsMgrInternal.h