py2to3: update tools/android/*.py to PY3

Details:
- use six.ensure_str / six.ensure_bytes
- use absl.flags instead of gflags
- put third_party/py/abseil:srcs into @bazel_tools
  so the embedded Android tools can also use it
- remove python_version = "PY2" from py_binary and
  py_test rules (the default is "PY3"), except in
  BUILD.tools, to preserve PY2 compatibility for
  running Bazel (its embedded Python tools)
- added srcs_version = "PY2AND3" to BUILD.tools to
  make it explicit that these libraries are meant
  to be py2 and py3 compatible

See https://github.com/bazelbuild/bazel/issues/10127

PiperOrigin-RevId: 278320319
diff --git a/src/BUILD b/src/BUILD
index 9a8fa0c1..4831949 100644
--- a/src/BUILD
+++ b/src/BUILD
@@ -127,7 +127,10 @@
                "//third_party/ijar:embedded_zipper_sources",
                "//third_party/ijar:zipper",
                "//third_party/java/j2objc:embedded_tools_srcs",
+               "//third_party/py/abseil:srcs",
                "//third_party/py/concurrent:srcs",
+               # TODO(laszlocsomor): delete "//third_party/py/gflags:srcs" after
+               # every script in @bazel_tools was migrated to use Abseil.
                "//third_party/py/gflags:srcs",
                "//third_party/py/six:srcs",
                "//src/conditions:embedded_tools",
diff --git a/tools/android/BUILD b/tools/android/BUILD
index d9ff665..44b782e 100644
--- a/tools/android/BUILD
+++ b/tools/android/BUILD
@@ -1,11 +1,10 @@
-load("//tools/python:private/defs.bzl", "py_library", "py_binary", "py_test")
+load("//tools/python:private/defs.bzl", "py_binary", "py_library", "py_test")
 
 package(default_visibility = ["//tools:__pkg__"])
 
 py_binary(
     name = "build_incremental_dexmanifest",
     srcs = [":build_incremental_dexmanifest.py"],
-    python_version = "PY2",
 )
 
 sh_test(
@@ -27,16 +26,14 @@
 py_binary(
     name = "build_split_manifest",
     srcs = ["build_split_manifest.py"],
-    python_version = "PY2",
     deps = [
-        "//third_party/py/gflags",
+        "//third_party/py/abseil",
     ],
 )
 
 py_test(
     name = "build_split_manifest_test",
     srcs = ["build_split_manifest_test.py"],
-    python_version = "PY2",
     deps = [
         ":build_split_manifest",
     ],
@@ -45,17 +42,15 @@
 py_binary(
     name = "incremental_install",
     srcs = ["incremental_install.py"],
-    python_version = "PY2",
     deps = [
+        "//third_party/py/abseil",
         "//third_party/py/concurrent:futures",
-        "//third_party/py/gflags",
     ],
 )
 
 py_test(
     name = "incremental_install_test",
     srcs = ["incremental_install_test.py"],
-    python_version = "PY2",
     tags = [
         # TODO(laszlocsomor): fix on Windows or describe why it cannot pass.
         "no_windows",
@@ -69,8 +64,7 @@
 py_binary(
     name = "strip_resources",
     srcs = ["strip_resources.py"],
-    python_version = "PY2",
-    deps = ["//third_party/py/gflags"],
+    deps = ["//third_party/py/abseil"],
 )
 
 sh_test(
@@ -92,10 +86,9 @@
     srcs = [
         "aar_native_libs_zip_creator.py",
     ],
-    python_version = "PY2",
     deps = [
         ":junction_lib",
-        "//third_party/py/gflags",
+        "//third_party/py/abseil",
     ],
 )
 
@@ -104,7 +97,6 @@
     srcs = [
         "aar_native_libs_zip_creator_test.py",
     ],
-    python_version = "PY2",
     deps = [
         ":aar_native_libs_zip_creator",
     ],
@@ -113,16 +105,14 @@
 py_binary(
     name = "stubify_manifest",
     srcs = ["stubify_manifest.py"],
-    python_version = "PY2",
     deps = [
-        "//third_party/py/gflags",
+        "//third_party/py/abseil",
     ],
 )
 
 py_test(
     name = "stubify_manifest_test",
     srcs = ["stubify_manifest_test.py"],
-    python_version = "PY2",
     deps = [
         ":stubify_manifest",
     ],
@@ -131,61 +121,53 @@
 py_binary(
     name = "aar_embedded_jars_extractor",
     srcs = ["aar_embedded_jars_extractor.py"],
-    python_version = "PY2",
     deps = [
         ":junction_lib",
-        "//third_party/py/gflags",
+        "//third_party/py/abseil",
     ],
 )
 
 py_test(
     name = "aar_embedded_jars_extractor_test",
     srcs = ["aar_embedded_jars_extractor_test.py"],
-    python_version = "PY2",
     deps = [":aar_embedded_jars_extractor"],
 )
 
 py_binary(
     name = "aar_resources_extractor",
     srcs = ["aar_resources_extractor.py"],
-    python_version = "PY2",
     deps = [
         ":junction_lib",
-        "//third_party/py/gflags",
+        "//third_party/py/abseil",
     ],
 )
 
 py_test(
     name = "aar_resources_extractor_test",
     srcs = ["aar_resources_extractor_test.py"],
-    python_version = "PY2",
     deps = [":aar_resources_extractor"],
 )
 
 py_binary(
     name = "resource_extractor",
     srcs = ["resource_extractor.py"],
-    python_version = "PY2",
 )
 
 py_test(
     name = "resource_extractor_test",
     srcs = ["resource_extractor_test.py"],
-    python_version = "PY2",
     deps = [":resource_extractor"],
 )
 
 py_binary(
     name = "instrumentation_test_check",
     srcs = ["instrumentation_test_check.py"],
-    python_version = "PY2",
-    deps = ["//third_party/py/gflags"],
+    deps = ["//third_party/py/abseil"],
 )
 
 py_test(
     name = "instrumentation_test_check_test",
     srcs = ["instrumentation_test_check_test.py"],
-    python_version = "PY2",
     deps = [":instrumentation_test_check"],
 )
 
@@ -205,7 +187,6 @@
         "//src/conditions:windows": "junction_test.py",
         "//conditions:default": "dummy_test.py",
     }),
-    python_version = "PY2",
     deps = [
         ":junction_lib",
         "//src/test/py/bazel:test_base",
diff --git a/tools/android/BUILD.tools b/tools/android/BUILD.tools
index 4f5fc70..02adb46 100644
--- a/tools/android/BUILD.tools
+++ b/tools/android/BUILD.tools
@@ -216,13 +216,15 @@
 py_binary(
     name = "instrumentation_test_check",
     srcs = ["instrumentation_test_check.py"],
+    # TODO(bazel-team): remove python_version = "PY2" while fixing https://github.com/bazelbuild/bazel/issues/10127.
     python_version = "PY2",
-    deps = ["//third_party/py/gflags"],
+    deps = ["//third_party/py/abseil"],
 )
 
 py_binary(
     name = "build_incremental_dexmanifest",
     srcs = [":build_incremental_dexmanifest.py"],
+    # TODO(bazel-team): remove python_version = "PY2" while fixing https://github.com/bazelbuild/bazel/issues/10127.
     python_version = "PY2",
     deps = [],
 )
@@ -230,28 +232,31 @@
 py_binary(
     name = "build_split_manifest",
     srcs = ["build_split_manifest.py"],
+    # TODO(bazel-team): remove python_version = "PY2" while fixing https://github.com/bazelbuild/bazel/issues/10127.
     python_version = "PY2",
     deps = [
-        "//third_party/py/gflags",
+        "//third_party/py/abseil",
     ],
 )
 
 py_binary(
     name = "incremental_install",
     srcs = ["incremental_install.py"],
+    # TODO(bazel-team): remove python_version = "PY2" while fixing https://github.com/bazelbuild/bazel/issues/10127.
     python_version = "PY2",
     deps = [
         "//third_party/py/concurrent:futures",
-        "//third_party/py/gflags",
+        "//third_party/py/abseil",
     ],
 )
 
 py_binary(
     name = "strip_resources",
     srcs = ["strip_resources.py"],
+    # TODO(bazel-team): remove python_version = "PY2" while fixing https://github.com/bazelbuild/bazel/issues/10127.
     python_version = "PY2",
     deps = [
-        "//third_party/py/gflags",
+        "//third_party/py/abseil",
     ],
 )
 
@@ -260,51 +265,58 @@
     srcs = [
         "aar_native_libs_zip_creator.py",
     ],
+    # TODO(bazel-team): remove python_version = "PY2" while fixing https://github.com/bazelbuild/bazel/issues/10127.
     python_version = "PY2",
     deps = [
         ":junction_lib",
-        "//third_party/py/gflags",
+        "//third_party/py/abseil",
     ],
 )
 
 py_binary(
     name = "stubify_manifest",
     srcs = ["stubify_manifest.py"],
+    # TODO(bazel-team): remove python_version = "PY2" while fixing https://github.com/bazelbuild/bazel/issues/10127.
     python_version = "PY2",
     deps = [
-        "//third_party/py/gflags",
+        "//third_party/py/abseil",
     ],
 )
 
 py_binary(
     name = "aar_embedded_jars_extractor",
     srcs = ["aar_embedded_jars_extractor.py"],
+    # TODO(bazel-team): remove python_version = "PY2" while fixing https://github.com/bazelbuild/bazel/issues/10127.
     python_version = "PY2",
     deps = [
         ":junction_lib",
-        "//third_party/py/gflags",
+        "//third_party/py/abseil",
     ],
 )
 
 py_binary(
     name = "aar_resources_extractor",
     srcs = ["aar_resources_extractor.py"],
+    # TODO(bazel-team): remove python_version = "PY2" while fixing https://github.com/bazelbuild/bazel/issues/10127.
     python_version = "PY2",
     deps = [
         ":junction_lib",
-        "//third_party/py/gflags",
+        "//third_party/py/abseil",
     ],
 )
 
 py_binary(
     name = "resource_extractor",
     srcs = ["resource_extractor.py"],
+    # TODO(bazel-team): remove python_version = "PY2" while fixing https://github.com/bazelbuild/bazel/issues/10127.
     python_version = "PY2",
 )
 
 py_library(
     name = "junction_lib",
     srcs = ["junction.py"],
+    # TODO(bazel-team): remove srcs_version = "PY2AND3" while fixing https://github.com/bazelbuild/bazel/issues/10127.
+    srcs_version = "PY2AND3",
     visibility = ["//visibility:private"],
 )
 
diff --git a/tools/android/aar_embedded_jars_extractor.py b/tools/android/aar_embedded_jars_extractor.py
index 2fa85b6..d1b51b1 100644
--- a/tools/android/aar_embedded_jars_extractor.py
+++ b/tools/android/aar_embedded_jars_extractor.py
@@ -1,3 +1,4 @@
+# Lint as: python2, python3
 # pylint: disable=g-direct-third-party-import
 # Copyright 2016 The Bazel Authors. All rights reserved.
 #
@@ -19,23 +20,30 @@
 of the jars and creates a param file for singlejar to merge them into one jar.
 """
 
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
 import os
 import re
 import sys
 import zipfile
 
+from absl import app
+from absl import flags
+import six
+
 from tools.android import junction
-from third_party.py import gflags
 
-FLAGS = gflags.FLAGS
+FLAGS = flags.FLAGS
 
-gflags.DEFINE_string("input_aar", None, "Input AAR")
-gflags.MarkFlagAsRequired("input_aar")
-gflags.DEFINE_string(
-    "output_singlejar_param_file", None, "Output parameter file for singlejar")
-gflags.MarkFlagAsRequired("output_singlejar_param_file")
-gflags.DEFINE_string("output_dir", None, "Output directory to extract jars in")
-gflags.MarkFlagAsRequired("output_dir")
+flags.DEFINE_string("input_aar", None, "Input AAR")
+flags.mark_flag_as_required("input_aar")
+flags.DEFINE_string("output_singlejar_param_file", None,
+                    "Output parameter file for singlejar")
+flags.mark_flag_as_required("output_singlejar_param_file")
+flags.DEFINE_string("output_dir", None, "Output directory to extract jars in")
+flags.mark_flag_as_required("output_dir")
 
 
 def ExtractEmbeddedJars(aar,
@@ -52,7 +60,7 @@
       # output_dir may be a temporary junction, so write the original
       # (unshortened) path to the params file
       singlejar_param_file.write(
-          (output_dir_orig + "/" + name + "\n").encode("utf-8"))
+          six.ensure_binary((output_dir_orig + "/" + name + "\n"), "utf-8"))
       aar.extract(name, output_dir)
 
 
@@ -68,7 +76,7 @@
                           output_dir_orig)
 
 
-def main():
+def main(unused_argv):
   if os.name == "nt":
     # Shorten paths unconditionally, because the extracted paths in
     # ExtractEmbeddedJars (which we cannot yet predict, because they depend on
@@ -90,4 +98,4 @@
 
 if __name__ == "__main__":
   FLAGS(sys.argv)
-  main()
+  app.run(main)
diff --git a/tools/android/aar_native_libs_zip_creator.py b/tools/android/aar_native_libs_zip_creator.py
index 0348418..8a4490b 100644
--- a/tools/android/aar_native_libs_zip_creator.py
+++ b/tools/android/aar_native_libs_zip_creator.py
@@ -1,3 +1,4 @@
+# Lint as: python2, python3
 # pylint: disable=g-direct-third-party-import
 # Copyright 2016 The Bazel Authors. All rights reserved.
 #
@@ -20,6 +21,8 @@
 directory structure of /lib/<cpu>/foo.so.
 """
 
+from __future__ import absolute_import
+from __future__ import division
 from __future__ import print_function
 
 import os
@@ -27,17 +30,20 @@
 import sys
 import zipfile
 
+from absl import app
+from absl import flags
+import six
+
 from tools.android import junction
-from third_party.py import gflags
 
-FLAGS = gflags.FLAGS
+FLAGS = flags.FLAGS
 
-gflags.DEFINE_string("input_aar", None, "Input AAR")
-gflags.MarkFlagAsRequired("input_aar")
-gflags.DEFINE_string("cpu", None, "CPU architecture to include")
-gflags.MarkFlagAsRequired("cpu")
-gflags.DEFINE_string("output_zip", None, "Output ZIP of native libs")
-gflags.MarkFlagAsRequired("output_zip")
+flags.DEFINE_string("input_aar", None, "Input AAR")
+flags.mark_flag_as_required("input_aar")
+flags.DEFINE_string("cpu", None, "CPU architecture to include")
+flags.mark_flag_as_required("cpu")
+flags.DEFINE_string("output_zip", None, "Output ZIP of native libs")
+flags.mark_flag_as_required("output_zip")
 
 
 class UnsupportedArchitectureException(Exception):
@@ -48,7 +54,7 @@
 def CreateNativeLibsZip(aar, cpu, native_libs_zip):
   native_lib_pattern = re.compile("^jni/.+/.+\\.so$")
   if any(native_lib_pattern.match(filename) for filename in aar.namelist()):
-    cpu_pattern = re.compile("^jni/" + cpu + "/.+\\.so$")
+    cpu_pattern = re.compile("^jni/" + six.ensure_str(cpu) + "/.+\\.so$")
     libs = [name for name in aar.namelist() if cpu_pattern.match(name)]
     if not libs:
       raise UnsupportedArchitectureException()
@@ -65,12 +71,13 @@
       try:
         CreateNativeLibsZip(input_aar, cpu, native_libs_zip)
       except UnsupportedArchitectureException:
-        print("AAR " + input_aar_path_for_error_msg +
-              " missing native libs for requested architecture: " + cpu)
+        print("AAR " + six.ensure_str(input_aar_path_for_error_msg) +
+              " missing native libs for requested architecture: " +
+              six.ensure_str(cpu))
         sys.exit(1)
 
 
-def main():
+def main(unused_argv):
   if os.name == "nt":
     with junction.TempJunction(os.path.dirname(FLAGS.input_aar)) as j_in:
       with junction.TempJunction(os.path.dirname(FLAGS.output_zip)) as j_out:
@@ -84,4 +91,4 @@
 
 if __name__ == "__main__":
   FLAGS(sys.argv)
-  main()
+  app.run(main)
diff --git a/tools/android/aar_resources_extractor.py b/tools/android/aar_resources_extractor.py
index b4c8577..c29e5f4 100644
--- a/tools/android/aar_resources_extractor.py
+++ b/tools/android/aar_resources_extractor.py
@@ -1,3 +1,4 @@
+# Lint as: python2, python3
 # pylint: disable=g-direct-third-party-import
 # Copyright 2017 The Bazel Authors. All rights reserved.
 #
@@ -22,20 +23,27 @@
 In the future, this script may be extended to also extract assets.
 """
 
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
 import os
 import sys
 import zipfile
 
+from absl import app
+from absl import flags
+import six
+
 from tools.android import junction
-from third_party.py import gflags
 
-FLAGS = gflags.FLAGS
+FLAGS = flags.FLAGS
 
-gflags.DEFINE_string("input_aar", None, "Input AAR")
-gflags.MarkFlagAsRequired("input_aar")
-gflags.DEFINE_string("output_res_dir", None, "Output resources directory")
-gflags.MarkFlagAsRequired("output_res_dir")
-gflags.DEFINE_string("output_assets_dir", None, "Output assets directory")
+flags.DEFINE_string("input_aar", None, "Input AAR")
+flags.mark_flag_as_required("input_aar")
+flags.DEFINE_string("output_res_dir", None, "Output resources directory")
+flags.mark_flag_as_required("output_res_dir")
+flags.DEFINE_string("output_assets_dir", None, "Output assets directory")
 
 
 def ExtractResources(aar, output_res_dir):
@@ -47,7 +55,8 @@
       ExtractOneFile(aar, name, output_res_dir_abs)
       aar_contains_no_resources = False
   if aar_contains_no_resources:
-    empty_xml_filename = output_res_dir + "/res/values/empty.xml"
+    empty_xml_filename = six.ensure_str(
+        output_res_dir) + "/res/values/empty.xml"
     WriteFileWithJunctions(empty_xml_filename, b"<resources/>")
 
 
@@ -63,8 +72,9 @@
     # aapt will ignore this file and not print an error message, because it
     # thinks that it is a swap file. We need to create at least one file so that
     # Bazel does not complain that the output tree artifact was not created.
-    empty_asset_filename = (output_assets_dir +
-                            "/assets/empty_asset_generated_by_bazel~")
+    empty_asset_filename = (
+        six.ensure_str(output_assets_dir) +
+        "/assets/empty_asset_generated_by_bazel~")
     WriteFileWithJunctions(empty_asset_filename, b"")
 
 
@@ -116,7 +126,7 @@
     aar.extract(name, abs_output_dir)
 
 
-def main():
+def main(unused_argv):
   with zipfile.ZipFile(FLAGS.input_aar, "r") as aar:
     ExtractResources(aar, FLAGS.output_res_dir)
     if FLAGS.output_assets_dir is not None:
@@ -124,4 +134,4 @@
 
 if __name__ == "__main__":
   FLAGS(sys.argv)
-  main()
+  app.run(main)
diff --git a/tools/android/aar_resources_extractor_test.py b/tools/android/aar_resources_extractor_test.py
index bce4a3d..64e4b9b 100644
--- a/tools/android/aar_resources_extractor_test.py
+++ b/tools/android/aar_resources_extractor_test.py
@@ -1,3 +1,4 @@
+# Lint as: python2, python3
 # Copyright 2017 The Bazel Authors. All rights reserved.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,12 +15,18 @@
 
 """Tests for aar_resources_extractor."""
 
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
 import io
 import os
 import shutil
 import unittest
 import zipfile
 
+import six
+
 from tools.android import aar_resources_extractor
 
 
@@ -44,8 +51,9 @@
 
   def DirContents(self, d):
     return [
-        _HostPath(path + "/" + f)
-        for (path, _, files) in os.walk(d) for f in files
+        _HostPath(six.ensure_str(path) + "/" + six.ensure_str(f))
+        for (path, _, files) in os.walk(d)
+        for f in files
     ]
 
   def testNoResources(self):
diff --git a/tools/android/build_split_manifest.py b/tools/android/build_split_manifest.py
index 8c4529d..25f14f2 100644
--- a/tools/android/build_split_manifest.py
+++ b/tools/android/build_split_manifest.py
@@ -1,3 +1,4 @@
+# Lint as: python2, python3
 # pylint: disable=g-direct-third-party-import
 # Copyright 2015 The Bazel Authors. All rights reserved.
 #
@@ -24,21 +25,20 @@
 Writes the old application class into the file designated by the third argument.
 """
 
-import sys
 from xml.etree import ElementTree
+from absl import app
+from absl import flags
 
-from third_party.py import gflags
+flags.DEFINE_string("main_manifest", None, "The main manifest of the app")
+flags.DEFINE_string("split_manifest", None, "The output manifest")
+flags.DEFINE_string(
+    "override_package", None,
+    "The Android package. Override the one specified in the "
+    "input manifest")
+flags.DEFINE_string("split", None, "The name of the split")
+flags.DEFINE_boolean("hascode", False, "Whether this split .apk has dexes")
 
-
-gflags.DEFINE_string("main_manifest", None, "The main manifest of the app")
-gflags.DEFINE_string("split_manifest", None, "The output manifest")
-gflags.DEFINE_string("override_package", None,
-                     "The Android package. Override the one specified in the "
-                     "input manifest")
-gflags.DEFINE_string("split", None, "The name of the split")
-gflags.DEFINE_boolean("hascode", False, "Whether this split .apk has dexes")
-
-FLAGS = gflags.FLAGS
+FLAGS = flags.FLAGS
 
 MANIFEST_TEMPLATE = """<?xml version="1.0" encoding="utf-8"?>
 <manifest
@@ -91,15 +91,14 @@
   }
 
 
-def main():
+def main(unused_argv):
   split_manifest = BuildSplitManifest(
       open(FLAGS.main_manifest, "rb").read(), FLAGS.override_package,
       FLAGS.split, FLAGS.hascode)
 
   with open(FLAGS.split_manifest, "wb") as output_xml:
-    output_xml.write(split_manifest)
+    output_xml.write(split_manifest.encode("utf-8"))
 
 
 if __name__ == "__main__":
-  FLAGS(sys.argv)
-  main()
+  app.run(main)
diff --git a/tools/android/incremental_install.py b/tools/android/incremental_install.py
index d7b9c48..9c7ef46 100644
--- a/tools/android/incremental_install.py
+++ b/tools/android/incremental_install.py
@@ -1,3 +1,4 @@
+# Lint as: python2, python3
 # pylint: disable=g-direct-third-party-import
 # pylint: disable=g-bad-file-header
 # Copyright 2015 The Bazel Authors. All rights reserved.
@@ -16,7 +17,12 @@
 
 """Installs an Android application, possibly in an incremental way."""
 
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
 import collections
+from concurrent import futures
 import hashlib
 import logging
 import os
@@ -29,38 +35,40 @@
 import time
 import zipfile
 
-from third_party.py import gflags
-from third_party.py.concurrent import futures
+from absl import app
+from absl import flags
+import six
 
+flags.DEFINE_string("split_main_apk", None, "The main APK for split install")
+flags.DEFINE_multi_string("split_apk", [], "Split APKs to install")
+flags.DEFINE_string("dexmanifest", None, "The .dex manifest")
+flags.DEFINE_multi_string("native_lib", None, "Native libraries to install")
+flags.DEFINE_string("resource_apk", None, "The resource .apk")
+flags.DEFINE_string(
+    "apk", None, "The app .apk. If not specified, "
+    "do incremental deployment")
+flags.DEFINE_string("adb", None, "ADB to use")
+flags.DEFINE_string("stub_datafile", None, "The stub data file")
+flags.DEFINE_string("output_marker", None, "The output marker file")
+flags.DEFINE_multi_string("extra_adb_arg", [], "Extra arguments to adb")
+flags.DEFINE_string("execroot", ".", "The exec root")
+flags.DEFINE_integer(
+    "adb_jobs",
+    2, "The number of instances of adb to use in parallel to "
+    "update files on the device",
+    lower_bound=1)
+flags.DEFINE_enum(
+    "start", "no", ["no", "cold", "warm", "debug"],
+    "Whether/how to start the app after installing it. 'cold' "
+    "and 'warm' will both cause the app to be started, 'warm' "
+    "will start it with previously saved application state, "
+    "'debug' will wait for the debugger before a clean start.")
+flags.DEFINE_boolean("start_app", False, "Deprecated, use 'start'.")
+flags.DEFINE_string("user_home_dir", None, "Path to the user's home directory")
+flags.DEFINE_string("flagfile", None,
+                    "Path to a file to read additional flags from")
 
-gflags.DEFINE_string("split_main_apk", None, "The main APK for split install")
-gflags.DEFINE_multistring("split_apk", [], "Split APKs to install")
-gflags.DEFINE_string("dexmanifest", None, "The .dex manifest")
-gflags.DEFINE_multistring("native_lib", None, "Native libraries to install")
-gflags.DEFINE_string("resource_apk", None, "The resource .apk")
-gflags.DEFINE_string("apk", None, "The app .apk. If not specified, "
-                     "do incremental deployment")
-gflags.DEFINE_string("adb", None, "ADB to use")
-gflags.DEFINE_string("stub_datafile", None, "The stub data file")
-gflags.DEFINE_string("output_marker", None, "The output marker file")
-gflags.DEFINE_multistring("extra_adb_arg", [], "Extra arguments to adb")
-gflags.DEFINE_string("execroot", ".", "The exec root")
-gflags.DEFINE_integer("adb_jobs", 2,
-                      "The number of instances of adb to use in parallel to "
-                      "update files on the device",
-                      lower_bound=1)
-gflags.DEFINE_enum("start", "no", ["no", "cold", "warm", "debug"],
-                   "Whether/how to start the app after installing it. 'cold' "
-                   "and 'warm' will both cause the app to be started, 'warm' "
-                   "will start it with previously saved application state, "
-                   "'debug' will wait for the debugger before a clean start.")
-gflags.DEFINE_boolean("start_app", False, "Deprecated, use 'start'.")
-gflags.DEFINE_string("user_home_dir", None, "Path to the user's home directory")
-gflags.DEFINE_string("flagfile", None,
-                     "Path to a file to read additional flags from")
-gflags.DEFINE_string("verbosity", None, "Logging verbosity")
-
-FLAGS = gflags.FLAGS
+FLAGS = flags.FLAGS
 
 DEVICE_DIRECTORY = "/data/local/tmp/incrementaldeployment"
 
@@ -173,8 +181,8 @@
 
     # Check these first so that the more specific error gets raised instead of
     # the more generic AdbError.
-    stdout = stdout.decode()
-    stderr = stderr.decode()
+    stdout = six.ensure_str(stdout)
+    stderr = six.ensure_str(stderr)
     if "device not found" in stderr:
       raise DeviceNotFoundError()
     elif "device unauthorized" in stderr:
@@ -204,7 +212,8 @@
   def GetInstallTime(self, package):
     """Get the installation time of a package."""
     _, stdout, _, _ = self._Shell("dumpsys package %s" % package)
-    match = re.search("firstInstallTime=(.*)$", stdout, re.MULTILINE)
+    match = re.search("firstInstallTime=(.*)$", six.ensure_str(stdout),
+                      re.MULTILINE)
     if match:
       return match.group(1)
     else:
@@ -239,7 +248,7 @@
     try:
       self._Exec(["pull", remote, local])
       with open(local, "rb") as f:
-        return f.read().decode("utf-8")
+        return six.ensure_str(f.read(), "utf-8")
     except (AdbError, IOError):
       return None
 
@@ -341,7 +350,7 @@
 def GetAppPackage(stub_datafile):
   """Returns the app package specified in a stub data file."""
   with open(stub_datafile, "rb") as f:
-    return f.readlines()[1].decode("utf-8").strip()
+    return six.ensure_str(f.readlines()[1], "utf-8").strip()
 
 
 def UploadDexes(adb, execroot, app_dir, temp_dir, dexmanifest, full_install):
@@ -507,7 +516,7 @@
   native_libs = {}
   if args is not None:
     for native_lib in args:
-      abi, path = native_lib.split(":")
+      abi, path = six.ensure_str(native_lib).split(":")
       if abi not in native_libs:
         native_libs[abi] = set()
 
@@ -539,7 +548,7 @@
   native_libs = ConvertNativeLibs(native_lib_args)
   libs = set()
   if native_libs:
-    abi = FindAbi(adb.GetAbi(), native_libs.keys())
+    abi = FindAbi(adb.GetAbi(), list(native_libs.keys()))
     if abi:
       libs = native_libs[abi]
 
@@ -613,7 +622,9 @@
     f.result()
 
   install_manifest = [
-      name + " " + checksum for name, checksum in install_checksums.items()]
+      six.ensure_str(name) + " " + checksum
+      for name, checksum in install_checksums.items()
+  ]
   adb.PushString("\n".join(install_manifest),
                  targetpath.join(app_dir, "native",
                                  "native_manifest")).result()
@@ -701,7 +712,9 @@
     adb.InstallMultiple(targetpath.join(execroot, apk), app_package)
 
   install_manifest = [
-      name + " " + checksum for name, checksum in install_checksums.items()]
+      six.ensure_str(name) + " " + checksum
+      for name, checksum in install_checksums.items()
+  ]
   adb.PushString("\n".join(install_manifest),
                  targetpath.join(app_dir, "split_manifest")).result()
 
@@ -752,7 +765,7 @@
         VerifyInstallTimestamp(adb, app_package)
 
       with open(hostpath.join(execroot, dexmanifest), "rb") as f:
-        dexmanifest = f.read().decode("utf-8")
+        dexmanifest = six.ensure_str(f.read(), "utf-8")
       UploadDexes(adb, execroot, app_dir, temp_dir, dexmanifest, bool(apk))
       # TODO(ahumesky): UploadDexes waits for all the dexes to be uploaded, and
       # then UploadResources is called. We could instead enqueue everything
@@ -798,8 +811,8 @@
     shutil.rmtree(temp_dir, True)
 
 
-def main():
-  if FLAGS.verbosity == "1":
+def main(unused_argv):
+  if FLAGS.verbosity == "1":  # 'verbosity' flag is defined in absl.logging
     level = logging.DEBUG
     fmt = "%(levelname)-5s %(asctime)s %(module)s:%(lineno)3d] %(message)s"
   else:
@@ -836,4 +849,4 @@
       FLAGS.Reset()
       FLAGS(sys.argv + [line.strip() for line in flagsfile.readlines()])
 
-  main()
+  app.run(main)
diff --git a/tools/android/incremental_install_test.py b/tools/android/incremental_install_test.py
index 5eee83f..359eacd 100644
--- a/tools/android/incremental_install_test.py
+++ b/tools/android/incremental_install_test.py
@@ -1,3 +1,4 @@
+# Lint as: python2, python3
 # pylint: disable=g-direct-third-party-import
 # Copyright 2015 The Bazel Authors. All rights reserved.
 #
@@ -15,12 +16,18 @@
 
 """Unit tests for stubify_incremental_install."""
 
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
 import os
 import unittest
 import zipfile
 
-from tools.android import incremental_install
 from third_party.py import mock
+import six
+
+from tools.android import incremental_install
 
 
 class MockAdb(object):
@@ -58,7 +65,7 @@
       content = self.files.get(remote)
       if content is not None:
         with open(local, "wb") as f:
-          f.write(content.encode("utf-8"))
+          f.write(six.ensure_binary(content, "utf-8"))
       else:
         returncode = 1
         stderr = "remote object '%s' does not exist\n" % remote
@@ -86,16 +93,16 @@
       self.shell_cmdlns.append(shell_cmdln)
       if shell_cmdln.startswith(("mkdir", "am", "monkey", "input")):
         pass
-      elif shell_cmdln.startswith("dumpsys package "):
+      elif six.ensure_str(shell_cmdln).startswith("dumpsys package "):
         if self.package_timestamp is not None:
           timestamp = "firstInstallTime=%s" % self.package_timestamp
         else:
           timestamp = ""
         return self._CreatePopenMock(0, timestamp, "")
-      elif shell_cmdln.startswith("rm"):
+      elif six.ensure_str(shell_cmdln).startswith("rm"):
         file_path = shell_cmdln.split()[2]
         self.files.pop(file_path, None)
-      elif shell_cmdln.startswith("getprop ro.product.cpu.abi"):
+      elif six.ensure_str(shell_cmdln).startswith("getprop ro.product.cpu.abi"):
         return self._CreatePopenMock(0, self.abi, "")
       else:
         raise Exception("Unknown shell command line: %s" % shell_cmdln)
diff --git a/tools/android/instrumentation_test_check.py b/tools/android/instrumentation_test_check.py
index 7ade739..65df85a 100644
--- a/tools/android/instrumentation_test_check.py
+++ b/tools/android/instrumentation_test_check.py
@@ -1,3 +1,4 @@
+# Lint as: python2, python3
 # pylint: disable=g-direct-third-party-import
 # Copyright 2017 The Bazel Authors. All rights reserved.
 #
@@ -20,17 +21,18 @@
 
 import os
 import sys
-
 import xml.etree.ElementTree as ET
-from third_party.py import gflags
 
-gflags.DEFINE_string("instrumentation_manifest", None,
-                     "AndroidManifest.xml of the instrumentation APK")
-gflags.DEFINE_string("target_manifest", None,
-                     "AndroidManifest.xml of the target APK")
-gflags.DEFINE_string("output", None, "Output of the check")
+from absl import app
+from absl import flags
 
-FLAGS = gflags.FLAGS
+flags.DEFINE_string("instrumentation_manifest", None,
+                    "AndroidManifest.xml of the instrumentation APK")
+flags.DEFINE_string("target_manifest", None,
+                    "AndroidManifest.xml of the target APK")
+flags.DEFINE_string("output", None, "Output of the check")
+
+FLAGS = flags.FLAGS
 
 
 class ManifestError(Exception):
@@ -100,7 +102,7 @@
   return target_package_to_instrument, target_package_name
 
 
-def main():
+def main(unused_argv):
   FLAGS(sys.argv)
 
   instr_manifest_path = FLAGS.instrumentation_manifest
@@ -121,7 +123,7 @@
         instr_manifest, instr_manifest_path, target_manifest,
         target_manifest_path)
   except ManifestError as e:
-    sys.exit(e.message)
+    sys.exit(str(e))
 
   with open(output_path, "w") as f:
     f.write("target_package={0}\n".format(package_to_instrument))
@@ -129,4 +131,4 @@
 
 
 if __name__ == "__main__":
-  main()
+  app.run(main)
diff --git a/tools/android/junction_test.py b/tools/android/junction_test.py
index e3ff421..d765460 100644
--- a/tools/android/junction_test.py
+++ b/tools/android/junction_test.py
@@ -1,3 +1,4 @@
+# Lint as: python2, python3
 # Copyright 2017 The Bazel Authors. All rights reserved.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,9 +14,14 @@
 # limitations under the License.
 """Tests for TempJunction."""
 
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
 import os
 import unittest
 
+import six
 from src.test.py.bazel import test_base
 from tools.android import junction
 
@@ -43,7 +49,8 @@
       # Ensure that `j` created the junction.
       self.assertTrue(os.path.exists(target))
       self.assertTrue(os.path.exists(juncpath))
-      self.assertTrue(juncpath.endswith(os.path.join("junc temp", "j")))
+      self.assertTrue(
+          six.ensure_str(juncpath).endswith(os.path.join("junc temp", "j")))
       self.assertTrue(os.path.isabs(juncpath))
       # Create a file under the junction.
       filepath = os.path.join(juncpath, "some file.txt")
@@ -73,7 +80,7 @@
     target = self.ScratchDir("junc target")
     # Make the `target` path a non-normalized Windows path with a space in it.
     # TempJunction should still work.
-    target = os.path.dirname(target) + "/junc target"
+    target = six.ensure_str(os.path.dirname(target)) + "/junc target"
     with junction.TempJunction(target, testonly_mkdtemp=tempdir) as j:
       self.assertTrue(os.path.exists(j))
       try:
diff --git a/tools/android/strip_resources.py b/tools/android/strip_resources.py
index f45d674..8425f07f 100644
--- a/tools/android/strip_resources.py
+++ b/tools/android/strip_resources.py
@@ -21,20 +21,19 @@
 invoke aapt, then extract AndroidManifest.xml from its output.
 """
 
-import sys
 import zipfile
 
-from third_party.py import gflags
+from absl import app
+from absl import flags
 
+flags.DEFINE_string("input_resource_apk", None, "The input resource .apk")
+flags.DEFINE_string("output_resource_apk", None, "The output resource .apk")
 
-gflags.DEFINE_string("input_resource_apk", None, "The input resource .apk")
-gflags.DEFINE_string("output_resource_apk", None, "The output resource .apk")
-
-FLAGS = gflags.FLAGS
+FLAGS = flags.FLAGS
 HERMETIC_TIMESTAMP = (2001, 1, 1, 0, 0, 0)
 
 
-def main():
+def main(unused_argv):
   with zipfile.ZipFile(FLAGS.input_resource_apk) as input_zip:
     with input_zip.open("AndroidManifest.xml") as android_manifest_entry:
       android_manifest = android_manifest_entry.read()
@@ -48,5 +47,4 @@
 
 
 if __name__ == "__main__":
-  FLAGS(sys.argv)
-  main()
+  app.run(main)
diff --git a/tools/android/stubify_manifest.py b/tools/android/stubify_manifest.py
index f2e8a48..8c938a6 100644
--- a/tools/android/stubify_manifest.py
+++ b/tools/android/stubify_manifest.py
@@ -28,21 +28,22 @@
 
 import sys
 from xml.etree import ElementTree
+from absl import app
+from absl import flags
 
-from third_party.py import gflags
+flags.DEFINE_string("mode", "mobile_install",
+                    "mobile_install or instant_run mode")
+flags.DEFINE_string("input_manifest", None, "The input manifest")
+flags.DEFINE_string("output_manifest", None, "The output manifest")
+flags.DEFINE_string(
+    "output_datafile", None, "The output data file that will "
+    "be embedded in the final APK")
+flags.DEFINE_string(
+    "override_package", None,
+    "The Android package. Override the one specified in the "
+    "input manifest")
 
-
-gflags.DEFINE_string("mode", "mobile_install",
-                     "mobile_install or instant_run mode")
-gflags.DEFINE_string("input_manifest", None, "The input manifest")
-gflags.DEFINE_string("output_manifest", None, "The output manifest")
-gflags.DEFINE_string("output_datafile", None, "The output data file that will "
-                     "be embedded in the final APK")
-gflags.DEFINE_string("override_package", None,
-                     "The Android package. Override the one specified in the "
-                     "input manifest")
-
-FLAGS = gflags.FLAGS
+FLAGS = flags.FLAGS
 
 ANDROID = "http://schemas.android.com/apk/res/android"
 READ_EXTERNAL_STORAGE = "android.permission.READ_EXTERNAL_STORAGE"
@@ -138,7 +139,7 @@
   return (manifest, application)
 
 
-def main():
+def main(unused_argv):
   if FLAGS.mode == "mobile_install":
     with open(FLAGS.input_manifest, "rb") as input_manifest:
       new_manifest, old_application, app_package = (
@@ -162,9 +163,8 @@
 
 
 if __name__ == "__main__":
-  FLAGS(sys.argv)
   try:
-    main()
+    app.run(main)
   except BadManifestException as e:
     print(e)
     sys.exit(1)
diff --git a/tools/android/stubify_manifest_test.py b/tools/android/stubify_manifest_test.py
index a46d2a6..648560a 100644
--- a/tools/android/stubify_manifest_test.py
+++ b/tools/android/stubify_manifest_test.py
@@ -1,3 +1,4 @@
+# Lint as: python2, python3
 # Copyright 2015 The Bazel Authors. All rights reserved.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +15,15 @@
 
 """Unit tests for stubify_application_manifest."""
 
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
 import unittest
 from xml.etree import ElementTree
 
+import six
+
 from tools.android.stubify_manifest import ANDROID
 from tools.android.stubify_manifest import BadManifestException
 from tools.android.stubify_manifest import INSTANT_RUN_BOOTSTRAP_APPLICATION
@@ -109,7 +116,8 @@
 
   def testRemovesHasCode(self):
     new_manifest, _, _ = StubifyMobileInstall(MANIFEST_WITH_HASCODE)
-    application = ElementTree.fromstring(new_manifest).find("application")
+    application = ElementTree.fromstring(
+        six.ensure_str(new_manifest)).find("application")
     self.assertFalse(("{%s}hasCode" % ANDROID) in application.attrib)
 
   def assertHasPermission(self, manifest_string, permission):