Merge change 6603 into donut

* changes:
  quick fix; utf8_codepoint_count must be utf8_length
diff --git a/api/current.xml b/api/current.xml
index d97a0f4..a396c4d 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -496,6 +496,17 @@
  visibility="public"
 >
 </field>
+<field name="GLOBAL_SEARCH"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value="&quot;android.permission.GLOBAL_SEARCH&quot;"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="HARDWARE_TEST"
  type="java.lang.String"
  transient="false"
@@ -25945,6 +25956,17 @@
  visibility="public"
 >
 </method>
+<method name="getPathPermissions"
+ return="android.content.pm.PathPermission[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getReadPermission"
  return="java.lang.String"
  abstract="false"
@@ -26113,6 +26135,19 @@
 <parameter name="sortOrder" type="java.lang.String">
 </parameter>
 </method>
+<method name="setPathPermissions"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="protected"
+>
+<parameter name="permissions" type="android.content.pm.PathPermission[]">
+</parameter>
+</method>
 <method name="setReadPermission"
  return="void"
  abstract="false"
@@ -37714,6 +37749,73 @@
 >
 </field>
 </class>
+<class name="PathPermission"
+ extends="android.os.PatternMatcher"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="PathPermission"
+ type="android.content.pm.PathPermission"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pattern" type="java.lang.String">
+</parameter>
+<parameter name="type" type="int">
+</parameter>
+<parameter name="readPermission" type="java.lang.String">
+</parameter>
+<parameter name="writePermission" type="java.lang.String">
+</parameter>
+</constructor>
+<constructor name="PathPermission"
+ type="android.content.pm.PathPermission"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="src" type="android.os.Parcel">
+</parameter>
+</constructor>
+<method name="getReadPermission"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getWritePermission"
+ return="java.lang.String"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<field name="CREATOR"
+ type="android.os.Parcelable.Creator"
+ transient="false"
+ volatile="false"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
 <class name="PermissionGroupInfo"
  extends="android.content.pm.PackageItemInfo"
  abstract="false"
@@ -38043,6 +38145,17 @@
  visibility="public"
 >
 </field>
+<field name="pathPermissions"
+ type="android.content.pm.PathPermission[]"
+ transient="false"
+ volatile="false"
+ value="null"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="readPermission"
  type="java.lang.String"
  transient="false"
diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp
index 022fe5a..e4b6791 100644
--- a/camera/libcameraservice/CameraService.cpp
+++ b/camera/libcameraservice/CameraService.cpp
@@ -504,8 +504,7 @@
     }
 
     // start recording mode
-    ret = mHardware->startRecording(recordingCallback,
-                                    mCameraService.get());
+    ret = mHardware->startRecording(recordingCallback, mCameraService.get());
     if (ret != NO_ERROR) {
         LOGE("mHardware->startRecording() failed with status %d", ret);
     }
@@ -798,7 +797,7 @@
 }
 
 // recording callback
-void CameraService::Client::recordingCallback(const sp<IMemory>& mem, void* user)
+void CameraService::Client::recordingCallback(nsecs_t timestamp, const sp<IMemory>& mem, void* user)
 {
     LOGV("recordingCallback");
     sp<Client> client = getClientFromCookie(user);
@@ -806,7 +805,7 @@
         return;
     }
     // The strong pointer guarantees the client will exist, but no lock is held.
-    client->postRecordingFrame(mem);
+    client->postRecordingFrame(timestamp, mem);
 }
 
 // take a picture - image is returned in callback
@@ -1072,14 +1071,14 @@
     mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_FRAME, frame);
 }
 
-void CameraService::Client::postRecordingFrame(const sp<IMemory>& frame)
+void CameraService::Client::postRecordingFrame(nsecs_t timestamp, const sp<IMemory>& frame)
 {
     LOGV("postRecordingFrame");
     if (frame == 0) {
         LOGW("frame is a null pointer");
         return;
     }
-    mCameraClient->dataCallback(CAMERA_MSG_VIDEO_FRAME, frame);
+    mCameraClient->dataCallbackTimestamp(timestamp, CAMERA_MSG_VIDEO_FRAME, frame);
 }
 
 void CameraService::Client::postPreviewFrame(const sp<IMemory>& mem)
diff --git a/camera/libcameraservice/CameraService.h b/camera/libcameraservice/CameraService.h
index 0f07673..ea93789 100644
--- a/camera/libcameraservice/CameraService.h
+++ b/camera/libcameraservice/CameraService.h
@@ -132,7 +132,7 @@
 
                     status_t    checkPid();
 
-        static      void        recordingCallback(const sp<IMemory>& mem, void* user);
+        static      void        recordingCallback(nsecs_t timestamp, const sp<IMemory>& mem, void* user);
         static      void        previewCallback(const sp<IMemory>& mem, void* user);
         static      void        shutterCallback(void *user);
         static      void        yuvPictureCallback(const sp<IMemory>& mem, void* user);
@@ -144,7 +144,7 @@
                     void        postRaw(const sp<IMemory>& mem);
                     void        postJpeg(const sp<IMemory>& mem);
                     void        postPreviewFrame(const sp<IMemory>& mem);
-                    void        postRecordingFrame(const sp<IMemory>& frame);
+                    void        postRecordingFrame(nsecs_t timestamp, const sp<IMemory>& frame);
                     void        copyFrameAndPostCopiedFrame(sp<IMemoryHeap> heap, size_t offset, size_t size);
                     void        postError(status_t error);
                     void        postAutoFocus(bool focused);
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 5cc5730..6b50405 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -17,6 +17,7 @@
 package android.content;
 
 import android.content.pm.PackageManager;
+import android.content.pm.PathPermission;
 import android.content.pm.ProviderInfo;
 import android.content.res.AssetFileDescriptor;
 import android.content.res.Configuration;
@@ -29,6 +30,7 @@
 import android.net.Uri;
 import android.os.Binder;
 import android.os.ParcelFileDescriptor;
+import android.os.Process;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -65,8 +67,10 @@
  */
 public abstract class ContentProvider implements ComponentCallbacks {
     private Context mContext = null;
+    private int mMyUid;
     private String mReadPermission;
     private String mWritePermission;
+    private PathPermission[] mPathPermissions;
 
     private Transport mTransport = new Transport();
 
@@ -108,24 +112,20 @@
         public IBulkCursor bulkQuery(Uri uri, String[] projection,
                 String selection, String[] selectionArgs, String sortOrder,
                 IContentObserver observer, CursorWindow window) {
-            checkReadPermission(uri);
+            enforceReadPermission(uri);
             Cursor cursor = ContentProvider.this.query(uri, projection,
                     selection, selectionArgs, sortOrder);
             if (cursor == null) {
                 return null;
             }
-            String wperm = getWritePermission();
             return new CursorToBulkCursorAdaptor(cursor, observer,
                     ContentProvider.this.getClass().getName(),
-                    wperm == null ||
-                    getContext().checkCallingOrSelfPermission(getWritePermission())
-                            == PackageManager.PERMISSION_GRANTED,
-                    window);
+                    hasWritePermission(uri), window);
         }
 
         public Cursor query(Uri uri, String[] projection,
                 String selection, String[] selectionArgs, String sortOrder) {
-            checkReadPermission(uri);
+            enforceReadPermission(uri);
             return ContentProvider.this.query(uri, projection, selection,
                     selectionArgs, sortOrder);
         }
@@ -136,55 +136,84 @@
 
 
         public Uri insert(Uri uri, ContentValues initialValues) {
-            checkWritePermission(uri);
+            enforceWritePermission(uri);
             return ContentProvider.this.insert(uri, initialValues);
         }
 
         public int bulkInsert(Uri uri, ContentValues[] initialValues) {
-            checkWritePermission(uri);
+            enforceWritePermission(uri);
             return ContentProvider.this.bulkInsert(uri, initialValues);
         }
 
         public int delete(Uri uri, String selection, String[] selectionArgs) {
-            checkWritePermission(uri);
+            enforceWritePermission(uri);
             return ContentProvider.this.delete(uri, selection, selectionArgs);
         }
 
         public int update(Uri uri, ContentValues values, String selection,
                 String[] selectionArgs) {
-            checkWritePermission(uri);
+            enforceWritePermission(uri);
             return ContentProvider.this.update(uri, values, selection, selectionArgs);
         }
 
         public ParcelFileDescriptor openFile(Uri uri, String mode)
                 throws FileNotFoundException {
-            if (mode != null && mode.startsWith("rw")) checkWritePermission(uri);
-            else checkReadPermission(uri);
+            if (mode != null && mode.startsWith("rw")) enforceWritePermission(uri);
+            else enforceReadPermission(uri);
             return ContentProvider.this.openFile(uri, mode);
         }
 
         public AssetFileDescriptor openAssetFile(Uri uri, String mode)
                 throws FileNotFoundException {
-            if (mode != null && mode.startsWith("rw")) checkWritePermission(uri);
-            else checkReadPermission(uri);
+            if (mode != null && mode.startsWith("rw")) enforceWritePermission(uri);
+            else enforceReadPermission(uri);
             return ContentProvider.this.openAssetFile(uri, mode);
         }
 
         public ISyncAdapter getSyncAdapter() {
-            checkWritePermission(null);
+            enforceWritePermission(null);
             SyncAdapter sa = ContentProvider.this.getSyncAdapter();
             return sa != null ? sa.getISyncAdapter() : null;
         }
 
-        private void checkReadPermission(Uri uri) {
+        private void enforceReadPermission(Uri uri) {
+            final int uid = Binder.getCallingUid();
+            if (uid == mMyUid) {
+                return;
+            }
+            
+            final Context context = getContext();
             final String rperm = getReadPermission();
             final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            if (getContext().checkUriPermission(uri, rperm, null, pid, uid,
+            if (rperm == null
+                    || context.checkPermission(rperm, pid, uid)
+                    == PackageManager.PERMISSION_GRANTED) {
+                return;
+            }
+            
+            PathPermission[] pps = getPathPermissions();
+            if (pps != null) {
+                final String path = uri.getPath();
+                int i = pps.length;
+                while (i > 0) {
+                    i--;
+                    final PathPermission pp = pps[i];
+                    final String pprperm = pp.getReadPermission();
+                    if (pprperm != null && pp.match(path)) {
+                        if (context.checkPermission(pprperm, pid, uid)
+                                == PackageManager.PERMISSION_GRANTED) {
+                            return;
+                        }
+                    }
+                }
+            }
+            
+            if (context.checkUriPermission(uri, pid, uid,
                     Intent.FLAG_GRANT_READ_URI_PERMISSION)
                     == PackageManager.PERMISSION_GRANTED) {
                 return;
             }
+            
             String msg = "Permission Denial: reading "
                     + ContentProvider.this.getClass().getName()
                     + " uri " + uri + " from pid=" + Binder.getCallingPid()
@@ -193,20 +222,57 @@
             throw new SecurityException(msg);
         }
 
-        private void checkWritePermission(Uri uri) {
+        private boolean hasWritePermission(Uri uri) {
+            final int uid = Binder.getCallingUid();
+            if (uid == mMyUid) {
+                return true;
+            }
+            
+            final Context context = getContext();
             final String wperm = getWritePermission();
             final int pid = Binder.getCallingPid();
-            final int uid = Binder.getCallingUid();
-            if (getContext().checkUriPermission(uri, null, wperm, pid, uid,
+            if (wperm == null
+                    || context.checkPermission(wperm, pid, uid)
+                    == PackageManager.PERMISSION_GRANTED) {
+                return true;
+            }
+            
+            PathPermission[] pps = getPathPermissions();
+            if (pps != null) {
+                final String path = uri.getPath();
+                int i = pps.length;
+                while (i > 0) {
+                    i--;
+                    final PathPermission pp = pps[i];
+                    final String ppwperm = pp.getWritePermission();
+                    if (ppwperm != null && pp.match(path)) {
+                        if (context.checkPermission(ppwperm, pid, uid)
+                                == PackageManager.PERMISSION_GRANTED) {
+                            return true;
+                        }
+                    }
+                }
+            }
+            
+            if (context.checkUriPermission(uri, pid, uid,
                     Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
                     == PackageManager.PERMISSION_GRANTED) {
+                return true;
+            }
+            
+            return false;
+        }
+        
+        private void enforceWritePermission(Uri uri) {
+            if (hasWritePermission(uri)) {
                 return;
             }
+            
             String msg = "Permission Denial: writing "
                     + ContentProvider.this.getClass().getName()
                     + " uri " + uri + " from pid=" + Binder.getCallingPid()
                     + ", uid=" + Binder.getCallingUid()
-                    + " requires " + wperm;
+                    + " requires " + getWritePermission();
             throw new SecurityException(msg);
         }
     }
@@ -266,6 +332,28 @@
     }
 
     /**
+     * Change the path-based permission required to read and/or write data in
+     * the content provider.  This is normally set for you from its manifest
+     * information when the provider is first created.
+     *
+     * @param permissions Array of path permission descriptions.
+     */
+    protected final void setPathPermissions(PathPermission[] permissions) {
+        mPathPermissions = permissions;
+    }
+
+    /**
+     * Return the path-based permissions required for read and/or write access to
+     * this content provider.  This method can be called from multiple
+     * threads, as described in
+     * <a href="{@docRoot}guide/topics/fundamentals.html#procthread">Application Fundamentals:
+     * Processes and Threads</a>.
+     */
+    public final PathPermission[] getPathPermissions() {
+        return mPathPermissions;
+    }
+
+    /**
      * Called when the provider is being started.
      *
      * @return true if the provider was successfully loaded, false otherwise
@@ -600,9 +688,11 @@
          */
         if (mContext == null) {
             mContext = context;
+            mMyUid = Process.myUid();
             if (info != null) {
                 setReadPermission(info.readPermission);
                 setWritePermission(info.writePermission);
+                setPathPermissions(info.pathPermissions);
             }
             ContentProvider.this.onCreate();
         }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index b293636..0e2deed 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1918,6 +1918,7 @@
                         outInfo.metaData, outError)) == null) {
                     return false;
                 }
+                
             } else if (parser.getName().equals("grant-uri-permission")) {
                 TypedArray sa = res.obtainAttributes(attrs,
                         com.android.internal.R.styleable.AndroidManifestGrantUriPermission);
@@ -1941,7 +1942,7 @@
                 if (str != null) {
                     pa = new PatternMatcher(str, PatternMatcher.PATTERN_SIMPLE_GLOB);
                 }
-
+                
                 sa.recycle();
 
                 if (pa != null) {
@@ -1956,6 +1957,101 @@
                         outInfo.info.uriPermissionPatterns = newp;
                     }
                     outInfo.info.grantUriPermissions = true;
+                } else {
+                    if (!RIGID_PARSER) {
+                        Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
+                        Log.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>");
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
+                    return false;
+                }
+                XmlUtils.skipCurrentTag(parser);
+
+            } else if (parser.getName().equals("path-permission")) {
+                TypedArray sa = res.obtainAttributes(attrs,
+                        com.android.internal.R.styleable.AndroidManifestPathPermission);
+
+                PathPermission pa = null;
+
+                String permission = sa.getNonResourceString(
+                        com.android.internal.R.styleable.AndroidManifestPathPermission_permission);
+                String readPermission = sa.getNonResourceString(
+                        com.android.internal.R.styleable.AndroidManifestPathPermission_readPermission);
+                if (readPermission == null) {
+                    readPermission = permission;
+                }
+                String writePermission = sa.getNonResourceString(
+                        com.android.internal.R.styleable.AndroidManifestPathPermission_writePermission);
+                if (writePermission == null) {
+                    writePermission = permission;
+                }
+                
+                boolean havePerm = false;
+                if (readPermission != null) {
+                    readPermission = readPermission.intern();
+                    havePerm = true;
+                }
+                if (writePermission != null) {
+                    writePermission = readPermission.intern();
+                    havePerm = true;
+                }
+
+                if (!havePerm) {
+                    if (!RIGID_PARSER) {
+                        Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
+                        Log.w(TAG, "No readPermission or writePermssion for <path-permission>");
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    outError[0] = "No readPermission or writePermssion for <path-permission>";
+                    return false;
+                }
+                
+                String path = sa.getNonResourceString(
+                        com.android.internal.R.styleable.AndroidManifestPathPermission_path);
+                if (path != null) {
+                    pa = new PathPermission(path,
+                            PatternMatcher.PATTERN_LITERAL, readPermission, writePermission);
+                }
+
+                path = sa.getNonResourceString(
+                        com.android.internal.R.styleable.AndroidManifestPathPermission_pathPrefix);
+                if (path != null) {
+                    pa = new PathPermission(path,
+                            PatternMatcher.PATTERN_PREFIX, readPermission, writePermission);
+                }
+
+                path = sa.getNonResourceString(
+                        com.android.internal.R.styleable.AndroidManifestPathPermission_pathPattern);
+                if (path != null) {
+                    pa = new PathPermission(path,
+                            PatternMatcher.PATTERN_SIMPLE_GLOB, readPermission, writePermission);
+                }
+
+                sa.recycle();
+
+                if (pa != null) {
+                    if (outInfo.info.pathPermissions == null) {
+                        outInfo.info.pathPermissions = new PathPermission[1];
+                        outInfo.info.pathPermissions[0] = pa;
+                    } else {
+                        final int N = outInfo.info.pathPermissions.length;
+                        PathPermission[] newp = new PathPermission[N+1];
+                        System.arraycopy(outInfo.info.pathPermissions, 0, newp, 0, N);
+                        newp[N] = pa;
+                        outInfo.info.pathPermissions = newp;
+                    }
+                } else {
+                    if (!RIGID_PARSER) {
+                        Log.w(TAG, "Problem in package " + mArchiveSourcePath + ":");
+                        Log.w(TAG, "No path, pathPrefix, or pathPattern for <path-permission>");
+                        XmlUtils.skipCurrentTag(parser);
+                        continue;
+                    }
+                    outError[0] = "No path, pathPrefix, or pathPattern for <path-permission>";
+                    return false;
                 }
                 XmlUtils.skipCurrentTag(parser);
 
diff --git a/core/java/android/content/pm/PathPermission.java b/core/java/android/content/pm/PathPermission.java
new file mode 100644
index 0000000..7e49d7d
--- /dev/null
+++ b/core/java/android/content/pm/PathPermission.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2009 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.content.pm;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.PatternMatcher;
+
+/**
+ * Description of permissions needed to access a particular path
+ * in a {@link ProviderInfo}.
+ */
+public class PathPermission extends PatternMatcher {
+    private final String mReadPermission;
+    private final String mWritePermission;
+    
+    public PathPermission(String pattern, int type, String readPermission,
+            String writePermission) {
+        super(pattern, type);
+        mReadPermission = readPermission;
+        mWritePermission = writePermission;
+    }
+    
+    public String getReadPermission() {
+        return mReadPermission;
+    }
+    
+    public String getWritePermission() {
+        return mWritePermission;
+    }
+    
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeString(mReadPermission);
+        dest.writeString(mWritePermission);
+    }
+    
+    public PathPermission(Parcel src) {
+        super(src);
+        mReadPermission = src.readString();
+        mWritePermission = src.readString();
+    }
+    
+    public static final Parcelable.Creator<PathPermission> CREATOR
+            = new Parcelable.Creator<PathPermission>() {
+        public PathPermission createFromParcel(Parcel source) {
+            return new PathPermission(source);
+        }
+
+        public PathPermission[] newArray(int size) {
+            return new PathPermission[size];
+        }
+    };
+}
\ No newline at end of file
diff --git a/core/java/android/content/pm/ProviderInfo.java b/core/java/android/content/pm/ProviderInfo.java
index b67ddf6..d01460e 100644
--- a/core/java/android/content/pm/ProviderInfo.java
+++ b/core/java/android/content/pm/ProviderInfo.java
@@ -28,6 +28,7 @@
  */
 public final class ProviderInfo extends ComponentInfo
         implements Parcelable {
+    
     /** The name provider is published under content:// */
     public String authority = null;
     
@@ -56,6 +57,14 @@
      */
     public PatternMatcher[] uriPermissionPatterns = null;
     
+    /**
+     * If non-null, these are path-specific permissions that are allowed for
+     * accessing the provider.  Any permissions listed here will allow a
+     * holding client to access the provider, and the provider will check
+     * the URI it provides when making calls against the patterns here.
+     */
+    public PathPermission[] pathPermissions = null;
+    
     /** If true, this content provider allows multiple instances of itself
      *  to run in different process.  If false, a single instances is always
      *  run in {@link #processName}. */
@@ -78,6 +87,7 @@
         writePermission = orig.writePermission;
         grantUriPermissions = orig.grantUriPermissions;
         uriPermissionPatterns = orig.uriPermissionPatterns;
+        pathPermissions = orig.pathPermissions;
         multiprocess = orig.multiprocess;
         initOrder = orig.initOrder;
         isSyncable = orig.isSyncable;
@@ -94,6 +104,7 @@
         out.writeString(writePermission);
         out.writeInt(grantUriPermissions ? 1 : 0);
         out.writeTypedArray(uriPermissionPatterns, parcelableFlags);
+        out.writeTypedArray(pathPermissions, parcelableFlags);
         out.writeInt(multiprocess ? 1 : 0);
         out.writeInt(initOrder);
         out.writeInt(isSyncable ? 1 : 0);
@@ -122,6 +133,7 @@
         writePermission = in.readString();
         grantUriPermissions = in.readInt() != 0;
         uriPermissionPatterns = in.createTypedArray(PatternMatcher.CREATOR);
+        pathPermissions = in.createTypedArray(PathPermission.CREATOR);
         multiprocess = in.readInt() != 0;
         initOrder = in.readInt();
         isSyncable = in.readInt() != 0;
diff --git a/core/java/android/speech/tts/TextToSpeech.java b/core/java/android/speech/tts/TextToSpeech.java
index f90cbff..ed1e4ff6 100644
--- a/core/java/android/speech/tts/TextToSpeech.java
+++ b/core/java/android/speech/tts/TextToSpeech.java
@@ -606,6 +606,7 @@
                 result = mITts.setLanguage(mCachedParams[Engine.TTS_PARAM_POSITION_LANGUAGE + 1],
                         mCachedParams[Engine.TTS_PARAM_POSITION_COUNTRY + 1],
                         mCachedParams[Engine.TTS_PARAM_POSITION_VARIANT + 1] );
+            } catch (RemoteException e) {
                 // TTS died; restart it.
                 mStarted = false;
                 initTts();
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 77a8a72..57b5aa6 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -55,6 +55,7 @@
     ~JNICameraContext() { release(); }
     virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2);
     virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr);
+    virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
     sp<Camera> getCamera() { Mutex::Autolock _l(mLock); return mCamera; }
     void release();
 
@@ -188,6 +189,12 @@
     }
 }
 
+void JNICameraContext::postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr)
+{
+    // TODO: plumb up to Java. For now, just drop the timestamp
+    postData(msgType, dataPtr);
+}
+
 // connect to camera service
 static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobject weak_this)
 {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 599360f..23967f4 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -995,6 +995,29 @@
         android:description="@string/permdesc_changeBackgroundDataSetting"
         android:label="@string/permlab_changeBackgroundDataSetting" />
 
+    <!-- This permission can be used on content providers to allow the global
+         search system to access their data.  Typically it used when the
+         provider has some permissions protecting it (which global search
+         would not be expected to hold), and added as a read-only permission
+         to the path in the provider where global search queries are
+         performed.  This permission can not be held by regular applications;
+         it is used by applications to protect themselves from everyone else
+         besides global search. -->
+    <permission android:name="android.permission.GLOBAL_SEARCH"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="signatureOrSystem" />
+
+    <!-- Internal permission protecting access to the global search
+         system: ensures that only the system can access the provider
+         to perform queries (since this otherwise provides unrestricted
+         access to a variety of content providers), and to write the
+         search statistics (to keep applications from gaming the source
+         ranking).
+         @hide -->
+    <permission android:name="android.permission.GLOBAL_SEARCH_CONTROL"
+        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+        android:protectionLevel="signature" />
+
     <application android:process="system"
                  android:persistent="true"
                  android:hasCode="false"
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 7571e24..12a76ba 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -953,6 +953,20 @@
         <attr name="pathPattern" format="string" />
     </declare-styleable>
     
+    <!-- Attributes that can be supplied in an AndroidManifest.xml
+         <code>path-permission</code> tag, a child of the
+         {@link #AndroidManifestProvider provider} tag, describing a permission
+         that allows access to a specific path in the provider.  This tag can be
+         specified multiple time to supply multiple paths. -->
+    <declare-styleable name="AndroidManifestPathPermission"  parent="AndroidManifestProvider">
+        <attr name="path" />
+        <attr name="pathPrefix" />
+        <attr name="pathPattern" />
+        <attr name="permission" />
+        <attr name="readPermission" />
+        <attr name="writePermission" />
+    </declare-styleable>
+    
     <!-- The <code>service</code> tag declares a
          {@link android.app.Service} class that is available
          as part of the package's application components, implementing
diff --git a/include/ui/Camera.h b/include/ui/Camera.h
index e3544ab..afb07b5 100644
--- a/include/ui/Camera.h
+++ b/include/ui/Camera.h
@@ -18,6 +18,7 @@
 #ifndef ANDROID_HARDWARE_CAMERA_H
 #define ANDROID_HARDWARE_CAMERA_H
 
+#include <utils/Timers.h>
 #include <ui/ICameraClient.h>
 
 namespace android {
@@ -94,6 +95,7 @@
 public:
     virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2) = 0;
     virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr) = 0;
+    virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr) = 0;
 };
 
 class Camera : public BnCameraClient, public IBinder::DeathRecipient
@@ -155,6 +157,7 @@
     // ICameraClient interface
     virtual void        notifyCallback(int32_t msgType, int32_t ext, int32_t ext2);
     virtual void        dataCallback(int32_t msgType, const sp<IMemory>& dataPtr);
+    virtual void        dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr);
 
     sp<ICamera>         remote();
 
diff --git a/include/ui/CameraHardwareInterface.h b/include/ui/CameraHardwareInterface.h
index 73036f0..822b4a8 100644
--- a/include/ui/CameraHardwareInterface.h
+++ b/include/ui/CameraHardwareInterface.h
@@ -28,7 +28,7 @@
 typedef void (*preview_callback)(const sp<IMemory>& mem, void* user);
 
 /** Callback for startRecord() */
-typedef void (*recording_callback)(const sp<IMemory>& mem, void* user);
+typedef void (*recording_callback)(nsecs_t timestamp, const sp<IMemory>& mem, void* user);
 
 /** Callback for takePicture() */
 typedef void (*shutter_callback)(void* user);
diff --git a/include/ui/ICameraClient.h b/include/ui/ICameraClient.h
index c4bdd07..1001c71 100644
--- a/include/ui/ICameraClient.h
+++ b/include/ui/ICameraClient.h
@@ -21,6 +21,7 @@
 #include <utils/IInterface.h>
 #include <utils/Parcel.h>
 #include <utils/IMemory.h>
+#include <utils/Timers.h>
 
 namespace android {
 
@@ -31,7 +32,7 @@
 
     virtual void            notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) = 0;
     virtual void            dataCallback(int32_t msgType, const sp<IMemory>& data) = 0;
-
+    virtual void            dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& data) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libs/ui/Camera.cpp b/libs/ui/Camera.cpp
index 975594f..5015379 100644
--- a/libs/ui/Camera.cpp
+++ b/libs/ui/Camera.cpp
@@ -310,6 +310,19 @@
     }
 }
 
+// callback from camera service when timestamped frame is ready
+void Camera::dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr)
+{
+    sp<CameraListener> listener;
+    {
+        Mutex::Autolock _l(mLock);
+        listener = mListener;
+    }
+    if (listener != NULL) {
+        listener->postDataTimestamp(timestamp, msgType, dataPtr);
+    }
+}
+
 void Camera::binderDied(const wp<IBinder>& who) {
     LOGW("ICamera died");
     notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_SERVER_DIED, 0);
diff --git a/libs/ui/ICameraClient.cpp b/libs/ui/ICameraClient.cpp
index c6cf75c..59a6cf2 100644
--- a/libs/ui/ICameraClient.cpp
+++ b/libs/ui/ICameraClient.cpp
@@ -27,6 +27,7 @@
 enum {
     NOTIFY_CALLBACK = IBinder::FIRST_CALL_TRANSACTION,
     DATA_CALLBACK,
+    DATA_CALLBACK_TIMESTAMP,
 };
 
 class BpCameraClient: public BpInterface<ICameraClient>
@@ -60,6 +61,17 @@
         remote()->transact(DATA_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
     }
 
+    // generic data callback from camera service to app with image data
+    void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& imageData)
+    {
+        LOGV("dataCallback");
+        Parcel data, reply;
+        data.writeInterfaceToken(ICameraClient::getInterfaceDescriptor());
+        data.writeInt64(timestamp);
+        data.writeInt32(msgType);
+        data.writeStrongBinder(imageData->asBinder());
+        remote()->transact(DATA_CALLBACK_TIMESTAMP, data, &reply, IBinder::FLAG_ONEWAY);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(CameraClient, "android.hardware.ICameraClient");
@@ -86,13 +98,22 @@
             return NO_ERROR;
         } break;
         case DATA_CALLBACK: {
-            LOGV("RAW_CALLBACK");
+            LOGV("DATA_CALLBACK");
             CHECK_INTERFACE(ICameraClient, data, reply);
             int32_t msgType = data.readInt32();
             sp<IMemory> imageData = interface_cast<IMemory>(data.readStrongBinder());
             dataCallback(msgType, imageData);
             return NO_ERROR;
         } break;
+        case DATA_CALLBACK_TIMESTAMP: {
+            LOGV("DATA_CALLBACK_TIMESTAMP");
+            CHECK_INTERFACE(ICameraClient, data, reply);
+            nsecs_t timestamp = data.readInt64();
+            int32_t msgType = data.readInt32();
+            sp<IMemory> imageData = interface_cast<IMemory>(data.readStrongBinder());
+            dataCallbackTimestamp(timestamp, msgType, imageData);
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 854138c..190d3e6 100644
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -88,7 +88,8 @@
 
     private NotificationRecord mSoundNotification;
     private AsyncPlayer mSound;
-    private int mDisabledNotifications;
+    private boolean mSystemReady;
+    private int mDisabledNotifications = StatusBarManager.DISABLE_NOTIFICATION_ALERTS;
 
     private NotificationRecord mVibrateNotification;
     private Vibrator mVibrator = new Vibrator();
@@ -377,6 +378,11 @@
         mSettingsObserver.observe();
     }
 
+    void systemReady() {
+        // no beeping until we're basically done booting
+        mSystemReady = true;
+    }
+
     // Toasts
     // ============================================================================
     public void enqueueToast(String pkg, ITransientNotification callback, int duration)
@@ -637,7 +643,7 @@
                     }
                 }
 
-                sendAccessibilityEventTypeNotificationChangedDoCheck(notification, pkg);
+                sendAccessibilityEvent(notification, pkg);
 
             } else {
                 if (old != null && old.statusBarKey != null) {
@@ -654,7 +660,8 @@
             // If we're not supposed to beep, vibrate, etc. then don't.
             if (((mDisabledNotifications & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) == 0)
                     && (!(old != null
-                        && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))) {
+                        && (notification.flags & Notification.FLAG_ONLY_ALERT_ONCE) != 0 ))
+                    && mSystemReady) {
                 // sound
                 final boolean useDefaultSound =
                     (notification.defaults & Notification.DEFAULT_SOUND) != 0; 
@@ -721,8 +728,7 @@
         idOut[0] = id;
     }
 
-    private void sendAccessibilityEventTypeNotificationChangedDoCheck(Notification notification,
-            CharSequence packageName) {
+    private void sendAccessibilityEvent(Notification notification, CharSequence packageName) {
         AccessibilityManager manager = AccessibilityManager.getInstance(mContext);
         if (!manager.isEnabled()) {
             return;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 3e4d5f9..b038a64 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -190,6 +190,7 @@
         StatusBarService statusBar = null;
         InputMethodManagerService imm = null;
         AppWidgetService appWidget = null;
+        NotificationManagerService notification = null;
 
         if (factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
             try {
@@ -240,8 +241,8 @@
 
             try {
                 Log.i(TAG, "Starting Notification Manager.");
-                ServiceManager.addService(Context.NOTIFICATION_SERVICE,
-                        new NotificationManagerService(context, statusBar, hardware));
+                notification = new NotificationManagerService(context, statusBar, hardware);
+                ServiceManager.addService(Context.NOTIFICATION_SERVICE, notification);
             } catch (Throwable e) {
                 Log.e(TAG, "Failure starting Notification Manager", e);
             }
@@ -348,6 +349,11 @@
 
         // It is now time to start up the app processes...
         boolean safeMode = wm.detectSafeMode();
+
+        if (notification != null) {
+            notification.systemReady();
+        }
+
         if (statusBar != null) {
             statusBar.systemReady();
         }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 2fe4dd4..aad542a 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -56,6 +56,7 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PathPermission;
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
@@ -7072,6 +7073,27 @@
                 == PackageManager.PERMISSION_GRANTED) {
             return null;
         }
+        
+        PathPermission[] pps = cpi.pathPermissions;
+        if (pps != null) {
+            int i = pps.length;
+            while (i > 0) {
+                i--;
+                PathPermission pp = pps[i];
+                if (checkComponentPermission(pp.getReadPermission(), callingPid, callingUid,
+                        cpi.exported ? -1 : cpi.applicationInfo.uid)
+                        == PackageManager.PERMISSION_GRANTED
+                        && mode == ParcelFileDescriptor.MODE_READ_ONLY || mode == -1) {
+                    return null;
+                }
+                if (checkComponentPermission(pp.getWritePermission(), callingPid, callingUid,
+                        cpi.exported ? -1 : cpi.applicationInfo.uid)
+                        == PackageManager.PERMISSION_GRANTED) {
+                    return null;
+                }
+            }
+        }
+        
         String msg = "Permission Denial: opening provider " + cpi.name
                 + " from " + (r != null ? r : "(null)") + " (pid=" + callingPid
                 + ", uid=" + callingUid + ") requires "