Bug 574120 - Add Android support to IPC code, r=cjones
authorMichael Wu <mwu@mozilla.com>
Fri, 25 Jun 2010 11:39:02 -0700
changeset 46920 1727bfc1114752eb69fab020c3866ac3bb91ec84
parent 46919 c37e3ae2d89de2e81fdbc85e81cfbde577c93f72
child 46921 103b167938e5ffa34c6c3fbb4dead5adafab88cc
push idunknown
push userunknown
push dateunknown
reviewerscjones
bugs574120
milestone1.9.3a6pre
Bug 574120 - Add Android support to IPC code, r=cjones
ipc/chromium/Makefile.in
ipc/chromium/src/base/debug_util_posix.cc
ipc/chromium/src/base/file_util.cc
ipc/chromium/src/base/file_util.h
ipc/chromium/src/base/file_util_linux.cc
ipc/chromium/src/base/file_util_posix.cc
ipc/chromium/src/base/message_loop.cc
ipc/chromium/src/base/message_pump_android.cc
ipc/chromium/src/base/message_pump_android.h
ipc/chromium/src/base/platform_file_posix.cc
ipc/chromium/src/base/process_util_posix.cc
ipc/chromium/src/base/shared_memory_posix.cc
ipc/chromium/src/base/sys_info_posix.cc
ipc/chromium/src/base/third_party/nspr/prcpucfg.h
ipc/chromium/src/base/third_party/nspr/prtime.cc
ipc/chromium/src/base/time_posix.cc
ipc/chromium/src/build/build_config.h
ipc/chromium/src/chrome/common/file_descriptor_set_posix.cc
ipc/chromium/src/third_party/libevent/select.c
ipc/glue/GeckoChildProcessHost.cpp
ipc/glue/SharedMemorySysV.h
--- a/ipc/chromium/Makefile.in
+++ b/ipc/chromium/Makefile.in
@@ -199,16 +199,23 @@ CPPSRCS += \
   thread_local_storage_posix.cc \
   waitable_event_posix.cc \
   waitable_event_watcher_posix.cc \
   file_descriptor_set_posix.cc \
   ipc_channel_posix.cc \
   process_watcher_posix_sigchld.cc \
   $(NULL)
 
+ifeq ($(OS_TARGET),Android)
+DEFINES += -DANDROID -D_POSIX_MONOTONIC_CLOCK=0
+CPPSRCS += \
+  message_pump_android.cc \
+  $(NULL)
+endif # Android
+
 endif # } OS_POSIX
 
 ifdef OS_MACOSX # {
 
 CMMSRCS += \
   base_paths_mac.mm \
   file_util_mac.mm \
   file_version_info_mac.mm \
--- a/ipc/chromium/src/base/debug_util_posix.cc
+++ b/ipc/chromium/src/base/debug_util_posix.cc
@@ -1,23 +1,25 @@
 // Copyright (c) 2006-2009 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 "build/build_config.h"
 #include "base/debug_util.h"
 
 #include <errno.h>
-#include <execinfo.h>
 #include <fcntl.h>
 #include <stdio.h>
 #include <sys/stat.h>
-#include <sys/sysctl.h>
 #include <sys/types.h>
 #include <unistd.h>
+#ifndef ANDROID
+#include <execinfo.h>
+#include <sys/sysctl.h>
+#endif
 
 #include "base/basictypes.h"
 #include "base/eintr_wrapper.h"
 #include "base/logging.h"
 #include "base/scoped_ptr.h"
 #include "base/string_piece.h"
 
 // static
@@ -112,32 +114,38 @@ void DebugUtil::BreakDebugger() {
   asm ("int3");
 #endif
 }
 
 StackTrace::StackTrace() {
   const int kMaxCallers = 256;
 
   void* callers[kMaxCallers];
+#ifndef ANDROID
   int count = backtrace(callers, kMaxCallers);
+#else
+  int count = 0;
+#endif
 
   // Though the backtrace API man page does not list any possible negative
   // return values, we still still exclude them because they would break the
   // memcpy code below.
   if (count > 0) {
     trace_.resize(count);
     memcpy(&trace_[0], callers, sizeof(callers[0]) * count);
   } else {
     trace_.resize(0);
   }
 }
 
 void StackTrace::PrintBacktrace() {
   fflush(stderr);
+#ifndef ANDROID
   backtrace_symbols_fd(&trace_[0], trace_.size(), STDERR_FILENO);
+#endif
 }
 
 void StackTrace::OutputToStream(std::ostream* os) {
 #ifdef CHROMIUM_MOZILLA_BUILD
   return;
 #else
   scoped_ptr_malloc<char*> trace_symbols(
       backtrace_symbols(&trace_[0], trace_.size()));
--- a/ipc/chromium/src/base/file_util.cc
+++ b/ipc/chromium/src/base/file_util.cc
@@ -3,16 +3,17 @@
 // found in the LICENSE file.
 
 #include "base/file_util.h"
 
 #if defined(OS_WIN)
 #include <io.h>
 #endif
 #include <stdio.h>
+#include <unistd.h>
 
 #include <fstream>
 
 #include "base/file_path.h"
 #include "base/logging.h"
 #include "base/string_util.h"
 
 #include "base/string_piece.h"
--- a/ipc/chromium/src/base/file_util.h
+++ b/ipc/chromium/src/base/file_util.h
@@ -7,17 +7,19 @@
 
 #ifndef BASE_FILE_UTIL_H_
 #define BASE_FILE_UTIL_H_
 
 #include "build/build_config.h"
 
 #if defined(OS_WIN)
 #include <windows.h>
-#elif defined(OS_POSIX)
+#elif defined(ANDROID)
+#include <sys/stat.h>
+#elif defined(OS_POSIX) 
 #include <fts.h>
 #include <sys/stat.h>
 #endif
 
 #include <stdio.h>
 
 #include <stack>
 #include <string>
@@ -458,16 +460,18 @@ class FileEnumerator {
 
   // A stack that keeps track of which subdirectories we still need to
   // enumerate in the breadth-first search.
   std::stack<FilePath> pending_paths_;
 
 #if defined(OS_WIN)
   WIN32_FIND_DATA find_data_;
   HANDLE find_handle_;
+#elif defined(ANDROID)
+  void *fts_;
 #elif defined(OS_POSIX)
   FTS* fts_;
   FTSENT* fts_ent_;
 #endif
 
   DISALLOW_EVIL_CONSTRUCTORS(FileEnumerator);
 };
 
--- a/ipc/chromium/src/base/file_util_linux.cc
+++ b/ipc/chromium/src/base/file_util_linux.cc
@@ -20,18 +20,22 @@ bool GetTempDir(FilePath* path) {
   if (tmp)
     *path = FilePath(tmp);
   else
     *path = FilePath("/tmp");
   return true;
 }
 
 bool GetShmemTempDir(FilePath* path) {
+#ifdef ANDROID
+  return GetTempDir(path);
+#else
   *path = FilePath("/dev/shm");
   return true;
+#endif
 }
 
 bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
   int infile = open(from_path.value().c_str(), O_RDONLY);
   if (infile < 0)
     return false;
 
   int outfile = creat(to_path.value().c_str(), 0666);
--- a/ipc/chromium/src/base/file_util_posix.cc
+++ b/ipc/chromium/src/base/file_util_posix.cc
@@ -3,17 +3,19 @@
 // found in the LICENSE file.
 
 #include "base/file_util.h"
 
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <fnmatch.h>
+#ifndef ANDROID
 #include <fts.h>
+#endif
 #include <libgen.h>
 #include <stdio.h>
 #include <string.h>
 #include <sys/errno.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <time.h>
@@ -111,16 +113,20 @@ bool Delete(const FilePath& path, bool r
     bool ret = (errno == ENOENT || errno == ENOTDIR);
     return ret;
   }
   if (!S_ISDIR(file_info.st_mode))
     return (unlink(path_str) == 0);
   if (!recursive)
     return (rmdir(path_str) == 0);
 
+#ifdef ANDROID
+  // XXX Need ftsless impl for bionic
+  return false;
+#else
   bool success = true;
   int ftsflags = FTS_PHYSICAL | FTS_NOSTAT;
   char top_dir[PATH_MAX];
   if (base::strlcpy(top_dir, path_str,
                     arraysize(top_dir)) >= arraysize(top_dir)) {
     return false;
   }
   char* dir_list[2] = { top_dir, NULL };
@@ -150,16 +156,17 @@ bool Delete(const FilePath& path, bool r
           DCHECK(false);
           break;
       }
       fts_ent = fts_read(fts);
     }
     fts_close(fts);
   }
   return success;
+#endif
 }
 
 bool Move(const FilePath& from_path, const FilePath& to_path) {
   if (rename(from_path.value().c_str(), to_path.value().c_str()) == 0)
     return true;
 
   if (!CopyDirectory(from_path, to_path, true))
     return false;
@@ -179,16 +186,20 @@ bool CopyDirectory(const FilePath& from_
   DCHECK(from_path.value().find('*') == std::string::npos);
 
   char top_dir[PATH_MAX];
   if (base::strlcpy(top_dir, from_path.value().c_str(),
                     arraysize(top_dir)) >= arraysize(top_dir)) {
     return false;
   }
 
+#ifdef ANDROID
+  // XXX Need ftsless impl for bionic
+  return false;
+#else
   char* dir_list[] = { top_dir, NULL };
   FTS* fts = fts_open(dir_list, FTS_PHYSICAL | FTS_NOSTAT, NULL);
   if (!fts) {
     LOG(ERROR) << "fts_open failed: " << strerror(errno);
     return false;
   }
 
   int error = 0;
@@ -266,16 +277,17 @@ bool CopyDirectory(const FilePath& from_
       error = errno;
   }
 
   if (error) {
     LOG(ERROR) << "CopyDirectory(): " << strerror(error);
     return false;
   }
   return true;
+#endif
 }
 
 bool PathExists(const FilePath& path) {
   struct stat64 file_info;
   return (stat64(path.value().c_str(), &file_info) == 0);
 }
 
 bool PathIsWritable(const FilePath& path) {
@@ -397,17 +409,21 @@ bool CreateNewTempDirectory(const FilePa
                             FilePath* new_temp_path) {
   FilePath tmpdir;
   if (!GetTempDir(&tmpdir))
     return false;
   tmpdir = tmpdir.Append(kTempFileName);
   std::string tmpdir_string = tmpdir.value();
   // this should be OK since mkdtemp just replaces characters in place
   char* buffer = const_cast<char*>(tmpdir_string.c_str());
+#ifdef ANDROID
+  char* dtemp = NULL;
+#else
   char* dtemp = mkdtemp(buffer);
+#endif
   if (!dtemp)
     return false;
   *new_temp_path = FilePath(dtemp);
   return true;
 }
 
 bool CreateDirectory(const FilePath& full_path) {
   std::vector<FilePath> subpaths;
@@ -523,35 +539,42 @@ FileEnumerator::FileEnumerator(const Fil
   // The Windows version of this code only matches against items in the top-most
   // directory, and we're comparing fnmatch against full paths, so this is the
   // easiest way to get the right pattern.
   pattern_ = pattern_.Append(pattern);
   pending_paths_.push(root_path);
 }
 
 FileEnumerator::~FileEnumerator() {
+#ifndef ANDROID
   if (fts_)
     fts_close(fts_);
+#endif
 }
 
 void FileEnumerator::GetFindInfo(FindInfo* info) {
   DCHECK(info);
 
   if (!is_in_find_op_)
     return;
 
+#ifndef ANDROID
   memcpy(&(info->stat), fts_ent_->fts_statp, sizeof(info->stat));
   info->filename.assign(fts_ent_->fts_name);
+#endif
 }
 
 // As it stands, this method calls itself recursively when the next item of
 // the fts enumeration doesn't match (type, pattern, etc.).  In the case of
 // large directories with many files this can be quite deep.
 // TODO(erikkay) - get rid of this recursive pattern
 FilePath FileEnumerator::Next() {
+#ifdef ANDROID
+  return FilePath();
+#else
   if (!is_in_find_op_) {
     if (pending_paths_.empty())
       return FilePath();
 
     // The last find FindFirstFile operation is done, prepare a new one.
     root_path_ = pending_paths_.top();
     root_path_ = root_path_.StripTrailingSeparators();
     pending_paths_.pop();
@@ -595,16 +618,17 @@ FilePath FileEnumerator::Next() {
     if (!recursive_)
       fts_set(fts_, fts_ent_, FTS_SKIP);
     return (file_type_ & FileEnumerator::DIRECTORIES) ? cur_file : Next();
   } else if (fts_ent_->fts_info == FTS_F) {
     return (file_type_ & FileEnumerator::FILES) ? cur_file : Next();
   }
   // TODO(erikkay) - verify that the other fts_info types aren't interesting
   return Next();
+#endif
 }
 
 ///////////////////////////////////////////////
 // MemoryMappedFile
 
 MemoryMappedFile::MemoryMappedFile()
     : file_(-1),
       data_(NULL),
--- a/ipc/chromium/src/base/message_loop.cc
+++ b/ipc/chromium/src/base/message_loop.cc
@@ -22,16 +22,19 @@
 #if defined(OS_LINUX)
 #ifdef MOZ_WIDGET_GTK2
 #include "base/message_pump_glib.h"
 #endif
 #ifdef MOZ_WIDGET_QT
 #include "base/message_pump_qt.h"
 #endif
 #endif
+#ifdef MOZ_WIDGET_ANDROID
+#include "base/message_pump_android.h"
+#endif
 
 #ifdef CHROMIUM_MOZILLA_BUILD
 #include "MessagePump.h"
 #endif
 
 using base::Time;
 using base::TimeDelta;
 
new file mode 100644
--- /dev/null
+++ b/ipc/chromium/src/base/message_pump_android.cc
@@ -0,0 +1,123 @@
+// Copyright (c) 2010 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 "base/message_pump_android.h"
+
+#include <fcntl.h>
+#include <math.h>
+
+#include "base/eintr_wrapper.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/platform_thread.h"
+
+namespace mozilla {
+bool ProcessNextEvent();
+void NotifyEvent();
+}
+
+namespace base {
+
+MessagePumpForUI::MessagePumpForUI()
+  : pump(*this)
+{
+}
+
+MessagePumpForUI::~MessagePumpForUI() {
+}
+
+MessagePumpAndroid::MessagePumpAndroid(MessagePumpForUI &aPump)
+  : pump(aPump)
+{
+}
+
+MessagePumpAndroid::~MessagePumpAndroid()
+{
+}
+
+void MessagePumpForUI::Run(Delegate* delegate) {
+  RunState state;
+  state.delegate = delegate;
+  state.should_quit = false;
+  state.run_depth = state_ ? state_->run_depth + 1 : 1;
+  // We really only do a single task for each iteration of the loop.  If we
+  // have done something, assume there is likely something more to do.  This
+  // will mean that we don't block on the message pump until there was nothing
+  // more to do.  We also set this to true to make sure not to block on the
+  // first iteration of the loop, so RunAllPending() works correctly.
+  state.more_work_is_plausible = true;
+
+  RunState* previous_state = state_;
+  state_ = &state;
+
+  // We run our own loop instead of using g_main_loop_quit in one of the
+  // callbacks.  This is so we only quit our own loops, and we don't quit
+  // nested loops run by others.  TODO(deanm): Is this what we want?
+
+  while (!state_->should_quit) {
+    mozilla::ProcessNextEvent();
+    if (work_scheduled) {
+      work_scheduled = false;
+      HandleDispatch();
+    }
+  }
+
+  state_ = previous_state;
+}
+
+void MessagePumpForUI::HandleDispatch() {
+  // We should only ever have a single message on the wakeup pipe, since we
+  // are only signaled when the queue went from empty to non-empty.  The qApp
+  // poll will tell us whether there was data, so this read shouldn't block.
+  if (state_->should_quit)
+    return;
+
+  state_->more_work_is_plausible = false;
+
+  if (state_->delegate->DoWork())
+    state_->more_work_is_plausible = true;
+
+  if (state_->should_quit)
+    return;
+
+  if (state_->delegate->DoDelayedWork(&delayed_work_time_))
+    state_->more_work_is_plausible = true;
+  if (state_->should_quit)
+    return;
+
+  // Don't do idle work if we think there are more important things
+  // that we could be doing.
+  if (state_->more_work_is_plausible)
+    return;
+
+  if (state_->delegate->DoIdleWork())
+    state_->more_work_is_plausible = true;
+  if (state_->should_quit)
+    return;
+}
+
+void MessagePumpForUI::Quit() {
+  if (state_) {
+    state_->should_quit = true;
+  } else {
+    NOTREACHED() << "Quit called outside Run!";
+  }
+}
+
+void MessagePumpForUI::ScheduleWork() {
+  // This can be called on any thread, so we don't want to touch any state
+  // variables as we would then need locks all over.  This ensures that if
+  // we are sleeping in a poll that we will wake up.
+  work_scheduled = true;
+  mozilla::NotifyEvent();
+}
+
+void MessagePumpForUI::ScheduleDelayedWork(const Time& delayed_work_time) {
+  // We need to wake up the loop in case the poll timeout needs to be
+  // adjusted.  This will cause us to try to do work, but that's ok.
+  delayed_work_time_ = delayed_work_time;
+  ScheduleWork();
+}
+
+}  // namespace base
new file mode 100644
--- /dev/null
+++ b/ipc/chromium/src/base/message_pump_android.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2010 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.
+
+#ifndef BASE_MESSAGE_PUMP_ANDROID_H_
+#define BASE_MESSAGE_PUMP_ANDROID_H_
+
+#include "base/message_pump.h"
+#include "base/time.h"
+
+namespace base {
+
+class MessagePumpForUI;
+
+class MessagePumpAndroid {
+
+ public:
+  MessagePumpAndroid(MessagePumpForUI &pump);
+  ~MessagePumpAndroid();
+
+ private:
+  base::MessagePumpForUI &pump;
+};
+
+// This class implements a MessagePump needed for TYPE_UI MessageLoops on
+// Android
+class MessagePumpForUI : public MessagePump {
+
+ public:
+  MessagePumpForUI();
+  ~MessagePumpForUI();
+
+  virtual void Run(Delegate* delegate);
+  virtual void Quit();
+  virtual void ScheduleWork();
+  virtual void ScheduleDelayedWork(const Time& delayed_work_time);
+
+  // Internal methods used for processing the pump callbacks.  They are
+  // public for simplicity but should not be used directly.
+  // HandleDispatch is called after the poll has completed.
+  void HandleDispatch();
+
+ private:
+  // We may make recursive calls to Run, so we save state that needs to be
+  // separate between them in this structure type.
+  struct RunState {
+    Delegate* delegate;
+
+    // Used to flag that the current Run() invocation should return ASAP.
+    bool should_quit;
+
+    // Used to count how many Run() invocations are on the stack.
+    int run_depth;
+
+    // Used internally for controlling whether we want a message pump
+    // iteration to be blocking or not.
+    bool more_work_is_plausible;
+  };
+
+  RunState* state_;
+
+  // This is the time when we need to do delayed work.
+  Time delayed_work_time_;
+
+  bool work_scheduled;
+
+  // MessagePump implementation for Android based on the GLib implement.
+  MessagePumpAndroid pump;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpForUI);
+};
+
+}  // namespace base
+
+#endif  // BASE_MESSAGE_PUMP_ANDROID_H_
--- a/ipc/chromium/src/base/platform_file_posix.cc
+++ b/ipc/chromium/src/base/platform_file_posix.cc
@@ -1,16 +1,19 @@
 // Copyright (c) 2006-2008 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 "base/platform_file.h"
 
 #include <fcntl.h>
 #include <errno.h>
+#ifdef ANDROID
+#include <linux/stat.h>
+#endif
 
 #include "base/logging.h"
 #include "base/string_util.h"
 
 namespace base {
 
 // TODO(erikkay): does it make sense to support PLATFORM_FILE_EXCLUSIVE_* here?
 PlatformFile CreatePlatformFile(const std::wstring& name,
--- a/ipc/chromium/src/base/process_util_posix.cc
+++ b/ipc/chromium/src/base/process_util_posix.cc
@@ -92,16 +92,20 @@ class ScopedDIRClose {
   inline void operator()(DIR* x) const {
     if (x) {
       closedir(x);
     }
   }
 };
 typedef scoped_ptr_malloc<DIR, ScopedDIRClose> ScopedDIR;
 
+#ifdef ANDROID
+typedef unsigned long int rlim_t;
+#endif
+
 void CloseSuperfluousFds(const base::InjectiveMultimap& saved_mapping) {
 #if defined(OS_LINUX)
   static const rlim_t kSystemDefaultMaxFds = 8192;
   static const char fd_dir[] = "/proc/self/fd";
 #elif defined(OS_MACOSX)
   static const rlim_t kSystemDefaultMaxFds = 256;
   static const char fd_dir[] = "/dev/fd";
 #endif
--- a/ipc/chromium/src/base/shared_memory_posix.cc
+++ b/ipc/chromium/src/base/shared_memory_posix.cc
@@ -281,16 +281,49 @@ void SharedMemory::Close() {
   Unmap();
 
   if (mapped_file_ > 0) {
     close(mapped_file_);
     mapped_file_ = -1;
   }
 }
 
+#ifdef ANDROID
+void SharedMemory::LockOrUnlockCommon(int function) {
+  DCHECK(mapped_file_ >= 0);
+  struct flock lockreq;
+  lockreq.l_type = function;
+  lockreq.l_whence = SEEK_SET;
+  lockreq.l_start = 0;
+  lockreq.l_len = 0;
+  while (fcntl(mapped_file_, F_SETLKW, &lockreq) < 0) {
+    if (errno == EINTR) {
+      continue;
+    } else if (errno == ENOLCK) {
+      // temporary kernel resource exaustion
+      PlatformThread::Sleep(500);
+      continue;
+    } else {
+      NOTREACHED() << "lockf() failed."
+                   << " function:" << function
+                   << " fd:" << mapped_file_
+                   << " errno:" << errno
+                   << " msg:" << strerror(errno);
+    }
+  }
+}
+
+void SharedMemory::Lock() {
+  LockOrUnlockCommon(F_WRLCK);
+}
+
+void SharedMemory::Unlock() {
+  LockOrUnlockCommon(F_UNLCK);
+}
+#else
 void SharedMemory::LockOrUnlockCommon(int function) {
   DCHECK(mapped_file_ >= 0);
   while (lockf(mapped_file_, function, 0) < 0) {
     if (errno == EINTR) {
       continue;
     } else if (errno == ENOLCK) {
       // temporary kernel resource exaustion
       PlatformThread::Sleep(500);
@@ -307,14 +340,15 @@ void SharedMemory::LockOrUnlockCommon(in
 
 void SharedMemory::Lock() {
   LockOrUnlockCommon(F_LOCK);
 }
 
 void SharedMemory::Unlock() {
   LockOrUnlockCommon(F_ULOCK);
 }
+#endif
 
 SharedMemoryHandle SharedMemory::handle() const {
   return FileDescriptor(mapped_file_, false);
 }
 
 }  // namespace base
--- a/ipc/chromium/src/base/sys_info_posix.cc
+++ b/ipc/chromium/src/base/sys_info_posix.cc
@@ -2,17 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/sys_info.h"
 #include "base/basictypes.h"
 
 #include <errno.h>
 #include <string.h>
+#ifndef ANDROID
 #include <sys/statvfs.h>
+#endif
 #include <sys/utsname.h>
 #include <unistd.h>
 
 #if defined(OS_MACOSX)
 #include <mach/mach_host.h>
 #include <mach/mach_init.h>
 #endif
 
@@ -59,21 +61,25 @@ int64 SysInfo::AmountOfPhysicalMemory() 
   }
 
   return static_cast<int64>(pages) * page_size;
 #endif
 }
 
 // static
 int64 SysInfo::AmountOfFreeDiskSpace(const std::wstring& path) {
+#ifndef ANDROID
   struct statvfs stats;
   if (statvfs(WideToUTF8(path).c_str(), &stats) != 0) {
     return -1;
   }
   return static_cast<int64>(stats.f_bavail) * stats.f_frsize;
+#else
+  return -1;
+#endif
 }
 
 // static
 bool SysInfo::HasEnvVar(const wchar_t* var) {
   std::string var_utf8 = WideToUTF8(std::wstring(var));
   return getenv(var_utf8.c_str()) != NULL;
 }
 
--- a/ipc/chromium/src/base/third_party/nspr/prcpucfg.h
+++ b/ipc/chromium/src/base/third_party/nspr/prcpucfg.h
@@ -29,15 +29,15 @@
 
 #ifndef BASE_THIRD_PARTY_NSPR_PRCPUCFG_H__
 #define BASE_THIRD_PARTY_NSPR_PRCPUCFG_H__
 
 #if defined(WIN32)
 #include "base/third_party/nspr/prcpucfg_win.h"
 #elif defined(__APPLE__)
 #include "base/third_party/nspr/prcpucfg_mac.h"
-#elif defined(__linux__)
+#elif defined(__linux__) || defined(ANDROID)
 #include "base/third_party/nspr/prcpucfg_linux.h"
 #else
 #error Provide a prcpucfg.h appropriate for your platform
 #endif
 
 #endif  // BASE_THIRD_PARTY_NSPR_PRCPUCFG_H__
--- a/ipc/chromium/src/base/third_party/nspr/prtime.cc
+++ b/ipc/chromium/src/base/third_party/nspr/prtime.cc
@@ -78,16 +78,35 @@ namespace nspr {
 
 /* Implements the Unix localtime_r() function for windows */
 #if defined(OS_WIN)
 static void localtime_r(const time_t* secs, struct tm* time) {
   (void) localtime_s(time, secs);
 }
 #endif
 
+/* 
+ * The COUNT_LEAPS macro counts the number of leap years passed by
+ * till the start of the given year Y.  At the start of the year 4
+ * A.D. the number of leap years passed by is 0, while at the start of
+ * the year 5 A.D. this count is 1. The number of years divisible by
+ * 100 but not divisible by 400 (the non-leap years) is deducted from
+ * the count to get the correct number of leap years.
+ *
+ * The COUNT_DAYS macro counts the number of days since 01/01/01 till the
+ * start of the given year Y. The number of days at the start of the year
+ * 1 is 0 while the number of days at the start of the year 2 is 365
+ * (which is ((2)-1) * 365) and so on. The reference point is 01/01/01
+ * midnight 00:00:00.
+ */
+
+#define COUNT_LEAPS(Y)   ( ((Y)-1)/4 - ((Y)-1)/100 + ((Y)-1)/400 )
+#define COUNT_DAYS(Y)  ( ((Y)-1)*365 + COUNT_LEAPS(Y) )
+#define DAYS_BETWEEN_YEARS(A, B)  (COUNT_DAYS(B) - COUNT_DAYS(A))
+
 /*
  *------------------------------------------------------------------------
  *
  * PR_ImplodeTime --
  *
  *     Cf. time_t mktime(struct tm *tp)
  *     Note that 1 year has < 2^25 seconds.  So an PRInt32 is large enough.
  *
@@ -146,16 +165,55 @@ PR_ImplodeTime(const PRExplodedTime *exp
         CFGregorianDateGetAbsoluteTime(gregorian_date, NULL);
     PRTime result = static_cast<PRTime>(absolute_time);
     result -= exploded->tm_params.tp_gmt_offset +
               exploded->tm_params.tp_dst_offset;
     result += kCFAbsoluteTimeIntervalSince1970;  // PRTime epoch is 1970
     result *= kSecondsToMicroseconds;
     result += exploded->tm_usec;
     return result;
+#elif defined(ANDROID)
+#define LL_ADD(r, a, b)     ((r) = (a) + (b))
+#define LL_SUB(r, a, b)     ((r) = (a) - (b))
+
+    PRExplodedTime copy;
+    PRTime retVal;
+    PRInt64 secPerDay, usecPerSec;
+    PRInt64 temp;
+    PRInt64 numSecs64;
+    PRInt32 numDays;
+    PRInt32 numSecs;
+
+    /* Normalize first.  Do this on our copy */
+    copy = *exploded;
+    PR_NormalizeTime(&copy, PR_GMTParameters);
+
+    numDays = DAYS_BETWEEN_YEARS(1970, copy.tm_year);
+
+    numSecs = copy.tm_yday * 86400 + copy.tm_hour * 3600
+            + copy.tm_min * 60 + copy.tm_sec;
+
+    LL_I2L(temp, numDays);
+    LL_I2L(secPerDay, 86400);
+    LL_MUL(temp, temp, secPerDay);
+    LL_I2L(numSecs64, numSecs);
+    LL_ADD(numSecs64, numSecs64, temp);
+
+    /* apply the GMT and DST offsets */
+    LL_I2L(temp,  copy.tm_params.tp_gmt_offset);
+    LL_SUB(numSecs64, numSecs64, temp);
+    LL_I2L(temp,  copy.tm_params.tp_dst_offset);
+    LL_SUB(numSecs64, numSecs64, temp);
+
+    LL_I2L(usecPerSec, 1000000L);
+    LL_MUL(temp, numSecs64, usecPerSec);
+    LL_I2L(retVal, copy.tm_usec);
+    LL_ADD(retVal, retVal, temp);
+
+    return retVal;
 #elif defined(OS_LINUX)
     struct tm exp_tm = {0};
     exp_tm.tm_sec  = exploded->tm_sec;
     exp_tm.tm_min  = exploded->tm_min;
     exp_tm.tm_hour = exploded->tm_hour;
     exp_tm.tm_mday = exploded->tm_mday;
     exp_tm.tm_mon  = exploded->tm_month;
     exp_tm.tm_year = exploded->tm_year - 1900;
@@ -184,35 +242,16 @@ PR_ImplodeTime(const PRExplodedTime *exp
     result *= kSecondsToMicroseconds;
     result += exploded->tm_usec;
     return result;
 #else
 #error No PR_ImplodeTime implemented on your platform.
 #endif
 }
 
-/* 
- * The COUNT_LEAPS macro counts the number of leap years passed by
- * till the start of the given year Y.  At the start of the year 4
- * A.D. the number of leap years passed by is 0, while at the start of
- * the year 5 A.D. this count is 1. The number of years divisible by
- * 100 but not divisible by 400 (the non-leap years) is deducted from
- * the count to get the correct number of leap years.
- *
- * The COUNT_DAYS macro counts the number of days since 01/01/01 till the
- * start of the given year Y. The number of days at the start of the year
- * 1 is 0 while the number of days at the start of the year 2 is 365
- * (which is ((2)-1) * 365) and so on. The reference point is 01/01/01
- * midnight 00:00:00.
- */
-
-#define COUNT_LEAPS(Y)   ( ((Y)-1)/4 - ((Y)-1)/100 + ((Y)-1)/400 )
-#define COUNT_DAYS(Y)  ( ((Y)-1)*365 + COUNT_LEAPS(Y) )
-#define DAYS_BETWEEN_YEARS(A, B)  (COUNT_DAYS(B) - COUNT_DAYS(A))
-
 /*
  * Static variables used by functions in this file
  */
 
 /*
  * The following array contains the day of year for the last day of
  * each month, where index 1 is January, and day 0 is January 1.
  */
--- a/ipc/chromium/src/base/time_posix.cc
+++ b/ipc/chromium/src/base/time_posix.cc
@@ -3,17 +3,21 @@
 // found in the LICENSE file.
 
 #include "base/time.h"
 
 #ifdef OS_MACOSX
 #include <mach/mach_time.h>
 #endif
 #include <sys/time.h>
+#ifdef ANDROID
+#include <time64.h>
+#else
 #include <time.h>
+#endif
 
 #include <limits>
 
 #include "base/basictypes.h"
 #include "base/logging.h"
 
 namespace base {
 
@@ -57,20 +61,24 @@ Time Time::FromExploded(bool is_local, c
   timestruct.tm_year   = exploded.year - 1900;
   timestruct.tm_wday   = exploded.day_of_week;  // mktime/timegm ignore this
   timestruct.tm_yday   = 0;     // mktime/timegm ignore this
   timestruct.tm_isdst  = -1;    // attempt to figure it out
   timestruct.tm_gmtoff = 0;     // not a POSIX field, so mktime/timegm ignore
   timestruct.tm_zone   = NULL;  // not a POSIX field, so mktime/timegm ignore
 
   time_t seconds;
+#ifdef ANDROID
+    seconds = mktime(&timestruct);
+#else
   if (is_local)
     seconds = mktime(&timestruct);
   else
     seconds = timegm(&timestruct);
+#endif
 
   int64 milliseconds;
   // Handle overflow.  Clamping the range to what mktime and timegm might
   // return is the best that can be done here.  It's not ideal, but it's better
   // than failing here or ignoring the overflow case and treating each time
   // overflow as one second prior to the epoch.
   if (seconds == -1 &&
       (exploded.year < 1969 || exploded.year > 1970)) {
--- a/ipc/chromium/src/build/build_config.h
+++ b/ipc/chromium/src/build/build_config.h
@@ -12,17 +12,17 @@
 //    ARCH_CPU_32_BITS / ARCH_CPU_64_BITS
 
 #ifndef BUILD_BUILD_CONFIG_H_
 #define BUILD_BUILD_CONFIG_H_
 
 // A set of macros to use for platform detection.
 #if defined(__APPLE__)
 #define OS_MACOSX 1
-#elif defined(__linux__)
+#elif defined(__linux__) || defined(ANDROID)
 #define OS_LINUX 1
 #elif defined(_WIN32)
 #define OS_WIN 1
 #else
 #error Please add support for your platform in build/build_config.h
 #endif
 
 // For access to standard POSIX features, use OS_POSIX instead of a more
--- a/ipc/chromium/src/chrome/common/file_descriptor_set_posix.cc
+++ b/ipc/chromium/src/chrome/common/file_descriptor_set_posix.cc
@@ -2,16 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "chrome/common/file_descriptor_set_posix.h"
 
 #include "base/eintr_wrapper.h"
 #include "base/logging.h"
 
+#include <unistd.h>
+
 FileDescriptorSet::FileDescriptorSet()
     : consumed_descriptor_highwater_(0) {
 }
 
 FileDescriptorSet::~FileDescriptorSet() {
   if (consumed_descriptor_highwater_ == descriptors_.size())
     return;
 
--- a/ipc/chromium/src/third_party/libevent/select.c
+++ b/ipc/chromium/src/third_party/libevent/select.c
@@ -54,16 +54,20 @@
 #include "event-internal.h"
 #include "evsignal.h"
 #include "log.h"
 
 #ifndef howmany
 #define        howmany(x, y)   (((x)+((y)-1))/(y))
 #endif
 
+#ifdef ANDROID
+typedef unsigned long int fd_mask;
+#endif
+
 struct selectop {
 	int event_fds;		/* Highest fd in fd set */
 	int event_fdsz;
 	fd_set *event_readset_in;
 	fd_set *event_writeset_in;
 	fd_set *event_readset_out;
 	fd_set *event_writeset_out;
 	struct event **event_r_by_fd;
--- a/ipc/glue/GeckoChildProcessHost.cpp
+++ b/ipc/glue/GeckoChildProcessHost.cpp
@@ -50,16 +50,17 @@
 #  define XP_LINUX 1
 #endif
 #include "nsExceptionHandler.h"
 
 #include "nsDirectoryServiceDefs.h"
 #include "nsIFile.h"
 
 #include "mozilla/ipc/BrowserProcessSubThread.h"
+#include <sys/stat.h>
 
 #ifdef XP_WIN
 #include "nsIWinTaskbar.h"
 #define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
 #endif
 
 using mozilla::MonitorAutoEnter;
 using mozilla::ipc::GeckoChildProcessHost;
@@ -192,25 +193,33 @@ GeckoChildProcessHost::PerformAsyncLaunc
   nsCOMPtr<nsIProperties> directoryService(do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID));
   nsCOMPtr<nsIFile> greDir;
   nsresult rv = directoryService->Get(NS_GRE_DIR, NS_GET_IID(nsIFile), getter_AddRefs(greDir));
   if (NS_SUCCEEDED(rv)) {
     nsCString path;
     greDir->GetNativePath(path);
     exePath = FilePath(path.get());
 #ifdef OS_LINUX
+#ifdef ANDROID
+    path += "/lib";
+#endif
     newEnvVars["LD_LIBRARY_PATH"] = path.get();
 #endif
   }
   else {
     exePath = FilePath(CommandLine::ForCurrentProcess()->argv()[0]);
     exePath = exePath.DirName();
   }
   exePath = exePath.AppendASCII(MOZ_CHILD_PROCESS_NAME);
 
+#ifdef ANDROID
+  // The java wrapper unpacks this for us but can't make it executable
+  chmod(exePath.value().c_str(), 0700);
+#endif
+
   // remap the IPC socket fd to a well-known int, as the OS does for
   // STDOUT_FILENO, for example
   int srcChannelFd, dstChannelFd;
   channel().GetClientFileDescriptorMapping(&srcChannelFd, &dstChannelFd);
   mFileMap.push_back(std::pair<int,int>(srcChannelFd, dstChannelFd));
 
   // no need for kProcessChannelID, the child process inherits the
   // other end of the socketpair() from us
--- a/ipc/glue/SharedMemorySysV.h
+++ b/ipc/glue/SharedMemorySysV.h
@@ -35,17 +35,17 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_ipc_SharedMemorySysV_h
 #define mozilla_ipc_SharedMemorySysV_h
 
-#ifdef OS_LINUX
+#if defined(OS_LINUX) && !defined(ANDROID)
 
 // SysV shared memory isn't available on Windows, but we define the
 // following macro so that #ifdefs are clearer (compared to #ifdef
 // OS_LINUX).
 #define MOZ_HAVE_SHAREDMEMORYSYSV
 
 #include "SharedMemory.h"