Home | History | Annotate | Download | only in process
      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
      3 // found in the LICENSE file.
      4 
      5 #include "base/process/process_metrics.h"
      6 
      7 #include <stddef.h>
      8 #include <stdint.h>
      9 
     10 #include <sstream>
     11 #include <string>
     12 
     13 #include "base/bind.h"
     14 #include "base/command_line.h"
     15 #include "base/files/file.h"
     16 #include "base/files/file_util.h"
     17 #include "base/files/scoped_temp_dir.h"
     18 #include "base/macros.h"
     19 #include "base/strings/string_number_conversions.h"
     20 #include "base/sys_info.h"
     21 #include "base/test/multiprocess_test.h"
     22 #include "base/threading/thread.h"
     23 #include "build/build_config.h"
     24 #include "testing/gtest/include/gtest/gtest.h"
     25 #include "testing/multiprocess_func_list.h"
     26 
     27 #if defined(OS_MACOSX)
     28 #include <sys/mman.h>
     29 #endif
     30 
     31 namespace base {
     32 namespace debug {
     33 
     34 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
     35 namespace {
     36 
     37 void BusyWork(std::vector<std::string>* vec) {
     38   int64_t test_value = 0;
     39   for (int i = 0; i < 100000; ++i) {
     40     ++test_value;
     41     vec->push_back(Int64ToString(test_value));
     42   }
     43 }
     44 
     45 }  // namespace
     46 #endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
     47 
     48 // Tests for SystemMetrics.
     49 // Exists as a class so it can be a friend of SystemMetrics.
     50 class SystemMetricsTest : public testing::Test {
     51  public:
     52   SystemMetricsTest() {}
     53 
     54  private:
     55   DISALLOW_COPY_AND_ASSIGN(SystemMetricsTest);
     56 };
     57 
     58 /////////////////////////////////////////////////////////////////////////////
     59 
     60 #if defined(OS_MACOSX) && !defined(OS_IOS) && !defined(ADDRESS_SANITIZER)
     61 TEST_F(SystemMetricsTest, LockedBytes) {
     62   ProcessHandle handle = GetCurrentProcessHandle();
     63   std::unique_ptr<ProcessMetrics> metrics(
     64       ProcessMetrics::CreateProcessMetrics(handle, nullptr));
     65 
     66   size_t initial_locked_bytes;
     67   bool result =
     68       metrics->GetMemoryBytes(nullptr, nullptr, nullptr, &initial_locked_bytes);
     69   ASSERT_TRUE(result);
     70 
     71   size_t size = 8 * 1024 * 1024;
     72   std::unique_ptr<char[]> memory(new char[size]);
     73   int r = mlock(memory.get(), size);
     74   ASSERT_EQ(0, r);
     75 
     76   size_t new_locked_bytes;
     77   result =
     78       metrics->GetMemoryBytes(nullptr, nullptr, nullptr, &new_locked_bytes);
     79   ASSERT_TRUE(result);
     80 
     81   // There should be around |size| more locked bytes, but multi-threading might
     82   // cause noise.
     83   EXPECT_LT(initial_locked_bytes + size / 2, new_locked_bytes);
     84   EXPECT_GT(initial_locked_bytes + size * 1.5, new_locked_bytes);
     85 
     86   r = munlock(memory.get(), size);
     87   ASSERT_EQ(0, r);
     88 
     89   result =
     90       metrics->GetMemoryBytes(nullptr, nullptr, nullptr, &new_locked_bytes);
     91   ASSERT_TRUE(result);
     92   EXPECT_EQ(initial_locked_bytes, new_locked_bytes);
     93 }
     94 #endif  // defined(OS_MACOSX) && !defined(OS_IOS) && !defined(ADDRESS_SANITIZER)
     95 
     96 #if defined(OS_LINUX) || defined(OS_ANDROID)
     97 TEST_F(SystemMetricsTest, IsValidDiskName) {
     98   std::string invalid_input1 = "";
     99   std::string invalid_input2 = "s";
    100   std::string invalid_input3 = "sdz+";
    101   std::string invalid_input4 = "hda0";
    102   std::string invalid_input5 = "mmcbl";
    103   std::string invalid_input6 = "mmcblka";
    104   std::string invalid_input7 = "mmcblkb";
    105   std::string invalid_input8 = "mmmblk0";
    106 
    107   EXPECT_FALSE(IsValidDiskName(invalid_input1));
    108   EXPECT_FALSE(IsValidDiskName(invalid_input2));
    109   EXPECT_FALSE(IsValidDiskName(invalid_input3));
    110   EXPECT_FALSE(IsValidDiskName(invalid_input4));
    111   EXPECT_FALSE(IsValidDiskName(invalid_input5));
    112   EXPECT_FALSE(IsValidDiskName(invalid_input6));
    113   EXPECT_FALSE(IsValidDiskName(invalid_input7));
    114   EXPECT_FALSE(IsValidDiskName(invalid_input8));
    115 
    116   std::string valid_input1 = "sda";
    117   std::string valid_input2 = "sdaaaa";
    118   std::string valid_input3 = "hdz";
    119   std::string valid_input4 = "mmcblk0";
    120   std::string valid_input5 = "mmcblk999";
    121 
    122   EXPECT_TRUE(IsValidDiskName(valid_input1));
    123   EXPECT_TRUE(IsValidDiskName(valid_input2));
    124   EXPECT_TRUE(IsValidDiskName(valid_input3));
    125   EXPECT_TRUE(IsValidDiskName(valid_input4));
    126   EXPECT_TRUE(IsValidDiskName(valid_input5));
    127 }
    128 
    129 TEST_F(SystemMetricsTest, ParseMeminfo) {
    130   struct SystemMemoryInfoKB meminfo;
    131   std::string invalid_input1 = "abc";
    132   std::string invalid_input2 = "MemTotal:";
    133   // Partial file with no MemTotal
    134   std::string invalid_input3 =
    135     "MemFree:         3913968 kB\n"
    136     "Buffers:         2348340 kB\n"
    137     "Cached:         49071596 kB\n"
    138     "SwapCached:           12 kB\n"
    139     "Active:         36393900 kB\n"
    140     "Inactive:       21221496 kB\n"
    141     "Active(anon):    5674352 kB\n"
    142     "Inactive(anon):   633992 kB\n";
    143   EXPECT_FALSE(ParseProcMeminfo(invalid_input1, &meminfo));
    144   EXPECT_FALSE(ParseProcMeminfo(invalid_input2, &meminfo));
    145   EXPECT_FALSE(ParseProcMeminfo(invalid_input3, &meminfo));
    146 
    147   std::string valid_input1 =
    148     "MemTotal:        3981504 kB\n"
    149     "MemFree:          140764 kB\n"
    150     "MemAvailable:     535413 kB\n"
    151     "Buffers:          116480 kB\n"
    152     "Cached:           406160 kB\n"
    153     "SwapCached:        21304 kB\n"
    154     "Active:          3152040 kB\n"
    155     "Inactive:         472856 kB\n"
    156     "Active(anon):    2972352 kB\n"
    157     "Inactive(anon):   270108 kB\n"
    158     "Active(file):     179688 kB\n"
    159     "Inactive(file):   202748 kB\n"
    160     "Unevictable:           0 kB\n"
    161     "Mlocked:               0 kB\n"
    162     "SwapTotal:       5832280 kB\n"
    163     "SwapFree:        3672368 kB\n"
    164     "Dirty:               184 kB\n"
    165     "Writeback:             0 kB\n"
    166     "AnonPages:       3101224 kB\n"
    167     "Mapped:           142296 kB\n"
    168     "Shmem:            140204 kB\n"
    169     "Slab:              54212 kB\n"
    170     "SReclaimable:      30936 kB\n"
    171     "SUnreclaim:        23276 kB\n"
    172     "KernelStack:        2464 kB\n"
    173     "PageTables:        24812 kB\n"
    174     "NFS_Unstable:          0 kB\n"
    175     "Bounce:                0 kB\n"
    176     "WritebackTmp:          0 kB\n"
    177     "CommitLimit:     7823032 kB\n"
    178     "Committed_AS:    7973536 kB\n"
    179     "VmallocTotal:   34359738367 kB\n"
    180     "VmallocUsed:      375940 kB\n"
    181     "VmallocChunk:   34359361127 kB\n"
    182     "DirectMap4k:       72448 kB\n"
    183     "DirectMap2M:     4061184 kB\n";
    184   // output from a much older kernel where the Active and Inactive aren't
    185   // broken down into anon and file and Huge Pages are enabled
    186   std::string valid_input2 =
    187     "MemTotal:       255908 kB\n"
    188     "MemFree:         69936 kB\n"
    189     "Buffers:         15812 kB\n"
    190     "Cached:         115124 kB\n"
    191     "SwapCached:          0 kB\n"
    192     "Active:          92700 kB\n"
    193     "Inactive:        63792 kB\n"
    194     "HighTotal:           0 kB\n"
    195     "HighFree:            0 kB\n"
    196     "LowTotal:       255908 kB\n"
    197     "LowFree:         69936 kB\n"
    198     "SwapTotal:      524280 kB\n"
    199     "SwapFree:       524200 kB\n"
    200     "Dirty:               4 kB\n"
    201     "Writeback:           0 kB\n"
    202     "Mapped:          42236 kB\n"
    203     "Slab:            25912 kB\n"
    204     "Committed_AS:   118680 kB\n"
    205     "PageTables:       1236 kB\n"
    206     "VmallocTotal:  3874808 kB\n"
    207     "VmallocUsed:      1416 kB\n"
    208     "VmallocChunk:  3872908 kB\n"
    209     "HugePages_Total:     0\n"
    210     "HugePages_Free:      0\n"
    211     "Hugepagesize:     4096 kB\n";
    212 
    213   EXPECT_TRUE(ParseProcMeminfo(valid_input1, &meminfo));
    214   EXPECT_EQ(meminfo.total, 3981504);
    215   EXPECT_EQ(meminfo.free, 140764);
    216   EXPECT_EQ(meminfo.available, 535413);
    217   EXPECT_EQ(meminfo.buffers, 116480);
    218   EXPECT_EQ(meminfo.cached, 406160);
    219   EXPECT_EQ(meminfo.active_anon, 2972352);
    220   EXPECT_EQ(meminfo.active_file, 179688);
    221   EXPECT_EQ(meminfo.inactive_anon, 270108);
    222   EXPECT_EQ(meminfo.inactive_file, 202748);
    223   EXPECT_EQ(meminfo.swap_total, 5832280);
    224   EXPECT_EQ(meminfo.swap_free, 3672368);
    225   EXPECT_EQ(meminfo.dirty, 184);
    226   EXPECT_EQ(meminfo.reclaimable, 30936);
    227 #if defined(OS_CHROMEOS)
    228   EXPECT_EQ(meminfo.shmem, 140204);
    229   EXPECT_EQ(meminfo.slab, 54212);
    230 #endif
    231   EXPECT_EQ(355725,
    232             base::SysInfo::AmountOfAvailablePhysicalMemory(meminfo) / 1024);
    233   // Simulate as if there is no MemAvailable.
    234   meminfo.available = 0;
    235   EXPECT_EQ(374448,
    236             base::SysInfo::AmountOfAvailablePhysicalMemory(meminfo) / 1024);
    237   meminfo = {};
    238   EXPECT_TRUE(ParseProcMeminfo(valid_input2, &meminfo));
    239   EXPECT_EQ(meminfo.total, 255908);
    240   EXPECT_EQ(meminfo.free, 69936);
    241   EXPECT_EQ(meminfo.available, 0);
    242   EXPECT_EQ(meminfo.buffers, 15812);
    243   EXPECT_EQ(meminfo.cached, 115124);
    244   EXPECT_EQ(meminfo.swap_total, 524280);
    245   EXPECT_EQ(meminfo.swap_free, 524200);
    246   EXPECT_EQ(meminfo.dirty, 4);
    247   EXPECT_EQ(69936,
    248             base::SysInfo::AmountOfAvailablePhysicalMemory(meminfo) / 1024);
    249 }
    250 
    251 TEST_F(SystemMetricsTest, ParseVmstat) {
    252   struct SystemMemoryInfoKB meminfo;
    253   // part of vmstat from a 3.2 kernel with numa enabled
    254   std::string valid_input1 =
    255     "nr_free_pages 905104\n"
    256     "nr_inactive_anon 142478"
    257     "nr_active_anon 1520046\n"
    258     "nr_inactive_file 4481001\n"
    259     "nr_active_file 8313439\n"
    260     "nr_unevictable 5044\n"
    261     "nr_mlock 5044\n"
    262     "nr_anon_pages 1633780\n"
    263     "nr_mapped 104742\n"
    264     "nr_file_pages 12828218\n"
    265     "nr_dirty 245\n"
    266     "nr_writeback 0\n"
    267     "nr_slab_reclaimable 831609\n"
    268     "nr_slab_unreclaimable 41164\n"
    269     "nr_page_table_pages 31470\n"
    270     "nr_kernel_stack 1735\n"
    271     "nr_unstable 0\n"
    272     "nr_bounce 0\n"
    273     "nr_vmscan_write 406\n"
    274     "nr_vmscan_immediate_reclaim 281\n"
    275     "nr_writeback_temp 0\n"
    276     "nr_isolated_anon 0\n"
    277     "nr_isolated_file 0\n"
    278     "nr_shmem 28820\n"
    279     "nr_dirtied 84674644\n"
    280     "nr_written 75307109\n"
    281     "nr_anon_transparent_hugepages 0\n"
    282     "nr_dirty_threshold 1536206\n"
    283     "nr_dirty_background_threshold 768103\n"
    284     "pgpgin 30777108\n"
    285     "pgpgout 319023278\n"
    286     "pswpin 179\n"
    287     "pswpout 406\n"
    288     "pgalloc_dma 0\n"
    289     "pgalloc_dma32 20833399\n"
    290     "pgalloc_normal 1622609290\n"
    291     "pgalloc_movable 0\n"
    292     "pgfree 1644355583\n"
    293     "pgactivate 75391882\n"
    294     "pgdeactivate 4121019\n"
    295     "pgfault 2542879679\n"
    296     "pgmajfault 487192\n";
    297   std::string valid_input2 =
    298     "nr_free_pages 180125\n"
    299     "nr_inactive_anon 51\n"
    300     "nr_active_anon 38832\n"
    301     "nr_inactive_file 50171\n"
    302     "nr_active_file 47510\n"
    303     "nr_unevictable 0\n"
    304     "nr_mlock 0\n"
    305     "nr_anon_pages 38825\n"
    306     "nr_mapped 24043\n"
    307     "nr_file_pages 97733\n"
    308     "nr_dirty 0\n"
    309     "nr_writeback 0\n"
    310     "nr_slab_reclaimable 4032\n"
    311     "nr_slab_unreclaimable 2848\n"
    312     "nr_page_table_pages 1505\n"
    313     "nr_kernel_stack 626\n"
    314     "nr_unstable 0\n"
    315     "nr_bounce 0\n"
    316     "nr_vmscan_write 0\n"
    317     "nr_vmscan_immediate_reclaim 0\n"
    318     "nr_writeback_temp 0\n"
    319     "nr_isolated_anon 0\n"
    320     "nr_isolated_file 0\n"
    321     "nr_shmem 58\n"
    322     "nr_dirtied 435358\n"
    323     "nr_written 401258\n"
    324     "nr_anon_transparent_hugepages 0\n"
    325     "nr_dirty_threshold 18566\n"
    326     "nr_dirty_background_threshold 4641\n"
    327     "pgpgin 299464\n"
    328     "pgpgout 2437788\n"
    329     "pswpin 12\n"
    330     "pswpout 901\n"
    331     "pgalloc_normal 144213030\n"
    332     "pgalloc_high 164501274\n"
    333     "pgalloc_movable 0\n"
    334     "pgfree 308894908\n"
    335     "pgactivate 239320\n"
    336     "pgdeactivate 1\n"
    337     "pgfault 716044601\n"
    338     "pgmajfault 2023\n"
    339     "pgrefill_normal 0\n"
    340     "pgrefill_high 0\n"
    341     "pgrefill_movable 0\n";
    342   EXPECT_TRUE(ParseProcVmstat(valid_input1, &meminfo));
    343   EXPECT_EQ(179LU, meminfo.pswpin);
    344   EXPECT_EQ(406LU, meminfo.pswpout);
    345   EXPECT_EQ(487192LU, meminfo.pgmajfault);
    346   EXPECT_TRUE(ParseProcVmstat(valid_input2, &meminfo));
    347   EXPECT_EQ(12LU, meminfo.pswpin);
    348   EXPECT_EQ(901LU, meminfo.pswpout);
    349   EXPECT_EQ(2023LU, meminfo.pgmajfault);
    350 }
    351 #endif  // defined(OS_LINUX) || defined(OS_ANDROID)
    352 
    353 #if defined(OS_LINUX) || defined(OS_CHROMEOS)
    354 
    355 // Test that ProcessMetrics::GetCPUUsage() doesn't return negative values when
    356 // the number of threads running on the process decreases between two successive
    357 // calls to it.
    358 TEST_F(SystemMetricsTest, TestNoNegativeCpuUsage) {
    359   ProcessHandle handle = GetCurrentProcessHandle();
    360   std::unique_ptr<ProcessMetrics> metrics(
    361       ProcessMetrics::CreateProcessMetrics(handle));
    362 
    363   EXPECT_GE(metrics->GetCPUUsage(), 0.0);
    364   Thread thread1("thread1");
    365   Thread thread2("thread2");
    366   Thread thread3("thread3");
    367 
    368   thread1.StartAndWaitForTesting();
    369   thread2.StartAndWaitForTesting();
    370   thread3.StartAndWaitForTesting();
    371 
    372   ASSERT_TRUE(thread1.IsRunning());
    373   ASSERT_TRUE(thread2.IsRunning());
    374   ASSERT_TRUE(thread3.IsRunning());
    375 
    376   std::vector<std::string> vec1;
    377   std::vector<std::string> vec2;
    378   std::vector<std::string> vec3;
    379 
    380   thread1.task_runner()->PostTask(FROM_HERE, Bind(&BusyWork, &vec1));
    381   thread2.task_runner()->PostTask(FROM_HERE, Bind(&BusyWork, &vec2));
    382   thread3.task_runner()->PostTask(FROM_HERE, Bind(&BusyWork, &vec3));
    383 
    384   EXPECT_GE(metrics->GetCPUUsage(), 0.0);
    385 
    386   thread1.Stop();
    387   EXPECT_GE(metrics->GetCPUUsage(), 0.0);
    388 
    389   thread2.Stop();
    390   EXPECT_GE(metrics->GetCPUUsage(), 0.0);
    391 
    392   thread3.Stop();
    393   EXPECT_GE(metrics->GetCPUUsage(), 0.0);
    394 }
    395 
    396 #endif  // defined(OS_LINUX) || defined(OS_CHROMEOS)
    397 
    398 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \
    399     defined(OS_ANDROID)
    400 TEST(SystemMetrics2Test, GetSystemMemoryInfo) {
    401   SystemMemoryInfoKB info;
    402   EXPECT_TRUE(GetSystemMemoryInfo(&info));
    403 
    404   // Ensure each field received a value.
    405   EXPECT_GT(info.total, 0);
    406 #if defined(OS_WIN)
    407   EXPECT_GT(info.avail_phys, 0);
    408 #else
    409   EXPECT_GT(info.free, 0);
    410 #endif
    411 #if defined(OS_LINUX) || defined(OS_ANDROID)
    412   EXPECT_GT(info.buffers, 0);
    413   EXPECT_GT(info.cached, 0);
    414   EXPECT_GT(info.active_anon, 0);
    415   EXPECT_GT(info.inactive_anon, 0);
    416   EXPECT_GT(info.active_file, 0);
    417   EXPECT_GT(info.inactive_file, 0);
    418 #endif  // defined(OS_LINUX) || defined(OS_ANDROID)
    419 
    420   // All the values should be less than the total amount of memory.
    421 #if !defined(OS_WIN)
    422   EXPECT_LT(info.free, info.total);
    423 #endif
    424 #if defined(OS_LINUX) || defined(OS_ANDROID)
    425   EXPECT_LT(info.buffers, info.total);
    426   EXPECT_LT(info.cached, info.total);
    427   EXPECT_LT(info.active_anon, info.total);
    428   EXPECT_LT(info.inactive_anon, info.total);
    429   EXPECT_LT(info.active_file, info.total);
    430   EXPECT_LT(info.inactive_file, info.total);
    431 #endif  // defined(OS_LINUX) || defined(OS_ANDROID)
    432 
    433 #if defined(OS_MACOSX) || defined(OS_IOS)
    434   EXPECT_GT(info.file_backed, 0);
    435 #endif
    436 
    437 #if defined(OS_CHROMEOS)
    438   // Chrome OS exposes shmem.
    439   EXPECT_GT(info.shmem, 0);
    440   EXPECT_LT(info.shmem, info.total);
    441   // Chrome unit tests are not run on actual Chrome OS hardware, so gem_objects
    442   // and gem_size cannot be tested here.
    443 #endif
    444 }
    445 #endif  // defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) ||
    446         // defined(OS_ANDROID)
    447 
    448 #if defined(OS_LINUX) || defined(OS_ANDROID)
    449 TEST(ProcessMetricsTest, ParseProcStatCPU) {
    450   // /proc/self/stat for a process running "top".
    451   const char kTopStat[] = "960 (top) S 16230 960 16230 34818 960 "
    452       "4202496 471 0 0 0 "
    453       "12 16 0 0 "  // <- These are the goods.
    454       "20 0 1 0 121946157 15077376 314 18446744073709551615 4194304 "
    455       "4246868 140733983044336 18446744073709551615 140244213071219 "
    456       "0 0 0 138047495 0 0 0 17 1 0 0 0 0 0";
    457   EXPECT_EQ(12 + 16, ParseProcStatCPU(kTopStat));
    458 
    459   // cat /proc/self/stat on a random other machine I have.
    460   const char kSelfStat[] = "5364 (cat) R 5354 5364 5354 34819 5364 "
    461       "0 142 0 0 0 "
    462       "0 0 0 0 "  // <- No CPU, apparently.
    463       "16 0 1 0 1676099790 2957312 114 4294967295 134512640 134528148 "
    464       "3221224832 3221224344 3086339742 0 0 0 0 0 0 0 17 0 0 0";
    465 
    466   EXPECT_EQ(0, ParseProcStatCPU(kSelfStat));
    467 
    468   // Some weird long-running process with a weird name that I created for the
    469   // purposes of this test.
    470   const char kWeirdNameStat[] = "26115 (Hello) You ()))  ) R 24614 26115 24614"
    471       " 34839 26115 4218880 227 0 0 0 "
    472       "5186 11 0 0 "
    473       "20 0 1 0 36933953 4296704 90 18446744073709551615 4194304 4196116 "
    474       "140735857761568 140735857761160 4195644 0 0 0 0 0 0 0 17 14 0 0 0 0 0 "
    475       "6295056 6295616 16519168 140735857770710 140735857770737 "
    476       "140735857770737 140735857774557 0";
    477   EXPECT_EQ(5186 + 11, ParseProcStatCPU(kWeirdNameStat));
    478 }
    479 #endif  // defined(OS_LINUX) || defined(OS_ANDROID)
    480 
    481 // Disable on Android because base_unittests runs inside a Dalvik VM that
    482 // starts and stop threads (crbug.com/175563).
    483 #if defined(OS_LINUX)
    484 // http://crbug.com/396455
    485 TEST(ProcessMetricsTest, DISABLED_GetNumberOfThreads) {
    486   const ProcessHandle current = GetCurrentProcessHandle();
    487   const int initial_threads = GetNumberOfThreads(current);
    488   ASSERT_GT(initial_threads, 0);
    489   const int kNumAdditionalThreads = 10;
    490   {
    491     std::unique_ptr<Thread> my_threads[kNumAdditionalThreads];
    492     for (int i = 0; i < kNumAdditionalThreads; ++i) {
    493       my_threads[i].reset(new Thread("GetNumberOfThreadsTest"));
    494       my_threads[i]->Start();
    495       ASSERT_EQ(GetNumberOfThreads(current), initial_threads + 1 + i);
    496     }
    497   }
    498   // The Thread destructor will stop them.
    499   ASSERT_EQ(initial_threads, GetNumberOfThreads(current));
    500 }
    501 #endif  // defined(OS_LINUX)
    502 
    503 #if defined(OS_LINUX)
    504 namespace {
    505 
    506 // Keep these in sync so the GetOpenFdCount test can refer to correct test main.
    507 #define ChildMain ChildFdCount
    508 #define ChildMainString "ChildFdCount"
    509 
    510 // Command line flag name and file name used for synchronization.
    511 const char kTempDirFlag[] = "temp-dir";
    512 const char kSignalClosed[] = "closed";
    513 
    514 bool SignalEvent(const FilePath& signal_dir, const char* signal_file) {
    515   File file(signal_dir.AppendASCII(signal_file),
    516             File::FLAG_CREATE | File::FLAG_WRITE);
    517   return file.IsValid();
    518 }
    519 
    520 // Check whether an event was signaled.
    521 bool CheckEvent(const FilePath& signal_dir, const char* signal_file) {
    522   File file(signal_dir.AppendASCII(signal_file),
    523             File::FLAG_OPEN | File::FLAG_READ);
    524   return file.IsValid();
    525 }
    526 
    527 // Busy-wait for an event to be signaled.
    528 void WaitForEvent(const FilePath& signal_dir, const char* signal_file) {
    529   while (!CheckEvent(signal_dir, signal_file))
    530     PlatformThread::Sleep(TimeDelta::FromMilliseconds(10));
    531 }
    532 
    533 // Subprocess to test the number of open file descriptors.
    534 MULTIPROCESS_TEST_MAIN(ChildMain) {
    535   CommandLine* command_line = CommandLine::ForCurrentProcess();
    536   const FilePath temp_path = command_line->GetSwitchValuePath(kTempDirFlag);
    537   CHECK(DirectoryExists(temp_path));
    538 
    539   // Try to close all the file descriptors, so the open count goes to 0.
    540   for (size_t i = 0; i < 1000; ++i)
    541     close(i);
    542   CHECK(SignalEvent(temp_path, kSignalClosed));
    543 
    544   // Wait to be terminated.
    545   while (true)
    546     PlatformThread::Sleep(TimeDelta::FromSeconds(1));
    547   return 0;
    548 }
    549 
    550 }  // namespace
    551 
    552 // Arc++ note: don't compile as SpawnMultiProcessTestChild brings in a lot of
    553 // extra dependency.
    554 #if !defined(OS_ANDROID) && !defined(__ANDROID__) && !defined(__ANDROID_HOST__)
    555 TEST(ProcessMetricsTest, GetOpenFdCount) {
    556   ScopedTempDir temp_dir;
    557   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
    558   const FilePath temp_path = temp_dir.GetPath();
    559   CommandLine child_command_line(GetMultiProcessTestChildBaseCommandLine());
    560   child_command_line.AppendSwitchPath(kTempDirFlag, temp_path);
    561   SpawnChildResult spawn_child = SpawnMultiProcessTestChild(
    562       ChildMainString, child_command_line, LaunchOptions());
    563   ASSERT_TRUE(spawn_child.process.IsValid());
    564   WaitForEvent(temp_path, kSignalClosed);
    565 
    566   std::unique_ptr<ProcessMetrics> metrics(
    567       ProcessMetrics::CreateProcessMetrics(spawn_child.process.Handle()));
    568   // Try a couple times to observe the child with 0 fds open.
    569   // Sometimes we've seen that the child can have 1 remaining
    570   // fd shortly after receiving the signal.  Potentially this
    571   // is actually the signal file still open in the child.
    572   int open_fds = -1;
    573   for (int tries = 0; tries < 5; ++tries) {
    574     open_fds = metrics->GetOpenFdCount();
    575     if (!open_fds) {
    576       break;
    577     }
    578     PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
    579   }
    580   EXPECT_EQ(0, open_fds);
    581   ASSERT_TRUE(spawn_child.process.Terminate(0, true));
    582 }
    583 #endif  // !defined(__ANDROID__)
    584 
    585 #endif  // defined(OS_LINUX)
    586 
    587 }  // namespace debug
    588 }  // namespace base
    589