Merge "Mount/Unmount secure containers Persist flags in PackageSetting. Flags are relevant to ApplicationInfo.FLAG_SYSTEM, Application.FLAG_ON_SDCARD, ApplicationInfo.FLAG_FORWARD_LOCK. New pm command to simulate mount/unmount in Pm. This will be removed when MountService/vold event generation gets fixed. Calls from MountService into PackageManager when media gets mounted/unmounted. Scan the packages and grant permissions when the sdcard gets mounted. This api might change again."
diff --git a/Android.mk b/Android.mk
index 7c7bb62..d6beac5 100644
--- a/Android.mk
+++ b/Android.mk
@@ -111,6 +111,7 @@
 	core/java/android/os/ICheckinService.aidl \
 	core/java/android/os/IMessenger.aidl \
 	core/java/android/os/IMountService.aidl \
+	core/java/android/os/INetworkManagementService.aidl \
 	core/java/android/os/INetStatService.aidl \
 	core/java/android/os/IParentalControlCallback.aidl \
 	core/java/android/os/IPermissionController.aidl \
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index ad6540a..e65cdf1 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -34,12 +34,14 @@
 #include <media/stagefright/MetaData.h>
 #include <media/stagefright/OMXClient.h>
 #include <media/stagefright/OMXCodec.h>
+#include <media/mediametadataretriever.h>
 
 using namespace android;
 
 static long gNumRepetitions;
 static long gMaxNumFrames;  // 0 means decode all available.
 static long gReproduceBug;  // if not -1.
+static bool gPreferSoftwareCodec;
 
 static int64_t getNowUs() {
     struct timeval tv;
@@ -59,7 +61,9 @@
         rawSource = source;
     } else {
         rawSource = OMXCodec::Create(
-            client->interface(), meta, false /* createEncoder */, source);
+            client->interface(), meta, false /* createEncoder */, source,
+            NULL /* matchComponentName */,
+            gPreferSoftwareCodec ? OMXCodec::kPreferSoftwareCodecs : 0);
 
         if (rawSource == NULL) {
             fprintf(stderr, "Failed to instantiate decoder for '%s'.\n", mime);
@@ -219,6 +223,8 @@
     fprintf(stderr, "       -m max-number-of-frames-to-decode in each pass\n");
     fprintf(stderr, "       -b bug to reproduce\n");
     fprintf(stderr, "       -p(rofiles) dump decoder profiles supported\n");
+    fprintf(stderr, "       -t(humbnail) extract video thumbnail\n");
+    fprintf(stderr, "       -s(oftware) prefer software codec\n");
 }
 
 int main(int argc, char **argv) {
@@ -227,12 +233,14 @@
     bool audioOnly = false;
     bool listComponents = false;
     bool dumpProfiles = false;
+    bool extractThumbnail = false;
     gNumRepetitions = 1;
     gMaxNumFrames = 0;
     gReproduceBug = -1;
+    gPreferSoftwareCodec = false;
 
     int res;
-    while ((res = getopt(argc, argv, "han:lm:b:p")) >= 0) {
+    while ((res = getopt(argc, argv, "han:lm:b:pts")) >= 0) {
         switch (res) {
             case 'a':
             {
@@ -274,6 +282,18 @@
                 break;
             }
 
+            case 't':
+            {
+                extractThumbnail = true;
+                break;
+            }
+
+            case 's':
+            {
+                gPreferSoftwareCodec = true;
+                break;
+            }
+
             case '?':
             case 'h':
             default:
@@ -288,6 +308,34 @@
     argc -= optind;
     argv += optind;
 
+    if (extractThumbnail) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        sp<IBinder> binder = sm->getService(String16("media.player"));
+        sp<IMediaPlayerService> service =
+            interface_cast<IMediaPlayerService>(binder);
+
+        CHECK(service.get() != NULL);
+
+        sp<IMediaMetadataRetriever> retriever =
+            service->createMetadataRetriever(getpid());
+
+        CHECK(retriever != NULL);
+
+        for (int k = 0; k < argc; ++k) {
+            const char *filename = argv[k];
+
+            CHECK_EQ(retriever->setDataSource(filename), OK);
+            CHECK_EQ(retriever->setMode(METADATA_MODE_FRAME_CAPTURE_ONLY), OK);
+
+            sp<IMemory> mem = retriever->captureFrame();
+
+            printf("captureFrame(%s) => %s\n",
+                   filename, mem != NULL ? "OK" : "FAILED");
+        }
+
+        return 0;
+    }
+
     if (dumpProfiles) {
         sp<IServiceManager> sm = defaultServiceManager();
         sp<IBinder> binder = sm->getService(String16("media.player"));
@@ -389,7 +437,8 @@
             sp<MetaData> meta;
             size_t i;
             for (i = 0; i < numTracks; ++i) {
-                meta = extractor->getTrackMetaData(i);
+                meta = extractor->getTrackMetaData(
+                        i, MediaExtractor::kIncludeExtensiveMetaData);
 
                 const char *mime;
                 meta->findCString(kKeyMIMEType, &mime);
@@ -403,6 +452,12 @@
                 }
             }
 
+            int64_t thumbTimeUs;
+            if (meta->findInt64(kKeyThumbnailTime, &thumbTimeUs)) {
+                printf("thumbnailTime: %lld us (%.2f secs)\n",
+                       thumbTimeUs, thumbTimeUs / 1E6);
+            }
+
             mediaSource = extractor->getTrack(i);
         }
 
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
new file mode 100644
index 0000000..bd6cabb
--- /dev/null
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -0,0 +1,105 @@
+/* //device/java/android/android/os/INetworkManagementService.aidl
+**
+** Copyright 2007, 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.
+*/
+
+package android.os;
+
+/**
+ * @hide
+ */
+interface INetworkManagementService
+{
+    /**
+     ** GENERAL
+     **/
+
+    /**
+     * Returns a list of currently known network interfaces
+     */
+    String[] listInterfaces();
+
+    /**
+     * Shuts down the service
+     */
+    void shutdown();
+
+    /**
+     ** TETHERING RELATED
+     **/
+
+
+    /**
+     * Returns true if IP forwarding is enabled
+     */
+    boolean getIpForwardingEnabled();
+
+    /**
+     * Enables/Disables IP Forwarding
+     */
+    void setIpForwardingEnabled(boolean enabled);
+
+    /**
+     * Start tethering services with the specified dhcp server range
+     */
+    void startTethering(String dhcpRangeStart, String dhcpRangeEnd);
+
+    /**
+     * Stop currently running tethering services
+     */
+    void stopTethering();
+
+    /**
+     * Returns true if tethering services are started
+     */
+    boolean isTetheringStarted();
+
+    /**
+     * Tethers the specified interface
+     */
+    void tetherInterface(String iface);
+
+    /**
+     * Untethers the specified interface
+     */
+    void untetherInterface(String iface);
+
+    /**
+     * Returns a list of currently tethered interfaces
+     */
+    String[] listTetheredInterfaces();
+
+    /**
+     * Sets the list of DNS forwarders (in order of priority)
+     */
+    void setDnsForwarders(in String[] dns);
+
+    /**
+     * Returns the list of DNS fowarders (in order of priority)
+     */
+    String[] getDnsForwarders();
+
+    /**
+     *  Enables Network Address Translation between two interfaces.
+     *  The address and netmask of the external interface is used for
+     *  the NAT'ed network.
+     */
+    void enableNat(String internalInterface, String externalInterface);
+
+    /**
+     *  Disables Network Address Translation between two interfaces.
+     */
+    void disableNat(String internalInterface, String externalInterface);
+}
diff --git a/core/java/android/provider/Browser.java b/core/java/android/provider/Browser.java
index b876f05..d67169f 100644
--- a/core/java/android/provider/Browser.java
+++ b/core/java/android/provider/Browser.java
@@ -173,9 +173,32 @@
         c.startActivity(i);
     }
 
+    /**
+     * Stores a String extra in an {@link Intent} representing the title of a
+     * page to share.  When receiving an {@link Intent#ACTION_SEND} from the
+     * Browser, use this to access the title.
+     * @hide
+     */
+    public final static String EXTRA_SHARE_TITLE = "share_title";
+
+    /**
+     * Stores a Bitmap extra in an {@link Intent} representing the screenshot of
+     * a page to share.  When receiving an {@link Intent#ACTION_SEND} from the
+     * Browser, use this to access the screenshot.
+     * @hide
+     */
+    public final static String EXTRA_SHARE_SCREENSHOT = "share_screenshot";
+
+    /**
+     * Stores a Bitmap extra in an {@link Intent} representing the favicon of a
+     * page to share.  When receiving an {@link Intent#ACTION_SEND} from the
+     * Browser, use this to access the favicon.
+     * @hide
+     */
+    public final static String EXTRA_SHARE_FAVICON = "share_favicon";
+
     public static final void sendString(Context c, String s) {
-        sendString(c, s,
-                c.getText(com.android.internal.R.string.sendText).toString());
+        sendString(c, s, c.getString(com.android.internal.R.string.sendText));
     }
 
     /**
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 93b5b4d..ece23a7 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -474,18 +474,44 @@
         public static final String DISPLAY_NAME_SOURCE = "display_name_source";
 
         /**
-         * The default text shown as the contact's display name.  It is based on
-         * available data, see {@link #DISPLAY_NAME_SOURCE}.
+         * <p>
+         * The standard text shown as the contact's display name, based on the best
+         * available information for the contact (for example, it might be the email address
+         * if the name is not available).
+         * The information actually used to compute the name is stored in
+         * {@link #DISPLAY_NAME_SOURCE}.
+         * </p>
+         * <p>
+         * A contacts provider is free to choose whatever representation makes most
+         * sense for its target market.
+         * For example in the default Android Open Source Project implementation,
+         * if the display name is
+         * based on the structured name and the structured name follows
+         * the Western full-name style, then this field contains the "given name first"
+         * version of the full name.
+         * <p>
          *
          * @see ContactsContract.ContactNameColumns#DISPLAY_NAME_ALTERNATIVE
          */
         public static final String DISPLAY_NAME_PRIMARY = "display_name";
 
         /**
-         * An alternative representation of the display name.  If display name is
+         * <p>
+         * An alternative representation of the display name, such as "family name first"
+         * instead of "given name first" for Western names.  If an alternative is not
+         * available, the values should be the same as {@link #DISPLAY_NAME_PRIMARY}.
+         * </p>
+         * <p>
+         * A contacts provider is free to provide alternatives as necessary for
+         * its target market.
+         * For example the default Android Open Source Project contacts provider
+         * currently provides an
+         * alternative in a single case:  if the display name is
          * based on the structured name and the structured name follows
-         * the Western full name style, then this field contains the "family name first"
-         * version of the full name.  Otherwise, it is the same as DISPLAY_NAME_PRIMARY.
+         * the Western full name style, then the field contains the "family name first"
+         * version of the full name.
+         * Other cases may be added later.
+         * </p>
          */
         public static final String DISPLAY_NAME_ALTERNATIVE = "display_name_alt";
 
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 763f273..49c2d0e 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2268,7 +2268,7 @@
         addInArray(child, index);
 
         child.mParent = this;
-        child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK) | DRAWN;
+        child.mPrivateFlags = (child.mPrivateFlags & ~DIRTY_MASK & ~DRAWING_CACHE_VALID) | DRAWN;
 
         if (child.hasFocus()) {
             requestChildFocus(child, child.findFocus());
diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml
index 53bb586..3dbfa25 100644
--- a/core/res/res/values/arrays.xml
+++ b/core/res/res/values/arrays.xml
@@ -131,7 +131,8 @@
          the first component from this list which is found to be installed is set as the
          preferred activity. -->
     <string-array name="default_web_search_providers">
-        <item>com.android.quicksearchbox/com.android.googlesearch.GoogleSearch</item>
+        <item>com.google.android.googlequicksearchbox/.google.GoogleSearch</item>
+        <item>com.android.quicksearchbox/.google.GoogleSearch</item>
         <item>com.google.android.providers.enhancedgooglesearch/.Launcher</item>
         <item>com.android.googlesearch/.GoogleSearch</item>
         <item>com.android.websearch/.Search.1</item>
diff --git a/include/media/IMediaDeathNotifier.h b/include/media/IMediaDeathNotifier.h
new file mode 100644
index 0000000..bb3d0d8
--- /dev/null
+++ b/include/media/IMediaDeathNotifier.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef ANDROID_IMEDIADEATHNOTIFIER_H
+#define ANDROID_IMEDIADEATHNOTIFIER_H
+
+#include <utils/threads.h>
+#include <media/IMediaPlayerService.h>
+#include <utils/SortedVector.h>
+
+namespace android {
+
+class IMediaDeathNotifier: virtual public RefBase
+{
+public:
+    IMediaDeathNotifier() { addObitRecipient(this); }
+    virtual ~IMediaDeathNotifier() { removeObitRecipient(this); }
+
+    virtual void died() = 0;
+    static const sp<IMediaPlayerService>& getMediaPlayerService();
+
+private:
+    IMediaDeathNotifier &operator=(const IMediaDeathNotifier &);
+    IMediaDeathNotifier(const IMediaDeathNotifier &);
+
+    static void addObitRecipient(const wp<IMediaDeathNotifier>& recipient);
+    static void removeObitRecipient(const wp<IMediaDeathNotifier>& recipient);
+
+    class DeathNotifier: public IBinder::DeathRecipient
+    {
+    public:
+                DeathNotifier() {}
+        virtual ~DeathNotifier();
+
+        virtual void binderDied(const wp<IBinder>& who);
+    };
+
+    friend class DeathNotifier;
+
+    static  Mutex                                   sServiceLock;
+    static  sp<IMediaPlayerService>                 sMediaPlayerService;
+    static  sp<DeathNotifier>                       sDeathNotifier;
+    static  SortedVector< wp<IMediaDeathNotifier> > sObitRecipients;
+};
+
+}; // namespace android
+
+#endif // ANDROID_IMEDIADEATHNOTIFIER_H
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 39bd5b1..d38c177 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -42,6 +42,11 @@
     typedef void *buffer_id;
     typedef void *node_id;
 
+    // Given the calling process' pid, returns true iff
+    // the implementation of the OMX interface lives in the same
+    // process.
+    virtual bool livesLocally(pid_t pid) = 0;
+
     struct ComponentInfo {
         String8 mName;
         List<String8> mRoles;
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 7132b18..87d23f6 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -21,8 +21,7 @@
 #include <ui/Surface.h>
 #include <media/IMediaPlayerClient.h>
 #include <media/IMediaPlayer.h>
-#include <media/IMediaPlayerService.h>
-#include <utils/SortedVector.h>
+#include <media/IMediaDeathNotifier.h>
 
 namespace android {
 
@@ -123,12 +122,13 @@
     virtual void notify(int msg, int ext1, int ext2) = 0;
 };
 
-class MediaPlayer : public BnMediaPlayerClient
+class MediaPlayer : public BnMediaPlayerClient,
+                    public virtual IMediaDeathNotifier
 {
 public:
     MediaPlayer();
     ~MediaPlayer();
-            void            onFirstRef();
+            void            died();
             void            disconnect();
             status_t        setDataSource(const char *url);
             status_t        setDataSource(int fd, int64_t offset, int64_t length);
@@ -164,19 +164,6 @@
             status_t        getDuration_l(int *msec);
             status_t        setDataSource(const sp<IMediaPlayer>& player);
 
-    static const sp<IMediaPlayerService>& getMediaPlayerService();
-    static void addObitRecipient(const wp<MediaPlayer>& recipient);
-    static void removeObitRecipient(const wp<MediaPlayer>& recipient);
-
-    class DeathNotifier: public IBinder::DeathRecipient
-    {
-    public:
-                DeathNotifier() {}
-        virtual ~DeathNotifier();
-
-        virtual void binderDied(const wp<IBinder>& who);
-    };
-
     sp<IMediaPlayer>            mPlayer;
     thread_id_t                 mLockThreadId;
     Mutex                       mLock;
@@ -196,13 +183,6 @@
     float                       mRightVolume;
     int                         mVideoWidth;
     int                         mVideoHeight;
-
-    friend class DeathNotifier;
-
-    static  Mutex                           sServiceLock;
-    static  sp<IMediaPlayerService>         sMediaPlayerService;
-    static  sp<DeathNotifier>               sDeathNotifier;
-    static  SortedVector< wp<MediaPlayer> > sObitRecipients;
 };
 
 }; // namespace android
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index 8c7392b..9ea6c7b 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -23,6 +23,7 @@
 #include <utils/List.h>
 #include <utils/Errors.h>
 #include <media/IMediaPlayerClient.h>
+#include <media/IMediaDeathNotifier.h>
 
 namespace android {
 
@@ -145,12 +146,14 @@
     virtual void notify(int msg, int ext1, int ext2) = 0;
 };
 
-class MediaRecorder : public BnMediaPlayerClient
+class MediaRecorder : public BnMediaPlayerClient,
+                      public virtual IMediaDeathNotifier
 {
 public:
     MediaRecorder();
     ~MediaRecorder();
 
+    void        died();
     status_t    initCheck();
     status_t    setCamera(const sp<ICamera>& camera);
     status_t    setPreviewSurface(const sp<Surface>& surface);
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 351763c..2c32386 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -109,6 +109,7 @@
     };
 
     sp<IOMX> mOMX;
+    bool mOMXLivesLocally;
     IOMX::node_id mNode;
     uint32_t mQuirks;
     bool mIsEncoder;
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index fc234ee..4ae4ec9b 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -24,7 +24,8 @@
     IAudioPolicyService.cpp \
     MediaScanner.cpp \
     MediaScannerClient.cpp \
-    autodetect.cpp
+    autodetect.cpp \
+    IMediaDeathNotifier.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libui libcutils libutils libbinder libsonivox libicuuc
diff --git a/media/libmedia/IMediaDeathNotifier.cpp b/media/libmedia/IMediaDeathNotifier.cpp
new file mode 100644
index 0000000..39ac076
--- /dev/null
+++ b/media/libmedia/IMediaDeathNotifier.cpp
@@ -0,0 +1,111 @@
+/*
+** Copyright 2010, 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.
+*/
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "IMediaDeathNotifier"
+#include <utils/Log.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+#include <media/IMediaDeathNotifier.h>
+
+namespace android {
+
+// client singleton for binder interface to services
+Mutex IMediaDeathNotifier::sServiceLock;
+sp<IMediaPlayerService> IMediaDeathNotifier::sMediaPlayerService;
+sp<IMediaDeathNotifier::DeathNotifier> IMediaDeathNotifier::sDeathNotifier;
+SortedVector< wp<IMediaDeathNotifier> > IMediaDeathNotifier::sObitRecipients;
+
+// establish binder interface to MediaPlayerService
+/*static*/const sp<IMediaPlayerService>&
+IMediaDeathNotifier::getMediaPlayerService()
+{
+    LOGV("getMediaPlayerService");
+    Mutex::Autolock _l(sServiceLock);
+    if (sMediaPlayerService.get() == 0) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        sp<IBinder> binder;
+        do {
+            binder = sm->getService(String16("media.player"));
+            if (binder != 0) {
+                break;
+             }
+             LOGW("Media player service not published, waiting...");
+             usleep(500000); // 0.5 s
+        } while(true);
+
+        if (sDeathNotifier == NULL) {
+        sDeathNotifier = new DeathNotifier();
+    }
+    binder->linkToDeath(sDeathNotifier);
+    sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
+    }
+    LOGE_IF(sMediaPlayerService == 0, "no media player service!?");
+    return sMediaPlayerService;
+}
+
+/*static*/ void
+IMediaDeathNotifier::addObitRecipient(const wp<IMediaDeathNotifier>& recipient)
+{
+    LOGV("addObitRecipient");
+    Mutex::Autolock _l(sServiceLock);
+    sObitRecipients.add(recipient);
+}
+
+/*static*/ void
+IMediaDeathNotifier::removeObitRecipient(const wp<IMediaDeathNotifier>& recipient)
+{
+    LOGV("removeObitRecipient");
+    Mutex::Autolock _l(sServiceLock);
+    sObitRecipients.remove(recipient);
+}
+
+void
+IMediaDeathNotifier::DeathNotifier::binderDied(const wp<IBinder>& who) {
+    LOGW("media server died");
+
+    // Need to do this with the lock held
+    SortedVector< wp<IMediaDeathNotifier> > list;
+    {
+        Mutex::Autolock _l(sServiceLock);
+        sMediaPlayerService.clear();
+        list = sObitRecipients;
+    }
+
+    // Notify application when media server dies.
+    // Don't hold the static lock during callback in case app
+    // makes a call that needs the lock.
+    size_t count = list.size();
+    for (size_t iter = 0; iter < count; ++iter) {
+        sp<IMediaDeathNotifier> notifier = list[iter].promote();
+        if (notifier != 0) {
+            notifier->died();
+        }
+    }
+}
+
+IMediaDeathNotifier::DeathNotifier::~DeathNotifier()
+{
+    LOGV("DeathNotifier::~DeathNotifier");
+    Mutex::Autolock _l(sServiceLock);
+    sObitRecipients.clear();
+    if (sMediaPlayerService != 0) {
+        sMediaPlayerService->asBinder()->unlinkToDeath(this);
+    }
+}
+
+}; // namespace android
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index b43e48f..277bce1 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -12,6 +12,7 @@
 
 enum {
     CONNECT = IBinder::FIRST_CALL_TRANSACTION,
+    LIVES_LOCALLY,
     LIST_NODES,
     ALLOCATE_NODE,
     FREE_NODE,
@@ -75,6 +76,15 @@
         : BpInterface<IOMX>(impl) {
     }
 
+    virtual bool livesLocally(pid_t pid) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+        data.writeInt32(pid);
+        remote()->transact(LIVES_LOCALLY, data, &reply);
+
+        return reply.readInt32() != 0;
+    }
+
     virtual status_t listNodes(List<ComponentInfo> *list) {
         list->clear();
 
@@ -369,6 +379,14 @@
 status_t BnOMX::onTransact(
     uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
     switch (code) {
+        case LIVES_LOCALLY:
+        {
+            CHECK_INTERFACE(IOMX, data, reply);
+            reply->writeInt32(livesLocally((pid_t)data.readInt32()));
+
+            return OK;
+        }
+
         case LIST_NODES:
         {
             CHECK_INTERFACE(IOMX, data, reply);
@@ -408,7 +426,7 @@
             if (err == OK) {
                 reply->writeIntPtr((intptr_t)node);
             }
-                
+
             return NO_ERROR;
         }
 
@@ -419,7 +437,7 @@
             node_id node = (void*)data.readIntPtr();
 
             reply->writeInt32(freeNode(node));
-                
+
             return NO_ERROR;
         }
 
@@ -631,7 +649,7 @@
 
             node_id node = (void*)data.readIntPtr();
             const char *parameter_name = data.readCString();
-            
+
             OMX_INDEXTYPE index;
             status_t err = getExtensionIndex(node, parameter_name, &index);
 
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 040366b..c0664f3 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -34,48 +34,6 @@
 
 namespace android {
 
-// client singleton for binder interface to service
-Mutex MediaPlayer::sServiceLock;
-sp<IMediaPlayerService> MediaPlayer::sMediaPlayerService;
-sp<MediaPlayer::DeathNotifier> MediaPlayer::sDeathNotifier;
-SortedVector< wp<MediaPlayer> > MediaPlayer::sObitRecipients;
-
-// establish binder interface to service
-const sp<IMediaPlayerService>& MediaPlayer::getMediaPlayerService()
-{
-    Mutex::Autolock _l(sServiceLock);
-    if (sMediaPlayerService.get() == 0) {
-        sp<IServiceManager> sm = defaultServiceManager();
-        sp<IBinder> binder;
-        do {
-            binder = sm->getService(String16("media.player"));
-            if (binder != 0)
-                break;
-            LOGW("MediaPlayerService not published, waiting...");
-            usleep(500000); // 0.5 s
-        } while(true);
-        if (sDeathNotifier == NULL) {
-            sDeathNotifier = new DeathNotifier();
-        }
-        binder->linkToDeath(sDeathNotifier);
-        sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
-    }
-    LOGE_IF(sMediaPlayerService==0, "no MediaPlayerService!?");
-    return sMediaPlayerService;
-}
-
-void MediaPlayer::addObitRecipient(const wp<MediaPlayer>& recipient)
-{
-    Mutex::Autolock _l(sServiceLock);
-    sObitRecipients.add(recipient);
-}
-
-void MediaPlayer::removeObitRecipient(const wp<MediaPlayer>& recipient)
-{
-    Mutex::Autolock _l(sServiceLock);
-    sObitRecipients.remove(recipient);
-}
-
 MediaPlayer::MediaPlayer()
 {
     LOGV("constructor");
@@ -94,15 +52,9 @@
     mLockThreadId = 0;
 }
 
-void MediaPlayer::onFirstRef()
-{
-    addObitRecipient(this);
-}
-
 MediaPlayer::~MediaPlayer()
 {
     LOGV("destructor");
-    removeObitRecipient(this);
     disconnect();
     IPCThreadState::self()->flushCommands();
 }
@@ -630,45 +582,13 @@
     }
 }
 
-void MediaPlayer::DeathNotifier::binderDied(const wp<IBinder>& who) {
-    LOGW("MediaPlayer server died!");
-
-    // Need to do this with the lock held
-    SortedVector< wp<MediaPlayer> > list;
-    {
-        Mutex::Autolock _l(MediaPlayer::sServiceLock);
-        MediaPlayer::sMediaPlayerService.clear();
-        list = sObitRecipients;
-    }
-
-    // Notify application when media server dies.
-    // Don't hold the static lock during callback in case app
-    // makes a call that needs the lock.
-    size_t count = list.size();
-    for (size_t iter = 0; iter < count; ++iter) {
-        sp<MediaPlayer> player = list[iter].promote();
-        if ((player != 0) && (player->mPlayer != 0)) {
-            player->notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
-        }
-    }
-}
-
-MediaPlayer::DeathNotifier::~DeathNotifier()
-{
-    Mutex::Autolock _l(sServiceLock);
-    sObitRecipients.clear();
-    if (sMediaPlayerService != 0) {
-        sMediaPlayerService->asBinder()->unlinkToDeath(this);
-    }
-}
-
 /*static*/ sp<IMemory> MediaPlayer::decode(const char* url, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
 {
     LOGV("decode(%s)", url);
     sp<IMemory> p;
     const sp<IMediaPlayerService>& service = getMediaPlayerService();
     if (service != 0) {
-        p = sMediaPlayerService->decode(url, pSampleRate, pNumChannels, pFormat);
+        p = service->decode(url, pSampleRate, pNumChannels, pFormat);
     } else {
         LOGE("Unable to locate media service");
     }
@@ -676,13 +596,19 @@
 
 }
 
+void MediaPlayer::died()
+{
+    LOGV("died");
+    notify(MEDIA_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
+}
+
 /*static*/ sp<IMemory> MediaPlayer::decode(int fd, int64_t offset, int64_t length, uint32_t *pSampleRate, int* pNumChannels, int* pFormat)
 {
     LOGV("decode(%d, %lld, %lld)", fd, offset, length);
     sp<IMemory> p;
     const sp<IMediaPlayerService>& service = getMediaPlayerService();
     if (service != 0) {
-        p = sMediaPlayerService->decode(fd, offset, length, pSampleRate, pNumChannels, pFormat);
+        p = service->decode(fd, offset, length, pSampleRate, pNumChannels, pFormat);
     } else {
         LOGE("Unable to locate media service");
     }
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 6b63931..7b5dabb 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -24,6 +24,7 @@
 #include <utils/String8.h>
 #include <media/IMediaPlayerService.h>
 #include <media/IMediaRecorder.h>
+#include <media/mediaplayer.h>  // for MEDIA_ERROR_SERVER_DIED
 
 namespace android {
 
@@ -576,19 +577,8 @@
 MediaRecorder::MediaRecorder()
 {
     LOGV("constructor");
-    sp<IServiceManager> sm = defaultServiceManager();
-    sp<IBinder> binder;
 
-    do {
-        binder = sm->getService(String16("media.player"));
-        if (binder != NULL) {
-            break;
-        }
-        LOGW("MediaPlayerService not published, waiting...");
-        usleep(500000); // 0.5 s
-    } while(true);
-
-    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
+    const sp<IMediaPlayerService>& service(getMediaPlayerService());
     if (service != NULL) {
         mMediaRecorder = service->createMediaRecorder(getpid());
     }
@@ -637,5 +627,11 @@
     }
 }
 
+void MediaRecorder::died()
+{
+    LOGV("died");
+    notify(MEDIA_RECORDER_EVENT_ERROR, MEDIA_ERROR_SERVER_DIED, 0);
+}
+
 }; // namespace android
 
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index e36e78c..26b9357 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -29,6 +29,7 @@
         MPEG4Extractor.cpp        \
         MPEG4Writer.cpp           \
         MediaExtractor.cpp        \
+        SampleIterator.cpp        \
         SampleTable.cpp           \
         ShoutcastSource.cpp       \
         StagefrightMediaScanner.cpp \
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 07a5a82..0e9900b 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -232,8 +232,9 @@
             uint32_t sampleIndex;
             uint32_t sampleTime;
             if (track->sampleTable->findThumbnailSample(&sampleIndex) == OK
-                    && track->sampleTable->getDecodingTime(
-                        sampleIndex, &sampleTime) == OK) {
+                    && track->sampleTable->getMetaDataForSample(
+                        sampleIndex, NULL /* offset */, NULL /* size */,
+                        &sampleTime) == OK) {
                 track->meta->setInt64(
                         kKeyThumbnailTime,
                         ((int64_t)sampleTime * 1000000) / track->timescale);
@@ -929,20 +930,16 @@
     if (mBuffer == NULL) {
         newBuffer = true;
 
-        status_t err = mSampleTable->getSampleOffsetAndSize(
-                mCurrentSampleIndex, &offset, &size);
-
-        if (err != OK) {
-            return err;
-        }
-
-        err = mSampleTable->getDecodingTime(mCurrentSampleIndex, &dts);
+        status_t err =
+            mSampleTable->getMetaDataForSample(
+                    mCurrentSampleIndex, &offset, &size, &dts);
 
         if (err != OK) {
             return err;
         }
 
         err = mGroup->acquire_buffer(&mBuffer);
+
         if (err != OK) {
             CHECK_EQ(mBuffer, NULL);
             return err;
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index c4d3b5d..c583b93 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1016,6 +1016,7 @@
         const char *componentName,
         const sp<MediaSource> &source)
     : mOMX(omx),
+      mOMXLivesLocally(omx->livesLocally(getpid())),
       mNode(node),
       mQuirks(quirks),
       mIsEncoder(isEncoder),
@@ -1191,12 +1192,22 @@
         IOMX::buffer_id buffer;
         if (portIndex == kPortIndexInput
                 && (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
-            err = mOMX->allocateBufferWithBackup(
-                    mNode, portIndex, mem, &buffer);
+            if (mOMXLivesLocally) {
+                err = mOMX->allocateBuffer(
+                        mNode, portIndex, def.nBufferSize, &buffer);
+            } else {
+                err = mOMX->allocateBufferWithBackup(
+                        mNode, portIndex, mem, &buffer);
+            }
         } else if (portIndex == kPortIndexOutput
                 && (mQuirks & kRequiresAllocateBufferOnOutputPorts)) {
-            err = mOMX->allocateBufferWithBackup(
-                    mNode, portIndex, mem, &buffer);
+            if (mOMXLivesLocally) {
+                err = mOMX->allocateBuffer(
+                        mNode, portIndex, def.nBufferSize, &buffer);
+            } else {
+                err = mOMX->allocateBufferWithBackup(
+                        mNode, portIndex, mem, &buffer);
+            }
         } else {
             err = mOMX->useBuffer(mNode, portIndex, mem, &buffer);
         }
diff --git a/media/libstagefright/SampleIterator.cpp b/media/libstagefright/SampleIterator.cpp
new file mode 100644
index 0000000..faad42ba
--- /dev/null
+++ b/media/libstagefright/SampleIterator.cpp
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#define LOG_TAG "SampleIterator"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include "include/SampleIterator.h"
+
+#include <arpa/inet.h>
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaDebug.h>
+#include <media/stagefright/Utils.h>
+
+#include "include/SampleTable.h"
+
+namespace android {
+
+SampleIterator::SampleIterator(SampleTable *table)
+    : mTable(table),
+      mInitialized(false),
+      mTimeToSampleIndex(0),
+      mTTSSampleIndex(0),
+      mTTSSampleTime(0),
+      mTTSCount(0),
+      mTTSDuration(0) {
+    reset();
+}
+
+void SampleIterator::reset() {
+    mSampleToChunkIndex = 0;
+    mFirstChunk = 0;
+    mFirstChunkSampleIndex = 0;
+    mStopChunk = 0;
+    mStopChunkSampleIndex = 0;
+    mSamplesPerChunk = 0;
+    mChunkDesc = 0;
+}
+
+status_t SampleIterator::seekTo(uint32_t sampleIndex) {
+    LOGV("seekTo(%d)", sampleIndex);
+
+    if (mTable->mSampleToChunkOffset < 0
+            || mTable->mChunkOffsetOffset < 0
+            || mTable->mSampleSizeOffset < 0
+            || mTable->mTimeToSampleCount == 0) {
+
+        return ERROR_MALFORMED;
+    }
+
+    if (mInitialized && mCurrentSampleIndex == sampleIndex) {
+        return OK;
+    }
+
+    if (!mInitialized || sampleIndex < mFirstChunkSampleIndex) {
+        reset();
+    }
+
+    if (sampleIndex >= mStopChunkSampleIndex) {
+        status_t err;
+        if ((err = findChunkRange(sampleIndex)) != OK) {
+            LOGE("findChunkRange failed");
+            return err;
+        }
+    }
+
+    CHECK(sampleIndex < mStopChunkSampleIndex);
+
+    uint32_t chunk =
+        (sampleIndex - mFirstChunkSampleIndex) / mSamplesPerChunk
+        + mFirstChunk;
+
+    if (!mInitialized || chunk != mCurrentChunkIndex) {
+        mCurrentChunkIndex = chunk;
+
+        status_t err;
+        if ((err = getChunkOffset(chunk, &mCurrentChunkOffset)) != OK) {
+            LOGE("getChunkOffset return error");
+            return err;
+        }
+
+        mCurrentChunkSampleSizes.clear();
+
+        uint32_t firstChunkSampleIndex =
+            mFirstChunkSampleIndex
+                + mSamplesPerChunk * (mCurrentChunkIndex - mFirstChunk);
+
+        for (uint32_t i = 0; i < mSamplesPerChunk; ++i) {
+            size_t sampleSize;
+            if ((err = getSampleSizeDirect(
+                            firstChunkSampleIndex + i, &sampleSize)) != OK) {
+                LOGE("getSampleSizeDirect return error");
+                return err;
+            }
+
+            mCurrentChunkSampleSizes.push(sampleSize);
+        }
+    }
+
+    uint32_t chunkRelativeSampleIndex =
+        (sampleIndex - mFirstChunkSampleIndex) % mSamplesPerChunk;
+
+    mCurrentSampleOffset = mCurrentChunkOffset;
+    for (uint32_t i = 0; i < chunkRelativeSampleIndex; ++i) {
+        mCurrentSampleOffset += mCurrentChunkSampleSizes[i];
+    }
+
+    mCurrentSampleSize = mCurrentChunkSampleSizes[chunkRelativeSampleIndex];
+    if (sampleIndex < mTTSSampleIndex) {
+        mTimeToSampleIndex = 0;
+        mTTSSampleIndex = 0;
+        mTTSSampleTime = 0;
+        mTTSCount = 0;
+        mTTSDuration = 0;
+    }
+
+    status_t err;
+    if ((err = findSampleTime(sampleIndex, &mCurrentSampleTime)) != OK) {
+        LOGE("findSampleTime return error");
+        return err;
+    }
+
+    mCurrentSampleIndex = sampleIndex;
+
+    mInitialized = true;
+
+    return OK;
+}
+
+status_t SampleIterator::findChunkRange(uint32_t sampleIndex) {
+    CHECK(sampleIndex >= mFirstChunkSampleIndex);
+
+    while (sampleIndex >= mStopChunkSampleIndex) {
+        if (mSampleToChunkIndex == mTable->mNumSampleToChunkOffsets) {
+            return ERROR_OUT_OF_RANGE;
+        }
+
+        mFirstChunkSampleIndex = mStopChunkSampleIndex;
+
+        const SampleTable::SampleToChunkEntry *entry =
+            &mTable->mSampleToChunkEntries[mSampleToChunkIndex];
+
+        mFirstChunk = entry->startChunk;
+        mSamplesPerChunk = entry->samplesPerChunk;
+        mChunkDesc = entry->chunkDesc;
+
+        if (mSampleToChunkIndex + 1 < mTable->mNumSampleToChunkOffsets) {
+            mStopChunk = entry[1].startChunk;
+
+            mStopChunkSampleIndex =
+                mFirstChunkSampleIndex
+                    + (mStopChunk - mFirstChunk) * mSamplesPerChunk;
+        } else {
+            mStopChunk = 0xffffffff;
+            mStopChunkSampleIndex = 0xffffffff;
+        }
+
+        ++mSampleToChunkIndex;
+    }
+
+    return OK;
+}
+
+status_t SampleIterator::getChunkOffset(uint32_t chunk, off_t *offset) {
+    *offset = 0;
+
+    if (chunk >= mTable->mNumChunkOffsets) {
+        return ERROR_OUT_OF_RANGE;
+    }
+
+    if (mTable->mChunkOffsetType == SampleTable::kChunkOffsetType32) {
+        uint32_t offset32;
+
+        if (mTable->mDataSource->readAt(
+                    mTable->mChunkOffsetOffset + 8 + 4 * chunk,
+                    &offset32,
+                    sizeof(offset32)) < (ssize_t)sizeof(offset32)) {
+            return ERROR_IO;
+        }
+
+        *offset = ntohl(offset32);
+    } else {
+        CHECK_EQ(mTable->mChunkOffsetType, SampleTable::kChunkOffsetType64);
+
+        uint64_t offset64;
+        if (mTable->mDataSource->readAt(
+                    mTable->mChunkOffsetOffset + 8 + 8 * chunk,
+                    &offset64,
+                    sizeof(offset64)) < (ssize_t)sizeof(offset64)) {
+            return ERROR_IO;
+        }
+
+        *offset = ntoh64(offset64);
+    }
+
+    return OK;
+}
+
+status_t SampleIterator::getSampleSizeDirect(
+        uint32_t sampleIndex, size_t *size) {
+    *size = 0;
+
+    if (sampleIndex >= mTable->mNumSampleSizes) {
+        return ERROR_OUT_OF_RANGE;
+    }
+
+    if (mTable->mDefaultSampleSize > 0) {
+        *size = mTable->mDefaultSampleSize;
+        return OK;
+    }
+
+    switch (mTable->mSampleSizeFieldSize) {
+        case 32:
+        {
+            if (mTable->mDataSource->readAt(
+                        mTable->mSampleSizeOffset + 12 + 4 * sampleIndex,
+                        size, sizeof(*size)) < (ssize_t)sizeof(*size)) {
+                return ERROR_IO;
+            }
+
+            *size = ntohl(*size);
+            break;
+        }
+
+        case 16:
+        {
+            uint16_t x;
+            if (mTable->mDataSource->readAt(
+                        mTable->mSampleSizeOffset + 12 + 2 * sampleIndex,
+                        &x, sizeof(x)) < (ssize_t)sizeof(x)) {
+                return ERROR_IO;
+            }
+
+            *size = ntohs(x);
+            break;
+        }
+
+        case 8:
+        {
+            uint8_t x;
+            if (mTable->mDataSource->readAt(
+                        mTable->mSampleSizeOffset + 12 + sampleIndex,
+                        &x, sizeof(x)) < (ssize_t)sizeof(x)) {
+                return ERROR_IO;
+            }
+
+            *size = x;
+            break;
+        }
+
+        default:
+        {
+            CHECK_EQ(mTable->mSampleSizeFieldSize, 4);
+
+            uint8_t x;
+            if (mTable->mDataSource->readAt(
+                        mTable->mSampleSizeOffset + 12 + sampleIndex / 2,
+                        &x, sizeof(x)) < (ssize_t)sizeof(x)) {
+                return ERROR_IO;
+            }
+
+            *size = (sampleIndex & 1) ? x & 0x0f : x >> 4;
+            break;
+        }
+    }
+
+    return OK;
+}
+
+status_t SampleIterator::findSampleTime(
+        uint32_t sampleIndex, uint32_t *time) {
+    if (sampleIndex >= mTable->mNumSampleSizes) {
+        return ERROR_OUT_OF_RANGE;
+    }
+
+    while (sampleIndex >= mTTSSampleIndex + mTTSCount) {
+        if (mTimeToSampleIndex == mTable->mTimeToSampleCount) {
+            return ERROR_OUT_OF_RANGE;
+        }
+
+        mTTSSampleIndex += mTTSCount;
+        mTTSSampleTime += mTTSCount * mTTSDuration;
+
+        mTTSCount = mTable->mTimeToSample[2 * mTimeToSampleIndex];
+        mTTSDuration = mTable->mTimeToSample[2 * mTimeToSampleIndex + 1];
+
+        ++mTimeToSampleIndex;
+    }
+
+    *time = mTTSSampleTime + mTTSDuration * (sampleIndex - mTTSSampleIndex);
+
+    return OK;
+}
+
+}  // namespace android
+
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index 2de96d4..89a522e 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -15,9 +15,11 @@
  */
 
 #define LOG_TAG "SampleTable"
+//#define LOG_NDEBUG 0
 #include <utils/Log.h>
 
 #include "include/SampleTable.h"
+#include "include/SampleIterator.h"
 
 #include <arpa/inet.h>
 
@@ -27,10 +29,16 @@
 
 namespace android {
 
-static const uint32_t kChunkOffsetType32 = FOURCC('s', 't', 'c', 'o');
-static const uint32_t kChunkOffsetType64 = FOURCC('c', 'o', '6', '4');
-static const uint32_t kSampleSizeType32 = FOURCC('s', 't', 's', 'z');
-static const uint32_t kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2');
+// static
+const uint32_t SampleTable::kChunkOffsetType32 = FOURCC('s', 't', 'c', 'o');
+// static
+const uint32_t SampleTable::kChunkOffsetType64 = FOURCC('c', 'o', '6', '4');
+// static
+const uint32_t SampleTable::kSampleSizeType32 = FOURCC('s', 't', 's', 'z');
+// static
+const uint32_t SampleTable::kSampleSizeTypeCompact = FOURCC('s', 't', 'z', '2');
+
+////////////////////////////////////////////////////////////////////////////////
 
 SampleTable::SampleTable(const sp<DataSource> &source)
     : mDataSource(source),
@@ -46,12 +54,20 @@
       mTimeToSampleCount(0),
       mTimeToSample(NULL),
       mSyncSampleOffset(-1),
-      mNumSyncSamples(0) {
+      mNumSyncSamples(0),
+      mSampleToChunkEntries(NULL) {
+    mSampleIterator = new SampleIterator(this);
 }
 
 SampleTable::~SampleTable() {
+    delete[] mSampleToChunkEntries;
+    mSampleToChunkEntries = NULL;
+
     delete[] mTimeToSample;
     mTimeToSample = NULL;
+
+    delete mSampleIterator;
+    mSampleIterator = NULL;
 }
 
 status_t SampleTable::setChunkOffsetParams(
@@ -124,6 +140,25 @@
         return ERROR_MALFORMED;
     }
 
+    mSampleToChunkEntries =
+        new SampleToChunkEntry[mNumSampleToChunkOffsets];
+
+    for (uint32_t i = 0; i < mNumSampleToChunkOffsets; ++i) {
+        uint8_t buffer[12];
+        if (mDataSource->readAt(
+                    mSampleToChunkOffset + 8 + i * 12, buffer, sizeof(buffer))
+                != (ssize_t)sizeof(buffer)) {
+            return ERROR_IO;
+        }
+
+        CHECK(U32_AT(buffer) >= 1);  // chunk index is 1 based in the spec.
+
+        // We want the chunk index to be 0-based.
+        mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1;
+        mSampleToChunkEntries[i].samplesPerChunk = U32_AT(&buffer[4]);
+        mSampleToChunkEntries[i].chunkDesc = U32_AT(&buffer[8]);
+    }
+
     return OK;
 }
 
@@ -250,217 +285,10 @@
     return mNumChunkOffsets;
 }
 
-status_t SampleTable::getChunkOffset(uint32_t chunk_index, off_t *offset) {
-    *offset = 0;
-
-    if (mChunkOffsetOffset < 0) {
-        return ERROR_MALFORMED;
-    }
-
-    if (chunk_index >= mNumChunkOffsets) {
-        return ERROR_OUT_OF_RANGE;
-    }
-
-    if (mChunkOffsetType == kChunkOffsetType32) {
-        uint32_t offset32;
-
-        if (mDataSource->readAt(
-                    mChunkOffsetOffset + 8 + 4 * chunk_index,
-                    &offset32,
-                    sizeof(offset32)) < (ssize_t)sizeof(offset32)) {
-            return ERROR_IO;
-        }
-
-        *offset = ntohl(offset32);
-    } else {
-        CHECK_EQ(mChunkOffsetType, kChunkOffsetType64);
-
-        uint64_t offset64;
-        if (mDataSource->readAt(
-                    mChunkOffsetOffset + 8 + 8 * chunk_index,
-                    &offset64,
-                    sizeof(offset64)) < (ssize_t)sizeof(offset64)) {
-            return ERROR_IO;
-        }
-
-        *offset = ntoh64(offset64);
-    }
-
-    return OK;
-}
-
-status_t SampleTable::getChunkForSample(
-        uint32_t sample_index,
-        uint32_t *chunk_index,
-        uint32_t *chunk_relative_sample_index,
-        uint32_t *desc_index) {
-    *chunk_index = 0;
-    *chunk_relative_sample_index = 0;
-    *desc_index = 0;
-
-    if (mSampleToChunkOffset < 0) {
-        return ERROR_MALFORMED;
-    }
-
-    if (sample_index >= countSamples()) {
-        return ERROR_END_OF_STREAM;
-    }
-
-    uint32_t first_chunk = 0;
-    uint32_t samples_per_chunk = 0;
-    uint32_t chunk_desc_index = 0;
-
-    uint32_t index = 0;
-    while (index < mNumSampleToChunkOffsets) {
-        uint8_t buffer[12];
-        if (mDataSource->readAt(mSampleToChunkOffset + 8 + index * 12,
-                                 buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) {
-            return ERROR_IO;
-        }
-
-        uint32_t stop_chunk = U32_AT(buffer);
-        if (sample_index < (stop_chunk - first_chunk) * samples_per_chunk) {
-            break;
-        }
-
-        sample_index -= (stop_chunk - first_chunk) * samples_per_chunk;
-        first_chunk = stop_chunk;
-        samples_per_chunk = U32_AT(&buffer[4]);
-        chunk_desc_index = U32_AT(&buffer[8]);
-
-        ++index;
-    }
-
-    *chunk_index = sample_index / samples_per_chunk + first_chunk - 1;
-    *chunk_relative_sample_index = sample_index % samples_per_chunk;
-    *desc_index = chunk_desc_index;
-
-    return OK;
-}
-
 uint32_t SampleTable::countSamples() const {
     return mNumSampleSizes;
 }
 
-status_t SampleTable::getSampleSize(
-        uint32_t sample_index, size_t *sample_size) {
-    *sample_size = 0;
-
-    if (mSampleSizeOffset < 0) {
-        return ERROR_MALFORMED;
-    }
-
-    if (sample_index >= mNumSampleSizes) {
-        return ERROR_OUT_OF_RANGE;
-    }
-
-    if (mDefaultSampleSize > 0) {
-        *sample_size = mDefaultSampleSize;
-        return OK;
-    }
-
-    switch (mSampleSizeFieldSize) {
-        case 32:
-        {
-            if (mDataSource->readAt(
-                        mSampleSizeOffset + 12 + 4 * sample_index,
-                        sample_size, sizeof(*sample_size)) < (ssize_t)sizeof(*sample_size)) {
-                return ERROR_IO;
-            }
-
-            *sample_size = ntohl(*sample_size);
-            break;
-        }
-
-        case 16:
-        {
-            uint16_t x;
-            if (mDataSource->readAt(
-                        mSampleSizeOffset + 12 + 2 * sample_index,
-                        &x, sizeof(x)) < (ssize_t)sizeof(x)) {
-                return ERROR_IO;
-            }
-
-            *sample_size = ntohs(x);
-            break;
-        }
-
-        case 8:
-        {
-            uint8_t x;
-            if (mDataSource->readAt(
-                        mSampleSizeOffset + 12 + sample_index,
-                        &x, sizeof(x)) < (ssize_t)sizeof(x)) {
-                return ERROR_IO;
-            }
-
-            *sample_size = x;
-            break;
-        }
-
-        default:
-        {
-            CHECK_EQ(mSampleSizeFieldSize, 4);
-
-            uint8_t x;
-            if (mDataSource->readAt(
-                        mSampleSizeOffset + 12 + sample_index / 2,
-                        &x, sizeof(x)) < (ssize_t)sizeof(x)) {
-                return ERROR_IO;
-            }
-
-            *sample_size = (sample_index & 1) ? x & 0x0f : x >> 4;
-            break;
-        }
-    }
-
-    return OK;
-}
-
-status_t SampleTable::getSampleOffsetAndSize(
-        uint32_t sample_index, off_t *offset, size_t *size) {
-    Mutex::Autolock autoLock(mLock);
-
-    *offset = 0;
-    *size = 0;
-
-    uint32_t chunk_index;
-    uint32_t chunk_relative_sample_index;
-    uint32_t desc_index;
-    status_t err = getChunkForSample(
-            sample_index, &chunk_index, &chunk_relative_sample_index,
-            &desc_index);
-
-    if (err != OK) {
-        return err;
-    }
-
-    err = getChunkOffset(chunk_index, offset);
-
-    if (err != OK) {
-        return err;
-    }
-
-    for (uint32_t j = 0; j < chunk_relative_sample_index; ++j) {
-        size_t sample_size;
-        err = getSampleSize(sample_index - j - 1, &sample_size);
-
-        if (err != OK) {
-            return err;
-        }
-
-        *offset += sample_size;
-    }
-
-    err = getSampleSize(sample_index, size);
-
-    if (err != OK) {
-        return err;
-    }
-
-    return OK;
-}
-
 status_t SampleTable::getMaxSampleSize(size_t *max_size) {
     Mutex::Autolock autoLock(mLock);
 
@@ -468,7 +296,7 @@
 
     for (uint32_t i = 0; i < mNumSampleSizes; ++i) {
         size_t sample_size;
-        status_t err = getSampleSize(i, &sample_size);
+        status_t err = getSampleSize_l(i, &sample_size);
 
         if (err != OK) {
             return err;
@@ -482,34 +310,6 @@
     return OK;
 }
 
-status_t SampleTable::getDecodingTime(uint32_t sample_index, uint32_t *time) {
-    // XXX FIXME idiotic (for the common use-case) O(n) algorithm below...
-
-    Mutex::Autolock autoLock(mLock);
-
-    if (sample_index >= mNumSampleSizes) {
-        return ERROR_OUT_OF_RANGE;
-    }
-
-    uint32_t cur_sample = 0;
-    *time = 0;
-    for (uint32_t i = 0; i < mTimeToSampleCount; ++i) {
-        uint32_t n = mTimeToSample[2 * i];
-        uint32_t delta = mTimeToSample[2 * i + 1];
-
-        if (sample_index < cur_sample + n) {
-            *time += delta * (sample_index - cur_sample);
-
-            return OK;
-        }
-
-        *time += delta * n;
-        cur_sample += n;
-    }
-
-    return ERROR_OUT_OF_RANGE;
-}
-
 uint32_t abs_difference(uint32_t time1, uint32_t time2) {
     return time1 > time2 ? time1 - time2 : time2 - time1;
 }
@@ -539,7 +339,7 @@
             }
 
             if (flags & kSyncSample_Flag) {
-                return findClosestSyncSample(*sample_index, sample_index);
+                return findClosestSyncSample_l(*sample_index, sample_index);
             }
 
             return OK;
@@ -552,7 +352,7 @@
     return ERROR_OUT_OF_RANGE;
 }
 
-status_t SampleTable::findClosestSyncSample(
+status_t SampleTable::findClosestSyncSample_l(
         uint32_t start_sample_index, uint32_t *sample_index) {
     *sample_index = 0;
 
@@ -590,6 +390,8 @@
 }
 
 status_t SampleTable::findThumbnailSample(uint32_t *sample_index) {
+    Mutex::Autolock autoLock(mLock);
+
     if (mSyncSampleOffset < 0) {
         // All samples are sync-samples.
         *sample_index = 0;
@@ -620,7 +422,7 @@
 
         // Now x is a sample index.
         size_t sampleSize;
-        status_t err = getSampleSize(x, &sampleSize);
+        status_t err = getSampleSize_l(x, &sampleSize);
         if (err != OK) {
             return err;
         }
@@ -636,5 +438,38 @@
     return OK;
 }
 
+status_t SampleTable::getSampleSize_l(
+        uint32_t sampleIndex, size_t *sampleSize) {
+    return mSampleIterator->getSampleSizeDirect(
+            sampleIndex, sampleSize);
+}
+
+status_t SampleTable::getMetaDataForSample(
+        uint32_t sampleIndex,
+        off_t *offset,
+        size_t *size,
+        uint32_t *decodingTime) {
+    Mutex::Autolock autoLock(mLock);
+
+    status_t err;
+    if ((err = mSampleIterator->seekTo(sampleIndex)) != OK) {
+        return err;
+    }
+
+    if (offset) {
+        *offset = mSampleIterator->getSampleOffset();
+    }
+
+    if (size) {
+        *size = mSampleIterator->getSampleSize();
+    }
+
+    if (decodingTime) {
+        *decodingTime = mSampleIterator->getSampleTime();
+    }
+
+    return OK;
+}
+
 }  // namespace android
 
diff --git a/media/libstagefright/id3/ID3.cpp b/media/libstagefright/id3/ID3.cpp
index 2b3ef1a..6d64717 100644
--- a/media/libstagefright/id3/ID3.cpp
+++ b/media/libstagefright/id3/ID3.cpp
@@ -33,7 +33,11 @@
       mSize(0),
       mFirstFrameOffset(0),
       mVersion(ID3_UNKNOWN) {
-    mIsValid = parse(source);
+    mIsValid = parseV2(source);
+
+    if (!mIsValid) {
+        mIsValid = parseV1(source);
+    }
 }
 
 ID3::~ID3() {
@@ -51,7 +55,7 @@
     return mVersion;
 }
 
-bool ID3::parse(const sp<DataSource> &source) {
+bool ID3::parseV2(const sp<DataSource> &source) {
     struct id3_header {
         char id[3];
         uint8_t version_major;
@@ -119,7 +123,7 @@
     }
 
     if (header.flags & 0x80) {
-        LOGI("removing unsynchronization");
+        LOGV("removing unsynchronization");
         removeUnsynchronization();
     }
 
@@ -128,12 +132,18 @@
         // Version 2.3 has an optional extended header.
 
         if (mSize < 4) {
+            free(mData);
+            mData = NULL;
+
             return false;
         }
 
         size_t extendedHeaderSize = U32_AT(&mData[0]) + 4;
 
         if (extendedHeaderSize > mSize) {
+            free(mData);
+            mData = NULL;
+
             return false;
         }
 
@@ -147,6 +157,9 @@
                 size_t paddingSize = U32_AT(&mData[6]);
 
                 if (mFirstFrameOffset + paddingSize > mSize) {
+                    free(mData);
+                    mData = NULL;
+
                     return false;
                 }
 
@@ -154,7 +167,7 @@
             }
 
             if (extendedFlags & 0x8000) {
-                LOGI("have crc");
+                LOGV("have crc");
             }
         }
     }
@@ -221,9 +234,37 @@
 
     if (mParent.mVersion == ID3_V2_2) {
         id->setTo((const char *)&mParent.mData[mOffset], 3);
-    } else {
-        CHECK_EQ(mParent.mVersion, ID3_V2_3);
+    } else if (mParent.mVersion == ID3_V2_3) {
         id->setTo((const char *)&mParent.mData[mOffset], 4);
+    } else {
+        CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1);
+
+        switch (mOffset) {
+            case 3:
+                id->setTo("TT2");
+                break;
+            case 33:
+                id->setTo("TP1");
+                break;
+            case 63:
+                id->setTo("TAL");
+                break;
+            case 93:
+                id->setTo("TYE");
+                break;
+            case 97:
+                id->setTo("COM");
+                break;
+            case 126:
+                id->setTo("TRK");
+                break;
+            case 127:
+                id->setTo("TCO");
+                break;
+            default:
+                CHECK(!"should not be here.");
+                break;
+        }
     }
 }
 
@@ -273,6 +314,20 @@
         return;
     }
 
+    if (mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1) {
+        if (mOffset == 126 || mOffset == 127) {
+            // Special treatment for the track number and genre.
+            char tmp[16];
+            sprintf(tmp, "%d", (int)*mFrameData);
+
+            id->setTo(tmp);
+            return;
+        }
+
+        id->setTo((const char *)mFrameData, mFrameSize);
+        return;
+    }
+
     size_t n = mFrameSize - getHeaderLength() - 1;
 
     if (*mFrameData == 0x00) {
@@ -280,7 +335,8 @@
         convertISO8859ToString8(mFrameData + 1, n, id);
     } else {
         // UCS-2
-        id->setTo((const char16_t *)(mFrameData + 1), n);
+        // API wants number of characters, not number of bytes...
+        id->setTo((const char16_t *)(mFrameData + 1), n / 2);
     }
 }
 
@@ -299,9 +355,11 @@
 size_t ID3::Iterator::getHeaderLength() const {
     if (mParent.mVersion == ID3_V2_2) {
         return 6;
-    } else {
-        CHECK_EQ(mParent.mVersion, ID3_V2_3);
+    } else if (mParent.mVersion == ID3_V2_3) {
         return 10;
+    } else {
+        CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1);
+        return 0;
     }
 }
 
@@ -345,9 +403,7 @@
             if (!strcmp(id, mID)) {
                 break;
             }
-        } else {
-            CHECK_EQ(mParent.mVersion, ID3_V2_3);
-
+        } else if (mParent.mVersion == ID3_V2_3) {
             if (mOffset + 10 > mParent.mSize) {
                 return;
             }
@@ -377,6 +433,52 @@
             if (!strcmp(id, mID)) {
                 break;
             }
+        } else {
+            CHECK(mParent.mVersion == ID3_V1 || mParent.mVersion == ID3_V1_1);
+
+            if (mOffset >= mParent.mSize) {
+                return;
+            }
+
+            mFrameData = &mParent.mData[mOffset];
+
+            switch (mOffset) {
+                case 3:
+                case 33:
+                case 63:
+                    mFrameSize = 30;
+                    break;
+                case 93:
+                    mFrameSize = 4;
+                    break;
+                case 97:
+                    if (mParent.mVersion == ID3_V1) {
+                        mFrameSize = 30;
+                    } else {
+                        mFrameSize = 29;
+                    }
+                    break;
+                case 126:
+                    mFrameSize = 1;
+                    break;
+                case 127:
+                    mFrameSize = 1;
+                    break;
+                default:
+                    CHECK(!"Should not be here, invalid offset.");
+                    break;
+            }
+
+            if (!mID) {
+                break;
+            }
+
+            String8 id;
+            getID(&id);
+
+            if (id == mID) {
+                break;
+            }
         }
 
         mOffset += mFrameSize;
@@ -461,5 +563,40 @@
     return NULL;
 }
 
+bool ID3::parseV1(const sp<DataSource> &source) {
+    const size_t V1_TAG_SIZE = 128;
+
+    off_t size;
+    if (source->getSize(&size) != OK || size < (off_t)V1_TAG_SIZE) {
+        return false;
+    }
+
+    mData = (uint8_t *)malloc(V1_TAG_SIZE);
+    if (source->readAt(size - V1_TAG_SIZE, mData, V1_TAG_SIZE)
+            != (ssize_t)V1_TAG_SIZE) {
+        free(mData);
+        mData = NULL;
+
+        return false;
+    }
+
+    if (memcmp("TAG", mData, 3)) {
+        free(mData);
+        mData = NULL;
+
+        return false;
+    }
+
+    mSize = V1_TAG_SIZE;
+    mFirstFrameOffset = 3;
+
+    if (mData[V1_TAG_SIZE - 3] != 0) {
+        mVersion = ID3_V1;
+    } else {
+        mVersion = ID3_V1_1;
+    }
+
+    return true;
+}
 
 }  // namespace android
diff --git a/media/libstagefright/id3/testid3.cpp b/media/libstagefright/id3/testid3.cpp
index 305b065..0741045 100644
--- a/media/libstagefright/id3/testid3.cpp
+++ b/media/libstagefright/id3/testid3.cpp
@@ -16,6 +16,8 @@
 
 #include "../include/ID3.h"
 
+#include <sys/stat.h>
+
 #include <ctype.h>
 #include <dirent.h>
 
@@ -108,6 +110,12 @@
 }
 
 void scan(const char *path) {
+    struct stat st;
+    if (stat(path, &st) == 0 && S_ISREG(st.st_mode)) {
+        scanFile(path);
+        return;
+    }
+
     DIR *dir = opendir(path);
 
     if (dir == NULL) {
diff --git a/media/libstagefright/include/ID3.h b/media/libstagefright/include/ID3.h
index 79931ac..da042a3 100644
--- a/media/libstagefright/include/ID3.h
+++ b/media/libstagefright/include/ID3.h
@@ -28,6 +28,8 @@
 struct ID3 {
     enum Version {
         ID3_UNKNOWN,
+        ID3_V1,
+        ID3_V1_1,
         ID3_V2_2,
         ID3_V2_3
     };
@@ -74,7 +76,8 @@
     size_t mFirstFrameOffset;
     Version mVersion;
 
-    bool parse(const sp<DataSource> &source);
+    bool parseV1(const sp<DataSource> &source);
+    bool parseV2(const sp<DataSource> &source);
     void removeUnsynchronization();
 
     ID3(const ID3 &);
diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h
index ce0b0d55aa..b559101 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -31,6 +31,8 @@
 public:
     OMX();
 
+    virtual bool livesLocally(pid_t pid);
+
     virtual status_t listNodes(List<ComponentInfo> *list);
 
     virtual status_t allocateNode(
diff --git a/media/libstagefright/include/SampleIterator.h b/media/libstagefright/include/SampleIterator.h
new file mode 100644
index 0000000..a5eaed9
--- /dev/null
+++ b/media/libstagefright/include/SampleIterator.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2010 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 <utils/Vector.h>
+
+namespace android {
+
+struct SampleTable;
+
+struct SampleIterator {
+    SampleIterator(SampleTable *table);
+
+    status_t seekTo(uint32_t sampleIndex);
+
+    uint32_t getChunkIndex() const { return mCurrentChunkIndex; }
+    uint32_t getDescIndex() const { return mChunkDesc; }
+    off_t getSampleOffset() const { return mCurrentSampleOffset; }
+    size_t getSampleSize() const { return mCurrentSampleSize; }
+    uint32_t getSampleTime() const { return mCurrentSampleTime; }
+
+    status_t getSampleSizeDirect(
+            uint32_t sampleIndex, size_t *size);
+
+private:
+    SampleTable *mTable;
+
+    bool mInitialized;
+
+    uint32_t mSampleToChunkIndex;
+    uint32_t mFirstChunk;
+    uint32_t mFirstChunkSampleIndex;
+    uint32_t mStopChunk;
+    uint32_t mStopChunkSampleIndex;
+    uint32_t mSamplesPerChunk;
+    uint32_t mChunkDesc;
+
+    uint32_t mCurrentChunkIndex;
+    off_t mCurrentChunkOffset;
+    Vector<size_t> mCurrentChunkSampleSizes;
+
+    uint32_t mTimeToSampleIndex;
+    uint32_t mTTSSampleIndex;
+    uint32_t mTTSSampleTime;
+    uint32_t mTTSCount;
+    uint32_t mTTSDuration;
+
+    uint32_t mCurrentSampleIndex;
+    off_t mCurrentSampleOffset;
+    size_t mCurrentSampleSize;
+    uint32_t mCurrentSampleTime;
+
+    void reset();
+    status_t findChunkRange(uint32_t sampleIndex);
+    status_t getChunkOffset(uint32_t chunk, off_t *offset);
+    status_t findSampleTime(uint32_t sampleIndex, uint32_t *time);
+
+    SampleIterator(const SampleIterator &);
+    SampleIterator &operator=(const SampleIterator &);
+};
+
+}  // namespace android
+
diff --git a/media/libstagefright/include/SampleTable.h b/media/libstagefright/include/SampleTable.h
index ead3431..533ce84 100644
--- a/media/libstagefright/include/SampleTable.h
+++ b/media/libstagefright/include/SampleTable.h
@@ -28,6 +28,7 @@
 namespace android {
 
 class DataSource;
+struct SampleIterator;
 
 class SampleTable : public RefBase {
 public:
@@ -50,21 +51,16 @@
     ////////////////////////////////////////////////////////////////////////////
 
     uint32_t countChunkOffsets() const;
-    status_t getChunkOffset(uint32_t chunk_index, off_t *offset);
-
-    status_t getChunkForSample(
-            uint32_t sample_index, uint32_t *chunk_index,
-            uint32_t *chunk_relative_sample_index, uint32_t *desc_index);
 
     uint32_t countSamples() const;
-    status_t getSampleSize(uint32_t sample_index, size_t *sample_size);
-
-    status_t getSampleOffsetAndSize(
-            uint32_t sample_index, off_t *offset, size_t *size);
 
     status_t getMaxSampleSize(size_t *size);
 
-    status_t getDecodingTime(uint32_t sample_index, uint32_t *time);
+    status_t getMetaDataForSample(
+            uint32_t sampleIndex,
+            off_t *offset,
+            size_t *size,
+            uint32_t *decodingTime);
 
     enum {
         kSyncSample_Flag = 1
@@ -72,15 +68,17 @@
     status_t findClosestSample(
             uint32_t req_time, uint32_t *sample_index, uint32_t flags);
 
-    status_t findClosestSyncSample(
-            uint32_t start_sample_index, uint32_t *sample_index);
-
     status_t findThumbnailSample(uint32_t *sample_index);
 
 protected:
     ~SampleTable();
 
 private:
+    static const uint32_t kChunkOffsetType32;
+    static const uint32_t kChunkOffsetType64;
+    static const uint32_t kSampleSizeType32;
+    static const uint32_t kSampleSizeTypeCompact;
+
     sp<DataSource> mDataSource;
     Mutex mLock;
 
@@ -102,6 +100,22 @@
     off_t mSyncSampleOffset;
     uint32_t mNumSyncSamples;
 
+    SampleIterator *mSampleIterator;
+
+    struct SampleToChunkEntry {
+        uint32_t startChunk;
+        uint32_t samplesPerChunk;
+        uint32_t chunkDesc;
+    };
+    SampleToChunkEntry *mSampleToChunkEntries;
+
+    friend struct SampleIterator;
+
+    status_t findClosestSyncSample_l(
+            uint32_t start_sample_index, uint32_t *sample_index);
+
+    status_t getSampleSize_l(uint32_t sample_index, size_t *sample_size);
+
     SampleTable(const SampleTable &);
     SampleTable &operator=(const SampleTable &);
 };
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 8c3f252..2121321 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -135,50 +135,6 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-class BufferMeta {
-public:
-    BufferMeta(OMX *owner, const sp<IMemory> &mem, bool is_backup = false)
-        : mOwner(owner),
-          mMem(mem),
-          mIsBackup(is_backup) {
-    }
-
-    BufferMeta(OMX *owner, size_t size)
-        : mOwner(owner),
-          mSize(size),
-          mIsBackup(false) {
-    }
-
-    void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) {
-        if (!mIsBackup) {
-            return;
-        }
-
-        memcpy((OMX_U8 *)mMem->pointer() + header->nOffset,
-               header->pBuffer + header->nOffset,
-               header->nFilledLen);
-    }
-
-    void CopyToOMX(const OMX_BUFFERHEADERTYPE *header) {
-        if (!mIsBackup) {
-            return;
-        }
-
-        memcpy(header->pBuffer + header->nOffset,
-               (const OMX_U8 *)mMem->pointer() + header->nOffset,
-               header->nFilledLen);
-    }
-
-private:
-    OMX *mOwner;
-    sp<IMemory> mMem;
-    size_t mSize;
-    bool mIsBackup;
-
-    BufferMeta(const BufferMeta &);
-    BufferMeta &operator=(const BufferMeta &);
-};
-
 OMX::OMX()
     : mMaster(new OMXMaster),
       mDispatcher(new CallbackDispatcher(this)),
@@ -208,6 +164,10 @@
     instance->onObserverDied(mMaster);
 }
 
+bool OMX::livesLocally(pid_t pid) {
+    return pid == getpid();
+}
+
 status_t OMX::listNodes(List<ComponentInfo> *list) {
     list->clear();
 
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index 2e23899..5b45c1c 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -586,14 +586,14 @@
 
         double r = uniform_rand();
 
-        if (r < 0.5) {
+        if (i > 0 && r < 0.5) {
             // 50% chance of just continuing to decode from last position.
 
             requestedSeekTimeUs = -1;
 
             LOGI("requesting linear read");
         } else {
-            if (r < 0.55) {
+            if (i > 0 && r < 0.55) {
                 // 5% chance of seeking beyond end of stream.
 
                 requestedSeekTimeUs = durationUs;
diff --git a/media/tests/omxjpegdecoder/Android.mk b/media/tests/omxjpegdecoder/Android.mk
index f679f19..b7c18bc 100644
--- a/media/tests/omxjpegdecoder/Android.mk
+++ b/media/tests/omxjpegdecoder/Android.mk
@@ -33,7 +33,8 @@
     libskia \
     libstagefright \
     libbinder \
-    libutils
+    libutils \
+    libjpeg
 
 LOCAL_C_INCLUDES := \
     $(JNI_H_INCLUDE) \
diff --git a/preloaded-classes b/preloaded-classes
index ec4d74c..90bbb37 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -753,10 +753,8 @@
 java.math.Multiplication
 java.net.ContentHandler
 java.net.InetAddress
-java.net.InetAddress$CacheElement
 java.net.InetAddress$WaitReachable
 java.net.JarURLConnection
-java.net.NegativeCache
 java.net.NetPermission
 java.net.ProxySelectorImpl
 java.net.Socket$ConnectLock
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 406897d..1c82c94 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -1203,12 +1203,10 @@
             // Remove expired alerts
             if (intentsToRemove != null) {
                 for (PendingIntent i : intentsToRemove) {
-                    mProximityAlerts.remove(i);
-                    ProximityAlert alert = mProximityAlerts.get(i);
+                    ProximityAlert alert = mProximityAlerts.remove(i);
                     mProximitiesEntered.remove(alert);
                 }
             }
-
         }
 
         // Note: this is called with the lock held.
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
new file mode 100644
index 0000000..97fa0cc
--- /dev/null
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+package com.android.server;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.INetworkManagementService;
+import android.os.Handler;
+import android.text.TextUtils;
+import android.util.Log;
+import java.util.ArrayList;
+
+import android.provider.Settings;
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+
+import java.io.File;
+import java.io.FileReader;
+import java.lang.IllegalStateException;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * @hide
+ */
+class NetworkManagementService extends INetworkManagementService.Stub {
+
+    private static final String TAG = "NetworkManagmentService";
+
+    class NetdResponseCode {
+        public static final int InterfaceListResult       = 110;
+        public static final int TetherInterfaceListResult = 111;
+        public static final int TetherDnsFwdTgtListResult = 112;
+
+        public static final int TetherStatusResult        = 210;
+        public static final int IpFwdStatusResult         = 211;
+    }
+
+    /**
+     * Binder context for this service
+     */
+    private Context mContext;
+
+    /**
+     * connector object for communicating with netd
+     */
+    private NativeDaemonConnector mConnector;
+
+    /**
+     * Constructs a new NetworkManagementService instance
+     *
+     * @param context  Binder context for this service
+     */
+    private NetworkManagementService(Context context) {
+        mContext = context;
+
+        mConnector = new NativeDaemonConnector(
+                new NetdCallbackReceiver(), "netd", 10, "NetdConnector");
+        Thread thread = new Thread(mConnector, NativeDaemonConnector.class.getName());
+        thread.start();
+    }
+
+    //
+    // Netd Callback handling
+    //
+
+    class NetdCallbackReceiver implements INativeDaemonConnectorCallbacks {
+        public void onDaemonConnected() {
+            new Thread() {
+                public void run() {
+                    // XXX: Run some tests
+                }
+            }.start();
+        }
+        public boolean onEvent(int code, String raw, String[] cooked) {
+           return false;
+        }
+    }
+
+    //
+    // INetworkManagementService members
+    //
+
+    public String[] listInterfaces() throws IllegalStateException {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+
+        ArrayList<String> rsp = mConnector.doCommand("list_interfaces");
+
+        String[] rdata = new String[rsp.size()];
+        int idx = 0;
+
+        for (String line : rsp) {
+            String []tok = line.split(" ");
+            int code = Integer.parseInt(tok[0]);
+            if (code == NetdResponseCode.InterfaceListResult) {
+                if (tok.length !=2) {
+                    throw new IllegalStateException(
+                            String.format("Malformatted list entry '%s'", line));
+                }
+                rdata[idx++] = tok[1];
+            } else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) {
+                return rdata;
+            } else {
+                throw new IllegalStateException(String.format("Unexpected response code %d", code));
+            }
+        }
+        throw new IllegalStateException("Got an empty response");
+    }
+
+    public void shutdown() {
+        if (mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.SHUTDOWN)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Requires SHUTDOWN permission");
+        }
+
+        Log.d(TAG, "Shutting down");
+    }
+
+    public boolean getIpForwardingEnabled() throws IllegalStateException{
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+
+        ArrayList<String> rsp = mConnector.doCommand("ipfwd status");
+
+        for (String line : rsp) {
+            String []tok = line.split(" ");
+            int code = Integer.parseInt(tok[0]);
+            if (code == NetdResponseCode.IpFwdStatusResult) {
+                // 211 Forwarding <enabled/disabled>
+                if (tok.length !=2) {
+                    throw new IllegalStateException(
+                            String.format("Malformatted list entry '%s'", line));
+                }
+                if (tok[2].equals("enabled"))
+                    return true;
+                return false;
+            } else {
+                throw new IllegalStateException(String.format("Unexpected response code %d", code));
+            }
+        }
+        throw new IllegalStateException("Got an empty response");
+    }
+
+    public void setIpForwardingEnabled(boolean enable) throws IllegalStateException {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+        mConnector.doCommand(String.format("ipfwd %sable", (enable ? "en" : "dis")));
+    }
+
+    public void startTethering(String dhcpRangeStart, String dhcpRangeEnd)
+             throws IllegalStateException {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+        mConnector.doCommand(String.format("tether start %s %s", dhcpRangeStart, dhcpRangeEnd));
+    }
+
+    public void stopTethering() throws IllegalStateException {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+        mConnector.doCommand("tether stop");
+    }
+
+    public boolean isTetheringStarted() throws IllegalStateException {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+
+        ArrayList<String> rsp = mConnector.doCommand("tether status");
+
+        for (String line : rsp) {
+            String []tok = line.split(" ");
+            int code = Integer.parseInt(tok[0]);
+            if (code == NetdResponseCode.TetherStatusResult) {
+                // XXX: Tethering services <started/stopped> <TBD>...
+                if (tok[2].equals("started"))
+                    return true;
+                return false;
+            } else {
+                throw new IllegalStateException(String.format("Unexpected response code %d", code));
+            }
+        }
+        throw new IllegalStateException("Got an empty response");
+    }
+
+    public void tetherInterface(String iface) throws IllegalStateException {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+        mConnector.doCommand("tether interface add " + iface);
+    }
+
+    public void untetherInterface(String iface) {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+        mConnector.doCommand("tether interface remove " + iface);
+    }
+
+    public String[] listTetheredInterfaces() throws IllegalStateException {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+
+        ArrayList<String> rsp = mConnector.doCommand("tether interface list");
+
+        String[] rdata = new String[rsp.size()];
+        int idx = 0;
+
+        for (String line : rsp) {
+            String []tok = line.split(" ");
+            int code = Integer.parseInt(tok[0]);
+            if (code == NetdResponseCode.TetherInterfaceListResult) {
+                if (tok.length !=2) {
+                    throw new IllegalStateException(
+                            String.format("Malformatted list entry '%s'", line));
+                }
+                rdata[idx++] = tok[1];
+            } else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) {
+                return rdata;
+            } else {
+                throw new IllegalStateException(String.format("Unexpected response code %d", code));
+            }
+        }
+        throw new IllegalStateException("Got an empty response");
+    }
+
+    public void setDnsForwarders(String[] dns) throws IllegalStateException {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+        try {
+            String cmd = "tether dns set ";
+            for (String s : dns) {
+                cmd += InetAddress.getByName(s).toString() + " ";
+            }
+            mConnector.doCommand(cmd);
+        } catch (UnknownHostException e) {
+            throw new IllegalStateException("Error resolving dns name", e);
+        }
+    }
+
+    public String[] getDnsForwarders() throws IllegalStateException {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.ACCESS_NETWORK_STATE, "NetworkManagementService");
+
+        ArrayList<String> rsp = mConnector.doCommand("tether dns list");
+
+        String[] rdata = new String[rsp.size()];
+        int idx = 0;
+
+        for (String line : rsp) {
+            String []tok = line.split(" ");
+            int code = Integer.parseInt(tok[0]);
+            if (code == NetdResponseCode.TetherDnsFwdTgtListResult) {
+                if (tok.length !=2) {
+                    throw new IllegalStateException(
+                            String.format("Malformatted list entry '%s'", line));
+                }
+                rdata[idx++] = tok[1];
+            } else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) {
+                return rdata;
+            } else {
+                throw new IllegalStateException(String.format("Unexpected response code %d", code));
+            }
+        }
+        throw new IllegalStateException("Got an empty response");
+    }
+
+    public void enableNat(String internalInterface, String externalInterface)
+            throws IllegalStateException {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+        mConnector.doCommand(
+                String.format("nat enable %s %s", internalInterface, externalInterface));
+    }
+
+    public void disableNat(String internalInterface, String externalInterface)
+            throws IllegalStateException {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+        mConnector.doCommand(
+                String.format("nat disable %s %s", internalInterface, externalInterface));
+    }
+}
+