[go: nahoru, domu]

IPC: Make ipc_perftests run on Android.

There was several minor issues:

- Base perf logging file location was off-limits on Android

- Printf needs to be flushed to be visible on Android.

- Android needs to reset the 'PipeMap' manually since we can't 'exec' after 
forking a test process. If we don't do this the Channel thinks we are in a single-
process test and tries to open an FD which was closed during forking.

- Android's base file descriptor needs to be increased to prevent stomping 
the android native logging file-descriptor with the default pipe.

- The test took too long, so the 'exponent' is reduced from 5 to 3

- We need an APK

With this patch the test runs like on other platforms, and lots of testing code is
fixed such that it works the same way on all platforms.

BUG=345471

Review URL: https://codereview.chromium.org/196343019

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@257877 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/base/posix/global_descriptors.h b/base/posix/global_descriptors.h
index c7b9f87..3d7369c31 100644
--- a/base/posix/global_descriptors.h
+++ b/base/posix/global_descriptors.h
@@ -41,7 +41,11 @@
 
   // Often we want a canonical descriptor for a given Key. In this case, we add
   // the following constant to the key value:
+#if !defined(OS_ANDROID)
   static const int kBaseDescriptor = 3;  // 0, 1, 2 are already taken.
+#else
+  static const int kBaseDescriptor = 4;  // 3 used by __android_log_write().
+#endif
 
   // Return the singleton instance of GlobalDescriptors.
   static GlobalDescriptors* GetInstance();
diff --git a/base/test/multiprocess_test_android.cc b/base/test/multiprocess_test_android.cc
index e9e776e..126d8b1 100644
--- a/base/test/multiprocess_test_android.cc
+++ b/base/test/multiprocess_test_android.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/posix/global_descriptors.h"
 #include "base/test/multiprocess_test.h"
 
 #include <unistd.h>
@@ -42,10 +43,10 @@
        it != fds_to_remap->end(); ++it) {
     fds_to_keep_open.insert(it->first);
   }
-  // Keep stdin, stdout and stderr open since this is not meant to spawn a
-  // daemon.
-  const int kFdForAndroidLogging = 3;  // FD used by __android_log_write().
-  for (int fd = kFdForAndroidLogging + 1; fd < getdtablesize(); ++fd) {
+  // Keep standard FDs (stdin, stdout, stderr, etc.) open since this
+  // is not meant to spawn a daemon.
+  int base = GlobalDescriptors::kBaseDescriptor;
+  for (int fd = base; fd < getdtablesize(); ++fd) {
     if (fds_to_keep_open.find(fd) == fds_to_keep_open.end()) {
       close(fd);
     }
diff --git a/base/test/perf_log.cc b/base/test/perf_log.cc
index efc1d42e..5d5027d 100644
--- a/base/test/perf_log.cc
+++ b/base/test/perf_log.cc
@@ -39,6 +39,7 @@
 
   fprintf(perf_log_file, "%s\t%g\t%s\n", test_name, value, units);
   printf("%s\t%g\t%s\n", test_name, value, units);
+  fflush(stdout);
 }
 
 }  // namespace base
diff --git a/base/test/perf_test_suite.cc b/base/test/perf_test_suite.cc
index 04ebb8b..415aaef0 100644
--- a/base/test/perf_test_suite.cc
+++ b/base/test/perf_test_suite.cc
@@ -24,9 +24,13 @@
   FilePath log_path =
       CommandLine::ForCurrentProcess()->GetSwitchValuePath("log-file");
   if (log_path.empty()) {
-    FilePath exe;
-    PathService::Get(FILE_EXE, &exe);
-    log_path = exe.ReplaceExtension(FILE_PATH_LITERAL("log"));
+    PathService::Get(FILE_EXE, &log_path);
+#if defined(OS_ANDROID)
+    base::FilePath tmp_dir;
+    PathService::Get(base::DIR_CACHE, &tmp_dir);
+    log_path = tmp_dir.Append(log_path.BaseName());
+#endif
+    log_path = log_path.ReplaceExtension(FILE_PATH_LITERAL("log"));
     log_path = log_path.InsertBeforeExtension(FILE_PATH_LITERAL("_perf"));
   }
   ASSERT_TRUE(InitPerfLog(log_path));
diff --git a/ipc/ipc.gyp b/ipc/ipc.gyp
index c5c5185..0546debb 100644
--- a/ipc/ipc.gyp
+++ b/ipc/ipc.gyp
@@ -195,6 +195,18 @@
             'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)ipc_tests<(SHARED_LIB_SUFFIX)',
           },
           'includes': [ '../build/apk_test.gypi' ],
+        },
+        {
+          'target_name': 'ipc_perftests_apk',
+          'type': 'none',
+          'dependencies': [
+            'ipc_perftests',
+          ],
+          'variables': {
+            'test_suite_name': 'ipc_perftests',
+            'input_shlib_path': '<(SHARED_LIB_DIR)/<(SHARED_LIB_PREFIX)ipc_perftests<(SHARED_LIB_SUFFIX)',
+          },
+          'includes': [ '../build/apk_test.gypi' ],
         }],
     }],
   ],
diff --git a/ipc/ipc_channel.h b/ipc/ipc_channel.h
index bfa5ec6..4426e5d 100644
--- a/ipc/ipc_channel.h
+++ b/ipc/ipc_channel.h
@@ -204,6 +204,14 @@
   static void SetGlobalPid(int pid);
 #endif
 
+#if defined(OS_ANDROID)
+  // Most tests are single process and work the same on all platforms. However
+  // in some cases we want to test multi-process, and Android differs in that it
+  // can't 'exec' after forking. This callback resets any data in the forked
+  // process such that it acts similar to if it was exec'd, for tests.
+  static void NotifyProcessForkedForTesting();
+#endif
+
  protected:
   // Used in Chrome by the TestSink to provide a dummy channel implementation
   // for testing. TestSink overrides the "interesting" functions in Channel so
diff --git a/ipc/ipc_channel_posix.cc b/ipc/ipc_channel_posix.cc
index 2bd0989..11b20ff 100644
--- a/ipc/ipc_channel_posix.cc
+++ b/ipc/ipc_channel_posix.cc
@@ -135,6 +135,9 @@
   ChannelToFDMap map_;
 
   friend struct DefaultSingletonTraits<PipeMap>;
+#if defined(OS_ANDROID)
+  friend void ::IPC::Channel::NotifyProcessForkedForTesting();
+#endif
 };
 
 //------------------------------------------------------------------------------
@@ -159,6 +162,15 @@
 }
 
 }  // namespace
+
+#if defined(OS_ANDROID)
+// When we fork for simple tests on Android, we can't 'exec', so we need to
+// reset these entries manually to get the expected testing behavior.
+void Channel::NotifyProcessForkedForTesting() {
+  PipeMap::GetInstance()->map_.clear();
+}
+#endif
+
 //------------------------------------------------------------------------------
 
 #if defined(OS_LINUX)
@@ -227,7 +239,7 @@
   // 1) It's a channel wrapping a pipe that is given to us.
   // 2) It's for a named channel, so we create it.
   // 3) It's for a client that we implement ourself. This is used
-  //    in unittesting.
+  //    in single-process unittesting.
   // 4) It's the initial IPC channel:
   //   4a) Client side: Pull the pipe out of the GlobalDescriptors set.
   //   4b) Server side: create the pipe.
diff --git a/ipc/ipc_multiprocess_test.cc b/ipc/ipc_multiprocess_test.cc
index 8e3c03a1d..8da67b2c 100644
--- a/ipc/ipc_multiprocess_test.cc
+++ b/ipc/ipc_multiprocess_test.cc
@@ -4,6 +4,7 @@
 
 #include "build/build_config.h"
 
+#include "ipc/ipc_channel.h"
 #include "ipc/ipc_multiprocess_test.h"
 
 #if defined(OS_POSIX)
@@ -14,6 +15,12 @@
 namespace internal {
 
 void MultiProcessTestIPCSetUp() {
+#if defined(OS_ANDROID)
+  // On Android we can't 'exec'. So for simple multi-process tests
+  // we need to reset some global data after forking to get the same
+  // behavior in simple multi-process tests.
+  IPC::Channel::NotifyProcessForkedForTesting();
+#endif
 #if defined(OS_POSIX)
   base::GlobalDescriptors::GetInstance()->Set(kPrimaryIPCChannel,
       kPrimaryIPCChannel + base::GlobalDescriptors::kBaseDescriptor);
diff --git a/ipc/ipc_perftests.cc b/ipc/ipc_perftests.cc
index e7eeab9..d0d7e0d 100644
--- a/ipc/ipc_perftests.cc
+++ b/ipc/ipc_perftests.cc
@@ -230,12 +230,13 @@
   ASSERT_TRUE(ConnectChannel());
   ASSERT_TRUE(StartClient());
 
-  const size_t kMsgSizeBase = 12;
-  const int kMsgSizeMaxExp = 5;
-  int msg_count = 100000;
-  size_t msg_size = kMsgSizeBase;
-  for (int i = 1; i <= kMsgSizeMaxExp; i++) {
-    listener.SetTestParams(msg_count, msg_size);
+  // Test several sizes. We use 12^N for message size, and limit the message
+  // count to keep the test duration reasonable.
+  const size_t kMsgSize[5] = {12, 144, 1728, 20736, 248832};
+  const size_t kMessageCount[5] = {50000, 50000, 50000, 12000, 1000};
+
+  for (size_t i = 0; i < 5; i++) {
+    listener.SetTestParams(kMessageCount[i], kMsgSize[i]);
 
     // This initial message will kick-start the ping-pong of messages.
     IPC::Message* message =
@@ -247,8 +248,6 @@
 
     // Run message loop.
     base::MessageLoop::current()->Run();
-
-    msg_size *= kMsgSizeBase;
   }
 
   // Send quit message.