summaryrefslogtreecommitdiffstats
path: root/chromecast/app/cast_main_delegate.cc
blob: 7ae36efa20a84311f44f7c04d5e0df8a509b98cf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromecast/app/cast_main_delegate.h"

#include <algorithm>
#include <string>
#include <vector>

#include "base/command_line.h"
#include "base/cpu.h"
#include "base/files/file.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_util.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/posix/global_descriptors.h"
#include "build/build_config.h"
#include "chromecast/base/cast_paths.h"
#include "chromecast/browser/cast_content_browser_client.h"
#include "chromecast/common/cast_resource_delegate.h"
#include "chromecast/common/global_descriptors.h"
#include "chromecast/renderer/cast_content_renderer_client.h"
#include "chromecast/utility/cast_content_utility_client.h"
#include "components/crash/content/app/crash_reporter_client.h"
#include "content/public/browser/browser_main_runner.h"
#include "content/public/common/content_switches.h"
#include "ui/base/resource/resource_bundle.h"

#if defined(OS_ANDROID)
#include "base/android/apk_assets.h"
#include "chromecast/app/android/cast_crash_reporter_client_android.h"
#include "chromecast/app/android/crash_handler.h"
#else
#include "chromecast/app/linux/cast_crash_reporter_client.h"
#endif  // defined(OS_ANDROID)

namespace {

#if !defined(OS_ANDROID)
base::LazyInstance<chromecast::CastCrashReporterClient>::Leaky
    g_crash_reporter_client = LAZY_INSTANCE_INITIALIZER;
#endif  // !defined(OS_ANDROID)

#if defined(OS_ANDROID)
const int kMaxCrashFiles = 10;
#endif  // defined(OS_ANDROID)

}  // namespace

namespace chromecast {
namespace shell {

CastMainDelegate::CastMainDelegate() {
}

CastMainDelegate::~CastMainDelegate() {
}

bool CastMainDelegate::BasicStartupComplete(int* exit_code) {
  RegisterPathProvider();

  logging::LoggingSettings settings;
  settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG;
#if defined(OS_ANDROID)
  const base::CommandLine* command_line(base::CommandLine::ForCurrentProcess());
  std::string process_type =
      command_line->GetSwitchValueASCII(switches::kProcessType);
  // Browser process logs are recorded for attaching with crash dumps.
  if (process_type.empty()) {
    base::FilePath log_file;
    PathService::Get(FILE_CAST_ANDROID_LOG, &log_file);
    settings.logging_dest = logging::LOG_TO_ALL;
    settings.log_file = log_file.value().c_str();
    settings.delete_old = logging::DELETE_OLD_LOG_FILE;
  }
#endif  // defined(OS_ANDROID)
  logging::InitLogging(settings);
  // Time, process, and thread ID are available through logcat.
  logging::SetLogItems(true, true, false, false);

#if defined(OS_ANDROID)
  // Only delete the old crash dumps if the current process is the browser
  // process. Empty |process_type| signifies browser process.
  if (process_type.empty()) {
    // Get a listing of all of the crash dump files.
    base::FilePath crash_directory;
    if (CastCrashReporterClientAndroid::GetCrashDumpLocation(
            process_type, &crash_directory)) {
      base::FileEnumerator crash_directory_list(crash_directory, false,
                                                base::FileEnumerator::FILES);
      std::vector<base::FilePath> crash_files;
      for (base::FilePath file = crash_directory_list.Next(); !file.empty();
           file = crash_directory_list.Next()) {
        crash_files.push_back(file);
      }
      // Delete crash dumps except for the |kMaxCrashFiles| most recent ones.
      if (crash_files.size() > kMaxCrashFiles) {
        auto newest_first =
            [](const base::FilePath& l, const base::FilePath& r) -> bool {
              base::File::Info l_info, r_info;
              base::GetFileInfo(l, &l_info);
              base::GetFileInfo(r, &r_info);
              return l_info.last_modified > r_info.last_modified;
            };
        std::partial_sort(crash_files.begin(),
                          crash_files.begin() + kMaxCrashFiles,
                          crash_files.end(), newest_first);
        for (auto file = crash_files.begin() + kMaxCrashFiles;
             file != crash_files.end(); ++file) {
          base::DeleteFile(*file, false);
        }
      }
    }
  }
#endif  // defined(OS_ANDROID)

  content::SetContentClient(&content_client_);
  return false;
}

void CastMainDelegate::PreSandboxStartup() {
#if defined(ARCH_CPU_ARM_FAMILY) && (defined(OS_ANDROID) || defined(OS_LINUX))
  // Create an instance of the CPU class to parse /proc/cpuinfo and cache the
  // results. This data needs to be cached when file-reading is still allowed,
  // since base::CPU expects to be callable later, when file-reading is no
  // longer allowed.
  base::CPU cpu_info;
#endif

  const base::CommandLine* command_line(base::CommandLine::ForCurrentProcess());
  std::string process_type =
      command_line->GetSwitchValueASCII(switches::kProcessType);

#if defined(OS_ANDROID)
  base::FilePath log_file;
  PathService::Get(FILE_CAST_ANDROID_LOG, &log_file);
  chromecast::CrashHandler::Initialize(process_type, log_file);
#else
  crash_reporter::SetCrashReporterClient(g_crash_reporter_client.Pointer());

  if (process_type != switches::kZygoteProcess) {
    CastCrashReporterClient::InitCrashReporter(process_type);
  }
#endif  // defined(OS_ANDROID)

  InitializeResourceBundle();
}

int CastMainDelegate::RunProcess(
    const std::string& process_type,
    const content::MainFunctionParams& main_function_params) {
#if defined(OS_ANDROID)
  if (!process_type.empty())
    return -1;

  // Note: Android must handle running its own browser process.
  // See ChromeMainDelegateAndroid::RunProcess.
  browser_runner_.reset(content::BrowserMainRunner::Create());
  return browser_runner_->Initialize(main_function_params);
#else
  return -1;
#endif  // defined(OS_ANDROID)
}

#if !defined(OS_ANDROID)
void CastMainDelegate::ZygoteForked() {
  const base::CommandLine* command_line(base::CommandLine::ForCurrentProcess());
  std::string process_type =
      command_line->GetSwitchValueASCII(switches::kProcessType);
  CastCrashReporterClient::InitCrashReporter(process_type);
}
#endif  // !defined(OS_ANDROID)

void CastMainDelegate::InitializeResourceBundle() {
  base::FilePath pak_file;
  CHECK(PathService::Get(FILE_CAST_PAK, &pak_file));
#if defined(OS_ANDROID)
  // On Android, the renderer runs with a different UID and can never access
  // the file system. Use the file descriptor passed in at launch time.
  auto global_descriptors = base::GlobalDescriptors::GetInstance();
  int pak_fd = global_descriptors->MaybeGet(kAndroidPakDescriptor);
  base::MemoryMappedFile::Region pak_region;
  if (pak_fd >= 0) {
    pak_region = global_descriptors->GetRegion(kAndroidPakDescriptor);
    ui::ResourceBundle::InitSharedInstanceWithPakFileRegion(base::File(pak_fd),
                                                            pak_region);
    ui::ResourceBundle::GetSharedInstance().AddDataPackFromFileRegion(
        base::File(pak_fd), pak_region, ui::SCALE_FACTOR_100P);
    return;
  } else {
    pak_fd = base::android::OpenApkAsset("assets/cast_shell.pak", &pak_region);
    // Loaded from disk for browsertests.
    if (pak_fd < 0) {
      int flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
      pak_fd = base::File(pak_file, flags).TakePlatformFile();
      pak_region = base::MemoryMappedFile::Region::kWholeFile;
    }
    DCHECK_GE(pak_fd, 0);
    global_descriptors->Set(kAndroidPakDescriptor, pak_fd, pak_region);
  }
#endif  // defined(OS_ANDROID)

  resource_delegate_.reset(new CastResourceDelegate());
  // TODO(gunsch): Use LOAD_COMMON_RESOURCES once ResourceBundle no longer
  // hardcodes resource file names.
  ui::ResourceBundle::InitSharedInstanceWithLocale(
      "en-US", resource_delegate_.get(),
      ui::ResourceBundle::DO_NOT_LOAD_COMMON_RESOURCES);

#if defined(OS_ANDROID)
  ui::ResourceBundle::GetSharedInstance().AddDataPackFromFileRegion(
      base::File(pak_fd), pak_region, ui::SCALE_FACTOR_NONE);
#else
  ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
      pak_file, ui::SCALE_FACTOR_NONE);
#endif  // defined(OS_ANDROID)
}

content::ContentBrowserClient* CastMainDelegate::CreateContentBrowserClient() {
  browser_client_ = CastContentBrowserClient::Create();
  return browser_client_.get();
}

content::ContentRendererClient*
CastMainDelegate::CreateContentRendererClient() {
  renderer_client_ = CastContentRendererClient::Create();
  return renderer_client_.get();
}

content::ContentUtilityClient* CastMainDelegate::CreateContentUtilityClient() {
  utility_client_ = CastContentUtilityClient::Create();
  return utility_client_.get();
}

}  // namespace shell
}  // namespace chromecast