Merge "Introduce mksquashfsimage.sh"
diff --git a/slideshow/Android.mk b/slideshow/Android.mk
new file mode 100644
index 0000000..8c782c3
--- /dev/null
+++ b/slideshow/Android.mk
@@ -0,0 +1,16 @@
+# Copyright 2015 The Android Open Source Project
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := slideshow.cpp
+LOCAL_MODULE := slideshow
+LOCAL_MODULE_TAGS := optional
+LOCAL_FORCE_STATIC_EXECUTABLE := true
+LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT_SBIN)
+LOCAL_UNSTRIPPED_PATH := $(TARGET_ROOT_OUT_SBIN_UNSTRIPPED)
+
+LOCAL_CFLAGS := -D__STDC_LIMIT_MACROS -Werror
+LOCAL_C_INCLUDES := bootable/recovery
+LOCAL_STATIC_LIBRARIES := libminui libpng libz libutils libstdc++ libcutils liblog libm libc
+include $(BUILD_EXECUTABLE)
diff --git a/slideshow/slideshow.cpp b/slideshow/slideshow.cpp
new file mode 100644
index 0000000..25a2206
--- /dev/null
+++ b/slideshow/slideshow.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <time.h>
+#include <linux/input.h>
+#include <cutils/klog.h>
+#include "minui/minui.h"
+
+#define NEXT_TIMEOUT_MS 5000
+#define LAST_TIMEOUT_S  30
+
+#define LOGE(x...) do { KLOG_ERROR("slideshow", x); } while (0)
+
+static int input_cb(int fd, unsigned int epevents, void *data)
+{
+    struct input_event ev;
+    int *key_code = (int *)data;
+
+    *key_code = -1;
+
+    if (ev_get_input(fd, epevents, &ev)) {
+        return -1;
+    }
+
+    if (ev.type == EV_KEY) {
+        *key_code = ev.code;
+    }
+
+    return 0;
+}
+
+static void clear()
+{
+    gr_color(0, 0, 0, 0);
+    gr_clear();
+    gr_flip();
+}
+
+static void draw(const char *resname)
+{
+    gr_surface surface;
+    int w, h, x, y;
+
+    if (res_create_display_surface(resname, &surface) < 0) {
+        LOGE("failed to create surface for %s\n", resname);
+        return;
+    }
+
+    w = gr_get_width(surface);
+    h = gr_get_height(surface);
+    x = (gr_fb_width() - w) / 2;
+    y = (gr_fb_height() - h) / 2;
+
+    gr_blit(surface, 0, 0, w, h, x, y);
+    gr_flip();
+
+    res_free_surface(surface);
+}
+
+int usage()
+{
+    LOGE("usage: slideshow [-t timeout] image.png [image2.png ...] last.png\n");
+    return EXIT_FAILURE;
+}
+
+int main(int argc, char **argv)
+{
+    int key_code = -1;
+    int input = false;
+    int opt;
+    long int timeout = NEXT_TIMEOUT_MS;
+    time_t start;
+
+    while ((opt = getopt(argc, argv, "t")) != -1) {
+        switch (opt) {
+        case 't':
+            timeout = strtol(optarg, NULL, 0);
+
+            if (timeout < 0 || timeout >= LONG_MAX) {
+                timeout = NEXT_TIMEOUT_MS;
+                LOGE("invalid timeout %s, defaulting to %u\n", optarg,
+                    timeout);
+            }
+            break;
+        default:
+            return usage();
+        }
+    }
+
+    if (optind >= argc) {
+        return usage();
+    }
+
+    if (gr_init() == -1 || ev_init(input_cb, &key_code) == -1) {
+        LOGE("failed to initialize minui\n");
+        return EXIT_FAILURE;
+    }
+
+    /* display all images except the last one, switch to next image after
+     * timeout or user input */
+
+    while (optind < argc - 1) {
+        draw(argv[optind++]);
+
+        if (ev_wait(timeout) == 0) {
+            ev_dispatch();
+
+            if (key_code != -1) {
+                input = true;
+            }
+        }
+    };
+
+    /* if there was user input while showing the images, display the last
+     * image and wait until the power button is pressed or LAST_TIMEOUT_S
+     * has elapsed */
+
+    if (input) {
+        start = time(NULL);
+        draw(argv[optind]);
+
+        do {
+            if (ev_wait(timeout) == 0) {
+                ev_dispatch();
+            }
+
+            if (time(NULL) - start >= LAST_TIMEOUT_S) {
+                break;
+            }
+        } while (key_code != KEY_POWER);
+    }
+
+    clear();
+    gr_exit();
+    ev_exit();
+
+    return EXIT_SUCCESS;
+}
diff --git a/tests/net_test/sendmsg.py b/tests/net_test/csocket.py
similarity index 88%
rename from tests/net_test/sendmsg.py
rename to tests/net_test/csocket.py
index 422a16a..4b268e9 100644
--- a/tests/net_test/sendmsg.py
+++ b/tests/net_test/csocket.py
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Python wrapper for sendmsg."""
+"""Python wrapper for C socket calls and data structures."""
 
 import ctypes
 import ctypes.util
@@ -23,7 +23,7 @@
 import cstruct
 
 
-# Data structures used by sendmsg.
+# Data structures.
 CMsgHdr = cstruct.Struct("cmsghdr", "@Lii", "len level type")
 Iovec = cstruct.Struct("iovec", "@LL", "base len")
 MsgHdr = cstruct.Struct("msghdr", "@LLLLLLi",
@@ -44,6 +44,12 @@
   return CMSG_ALIGNTO * ((length / CMSG_ALIGNTO) + (length % CMSG_ALIGNTO != 0))
 
 
+def MaybeRaiseSocketError(ret):
+  if ret < 0:
+    errno = ctypes.get_errno()
+    raise socket.error(errno, os.strerror(errno))
+
+
 def Sockaddr(addr):
   if ":" in addr[0]:
     family = socket.AF_INET6
@@ -100,12 +106,25 @@
   return msg_control
 
 
+def Bind(s, to):
+  """Python wrapper for connect."""
+  ret = libc.bind(s.fileno(), to.CPointer(), len(to))
+  MaybeRaiseSocketError(ret)
+  return ret
+
+def Connect(s, to):
+  """Python wrapper for connect."""
+  ret = libc.connect(s.fileno(), to.CPointer(), len(to))
+  MaybeRaiseSocketError(ret)
+  return ret
+
+
 def Sendmsg(s, to, data, control, flags):
   """Python wrapper for sendmsg.
 
   Args:
     s: A Python socket object. Becomes sockfd.
-    to: A Python socket address tuple. Becomes msg->msg_name.
+    to: An address tuple, or a SockaddrIn[6] struct. Becomes msg->msg_name.
     data: A string, the data to write. Goes into msg->msg_iov.
     control: A list of cmsg options. Becomes msg->msg_control.
     flags: An integer. Becomes msg->msg_flags.
@@ -122,9 +141,10 @@
 
   # Convert the destination address into a struct sockaddr.
   if to:
-    name = Sockaddr(to)
-    msg_name = name.CPointer()
-    msg_namelen = len(name)
+    if isinstance(to, tuple):
+      to = Sockaddr(to)
+    msg_name = to.CPointer()
+    msg_namelen = len(to)
   else:
     msg_name = 0
     msg_namelen = 0
@@ -155,9 +175,6 @@
 
   # Call sendmsg.
   ret = libc.sendmsg(s.fileno(), msghdr, 0)
-
-  if ret < 0:
-    errno = ctypes.get_errno()
-    raise socket.error(errno, os.strerror(errno))
+  MaybeRaiseSocketError(ret)
 
   return ret
diff --git a/tests/net_test/iproute.py b/tests/net_test/iproute.py
index 1060fb7..cde1803 100644
--- a/tests/net_test/iproute.py
+++ b/tests/net_test/iproute.py
@@ -150,6 +150,7 @@
 
 
 ### FIB rule constants. See include/uapi/linux/fib_rules.h.
+FRA_IIFNAME = 3
 FRA_PRIORITY = 6
 FRA_FWMARK = 10
 FRA_SUPPRESS_PREFIXLEN = 14
@@ -225,6 +226,9 @@
   def _NlAttrIPAddress(self, nla_type, family, address):
     return self._NlAttr(nla_type, socket.inet_pton(family, address))
 
+  def _NlAttrInterfaceName(self, nla_type, interface):
+    return self._NlAttr(nla_type, interface + "\x00")
+
   def _GetConstantName(self, value, prefix):
     thismodule = sys.modules[__name__]
     for name in dir(thismodule):
@@ -462,11 +466,12 @@
     return self._Rule(version, is_add, RTN_UNICAST, table, nlattr, priority)
 
   def OifRule(self, version, is_add, oif, table, priority):
-    nlattr = self._NlAttr(FRA_OIFNAME, oif + "\x00")
+    nlattr = self._NlAttrInterfaceName(FRA_OIFNAME, oif)
     return self._Rule(version, is_add, RTN_UNICAST, table, nlattr, priority)
 
   def UidRangeRule(self, version, is_add, start, end, table, priority):
-    nlattr = (self._NlAttrU32(FRA_UID_START, start) +
+    nlattr = (self._NlAttrInterfaceName(FRA_IIFNAME, "lo") +
+              self._NlAttrU32(FRA_UID_START, start) +
               self._NlAttrU32(FRA_UID_END, end))
     return self._Rule(version, is_add, RTN_UNICAST, table, nlattr, priority)
 
diff --git a/tests/net_test/multinetwork_base.py b/tests/net_test/multinetwork_base.py
index e3cda7a..8940258 100644
--- a/tests/net_test/multinetwork_base.py
+++ b/tests/net_test/multinetwork_base.py
@@ -27,10 +27,10 @@
 
 from scapy import all as scapy
 
+import csocket
 import cstruct
 import iproute
 import net_test
-import sendmsg
 
 
 IFF_TUN = 1
@@ -447,7 +447,7 @@
           4: (net_test.SOL_IP, IP_PKTINFO),
           6: (net_test.SOL_IPV6, IPV6_PKTINFO)}[version]
       cmsgs.append((cmsg_level, cmsg_name, pktinfo))
-    sendmsg.Sendmsg(s, (dstaddr, dstport), payload, cmsgs, sendmsg.MSG_CONFIRM)
+    csocket.Sendmsg(s, (dstaddr, dstport), payload, cmsgs, csocket.MSG_CONFIRM)
 
   def ReceiveEtherPacketOn(self, netid, packet):
     posix.write(self.tuns[netid].fileno(), str(packet))
diff --git a/tests/net_test/srcaddr_selection_test.py b/tests/net_test/srcaddr_selection_test.py
index 323c7da..eb09b7f 100755
--- a/tests/net_test/srcaddr_selection_test.py
+++ b/tests/net_test/srcaddr_selection_test.py
@@ -23,11 +23,11 @@
 
 from scapy import all as scapy
 
+import csocket
 import iproute
 import multinetwork_base
 import multinetwork_test
 import net_test
-import sendmsg
 
 # Setsockopt values.
 IPV6_ADDR_PREFERENCES = 72
@@ -88,7 +88,7 @@
     pktinfo = multinetwork_base.MakePktInfo(6, address, 0)
     cmsgs = [(net_test.SOL_IPV6, IPV6_PKTINFO, pktinfo)]
     s = self.BuildSocket(6, net_test.UDPSocket, netid, "mark")
-    return sendmsg.Sendmsg(s, (dest, 53), "Hello", cmsgs, 0)
+    return csocket.Sendmsg(s, (dest, 53), "Hello", cmsgs, 0)
 
   def assertAddressUsable(self, address, netid):
     self.BindToAddress(address)