merge in oc-release history after reset to oc-dev
diff --git a/dx/src/com/android/dx/cf/attrib/AttSourceDebugExtension.java b/dx/src/com/android/dx/cf/attrib/AttSourceDebugExtension.java
new file mode 100644
index 0000000..3dd4fec
--- /dev/null
+++ b/dx/src/com/android/dx/cf/attrib/AttSourceDebugExtension.java
@@ -0,0 +1,62 @@
+/*
+ * 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.dx.cf.attrib;
+
+import com.android.dx.rop.cst.CstString;
+
+/**
+ * Attribute class for standard {@code SourceDebugExtension} attributes.
+ */
+public final class AttSourceDebugExtension extends BaseAttribute {
+    /** {@code non-null;} attribute name for attributes of this type */
+    public static final String ATTRIBUTE_NAME = "SourceDebugExtension";
+
+    /** {@code non-null;} Contents of SMAP */
+    private final CstString smapString;
+
+    /**
+     * Constructs an instance.
+     *
+     * @param smapString {@code non-null;} the SMAP data from the class file.
+     */
+    public AttSourceDebugExtension(CstString smapString) {
+        super(ATTRIBUTE_NAME);
+
+        if (smapString == null) {
+            throw new NullPointerException("smapString == null");
+        }
+
+        this.smapString = smapString;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public int byteLength() {
+        // Add 6 for the standard attribute header: the attribute name
+        // index (2 bytes) and the attribute length (4 bytes).
+        return 6 + smapString.getUtf8Size();
+    }
+
+    /**
+     * Gets the SMAP data of this instance.
+     *
+     * @return {@code non-null;} the SMAP data.
+     */
+    public CstString getSmapString() {
+        return smapString;
+    }
+}
diff --git a/dx/src/com/android/dx/cf/direct/StdAttributeFactory.java b/dx/src/com/android/dx/cf/direct/StdAttributeFactory.java
index 992809a..710ba57 100644
--- a/dx/src/com/android/dx/cf/direct/StdAttributeFactory.java
+++ b/dx/src/com/android/dx/cf/direct/StdAttributeFactory.java
@@ -31,6 +31,7 @@
 import com.android.dx.cf.attrib.AttRuntimeVisibleAnnotations;
 import com.android.dx.cf.attrib.AttRuntimeVisibleParameterAnnotations;
 import com.android.dx.cf.attrib.AttSignature;
+import com.android.dx.cf.attrib.AttSourceDebugExtension;
 import com.android.dx.cf.attrib.AttSourceFile;
 import com.android.dx.cf.attrib.AttSynthetic;
 import com.android.dx.cf.attrib.InnerClassList;
@@ -103,6 +104,9 @@
                 if (name == AttSignature.ATTRIBUTE_NAME) {
                     return signature(cf, offset, length, observer);
                 }
+                if (name == AttSourceDebugExtension.ATTRIBUTE_NAME) {
+                    return sourceDebugExtension(cf, offset, length, observer);
+                }
                 if (name == AttSourceFile.ATTRIBUTE_NAME) {
                     return sourceFile(cf, offset, length, observer);
                 }
@@ -692,6 +696,23 @@
     }
 
     /**
+     * Parses a {@code SourceDebugExtesion} attribute.
+     */
+    private Attribute sourceDebugExtension(DirectClassFile cf, int offset, int length,
+                                           ParseObserver observer) {
+        ByteArray bytes = cf.getBytes().slice(offset, offset + length);
+        CstString smapString = new CstString(bytes);
+        Attribute result = new AttSourceDebugExtension(smapString);
+
+        if (observer != null) {
+            String decoded = smapString.getString();
+            observer.parsed(bytes, offset, length, "sourceDebugExtension: " + decoded);
+        }
+
+        return result;
+    }
+
+    /**
      * Parses a {@code SourceFile} attribute.
      */
     private Attribute sourceFile(DirectClassFile cf, int offset, int length,
diff --git a/dx/src/com/android/dx/dex/cf/AttributeTranslator.java b/dx/src/com/android/dx/dex/cf/AttributeTranslator.java
index 90e32c3..31f19c0 100644
--- a/dx/src/com/android/dx/dex/cf/AttributeTranslator.java
+++ b/dx/src/com/android/dx/dex/cf/AttributeTranslator.java
@@ -25,6 +25,7 @@
 import com.android.dx.cf.attrib.AttRuntimeVisibleAnnotations;
 import com.android.dx.cf.attrib.AttRuntimeVisibleParameterAnnotations;
 import com.android.dx.cf.attrib.AttSignature;
+import com.android.dx.cf.attrib.AttSourceDebugExtension;
 import com.android.dx.cf.attrib.InnerClassList;
 import com.android.dx.cf.direct.DirectClassFile;
 import com.android.dx.cf.iface.AttributeList;
@@ -88,11 +89,16 @@
     public static Annotations getAnnotations(AttributeList attribs) {
         Annotations result = getAnnotations0(attribs);
         Annotation signature = getSignature(attribs);
+        Annotation sourceDebugExtension = getSourceDebugExtension(attribs);
 
         if (signature != null) {
             result = Annotations.combine(result, signature);
         }
 
+        if (sourceDebugExtension != null) {
+            result = Annotations.combine(result, sourceDebugExtension);
+        }
+
         return result;
     }
 
@@ -214,6 +220,18 @@
         return AnnotationUtils.makeSignature(signature.getSignature());
     }
 
+
+    private static Annotation getSourceDebugExtension(AttributeList attribs) {
+        AttSourceDebugExtension extension = (AttSourceDebugExtension)
+            attribs.findFirst(AttSourceDebugExtension.ATTRIBUTE_NAME);
+
+        if (extension == null) {
+            return null;
+        }
+
+        return AnnotationUtils.makeSourceDebugExtension(extension.getSmapString());
+    }
+
     /**
      * Gets the {@code EnclosingMethod} attribute out of a given
      * {@link AttributeList}, if any, translating it to an annotation.
diff --git a/dx/src/com/android/dx/dex/file/AnnotationUtils.java b/dx/src/com/android/dx/dex/file/AnnotationUtils.java
index 6441522..109583e 100644
--- a/dx/src/com/android/dx/dex/file/AnnotationUtils.java
+++ b/dx/src/com/android/dx/dex/file/AnnotationUtils.java
@@ -62,6 +62,10 @@
     private static final CstType SIGNATURE_TYPE =
         CstType.intern(Type.intern("Ldalvik/annotation/Signature;"));
 
+        /** {@code non-null;} type for {@code SourceDebugExtension} annotations */
+    private static final CstType SOURCE_DEBUG_EXTENSION_TYPE =
+        CstType.intern(Type.intern("Ldalvik/annotation/SourceDebugExtension;"));
+
     /** {@code non-null;} type for {@code Throws} annotations */
     private static final CstType THROWS_TYPE =
         CstType.intern(Type.intern("Ldalvik/annotation/Throws;"));
@@ -220,6 +224,20 @@
     }
 
     /**
+     * Constructs a standard {@code SourceDebugExtension} annotation.
+     *
+     * @param smapString {@code non-null;} the SMAP string associated with
+     * @return {@code non-null;} the annotation
+     */
+    public static Annotation makeSourceDebugExtension(CstString smapString) {
+        Annotation result = new Annotation(SOURCE_DEBUG_EXTENSION_TYPE, SYSTEM);
+
+        result.put(new NameValuePair(VALUE_STRING, smapString));
+        result.setImmutable();
+        return result;
+    }
+
+    /**
      * Constructs a standard {@code Throws} annotation.
      *
      * @param types {@code non-null;} the list of thrown types
diff --git a/dx/tests/133-source-debug-extension/expected.txt b/dx/tests/133-source-debug-extension/expected.txt
new file mode 100644
index 0000000..04d943c
--- /dev/null
+++ b/dx/tests/133-source-debug-extension/expected.txt
@@ -0,0 +1,4 @@
+1c1
+< SourceDebugExtension
+---
+> (Ldalvik/annotation/SourceDebugExtension;
diff --git a/dx/tests/133-source-debug-extension/info.txt b/dx/tests/133-source-debug-extension/info.txt
new file mode 100644
index 0000000..3bec03c
--- /dev/null
+++ b/dx/tests/133-source-debug-extension/info.txt
@@ -0,0 +1,7 @@
+This test checks that SourceDebugExtension information propagates from
+the class file to the DEX file emitted by dx. It extracts SMAP information
+from the class file and DEX file and checks the strings match.
+
+NB dalvik/dexdump does not have support for DEX annotations so the test
+just checks that the SMAP string appears in the DEX file and assumes
+it is packaged within an annotation.
diff --git a/dx/tests/133-source-debug-extension/run b/dx/tests/133-source-debug-extension/run
new file mode 100755
index 0000000..4c12360
--- /dev/null
+++ b/dx/tests/133-source-debug-extension/run
@@ -0,0 +1,30 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 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.
+
+# Test runs in temporary directory created by test-run.
+
+test_class=HelloKt.class
+test_dex=HelloKt.dex
+
+# Generate DEX file
+dx --dex --output=$test_dex $test_class
+
+# Extract for SMAP string in DEX and class file.
+for i in $test_class $test_dex; do
+  strings $i | sed -n -e "/SourceDebugExtension/ p" -e "/SMAP/,/23/ p" > $i.output
+done
+
+diff $test_class.output $test_dex.output