OLD | NEW |
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
| 5 #include <pthread.h> |
| 6 #include <unistd.h> |
| 7 |
| 8 #include <sstream> |
| 9 #include <string> |
| 10 |
| 11 #include "native_client/src/untrusted/irt/irt.h" |
| 12 |
| 13 #include "ppapi/cpp/completion_callback.h" |
5 #include "ppapi/cpp/instance.h" | 14 #include "ppapi/cpp/instance.h" |
6 #include "ppapi/cpp/module.h" | 15 #include "ppapi/cpp/module.h" |
7 #include "ppapi/cpp/var.h" | 16 #include "ppapi/cpp/var.h" |
8 | 17 |
9 namespace { | 18 namespace { |
10 | 19 |
| 20 std::string g_last_error; |
| 21 pp::Instance* g_instance = NULL; |
| 22 |
| 23 // This should be the same as FileDescriptorSet::kMaxDescriptorsPerMessage in |
| 24 // ipc/file_descriptor_set_posix.h. |
| 25 // TODO(yusukes): Once all the NaCl toolchains support C++11, Add |
| 26 // #include "ipc/file_descriptor_set_posix.h" and remove the constant. |
| 27 const size_t kMaxDescriptorsPerMessage = 7; |
| 28 |
| 29 // Returns true if the resource file whose name is |key| exists and its content |
| 30 // matches |content|. |
| 31 bool LoadManifestInternal(nacl_irt_resource_open* nacl_irt_resource_open, |
| 32 const std::string& key, |
| 33 const std::string& content) { |
| 34 int desc; |
| 35 int error; |
| 36 error = nacl_irt_resource_open->open_resource(key.c_str(), &desc); |
| 37 if (0 != error) { |
| 38 g_last_error = "Can't open file " + key; |
| 39 return false; |
| 40 } |
| 41 |
| 42 std::string str; |
| 43 |
| 44 char buffer[4096]; |
| 45 int len; |
| 46 while ((len = read(desc, buffer, sizeof(buffer) - 1)) > 0) { |
| 47 // Null terminate. |
| 48 buffer[len] = '\0'; |
| 49 str += buffer; |
| 50 } |
| 51 if (close(desc)) { |
| 52 g_last_error = "Close failed: file=" + key; |
| 53 return false; |
| 54 } |
| 55 |
| 56 if (str != content) { |
| 57 g_last_error = "Wrong file content: file=" + key + ", expected=" + content + |
| 58 ", actual=" + str; |
| 59 return false; |
| 60 } |
| 61 |
| 62 return true; |
| 63 } |
| 64 |
| 65 // Tests if open_resource works in a packaged app. This test is similar to |
| 66 // NaClBrowserTest*.IrtManifestFile, but unlike the NaCl test, this one tests |
| 67 // the "fast path" in DownloadNexe() in ppb_nacl_private_impl.cc which opens |
| 68 // resource files without using URLLoader. |
| 69 void LoadManifest() { |
| 70 if (pthread_detach(pthread_self())) { |
| 71 g_last_error = "pthread_detach failed"; |
| 72 return; |
| 73 } |
| 74 |
| 75 struct nacl_irt_resource_open nacl_irt_resource_open; |
| 76 if (sizeof(nacl_irt_resource_open) != |
| 77 nacl_interface_query(NACL_IRT_RESOURCE_OPEN_v0_1, |
| 78 &nacl_irt_resource_open, |
| 79 sizeof(nacl_irt_resource_open))) { |
| 80 g_last_error = "NACL_IRT_RESOURCE_OPEN_v0_1 not found"; |
| 81 return; |
| 82 } |
| 83 |
| 84 for (size_t i = 0; i <= kMaxDescriptorsPerMessage; ++i) { |
| 85 std::stringstream key; |
| 86 key << "test_file" << i; |
| 87 std::string content = "Example contents for open_resource test" + |
| 88 std::string(i % 2 ? "2" : ""); |
| 89 if (!LoadManifestInternal(&nacl_irt_resource_open, key.str(), content)) |
| 90 break; |
| 91 // Open the same resource file again to make sure each file descriptor |
| 92 // returned from open_resource has its own file offset. |
| 93 if (!LoadManifestInternal(&nacl_irt_resource_open, key.str(), content)) |
| 94 break; |
| 95 } |
| 96 } |
| 97 |
| 98 void PostReply(void* user_data, int32_t status) { |
| 99 if (!g_last_error.empty()) |
| 100 g_instance->PostMessage(g_last_error.c_str()); |
| 101 else |
| 102 g_instance->PostMessage("Test passed"); |
| 103 } |
| 104 |
| 105 void* RunTestsOnBackgroundThread(void* thread_id) { |
| 106 LoadManifest(); |
| 107 pp::Module::Get()->core()->CallOnMainThread( |
| 108 0, pp::CompletionCallback(&PostReply, NULL)); |
| 109 return NULL; |
| 110 } |
| 111 |
11 class MyInstance : public pp::Instance { | 112 class MyInstance : public pp::Instance { |
12 public: | 113 public: |
13 explicit MyInstance(PP_Instance instance) : pp::Instance(instance) { } | 114 explicit MyInstance(PP_Instance instance) : pp::Instance(instance) { |
| 115 g_instance = this; |
| 116 } |
14 virtual ~MyInstance() { } | 117 virtual ~MyInstance() { } |
15 | 118 |
16 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) { | 119 virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]) { |
17 PostMessage("hello"); | 120 pthread_t thread; |
| 121 // irt_open_resource() isn't allowed to be called on the main thread once |
| 122 // Pepper starts, so the test must happen on a background thread. |
| 123 if (pthread_create(&thread, NULL, &RunTestsOnBackgroundThread, NULL)) { |
| 124 g_last_error = "pthread_create failed"; |
| 125 PostReply(NULL, 0); |
| 126 } |
18 return true; | 127 return true; |
19 } | 128 } |
20 }; | 129 }; |
21 | 130 |
22 class MyModule : public pp::Module { | 131 class MyModule : public pp::Module { |
23 public: | 132 public: |
24 MyModule() : pp::Module() { } | 133 MyModule() : pp::Module() { } |
25 virtual ~MyModule() { } | 134 virtual ~MyModule() { } |
26 | 135 |
27 virtual pp::Instance* CreateInstance(PP_Instance instance) { | 136 virtual pp::Instance* CreateInstance(PP_Instance instance) { |
28 return new MyInstance(instance); | 137 return new MyInstance(instance); |
29 } | 138 } |
30 }; | 139 }; |
31 | 140 |
32 } // namespace | 141 } // namespace |
33 | 142 |
34 namespace pp { | 143 namespace pp { |
35 | 144 |
36 Module* CreateModule() { | 145 Module* CreateModule() { |
37 return new MyModule(); | 146 return new MyModule(); |
38 } | 147 } |
39 | 148 |
40 } // namespace pp | 149 } // namespace pp |
OLD | NEW |