APPLINK-6593:
[profile/ivi/smartdevicelink.git] / src / appMain / main.cc
1 /**
2  * \file appMain.cc
3  * \brief SmartDeviceLink main application sources
4  * Copyright (c) 2013, Ford Motor Company
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * Redistributions of source code must retain the above copyright notice, this
11  * list of conditions and the following disclaimer.
12  *
13  * Redistributions in binary form must reproduce the above copyright notice,
14  * this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided with the
16  * distribution.
17  *
18  * Neither the name of the Ford Motor Company nor the names of its contributors
19  * may be used to endorse or promote products derived from this software
20  * without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
26  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  */
34
35 #include <sys/stat.h>
36 #include <signal.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <cstdio>
40 #include <cstdlib>
41 #include <vector>
42 #include <string>
43 #include <iostream>  // cpplint: Streams are highly discouraged.
44 #include <fstream>   // cpplint: Streams are highly discouraged.
45
46 // ----------------------------------------------------------------------------
47
48 #include "./life_cycle.h"
49
50 #include "utils/signals.h"
51 #include "config_profile/profile.h"
52
53 #if defined(EXTENDED_MEDIA_MODE)
54 #include <gst/gst.h>
55 #endif
56
57 #include "media_manager/media_manager_impl.h"
58 // ----------------------------------------------------------------------------
59 // Third-Party includes
60 #include "networking.h"  // cpplint: Include the directory when naming .h files
61
62 // ----------------------------------------------------------------------------
63
64 namespace {
65
66 const char kBrowser[] = "/usr/bin/chromium-browser";
67 const char kBrowserName[] = "chromium-browser";
68 const char kBrowserParams[] = "--auth-schemes=basic,digest,ntlm";
69 const char kLocalHostAddress[] = "127.0.0.1";
70 const char kApplicationVersion[] = "SDL_RB_3.3";
71
72 #ifdef __QNX__
73 bool Execute(std::string command, const char * const *) {
74   log4cxx::LoggerPtr logger = log4cxx::LoggerPtr(
75       log4cxx::Logger::getLogger("appMain"));
76   if (system(command.c_str()) == -1) {
77     LOG4CXX_INFO(logger, "Can't start HMI!");
78     return false;
79   }
80   return true;
81 }
82 #else
83 bool Execute(std::string file, const char * const * argv) {
84   log4cxx::LoggerPtr logger = log4cxx::LoggerPtr(
85       log4cxx::Logger::getLogger("appMain"));
86   // Create a child process.
87   pid_t pid_hmi = fork();
88
89   switch (pid_hmi) {
90     case -1: {  // Error
91       LOG4CXX_INFO(logger, "fork() failed!");
92       return false;
93     }
94     case 0: {  // Child process
95       int32_t fd_dev0 = open("/dev/null", O_RDWR, S_IWRITE);
96       if (0 > fd_dev0) {
97         LOG4CXX_WARN(logger, "Open dev0 failed!");
98         return false;
99       }
100       // close input/output file descriptors.
101       close(STDIN_FILENO);
102       close(STDOUT_FILENO);
103       close(STDERR_FILENO);
104
105       // move input/output to /dev/null.
106       dup2(fd_dev0, STDIN_FILENO);
107       dup2(fd_dev0, STDOUT_FILENO);
108       dup2(fd_dev0, STDERR_FILENO);
109
110       // Execute the program.
111       if (execvp(file.c_str(), const_cast<char* const *>(argv)) == -1) {
112         LOG4CXX_ERROR_WITH_ERRNO(logger, "execvp() failed! Can't start HMI!");
113         _exit(EXIT_FAILURE);
114       }
115
116       return true;
117     }
118     default: { /* Parent process */
119       LOG4CXX_INFO(logger, "Process created with pid " << pid_hmi);
120       return true;
121     }
122   }
123 }
124 #endif
125
126 #ifdef WEB_HMI
127 /**
128  * Initialize HTML based HMI.
129  * @return true if success otherwise false.
130  */
131 bool InitHmi() {
132 log4cxx::LoggerPtr logger = log4cxx::LoggerPtr(
133                               log4cxx::Logger::getLogger("appMain"));
134
135 struct stat sb;
136 if (stat("hmi_link", &sb) == -1) {
137   LOG4CXX_INFO(logger, "File with HMI link doesn't exist!");
138   return false;
139 }
140
141 std::ifstream file_str;
142 file_str.open("hmi_link");
143
144 if (!file_str.is_open()) {
145   LOG4CXX_INFO(logger, "File with HMI link was not opened!");
146   return false;
147 }
148
149 file_str.seekg(0, std::ios::end);
150 int32_t length = file_str.tellg();
151 file_str.seekg(0, std::ios::beg);
152
153 std::string hmi_link;
154 std::getline(file_str, hmi_link);
155
156
157 LOG4CXX_INFO(logger,
158              "Input string:" << hmi_link << " length = " << hmi_link.size());
159 file_str.close();
160
161 if (stat(hmi_link.c_str(), &sb) == -1) {
162   LOG4CXX_INFO(logger, "HMI index.html doesn't exist!");
163   return false;
164 }
165
166   std::string kBin = kBrowser;
167   const char* const kParams[4] = {kBrowserName, kBrowserParams,
168       hmi_link.c_str(), NULL};
169
170   return Execute(kBin, kParams);
171 }
172 #endif  // WEB_HMI
173
174 #ifdef QT_HMI
175 /**
176  * Initialize HTML based HMI.
177  * @return true if success otherwise false.
178  */
179 bool InitHmi() {
180   log4cxx::LoggerPtr logger = log4cxx::LoggerPtr(
181       log4cxx::Logger::getLogger("appMain"));
182   std::string kStartHmi = "./start_hmi.sh";
183   struct stat sb;
184   if (stat(kStartHmi.c_str(), &sb) == -1) {
185     LOG4CXX_INFO(logger, "HMI start script doesn't exist!");
186     return false;
187   }
188
189   return Execute(kStartHmi, NULL);
190 }
191 #endif  // QT_HMI
192
193 }
194
195 /**
196  * \brief Entry point of the program.
197  * \param argc number of argument
198  * \param argv array of arguments
199  * \return EXIT_SUCCESS or EXIT_FAILURE
200  */
201 int32_t main(int32_t argc, char** argv) {
202
203   // --------------------------------------------------------------------------
204   // Logger initialization
205
206   log4cxx::LoggerPtr logger = log4cxx::LoggerPtr(
207                                 log4cxx::Logger::getLogger("appMain"));
208   log4cxx::PropertyConfigurator::configure("log4cxx.properties");
209
210   threads::Thread::SetNameForId(threads::Thread::CurrentId(), "MainThread");
211
212   LOG4CXX_INFO(logger, "Application started!");
213   LOG4CXX_INFO(logger, "Application version " << kApplicationVersion);
214
215   // Initialize gstreamer. Needed to activate debug from the command line.
216 #if defined(EXTENDED_MEDIA_MODE)
217   gst_init(&argc, &argv);
218 #endif
219
220   // --------------------------------------------------------------------------
221   // Components initialization
222   if ((argc > 1)&&(0 != argv)) {
223       profile::Profile::instance()->config_file_name(argv[1]);
224   } else {
225       profile::Profile::instance()->config_file_name("smartDeviceLink.ini");
226   }
227
228   main_namespace::LifeCycle::instance()->StartComponents();
229
230   // --------------------------------------------------------------------------
231   // Third-Party components initialization.
232
233   if (!main_namespace::LifeCycle::instance()->InitMessageSystem()) {
234     main_namespace::LifeCycle::instance()->StopComponents();
235 // without this line log4cxx threads continue using some instances destroyed by exit()
236     log4cxx::Logger::getRootLogger()->closeNestedAppenders();
237     exit(EXIT_FAILURE);
238   }
239   LOG4CXX_INFO(logger, "InitMessageBroker successful");
240
241   if (profile::Profile::instance()->launch_hmi()) {
242     if (profile::Profile::instance()->server_address() ==
243         std::string(kLocalHostAddress)) {
244       LOG4CXX_INFO(logger, "Start HMI on localhost");
245
246 #ifndef NO_HMI
247       if (!InitHmi()) {
248         main_namespace::LifeCycle::instance()->StopComponents();
249 // without this line log4cxx threads continue using some instances destroyed by exit()
250         log4cxx::Logger::getRootLogger()->closeNestedAppenders();
251         exit(EXIT_FAILURE);
252       }
253       LOG4CXX_INFO(logger, "InitHmi successful");
254 #endif // #ifndef NO_HMI
255     }
256   }
257   // --------------------------------------------------------------------------
258
259   utils::SubscribeToTerminateSignal(
260     &main_namespace::LifeCycle::StopComponentsOnSignal);
261
262   pause();
263 }