Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(25)

Side by Side Diff: media/gpu/video_encode_accelerator_unittest.cc

Issue 2893953002: Revert of Remove ScopedVector from all other codes in media/ (Closed)
Patch Set: Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « media/gpu/jpeg_decode_accelerator_unittest.cc ('k') | media/midi/midi_device_android.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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 <inttypes.h> 5 #include <inttypes.h>
6 #include <stddef.h> 6 #include <stddef.h>
7 #include <stdint.h> 7 #include <stdint.h>
8 8
9 #include <algorithm> 9 #include <algorithm>
10 #include <memory> 10 #include <memory>
11 #include <queue> 11 #include <queue>
12 #include <string> 12 #include <string>
13 #include <utility> 13 #include <utility>
14 14
15 #include "base/at_exit.h" 15 #include "base/at_exit.h"
16 #include "base/bind.h" 16 #include "base/bind.h"
17 #include "base/bits.h" 17 #include "base/bits.h"
18 #include "base/command_line.h" 18 #include "base/command_line.h"
19 #include "base/files/file_util.h" 19 #include "base/files/file_util.h"
20 #include "base/macros.h" 20 #include "base/macros.h"
21 #include "base/memory/aligned_memory.h" 21 #include "base/memory/aligned_memory.h"
22 #include "base/memory/ptr_util.h"
23 #include "base/memory/ref_counted.h" 22 #include "base/memory/ref_counted.h"
23 #include "base/memory/scoped_vector.h"
24 #include "base/memory/weak_ptr.h" 24 #include "base/memory/weak_ptr.h"
25 #include "base/message_loop/message_loop.h" 25 #include "base/message_loop/message_loop.h"
26 #include "base/numerics/safe_conversions.h" 26 #include "base/numerics/safe_conversions.h"
27 #include "base/process/process_handle.h" 27 #include "base/process/process_handle.h"
28 #include "base/single_thread_task_runner.h" 28 #include "base/single_thread_task_runner.h"
29 #include "base/strings/string_number_conversions.h" 29 #include "base/strings/string_number_conversions.h"
30 #include "base/strings/string_split.h" 30 #include "base/strings/string_split.h"
31 #include "base/strings/stringprintf.h" 31 #include "base/strings/stringprintf.h"
32 #include "base/strings/utf_string_conversions.h" 32 #include "base/strings/utf_string_conversions.h"
33 #include "base/threading/thread.h" 33 #include "base/threading/thread.h"
(...skipping 339 matching lines...) Expand 10 before | Expand all | Expand 10 after
373 } 373 }
374 src_offset += static_cast<off_t>(visible_buffer_size); 374 src_offset += static_cast<off_t>(visible_buffer_size);
375 } 375 }
376 src.Close(); 376 src.Close();
377 377
378 LOG_ASSERT(test_stream->num_frames > 0UL); 378 LOG_ASSERT(test_stream->num_frames > 0UL);
379 } 379 }
380 380
381 // Parse |data| into its constituent parts, set the various output fields 381 // Parse |data| into its constituent parts, set the various output fields
382 // accordingly, read in video stream, and store them to |test_streams|. 382 // accordingly, read in video stream, and store them to |test_streams|.
383 static void ParseAndReadTestStreamData( 383 static void ParseAndReadTestStreamData(const base::FilePath::StringType& data,
384 const base::FilePath::StringType& data, 384 ScopedVector<TestStream>* test_streams) {
385 std::vector<std::unique_ptr<TestStream>>* test_streams) {
386 // Split the string to individual test stream data. 385 // Split the string to individual test stream data.
387 std::vector<base::FilePath::StringType> test_streams_data = 386 std::vector<base::FilePath::StringType> test_streams_data =
388 base::SplitString(data, base::FilePath::StringType(1, ';'), 387 base::SplitString(data, base::FilePath::StringType(1, ';'),
389 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); 388 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
390 LOG_ASSERT(test_streams_data.size() >= 1U) << data; 389 LOG_ASSERT(test_streams_data.size() >= 1U) << data;
391 390
392 // Parse each test stream data and read the input file. 391 // Parse each test stream data and read the input file.
393 for (size_t index = 0; index < test_streams_data.size(); ++index) { 392 for (size_t index = 0; index < test_streams_data.size(); ++index) {
394 std::vector<base::FilePath::StringType> fields = base::SplitString( 393 std::vector<base::FilePath::StringType> fields = base::SplitString(
395 test_streams_data[index], base::FilePath::StringType(1, ','), 394 test_streams_data[index], base::FilePath::StringType(1, ','),
396 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); 395 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
397 // Try using ":" as the seperator if "," isn't used. 396 // Try using ":" as the seperator if "," isn't used.
398 if (fields.size() == 1U) { 397 if (fields.size() == 1U) {
399 fields = base::SplitString(test_streams_data[index], 398 fields = base::SplitString(test_streams_data[index],
400 base::FilePath::StringType(1, ':'), 399 base::FilePath::StringType(1, ':'),
401 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); 400 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
402 } 401 }
403 LOG_ASSERT(fields.size() >= 4U) << data; 402 LOG_ASSERT(fields.size() >= 4U) << data;
404 LOG_ASSERT(fields.size() <= 9U) << data; 403 LOG_ASSERT(fields.size() <= 9U) << data;
405 auto test_stream = base::MakeUnique<TestStream>(); 404 TestStream* test_stream = new TestStream();
406 405
407 test_stream->in_filename = FilePathStringTypeToString(fields[0]); 406 test_stream->in_filename = FilePathStringTypeToString(fields[0]);
408 int width, height; 407 int width, height;
409 bool result = base::StringToInt(fields[1], &width); 408 bool result = base::StringToInt(fields[1], &width);
410 LOG_ASSERT(result); 409 LOG_ASSERT(result);
411 result = base::StringToInt(fields[2], &height); 410 result = base::StringToInt(fields[2], &height);
412 LOG_ASSERT(result); 411 LOG_ASSERT(result);
413 test_stream->visible_size = gfx::Size(width, height); 412 test_stream->visible_size = gfx::Size(width, height);
414 LOG_ASSERT(!test_stream->visible_size.IsEmpty()); 413 LOG_ASSERT(!test_stream->visible_size.IsEmpty());
415 int profile; 414 int profile;
(...skipping 16 matching lines...) Expand all
432 431
433 if (fields.size() >= 8 && !fields[7].empty()) { 432 if (fields.size() >= 8 && !fields[7].empty()) {
434 LOG_ASSERT(base::StringToUint( 433 LOG_ASSERT(base::StringToUint(
435 fields[7], &test_stream->requested_subsequent_bitrate)); 434 fields[7], &test_stream->requested_subsequent_bitrate));
436 } 435 }
437 436
438 if (fields.size() >= 9 && !fields[8].empty()) { 437 if (fields.size() >= 9 && !fields[8].empty()) {
439 LOG_ASSERT(base::StringToUint( 438 LOG_ASSERT(base::StringToUint(
440 fields[8], &test_stream->requested_subsequent_framerate)); 439 fields[8], &test_stream->requested_subsequent_framerate));
441 } 440 }
442 test_streams->push_back(std::move(test_stream)); 441 test_streams->push_back(test_stream);
443 } 442 }
444 } 443 }
445 444
446 static std::unique_ptr<VideoEncodeAccelerator> CreateFakeVEA() { 445 static std::unique_ptr<VideoEncodeAccelerator> CreateFakeVEA() {
447 std::unique_ptr<VideoEncodeAccelerator> encoder; 446 std::unique_ptr<VideoEncodeAccelerator> encoder;
448 if (g_fake_encoder) { 447 if (g_fake_encoder) {
449 encoder.reset(new FakeVideoEncodeAccelerator( 448 encoder.reset(new FakeVideoEncodeAccelerator(
450 scoped_refptr<base::SingleThreadTaskRunner>( 449 scoped_refptr<base::SingleThreadTaskRunner>(
451 base::ThreadTaskRunnerHandle::Get()))); 450 base::ThreadTaskRunnerHandle::Get())));
452 } 451 }
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
539 bool run_at_fps() const { return run_at_fps_; } 538 bool run_at_fps() const { return run_at_fps_; }
540 539
541 // Whether to measure encode latency. This is set by the command line switch 540 // Whether to measure encode latency. This is set by the command line switch
542 // "--measure_latency". 541 // "--measure_latency".
543 bool needs_encode_latency() const { return needs_encode_latency_; } 542 bool needs_encode_latency() const { return needs_encode_latency_; }
544 543
545 // Verify the encoder output of all testcases. This is set by the command line 544 // Verify the encoder output of all testcases. This is set by the command line
546 // switch "--verify_all_output". 545 // switch "--verify_all_output".
547 bool verify_all_output() const { return verify_all_output_; } 546 bool verify_all_output() const { return verify_all_output_; }
548 547
549 std::vector<std::unique_ptr<TestStream>> test_streams_; 548 ScopedVector<TestStream> test_streams_;
550 549
551 private: 550 private:
552 std::unique_ptr<base::FilePath::StringType> test_stream_data_; 551 std::unique_ptr<base::FilePath::StringType> test_stream_data_;
553 base::FilePath log_path_; 552 base::FilePath log_path_;
554 std::unique_ptr<base::File> log_file_; 553 std::unique_ptr<base::File> log_file_;
555 bool run_at_fps_; 554 bool run_at_fps_;
556 bool needs_encode_latency_; 555 bool needs_encode_latency_;
557 bool verify_all_output_; 556 bool verify_all_output_;
558 }; 557 };
559 558
(...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after
917 916
918 std::unique_ptr<VideoEncodeAccelerator> encoder_; 917 std::unique_ptr<VideoEncodeAccelerator> encoder_;
919 918
920 // Used to notify another thread about the state. VEAClientBase does not own 919 // Used to notify another thread about the state. VEAClientBase does not own
921 // this. 920 // this.
922 ClientStateNotification<ClientState>* note_; 921 ClientStateNotification<ClientState>* note_;
923 922
924 // All methods of this class should be run on the same thread. 923 // All methods of this class should be run on the same thread.
925 base::ThreadChecker thread_checker_; 924 base::ThreadChecker thread_checker_;
926 925
927 std::vector<std::unique_ptr<base::SharedMemory>> output_shms_; 926 ScopedVector<base::SharedMemory> output_shms_;
928 int32_t next_output_buffer_id_; 927 int32_t next_output_buffer_id_;
929 }; 928 };
930 929
931 class VEAClient : public VEAClientBase { 930 class VEAClient : public VEAClientBase {
932 public: 931 public:
933 VEAClient(TestStream* test_stream, 932 VEAClient(TestStream* test_stream,
934 ClientStateNotification<ClientState>* note, 933 ClientStateNotification<ClientState>* note,
935 bool save_to_file, 934 bool save_to_file,
936 unsigned int keyframe_period, 935 unsigned int keyframe_period,
937 bool force_bitrate, 936 bool force_bitrate,
(...skipping 462 matching lines...) Expand 10 before | Expand all | Expand 10 after
1400 WriteIvfFileHeader(); 1399 WriteIvfFileHeader();
1401 1400
1402 input_coded_size_ = input_coded_size; 1401 input_coded_size_ = input_coded_size;
1403 num_required_input_buffers_ = input_count; 1402 num_required_input_buffers_ = input_count;
1404 ASSERT_GT(num_required_input_buffers_, 0UL); 1403 ASSERT_GT(num_required_input_buffers_, 0UL);
1405 1404
1406 output_buffer_size_ = output_size; 1405 output_buffer_size_ = output_size;
1407 ASSERT_GT(output_buffer_size_, 0UL); 1406 ASSERT_GT(output_buffer_size_, 0UL);
1408 1407
1409 for (unsigned int i = 0; i < kNumOutputBuffers; ++i) { 1408 for (unsigned int i = 0; i < kNumOutputBuffers; ++i) {
1410 auto shm = base::MakeUnique<base::SharedMemory>(); 1409 base::SharedMemory* shm = new base::SharedMemory();
1411 LOG_ASSERT(shm->CreateAndMapAnonymous(output_buffer_size_)); 1410 LOG_ASSERT(shm->CreateAndMapAnonymous(output_buffer_size_));
1412 FeedEncoderWithOutput(shm.get()); 1411 output_shms_.push_back(shm);
1413 output_shms_.push_back(std::move(shm)); 1412 FeedEncoderWithOutput(shm);
1414 } 1413 }
1415 1414
1416 if (g_env->run_at_fps()) { 1415 if (g_env->run_at_fps()) {
1417 input_timer_.reset(new base::RepeatingTimer()); 1416 input_timer_.reset(new base::RepeatingTimer());
1418 input_timer_->Start( 1417 input_timer_->Start(
1419 FROM_HERE, base::TimeDelta::FromSeconds(1) / current_framerate_, 1418 FROM_HERE, base::TimeDelta::FromSeconds(1) / current_framerate_,
1420 base::Bind(&VEAClient::OnInputTimer, base::Unretained(this))); 1419 base::Bind(&VEAClient::OnInputTimer, base::Unretained(this)));
1421 } else { 1420 } else {
1422 while (inputs_at_client_.size() < 1421 while (inputs_at_client_.size() <
1423 num_required_input_buffers_ + kNumExtraInputFrames) 1422 num_required_input_buffers_ + kNumExtraInputFrames)
(...skipping 472 matching lines...) Expand 10 before | Expand all | Expand 10 after
1896 1895
1897 void SimpleVEAClientBase::RequireBitstreamBuffers( 1896 void SimpleVEAClientBase::RequireBitstreamBuffers(
1898 unsigned int input_count, 1897 unsigned int input_count,
1899 const gfx::Size& input_coded_size, 1898 const gfx::Size& input_coded_size,
1900 size_t output_size) { 1899 size_t output_size) {
1901 DCHECK(thread_checker_.CalledOnValidThread()); 1900 DCHECK(thread_checker_.CalledOnValidThread());
1902 SetState(CS_ENCODING); 1901 SetState(CS_ENCODING);
1903 ASSERT_GT(output_size, 0UL); 1902 ASSERT_GT(output_size, 0UL);
1904 1903
1905 for (unsigned int i = 0; i < kNumOutputBuffers; ++i) { 1904 for (unsigned int i = 0; i < kNumOutputBuffers; ++i) {
1906 auto shm = base::MakeUnique<base::SharedMemory>(); 1905 base::SharedMemory* shm = new base::SharedMemory();
1907 LOG_ASSERT(shm->CreateAndMapAnonymous(output_size)); 1906 LOG_ASSERT(shm->CreateAndMapAnonymous(output_size));
1908 FeedEncoderWithOutput(shm.get(), output_size); 1907 output_shms_.push_back(shm);
1909 output_shms_.push_back(std::move(shm)); 1908 FeedEncoderWithOutput(shm, output_size);
1910 } 1909 }
1911 } 1910 }
1912 1911
1913 void SimpleVEAClientBase::FeedEncoderWithOutput(base::SharedMemory* shm, 1912 void SimpleVEAClientBase::FeedEncoderWithOutput(base::SharedMemory* shm,
1914 size_t output_size) { 1913 size_t output_size) {
1915 if (!has_encoder()) 1914 if (!has_encoder())
1916 return; 1915 return;
1917 1916
1918 base::SharedMemoryHandle dup_handle = shm->handle().Duplicate(); 1917 base::SharedMemoryHandle dup_handle = shm->handle().Duplicate();
1919 LOG_ASSERT(dup_handle.IsValid()); 1918 LOG_ASSERT(dup_handle.IsValid());
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
2079 const bool save_to_file = std::get<1>(GetParam()); 2078 const bool save_to_file = std::get<1>(GetParam());
2080 const unsigned int keyframe_period = std::get<2>(GetParam()); 2079 const unsigned int keyframe_period = std::get<2>(GetParam());
2081 const bool force_bitrate = std::get<3>(GetParam()); 2080 const bool force_bitrate = std::get<3>(GetParam());
2082 const bool test_perf = std::get<4>(GetParam()); 2081 const bool test_perf = std::get<4>(GetParam());
2083 const bool mid_stream_bitrate_switch = std::get<5>(GetParam()); 2082 const bool mid_stream_bitrate_switch = std::get<5>(GetParam());
2084 const bool mid_stream_framerate_switch = std::get<6>(GetParam()); 2083 const bool mid_stream_framerate_switch = std::get<6>(GetParam());
2085 const bool verify_output = 2084 const bool verify_output =
2086 std::get<7>(GetParam()) || g_env->verify_all_output(); 2085 std::get<7>(GetParam()) || g_env->verify_all_output();
2087 const bool verify_output_timestamp = std::get<8>(GetParam()); 2086 const bool verify_output_timestamp = std::get<8>(GetParam());
2088 2087
2089 std::vector<std::unique_ptr<ClientStateNotification<ClientState>>> notes; 2088 ScopedVector<ClientStateNotification<ClientState>> notes;
2090 std::vector<std::unique_ptr<VEAClient>> clients; 2089 ScopedVector<VEAClient> clients;
2091 base::Thread vea_client_thread("EncoderClientThread"); 2090 base::Thread vea_client_thread("EncoderClientThread");
2092 ASSERT_TRUE(vea_client_thread.Start()); 2091 ASSERT_TRUE(vea_client_thread.Start());
2093 2092
2094 if (g_env->test_streams_.size() > 1) 2093 if (g_env->test_streams_.size() > 1)
2095 num_concurrent_encoders = g_env->test_streams_.size(); 2094 num_concurrent_encoders = g_env->test_streams_.size();
2096 2095
2097 // Create all encoders. 2096 // Create all encoders.
2098 for (size_t i = 0; i < num_concurrent_encoders; i++) { 2097 for (size_t i = 0; i < num_concurrent_encoders; i++) {
2099 size_t test_stream_index = i % g_env->test_streams_.size(); 2098 size_t test_stream_index = i % g_env->test_streams_.size();
2100 // Disregard save_to_file if we didn't get an output filename. 2099 // Disregard save_to_file if we didn't get an output filename.
2101 bool encoder_save_to_file = 2100 bool encoder_save_to_file =
2102 (save_to_file && 2101 (save_to_file &&
2103 !g_env->test_streams_[test_stream_index]->out_filename.empty()); 2102 !g_env->test_streams_[test_stream_index]->out_filename.empty());
2104 2103
2105 notes.push_back(base::MakeUnique<ClientStateNotification<ClientState>>()); 2104 notes.push_back(new ClientStateNotification<ClientState>());
2106 clients.push_back(base::MakeUnique<VEAClient>( 2105 clients.push_back(new VEAClient(
2107 g_env->test_streams_[test_stream_index].get(), notes.back().get(), 2106 g_env->test_streams_[test_stream_index], notes.back(),
2108 encoder_save_to_file, keyframe_period, force_bitrate, test_perf, 2107 encoder_save_to_file, keyframe_period, force_bitrate, test_perf,
2109 mid_stream_bitrate_switch, mid_stream_framerate_switch, verify_output, 2108 mid_stream_bitrate_switch, mid_stream_framerate_switch, verify_output,
2110 verify_output_timestamp)); 2109 verify_output_timestamp));
2111 2110
2112 vea_client_thread.task_runner()->PostTask( 2111 vea_client_thread.task_runner()->PostTask(
2113 FROM_HERE, base::Bind(&VEAClient::CreateEncoder, 2112 FROM_HERE, base::Bind(&VEAClient::CreateEncoder,
2114 base::Unretained(clients.back().get()))); 2113 base::Unretained(clients.back())));
2115 } 2114 }
2116 2115
2117 // All encoders must pass through states in this order. 2116 // All encoders must pass through states in this order.
2118 enum ClientState state_transitions[] = {CS_INITIALIZED, CS_ENCODING, 2117 enum ClientState state_transitions[] = {CS_INITIALIZED, CS_ENCODING,
2119 CS_FINISHED, CS_VALIDATED}; 2118 CS_FINISHED, CS_VALIDATED};
2120 2119
2121 // Wait for all encoders to go through all states and finish. 2120 // Wait for all encoders to go through all states and finish.
2122 // Do this by waiting for all encoders to advance to state n before checking 2121 // Do this by waiting for all encoders to advance to state n before checking
2123 // state n+1, to verify that they are able to operate concurrently. 2122 // state n+1, to verify that they are able to operate concurrently.
2124 // It also simulates the real-world usage better, as the main thread, on which 2123 // It also simulates the real-world usage better, as the main thread, on which
2125 // encoders are created/destroyed, is a single GPU Process ChildThread. 2124 // encoders are created/destroyed, is a single GPU Process ChildThread.
2126 // Moreover, we can't have proper multithreading on X11, so this could cause 2125 // Moreover, we can't have proper multithreading on X11, so this could cause
2127 // hard to debug issues there, if there were multiple "ChildThreads". 2126 // hard to debug issues there, if there were multiple "ChildThreads".
2128 for (const auto& state : state_transitions) { 2127 for (const auto& state : state_transitions) {
2129 for (size_t i = 0; i < num_concurrent_encoders && !HasFailure(); i++) { 2128 for (size_t i = 0; i < num_concurrent_encoders && !HasFailure(); i++) {
2130 EXPECT_EQ(state, notes[i]->Wait()); 2129 EXPECT_EQ(state, notes[i]->Wait());
2131 } 2130 }
2132 if (HasFailure()) { 2131 if (HasFailure()) {
2133 break; 2132 break;
2134 } 2133 }
2135 } 2134 }
2136 2135
2137 for (size_t i = 0; i < num_concurrent_encoders; ++i) { 2136 for (size_t i = 0; i < num_concurrent_encoders; ++i) {
2138 vea_client_thread.task_runner()->PostTask( 2137 vea_client_thread.task_runner()->PostTask(
2139 FROM_HERE, base::Bind(&VEAClient::DestroyEncoder, 2138 FROM_HERE,
2140 base::Unretained(clients[i].get()))); 2139 base::Bind(&VEAClient::DestroyEncoder, base::Unretained(clients[i])));
2141 } 2140 }
2142 2141
2143 // This ensures all tasks have finished. 2142 // This ensures all tasks have finished.
2144 vea_client_thread.Stop(); 2143 vea_client_thread.Stop();
2145 } 2144 }
2146 2145
2147 // Test parameters: 2146 // Test parameters:
2148 // - Test type 2147 // - Test type
2149 // 0: No input test 2148 // 0: No input test
2150 // 1: Cache line-unaligned test 2149 // 1: Cache line-unaligned test
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after
2381 2380
2382 media::g_env = 2381 media::g_env =
2383 reinterpret_cast<media::VideoEncodeAcceleratorTestEnvironment*>( 2382 reinterpret_cast<media::VideoEncodeAcceleratorTestEnvironment*>(
2384 testing::AddGlobalTestEnvironment( 2383 testing::AddGlobalTestEnvironment(
2385 new media::VideoEncodeAcceleratorTestEnvironment( 2384 new media::VideoEncodeAcceleratorTestEnvironment(
2386 std::move(test_stream_data), log_path, run_at_fps, 2385 std::move(test_stream_data), log_path, run_at_fps,
2387 needs_encode_latency, verify_all_output))); 2386 needs_encode_latency, verify_all_output)));
2388 2387
2389 return RUN_ALL_TESTS(); 2388 return RUN_ALL_TESTS();
2390 } 2389 }
OLDNEW
« no previous file with comments | « media/gpu/jpeg_decode_accelerator_unittest.cc ('k') | media/midi/midi_device_android.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698