Merge "DO NOT MERGE Add A2DP and Headset connection stress tests." into gingerbread
diff --git a/api/current.xml b/api/current.xml
index 215a864..89d769e 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -4710,7 +4710,7 @@
type="int"
transient="false"
volatile="false"
- value="16843457"
+ value="16843456"
static="true"
final="true"
deprecated="not deprecated"
@@ -5916,6 +5916,17 @@
visibility="public"
>
</field>
+<field name="kraken_resource_pad64"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843457"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="kraken_resource_pad7"
type="int"
transient="false"
@@ -26622,17 +26633,6 @@
visibility="public"
>
</field>
-<field name="FLAG_HIGH_PRIORITY"
- type="int"
- transient="false"
- volatile="false"
- value="128"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="FLAG_INSISTENT"
type="int"
transient="false"
@@ -46060,17 +46060,6 @@
visibility="public"
>
</field>
-<field name="FLAG_IMMERSIVE"
- type="int"
- transient="false"
- volatile="false"
- value="512"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="FLAG_MULTIPROCESS"
type="int"
transient="false"
@@ -76089,6 +76078,19 @@
visibility="public"
>
</method>
+<method name="getPreviewFpsRange"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="range" type="int[]">
+</parameter>
+</method>
<method name="getPreviewFrameRate"
return="int"
abstract="false"
@@ -76096,7 +76098,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -76221,6 +76223,17 @@
visibility="public"
>
</method>
+<method name="getSupportedPreviewFpsRange"
+ return="java.util.List<int[]>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getSupportedPreviewFrameRates"
return="java.util.List<java.lang.Integer>"
abstract="false"
@@ -76228,7 +76241,7 @@
synchronized="false"
static="false"
final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
visibility="public"
>
</method>
@@ -76610,7 +76623,7 @@
<parameter name="pixel_format" type="int">
</parameter>
</method>
-<method name="setPreviewFrameRate"
+<method name="setPreviewFpsRange"
return="void"
abstract="false"
native="false"
@@ -76620,6 +76633,21 @@
deprecated="not deprecated"
visibility="public"
>
+<parameter name="min" type="int">
+</parameter>
+<parameter name="max" type="int">
+</parameter>
+</method>
+<method name="setPreviewFrameRate"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="deprecated"
+ visibility="public"
+>
<parameter name="fps" type="int">
</parameter>
</method>
@@ -77033,6 +77061,28 @@
visibility="public"
>
</field>
+<field name="PREVIEW_FPS_MAX_INDEX"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="PREVIEW_FPS_MIN_INDEX"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="SCENE_MODE_ACTION"
type="java.lang.String"
transient="false"
@@ -84043,6 +84093,17 @@
visibility="public"
>
</field>
+<field name="PROVIDERS_CHANGED_ACTION"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.location.PROVIDERS_CHANGED""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
</class>
<class name="LocationProvider"
extends="java.lang.Object"
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index a3a8f09..f7a9a18 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1162,6 +1162,7 @@
*/
protected void onPause() {
mCalled = true;
+ QueuedWork.waitToFinish();
}
/**
@@ -3739,48 +3740,6 @@
return null;
}
- /**
- * Bit indicating that this activity is "immersive" and should not be
- * interrupted by notifications if possible.
- *
- * This value is initially set by the manifest property
- * <code>android:immersive</code> but may be changed at runtime by
- * {@link #setImmersive}.
- *
- * @see android.content.pm.ActivityInfo#FLAG_IMMERSIVE
- * @hide
- */
- public boolean isImmersive() {
- try {
- return ActivityManagerNative.getDefault().isImmersive(mToken);
- } catch (RemoteException e) {
- return false;
- }
- }
-
- /**
- * Adjust the current immersive mode setting.
- *
- * Note that changing this value will have no effect on the activity's
- * {@link android.content.pm.ActivityInfo} structure; that is, if
- * <code>android:immersive</code> is set to <code>true</code>
- * in the application's manifest entry for this activity, the {@link
- * android.content.pm.ActivityInfo#flags ActivityInfo.flags} member will
- * always have its {@link android.content.pm.ActivityInfo#FLAG_IMMERSIVE
- * FLAG_IMMERSIVE} bit set.
- *
- * @see #isImmersive
- * @see android.content.pm.ActivityInfo#FLAG_IMMERSIVE
- * @hide
- */
- public void setImmersive(boolean i) {
- try {
- ActivityManagerNative.getDefault().setImmersive(mToken, i);
- } catch (RemoteException e) {
- // pass
- }
- }
-
// ------------------ Internal API ------------------
final void setParent(Activity parent) {
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 1d1b4dc..a180837 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1261,32 +1261,6 @@
return true;
}
- case IS_IMMERSIVE_TRANSACTION: {
- data.enforceInterface(IActivityManager.descriptor);
- IBinder token = data.readStrongBinder();
- boolean isit = isImmersive(token);
- reply.writeNoException();
- reply.writeInt(isit ? 1 : 0);
- return true;
- }
-
- case SET_IMMERSIVE_TRANSACTION: {
- data.enforceInterface(IActivityManager.descriptor);
- IBinder token = data.readStrongBinder();
- boolean imm = data.readInt() == 1;
- setImmersive(token, imm);
- reply.writeNoException();
- return true;
- }
-
- case IS_TOP_ACTIVITY_IMMERSIVE_TRANSACTION: {
- data.enforceInterface(IActivityManager.descriptor);
- boolean isit = isTopActivityImmersive();
- reply.writeNoException();
- reply.writeInt(isit ? 1 : 0);
- return true;
- }
-
case CRASH_APPLICATION_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int uid = data.readInt();
@@ -2858,46 +2832,6 @@
reply.recycle();
}
- public void setImmersive(IBinder token, boolean immersive)
- throws RemoteException {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IActivityManager.descriptor);
- data.writeStrongBinder(token);
- data.writeInt(immersive ? 1 : 0);
- mRemote.transact(SET_IMMERSIVE_TRANSACTION, data, reply, 0);
- reply.readException();
- data.recycle();
- reply.recycle();
- }
-
- public boolean isImmersive(IBinder token)
- throws RemoteException {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IActivityManager.descriptor);
- data.writeStrongBinder(token);
- mRemote.transact(IS_IMMERSIVE_TRANSACTION, data, reply, 0);
- reply.readException();
- boolean res = reply.readInt() == 1;
- data.recycle();
- reply.recycle();
- return res;
- }
-
- public boolean isTopActivityImmersive()
- throws RemoteException {
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(IActivityManager.descriptor);
- mRemote.transact(IS_TOP_ACTIVITY_IMMERSIVE_TRANSACTION, data, reply, 0);
- reply.readException();
- boolean res = reply.readInt() == 1;
- data.recycle();
- reply.recycle();
- return res;
- }
-
public void crashApplication(int uid, int initialPid, String packageName,
String message) throws RemoteException {
Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index c07e3d3..ca6fc8a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -152,7 +152,7 @@
= new ArrayList<Application>();
// set of instantiated backup agents, keyed by package name
final HashMap<String, BackupAgent> mBackupAgents = new HashMap<String, BackupAgent>();
- static final ThreadLocal sThreadLocal = new ThreadLocal();
+ static final ThreadLocal<ActivityThread> sThreadLocal = new ThreadLocal();
Instrumentation mInstrumentation;
String mInstrumentationAppDir = null;
String mInstrumentationAppPackage = null;
@@ -186,6 +186,8 @@
final GcIdler mGcIdler = new GcIdler();
boolean mGcIdlerScheduled = false;
+ static Handler sMainThreadHandler; // set once in main()
+
private static final class ActivityClientRecord {
IBinder token;
int ident;
@@ -1111,7 +1113,7 @@
}
public static final ActivityThread currentActivityThread() {
- return (ActivityThread)sThreadLocal.get();
+ return sThreadLocal.get();
}
public static final String currentPackageName() {
@@ -1780,6 +1782,8 @@
}
}
+ QueuedWork.waitToFinish();
+
try {
if (data.sync) {
if (DEBUG_BROADCAST) Slog.i(TAG,
@@ -2007,6 +2011,9 @@
data.args.setExtrasClassLoader(s.getClassLoader());
}
int res = s.onStartCommand(data.args, data.flags, data.startId);
+
+ QueuedWork.waitToFinish();
+
try {
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, 1, data.startId, res);
@@ -2035,6 +2042,9 @@
final String who = s.getClassName();
((ContextImpl) context).scheduleFinalCleanup(who, "Service");
}
+
+ QueuedWork.waitToFinish();
+
try {
ActivityManagerNative.getDefault().serviceDoneExecuting(
token, 0, 0, 0);
@@ -3171,6 +3181,7 @@
instrApp.sourceDir = ii.sourceDir;
instrApp.publicSourceDir = ii.publicSourceDir;
instrApp.dataDir = ii.dataDir;
+ instrApp.nativeLibraryDir = ii.nativeLibraryDir;
LoadedApk pi = getPackageInfo(instrApp,
appContext.getClassLoader(), false, true);
ContextImpl instrContext = new ContextImpl();
@@ -3598,6 +3609,9 @@
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
+ if (sMainThreadHandler == null) {
+ sMainThreadHandler = new Handler();
+ }
ActivityThread thread = new ActivityThread();
thread.attach(false);
diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java
index 2e301c9..9e3cd7e 100644
--- a/core/java/android/app/ApplicationLoaders.java
+++ b/core/java/android/app/ApplicationLoaders.java
@@ -19,6 +19,7 @@
import dalvik.system.PathClassLoader;
import java.util.HashMap;
+import java.util.Map;
class ApplicationLoaders
{
@@ -27,8 +28,7 @@
return gApplicationLoaders;
}
- public ClassLoader getClassLoader(String zip, String appDataDir,
- ClassLoader parent)
+ public ClassLoader getClassLoader(String zip, String libPath, ClassLoader parent)
{
/*
* This is the parent we use if they pass "null" in. In theory
@@ -49,13 +49,13 @@
* new ClassLoader for the zip archive.
*/
if (parent == baseParent) {
- ClassLoader loader = (ClassLoader)mLoaders.get(zip);
+ ClassLoader loader = mLoaders.get(zip);
if (loader != null) {
return loader;
}
PathClassLoader pathClassloader =
- new PathClassLoader(zip, appDataDir + "/lib", parent);
+ new PathClassLoader(zip, libPath, parent);
mLoaders.put(zip, pathClassloader);
return pathClassloader;
@@ -65,7 +65,7 @@
}
}
- private final HashMap mLoaders = new HashMap();
+ private final Map<String, ClassLoader> mLoaders = new HashMap<String, ClassLoader>();
private static final ApplicationLoaders gApplicationLoaders
= new ApplicationLoaders();
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 7b35e7f..0cd1f3a 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -119,9 +119,12 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import java.util.WeakHashMap;
-import java.util.Map.Entry;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.atomic.AtomicBoolean;
class ReceiverRestrictedContext extends ContextWrapper {
ReceiverRestrictedContext(Context base) {
@@ -170,8 +173,8 @@
private static ThrottleManager sThrottleManager;
private static WifiManager sWifiManager;
private static LocationManager sLocationManager;
- private static final HashMap<File, SharedPreferencesImpl> sSharedPrefs =
- new HashMap<File, SharedPreferencesImpl>();
+ private static final HashMap<String, SharedPreferencesImpl> sSharedPrefs =
+ new HashMap<String, SharedPreferencesImpl>();
private AudioManager mAudioManager;
/*package*/ LoadedApk mPackageInfo;
@@ -210,7 +213,7 @@
private File mCacheDir;
private File mExternalFilesDir;
private File mExternalCacheDir;
-
+
private static long sInstanceCount = 0;
private static final String[] EMPTY_FILE_LIST = {};
@@ -335,15 +338,15 @@
@Override
public SharedPreferences getSharedPreferences(String name, int mode) {
SharedPreferencesImpl sp;
- File f = getSharedPrefsFile(name);
synchronized (sSharedPrefs) {
- sp = sSharedPrefs.get(f);
+ sp = sSharedPrefs.get(name);
if (sp != null && !sp.hasFileChanged()) {
//Log.i(TAG, "Returning existing prefs " + name + ": " + sp);
return sp;
}
}
-
+ File f = getSharedPrefsFile(name);
+
FileInputStream str = null;
File backup = makeBackupFile(f);
if (backup.exists()) {
@@ -355,7 +358,7 @@
if (f.exists() && !f.canRead()) {
Log.w(TAG, "Attempt to read preferences file " + f + " without permission");
}
-
+
Map map = null;
if (f.exists() && f.canRead()) {
try {
@@ -376,10 +379,10 @@
//Log.i(TAG, "Updating existing prefs " + name + " " + sp + ": " + map);
sp.replace(map);
} else {
- sp = sSharedPrefs.get(f);
+ sp = sSharedPrefs.get(name);
if (sp == null) {
sp = new SharedPreferencesImpl(f, mode, map);
- sSharedPrefs.put(f, sp);
+ sSharedPrefs.put(name, sp);
}
}
return sp;
@@ -2698,10 +2701,12 @@
private final File mFile;
private final File mBackupFile;
private final int mMode;
- private Map mMap;
- private final FileStatus mFileStatus = new FileStatus();
- private long mTimestamp;
+ private Map<String, Object> mMap; // guarded by 'this'
+ private long mTimestamp; // guarded by 'this'
+ private int mDiskWritesInFlight = 0; // guarded by 'this'
+
+ private final Object mWritingToDiskLock = new Object();
private static final Object mContent = new Object();
private WeakHashMap<OnSharedPreferenceChangeListener, Object> mListeners;
@@ -2710,22 +2715,24 @@
mFile = file;
mBackupFile = makeBackupFile(file);
mMode = mode;
- mMap = initialContents != null ? initialContents : new HashMap();
- if (FileUtils.getFileStatus(file.getPath(), mFileStatus)) {
- mTimestamp = mFileStatus.mtime;
+ mMap = initialContents != null ? initialContents : new HashMap<String, Object>();
+ FileStatus stat = new FileStatus();
+ if (FileUtils.getFileStatus(file.getPath(), stat)) {
+ mTimestamp = stat.mtime;
}
mListeners = new WeakHashMap<OnSharedPreferenceChangeListener, Object>();
}
public boolean hasFileChanged() {
+ FileStatus stat = new FileStatus();
+ if (!FileUtils.getFileStatus(mFile.getPath(), stat)) {
+ return true;
+ }
synchronized (this) {
- if (!FileUtils.getFileStatus(mFile.getPath(), mFileStatus)) {
- return true;
- }
- return mTimestamp != mFileStatus.mtime;
+ return mTimestamp != stat.mtime;
}
}
-
+
public void replace(Map newContents) {
if (newContents != null) {
synchronized (this) {
@@ -2733,7 +2740,7 @@
}
}
}
-
+
public void registerOnSharedPreferenceChangeListener(OnSharedPreferenceChangeListener listener) {
synchronized(this) {
mListeners.put(listener, mContent);
@@ -2749,7 +2756,7 @@
public Map<String, ?> getAll() {
synchronized(this) {
//noinspection unchecked
- return new HashMap(mMap);
+ return new HashMap<String, Object>(mMap);
}
}
@@ -2768,7 +2775,7 @@
}
public long getLong(String key, long defValue) {
synchronized (this) {
- Long v = (Long) mMap.get(key);
+ Long v = (Long)mMap.get(key);
return v != null ? v : defValue;
}
}
@@ -2791,10 +2798,31 @@
}
}
+ public Editor edit() {
+ return new EditorImpl();
+ }
+
+ // Return value from EditorImpl#commitToMemory()
+ private static class MemoryCommitResult {
+ public boolean changesMade; // any keys different?
+ public List<String> keysModified; // may be null
+ public Set<OnSharedPreferenceChangeListener> listeners; // may be null
+ public Map<?, ?> mapToWriteToDisk;
+ public final CountDownLatch writtenToDiskLatch = new CountDownLatch(1);
+ public volatile boolean writeToDiskResult = false;
+
+ public void setDiskWriteResult(boolean result) {
+ writeToDiskResult = result;
+ writtenToDiskLatch.countDown();
+ }
+ }
+
public final class EditorImpl implements Editor {
private final Map<String, Object> mModified = Maps.newHashMap();
private boolean mClear = false;
+ private AtomicBoolean mCommitInFlight = new AtomicBoolean(false);
+
public Editor putString(String key, String value) {
synchronized (this) {
mModified.put(key, value);
@@ -2841,30 +2869,67 @@
}
public void startCommit() {
- // TODO: implement
- commit();
+ if (!mCommitInFlight.compareAndSet(false, true)) {
+ throw new IllegalStateException("can't call startCommit() twice");
+ }
+
+ final MemoryCommitResult mcr = commitToMemory();
+ final Runnable awaitCommit = new Runnable() {
+ public void run() {
+ try {
+ mcr.writtenToDiskLatch.await();
+ } catch (InterruptedException ignored) {
+ }
+ }
+ };
+
+ QueuedWork.add(awaitCommit);
+
+ Runnable postWriteRunnable = new Runnable() {
+ public void run() {
+ awaitCommit.run();
+ mCommitInFlight.set(false);
+ QueuedWork.remove(awaitCommit);
+ }
+ };
+
+ SharedPreferencesImpl.this.enqueueDiskWrite(mcr, postWriteRunnable);
+
+ // Okay to notify the listeners before it's hit disk
+ // because the listeners should always get the same
+ // SharedPreferences instance back, which has the
+ // changes reflected in memory.
+ notifyListeners(mcr);
}
- public boolean commit() {
- boolean returnValue;
-
- boolean hasListeners;
- boolean changesMade = false;
- List<String> keysModified = null;
- Set<OnSharedPreferenceChangeListener> listeners = null;
-
+ // Returns true if any changes were made
+ private MemoryCommitResult commitToMemory() {
+ MemoryCommitResult mcr = new MemoryCommitResult();
synchronized (SharedPreferencesImpl.this) {
- hasListeners = mListeners.size() > 0;
+ // We optimistically don't make a deep copy until
+ // a memory commit comes in when we're already
+ // writing to disk.
+ if (mDiskWritesInFlight > 0) {
+ // We can't modify our mMap as a currently
+ // in-flight write owns it. Clone it before
+ // modifying it.
+ // noinspection unchecked
+ mMap = new HashMap<String, Object>(mMap);
+ }
+ mcr.mapToWriteToDisk = mMap;
+ mDiskWritesInFlight++;
+
+ boolean hasListeners = mListeners.size() > 0;
if (hasListeners) {
- keysModified = new ArrayList<String>();
- listeners =
- new HashSet<OnSharedPreferenceChangeListener>(mListeners.keySet());
+ mcr.keysModified = new ArrayList<String>();
+ mcr.listeners =
+ new HashSet<OnSharedPreferenceChangeListener>(mListeners.keySet());
}
synchronized (this) {
if (mClear) {
if (!mMap.isEmpty()) {
- changesMade = true;
+ mcr.changesMade = true;
mMap.clear();
}
mClear = false;
@@ -2874,53 +2939,122 @@
String k = e.getKey();
Object v = e.getValue();
if (v == this) { // magic value for a removal mutation
- if (mMap.containsKey(k)) {
- mMap.remove(k);
- changesMade = true;
+ if (!mMap.containsKey(k)) {
+ continue;
}
+ mMap.remove(k);
} else {
boolean isSame = false;
if (mMap.containsKey(k)) {
Object existingValue = mMap.get(k);
- isSame = existingValue != null && existingValue.equals(v);
+ if (existingValue != null && existingValue.equals(v)) {
+ continue;
+ }
}
- if (!isSame) {
- mMap.put(k, v);
- changesMade = true;
- }
+ mMap.put(k, v);
}
+ mcr.changesMade = true;
if (hasListeners) {
- keysModified.add(k);
+ mcr.keysModified.add(k);
}
}
mModified.clear();
}
-
- returnValue = writeFileLocked(changesMade);
}
+ return mcr;
+ }
- if (hasListeners) {
- for (int i = keysModified.size() - 1; i >= 0; i--) {
- final String key = keysModified.get(i);
- for (OnSharedPreferenceChangeListener listener : listeners) {
+ public boolean commit() {
+ MemoryCommitResult mcr = commitToMemory();
+ SharedPreferencesImpl.this.enqueueDiskWrite(
+ mcr, null /* sync write on this thread okay */);
+ try {
+ mcr.writtenToDiskLatch.await();
+ } catch (InterruptedException e) {
+ return false;
+ }
+ notifyListeners(mcr);
+ return mcr.writeToDiskResult;
+ }
+
+ private void notifyListeners(final MemoryCommitResult mcr) {
+ if (mcr.listeners == null || mcr.keysModified == null ||
+ mcr.keysModified.size() == 0) {
+ return;
+ }
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ for (int i = mcr.keysModified.size() - 1; i >= 0; i--) {
+ final String key = mcr.keysModified.get(i);
+ for (OnSharedPreferenceChangeListener listener : mcr.listeners) {
if (listener != null) {
listener.onSharedPreferenceChanged(SharedPreferencesImpl.this, key);
}
}
}
+ } else {
+ // Run this function on the main thread.
+ ActivityThread.sMainThreadHandler.post(new Runnable() {
+ public void run() {
+ notifyListeners(mcr);
+ }
+ });
}
-
- return returnValue;
}
}
- public Editor edit() {
- return new EditorImpl();
+ /**
+ * Enqueue an already-committed-to-memory result to be written
+ * to disk.
+ *
+ * They will be written to disk one-at-a-time in the order
+ * that they're enqueued.
+ *
+ * @param postWriteRunnable if non-null, we're being called
+ * from startCommit() and this is the runnable to run after
+ * the write proceeds. if null (from a regular commit()),
+ * then we're allowed to do this disk write on the main
+ * thread (which in addition to reducing allocations and
+ * creating a background thread, this has the advantage that
+ * we catch them in userdebug StrictMode reports to convert
+ * them where possible to startCommit...)
+ */
+ private void enqueueDiskWrite(final MemoryCommitResult mcr,
+ final Runnable postWriteRunnable) {
+ final Runnable writeToDiskRunnable = new Runnable() {
+ public void run() {
+ synchronized (mWritingToDiskLock) {
+ writeToFile(mcr);
+ }
+ synchronized (SharedPreferencesImpl.this) {
+ mDiskWritesInFlight--;
+ }
+ if (postWriteRunnable != null) {
+ postWriteRunnable.run();
+ }
+ }
+ };
+
+ final boolean isFromSyncCommit = (postWriteRunnable == null);
+
+ // Typical #commit() path with fewer allocations, doing a write on
+ // the current thread.
+ if (isFromSyncCommit) {
+ boolean wasEmpty = false;
+ synchronized (SharedPreferencesImpl.this) {
+ wasEmpty = mDiskWritesInFlight == 1;
+ }
+ if (wasEmpty) {
+ writeToDiskRunnable.run();
+ return;
+ }
+ }
+
+ QueuedWork.singleThreadExecutor().execute(writeToDiskRunnable);
}
- private FileOutputStream createFileOutputStream(File file) {
+ private static FileOutputStream createFileOutputStream(File file) {
FileOutputStream str = null;
try {
str = new FileOutputStream(file);
@@ -2943,49 +3077,56 @@
return str;
}
- private boolean writeFileLocked(boolean changesMade) {
+ // Note: must hold mWritingToDiskLock
+ private void writeToFile(MemoryCommitResult mcr) {
// Rename the current file so it may be used as a backup during the next read
if (mFile.exists()) {
- if (!changesMade) {
+ if (!mcr.changesMade) {
// If the file already exists, but no changes were
// made to the underlying map, it's wasteful to
// re-write the file. Return as if we wrote it
// out.
- return true;
+ mcr.setDiskWriteResult(true);
+ return;
}
if (!mBackupFile.exists()) {
if (!mFile.renameTo(mBackupFile)) {
Log.e(TAG, "Couldn't rename file " + mFile
+ " to backup file " + mBackupFile);
- return false;
+ mcr.setDiskWriteResult(false);
+ return;
}
} else {
mFile.delete();
}
}
-
+
// Attempt to write the file, delete the backup and return true as atomically as
// possible. If any exception occurs, delete the new file; next time we will restore
// from the backup.
try {
FileOutputStream str = createFileOutputStream(mFile);
if (str == null) {
- return false;
+ mcr.setDiskWriteResult(false);
+ return;
}
- XmlUtils.writeMapXml(mMap, str);
+ XmlUtils.writeMapXml(mcr.mapToWriteToDisk, str);
str.close();
setFilePermissionsFromMode(mFile.getPath(), mMode, 0);
- if (FileUtils.getFileStatus(mFile.getPath(), mFileStatus)) {
- mTimestamp = mFileStatus.mtime;
+ FileStatus stat = new FileStatus();
+ if (FileUtils.getFileStatus(mFile.getPath(), stat)) {
+ synchronized (this) {
+ mTimestamp = stat.mtime;
+ }
}
-
// Writing was successful, delete the backup file if there is one.
mBackupFile.delete();
- return true;
+ mcr.setDiskWriteResult(true);
+ return;
} catch (XmlPullParserException e) {
- Log.w(TAG, "writeFileLocked: Got exception:", e);
+ Log.w(TAG, "writeToFile: Got exception:", e);
} catch (IOException e) {
- Log.w(TAG, "writeFileLocked: Got exception:", e);
+ Log.w(TAG, "writeToFile: Got exception:", e);
}
// Clean up an unsuccessfully written file
if (mFile.exists()) {
@@ -2993,7 +3134,7 @@
Log.e(TAG, "Couldn't clean up partially-written file " + mFile);
}
}
- return false;
+ mcr.setDiskWriteResult(false);
}
}
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 664cf18..f9bd461 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -311,10 +311,6 @@
public void finishHeavyWeightApp() throws RemoteException;
- public void setImmersive(IBinder token, boolean immersive) throws RemoteException;
- public boolean isImmersive(IBinder token) throws RemoteException;
- public boolean isTopActivityImmersive() throws RemoteException;
-
public void crashApplication(int uid, int initialPid, String packageName,
String message) throws RemoteException;
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 0f98152..0644f96 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -72,6 +72,7 @@
private final String mResDir;
private final String[] mSharedLibraries;
private final String mDataDir;
+ private final String mLibDir;
private final File mDataDirFile;
private final ClassLoader mBaseClassLoader;
private final boolean mSecurityViolation;
@@ -108,6 +109,7 @@
mSharedLibraries = aInfo.sharedLibraryFiles;
mDataDir = aInfo.dataDir;
mDataDirFile = mDataDir != null ? new File(mDataDir) : null;
+ mLibDir = aInfo.nativeLibraryDir;
mBaseClassLoader = baseLoader;
mSecurityViolation = securityViolation;
mIncludeCode = includeCode;
@@ -140,6 +142,7 @@
mSharedLibraries = null;
mDataDir = null;
mDataDirFile = null;
+ mLibDir = null;
mBaseClassLoader = null;
mSecurityViolation = false;
mIncludeCode = true;
@@ -279,11 +282,12 @@
* create the class loader.
*/
- if (ActivityThread.localLOGV) Slog.v(ActivityThread.TAG, "Class path: " + zip);
+ if (ActivityThread.localLOGV)
+ Slog.v(ActivityThread.TAG, "Class path: " + zip + ", JNI path: " + mLibDir);
mClassLoader =
ApplicationLoaders.getDefault().getClassLoader(
- zip, mDataDir, mBaseClassLoader);
+ zip, mLibDir, mBaseClassLoader);
initializeJavaContextClassLoader();
} else {
if (mBaseClassLoader == null) {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 83a2024..5525ce3 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -112,8 +112,6 @@
* An intent to launch instead of posting the notification to the status bar. Only for use with
* extremely high-priority notifications demanding the user's attention, such as an incoming
* call (handled in the core Android Phone app with a full-screen Activity).
- * Use with {@link #FLAG_HIGH_PRIORITY} to ensure that this notification will reach the user
- * even when other notifications are suppressed.
*/
public PendingIntent fullScreenIntent;
@@ -273,14 +271,6 @@
*/
public static final int FLAG_FOREGROUND_SERVICE = 0x00000040;
- /**
- * Bit to be bitwise-ored into the {@link #flags} field that should be set if this notification
- * represents a high-priority event that may be shown to the user even if notifications are
- * otherwise unavailable (that is, when the status bar is hidden). This flag is ideally used
- * in conjunction with {@link #fullScreenIntent}.
- */
- public static final int FLAG_HIGH_PRIORITY = 0x00000080;
-
public int flags;
/**
@@ -549,9 +539,6 @@
sb.append(Integer.toHexString(this.defaults));
sb.append(",flags=0x");
sb.append(Integer.toHexString(this.flags));
- if ((this.flags & FLAG_HIGH_PRIORITY) != 0) {
- sb.append("!!!1!one!");
- }
sb.append(")");
return sb.toString();
}
diff --git a/core/java/android/app/QueuedWork.java b/core/java/android/app/QueuedWork.java
new file mode 100644
index 0000000..af6bb1b
--- /dev/null
+++ b/core/java/android/app/QueuedWork.java
@@ -0,0 +1,91 @@
+/*
+ * 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.
+ */
+
+package android.app;
+
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * Internal utility class to keep track of process-global work that's
+ * outstanding and hasn't been finished yet.
+ *
+ * This was created for writing SharedPreference edits out
+ * asynchronously so we'd have a mechanism to wait for the writes in
+ * Activity.onPause and similar places, but we may use this mechanism
+ * for other things in the future.
+ *
+ * @hide
+ */
+public class QueuedWork {
+
+ // The set of Runnables that will finish or wait on any async
+ // activities started by the application.
+ private static final ConcurrentLinkedQueue<Runnable> sPendingWorkFinishers =
+ new ConcurrentLinkedQueue<Runnable>();
+
+ private static ExecutorService sSingleThreadExecutor = null; // lazy, guarded by class
+
+ /**
+ * Returns a single-thread Executor shared by the entire process,
+ * creating it if necessary.
+ */
+ public static ExecutorService singleThreadExecutor() {
+ synchronized (QueuedWork.class) {
+ if (sSingleThreadExecutor == null) {
+ // TODO: can we give this single thread a thread name?
+ sSingleThreadExecutor = Executors.newSingleThreadExecutor();
+ }
+ return sSingleThreadExecutor;
+ }
+ }
+
+ /**
+ * Add a runnable to finish (or wait for) a deferred operation
+ * started in this context earlier. Typically finished by e.g.
+ * an Activity#onPause. Used by SharedPreferences$Editor#startCommit().
+ *
+ * Note that this doesn't actually start it running. This is just
+ * a scratch set for callers doing async work to keep updated with
+ * what's in-flight. In the common case, caller code
+ * (e.g. SharedPreferences) will pretty quickly call remove()
+ * after an add(). The only time these Runnables are run is from
+ * waitToFinish(), below.
+ */
+ public static void add(Runnable finisher) {
+ sPendingWorkFinishers.add(finisher);
+ }
+
+ public static void remove(Runnable finisher) {
+ sPendingWorkFinishers.remove(finisher);
+ }
+
+ /**
+ * Finishes or waits for async operations to complete.
+ * (e.g. SharedPreferences$Editor#startCommit writes)
+ *
+ * Is called from the Activity base class's onPause(), after
+ * BroadcastReceiver's onReceive, after Service command handling,
+ * etc. (so async work is never lost)
+ */
+ public static void waitToFinish() {
+ Runnable toFinish;
+ while ((toFinish = sPendingWorkFinishers.poll()) != null) {
+ toFinish.run();
+ }
+ }
+}
diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java
index f1b1490..b3db2ac 100644
--- a/core/java/android/content/SharedPreferences.java
+++ b/core/java/android/content/SharedPreferences.java
@@ -40,7 +40,9 @@
/**
* Called when a shared preference is changed, added, or removed. This
* may be called even if a preference is set to its existing value.
- *
+ *
+ * <p>This callback will be run on your main thread.
+ *
* @param sharedPreferences The {@link SharedPreferences} that received
* the change.
* @param key The key of the preference that was changed, added, or
@@ -187,9 +189,6 @@
* <p>If you call this from an {@link android.app.Activity},
* the base class will wait for any async commits to finish in
* its {@link android.app.Activity#onPause}.</p>
- *
- * @return Returns true if the new values were successfully written
- * to persistent storage.
*/
void startCommit();
}
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 364c91e..395c392 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -149,22 +149,6 @@
* {@link android.R.attr#finishOnCloseSystemDialogs} attribute.
*/
public static final int FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS = 0x0100;
- /**
- * Bit in {@link #flags} corresponding to an immersive activity
- * that wishes not to be interrupted by notifications.
- * Applications that hide the system notification bar with
- * {@link android.view.WindowManager.LayoutParams#FLAG_FULLSCREEN}
- * may still be interrupted by high-priority notifications; for example, an
- * incoming phone call may use
- * {@link android.app.Notification#fullScreenIntent fullScreenIntent}
- * to present a full-screen in-call activity to the user, pausing the
- * current activity as a side-effect. An activity with
- * {@link #FLAG_IMMERSIVE} set, however, will not be interrupted; the
- * notification may be shown in some other way (such as a small floating
- * "toast" window).
- * {@see android.app.Notification#FLAG_HIGH_PRIORITY}
- */
- public static final int FLAG_IMMERSIVE = 0x0200;
/**
* Options that have been set in the activity declaration in the
* manifest.
@@ -175,7 +159,6 @@
* {@link #FLAG_STATE_NOT_NEEDED}, {@link #FLAG_EXCLUDE_FROM_RECENTS},
* {@link #FLAG_ALLOW_TASK_REPARENTING}, {@link #FLAG_NO_HISTORY},
* {@link #FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS},
- * {@link #FLAG_IMMERSIVE}
*/
public int flags;
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index c812f36..ae6a311 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -291,14 +291,6 @@
public static final int FLAG_FORWARD_LOCK = 1<<29;
/**
- * Value for {@link #flags}: Set to true if the application is
- * native-debuggable, i.e. embeds a gdbserver binary in its .apk
- *
- * {@hide}
- */
- public static final int FLAG_NATIVE_DEBUGGABLE = 1<<28;
-
- /**
* Value for {@link #flags}: set to <code>true</code> if the application
* has reported that it is heavy-weight, and thus can not participate in
* the normal application lifecycle.
@@ -359,7 +351,14 @@
* data.
*/
public String dataDir;
-
+
+ /**
+ * Full path to the directory where native JNI libraries are stored.
+ *
+ * {@hide}
+ */
+ public String nativeLibraryDir;
+
/**
* The kernel user-ID that has been assigned to this application;
* currently this is not a unique ID (multiple applications can have
@@ -452,6 +451,7 @@
flags = orig.flags;
sourceDir = orig.sourceDir;
publicSourceDir = orig.publicSourceDir;
+ nativeLibraryDir = orig.nativeLibraryDir;
resourceDirs = orig.resourceDirs;
sharedLibraryFiles = orig.sharedLibraryFiles;
dataDir = orig.dataDir;
@@ -483,6 +483,7 @@
dest.writeInt(flags);
dest.writeString(sourceDir);
dest.writeString(publicSourceDir);
+ dest.writeString(nativeLibraryDir);
dest.writeStringArray(resourceDirs);
dest.writeStringArray(sharedLibraryFiles);
dest.writeString(dataDir);
@@ -514,6 +515,7 @@
flags = source.readInt();
sourceDir = source.readString();
publicSourceDir = source.readString();
+ nativeLibraryDir = source.readString();
resourceDirs = source.readStringArray();
sharedLibraryFiles = source.readStringArray();
dataDir = source.readString();
diff --git a/core/java/android/content/pm/InstrumentationInfo.java b/core/java/android/content/pm/InstrumentationInfo.java
index 3e868a7..ea47e8e 100644
--- a/core/java/android/content/pm/InstrumentationInfo.java
+++ b/core/java/android/content/pm/InstrumentationInfo.java
@@ -50,7 +50,14 @@
* data.
*/
public String dataDir;
-
+
+ /**
+ * Full path to the directory where the native JNI libraries are stored.
+ *
+ * {@hide}
+ */
+ public String nativeLibraryDir;
+
/**
* Specifies whether or not this instrumentation will handle profiling.
*/
@@ -68,6 +75,7 @@
sourceDir = orig.sourceDir;
publicSourceDir = orig.publicSourceDir;
dataDir = orig.dataDir;
+ nativeLibraryDir = orig.nativeLibraryDir;
handleProfiling = orig.handleProfiling;
functionalTest = orig.functionalTest;
}
@@ -88,6 +96,7 @@
dest.writeString(sourceDir);
dest.writeString(publicSourceDir);
dest.writeString(dataDir);
+ dest.writeString(nativeLibraryDir);
dest.writeInt((handleProfiling == false) ? 0 : 1);
dest.writeInt((functionalTest == false) ? 0 : 1);
}
@@ -108,6 +117,7 @@
sourceDir = source.readString();
publicSourceDir = source.readString();
dataDir = source.readString();
+ nativeLibraryDir = source.readString();
handleProfiling = source.readInt() != 0;
functionalTest = source.readInt() != 0;
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 2a39dc0..e20cb5e 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1883,12 +1883,6 @@
a.info.flags |= ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS;
}
- if (sa.getBoolean(
- com.android.internal.R.styleable.AndroidManifestActivity_immersive,
- false)) {
- a.info.flags |= ActivityInfo.FLAG_IMMERSIVE;
- }
-
if (!receiver) {
a.info.launchMode = sa.getInt(
com.android.internal.R.styleable.AndroidManifestActivity_launchMode,
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index e432a47..21cb3a8 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -1224,7 +1224,6 @@
* The array index of minimum preview fps for use with {@link
* #getPreviewFpsRange(int[])} or {@link
* #getSupportedPreviewFpsRange()}.
- * @hide
*/
public static final int PREVIEW_FPS_MIN_INDEX = 0;
@@ -1232,7 +1231,6 @@
* The array index of maximum preview fps for use with {@link
* #getPreviewFpsRange(int[])} or {@link
* #getSupportedPreviewFpsRange()}.
- * @hide
*/
public static final int PREVIEW_FPS_MAX_INDEX = 1;
@@ -1471,7 +1469,9 @@
* target frame rate. The actual frame rate depends on the driver.
*
* @param fps the frame rate (frames per second)
+ * @deprecated replaced by {@link #setPreviewFpsRange(int,int)}
*/
+ @Deprecated
public void setPreviewFrameRate(int fps) {
set(KEY_PREVIEW_FRAME_RATE, fps);
}
@@ -1482,7 +1482,9 @@
* depends on the driver.
*
* @return the frame rate setting (frames per second)
+ * @deprecated replaced by {@link #getPreviewFpsRange(int[])}
*/
+ @Deprecated
public int getPreviewFrameRate() {
return getInt(KEY_PREVIEW_FRAME_RATE);
}
@@ -1492,7 +1494,9 @@
*
* @return a list of supported preview frame rates. null if preview
* frame rate setting is not supported.
+ * @deprecated replaced by {@link #getSupportedPreviewFpsRange()}
*/
+ @Deprecated
public List<Integer> getSupportedPreviewFrameRates() {
String str = get(KEY_PREVIEW_FRAME_RATE + SUPPORTED_VALUES_SUFFIX);
return splitInt(str);
@@ -1500,7 +1504,7 @@
/**
* Sets the maximum and maximum preview fps. This controls the rate of
- * preview frames received in {@link #PreviewCallback}. The minimum and
+ * preview frames received in {@link PreviewCallback}. The minimum and
* maximum preview fps must be one of the elements from {@link
* #getSupportedPreviewFpsRange}.
*
@@ -1509,7 +1513,6 @@
* @throws RuntimeException if fps range is invalid.
* @see #setPreviewCallbackWithBuffer(Camera.PreviewCallback)
* @see #getSupportedPreviewFpsRange()
- * @hide
*/
public void setPreviewFpsRange(int min, int max) {
set(KEY_PREVIEW_FPS_RANGE, "" + min + "," + max);
@@ -1523,12 +1526,11 @@
* @see #PREVIEW_FPS_MIN_INDEX
* @see #PREVIEW_FPS_MAX_INDEX
* @see #getSupportedPreviewFpsRange()
- * @hide
*/
public void getPreviewFpsRange(int[] range) {
if (range == null || range.length != 2) {
throw new IllegalArgumentException(
- "range must be an float array with two elements.");
+ "range must be an array with two elements.");
}
splitInt(get(KEY_PREVIEW_FPS_RANGE), range);
}
@@ -1549,7 +1551,6 @@
* minimum fps).
* @see #PREVIEW_FPS_MIN_INDEX
* @see #PREVIEW_FPS_MAX_INDEX
- * @hide
*/
public List<int[]> getSupportedPreviewFpsRange() {
String str = get(KEY_PREVIEW_FPS_RANGE + SUPPORTED_VALUES_SUFFIX);
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index 2a32e54..3b2bf1e 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -563,13 +563,13 @@
return mMessenger;
}
}
-
+
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
Handler.this.sendMessage(msg);
}
}
-
+
private final Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java
index 197d976..1453329 100644
--- a/core/java/android/preference/Preference.java
+++ b/core/java/android/preference/Preference.java
@@ -1195,7 +1195,7 @@
private void tryCommit(SharedPreferences.Editor editor) {
if (mPreferenceManager.shouldCommit()) {
- editor.commit();
+ editor.startCommit();
}
}
diff --git a/core/java/android/server/BluetoothService.java b/core/java/android/server/BluetoothService.java
index f00389b..abd66ae 100644
--- a/core/java/android/server/BluetoothService.java
+++ b/core/java/android/server/BluetoothService.java
@@ -1737,7 +1737,7 @@
mContext.getSharedPreferences(SHARED_PREFERENCES_NAME,
mContext.MODE_PRIVATE).edit();
editor.putBoolean(SHARED_PREFERENCE_DOCK_ADDRESS + mDockAddress, true);
- editor.commit();
+ editor.startCommit();
}
}
}
diff --git a/core/java/android/webkit/PluginManager.java b/core/java/android/webkit/PluginManager.java
index cdcb662..e5eeb8c 100644
--- a/core/java/android/webkit/PluginManager.java
+++ b/core/java/android/webkit/PluginManager.java
@@ -21,9 +21,9 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
-import android.app.Service;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -59,7 +59,9 @@
*/
public static final String PLUGIN_PERMISSION = "android.webkit.permission.PLUGIN";
- private static final String LOGTAG = "webkit";
+ private static final String LOGTAG = "PluginManager";
+
+ private static final String PLUGIN_SYSTEM_LIB = "/system/lib/plugins/";
private static final String PLUGIN_TYPE = "type";
private static final String TYPE_NATIVE = "native";
@@ -111,9 +113,8 @@
ArrayList<String> directories = new ArrayList<String>();
PackageManager pm = mContext.getPackageManager();
- List<ResolveInfo> plugins = pm.queryIntentServices(new Intent(
- PLUGIN_ACTION), PackageManager.GET_SERVICES
- | PackageManager.GET_META_DATA);
+ List<ResolveInfo> plugins = pm.queryIntentServices(new Intent(PLUGIN_ACTION),
+ PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
synchronized(mPackageInfoCache) {
@@ -143,10 +144,19 @@
continue;
}
- // check if their is a conflict in the lib directory names
+ /*
+ * find the location of the plugin's shared library. The default
+ * is to assume the app is either a user installed app or an
+ * updated system app. In both of these cases the library is
+ * stored in the app's data directory.
+ */
String directory = pkgInfo.applicationInfo.dataDir + "/lib";
- if (directories.contains(directory)) {
- continue;
+ final int appFlags = pkgInfo.applicationInfo.flags;
+ final int updatedSystemFlags = ApplicationInfo.FLAG_SYSTEM |
+ ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+ // preloaded system app with no user updates
+ if ((appFlags & updatedSystemFlags) == ApplicationInfo.FLAG_SYSTEM) {
+ directory = PLUGIN_SYSTEM_LIB + pkgInfo.packageName;
}
// check if the plugin has the required permissions
@@ -236,7 +246,7 @@
// must be synchronized to ensure the consistency of the cache
synchronized(mPackageInfoCache) {
for (PackageInfo pkgInfo : mPackageInfoCache) {
- if (pluginLib.startsWith(pkgInfo.applicationInfo.dataDir)) {
+ if (pluginLib.contains(pkgInfo.packageName)) {
return pkgInfo.packageName;
}
}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 05c159b..052de97 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -5161,13 +5161,10 @@
}
} else {
if (mSelectingText) {
- // tapping on selection or controls does nothing
- if (!nativeHitSelection(contentX, contentY)) {
- if (mMapTrackballToArrowKeys) { // gmail
- copySelection();
- }
- selectionDone();
+ if (nativeHitSelection(contentX, contentY)) {
+ copySelection();
}
+ selectionDone();
break;
}
if (mTouchMode == TOUCH_INIT_MODE) {
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index c77416b..46f7db4 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -260,9 +260,15 @@
/**
* Sets a drawable as the content of this ImageView.
- *
+ *
+ * <p class="note">This does Bitmap reading and decoding on the UI
+ * thread, which can cause a latency hiccup. If that's a concern,
+ * consider using {@link #setImageDrawable} or
+ * {@link #setImageBitmap} and
+ * {@link android.graphics.BitmapFactory} instead.</p>
+ *
* @param resId the resource identifier of the the drawable
- *
+ *
* @attr ref android.R.styleable#ImageView_src
*/
@android.view.RemotableViewMethod
@@ -279,7 +285,13 @@
/**
* Sets the content of this ImageView to the specified Uri.
- *
+ *
+ * <p class="note">This does Bitmap reading and decoding on the UI
+ * thread, which can cause a latency hiccup. If that's a concern,
+ * consider using {@link #setImageDrawable} or
+ * {@link #setImageBitmap} and
+ * {@link android.graphics.BitmapFactory} instead.</p>
+ *
* @param uri The Uri of an image
*/
@android.view.RemotableViewMethod
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 248f6eb..d1a14d2 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -4303,6 +4303,15 @@
if (shouldAdvanceFocusOnEnter()) {
return 0;
}
+ break;
+
+ // Has to be done on key down (and not on key up) to correctly be intercepted.
+ case KeyEvent.KEYCODE_BACK:
+ if (mIsInTextSelectionMode) {
+ stopTextSelectionMode();
+ return -1;
+ }
+ break;
}
if (mInput != null) {
@@ -4456,6 +4465,7 @@
return super.onKeyUp(keyCode, event);
}
+ break;
}
if (mInput != null)
@@ -6618,9 +6628,10 @@
end = mPrevEnd;
} else {
if ((mPrevStart != mPrevEnd) && (start == end)) {
- if ((start >= mPrevStart) && (start <= mPrevEnd)) {
+ if ((start >= mPrevStart) && (start < mPrevEnd)) {
// Tapping inside the selection does nothing
Selection.setSelection((Spannable) mText, mPrevStart, mPrevEnd);
+ showContextMenu();
return;
} else {
// Tapping outside stops selection mode, if any
@@ -7221,9 +7232,6 @@
setAlphabeticShortcut('v');
}
- menu.add(0, ID_STOP_SELECTING_TEXT, 0, com.android.internal.R.string.stopSelectingText).
- setOnMenuItemClickListener(handler);
-
added = true;
} else {
/*
@@ -7272,10 +7280,12 @@
}
}
- if (canPaste()) {
+ // Paste location is too imprecise. Only allow on empty text fields.
+ if (canPaste() && textIsOnlySpaces()) {
menu.add(0, ID_PASTE, 0, com.android.internal.R.string.paste).
setOnMenuItemClickListener(handler).
setAlphabeticShortcut('v');
+ added = true;
}
if (isInputMethodTarget()) {
@@ -7299,6 +7309,17 @@
}
}
+ private boolean textIsOnlySpaces() {
+ final int length = mTransformed.length();
+ for (int i=0; i<length; i++) {
+ final char c = mTransformed.charAt(i);
+ final int type = Character.getType(c);
+ if (type != Character.SPACE_SEPARATOR)
+ return false;
+ }
+ return true;
+ }
+
/**
* Returns whether this text view is a current input method target. The
* default implementation just checks with {@link InputMethodManager}.
@@ -7311,7 +7332,6 @@
// Context menu entries
private static final int ID_SELECT_ALL = android.R.id.selectAll;
private static final int ID_START_SELECTING_TEXT = android.R.id.startSelectingText;
- private static final int ID_STOP_SELECTING_TEXT = android.R.id.stopSelectingText;
private static final int ID_CUT = android.R.id.cut;
private static final int ID_COPY = android.R.id.copy;
private static final int ID_PASTE = android.R.id.paste;
@@ -7358,10 +7378,6 @@
startTextSelectionMode();
return true;
- case ID_STOP_SELECTING_TEXT:
- stopTextSelectionMode();
- return true;
-
case ID_CUT:
clip.setText(mTransformed.subSequence(min, max));
((Editable) mText).delete(min, max);
@@ -7737,6 +7753,8 @@
private boolean mStartIsDragged = false;
// Starting time of the fade timer
private long mFadeOutTimerStart;
+ // Used to detect a tap (vs drag) on the controller
+ private long mOnDownTimerStart;
// The cursor controller images
private final Handle mStartHandle, mEndHandle;
// Offset between finger hot point on active cursor controller and actual cursor
@@ -7884,12 +7902,22 @@
mOffsetX = (bounds.left + bounds.right) / 2.0f - x;
mOffsetY = draggedHandle.mHotSpotVerticalPosition - y;
+ mOnDownTimerStart = event.getEventTime();
((ArrowKeyMovementMethod)mMovement).setCursorController(this);
}
}
}
break;
+ case MotionEvent.ACTION_UP:
+ int time = (int) (event.getEventTime() - mOnDownTimerStart);
+
+ if (time <= ViewConfiguration.getTapTimeout()) {
+ // A tap on the controller (not a drag) opens the contextual Copy menu
+ showContextMenu();
+ }
+ break;
+
case MotionEvent.ACTION_POINTER_DOWN:
case MotionEvent.ACTION_POINTER_UP:
// Handle multi-point gestures. Keep min and max offset positions.
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
new file mode 100644
index 0000000..8b618c7
--- /dev/null
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -0,0 +1,296 @@
+package com.android.internal.content;
+
+import android.content.pm.PackageManager;
+import android.os.Build;
+import android.os.FileUtils;
+import android.os.SystemProperties;
+import android.util.Config;
+import android.util.Log;
+import android.util.Pair;
+import android.util.Slog;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
+
+/**
+ * Native libraries helper.
+ *
+ * @hide
+ */
+public class NativeLibraryHelper {
+ private static final String TAG = "NativeHelper";
+
+ private static final boolean DEBUG_NATIVE = false;
+
+ /*
+ * The following constants are returned by listPackageSharedLibsForAbiLI
+ * to indicate if native shared libraries were found in the package.
+ * Values are:
+ * PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES => native libraries found and installed
+ * PACKAGE_INSTALL_NATIVE_NO_LIBRARIES => no native libraries in package
+ * PACKAGE_INSTALL_NATIVE_ABI_MISMATCH => native libraries for another ABI found
+ * in package (and not installed)
+ *
+ */
+ private static final int PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES = 0;
+ private static final int PACKAGE_INSTALL_NATIVE_NO_LIBRARIES = 1;
+ private static final int PACKAGE_INSTALL_NATIVE_ABI_MISMATCH = 2;
+
+ // Directory in the APK that holds all the native shared libraries.
+ private static final String APK_LIB = "lib/";
+ private static final int APK_LIB_LENGTH = APK_LIB.length();
+
+ // Prefix that native shared libraries must have.
+ private static final String LIB_PREFIX = "lib";
+ private static final int LIB_PREFIX_LENGTH = LIB_PREFIX.length();
+
+ // Suffix that the native shared libraries must have.
+ private static final String LIB_SUFFIX = ".so";
+ private static final int LIB_SUFFIX_LENGTH = LIB_SUFFIX.length();
+
+ // Name of the GDB binary.
+ private static final String GDBSERVER = "gdbserver";
+
+ // the minimum length of a valid native shared library of the form
+ // lib/<something>/lib<name>.so.
+ private static final int MIN_ENTRY_LENGTH = APK_LIB_LENGTH + 2 + LIB_PREFIX_LENGTH + 1
+ + LIB_SUFFIX_LENGTH;
+
+ /*
+ * Find all files of the form lib/<cpuAbi>/lib<name>.so in the .apk
+ * and add them to a list to be installed later.
+ *
+ * NOTE: this method may throw an IOException if the library cannot
+ * be copied to its final destination, e.g. if there isn't enough
+ * room left on the data partition, or a ZipException if the package
+ * file is malformed.
+ */
+ private static int listPackageSharedLibsForAbiLI(ZipFile zipFile,
+ String cpuAbi, List<Pair<ZipEntry, String>> libEntries) throws IOException,
+ ZipException {
+ final int cpuAbiLen = cpuAbi.length();
+ boolean hasNativeLibraries = false;
+ boolean installedNativeLibraries = false;
+
+ if (DEBUG_NATIVE) {
+ Slog.d(TAG, "Checking " + zipFile.getName() + " for shared libraries of CPU ABI type "
+ + cpuAbi);
+ }
+
+ Enumeration<? extends ZipEntry> entries = zipFile.entries();
+
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = entries.nextElement();
+
+ // skip directories
+ if (entry.isDirectory()) {
+ continue;
+ }
+ String entryName = entry.getName();
+
+ /*
+ * Check that the entry looks like lib/<something>/lib<name>.so
+ * here, but don't check the ABI just yet.
+ *
+ * - must be sufficiently long
+ * - must end with LIB_SUFFIX, i.e. ".so"
+ * - must start with APK_LIB, i.e. "lib/"
+ */
+ if (entryName.length() < MIN_ENTRY_LENGTH || !entryName.endsWith(LIB_SUFFIX)
+ || !entryName.startsWith(APK_LIB)) {
+ continue;
+ }
+
+ // file name must start with LIB_PREFIX, i.e. "lib"
+ int lastSlash = entryName.lastIndexOf('/');
+
+ if (lastSlash < 0
+ || !entryName.regionMatches(lastSlash + 1, LIB_PREFIX, 0, LIB_PREFIX_LENGTH)) {
+ continue;
+ }
+
+ hasNativeLibraries = true;
+
+ // check the cpuAbi now, between lib/ and /lib<name>.so
+ if (lastSlash != APK_LIB_LENGTH + cpuAbiLen
+ || !entryName.regionMatches(APK_LIB_LENGTH, cpuAbi, 0, cpuAbiLen))
+ continue;
+
+ /*
+ * Extract the library file name, ensure it doesn't contain
+ * weird characters. we're guaranteed here that it doesn't contain
+ * a directory separator though.
+ */
+ String libFileName = entryName.substring(lastSlash+1);
+ if (!FileUtils.isFilenameSafe(new File(libFileName))) {
+ continue;
+ }
+
+ installedNativeLibraries = true;
+
+ if (DEBUG_NATIVE) {
+ Log.d(TAG, "Caching shared lib " + entry.getName());
+ }
+
+ libEntries.add(Pair.create(entry, libFileName));
+ }
+ if (!hasNativeLibraries)
+ return PACKAGE_INSTALL_NATIVE_NO_LIBRARIES;
+
+ if (!installedNativeLibraries)
+ return PACKAGE_INSTALL_NATIVE_ABI_MISMATCH;
+
+ return PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES;
+ }
+
+ /*
+ * Find the gdbserver executable program in a package at
+ * lib/<cpuAbi>/gdbserver and add it to the list of binaries
+ * to be copied out later.
+ *
+ * Returns PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES on success,
+ * or PACKAGE_INSTALL_NATIVE_NO_LIBRARIES otherwise.
+ */
+ private static int listPackageGdbServerLI(ZipFile zipFile, String cpuAbi,
+ List<Pair<ZipEntry, String>> nativeFiles) throws IOException, ZipException {
+ final String apkGdbServerPath = "lib/" + cpuAbi + "/" + GDBSERVER;
+
+ Enumeration<? extends ZipEntry> entries = zipFile.entries();
+
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = entries.nextElement();
+ // skip directories
+ if (entry.isDirectory()) {
+ continue;
+ }
+ String entryName = entry.getName();
+
+ if (!entryName.equals(apkGdbServerPath)) {
+ continue;
+ }
+
+ if (Config.LOGD) {
+ Log.d(TAG, "Found gdbserver: " + entry.getName());
+ }
+
+ final String installGdbServerPath = APK_LIB + GDBSERVER;
+ nativeFiles.add(Pair.create(entry, installGdbServerPath));
+
+ return PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES;
+ }
+ return PACKAGE_INSTALL_NATIVE_NO_LIBRARIES;
+ }
+
+ /*
+ * Examine shared libraries stored in the APK as
+ * lib/<cpuAbi>/lib<name>.so and add them to a list to be copied
+ * later.
+ *
+ * This function will first try the main CPU ABI defined by Build.CPU_ABI
+ * (which corresponds to ro.product.cpu.abi), and also try an alternate
+ * one if ro.product.cpu.abi2 is defined.
+ */
+ public static int listPackageNativeBinariesLI(ZipFile zipFile,
+ List<Pair<ZipEntry, String>> nativeFiles) throws ZipException, IOException {
+ String cpuAbi = Build.CPU_ABI;
+
+ int result = listPackageSharedLibsForAbiLI(zipFile, cpuAbi, nativeFiles);
+
+ /*
+ * Some architectures are capable of supporting several CPU ABIs
+ * for example, 'armeabi-v7a' also supports 'armeabi' native code
+ * this is indicated by the definition of the ro.product.cpu.abi2
+ * system property.
+ *
+ * only scan the package twice in case of ABI mismatch
+ */
+ if (result == PACKAGE_INSTALL_NATIVE_ABI_MISMATCH) {
+ final String cpuAbi2 = SystemProperties.get("ro.product.cpu.abi2", null);
+ if (cpuAbi2 != null) {
+ result = listPackageSharedLibsForAbiLI(zipFile, cpuAbi2, nativeFiles);
+ }
+
+ if (result == PACKAGE_INSTALL_NATIVE_ABI_MISMATCH) {
+ Slog.w(TAG, "Native ABI mismatch from package file");
+ return PackageManager.INSTALL_FAILED_INVALID_APK;
+ }
+
+ if (result == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES) {
+ cpuAbi = cpuAbi2;
+ }
+ }
+
+ /*
+ * Debuggable packages may have gdbserver embedded, so add it to
+ * the list to the list of items to be extracted (as lib/gdbserver)
+ * into the application's native library directory later.
+ */
+ if (result == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES) {
+ listPackageGdbServerLI(zipFile, cpuAbi, nativeFiles);
+ }
+ return PackageManager.INSTALL_SUCCEEDED;
+ }
+
+ public static int copyNativeBinariesLI(File scanFile, File sharedLibraryDir) {
+ /*
+ * Check all the native files that need to be copied and add
+ * that to the container size.
+ */
+ ZipFile zipFile;
+ try {
+ zipFile = new ZipFile(scanFile);
+
+ List<Pair<ZipEntry, String>> nativeFiles = new LinkedList<Pair<ZipEntry, String>>();
+
+ NativeLibraryHelper.listPackageNativeBinariesLI(zipFile, nativeFiles);
+
+ final int N = nativeFiles.size();
+
+ for (int i = 0; i < N; i++) {
+ final Pair<ZipEntry, String> entry = nativeFiles.get(i);
+
+ File destFile = new File(sharedLibraryDir, entry.second);
+ copyNativeBinaryLI(zipFile, entry.first, sharedLibraryDir, destFile);
+ }
+ } catch (ZipException e) {
+ Slog.w(TAG, "Failed to extract data from package file", e);
+ return PackageManager.INSTALL_FAILED_INVALID_APK;
+ } catch (IOException e) {
+ Slog.w(TAG, "Failed to cache package shared libs", e);
+ return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
+ }
+
+ return PackageManager.INSTALL_SUCCEEDED;
+ }
+
+ private static void copyNativeBinaryLI(ZipFile zipFile, ZipEntry entry,
+ File binaryDir, File binaryFile) throws IOException {
+ InputStream inputStream = zipFile.getInputStream(entry);
+ try {
+ File tempFile = File.createTempFile("tmp", "tmp", binaryDir);
+ String tempFilePath = tempFile.getPath();
+ // XXX package manager can't change owner, so the executable files for
+ // now need to be left as world readable and owned by the system.
+ if (!FileUtils.copyToFile(inputStream, tempFile)
+ || !tempFile.setLastModified(entry.getTime())
+ || FileUtils.setPermissions(tempFilePath, FileUtils.S_IRUSR | FileUtils.S_IWUSR
+ | FileUtils.S_IRGRP | FileUtils.S_IXUSR | FileUtils.S_IXGRP
+ | FileUtils.S_IXOTH | FileUtils.S_IROTH, -1, -1) != 0
+ || !tempFile.renameTo(binaryFile)) {
+ // Failed to properly write file.
+ tempFile.delete();
+ throw new IOException("Couldn't create cached binary " + binaryFile + " in "
+ + binaryDir);
+ }
+ } finally {
+ inputStream.close();
+ }
+ }
+}
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index 4d0a9e0..d6c43f9 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -56,22 +56,22 @@
return null;
}
- public static String createSdDir(File tmpPackageFile, String cid,
+ public static String createSdDir(long sizeBytes, String cid,
String sdEncKey, int uid) {
// Create mount point via MountService
IMountService mountService = getMountService();
- long len = tmpPackageFile.length();
- int mbLen = (int) (len >> 20);
- if ((len - (mbLen * 1024 * 1024)) > 0) {
- mbLen++;
+ int sizeMb = (int) (sizeBytes >> 20);
+ if ((sizeBytes - (sizeMb * 1024 * 1024)) > 0) {
+ sizeMb++;
}
// Add buffer size
- mbLen++;
- if (localLOGV) Log.i(TAG, "Size of container " + mbLen + " MB " + len + " bytes");
+ sizeMb++;
+ if (localLOGV)
+ Log.i(TAG, "Size of container " + sizeMb + " MB " + sizeBytes + " bytes");
try {
int rc = mountService.createSecureContainer(
- cid, mbLen, "fat", sdEncKey, uid);
+ cid, sizeMb, "fat", sdEncKey, uid);
if (rc != StorageResultCode.OperationSucceeded) {
Log.e(TAG, "Failed to create secure container " + cid);
return null;
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index b7d0c67..f3b9357 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -66,16 +66,6 @@
// ----------------------------------------------------------------------------
-static void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL)
-{
- jclass npeClazz;
-
- npeClazz = env->FindClass(exc);
- LOG_FATAL_IF(npeClazz == NULL, "Unable to find class %s", exc);
-
- env->ThrowNew(npeClazz, msg);
-}
-
enum {
STYLE_NUM_ENTRIES = 6,
STYLE_TYPE = 0,
@@ -131,14 +121,14 @@
LOGV("openAsset in %p (Java object %p)\n", am, clazz);
- if (fileName == NULL || am == NULL) {
- doThrow(env, "java/lang/NullPointerException");
+ if (fileName == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", "fileName");
return -1;
}
if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
&& mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
- doThrow(env, "java/lang/IllegalArgumentException");
+ jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
return -1;
}
@@ -146,7 +136,7 @@
Asset* a = am->open(fileName8, (Asset::AccessMode)mode);
if (a == NULL) {
- doThrow(env, "java/io/FileNotFoundException", fileName8);
+ jniThrowException(env, "java/io/FileNotFoundException", fileName8);
env->ReleaseStringUTFChars(fileName, fileName8);
return -1;
}
@@ -164,7 +154,7 @@
delete a;
if (fd < 0) {
- doThrow(env, "java/io/FileNotFoundException",
+ jniThrowException(env, "java/io/FileNotFoundException",
"This file can not be opened as a file descriptor; it is probably compressed");
return NULL;
}
@@ -199,8 +189,8 @@
LOGV("openAssetFd in %p (Java object %p)\n", am, clazz);
- if (fileName == NULL || am == NULL) {
- doThrow(env, "java/lang/NullPointerException");
+ if (fileName == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", "fileName");
return NULL;
}
@@ -208,7 +198,7 @@
Asset* a = am->open(fileName8, Asset::ACCESS_RANDOM);
if (a == NULL) {
- doThrow(env, "java/io/FileNotFoundException", fileName8);
+ jniThrowException(env, "java/io/FileNotFoundException", fileName8);
env->ReleaseStringUTFChars(fileName, fileName8);
return NULL;
}
@@ -231,14 +221,14 @@
LOGV("openNonAssetNative in %p (Java object %p)\n", am, clazz);
- if (fileName == NULL || am == NULL) {
- doThrow(env, "java/lang/NullPointerException");
+ if (fileName == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", "fileName");
return -1;
}
if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
&& mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
- doThrow(env, "java/lang/IllegalArgumentException");
+ jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
return -1;
}
@@ -248,7 +238,7 @@
: am->openNonAsset(fileName8, (Asset::AccessMode)mode);
if (a == NULL) {
- doThrow(env, "java/io/FileNotFoundException", fileName8);
+ jniThrowException(env, "java/io/FileNotFoundException", fileName8);
env->ReleaseStringUTFChars(fileName, fileName8);
return -1;
}
@@ -271,8 +261,8 @@
LOGV("openNonAssetFd in %p (Java object %p)\n", am, clazz);
- if (fileName == NULL || am == NULL) {
- doThrow(env, "java/lang/NullPointerException");
+ if (fileName == NULL ) {
+ jniThrowException(env, "java/lang/NullPointerException", "fileName");
return NULL;
}
@@ -282,7 +272,7 @@
: am->openNonAsset(fileName8, Asset::ACCESS_RANDOM);
if (a == NULL) {
- doThrow(env, "java/io/FileNotFoundException", fileName8);
+ jniThrowException(env, "java/io/FileNotFoundException", fileName8);
env->ReleaseStringUTFChars(fileName, fileName8);
return NULL;
}
@@ -301,8 +291,8 @@
return NULL;
}
- if (fileName == NULL || am == NULL) {
- doThrow(env, "java/lang/NullPointerException");
+ if (fileName == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", "fileName");
return NULL;
}
@@ -313,7 +303,7 @@
env->ReleaseStringUTFChars(fileName, fileName8);
if (dir == NULL) {
- doThrow(env, "java/io/FileNotFoundException", fileName8);
+ jniThrowException(env, "java/io/FileNotFoundException", fileName8);
return NULL;
}
@@ -329,7 +319,6 @@
jobjectArray array = env->NewObjectArray(dir->getFileCount(),
cls, NULL);
if (array == NULL) {
- doThrow(env, "java/lang/OutOfMemoryError");
delete dir;
return NULL;
}
@@ -338,11 +327,11 @@
const String8& name = dir->getFileName(i);
jstring str = env->NewStringUTF(name.string());
if (str == NULL) {
- doThrow(env, "java/lang/OutOfMemoryError");
delete dir;
return NULL;
}
env->SetObjectArrayElement(array, i, str);
+ env->DeleteLocalRef(str);
}
delete dir;
@@ -358,7 +347,7 @@
//printf("Destroying Asset Stream: %p\n", a);
if (a == NULL) {
- doThrow(env, "java/lang/NullPointerException");
+ jniThrowException(env, "java/lang/NullPointerException", "asset");
return;
}
@@ -371,7 +360,7 @@
Asset* a = (Asset*)asset;
if (a == NULL) {
- doThrow(env, "java/lang/NullPointerException");
+ jniThrowException(env, "java/lang/NullPointerException", "asset");
return -1;
}
@@ -387,7 +376,7 @@
Asset* a = (Asset*)asset;
if (a == NULL || bArray == NULL) {
- doThrow(env, "java/lang/NullPointerException");
+ jniThrowException(env, "java/lang/NullPointerException", "asset");
return -1;
}
@@ -397,7 +386,7 @@
jsize bLen = env->GetArrayLength(bArray);
if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
- doThrow(env, "java/lang/IndexOutOfBoundsException");
+ jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
return -1;
}
@@ -408,7 +397,7 @@
if (res > 0) return res;
if (res < 0) {
- doThrow(env, "java/io/IOException");
+ jniThrowException(env, "java/io/IOException", "");
}
return -1;
}
@@ -420,7 +409,7 @@
Asset* a = (Asset*)asset;
if (a == NULL) {
- doThrow(env, "java/lang/NullPointerException");
+ jniThrowException(env, "java/lang/NullPointerException", "asset");
return -1;
}
@@ -434,7 +423,7 @@
Asset* a = (Asset*)asset;
if (a == NULL) {
- doThrow(env, "java/lang/NullPointerException");
+ jniThrowException(env, "java/lang/NullPointerException", "asset");
return -1;
}
@@ -447,7 +436,7 @@
Asset* a = (Asset*)asset;
if (a == NULL) {
- doThrow(env, "java/lang/NullPointerException");
+ jniThrowException(env, "java/lang/NullPointerException", "asset");
return -1;
}
@@ -458,7 +447,7 @@
jstring path)
{
if (path == NULL) {
- doThrow(env, "java/lang/NullPointerException");
+ jniThrowException(env, "java/lang/NullPointerException", "path");
return JNI_FALSE;
}
@@ -490,7 +479,7 @@
jstring locale)
{
if (locale == NULL) {
- doThrow(env, "java/lang/NullPointerException");
+ jniThrowException(env, "java/lang/NullPointerException", "locale");
return;
}
@@ -525,7 +514,12 @@
}
for (int i=0; i<N; i++) {
- env->SetObjectArrayElement(result, i, env->NewStringUTF(locales[i].string()));
+ jstring str = env->NewStringUTF(locales[i].string());
+ if (str == NULL) {
+ return NULL;
+ }
+ env->SetObjectArrayElement(result, i, str);
+ env->DeleteLocalRef(str);
}
return result;
@@ -576,7 +570,7 @@
jstring defPackage)
{
if (name == NULL) {
- doThrow(env, "java/lang/NullPointerException");
+ jniThrowException(env, "java/lang/NullPointerException", "name");
return 0;
}
@@ -814,14 +808,10 @@
}
String8 name(am->getAssetPath((void*)cookie));
if (name.length() == 0) {
- doThrow(env, "java/lang/IndexOutOfBoundsException");
+ jniThrowException(env, "java/lang/IndexOutOfBoundsException", "Empty cookie name");
return NULL;
}
jstring str = env->NewStringUTF(name.string());
- if (str == NULL) {
- doThrow(env, "java/lang/OutOfMemoryError");
- return NULL;
- }
return str;
}
@@ -889,7 +879,7 @@
const ResTable& res(theme->getResTable());
if (tag == NULL) {
- doThrow(env, "java/lang/NullPointerException");
+ jniThrowException(env, "java/lang/NullPointerException", "tag");
return;
}
@@ -917,8 +907,16 @@
jintArray outValues,
jintArray outIndices)
{
- if (themeToken == 0 || attrs == NULL || outValues == NULL) {
- doThrow(env, "java/lang/NullPointerException");
+ if (themeToken == 0) {
+ jniThrowException(env, "java/lang/NullPointerException", "theme token");
+ return JNI_FALSE;
+ }
+ if (attrs == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", "attrs");
+ return JNI_FALSE;
+ }
+ if (outValues == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", "out values");
return JNI_FALSE;
}
@@ -934,13 +932,13 @@
const jsize NI = env->GetArrayLength(attrs);
const jsize NV = env->GetArrayLength(outValues);
if (NV < (NI*STYLE_NUM_ENTRIES)) {
- doThrow(env, "java/lang/IndexOutOfBoundsException");
+ jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
return JNI_FALSE;
}
jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
if (src == NULL) {
- doThrow(env, "java/lang/OutOfMemoryError");
+ jniThrowException(env, "java/lang/OutOfMemoryError", "");
return JNI_FALSE;
}
@@ -948,7 +946,7 @@
jint* dest = baseDest;
if (dest == NULL) {
env->ReleasePrimitiveArrayCritical(attrs, src, 0);
- doThrow(env, "java/lang/OutOfMemoryError");
+ jniThrowException(env, "java/lang/OutOfMemoryError", "");
return JNI_FALSE;
}
@@ -1152,8 +1150,16 @@
jintArray outValues,
jintArray outIndices)
{
- if (xmlParserToken == 0 || attrs == NULL || outValues == NULL) {
- doThrow(env, "java/lang/NullPointerException");
+ if (xmlParserToken == 0) {
+ jniThrowException(env, "java/lang/NullPointerException", "xmlParserToken");
+ return JNI_FALSE;
+ }
+ if (attrs == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", "attrs");
+ return JNI_FALSE;
+ }
+ if (outValues == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", "out values");
return JNI_FALSE;
}
@@ -1169,13 +1175,13 @@
const jsize NI = env->GetArrayLength(attrs);
const jsize NV = env->GetArrayLength(outValues);
if (NV < (NI*STYLE_NUM_ENTRIES)) {
- doThrow(env, "java/lang/IndexOutOfBoundsException");
+ jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
return JNI_FALSE;
}
jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
if (src == NULL) {
- doThrow(env, "java/lang/OutOfMemoryError");
+ jniThrowException(env, "java/lang/OutOfMemoryError", "");
return JNI_FALSE;
}
@@ -1183,7 +1189,7 @@
jint* dest = baseDest;
if (dest == NULL) {
env->ReleasePrimitiveArrayCritical(attrs, src, 0);
- doThrow(env, "java/lang/OutOfMemoryError");
+ jniThrowException(env, "java/lang/OutOfMemoryError", "");
return JNI_FALSE;
}
@@ -1306,7 +1312,7 @@
jintArray outValues)
{
if (outValues == NULL) {
- doThrow(env, "java/lang/NullPointerException");
+ jniThrowException(env, "java/lang/NullPointerException", "out values");
return JNI_FALSE;
}
@@ -1324,7 +1330,7 @@
jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
jint* dest = baseDest;
if (dest == NULL) {
- doThrow(env, "java/lang/OutOfMemoryError");
+ jniThrowException(env, "java/lang/OutOfMemoryError", "");
return JNI_FALSE;
}
@@ -1399,8 +1405,8 @@
LOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
- if (fileName == NULL || am == NULL) {
- doThrow(env, "java/lang/NullPointerException");
+ if (fileName == NULL) {
+ jniThrowException(env, "java/lang/NullPointerException", "fileName");
return 0;
}
@@ -1410,7 +1416,7 @@
: am->openNonAsset(fileName8, Asset::ACCESS_BUFFER);
if (a == NULL) {
- doThrow(env, "java/io/FileNotFoundException", fileName8);
+ jniThrowException(env, "java/io/FileNotFoundException", fileName8);
env->ReleaseStringUTFChars(fileName, fileName8);
return 0;
}
@@ -1422,7 +1428,7 @@
delete a;
if (err != NO_ERROR) {
- doThrow(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
+ jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
return 0;
}
@@ -1446,7 +1452,7 @@
jintArray array = env->NewIntArray(N * 2);
if (array == NULL) {
- doThrow(env, "java/lang/OutOfMemoryError");
+ jniThrowException(env, "java/lang/OutOfMemoryError", "");
res.unlockBag(startOfBag);
return NULL;
}
@@ -1540,13 +1546,12 @@
res.unlockBag(startOfBag);
return NULL;
}
- }
- env->SetObjectArrayElement(array, i, str);
+ env->SetObjectArrayElement(array, i, str);
- // If we have a large amount of strings in our array, we might
- // overflow the local reference table of the VM.
- if (str != NULL) {
+ // str is not NULL at that point, otherwise ExceptionCheck would have been true.
+ // If we have a large amount of strings in our array, we might
+ // overflow the local reference table of the VM.
env->DeleteLocalRef(str);
}
}
@@ -1571,7 +1576,7 @@
jintArray array = env->NewIntArray(N);
if (array == NULL) {
- doThrow(env, "java/lang/OutOfMemoryError");
+ jniThrowException(env, "java/lang/OutOfMemoryError", "");
res.unlockBag(startOfBag);
return NULL;
}
@@ -1603,7 +1608,7 @@
{
AssetManager* am = new AssetManager();
if (am == NULL) {
- doThrow(env, "java/lang/OutOfMemoryError");
+ jniThrowException(env, "java/lang/OutOfMemoryError", "");
return;
}
@@ -1637,11 +1642,6 @@
}
jstring str = env->NewStringUTF(alloc.string());
- if (str == NULL) {
- doThrow(env, "java/lang/OutOfMemoryError");
- return NULL;
- }
-
return str;
}
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 245643b..7942c56 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -703,8 +703,8 @@
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="6876518925844129331">"Vybrat vše"</string>
- <string name="selectText" msgid="3889149123626888637">"Označit text"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Zastavit označování textu"</string>
+ <!-- no translation found for selectText (4862359311088898878) -->
+ <skip />
<string name="cut" msgid="3092569408438626261">"Vyjmout"</string>
<string name="copy" msgid="2681946229533511987">"Kopírovat"</string>
<string name="paste" msgid="5629880836805036433">"Vložit"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index e7e8019..bab18f2 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -703,8 +703,8 @@
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="6876518925844129331">"Vælg alle"</string>
- <string name="selectText" msgid="3889149123626888637">"Marker tekst"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Hold op med at markere tekst"</string>
+ <!-- no translation found for selectText (4862359311088898878) -->
+ <skip />
<string name="cut" msgid="3092569408438626261">"Klip"</string>
<string name="copy" msgid="2681946229533511987">"Kopier"</string>
<string name="paste" msgid="5629880836805036433">"Indsæt"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index edbe4c4..c20aa16 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -703,8 +703,8 @@
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="6876518925844129331">"Alles auswählen"</string>
- <string name="selectText" msgid="3889149123626888637">"Text auswählen"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Textauswahl beenden"</string>
+ <!-- no translation found for selectText (4862359311088898878) -->
+ <skip />
<string name="cut" msgid="3092569408438626261">"Ausschneiden"</string>
<string name="copy" msgid="2681946229533511987">"Kopieren"</string>
<string name="paste" msgid="5629880836805036433">"Einfügen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index cfa36d2..ab29601 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -703,8 +703,8 @@
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="6876518925844129331">"Επιλογή όλων"</string>
- <string name="selectText" msgid="3889149123626888637">"Επιλογή κειμένου"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Διακοπή επιλογής κειμένου"</string>
+ <!-- no translation found for selectText (4862359311088898878) -->
+ <skip />
<string name="cut" msgid="3092569408438626261">"Αποκοπή"</string>
<string name="copy" msgid="2681946229533511987">"Αντιγραφή"</string>
<string name="paste" msgid="5629880836805036433">"Επικόλληση"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index dbf32b6..fce56cd 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -703,8 +703,8 @@
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="6876518925844129331">"Seleccionar todos"</string>
- <string name="selectText" msgid="3889149123626888637">"Seleccionar texto"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Detener la selección de texto"</string>
+ <!-- no translation found for selectText (4862359311088898878) -->
+ <skip />
<string name="cut" msgid="3092569408438626261">"Cortar"</string>
<string name="copy" msgid="2681946229533511987">"Copiar"</string>
<string name="paste" msgid="5629880836805036433">"Pegar"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 425fca3..4fdaf3c 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -703,8 +703,8 @@
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="6876518925844129331">"Seleccionar todo"</string>
- <string name="selectText" msgid="3889149123626888637">"Seleccionar texto"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Detener selección de texto"</string>
+ <!-- no translation found for selectText (4862359311088898878) -->
+ <skip />
<string name="cut" msgid="3092569408438626261">"Cortar"</string>
<string name="copy" msgid="2681946229533511987">"Copiar"</string>
<string name="paste" msgid="5629880836805036433">"Pegar"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 2dacb30..9f0fa0b 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -703,8 +703,8 @@
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="6876518925844129331">"Tout sélectionner"</string>
- <string name="selectText" msgid="3889149123626888637">"Sélectionner le texte"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Arrêter sélection de texte"</string>
+ <!-- no translation found for selectText (4862359311088898878) -->
+ <skip />
<string name="cut" msgid="3092569408438626261">"Couper"</string>
<string name="copy" msgid="2681946229533511987">"Copier"</string>
<string name="paste" msgid="5629880836805036433">"Coller"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index c7aac82..4731f39 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -703,8 +703,8 @@
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="6876518925844129331">"Seleziona tutto"</string>
- <string name="selectText" msgid="3889149123626888637">"Seleziona testo"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Termina selezione testo"</string>
+ <!-- no translation found for selectText (4862359311088898878) -->
+ <skip />
<string name="cut" msgid="3092569408438626261">"Taglia"</string>
<string name="copy" msgid="2681946229533511987">"Copia"</string>
<string name="paste" msgid="5629880836805036433">"Incolla"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 25e977d..a9613f4 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -703,8 +703,8 @@
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="6876518925844129331">"すべて選択"</string>
- <string name="selectText" msgid="3889149123626888637">"テキストを選択"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"テキストの選択を終了"</string>
+ <!-- no translation found for selectText (4862359311088898878) -->
+ <skip />
<string name="cut" msgid="3092569408438626261">"切り取り"</string>
<string name="copy" msgid="2681946229533511987">"コピー"</string>
<string name="paste" msgid="5629880836805036433">"貼り付け"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index faf589e..d6ab5ad 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -703,8 +703,8 @@
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="6876518925844129331">"모두 선택"</string>
- <string name="selectText" msgid="3889149123626888637">"텍스트 선택"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"텍스트 선택 중지"</string>
+ <!-- no translation found for selectText (4862359311088898878) -->
+ <skip />
<string name="cut" msgid="3092569408438626261">"잘라내기"</string>
<string name="copy" msgid="2681946229533511987">"복사"</string>
<string name="paste" msgid="5629880836805036433">"붙여넣기"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 2c23d53..021b20e 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -703,8 +703,8 @@
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="6876518925844129331">"Merk alt"</string>
- <string name="selectText" msgid="3889149123626888637">"Merk tekst"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Slutt å merke tekst"</string>
+ <!-- no translation found for selectText (4862359311088898878) -->
+ <skip />
<string name="cut" msgid="3092569408438626261">"Klipp ut"</string>
<string name="copy" msgid="2681946229533511987">"Kopier"</string>
<string name="paste" msgid="5629880836805036433">"Lim inn"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 10a8e74..a74db2b 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -703,8 +703,8 @@
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="6876518925844129331">"Alles selecteren"</string>
- <string name="selectText" msgid="3889149123626888637">"Tekst selecteren"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Stoppen met tekst selecteren"</string>
+ <!-- no translation found for selectText (4862359311088898878) -->
+ <skip />
<string name="cut" msgid="3092569408438626261">"Knippen"</string>
<string name="copy" msgid="2681946229533511987">"Kopiëren"</string>
<string name="paste" msgid="5629880836805036433">"Plakken"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 70c3170..f5ed50c 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -703,8 +703,8 @@
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="6876518925844129331">"Zaznacz wszystko"</string>
- <string name="selectText" msgid="3889149123626888637">"Zaznacz tekst"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Zatrzymaj wybieranie tekstu"</string>
+ <!-- no translation found for selectText (4862359311088898878) -->
+ <skip />
<string name="cut" msgid="3092569408438626261">"Wytnij"</string>
<string name="copy" msgid="2681946229533511987">"Kopiuj"</string>
<string name="paste" msgid="5629880836805036433">"Wklej"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 9a8c6e9..7914a3d 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -703,8 +703,8 @@
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="6876518925844129331">"Seleccionar tudo"</string>
- <string name="selectText" msgid="3889149123626888637">"Seleccionar texto"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Parar selecção de texto"</string>
+ <!-- no translation found for selectText (4862359311088898878) -->
+ <skip />
<string name="cut" msgid="3092569408438626261">"Cortar"</string>
<string name="copy" msgid="2681946229533511987">"Copiar"</string>
<string name="paste" msgid="5629880836805036433">"Colar"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 2119539..c9c792e 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -703,8 +703,8 @@
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="6876518925844129331">"Selecionar tudo"</string>
- <string name="selectText" msgid="3889149123626888637">"Selecionar texto"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Parar seleção de texto"</string>
+ <!-- no translation found for selectText (4862359311088898878) -->
+ <skip />
<string name="cut" msgid="3092569408438626261">"Recortar"</string>
<string name="copy" msgid="2681946229533511987">"Copiar"</string>
<string name="paste" msgid="5629880836805036433">"Colar"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index a99107e..786571b 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -703,8 +703,8 @@
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="6876518925844129331">"Выбрать все"</string>
- <string name="selectText" msgid="3889149123626888637">"Выбрать текст"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Остановить выделение текста"</string>
+ <!-- no translation found for selectText (4862359311088898878) -->
+ <skip />
<string name="cut" msgid="3092569408438626261">"Вырезать"</string>
<string name="copy" msgid="2681946229533511987">"Копировать"</string>
<string name="paste" msgid="5629880836805036433">"Вставить"</string>
@@ -782,11 +782,11 @@
<string name="perms_hide" msgid="7283915391320676226"><b>"Скрыть"</b></string>
<string name="perms_show_all" msgid="2671791163933091180"><b>"Показать все"</b></string>
<string name="usb_storage_activity_title" msgid="2399289999608900443">"Запоминающее устройство USB"</string>
- <string name="usb_storage_title" msgid="5901459041398751495">"устройство USB подключено"</string>
+ <string name="usb_storage_title" msgid="5901459041398751495">"USB-подключение установлено"</string>
<string name="usb_storage_message" msgid="4796759646167247178">"Телефон подключен к компьютеру через порт USB. Нажмите кнопку ниже, если необходимо копировать файлы с компьютера на SD-карту устройства Android (или наоборот)."</string>
<string name="usb_storage_button_mount" msgid="1052259930369508235">"Включить USB-накопитель"</string>
<string name="usb_storage_error_message" msgid="2534784751603345363">"При использовании SD-карты как USB-накопителя возникла неполадка."</string>
- <string name="usb_storage_notification_title" msgid="8175892554757216525">"устройство USB подключено"</string>
+ <string name="usb_storage_notification_title" msgid="8175892554757216525">"USB-подключение установлено"</string>
<string name="usb_storage_notification_message" msgid="7380082404288219341">"Выберите копирование файлов на компьютер или с компьютера."</string>
<string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"Выключить USB-накопитель"</string>
<string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Выберите, чтобы выключить USB-накопитель."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index b3e415d..8a115697 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -703,8 +703,8 @@
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="6876518925844129331">"Välj alla"</string>
- <string name="selectText" msgid="3889149123626888637">"Markera text"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Sluta välja text"</string>
+ <!-- no translation found for selectText (4862359311088898878) -->
+ <skip />
<string name="cut" msgid="3092569408438626261">"Klipp ut"</string>
<string name="copy" msgid="2681946229533511987">"Kopiera"</string>
<string name="paste" msgid="5629880836805036433">"Klistra in"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index a6bc41e..b45d5bb 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -703,8 +703,8 @@
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="6876518925844129331">"Tümünü seç"</string>
- <string name="selectText" msgid="3889149123626888637">"Metin seç"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"Metin seçmeyi durdur"</string>
+ <!-- no translation found for selectText (4862359311088898878) -->
+ <skip />
<string name="cut" msgid="3092569408438626261">"Kes"</string>
<string name="copy" msgid="2681946229533511987">"Kopyala"</string>
<string name="paste" msgid="5629880836805036433">"Yapıştır"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index aa3f12d..88c38e5 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -703,8 +703,8 @@
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="6876518925844129331">"全选"</string>
- <string name="selectText" msgid="3889149123626888637">"选择文字"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"停止选择文字"</string>
+ <!-- no translation found for selectText (4862359311088898878) -->
+ <skip />
<string name="cut" msgid="3092569408438626261">"剪切"</string>
<string name="copy" msgid="2681946229533511987">"复制"</string>
<string name="paste" msgid="5629880836805036433">"粘贴"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 5bf0342..7d3c27a 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -703,8 +703,8 @@
<string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
<string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
<string name="selectAll" msgid="6876518925844129331">"全部選取"</string>
- <string name="selectText" msgid="3889149123626888637">"選取文字"</string>
- <string name="stopSelectingText" msgid="4157931463872320996">"停止選取文字"</string>
+ <!-- no translation found for selectText (4862359311088898878) -->
+ <skip />
<string name="cut" msgid="3092569408438626261">"剪下"</string>
<string name="copy" msgid="2681946229533511987">"複製"</string>
<string name="paste" msgid="5629880836805036433">"貼上"</string>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 5b7e88f..3af12b7 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1250,8 +1250,7 @@
<public type="attr" name="logo" id="0x010102be" />
<public type="attr" name="xlargeScreens" id="0x010102bf" />
- <public type="attr" name="cantSaveState" id="0x010102c0" />
- <public type="attr" name="immersive" id="0x010102c1" />
+ <public type="attr" name="immersive" id="0x010102c0" />
<public-padding type="attr" name="kraken_resource_pad" end="0x01010300" />
<public-padding type="id" name="kraken_resource_pad" end="0x01020040" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 52abe45..03b721c 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1853,12 +1853,9 @@
<!-- Item on EditText context menu. This action is used to select all text in the edit field. -->
<string name="selectAll">Select all</string>
- <!-- Item on EditText context menu. This action is used to start selecting text in the edit field. -->
+ <!-- Item on EditText context menu. This action is used to start selecting text in the edit field. [CHAR LIMIT=20] -->
<string name="selectText">Select word</string>
- <!-- Item on EditText context menu. This action is used to stop selecting text in the edit field. -->
- <string name="stopSelectingText">Stop selecting text</string>
-
<!-- Item on EditText context menu. This action is used to cut selected the text into the clipboard. -->
<string name="cut">Cut</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 02a601a..af04117 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -88,13 +88,6 @@
<item name="windowExitAnimation">@anim/status_bar_exit</item>
</style>
- <!-- {@hide} -->
- <style name="Animation.StatusBar.IntruderAlert"
- parent="@android:style/Animation.StatusBar">
- <item name="android:windowEnterAnimation">@anim/priority_alert_enter</item>
- <item name="android:windowExitAnimation">@anim/priority_alert_exit</item>
- </style>
-
<!-- Standard animations for a translucent window or activity. This
style is <em>not<em> used by default for the translucent theme
(since translucent activities are a special case that have no
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index cbf8c87..de3d153 100755
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -358,6 +358,7 @@
assertTrue((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
assertEquals(srcPath, drmInstallPath);
assertEquals(publicSrcPath, appInstallPath);
+ assertTrue(info.nativeLibraryDir.startsWith(dataDir.getPath()));
} else {
assertFalse((info.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
int rLoc = getInstallLoc(flags, expInstallLocation, pkgLen);
@@ -365,10 +366,12 @@
assertEquals(srcPath, appInstallPath);
assertEquals(publicSrcPath, appInstallPath);
assertFalse((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
+ assertTrue(info.nativeLibraryDir.startsWith(dataDir.getPath()));
} else if (rLoc == INSTALL_LOC_SD){
assertTrue((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
assertTrue(srcPath.startsWith(SECURE_CONTAINERS_PREFIX));
assertTrue(publicSrcPath.startsWith(SECURE_CONTAINERS_PREFIX));
+ assertTrue(info.nativeLibraryDir.startsWith(SECURE_CONTAINERS_PREFIX));
} else {
// TODO handle error. Install should have failed.
}
diff --git a/docs/html/guide/topics/providers/content-providers.jd b/docs/html/guide/topics/providers/content-providers.jd
index 30f8d8c..da4e7a1 100644
--- a/docs/html/guide/topics/providers/content-providers.jd
+++ b/docs/html/guide/topics/providers/content-providers.jd
@@ -779,7 +779,7 @@
requested. Here is the general format for each type:</p></li>
<ul>
-<li><p>For a single record: {@code vnd.android.cursor.item/vnd.<em>yourcompanyname.contenttype</em}</p>
+<li><p>For a single record: {@code vnd.android.cursor.item/vnd.<em>yourcompanyname.contenttype</em>}</p>
<p>For example, a request for train record 122, like this URI,</p>
<p style="margin-left: 2em">{@code content://com.example.transportationprovider/trains/122}</p>
diff --git a/include/media/stagefright/AudioSource.h b/include/media/stagefright/AudioSource.h
index 2597e9e..1af4254 100644
--- a/include/media/stagefright/AudioSource.h
+++ b/include/media/stagefright/AudioSource.h
@@ -49,7 +49,17 @@
virtual ~AudioSource();
private:
- enum { kMaxBufferSize = 2048 };
+ enum {
+ kMaxBufferSize = 2048,
+
+ // After the initial mute, we raise the volume linearly
+ // over kAutoRampDurationUs.
+ kAutoRampDurationUs = 300000,
+
+ // This is the initial mute duration to suppress
+ // the video recording signal tone
+ kAutoRampStartUs = 700000,
+ };
AudioRecord *mRecord;
status_t mInitCheck;
@@ -67,6 +77,12 @@
void trackMaxAmplitude(int16_t *data, int nSamples);
+ // This is used to raise the volume from mute to the
+ // actual level linearly.
+ void rampVolume(
+ int32_t startFrame, int32_t rampDurationFrames,
+ uint8_t *data, size_t bytes);
+
AudioSource(const AudioSource &);
AudioSource &operator=(const AudioSource &);
};
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 010ded1..875bc5b 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -102,6 +102,7 @@
kInputBufferSizesAreBogus = 512,
kSupportsMultipleFramesPerInputBuffer = 1024,
kAvoidMemcopyInputRecordingFrames = 2048,
+ kRequiresLargerEncoderOutputBuffer = 4096,
};
struct BufferInfo {
diff --git a/include/media/stagefright/foundation/ALooper.h b/include/media/stagefright/foundation/ALooper.h
index 153ead9..70e0c5e 100644
--- a/include/media/stagefright/foundation/ALooper.h
+++ b/include/media/stagefright/foundation/ALooper.h
@@ -19,6 +19,7 @@
#define A_LOOPER_H_
#include <media/stagefright/foundation/ABase.h>
+#include <media/stagefright/foundation/AString.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/List.h>
@@ -36,6 +37,9 @@
ALooper();
+ // Takes effect in a subsequent call to start().
+ void setName(const char *name);
+
handler_id registerHandler(const sp<AHandler> &handler);
void unregisterHandler(handler_id handlerID);
@@ -63,6 +67,8 @@
Mutex mLock;
Condition mQueueChangedCondition;
+ AString mName;
+
List<Event> mEventQueue;
struct LooperThread;
diff --git a/include/private/surfaceflinger/SharedBufferStack.h b/include/private/surfaceflinger/SharedBufferStack.h
index d016dfa..d689667 100644
--- a/include/private/surfaceflinger/SharedBufferStack.h
+++ b/include/private/surfaceflinger/SharedBufferStack.h
@@ -151,7 +151,6 @@
~SharedBufferBase();
status_t getStatus() const;
int32_t getIdentity() const;
- size_t getFrontBuffer() const;
String8 dump(char const* prefix) const;
protected:
@@ -226,6 +225,11 @@
inline ssize_t operator()();
};
+ struct DequeueUpdate : public UpdateBase {
+ inline DequeueUpdate(SharedBufferBase* sbb);
+ inline ssize_t operator()();
+ };
+
struct UndoDequeueUpdate : public UpdateBase {
inline UndoDequeueUpdate(SharedBufferBase* sbb);
inline ssize_t operator()();
diff --git a/libs/surfaceflinger_client/SharedBufferStack.cpp b/libs/surfaceflinger_client/SharedBufferStack.cpp
index 4ad9f86..38b2fae 100644
--- a/libs/surfaceflinger_client/SharedBufferStack.cpp
+++ b/libs/surfaceflinger_client/SharedBufferStack.cpp
@@ -191,12 +191,6 @@
return stack.identity;
}
-size_t SharedBufferBase::getFrontBuffer() const
-{
- SharedBufferStack& stack( *mSharedStack );
- return size_t( stack.head );
-}
-
String8 SharedBufferBase::dump(char const* prefix) const
{
const size_t SIZE = 1024;
@@ -281,6 +275,16 @@
return NO_ERROR;
}
+SharedBufferClient::DequeueUpdate::DequeueUpdate(SharedBufferBase* sbb)
+ : UpdateBase(sbb) {
+}
+ssize_t SharedBufferClient::DequeueUpdate::operator()() {
+ if (android_atomic_dec(&stack.available) == 0) {
+ LOGW("dequeue probably called from multiple threads!");
+ }
+ return NO_ERROR;
+}
+
SharedBufferClient::UndoDequeueUpdate::UndoDequeueUpdate(SharedBufferBase* sbb)
: UpdateBase(sbb) {
}
@@ -388,12 +392,8 @@
if (err != NO_ERROR)
return ssize_t(err);
- // NOTE: 'stack.available' is part of the conditions, however
- // decrementing it, never changes any conditions, so we don't need
- // to do this as part of an update.
- if (android_atomic_dec(&stack.available) == 0) {
- LOGW("dequeue probably called from multiple threads!");
- }
+ DequeueUpdate update(this);
+ updateCondition( update );
undoDequeueTail = tail;
int dequeued = stack.index[tail];
diff --git a/libs/utils/ZipFileRO.cpp b/libs/utils/ZipFileRO.cpp
index 604f558..a0e01c6 100644
--- a/libs/utils/ZipFileRO.cpp
+++ b/libs/utils/ZipFileRO.cpp
@@ -508,8 +508,8 @@
}
if (get4LE(lfhBuf) != kLFHSignature) {
- LOGW("didn't find signature at start of lfh, offset=%ld\n",
- localHdrOffset);
+ LOGW("didn't find signature at start of lfh, offset=%ld (got 0x%08lx, expected 0x%08x)\n",
+ localHdrOffset, get4LE(lfhBuf), kLFHSignature);
return false;
}
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index 9ceda7e..9aa84a03 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -127,6 +127,13 @@
"android.location.GPS_ENABLED_CHANGE";
/**
+ * Broadcast intent action when the configured location providers
+ * change.
+ */
+ public static final String PROVIDERS_CHANGED_ACTION =
+ "android.location.PROVIDERS_CHANGED";
+
+ /**
* Broadcast intent action indicating that the GPS has either started or
* stopped receiving GPS fixes. An intent extra provides this state as a
* boolean, where {@code true} means that the GPS is actively receiving fixes.
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index c8dfede..4c729e4 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -40,6 +40,7 @@
mGroup(NULL) {
LOGV("sampleRate: %d, channels: %d", sampleRate, channels);
+ CHECK(channels == 1 || channels == 2);
uint32_t flags = AudioRecord::RECORD_AGC_ENABLE |
AudioRecord::RECORD_NS_ENABLE |
AudioRecord::RECORD_IIR_ENABLE;
@@ -158,6 +159,38 @@
}
+void AudioSource::rampVolume(
+ int32_t startFrame, int32_t rampDurationFrames,
+ uint8_t *data, size_t bytes) {
+
+ const int32_t kShift = 14;
+ int32_t fixedMultiplier = (startFrame << kShift) / rampDurationFrames;
+ const int32_t nChannels = mRecord->channelCount();
+ int32_t stopFrame = startFrame + bytes / sizeof(int16_t);
+ int16_t *frame = (int16_t *) data;
+ if (stopFrame > rampDurationFrames) {
+ stopFrame = rampDurationFrames;
+ }
+
+ while (startFrame < stopFrame) {
+ if (nChannels == 1) { // mono
+ frame[0] = (frame[0] * fixedMultiplier) >> kShift;
+ ++frame;
+ ++startFrame;
+ } else { // stereo
+ frame[0] = (frame[0] * fixedMultiplier) >> kShift;
+ frame[1] = (frame[1] * fixedMultiplier) >> kShift;
+ frame += 2;
+ startFrame += 2;
+ }
+
+ // Update the multiplier every 4 frames
+ if ((startFrame & 3) == 0) {
+ fixedMultiplier = (startFrame << kShift) / rampDurationFrames;
+ }
+ }
+}
+
status_t AudioSource::read(
MediaBuffer **out, const ReadOptions *options) {
*out = NULL;
@@ -242,6 +275,19 @@
continue;
}
+ if (mPrevSampleTimeUs - mStartTimeUs < kAutoRampStartUs) {
+ // Mute the initial video recording signal
+ memset((uint8_t *) buffer->data(), 0, n);
+ } else if (mPrevSampleTimeUs - mStartTimeUs < kAutoRampStartUs + kAutoRampDurationUs) {
+ int32_t autoRampDurationFrames =
+ (kAutoRampDurationUs * sampleRate + 500000LL) / 1000000LL;
+
+ int32_t autoRampStartFrames =
+ (kAutoRampStartUs * sampleRate + 500000LL) / 1000000LL;
+
+ int32_t nFrames = numFramesRecorded - autoRampStartFrames;
+ rampVolume(nFrames, autoRampDurationFrames, (uint8_t *) buffer->data(), n);
+ }
if (mTrackMaxAmplitude) {
trackMaxAmplitude((int16_t *) buffer->data(), n >> 1);
}
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index a0cd5c3..7daac96 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -196,7 +196,6 @@
mExtractorFlags(0),
mLastVideoBuffer(NULL),
mVideoBuffer(NULL),
- mRTSPTimeOffset(0),
mSuspensionState(NULL) {
CHECK_EQ(mClient.connect(), OK);
@@ -739,7 +738,10 @@
}
status_t AwesomePlayer::getPosition(int64_t *positionUs) {
- if (mSeeking) {
+ if (mRTSPController != NULL) {
+ *positionUs = mRTSPController->getNormalPlayTimeUs();
+ }
+ else if (mSeeking) {
*positionUs = mSeekTimeUs;
} else if (mVideoSource != NULL) {
Mutex::Autolock autoLock(mMiscStateLock);
@@ -750,10 +752,6 @@
*positionUs = 0;
}
- if (mRTSPController != NULL) {
- *positionUs += mRTSPTimeOffset;
- }
-
return OK;
}
@@ -770,13 +768,10 @@
status_t AwesomePlayer::seekTo_l(int64_t timeUs) {
if (mRTSPController != NULL) {
- pause_l();
mRTSPController->seek(timeUs);
- play_l();
notifyListener_l(MEDIA_SEEK_COMPLETE);
mSeekNotificationSent = true;
- mRTSPTimeOffset = timeUs;
return OK;
}
@@ -1246,6 +1241,7 @@
} else if (!strncmp("rtsp://gtalk/", mUri.string(), 13)) {
if (mLooper == NULL) {
mLooper = new ALooper;
+ mLooper->setName("gtalk rtp");
mLooper->start(
false /* runOnCallingThread */,
false /* canCallJava */,
@@ -1357,6 +1353,7 @@
} else if (!strncasecmp("rtsp://", mUri.string(), 7)) {
if (mLooper == NULL) {
mLooper = new ALooper;
+ mLooper->setName("rtsp");
mLooper->start();
}
mRTSPController = new ARTSPController(mLooper);
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index c02b7f3..9171aab 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -180,6 +180,7 @@
mLastAccessPos(0),
mFetching(true),
mLastFetchTimeUs(-1) {
+ mLooper->setName("NuCachedSource2");
mLooper->registerHandler(mReflector);
mLooper->start();
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 4741b1d..165cec9 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -353,6 +353,15 @@
quirks |= kRequiresLoadedToIdleAfterAllocation;
quirks |= kRequiresAllocateBufferOnInputPorts;
quirks |= kRequiresAllocateBufferOnOutputPorts;
+ if (!strncmp(componentName, "OMX.qcom.video.encoder.avc", 26)) {
+
+ // The AVC encoder advertises the size of output buffers
+ // based on the input video resolution and assumes
+ // the worst/least compression ratio is 0.5. It is found that
+ // sometimes, the output buffer size is larger than
+ // size advertised by the encoder.
+ quirks |= kRequiresLargerEncoderOutputBuffer;
+ }
}
if (!strncmp(componentName, "OMX.qcom.7x30.video.encoder.", 28)) {
}
@@ -906,6 +915,10 @@
video_def->nBitrate = bitRate; // Q16 format
video_def->eCompressionFormat = compressionFormat;
video_def->eColorFormat = OMX_COLOR_FormatUnused;
+ if (mQuirks & kRequiresLargerEncoderOutputBuffer) {
+ // Increases the output buffer size
+ def.nBufferSize = ((def.nBufferSize * 3) >> 1);
+ }
err = mOMX->setParameter(
mNode, OMX_IndexParamPortDefinition, &def, sizeof(def));
diff --git a/media/libstagefright/foundation/ALooper.cpp b/media/libstagefright/foundation/ALooper.cpp
index 77afb01..b7087f8 100644
--- a/media/libstagefright/foundation/ALooper.cpp
+++ b/media/libstagefright/foundation/ALooper.cpp
@@ -65,6 +65,10 @@
stop();
}
+void ALooper::setName(const char *name) {
+ mName = name;
+}
+
ALooper::handler_id ALooper::registerHandler(const sp<AHandler> &handler) {
return gLooperRoster.registerHandler(this, handler);
}
@@ -100,7 +104,8 @@
mThread = new LooperThread(this, canCallJava);
- status_t err = mThread->run("ALooper", priority);
+ status_t err = mThread->run(
+ mName.empty() ? "ALooper" : mName.c_str(), priority);
if (err != OK) {
mThread.clear();
}
diff --git a/media/libstagefright/include/ARTSPController.h b/media/libstagefright/include/ARTSPController.h
index 7020564..7016880 100644
--- a/media/libstagefright/include/ARTSPController.h
+++ b/media/libstagefright/include/ARTSPController.h
@@ -41,6 +41,8 @@
virtual sp<MetaData> getTrackMetaData(
size_t index, uint32_t flags);
+ int64_t getNormalPlayTimeUs();
+
void onMessageReceived(const sp<AMessage> &msg);
protected:
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 49b5c78..55e2c36 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -180,7 +180,6 @@
sp<ALooper> mLooper;
sp<ARTSPController> mRTSPController;
- int64_t mRTSPTimeOffset;
sp<ARTPSession> mRTPSession;
sp<UDPPusher> mRTPPusher, mRTCPPusher;
diff --git a/media/libstagefright/rtsp/AAMRAssembler.cpp b/media/libstagefright/rtsp/AAMRAssembler.cpp
index c56578b..154ba31 100644
--- a/media/libstagefright/rtsp/AAMRAssembler.cpp
+++ b/media/libstagefright/rtsp/AAMRAssembler.cpp
@@ -178,12 +178,8 @@
}
}
- uint64_t ntpTime;
- CHECK(buffer->meta()->findInt64(
- "ntp-time", (int64_t *)&ntpTime));
-
sp<ABuffer> accessUnit = new ABuffer(totalSize);
- accessUnit->meta()->setInt64("ntp-time", ntpTime);
+ CopyTimes(accessUnit, buffer);
size_t dstOffset = 0;
for (size_t i = 0; i < tableOfContents.size(); ++i) {
diff --git a/media/libstagefright/rtsp/AAVCAssembler.cpp b/media/libstagefright/rtsp/AAVCAssembler.cpp
index b22de2c..6b1e292 100644
--- a/media/libstagefright/rtsp/AAVCAssembler.cpp
+++ b/media/libstagefright/rtsp/AAVCAssembler.cpp
@@ -155,7 +155,7 @@
sp<ABuffer> unit = new ABuffer(nalSize);
memcpy(unit->data(), &data[2], nalSize);
- PropagateTimes(buffer, unit);
+ CopyTimes(unit, buffer);
addSingleNALUnit(unit);
@@ -287,7 +287,7 @@
++totalSize;
sp<ABuffer> unit = new ABuffer(totalSize);
- PropagateTimes(buffer, unit);
+ CopyTimes(unit, *queue->begin());
unit->data()[0] = (nri << 5) | nalType;
@@ -325,10 +325,6 @@
LOG(VERBOSE) << "Access unit complete (" << mNALUnits.size() << " nal units)";
#endif
- uint64_t ntpTime;
- CHECK((*mNALUnits.begin())->meta()->findInt64(
- "ntp-time", (int64_t *)&ntpTime));
-
size_t totalSize = 0;
for (List<sp<ABuffer> >::iterator it = mNALUnits.begin();
it != mNALUnits.end(); ++it) {
@@ -347,7 +343,7 @@
offset += nal->size();
}
- accessUnit->meta()->setInt64("ntp-time", ntpTime);
+ CopyTimes(accessUnit, *mNALUnits.begin());
#if 0
printf(mAccessUnitDamaged ? "X" : ".");
diff --git a/media/libstagefright/rtsp/AH263Assembler.cpp b/media/libstagefright/rtsp/AH263Assembler.cpp
index 2818041..498295c 100644
--- a/media/libstagefright/rtsp/AH263Assembler.cpp
+++ b/media/libstagefright/rtsp/AH263Assembler.cpp
@@ -128,10 +128,6 @@
LOG(VERBOSE) << "Access unit complete (" << mPackets.size() << " packets)";
#endif
- uint64_t ntpTime;
- CHECK((*mPackets.begin())->meta()->findInt64(
- "ntp-time", (int64_t *)&ntpTime));
-
size_t totalSize = 0;
List<sp<ABuffer> >::iterator it = mPackets.begin();
while (it != mPackets.end()) {
@@ -155,7 +151,7 @@
++it;
}
- accessUnit->meta()->setInt64("ntp-time", ntpTime);
+ CopyTimes(accessUnit, *mPackets.begin());
#if 0
printf(mAccessUnitDamaged ? "X" : ".");
diff --git a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
index 6e46361..b0d2c64 100644
--- a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
@@ -103,10 +103,6 @@
LOG(VERBOSE) << "Access unit complete (" << mPackets.size() << " packets)";
#endif
- uint64_t ntpTime;
- CHECK((*mPackets.begin())->meta()->findInt64(
- "ntp-time", (int64_t *)&ntpTime));
-
size_t totalSize = 0;
List<sp<ABuffer> >::iterator it = mPackets.begin();
while (it != mPackets.end()) {
@@ -142,7 +138,7 @@
++it;
}
- accessUnit->meta()->setInt64("ntp-time", ntpTime);
+ CopyTimes(accessUnit, *mPackets.begin());
#if 0
printf(mAccessUnitDamaged ? "X" : ".");
diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
index 7e633d7..7dd3e3f 100644
--- a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
@@ -101,10 +101,6 @@
LOG(VERBOSE) << "Access unit complete (" << mPackets.size() << " nal units)";
#endif
- uint64_t ntpTime;
- CHECK((*mPackets.begin())->meta()->findInt64(
- "ntp-time", (int64_t *)&ntpTime));
-
size_t totalSize = 0;
for (List<sp<ABuffer> >::iterator it = mPackets.begin();
it != mPackets.end(); ++it) {
@@ -120,7 +116,7 @@
offset += nal->size();
}
- accessUnit->meta()->setInt64("ntp-time", ntpTime);
+ CopyTimes(accessUnit, *mPackets.begin());
#if 0
printf(mAccessUnitDamaged ? "X" : ".");
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index b930184..2d7738b 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -402,16 +402,41 @@
return csd;
}
+static bool GetClockRate(const AString &desc, uint32_t *clockRate) {
+ ssize_t slashPos = desc.find("/");
+ if (slashPos < 0) {
+ return false;
+ }
+
+ const char *s = desc.c_str() + slashPos + 1;
+
+ char *end;
+ unsigned long x = strtoul(s, &end, 10);
+
+ if (end == s || (*end != '\0' && *end != '/')) {
+ return false;
+ }
+
+ *clockRate = x;
+
+ return true;
+}
+
APacketSource::APacketSource(
const sp<ASessionDescription> &sessionDesc, size_t index)
: mInitCheck(NO_INIT),
mFormat(new MetaData),
- mEOSResult(OK) {
+ mEOSResult(OK),
+ mRTPTimeBase(0),
+ mNormalPlayTimeBaseUs(0),
+ mLastNormalPlayTimeUs(0) {
unsigned long PT;
AString desc;
AString params;
sessionDesc->getFormatType(index, &PT, &desc, ¶ms);
+ CHECK(GetClockRate(desc, &mClockRate));
+
int64_t durationUs;
if (sessionDesc->getDurationUs(&durationUs)) {
mFormat->setInt64(kKeyDuration, durationUs);
@@ -571,6 +596,8 @@
if (!mBuffers.empty()) {
const sp<ABuffer> buffer = *mBuffers.begin();
+ updateNormalPlayTime_l(buffer);
+
MediaBuffer *mediaBuffer = new MediaBuffer(buffer->size());
int64_t timeUs;
@@ -588,6 +615,16 @@
return mEOSResult;
}
+void APacketSource::updateNormalPlayTime_l(const sp<ABuffer> &buffer) {
+ uint32_t rtpTime;
+ CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
+
+ mLastNormalPlayTimeUs =
+ (((double)rtpTime - (double)mRTPTimeBase) / mClockRate)
+ * 1000000ll
+ + mNormalPlayTimeBaseUs;
+}
+
void APacketSource::queueAccessUnit(const sp<ABuffer> &buffer) {
int32_t damaged;
if (buffer->meta()->findInt32("damaged", &damaged) && damaged) {
@@ -613,4 +650,17 @@
mBuffers.clear();
}
+int64_t APacketSource::getNormalPlayTimeUs() {
+ Mutex::Autolock autoLock(mLock);
+ return mLastNormalPlayTimeUs;
+}
+
+void APacketSource::setNormalPlayTimeMapping(
+ uint32_t rtpTime, int64_t normalPlayTimeUs) {
+ Mutex::Autolock autoLock(mLock);
+
+ mRTPTimeBase = rtpTime;
+ mNormalPlayTimeBaseUs = normalPlayTimeUs;
+}
+
} // namespace android
diff --git a/media/libstagefright/rtsp/APacketSource.h b/media/libstagefright/rtsp/APacketSource.h
index 197af3e..3833ab1 100644
--- a/media/libstagefright/rtsp/APacketSource.h
+++ b/media/libstagefright/rtsp/APacketSource.h
@@ -45,6 +45,11 @@
void flushQueue();
+ int64_t getNormalPlayTimeUs();
+
+ void setNormalPlayTimeMapping(
+ uint32_t rtpTime, int64_t normalPlayTimeUs);
+
protected:
virtual ~APacketSource();
@@ -58,6 +63,15 @@
List<sp<ABuffer> > mBuffers;
status_t mEOSResult;
+ uint32_t mClockRate;
+
+ uint32_t mRTPTimeBase;
+ int64_t mNormalPlayTimeBaseUs;
+
+ int64_t mLastNormalPlayTimeUs;
+
+ void updateNormalPlayTime_l(const sp<ABuffer> &buffer);
+
DISALLOW_EVIL_CONSTRUCTORS(APacketSource);
};
diff --git a/media/libstagefright/rtsp/ARTPAssembler.cpp b/media/libstagefright/rtsp/ARTPAssembler.cpp
index 24225b8..9ba2b37 100644
--- a/media/libstagefright/rtsp/ARTPAssembler.cpp
+++ b/media/libstagefright/rtsp/ARTPAssembler.cpp
@@ -35,18 +35,6 @@
: mFirstFailureTimeUs(-1) {
}
-void ARTPAssembler::PropagateTimes(
- const sp<ABuffer> &from, const sp<ABuffer> &to) {
- uint32_t rtpTime;
- CHECK(from->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
-
- uint64_t ntpTime = 0;
- CHECK(from->meta()->findInt64("ntp-time", (int64_t *)&ntpTime));
-
- to->meta()->setInt32("rtp-time", rtpTime);
- to->meta()->setInt64("ntp-time", ntpTime);
-}
-
void ARTPAssembler::onPacketReceived(const sp<ARTPSource> &source) {
AssemblyStatus status;
for (;;) {
@@ -75,4 +63,19 @@
}
}
+// static
+void ARTPAssembler::CopyTimes(const sp<ABuffer> &to, const sp<ABuffer> &from) {
+ uint64_t ntpTime;
+ CHECK(from->meta()->findInt64("ntp-time", (int64_t *)&ntpTime));
+
+ uint32_t rtpTime;
+ CHECK(from->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
+
+ to->meta()->setInt64("ntp-time", ntpTime);
+ to->meta()->setInt32("rtp-time", rtpTime);
+
+ // Copy the seq number.
+ to->setInt32Data(from->int32Data());
+}
+
} // namespace android
diff --git a/media/libstagefright/rtsp/ARTPAssembler.h b/media/libstagefright/rtsp/ARTPAssembler.h
index e598088..70ea1866 100644
--- a/media/libstagefright/rtsp/ARTPAssembler.h
+++ b/media/libstagefright/rtsp/ARTPAssembler.h
@@ -40,12 +40,11 @@
virtual void onByeReceived() = 0;
protected:
- static void PropagateTimes(
- const sp<ABuffer> &from, const sp<ABuffer> &to);
-
virtual AssemblyStatus assembleMore(const sp<ARTPSource> &source) = 0;
virtual void packetLost() = 0;
+ static void CopyTimes(const sp<ABuffer> &to, const sp<ABuffer> &from);
+
private:
int64_t mFirstFailureTimeUs;
diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp
index d4eed7c..ce1ee0e 100644
--- a/media/libstagefright/rtsp/ARTPWriter.cpp
+++ b/media/libstagefright/rtsp/ARTPWriter.cpp
@@ -31,6 +31,7 @@
mReflector(new AHandlerReflector<ARTPWriter>(this)) {
CHECK_GE(fd, 0);
+ mLooper->setName("rtp writer");
mLooper->registerHandler(mReflector);
mLooper->start();
diff --git a/media/libstagefright/rtsp/ARTSPController.cpp b/media/libstagefright/rtsp/ARTSPController.cpp
index 9df17cba..a89946b 100644
--- a/media/libstagefright/rtsp/ARTSPController.cpp
+++ b/media/libstagefright/rtsp/ARTSPController.cpp
@@ -138,4 +138,9 @@
}
}
+int64_t ARTSPController::getNormalPlayTimeUs() {
+ CHECK(mHandler != NULL);
+ return mHandler->getNormalPlayTimeUs();
+}
+
} // namespace android
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 4c6f058..f20dd6f 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -23,6 +23,8 @@
#include "ARTSPConnection.h"
#include "ASessionDescription.h"
+#include <ctype.h>
+
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
@@ -31,8 +33,44 @@
#define USE_TCP_INTERLEAVED 0
+// If no access units are received within 3 secs, assume that the rtp
+// stream has ended and signal end of stream.
+static int64_t kAccessUnitTimeoutUs = 3000000ll;
+
+// If no access units arrive for the first 10 secs after starting the
+// stream, assume none ever will and signal EOS or switch transports.
+static int64_t kStartupTimeoutUs = 10000000ll;
+
namespace android {
+static bool GetAttribute(const char *s, const char *key, AString *value) {
+ value->clear();
+
+ size_t keyLen = strlen(key);
+
+ for (;;) {
+ while (isspace(*s)) {
+ ++s;
+ }
+
+ const char *colonPos = strchr(s, ';');
+
+ size_t len =
+ (colonPos == NULL) ? strlen(s) : colonPos - s;
+
+ if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) {
+ value->setTo(&s[keyLen + 1], len - keyLen - 1);
+ return true;
+ }
+
+ if (colonPos == NULL) {
+ return false;
+ }
+
+ s = colonPos + 1;
+ }
+}
+
struct MyHandler : public AHandler {
MyHandler(const char *url, const sp<ALooper> &looper)
: mLooper(looper),
@@ -43,8 +81,10 @@
mSetupTracksSuccessful(false),
mSeekPending(false),
mFirstAccessUnit(true),
- mFirstAccessUnitNTP(0) {
-
+ mFirstAccessUnitNTP(0),
+ mNumAccessUnitsReceived(0),
+ mCheckPending(false) {
+ mNetLooper->setName("rtsp net");
mNetLooper->start(false /* runOnCallingThread */,
false /* canCallJava */,
PRIORITY_HIGHEST);
@@ -76,6 +116,20 @@
msg->post();
}
+ int64_t getNormalPlayTimeUs() {
+ int64_t maxTimeUs = 0;
+ for (size_t i = 0; i < mTracks.size(); ++i) {
+ int64_t timeUs = mTracks.editItemAt(i).mPacketSource
+ ->getNormalPlayTimeUs();
+
+ if (i == 0 || timeUs > maxTimeUs) {
+ maxTimeUs = timeUs;
+ }
+ }
+
+ return maxTimeUs;
+ }
+
virtual void onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case 'conn':
@@ -269,12 +323,14 @@
CHECK_EQ(response->mStatusCode, 200u);
+ parsePlayResponse(response);
+
mDoneMsg->setInt32("result", OK);
mDoneMsg->post();
mDoneMsg = NULL;
sp<AMessage> timeout = new AMessage('tiou', id());
- timeout->post(10000000ll);
+ timeout->post(kStartupTimeoutUs);
} else {
sp<AMessage> reply = new AMessage('disc', id());
mConn->disconnect(reply);
@@ -332,16 +388,38 @@
break;
}
+ case 'chek':
+ {
+ if (mNumAccessUnitsReceived == 0) {
+ LOG(INFO) << "stream ended? aborting.";
+ (new AMessage('abor', id()))->post();
+ break;
+ }
+
+ mNumAccessUnitsReceived = 0;
+ msg->post(kAccessUnitTimeoutUs);
+ break;
+ }
+
case 'accu':
{
+ ++mNumAccessUnitsReceived;
+
+ if (!mCheckPending) {
+ mCheckPending = true;
+ sp<AMessage> check = new AMessage('chek', id());
+ check->post(kAccessUnitTimeoutUs);
+ }
+
size_t trackIndex;
CHECK(msg->findSize("track-index", &trackIndex));
+ TrackInfo *track = &mTracks.editItemAt(trackIndex);
+
int32_t eos;
if (msg->findInt32("eos", &eos)) {
LOG(INFO) << "received BYE on track index " << trackIndex;
#if 0
- TrackInfo *track = &mTracks.editItemAt(trackIndex);
track->mPacketSource->signalEOS(ERROR_END_OF_STREAM);
#endif
return;
@@ -352,10 +430,32 @@
sp<ABuffer> accessUnit = static_cast<ABuffer *>(obj.get());
+ uint32_t seqNum = (uint32_t)accessUnit->int32Data();
+
+ if (seqNum < track->mFirstSeqNumInSegment) {
+ LOG(INFO) << "dropping stale access-unit "
+ << "(" << seqNum << " < "
+ << track->mFirstSeqNumInSegment << ")";
+ break;
+ }
+
uint64_t ntpTime;
CHECK(accessUnit->meta()->findInt64(
"ntp-time", (int64_t *)&ntpTime));
+ uint32_t rtpTime;
+ CHECK(accessUnit->meta()->findInt32(
+ "rtp-time", (int32_t *)&rtpTime));
+
+ if (track->mNewSegment) {
+ track->mNewSegment = false;
+
+ LOG(VERBOSE) << "first segment unit ntpTime="
+ << StringPrintf("0x%016llx", ntpTime)
+ << " rtpTime=" << rtpTime
+ << " seq=" << seqNum;
+ }
+
if (mFirstAccessUnit) {
mFirstAccessUnit = false;
mFirstAccessUnitNTP = ntpTime;
@@ -414,6 +514,11 @@
case 'see1':
{
+ // Session is paused now.
+ for (size_t i = 0; i < mTracks.size(); ++i) {
+ mTracks.editItemAt(i).mPacketSource->flushQueue();
+ }
+
int64_t timeUs;
CHECK(msg->findInt64("time", &timeUs));
@@ -440,15 +545,13 @@
{
CHECK(mSeekPending);
- LOG(INFO) << "seek completed.";
- mSeekPending = false;
-
int32_t result;
CHECK(msg->findInt32("result", &result));
- if (result != OK) {
- LOG(ERROR) << "seek FAILED";
- break;
- }
+
+ LOG(INFO) << "PLAY completed with result "
+ << result << " (" << strerror(-result) << ")";
+
+ CHECK_EQ(result, (status_t)OK);
sp<RefBase> obj;
CHECK(msg->findObject("response", &obj));
@@ -457,9 +560,10 @@
CHECK_EQ(response->mStatusCode, 200u);
- for (size_t i = 0; i < mTracks.size(); ++i) {
- mTracks.editItemAt(i).mPacketSource->flushQueue();
- }
+ parsePlayResponse(response);
+
+ LOG(INFO) << "seek completed.";
+ mSeekPending = false;
break;
}
@@ -480,9 +584,8 @@
{
if (mFirstAccessUnit) {
LOG(WARNING) << "Never received any data, disconnecting.";
-
+ (new AMessage('abor', id()))->post();
}
- (new AMessage('abor', id()))->post();
break;
}
@@ -492,6 +595,90 @@
}
}
+ static void SplitString(
+ const AString &s, const char *separator, List<AString> *items) {
+ items->clear();
+ size_t start = 0;
+ while (start < s.size()) {
+ ssize_t offset = s.find(separator, start);
+
+ if (offset < 0) {
+ items->push_back(AString(s, start, s.size() - start));
+ break;
+ }
+
+ items->push_back(AString(s, start, offset - start));
+ start = offset + strlen(separator);
+ }
+ }
+
+ void parsePlayResponse(const sp<ARTSPResponse> &response) {
+ ssize_t i = response->mHeaders.indexOfKey("range");
+ if (i < 0) {
+ // Server doesn't even tell use what range it is going to
+ // play, therefore we won't support seeking.
+ return;
+ }
+
+ AString range = response->mHeaders.valueAt(i);
+ LOG(VERBOSE) << "Range: " << range;
+
+ AString val;
+ CHECK(GetAttribute(range.c_str(), "npt", &val));
+ float npt1, npt2;
+
+ if (val == "now-") {
+ // This is a live stream and therefore not seekable.
+ return;
+ } else {
+ CHECK_EQ(sscanf(val.c_str(), "%f-%f", &npt1, &npt2), 2);
+ }
+
+ i = response->mHeaders.indexOfKey("rtp-info");
+ CHECK_GE(i, 0);
+
+ AString rtpInfo = response->mHeaders.valueAt(i);
+ List<AString> streamInfos;
+ SplitString(rtpInfo, ",", &streamInfos);
+
+ int n = 1;
+ for (List<AString>::iterator it = streamInfos.begin();
+ it != streamInfos.end(); ++it) {
+ (*it).trim();
+ LOG(VERBOSE) << "streamInfo[" << n << "] = " << *it;
+
+ CHECK(GetAttribute((*it).c_str(), "url", &val));
+
+ size_t trackIndex = 0;
+ while (trackIndex < mTracks.size()
+ && !(val == mTracks.editItemAt(trackIndex).mURL)) {
+ ++trackIndex;
+ }
+ CHECK_LT(trackIndex, mTracks.size());
+
+ CHECK(GetAttribute((*it).c_str(), "seq", &val));
+
+ char *end;
+ unsigned long seq = strtoul(val.c_str(), &end, 10);
+
+ TrackInfo *info = &mTracks.editItemAt(trackIndex);
+ info->mFirstSeqNumInSegment = seq;
+ info->mNewSegment = true;
+
+ CHECK(GetAttribute((*it).c_str(), "rtptime", &val));
+
+ uint32_t rtpTime = strtoul(val.c_str(), &end, 10);
+
+ LOG(VERBOSE) << "track #" << n
+ << ": rtpTime=" << rtpTime << " <=> npt=" << npt1;
+
+ info->mPacketSource->setNormalPlayTimeMapping(
+ rtpTime, (int64_t)(npt1 * 1E6));
+
+ ++n;
+ }
+ }
+
sp<APacketSource> getPacketSource(size_t index) {
CHECK_GE(index, 0u);
CHECK_LT(index, mTracks.size());
@@ -516,11 +703,16 @@
bool mSeekPending;
bool mFirstAccessUnit;
uint64_t mFirstAccessUnitNTP;
+ int64_t mNumAccessUnitsReceived;
+ bool mCheckPending;
struct TrackInfo {
+ AString mURL;
int mRTPSocket;
int mRTCPSocket;
bool mUsingInterleavedTCP;
+ uint32_t mFirstSeqNumInSegment;
+ bool mNewSegment;
sp<APacketSource> mPacketSource;
};
@@ -550,8 +742,13 @@
mTracks.push(TrackInfo());
TrackInfo *info = &mTracks.editItemAt(mTracks.size() - 1);
+ info->mURL = trackURL;
info->mPacketSource = source;
info->mUsingInterleavedTCP = false;
+ info->mFirstSeqNumInSegment = 0;
+ info->mNewSegment = true;
+
+ LOG(VERBOSE) << "track #" << mTracks.size() << " URL=" << trackURL;
AString request = "SETUP ";
request.append(trackURL);
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index b121158..1ffcd56 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -229,14 +229,6 @@
#define EGL_NATIVE_BUFFER_ANDROID 0x3140 /* eglCreateImageKHR target */
#endif
-#ifndef EGL_ANDROID_get_render_buffer
-#define EGL_ANDROID_get_render_buffer 1
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLClientBuffer EGLAPIENTRY eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw);
-#endif
-typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLGETRENDERBUFFERANDROIDPROC) (EGLDisplay dpy, EGLSurface draw);
-#endif
-
#ifndef EGL_ANDROID_swap_rectangle
#define EGL_ANDROID_swap_rectangle 1
#ifdef EGL_EGLEXT_PROTOTYPES
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 9e25681..163b2dbc 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -158,7 +158,6 @@
virtual EGLint getSwapBehavior() const;
virtual EGLBoolean swapBuffers();
virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
- virtual EGLClientBuffer getRenderBuffer() const;
protected:
GGLSurface depth;
};
@@ -202,9 +201,6 @@
{
return EGL_FALSE;
}
-EGLClientBuffer egl_surface_t::getRenderBuffer() const {
- return 0;
-}
// ----------------------------------------------------------------------------
@@ -230,7 +226,6 @@
virtual EGLint getRefreshRate() const;
virtual EGLint getSwapBehavior() const;
virtual EGLBoolean setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
- virtual EGLClientBuffer getRenderBuffer() const;
private:
status_t lock(android_native_buffer_t* buf, int usage, void** vaddr);
@@ -626,11 +621,6 @@
return EGL_TRUE;
}
-EGLClientBuffer egl_window_surface_v2_t::getRenderBuffer() const
-{
- return buffer;
-}
-
EGLBoolean egl_window_surface_v2_t::bindDrawSurface(ogles_context_t* gl)
{
GGLSurface buffer;
@@ -857,7 +847,6 @@
// "KHR_image_pixmap "
"EGL_ANDROID_image_native_buffer "
"EGL_ANDROID_swap_rectangle "
- "EGL_ANDROID_get_render_buffer "
;
// ----------------------------------------------------------------------------
@@ -910,8 +899,6 @@
(__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
{ "eglSetSwapRectangleANDROID",
(__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
- { "eglGetRenderBufferANDROID",
- (__eglMustCastToProperFunctionPointerType)&eglGetRenderBufferANDROID },
};
/*
@@ -2129,18 +2116,3 @@
return EGL_TRUE;
}
-
-EGLClientBuffer eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw)
-{
- if (egl_display_t::is_valid(dpy) == EGL_FALSE)
- return setError(EGL_BAD_DISPLAY, (EGLClientBuffer)0);
-
- egl_surface_t* d = static_cast<egl_surface_t*>(draw);
- if (!d->isValid())
- return setError(EGL_BAD_SURFACE, (EGLClientBuffer)0);
- if (d->dpy != dpy)
- return setError(EGL_BAD_DISPLAY, (EGLClientBuffer)0);
-
- // post the surface
- return d->getRenderBuffer();
-}
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 94b60a1..5e61607 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -61,7 +61,6 @@
"EGL_KHR_image_pixmap "
"EGL_ANDROID_image_native_buffer "
"EGL_ANDROID_swap_rectangle "
- "EGL_ANDROID_get_render_buffer "
;
// ----------------------------------------------------------------------------
@@ -408,8 +407,6 @@
(__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
{ "eglSetSwapRectangleANDROID",
(__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
- { "eglGetRenderBufferANDROID",
- (__eglMustCastToProperFunctionPointerType)&eglGetRenderBufferANDROID },
};
extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS];
@@ -1810,19 +1807,3 @@
}
return setError(EGL_BAD_DISPLAY, NULL);
}
-
-EGLClientBuffer eglGetRenderBufferANDROID(EGLDisplay dpy, EGLSurface draw)
-{
- SurfaceRef _s(draw);
- if (!_s.get()) return setError(EGL_BAD_SURFACE, (EGLClientBuffer*)0);
-
- if (!validate_display_surface(dpy, draw))
- return 0;
- egl_display_t const * const dp = get_display(dpy);
- egl_surface_t const * const s = get_surface(draw);
- if (s->cnx->egl.eglGetRenderBufferANDROID) {
- return s->cnx->egl.eglGetRenderBufferANDROID(
- dp->disp[s->impl].dpy, s->surface);
- }
- return setError(EGL_BAD_DISPLAY, (EGLClientBuffer*)0);
-}
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index c6e0a24..f08bd3c 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -17,7 +17,9 @@
package com.android.defcontainer;
import com.android.internal.app.IMediaContainerService;
+import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.content.PackageHelper;
+
import android.content.Intent;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
@@ -37,6 +39,7 @@
import android.app.IntentService;
import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.Pair;
import java.io.File;
import java.io.FileInputStream;
@@ -44,6 +47,11 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipException;
+import java.util.zip.ZipFile;
import android.os.FileUtils;
import android.provider.Settings;
@@ -59,6 +67,8 @@
private static final String TAG = "DefContainer";
private static final boolean localLOGV = true;
+ private static final String LIB_DIR_NAME = "lib";
+
private IMediaContainerService.Stub mBinder = new IMediaContainerService.Stub() {
/*
* Creates a new container and copies resource there.
@@ -194,18 +204,51 @@
Log.w(TAG, "Make sure sdcard is mounted.");
return null;
}
- // Create new container at newCachePath
+
+ // The .apk file
String codePath = packageURI.getPath();
File codeFile = new File(codePath);
- String newCachePath = null;
+
+ // Calculate size of container needed to hold base APK.
+ long sizeBytes = codeFile.length();
+
+ // Check all the native files that need to be copied and add that to the container size.
+ ZipFile zipFile;
+ List<Pair<ZipEntry, String>> nativeFiles;
+ try {
+ zipFile = new ZipFile(codeFile);
+
+ nativeFiles = new LinkedList<Pair<ZipEntry, String>>();
+
+ NativeLibraryHelper.listPackageNativeBinariesLI(zipFile, nativeFiles);
+
+ final int N = nativeFiles.size();
+ for (int i = 0; i < N; i++) {
+ final Pair<ZipEntry, String> entry = nativeFiles.get(i);
+
+ /*
+ * Note that PackageHelper.createSdDir adds a 1MB padding on
+ * our claimed size, so we don't have to worry about block
+ * alignment here.
+ */
+ sizeBytes += entry.first.getSize();
+ }
+ } catch (ZipException e) {
+ Log.w(TAG, "Failed to extract data from package file", e);
+ return null;
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to cache package shared libs", e);
+ return null;
+ }
+
// Create new container
- if ((newCachePath = PackageHelper.createSdDir(codeFile,
- newCid, key, Process.myUid())) == null) {
+ String newCachePath = null;
+ if ((newCachePath = PackageHelper.createSdDir(sizeBytes, newCid, key, Process.myUid())) == null) {
Log.e(TAG, "Failed to create container " + newCid);
return null;
}
- if (localLOGV) Log.i(TAG, "Created container for " + newCid
- + " at path : " + newCachePath);
+ if (localLOGV)
+ Log.i(TAG, "Created container for " + newCid + " at path : " + newCachePath);
File resFile = new File(newCachePath, resFileName);
if (!FileUtils.copyFile(new File(codePath), resFile)) {
Log.e(TAG, "Failed to copy " + codePath + " to " + resFile);
@@ -213,6 +256,32 @@
PackageHelper.destroySdDir(newCid);
return null;
}
+
+ try {
+ File sharedLibraryDir = new File(newCachePath, LIB_DIR_NAME);
+ sharedLibraryDir.mkdir();
+
+ final int N = nativeFiles.size();
+ for (int i = 0; i < N; i++) {
+ final Pair<ZipEntry, String> entry = nativeFiles.get(i);
+
+ InputStream is = zipFile.getInputStream(entry.first);
+ try {
+ File destFile = new File(sharedLibraryDir, entry.second);
+ if (!FileUtils.copyToFile(is, destFile)) {
+ throw new IOException("Couldn't copy native binary "
+ + entry.first.getName() + " to " + entry.second);
+ }
+ } finally {
+ is.close();
+ }
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Couldn't copy native file to container", e);
+ PackageHelper.destroySdDir(newCid);
+ return null;
+ }
+
if (localLOGV) Log.i(TAG, "Copied " + codePath + " to " + resFile);
if (!PackageHelper.finalizeSdDir(newCid)) {
Log.e(TAG, "Failed to finalize " + newCid + " at path " + newCachePath);
diff --git a/packages/SystemUI/res/drawable-hdpi/alert_bar_background_normal.9.png b/packages/SystemUI/res/drawable-hdpi/alert_bar_background_normal.9.png
deleted file mode 100644
index bc127bd..0000000
--- a/packages/SystemUI/res/drawable-hdpi/alert_bar_background_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/alert_bar_background_pressed.9.png b/packages/SystemUI/res/drawable-hdpi/alert_bar_background_pressed.9.png
deleted file mode 100644
index 59af804..0000000
--- a/packages/SystemUI/res/drawable-hdpi/alert_bar_background_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/alert_bar_background_normal.9.png b/packages/SystemUI/res/drawable-mdpi/alert_bar_background_normal.9.png
deleted file mode 100644
index 258de13..0000000
--- a/packages/SystemUI/res/drawable-mdpi/alert_bar_background_normal.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/alert_bar_background_pressed.9.png b/packages/SystemUI/res/drawable-mdpi/alert_bar_background_pressed.9.png
deleted file mode 100644
index 258de13..0000000
--- a/packages/SystemUI/res/drawable-mdpi/alert_bar_background_pressed.9.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/alert_bar_background.xml b/packages/SystemUI/res/drawable/alert_bar_background.xml
deleted file mode 100644
index 24b6aa3..0000000
--- a/packages/SystemUI/res/drawable/alert_bar_background.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2008 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:state_pressed="true"
- android:drawable="@drawable/alert_bar_background_pressed" />
- <item
- android:drawable="@drawable/alert_bar_background_normal" />
-</selector>
-
diff --git a/packages/SystemUI/res/layout/intruder_alert.xml b/packages/SystemUI/res/layout/intruder_alert.xml
deleted file mode 100644
index ba4a774..0000000
--- a/packages/SystemUI/res/layout/intruder_alert.xml
+++ /dev/null
@@ -1,58 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/* apps/common/assets/default/default/skins/StatusBar.xml
-**
-** Copyright 2006, 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.
-*/
--->
-
-<!-- android:background="@drawable/status_bar_closed_default_background" -->
-<FrameLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_height="32dip"
- android:layout_width="match_parent"
- android:paddingLeft="8dip"
- android:paddingRight="8dip"
- >
-
- <LinearLayout
- android:id="@+id/intruder_alert_content"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:animationCache="false"
- android:orientation="horizontal"
- android:background="@drawable/alert_bar_background"
- android:clickable="true"
- android:focusable="true"
- android:descendantFocusability="afterDescendants"
- >
-
- <ImageView
- android:id="@+id/alertIcon"
- android:layout_width="25dip"
- android:layout_height="25dip"
- android:layout_marginLeft="6dip"
- android:layout_marginRight="8dip"
- />
- <TextView
- android:id="@+id/alertText"
- android:textAppearance="@style/TextAppearance.StatusBar.IntruderAlert"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:singleLine="true"
- />
- </LinearLayout>
-</FrameLayout>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
index a47415e..8f2da7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarService.java
@@ -91,11 +91,6 @@
private static final int MSG_ANIMATE = 1000;
private static final int MSG_ANIMATE_REVEAL = 1001;
- private static final int MSG_SHOW_INTRUDER = 1002;
- private static final int MSG_HIDE_INTRUDER = 1003;
-
- // will likely move to a resource or other tunable param at some point
- private static final int INTRUDER_ALERT_DECAY_MS = 10000;
StatusBarPolicy mIconPolicy;
@@ -247,9 +242,6 @@
// we're never destroyed
}
- // for immersive activities
- private View mIntruderAlertView;
-
/**
* Nobody binds to us.
*/
@@ -270,10 +262,6 @@
R.layout.status_bar_expanded, null);
expanded.mService = this;
- mIntruderAlertView = View.inflate(context, R.layout.intruder_alert, null);
- mIntruderAlertView.setVisibility(View.GONE);
- mIntruderAlertView.setClickable(true);
-
StatusBarView sb = (StatusBarView)View.inflate(context, R.layout.status_bar, null);
sb.mService = this;
@@ -354,23 +342,6 @@
// TODO lp.windowAnimations = R.style.Animation_StatusBar;
WindowManagerImpl.getDefault().addView(view, lp);
-
- lp = new WindowManager.LayoutParams(
- ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT,
- WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
- WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
- | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
- | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
- | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM,
- PixelFormat.TRANSLUCENT);
- lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL;
- lp.y += height * 1.5; // FIXME
- lp.setTitle("IntruderAlert");
- lp.windowAnimations = com.android.internal.R.style.Animation_StatusBar_IntruderAlert;
-
- WindowManagerImpl.getDefault().addView(mIntruderAlertView, lp);
}
public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) {
@@ -395,55 +366,23 @@
}
public void addNotification(IBinder key, StatusBarNotification notification) {
- StatusBarIconView iconView = addNotificationViews(key, notification);
- if (iconView == null) return;
-
- boolean immersive = false;
- try {
- immersive = ActivityManagerNative.getDefault().isTopActivityImmersive();
- Slog.d(TAG, "Top activity is " + (immersive?"immersive":"not immersive"));
- } catch (RemoteException ex) {
- }
- if (immersive) {
- if ((notification.notification.flags & Notification.FLAG_HIGH_PRIORITY) != 0) {
- Slog.d(TAG, "Presenting high-priority notification in immersive activity");
- // @@@ special new transient ticker mode
- // 1. Populate mIntruderAlertView
-
- ImageView alertIcon = (ImageView) mIntruderAlertView.findViewById(R.id.alertIcon);
- TextView alertText = (TextView) mIntruderAlertView.findViewById(R.id.alertText);
- alertIcon.setImageDrawable(StatusBarIconView.getIcon(
- alertIcon.getContext(),
- iconView.getStatusBarIcon()));
- alertText.setText(notification.notification.tickerText);
-
- View button = mIntruderAlertView.findViewById(R.id.intruder_alert_content);
- button.setOnClickListener(
- new Launcher(notification.notification.contentIntent,
- notification.pkg, notification.tag, notification.id));
-
- // 2. Animate mIntruderAlertView in
- mHandler.sendEmptyMessage(MSG_SHOW_INTRUDER);
-
- // 3. Set alarm to age the notification off (TODO)
- mHandler.removeMessages(MSG_HIDE_INTRUDER);
- mHandler.sendEmptyMessageDelayed(MSG_HIDE_INTRUDER, INTRUDER_ALERT_DECAY_MS);
- }
- } else if (notification.notification.fullScreenIntent != null) {
- // not immersive & a full-screen alert should be shown
- Slog.d(TAG, "Notification has fullScreenIntent and activity is not immersive;"
- + " sending fullScreenIntent");
+ boolean shouldTick = true;
+ if (notification.notification.fullScreenIntent != null) {
+ shouldTick = false;
+ Slog.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
try {
notification.notification.fullScreenIntent.send();
} catch (PendingIntent.CanceledException e) {
}
- } else {
- // usual case: status bar visible & not immersive
+ }
- // show the ticker
+ StatusBarIconView iconView = addNotificationViews(key, notification);
+ if (iconView == null) return;
+
+ if (shouldTick) {
tick(notification);
}
-
+
// Recalculate the position of the sliding windows and the titles.
setAreThereNotifications();
updateExpandedViewPos(EXPANDED_LEAVE_ALONE);
@@ -721,12 +660,6 @@
case MSG_ANIMATE_REVEAL:
doRevealAnimation();
break;
- case MSG_SHOW_INTRUDER:
- setIntruderAlertVisibility(true);
- break;
- case MSG_HIDE_INTRUDER:
- setIntruderAlertVisibility(false);
- break;
}
}
}
@@ -1109,9 +1042,6 @@
// close the shade if it was open
animateCollapse();
-
- // If this click was on the intruder alert, hide that instead
- mHandler.sendEmptyMessage(MSG_HIDE_INTRUDER);
}
}
@@ -1548,10 +1478,6 @@
}
};
- private void setIntruderAlertVisibility(boolean vis) {
- mIntruderAlertView.setVisibility(vis ? View.VISIBLE : View.GONE);
- }
-
/**
* Reload some of our resources when the configuration changes.
*
diff --git a/services/java/com/android/server/BootReceiver.java b/services/java/com/android/server/BootReceiver.java
index f409751..d15a058 100644
--- a/services/java/com/android/server/BootReceiver.java
+++ b/services/java/com/android/server/BootReceiver.java
@@ -165,7 +165,9 @@
if (prefs != null) {
long lastTime = prefs.getLong(filename, 0);
if (lastTime == fileTime) return; // Already logged this particular file
- prefs.edit().putLong(filename, fileTime).commit();
+ // TODO: move all these SharedPreferences Editor commits
+ // outside this function to the end of logBootEvents
+ prefs.edit().putLong(filename, fileTime).startCommit();
}
Slog.i(TAG, "Copying " + filename + " to DropBox (" + tag + ")");
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 3bcf427..a38970f 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -858,18 +858,22 @@
}
private void updateProvidersLocked() {
+ boolean changesMade = false;
for (int i = mProviders.size() - 1; i >= 0; i--) {
LocationProviderInterface p = mProviders.get(i);
boolean isEnabled = p.isEnabled();
String name = p.getName();
boolean shouldBeEnabled = isAllowedBySettingsLocked(name);
-
if (isEnabled && !shouldBeEnabled) {
updateProviderListenersLocked(name, false);
+ changesMade = true;
} else if (!isEnabled && shouldBeEnabled) {
updateProviderListenersLocked(name, true);
+ changesMade = true;
}
-
+ }
+ if (changesMade) {
+ mContext.sendBroadcast(new Intent(LocationManager.PROVIDERS_CHANGED_ACTION));
}
}
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 0ff33d1..a2d3298 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -18,6 +18,7 @@
import com.android.internal.app.IMediaContainerService;
import com.android.internal.app.ResolverActivity;
+import com.android.internal.content.NativeLibraryHelper;
import com.android.internal.content.PackageHelper;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
@@ -112,6 +113,7 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -188,6 +190,8 @@
"com.android.defcontainer",
"com.android.defcontainer.DefaultContainerService");
+ private static final String LIB_DIR_NAME = "lib";
+
static final String mTempContainerPrefix = "smdl2tmp";
final HandlerThread mHandlerThread = new HandlerThread("PackageManager",
@@ -678,13 +682,6 @@
return false;
}
- static boolean isFwdLocked(int flags) {
- if ((flags & PackageManager.INSTALL_FORWARD_LOCK) != 0) {
- return true;
- }
- return false;
- }
-
public static final IPackageManager main(Context context, boolean factoryTest) {
PackageManagerService m = new PackageManagerService(context, factoryTest);
ServiceManager.addService("package", m);
@@ -1497,6 +1494,7 @@
ps.pkg.applicationInfo.publicSourceDir = ps.resourcePathString;
ps.pkg.applicationInfo.sourceDir = ps.codePathString;
ps.pkg.applicationInfo.dataDir = getDataPathForPackage(ps.pkg).getPath();
+ ps.pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString;
ps.pkg.mSetEnabled = ps.enabled;
}
return generatePackageInfo(ps.pkg, flags);
@@ -2376,8 +2374,7 @@
PackageParser.Package p = i.next();
if (p.applicationInfo != null
&& (p.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) != 0
- && (!mSafeMode || (p.applicationInfo.flags
- &ApplicationInfo.FLAG_SYSTEM) != 0)) {
+ && (!mSafeMode || isSystemApp(p))) {
finalList.add(PackageParser.generateApplicationInfo(p, flags));
}
}
@@ -2621,9 +2618,9 @@
+ "reverting from " + ps.codePathString
+ ": new version " + pkg.mVersionCode
+ " better than installed " + ps.versionCode);
- InstallArgs args = new FileInstallArgs(ps.codePathString, ps.resourcePathString);
+ InstallArgs args = new FileInstallArgs(ps.codePathString,
+ ps.resourcePathString, ps.nativeLibraryPathString);
args.cleanUpResourcesLI();
- removeNativeBinariesLI(pkg);
mSettings.enableSystemPackageLP(ps.name);
}
}
@@ -2663,8 +2660,8 @@
return scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE);
}
- private static void setApplicationInfoPaths(PackageParser.Package pkg,
- String destCodePath, String destResPath) {
+ private static void setApplicationInfoPaths(PackageParser.Package pkg, String destCodePath,
+ String destResPath) {
pkg.mPath = pkg.mScanPath = destCodePath;
pkg.applicationInfo.sourceDir = destCodePath;
pkg.applicationInfo.publicSourceDir = destResPath;
@@ -3146,10 +3143,10 @@
if (dataPath.exists()) {
mOutPermissions[1] = 0;
FileUtils.getPermissions(dataPath.getPath(), mOutPermissions);
- if (mOutPermissions[1] == pkg.applicationInfo.uid
- || !Process.supportsProcesses()) {
- pkg.applicationInfo.dataDir = dataPath.getPath();
- } else {
+
+ // If we have mismatched owners for the data path, we have a
+ // problem (unless we're running in the simulator.)
+ if (mOutPermissions[1] != pkg.applicationInfo.uid && Process.supportsProcesses()) {
boolean recovered = false;
if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) != 0) {
// If this is a system app, we can at least delete its
@@ -3186,6 +3183,7 @@
pkg.applicationInfo.dataDir = "/mismatched_uid/settings_"
+ pkg.applicationInfo.uid + "/fs_"
+ mOutPermissions[1];
+ pkg.applicationInfo.nativeLibraryDir = pkg.applicationInfo.dataDir;
String msg = "Package " + pkg.packageName
+ " has mismatched uid: "
+ mOutPermissions[1] + " on disk, "
@@ -3229,32 +3227,38 @@
pkg.applicationInfo.dataDir = null;
}
}
-
+
+ /*
+ * Set the data dir to the default "/data/data/<package name>/lib"
+ * if we got here without anyone telling us different (e.g., apps
+ * stored on SD card have their native libraries stored in the ASEC
+ * container with the APK).
+ */
+ if (pkg.applicationInfo.nativeLibraryDir == null && pkg.applicationInfo.dataDir != null) {
+ pkg.applicationInfo.nativeLibraryDir = new File(dataPath, LIB_DIR_NAME).getPath();
+ }
+
pkgSetting.uidError = uidError;
}
- // Perform shared library installation and dex validation and
- // optimization, if this is not a system app.
+ // If we're running in the simulator, we don't need to unpack anything.
if (mInstaller != null) {
String path = scanFile.getPath();
- if (scanFileNewer) {
- // Note: We don't want to unpack the native binaries for
- // system applications, unless they have been updated
- // (the binaries are already under /system/lib).
- //
- // In other words, we're going to unpack the binaries
- // only for non-system apps and system app upgrades.
- //
- int flags = pkg.applicationInfo.flags;
- if ((flags & ApplicationInfo.FLAG_SYSTEM) == 0 ||
- (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
- Log.i(TAG, path + " changed; unpacking");
- int err = cachePackageSharedLibsLI(pkg, scanFile);
- if (err != PackageManager.INSTALL_SUCCEEDED) {
- mLastScanError = err;
- return null;
- }
- }
+ /* Note: We don't want to unpack the native binaries for
+ * system applications, unless they have been updated
+ * (the binaries are already under /system/lib).
+ * Also, don't unpack libs for apps on the external card
+ * since they should have their libraries in the ASEC
+ * container already.
+ *
+ * In other words, we're going to unpack the binaries
+ * only for non-system apps and system app upgrades.
+ */
+ if ((!isSystemApp(pkg) || isUpdatedSystemApp(pkg)) && !isExternal(pkg)) {
+ Log.i(TAG, path + " changed; unpacking");
+ File sharedLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
+ sharedLibraryDir.mkdir();
+ NativeLibraryHelper.copyNativeBinariesLI(scanFile, sharedLibraryDir);
}
pkg.mScanPath = path;
@@ -3517,6 +3521,7 @@
a.info.sourceDir = pkg.applicationInfo.sourceDir;
a.info.publicSourceDir = pkg.applicationInfo.publicSourceDir;
a.info.dataDir = pkg.applicationInfo.dataDir;
+ a.info.nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir;
mInstrumentation.put(a.getComponentName(), a);
if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
if (r == null) {
@@ -3557,266 +3562,30 @@
}
}
- // The following constants are returned by cachePackageSharedLibsForAbiLI
- // to indicate if native shared libraries were found in the package.
- // Values are:
- // PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES => native libraries found and installed
- // PACKAGE_INSTALL_NATIVE_NO_LIBRARIES => no native libraries in package
- // PACKAGE_INSTALL_NATIVE_ABI_MISMATCH => native libraries for another ABI found
- // in package (and not installed)
- //
- private static final int PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES = 0;
- private static final int PACKAGE_INSTALL_NATIVE_NO_LIBRARIES = 1;
- private static final int PACKAGE_INSTALL_NATIVE_ABI_MISMATCH = 2;
-
// Return the path of the directory that will contain the native binaries
// of a given installed package. This is relative to the data path.
//
- private static File getNativeBinaryDirForPackage(PackageParser.Package pkg) {
- return new File(pkg.applicationInfo.dataDir + "/lib");
+ private File getNativeBinaryDirForPackage(PackageParser.Package pkg) {
+ final String nativeLibraryDir = pkg.applicationInfo.nativeLibraryDir;
+ if (nativeLibraryDir != null) {
+ return new File(nativeLibraryDir);
+ } else {
+ // Fall back for old packages
+ return new File(pkg.applicationInfo.dataDir, LIB_DIR_NAME);
+ }
}
- // Find all files of the form lib/<cpuAbi>/lib<name>.so in the .apk
- // and automatically copy them to /data/data/<appname>/lib if present.
- //
- // NOTE: this method may throw an IOException if the library cannot
- // be copied to its final destination, e.g. if there isn't enough
- // room left on the data partition, or a ZipException if the package
- // file is malformed.
- //
- private int cachePackageSharedLibsForAbiLI(PackageParser.Package pkg,
- File scanFile, String cpuAbi) throws IOException, ZipException {
- File sharedLibraryDir = getNativeBinaryDirForPackage(pkg);
- final String apkLib = "lib/";
- final int apkLibLen = apkLib.length();
- final int cpuAbiLen = cpuAbi.length();
- final String libPrefix = "lib";
- final int libPrefixLen = libPrefix.length();
- final String libSuffix = ".so";
- final int libSuffixLen = libSuffix.length();
- boolean hasNativeLibraries = false;
- boolean installedNativeLibraries = false;
-
- // the minimum length of a valid native shared library of the form
- // lib/<something>/lib<name>.so.
- final int minEntryLen = apkLibLen + 2 + libPrefixLen + 1 + libSuffixLen;
-
- ZipFile zipFile = new ZipFile(scanFile);
- Enumeration<ZipEntry> entries =
- (Enumeration<ZipEntry>) zipFile.entries();
-
- while (entries.hasMoreElements()) {
- ZipEntry entry = entries.nextElement();
- // skip directories
- if (entry.isDirectory()) {
- continue;
- }
- String entryName = entry.getName();
-
- // check that the entry looks like lib/<something>/lib<name>.so
- // here, but don't check the ABI just yet.
- //
- // - must be sufficiently long
- // - must end with libSuffix, i.e. ".so"
- // - must start with apkLib, i.e. "lib/"
- if (entryName.length() < minEntryLen ||
- !entryName.endsWith(libSuffix) ||
- !entryName.startsWith(apkLib) ) {
- continue;
- }
-
- // file name must start with libPrefix, i.e. "lib"
- int lastSlash = entryName.lastIndexOf('/');
-
- if (lastSlash < 0 ||
- !entryName.regionMatches(lastSlash+1, libPrefix, 0, libPrefixLen) ) {
- continue;
- }
-
- hasNativeLibraries = true;
-
- // check the cpuAbi now, between lib/ and /lib<name>.so
- //
- if (lastSlash != apkLibLen + cpuAbiLen ||
- !entryName.regionMatches(apkLibLen, cpuAbi, 0, cpuAbiLen) )
- continue;
-
- // extract the library file name, ensure it doesn't contain
- // weird characters. we're guaranteed here that it doesn't contain
- // a directory separator though.
- String libFileName = entryName.substring(lastSlash+1);
- if (!FileUtils.isFilenameSafe(new File(libFileName))) {
- continue;
- }
-
- installedNativeLibraries = true;
-
- // Always extract the shared library
- String sharedLibraryFilePath = sharedLibraryDir.getPath() +
- File.separator + libFileName;
- File sharedLibraryFile = new File(sharedLibraryFilePath);
-
- if (Config.LOGD) {
- Log.d(TAG, "Caching shared lib " + entry.getName());
- }
- if (mInstaller == null) {
- sharedLibraryDir.mkdir();
- }
- cacheNativeBinaryLI(pkg, zipFile, entry, sharedLibraryDir,
- sharedLibraryFile);
- }
- if (!hasNativeLibraries)
- return PACKAGE_INSTALL_NATIVE_NO_LIBRARIES;
-
- if (!installedNativeLibraries)
- return PACKAGE_INSTALL_NATIVE_ABI_MISMATCH;
-
- return PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES;
- }
-
- // Find the gdbserver executable program in a package at
- // lib/<cpuAbi>/gdbserver and copy it to /data/data/<name>/lib/gdbserver
- //
- // Returns PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES on success,
- // or PACKAGE_INSTALL_NATIVE_NO_LIBRARIES otherwise.
- //
- private int cachePackageGdbServerLI(PackageParser.Package pkg,
- File scanFile, String cpuAbi) throws IOException, ZipException {
- File installGdbServerDir = getNativeBinaryDirForPackage(pkg);
- final String GDBSERVER = "gdbserver";
- final String apkGdbServerPath = "lib/" + cpuAbi + "/" + GDBSERVER;
-
- ZipFile zipFile = new ZipFile(scanFile);
- Enumeration<ZipEntry> entries =
- (Enumeration<ZipEntry>) zipFile.entries();
-
- while (entries.hasMoreElements()) {
- ZipEntry entry = entries.nextElement();
- // skip directories
- if (entry.isDirectory()) {
- continue;
- }
- String entryName = entry.getName();
-
- if (!entryName.equals(apkGdbServerPath)) {
- continue;
- }
-
- String installGdbServerPath = installGdbServerDir.getPath() +
- "/" + GDBSERVER;
- File installGdbServerFile = new File(installGdbServerPath);
-
- if (Config.LOGD) {
- Log.d(TAG, "Caching gdbserver " + entry.getName());
- }
- if (mInstaller == null) {
- installGdbServerDir.mkdir();
- }
- cacheNativeBinaryLI(pkg, zipFile, entry, installGdbServerDir,
- installGdbServerFile);
-
- return PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES;
- }
- return PACKAGE_INSTALL_NATIVE_NO_LIBRARIES;
- }
-
- // extract shared libraries stored in the APK as lib/<cpuAbi>/lib<name>.so
- // and copy them to /data/data/<appname>/lib.
- //
- // This function will first try the main CPU ABI defined by Build.CPU_ABI
- // (which corresponds to ro.product.cpu.abi), and also try an alternate
- // one if ro.product.cpu.abi2 is defined.
- //
- private int cachePackageSharedLibsLI(PackageParser.Package pkg, File scanFile) {
- // Remove all native binaries from a directory. This is used when upgrading
- // a package: in case the new .apk doesn't contain a native binary that was
- // in the old one (and thus installed), we need to remove it from
- // /data/data/<appname>/lib
- //
- // The simplest way to do that is to remove all files in this directory,
- // since it is owned by "system", applications are not supposed to write
- // anything there.
- removeNativeBinariesLI(pkg);
-
- String cpuAbi = Build.CPU_ABI;
- try {
- int result = cachePackageSharedLibsForAbiLI(pkg, scanFile, cpuAbi);
-
- // some architectures are capable of supporting several CPU ABIs
- // for example, 'armeabi-v7a' also supports 'armeabi' native code
- // this is indicated by the definition of the ro.product.cpu.abi2
- // system property.
- //
- // only scan the package twice in case of ABI mismatch
- if (result == PACKAGE_INSTALL_NATIVE_ABI_MISMATCH) {
- final String cpuAbi2 = SystemProperties.get("ro.product.cpu.abi2",null);
- if (cpuAbi2 != null) {
- result = cachePackageSharedLibsForAbiLI(pkg, scanFile, cpuAbi2);
- }
-
- if (result == PACKAGE_INSTALL_NATIVE_ABI_MISMATCH) {
- Slog.w(TAG,"Native ABI mismatch from package file");
- return PackageManager.INSTALL_FAILED_INVALID_APK;
- }
-
- if (result == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES) {
- cpuAbi = cpuAbi2;
- }
- }
-
- // for debuggable packages, also extract gdbserver from lib/<abi>
- // into /data/data/<appname>/lib too.
- if (result == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES &&
- (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
- int result2 = cachePackageGdbServerLI(pkg, scanFile, cpuAbi);
- if (result2 == PACKAGE_INSTALL_NATIVE_FOUND_LIBRARIES) {
- pkg.applicationInfo.flags |= ApplicationInfo.FLAG_NATIVE_DEBUGGABLE;
- }
- }
- } catch (ZipException e) {
- Slog.w(TAG, "Failed to extract data from package file", e);
- return PackageManager.INSTALL_FAILED_INVALID_APK;
- } catch (IOException e) {
- Slog.w(TAG, "Failed to cache package shared libs", e);
- return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
- }
- return PackageManager.INSTALL_SUCCEEDED;
- }
-
- private void cacheNativeBinaryLI(PackageParser.Package pkg,
- ZipFile zipFile, ZipEntry entry,
- File binaryDir,
- File binaryFile) throws IOException {
- InputStream inputStream = zipFile.getInputStream(entry);
- try {
- File tempFile = File.createTempFile("tmp", "tmp", binaryDir);
- String tempFilePath = tempFile.getPath();
- // XXX package manager can't change owner, so the executable files for
- // now need to be left as world readable and owned by the system.
- if (! FileUtils.copyToFile(inputStream, tempFile) ||
- ! tempFile.setLastModified(entry.getTime()) ||
- FileUtils.setPermissions(tempFilePath,
- FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP
- |FileUtils.S_IXUSR|FileUtils.S_IXGRP|FileUtils.S_IXOTH
- |FileUtils.S_IROTH, -1, -1) != 0 ||
- ! tempFile.renameTo(binaryFile)) {
- // Failed to properly write file.
- tempFile.delete();
- throw new IOException("Couldn't create cached binary "
- + binaryFile + " in " + binaryDir);
- }
- } finally {
- inputStream.close();
- }
+ // Convenience call for removeNativeBinariesLI(File)
+ private void removeNativeBinariesLI(PackageParser.Package pkg) {
+ File nativeLibraryDir = getNativeBinaryDirForPackage(pkg);
+ removeNativeBinariesLI(nativeLibraryDir);
}
// Remove the native binaries of a given package. This simply
// gets rid of the files in the 'lib' sub-directory.
- private void removeNativeBinariesLI(PackageParser.Package pkg) {
- File binaryDir = getNativeBinaryDirForPackage(pkg);
-
+ public void removeNativeBinariesLI(File binaryDir) {
if (DEBUG_NATIVE) {
- Slog.w(TAG,"Deleting native binaries from: " + binaryDir.getPath());
+ Slog.w(TAG, "Deleting native binaries from: " + binaryDir.getPath());
}
// Just remove any file in the directory. Since the directory
@@ -3824,15 +3593,14 @@
// to have written anything there.
//
if (binaryDir.exists()) {
- File[] binaries = binaryDir.listFiles();
+ File[] binaries = binaryDir.listFiles();
if (binaries != null) {
- for (int nn=0; nn < binaries.length; nn++) {
+ for (int nn = 0; nn < binaries.length; nn++) {
if (DEBUG_NATIVE) {
- Slog.d(TAG," Deleting " + binaries[nn].getName());
+ Slog.d(TAG, " Deleting " + binaries[nn].getName());
}
if (!binaries[nn].delete()) {
- Slog.w(TAG,"Could not delete native binary: " +
- binaries[nn].getPath());
+ Slog.w(TAG, "Could not delete native binary: " + binaries[nn].getPath());
}
}
}
@@ -4144,11 +3912,10 @@
|| (checkSignaturesLP(mPlatformPackage.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH);
if (bp.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) {
- if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) {
+ if (isSystemApp(pkg)) {
// For updated system applications, the signatureOrSystem permission
// is granted only if it had been defined by the original application.
- if ((pkg.applicationInfo.flags
- & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {
+ if (isUpdatedSystemApp(pkg)) {
PackageSetting sysPs = mSettings.getDisabledSystemPkg(pkg.packageName);
if(sysPs.grantedPermissions.contains(perm)) {
allowed = true;
@@ -4936,7 +4703,7 @@
// App explictly prefers external. Let policy decide
} else {
// Prefer previous location
- if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
+ if (isExternal(pkg)) {
return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
}
return PackageHelper.RECOMMEND_INSTALL_INTERNAL;
@@ -5048,16 +4815,16 @@
final InstallArgs srcArgs;
final InstallArgs targetArgs;
int mRet;
- MoveParams(InstallArgs srcArgs,
- IPackageMoveObserver observer,
- int flags, String packageName) {
+
+ MoveParams(InstallArgs srcArgs, IPackageMoveObserver observer, int flags,
+ String packageName, String dataDir) {
this.srcArgs = srcArgs;
this.observer = observer;
this.flags = flags;
this.packageName = packageName;
if (srcArgs != null) {
Uri packageUri = Uri.fromFile(new File(srcArgs.getCodePath()));
- targetArgs = createInstallArgs(packageUri, flags, packageName);
+ targetArgs = createInstallArgs(packageUri, flags, packageName, dataDir);
} else {
targetArgs = null;
}
@@ -5113,21 +4880,22 @@
}
}
- private InstallArgs createInstallArgs(int flags, String fullCodePath, String fullResourcePath) {
+ private InstallArgs createInstallArgs(int flags, String fullCodePath, String fullResourcePath,
+ String nativeLibraryPath) {
if (installOnSd(flags)) {
- return new SdInstallArgs(fullCodePath, fullResourcePath);
+ return new SdInstallArgs(fullCodePath, fullResourcePath, nativeLibraryPath);
} else {
- return new FileInstallArgs(fullCodePath, fullResourcePath);
+ return new FileInstallArgs(fullCodePath, fullResourcePath, nativeLibraryPath);
}
}
- private InstallArgs createInstallArgs(Uri packageURI, int flags,
- String pkgName) {
+ // Used by package mover
+ private InstallArgs createInstallArgs(Uri packageURI, int flags, String pkgName, String dataDir) {
if (installOnSd(flags)) {
String cid = getNextCodePath(null, pkgName, "/" + SdInstallArgs.RES_FILE_NAME);
return new SdInstallArgs(packageURI, cid);
} else {
- return new FileInstallArgs(packageURI, pkgName);
+ return new FileInstallArgs(packageURI, pkgName, dataDir);
}
}
@@ -5154,6 +4922,7 @@
abstract int doPostInstall(int status);
abstract String getCodePath();
abstract String getResourcePath();
+ abstract String getNativeLibraryPath();
// Need installer lock especially for dex file removal.
abstract void cleanUpResourcesLI();
abstract boolean doPostDeleteLI(boolean delete);
@@ -5164,6 +4933,7 @@
File installDir;
String codeFileName;
String resourceFileName;
+ String libraryPath;
boolean created = false;
FileInstallArgs(InstallParams params) {
@@ -5171,21 +4941,22 @@
params.flags, params.installerPackageName);
}
- FileInstallArgs(String fullCodePath, String fullResourcePath) {
+ FileInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath) {
super(null, null, 0, null);
File codeFile = new File(fullCodePath);
installDir = codeFile.getParentFile();
codeFileName = fullCodePath;
resourceFileName = fullResourcePath;
+ libraryPath = nativeLibraryPath;
}
- FileInstallArgs(Uri packageURI, String pkgName) {
+ FileInstallArgs(Uri packageURI, String pkgName, String dataDir) {
super(packageURI, null, 0, null);
- boolean fwdLocked = isFwdLocked(flags);
- installDir = fwdLocked ? mDrmAppPrivateInstallDir : mAppInstallDir;
+ installDir = isFwdLocked() ? mDrmAppPrivateInstallDir : mAppInstallDir;
String apkName = getNextCodePath(null, pkgName, ".apk");
codeFileName = new File(installDir, apkName + ".apk").getPath();
resourceFileName = getResourcePathFromCodePath();
+ libraryPath = new File(dataDir, LIB_DIR_NAME).getPath();
}
boolean checkFreeStorage(IMediaContainerService imcs) throws RemoteException {
@@ -5197,8 +4968,7 @@
}
void createCopyFile() {
- boolean fwdLocked = isFwdLocked(flags);
- installDir = fwdLocked ? mDrmAppPrivateInstallDir : mAppInstallDir;
+ installDir = isFwdLocked() ? mDrmAppPrivateInstallDir : mAppInstallDir;
codeFileName = createTempPackageFile(installDir).getPath();
resourceFileName = getResourcePathFromCodePath();
created = true;
@@ -5226,8 +4996,7 @@
}
ParcelFileDescriptor out = null;
try {
- out = ParcelFileDescriptor.open(codeFile,
- ParcelFileDescriptor.MODE_READ_WRITE);
+ out = ParcelFileDescriptor.open(codeFile, ParcelFileDescriptor.MODE_READ_WRITE);
} catch (FileNotFoundException e) {
Slog.e(TAG, "Failed to create file descritpor for : " + codeFileName);
return PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
@@ -5241,6 +5010,11 @@
} finally {
try { if (out != null) out.close(); } catch (IOException e) {}
}
+
+ if (!temp) {
+ NativeLibraryHelper.copyNativeBinariesLI(codeFile, new File(libraryPath));
+ }
+
return ret;
}
@@ -5296,6 +5070,11 @@
}
}
+ @Override
+ String getNativeLibraryPath() {
+ return libraryPath;
+ }
+
private boolean cleanUp() {
boolean ret = true;
String sourceDir = getCodePath();
@@ -5332,11 +5111,14 @@
// we don't consider this to be a failure of the core package deletion
}
}
+ if (libraryPath != null) {
+ removeNativeBinariesLI(new File(libraryPath));
+ }
}
private boolean setPermissions() {
// TODO Do this in a more elegant way later on. for now just a hack
- if (!isFwdLocked(flags)) {
+ if (!isFwdLocked()) {
final int filePermissions =
FileUtils.S_IRUSR|FileUtils.S_IWUSR|FileUtils.S_IRGRP
|FileUtils.S_IROTH;
@@ -5354,35 +5136,42 @@
}
boolean doPostDeleteLI(boolean delete) {
+ // XXX err, shouldn't we respect the delete flag?
cleanUpResourcesLI();
return true;
}
+
+ private boolean isFwdLocked() {
+ return (flags & PackageManager.INSTALL_FORWARD_LOCK) != 0;
+ }
}
class SdInstallArgs extends InstallArgs {
- String cid;
- String cachePath;
static final String RES_FILE_NAME = "pkg.apk";
+ String cid;
+ String packagePath;
+ String libraryPath;
+
SdInstallArgs(InstallParams params) {
super(params.packageURI, params.observer,
params.flags, params.installerPackageName);
}
- SdInstallArgs(String fullCodePath, String fullResourcePath) {
+ SdInstallArgs(String fullCodePath, String fullResourcePath, String nativeLibraryPath) {
super(null, null, PackageManager.INSTALL_EXTERNAL, null);
// Extract cid from fullCodePath
int eidx = fullCodePath.lastIndexOf("/");
String subStr1 = fullCodePath.substring(0, eidx);
int sidx = subStr1.lastIndexOf("/");
cid = subStr1.substring(sidx+1, eidx);
- cachePath = subStr1;
+ setCachePath(subStr1);
}
SdInstallArgs(String cid) {
super(null, null, PackageManager.INSTALL_EXTERNAL, null);
this.cid = cid;
- cachePath = PackageHelper.getSdDir(cid);
+ setCachePath(PackageHelper.getSdDir(cid));
}
SdInstallArgs(Uri packageURI, String cid) {
@@ -5402,21 +5191,30 @@
if (temp) {
createCopyFile();
}
- cachePath = imcs.copyResourceToContainer(
+ String newCachePath = imcs.copyResourceToContainer(
packageURI, cid,
getEncryptKey(), RES_FILE_NAME);
- return (cachePath == null) ? PackageManager.INSTALL_FAILED_CONTAINER_ERROR :
- PackageManager.INSTALL_SUCCEEDED;
+ if (newCachePath != null) {
+ setCachePath(newCachePath);
+ return PackageManager.INSTALL_SUCCEEDED;
+ } else {
+ return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
+ }
}
@Override
String getCodePath() {
- return cachePath + "/" + RES_FILE_NAME;
+ return packagePath;
}
@Override
String getResourcePath() {
- return cachePath + "/" + RES_FILE_NAME;
+ return packagePath;
+ }
+
+ @Override
+ String getNativeLibraryPath() {
+ return libraryPath;
}
int doPreInstall(int status) {
@@ -5426,8 +5224,11 @@
} else {
boolean mounted = PackageHelper.isContainerMounted(cid);
if (!mounted) {
- cachePath = PackageHelper.mountSdDir(cid, getEncryptKey(), Process.SYSTEM_UID);
- if (cachePath == null) {
+ String newCachePath = PackageHelper.mountSdDir(cid, getEncryptKey(),
+ Process.SYSTEM_UID);
+ if (newCachePath != null) {
+ setCachePath(newCachePath);
+ } else {
return PackageManager.INSTALL_FAILED_CONTAINER_ERROR;
}
}
@@ -5473,13 +5274,19 @@
return false;
}
Log.i(TAG, "Succesfully renamed " + cid +
- " at path: " + cachePath + " to " + newCacheId +
+ " to " + newCacheId +
" at new path: " + newCachePath);
cid = newCacheId;
- cachePath = newCachePath;
+ setCachePath(newCachePath);
return true;
}
+ private void setCachePath(String newCachePath) {
+ File cachePath = new File(newCachePath);
+ libraryPath = new File(cachePath, LIB_DIR_NAME).getPath();
+ packagePath = new File(cachePath, RES_FILE_NAME).getPath();
+ }
+
int doPostInstall(int status) {
if (status != PackageManager.INSTALL_SUCCEEDED) {
cleanUp();
@@ -5695,7 +5502,7 @@
return;
}
}
- boolean sysPkg = ((oldPackage.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
+ boolean sysPkg = (isSystemApp(oldPackage));
if (sysPkg) {
replaceSystemPackageLI(oldPackage, pkg, parseFlags, scanMode, installerPackageName, res);
} else {
@@ -5855,7 +5662,7 @@
!ps.codePathString.equals(oldPkgSetting.codePathString)) {
int installFlags = 0;
res.removedInfo.args = createInstallArgs(0, oldPkgSetting.codePathString,
- oldPkgSetting.resourcePathString);
+ oldPkgSetting.resourcePathString, oldPkgSetting.nativeLibraryPathString);
}
}
}
@@ -6006,6 +5813,7 @@
}
// Set application objects path explicitly after the rename
setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath());
+ pkg.applicationInfo.nativeLibraryDir = args.getNativeLibraryPath();
if (replace) {
replacePackageLI(pkg, parseFlags, scanMode,
installerPackageName, res);
@@ -6020,8 +5828,7 @@
int retCode = 0;
// TODO Gross hack but fix later. Ideally move this to be a post installation
// check after alloting uid.
- if ((newPackage.applicationInfo.flags
- & ApplicationInfo.FLAG_FORWARD_LOCK) != 0) {
+ if (isForwardLocked(newPackage)) {
File destResourceFile = new File(newPackage.applicationInfo.publicSourceDir);
try {
extractPublicFiles(newPackage, destResourceFile);
@@ -6056,12 +5863,20 @@
return PackageManager.INSTALL_SUCCEEDED;
}
- private boolean isForwardLocked(PackageParser.Package pkg) {
- return ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0);
+ private static boolean isForwardLocked(PackageParser.Package pkg) {
+ return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0;
}
- private boolean isExternal(PackageParser.Package pkg) {
- return ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
+ private static boolean isExternal(PackageParser.Package pkg) {
+ return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
+ }
+
+ private static boolean isSystemApp(PackageParser.Package pkg) {
+ return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ }
+
+ private static boolean isUpdatedSystemApp(PackageParser.Package pkg) {
+ return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
}
private void extractPublicFiles(PackageParser.Package newPackage,
@@ -6291,7 +6106,7 @@
// we don't consider this to be a failure of the core package deletion
}
} else {
- //for emulator
+ // for simulator
PackageParser.Package pkg = mPackages.get(packageName);
File dataDir = new File(pkg.applicationInfo.dataDir);
dataDir.delete();
@@ -6374,7 +6189,7 @@
synchronized (mPackages) {
// Reinstate the old system package
mSettings.enableSystemPackageLP(p.packageName);
- // Remove any native libraries.
+ // Remove any native libraries. XXX needed?
removeNativeBinariesLI(p);
}
// Install the system package
@@ -6410,12 +6225,10 @@
// Delete application code and resources
if (deleteCodeAndResources) {
// TODO can pick up from PackageSettings as well
- int installFlags = ((p.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE)!=0) ?
- PackageManager.INSTALL_EXTERNAL : 0;
- installFlags |= ((p.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK)!=0) ?
- PackageManager.INSTALL_FORWARD_LOCK : 0;
- outInfo.args = createInstallArgs(installFlags,
- applicationInfo.sourceDir, applicationInfo.publicSourceDir);
+ int installFlags = isExternal(p) ? PackageManager.INSTALL_EXTERNAL : 0;
+ installFlags |= isForwardLocked(p) ? PackageManager.INSTALL_FORWARD_LOCK : 0;
+ outInfo.args = createInstallArgs(installFlags, applicationInfo.sourceDir,
+ applicationInfo.publicSourceDir, applicationInfo.nativeLibraryDir);
}
return true;
}
@@ -6460,7 +6273,7 @@
return false;
}
boolean ret = false;
- if ( (p.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ if (isSystemApp(p)) {
Log.i(TAG, "Removing system package:"+p.packageName);
// When an updated system application is deleted we delete the existing resources as well and
// fall back to existing code in system partition
@@ -7160,10 +6973,14 @@
pw.print(" pkg="); pw.println(ps.pkg);
pw.print(" codePath="); pw.println(ps.codePathString);
pw.print(" resourcePath="); pw.println(ps.resourcePathString);
+ pw.print(" nativeLibraryPath="); pw.println(ps.nativeLibraryPathString);
pw.print(" obbPath="); pw.println(ps.obbPathString);
if (ps.pkg != null) {
pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir);
pw.print(" targetSdk="); pw.println(ps.pkg.applicationInfo.targetSdkVersion);
+ if (ps.pkg.mOperationPending) {
+ pw.println(" mOperationPending=true");
+ }
pw.print(" supportsScreens=[");
boolean first = true;
if ((ps.pkg.applicationInfo.flags &
@@ -7211,9 +7028,6 @@
pw.print(" pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags));
pw.print(" installStatus="); pw.print(ps.installStatus);
pw.print(" enabled="); pw.println(ps.enabled);
- if (ps.pkg.mOperationPending) {
- pw.println(" mOperationPending=true");
- }
if (ps.disabledComponents.size() > 0) {
pw.println(" disabledComponents:");
for (String s : ps.disabledComponents) {
@@ -7730,6 +7544,7 @@
String codePathString;
File resourcePath;
String resourcePathString;
+ String nativeLibraryPathString;
String obbPathString;
private long timeStamp;
private String timeStampString = "0";
@@ -7769,7 +7584,7 @@
this.resourcePathString = resourcePath.toString();
this.versionCode = pVersionCode;
}
-
+
public void setInstallerPackageName(String packageName) {
installerPackageName = packageName;
}
@@ -8282,8 +8097,8 @@
private void insertPackageSettingLP(PackageSetting p, PackageParser.Package pkg) {
p.pkg = pkg;
pkg.mSetEnabled = p.enabled;
- String codePath = pkg.applicationInfo.sourceDir;
- String resourcePath = pkg.applicationInfo.publicSourceDir;
+ final String codePath = pkg.applicationInfo.sourceDir;
+ final String resourcePath = pkg.applicationInfo.publicSourceDir;
// Update code path if needed
if (!codePath.equalsIgnoreCase(p.codePathString)) {
Slog.w(TAG, "Code path for pkg : " + p.pkg.packageName +
@@ -8298,6 +8113,12 @@
p.resourcePath = new File(resourcePath);
p.resourcePathString = resourcePath;
}
+ // Update the native library path if needed
+ final String nativeLibraryPath = pkg.applicationInfo.nativeLibraryDir;
+ if (nativeLibraryPath != null
+ && !nativeLibraryPath.equalsIgnoreCase(p.nativeLibraryPathString)) {
+ p.nativeLibraryPathString = nativeLibraryPath;
+ }
// Update version code if needed
if (pkg.mVersionCode != p.versionCode) {
p.versionCode = pkg.mVersionCode;
@@ -8595,7 +8416,7 @@
StringBuilder sb = new StringBuilder();
for (PackageSetting pkg : mPackages.values()) {
ApplicationInfo ai = pkg.pkg.applicationInfo;
- String dataPath = ai.dataDir;
+ String dataPath = ai.dataDir;
boolean isDebug = (ai.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
// Avoid any application that has a space in its path
@@ -8668,6 +8489,9 @@
if (!pkg.resourcePathString.equals(pkg.codePathString)) {
serializer.attribute(null, "resourcePath", pkg.resourcePathString);
}
+ if (pkg.nativeLibraryPathString != null) {
+ serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString);
+ }
if (pkg.sharedUser == null) {
serializer.attribute(null, "userId",
Integer.toString(pkg.userId));
@@ -8707,6 +8531,9 @@
if (!pkg.resourcePathString.equals(pkg.codePathString)) {
serializer.attribute(null, "resourcePath", pkg.resourcePathString);
}
+ if (pkg.nativeLibraryPathString != null) {
+ serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString);
+ }
serializer.attribute(null, "flags",
Integer.toString(pkg.pkgFlags));
serializer.attribute(null, "ts", pkg.getTimeStampStr());
@@ -9111,6 +8938,7 @@
String sharedIdStr = null;
String codePathStr = null;
String resourcePathStr = null;
+ String nativeLibraryPathStr = null;
String obbPathStr = null;
String systemStr = null;
String installerPackageName = null;
@@ -9129,6 +8957,7 @@
sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
codePathStr = parser.getAttributeValue(null, "codePath");
resourcePathStr = parser.getAttributeValue(null, "resourcePath");
+ nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
obbPathStr = parser.getAttributeValue(null, "obbPath");
version = parser.getAttributeValue(null, "version");
if (version != null) {
@@ -9227,6 +9056,7 @@
if (packageSetting != null) {
packageSetting.uidError = "true".equals(uidError);
packageSetting.installerPackageName = installerPackageName;
+ packageSetting.nativeLibraryPathString = nativeLibraryPathStr;
packageSetting.obbPathString = obbPathStr;
final String enabledStr = parser.getAttributeValue(null, "enabled");
if (enabledStr != null) {
@@ -9893,12 +9723,10 @@
returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST;
} else {
// Disable moving fwd locked apps and system packages
- if (pkg.applicationInfo != null &&
- (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ if (pkg.applicationInfo != null && isSystemApp(pkg)) {
Slog.w(TAG, "Cannot move system application");
returnCode = PackageManager.MOVE_FAILED_SYSTEM_PACKAGE;
- } else if (pkg.applicationInfo != null &&
- (pkg.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK) != 0) {
+ } else if (pkg.applicationInfo != null && isForwardLocked(pkg)) {
Slog.w(TAG, "Cannot move forward locked app.");
returnCode = PackageManager.MOVE_FAILED_FORWARD_LOCKED;
} else if (pkg.mOperationPending) {
@@ -9913,8 +9741,8 @@
} else {
newFlags = (flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0 ?
PackageManager.INSTALL_EXTERNAL : PackageManager.INSTALL_INTERNAL;
- currFlags = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0 ?
- PackageManager.INSTALL_EXTERNAL : PackageManager.INSTALL_INTERNAL;
+ currFlags = isExternal(pkg) ? PackageManager.INSTALL_EXTERNAL
+ : PackageManager.INSTALL_INTERNAL;
if (newFlags == currFlags) {
Slog.w(TAG, "No move required. Trying to move to same location");
returnCode = PackageManager.MOVE_FAILED_INVALID_LOCATION;
@@ -9926,13 +9754,13 @@
}
}
if (returnCode != PackageManager.MOVE_SUCCEEDED) {
- processPendingMove(new MoveParams(null, observer, 0, packageName), returnCode);
+ processPendingMove(new MoveParams(null, observer, 0, packageName, null), returnCode);
} else {
Message msg = mHandler.obtainMessage(INIT_COPY);
InstallArgs srcArgs = createInstallArgs(currFlags, pkg.applicationInfo.sourceDir,
- pkg.applicationInfo.publicSourceDir);
- MoveParams mp = new MoveParams(srcArgs, observer, newFlags,
- packageName);
+ pkg.applicationInfo.publicSourceDir, pkg.applicationInfo.nativeLibraryDir);
+ MoveParams mp = new MoveParams(srcArgs, observer, newFlags, packageName,
+ pkg.applicationInfo.dataDir);
msg.obj = mp;
mHandler.sendMessage(msg);
}
@@ -9950,7 +9778,7 @@
ArrayList<String> pkgList = null;
synchronized (mPackages) {
PackageParser.Package pkg = mPackages.get(mp.packageName);
- if (pkg == null ) {
+ if (pkg == null) {
Slog.w(TAG, " Package " + mp.packageName +
" doesn't exist. Aborting move");
returnCode = PackageManager.MOVE_FAILED_DOESNT_EXIST;
@@ -9983,9 +9811,10 @@
" Aborting move and returning error");
returnCode = PackageManager.MOVE_FAILED_INTERNAL_ERROR;
} else {
- String oldCodePath = pkg.mPath;
- String newCodePath = mp.targetArgs.getCodePath();
- String newResPath = mp.targetArgs.getResourcePath();
+ final String oldCodePath = pkg.mPath;
+ final String newCodePath = mp.targetArgs.getCodePath();
+ final String newResPath = mp.targetArgs.getResourcePath();
+ final String newNativePath = mp.targetArgs.getNativeLibraryPath();
pkg.mPath = newCodePath;
// Move dex files around
if (moveDexFilesLI(pkg)
@@ -9998,6 +9827,7 @@
pkg.mScanPath = newCodePath;
pkg.applicationInfo.sourceDir = newCodePath;
pkg.applicationInfo.publicSourceDir = newResPath;
+ pkg.applicationInfo.nativeLibraryDir = newNativePath;
PackageSetting ps = (PackageSetting) pkg.mExtras;
ps.codePath = new File(pkg.applicationInfo.sourceDir);
ps.codePathString = ps.codePath.getPath();
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index d535343..5d5e862 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -5687,35 +5687,6 @@
}
}
- public void setImmersive(IBinder token, boolean immersive) {
- synchronized(this) {
- int index = (token != null) ? mMainStack.indexOfTokenLocked(token) : -1;
- if (index < 0) {
- throw new IllegalArgumentException();
- }
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
- r.immersive = immersive;
- }
- }
-
- public boolean isImmersive(IBinder token) {
- synchronized (this) {
- int index = (token != null) ? mMainStack.indexOfTokenLocked(token) : -1;
- if (index < 0) {
- throw new IllegalArgumentException();
- }
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(index);
- return r.immersive;
- }
- }
-
- public boolean isTopActivityImmersive() {
- synchronized (this) {
- ActivityRecord r = mMainStack.topRunningActivityLocked(null);
- return (r != null) ? r.immersive : false;
- }
- }
-
public final void enterSafeMode() {
synchronized(this) {
// It only makes sense to do this before the system is ready
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 62be918..1687db1 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -103,7 +103,6 @@
boolean idle; // has the activity gone idle?
boolean hasBeenLaunched;// has this activity ever been launched?
boolean frozenBeforeDestroy;// has been frozen but not yet destroyed.
- boolean immersive; // immersive mode (don't interrupt if possible)
String stringName; // for caching of toString().
@@ -160,7 +159,6 @@
pw.print(prefix); pw.print("keysPaused="); pw.print(keysPaused);
pw.print(" inHistory="); pw.print(inHistory);
pw.print(" persistent="); pw.print(persistent);
- pw.print(" immersive="); pw.print(immersive);
pw.print(" launchMode="); pw.println(launchMode);
pw.print(prefix); pw.print("fullscreen="); pw.print(fullscreen);
pw.print(" visible="); pw.print(visible);
@@ -287,8 +285,6 @@
} else {
isHomeActivity = false;
}
-
- immersive = (aInfo.flags & ActivityInfo.FLAG_IMMERSIVE) != 0;
} else {
realActivity = null;
taskAffinity = null;
@@ -300,7 +296,6 @@
packageName = null;
fullscreen = true;
isHomeActivity = false;
- immersive = false;
}
}
diff --git a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
index b665d2f..1078701 100644
--- a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
+++ b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
@@ -76,17 +76,7 @@
win.setAttributes(winParams);
}
},
- new Test("Immersive: Enter") {
- public void run() {
- setImmersive(true);
- }
- },
- new Test("Immersive: Exit") {
- public void run() {
- setImmersive(false);
- }
- },
- new Test("Priority notification") {
+ new Test("fullScreenIntent") {
public void run() {
Notification not = new Notification(StatusBarTest.this,
R.drawable.stat_sys_phone,
@@ -96,9 +86,8 @@
"(888) 555-5038",
null
);
- not.flags |= Notification.FLAG_HIGH_PRIORITY;
Intent fullScreenIntent = new Intent(StatusBarTest.this, TestAlertActivity.class);
- int id = (int)System.currentTimeMillis(); // XXX HAX
+ int id = (int)System.currentTimeMillis();
fullScreenIntent.putExtra("id", id);
not.fullScreenIntent = PendingIntent.getActivity(
StatusBarTest.this,